3 * Copyright © 2006 Daniele Lacamera
4 * Released under the terms of GNU GPL v.2
5 * http://www.gnu.org/copyleft/gpl.html
7 * This program is released under the GPL with the additional exemption that
8 * compiling, linking, and/or using OpenSSL is allowed.
11 #include <sys/types.h>
12 #include <sys/ioctl.h>
14 #include "compat/poll.h"
17 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <sys/socket.h>
34 unsigned char *crc32(unsigned char*,int);
35 static unsigned long long mycounter
=1;
37 static EVP_CIPHER_CTX ctx
;
39 static struct peer
*list
=NULL
;
41 static struct itimerval TIMER
= {
42 .it_interval
={ .tv_sec
=0, .tv_usec
=0},
43 .it_value
={ .tv_sec
=SESSION_TIMEOUT
/2, .tv_usec
=0 }
47 * Add a peer to the main list.
48 * Client will have a list of one peer only,
49 * server will have a peer in the list for each "connection"
53 void addpeer(struct peer
*np
)
61 * Internal, recursive functions:
63 static int _peers(struct peer
*iter
)
68 return 1+_peers(iter
->next
);
71 static void _populatepoll(struct pollfd
*pfd
, struct peer
*iter
,int index
, struct peer
*peerlist
)
76 memcpy(&(peerlist
[index
]),iter
,sizeof(struct peer
));
77 datafd
=vde_datafd(iter
->plug
);
80 pfd
[index
++].events
=POLLIN
|POLLHUP
;
84 _populatepoll(pfd
,iter
->next
,index
, peerlist
);
89 _populatepoll(pfd
,iter
->next
,index
, peerlist
);
94 struct peer
*_getpeer(struct sockaddr_in saddr
, struct peer
*sublist
)
98 if(sublist
->in_a
.sin_addr
.s_addr
==saddr
.sin_addr
.s_addr
&& sublist
->in_a
.sin_port
==saddr
.sin_port
)
100 return _getpeer(saddr
,sublist
->next
);
104 struct peer
*_getpeerbna(struct sockaddr_in saddr
, struct peer
*sublist
)
108 if(sublist
->handover_a
.sin_addr
.s_addr
==saddr
.sin_addr
.s_addr
&& sublist
->handover_a
.sin_port
==saddr
.sin_port
)
110 return _getpeerbna(saddr
,sublist
->next
);
114 static struct peer
*_getpeerbyid(struct datagram
*pkt
, struct peer
*sublist
)
116 if(pkt
->len
!=FILENAMESIZE
+1)
120 if(strncmp((char *)pkt
->data
+1,sublist
->id
,FILENAMESIZE
)==0)
122 return _getpeerbyid(pkt
,sublist
->next
);
128 set_expire(struct peer
*p
)
130 gettimeofday(&(p
->expire
),NULL
);
131 p
->expire
.tv_sec
+=SESSION_TIMEOUT
;
135 * Check progressive number validity in incoming datagram
138 isvalid_timestamp(unsigned char *block
, int size
, struct peer
*p
)
143 unsigned long long pktcounter
=0;
145 pktcounter
+=block
[size
-12+i
]<<(i
*8);
147 if(pktcounter
>p
->counter
){
148 p
->counter
=pktcounter
;
151 //fprintf(stderr,"bad timestamp!\n");
158 * Check CRC32 Checksum from incoming datagram
161 isvalid_crc32(unsigned char *block
, int len
)
163 unsigned char *crc
=(unsigned char *)crc32(block
,len
-4);
164 if(strncmp((char*)block
+(len
-4),(char*)crc
,4)==0){
169 //fprintf(stderr,"bad crc32!\n");
177 * Returns peer list length.
180 static int numberofpeers(){
181 struct peer
*iter
=list
;
187 struct peer
*clean_peerlist(struct peer
*sublist
)
192 if(sublist
->state
== ST_AUTH
&& vde_datafd(sublist
->plug
) < 0){
193 struct peer
*nxt
=sublist
->next
;
198 if(sublist
->state
== ST_AUTH
){
200 gettimeofday(&now
,NULL
);
202 if(after(now
,sublist
->expire
)){
203 struct peer
*nxt
=sublist
->next
;
204 vde_close(sublist
->plug
);
210 sublist
->next
=clean_peerlist(sublist
->next
);
216 autocleaner(int signo
)
218 struct itimerval
*old
=NULL
;
219 list
=clean_peerlist(list
);
220 setitimer(ITIMER_REAL
, &TIMER
, old
);
224 * Returns a list of all the peer in the peer list, adding their
225 * network socket to pollfd.
226 * This is called in blowfish_select, to populate the pollfd structure.
228 static struct peer
*populate_peerlist(struct pollfd
*pfd
)
230 static struct peer
*iter
, *peerlist
;
231 iter
=list
; //=clean_peerlist(list);
234 peerlist
=(struct peer
*) malloc( (numberofpeers()+1)*sizeof(struct peer
) );
235 _populatepoll(pfd
,iter
,1,peerlist
);
241 * Get a pointer to the peer in the list which has the given udp address.
243 struct peer
*getpeer(struct sockaddr_in saddr
)
245 struct peer
*iter
=list
;
246 return (_getpeer(saddr
,iter
));
250 struct peer
*getpeerbynewaddr(struct sockaddr_in saddr
)
252 struct peer
*iter
=list
;
253 return (_getpeerbna(saddr
,iter
));
259 * Get a pointer to the peer in the list which key filename is the same of that in the login datagram.
261 struct peer
*getpeerbyid(struct datagram
*pkt
)
263 struct peer
*iter
=list
;
264 return (_getpeerbyid(pkt
,iter
));
269 * Send a plain "access denied" message to the specified peer.
272 deny_access(struct peer
*p
)
274 send_udp((unsigned char *)"Access Denied.\0",15,p
,CMD_DENY
);
278 * Main select routine.
279 * A poll will wake up whenever a new packet is available to read, either from one
280 * of the vde_plug attached, or from udp socket.
281 * Returns a struct datagram aware of its own source.
282 * Also discriminate commands from data, by first byte.
284 struct datagram
*blowfish_select (int timeout
)
288 static struct pollfd
*pfd
= NULL
;
289 static struct datagram
*ret
= NULL
;
290 static struct peer
*peerlist
= NULL
;
295 pfd
=malloc((1+numberofpeers())*sizeof(struct pollfd
));
298 pfd
[0].events
=POLLIN
|POLLHUP
;
299 peerlist
= populate_peerlist(pfd
);
302 pollret
=poll(pfd
,1+numberofpeers(),1000);
310 ret
= malloc(sizeof(struct datagram
));
311 bzero(ret
,sizeof(struct datagram
));
312 ret
->orig
= malloc(sizeof (struct peer
));
313 bzero(ret
->orig
,sizeof(struct peer
));
315 } while (pollret
==0);
319 if (pfd
[0].revents
&POLLIN
) {
320 unsigned char inpkt
[MAXPKT
];
321 unsigned char *inbuff
=inpkt
+1;
323 struct sockaddr_in ipaddress
;
324 peerlen
= sizeof(struct sockaddr_in
);
325 ilen
= recvfrom(nfd
, inpkt
, MAXPKT
, 0,
326 (struct sockaddr
*) &ipaddress
, &peerlen
);
328 ret
->orig
=getpeer(ipaddress
);
330 ret
->orig
=malloc(sizeof(struct peer
));
331 bzero(ret
->orig
,sizeof(struct peer
));
332 ret
->orig
->in_a
.sin_family
= AF_INET
;
333 ret
->orig
->in_a
.sin_port
= ipaddress
.sin_port
;
334 ret
->orig
->in_a
.sin_addr
.s_addr
= ipaddress
.sin_addr
.s_addr
;
335 ret
->orig
->state
=ST_CLOSED
;
339 if((inpkt
[0]==PKT_DATA
)&&
340 (ret
->orig
->state
==ST_AUTH
|| ret
->orig
->state
==ST_SERVER
))
346 EVP_DecryptInit (&ctx
, EVP_bf_cbc (), ret
->orig
->key
, ret
->orig
->iv
);
348 if (EVP_DecryptUpdate (&ctx
, ret
->data
, &ret
->len
, inbuff
, ilen
) != 1)
350 fprintf (stderr
,"error in decrypt update\n");
353 if (EVP_DecryptFinal (&ctx
, ret
->data
+ ret
->len
, &tlen
) != 1)
355 fprintf (stderr
,"error in decrypt final\n");
358 EVP_CIPHER_CTX_cleanup(&ctx
);
360 if( isvalid_crc32(ret
->data
,ret
->len
) && isvalid_timestamp(ret
->data
,ret
->len
,ret
->orig
) ){
362 if(ret
->orig
->state
==ST_AUTH
)
363 set_expire(ret
->orig
);
366 // deny_access(ret->orig);
369 }else if((inpkt
[0]==CMD_HANDOVER
)){
373 //fprintf (stderr,"Recived Handover datagram.: ");
374 EVP_DecryptInit (&ctx
, EVP_bf_cbc (), ret
->orig
->key
, ret
->orig
->iv
);
376 if (EVP_DecryptUpdate (&ctx
, ret
->data
+1, &ret
->len
, inbuff
, ilen
) != 1)
378 fprintf (stderr
,"error in decrypt update\n");
381 if (EVP_DecryptFinal (&ctx
, ret
->data
+ 1 + ret
->len
, &tlen
) != 1)
383 fprintf (stderr
,"error in decrypt final\n");
386 EVP_CIPHER_CTX_cleanup(&ctx
);
389 if( isvalid_crc32(ret
->data
+1,ret
->len
-1) && isvalid_timestamp(ret
->data
,ret
->len
,ret
->orig
) ){
391 ret
->data
[0]=CMD_HANDOVER
;
392 //fprintf (stderr,"Valid Handover. Resending key.\n");
395 fprintf (stderr
,"Invalid Handover packet. crc32?%d, timestamp?%d \n",isvalid_crc32(ret
->data
+1,ret
->len
-1), isvalid_timestamp(ret
->data
,ret
->len
,ret
->orig
));
396 deny_access(ret
->orig
);
400 }else if(inpkt
[0]&PKT_CTL
){
402 memcpy(ret
->data
,inpkt
,ilen
);
406 deny_access(ret
->orig
);
414 // This increment comes with "static int i" def, to ensure fairness among peers.
416 if(i
>numberofpeers())
419 if (pfd
[i
].revents
&POLLIN
) {
420 /* c=read(pfd[i].fd,ret->data,2);
424 vde_len+=((unsigned char)(ret->data[0]))<<8;
425 vde_len+=(unsigned char)(ret->data[1]);
428 while(ret->len < (vde_len + 2)){
429 ret->len += read(pfd[i].fd, ret->data+ret->len, ((vde_len+2) - ret->len));
431 // fprintf(stderr,"Read %d.\n",vde_len);
434 ret
->len
= vde_recv(peerlist
[i
].plug
, ret
->data
, MAXPKT
,0);
440 ret
->orig
= &(peerlist
[i
]);
442 //set_expire(&(peerlist[i]));
448 // list=clean_peerlist(list);
455 * Send a virtual frame to the vde_plug process associated
459 send_vdeplug(const char *data
, size_t len
, struct peer
*p
)
461 static unsigned int outbuf
[MAXPKT
];
463 static u_int16_t outlen
;
467 if(outp
==0 && (len
>=2) ){
469 outlen
+=(unsigned char)data
[1];
470 outlen
+=((unsigned char)(data
[0]))<<8;
474 vde_send(p
->plug
,data
,outlen
,0);
475 send_vdeplug(data
+outlen
,len
-outlen
, p
);
479 memcpy(outbuf
+outp
,data
,len
);
482 vde_send(p
->plug
,(char *)outbuf
,outlen
,0);
487 * Include a progressive number into outgoing datagram,
488 * to prevent packet replication/injection attack.
492 set_timestamp(unsigned char *block
)
496 block
[i
]=(unsigned char)(mycounter
>>(i
*8))&(0x00000000000000FF);
505 * Send an udp datagram to specified peer.
508 send_udp (unsigned char *data
, size_t len
, struct peer
*p
, unsigned char flags
)
511 unsigned char outpkt
[MAXPKT
];
512 unsigned char *outbuf
=outpkt
+1;
514 struct sockaddr_in
*destination
=&(p
->in_a
);
516 if(flags
==CMD_CHALLENGE
|| flags
==CMD_LOGIN
|| flags
==CMD_DENY
|| flags
==CMD_AUTH_OK
|| flags
==CMD_IDENTIFY
){
517 memcpy(outbuf
,data
,len
);
520 if(flags
==PKT_DATA
||flags
==CMD_HANDOVER
){
521 set_timestamp(data
+len
);
524 crc
= crc32(data
,len
);
525 memcpy(data
+len
,crc32(data
,len
),4);
530 if(flags
==CMD_HANDOVER
){
532 destination
=&(p
->handover_a
);
535 EVP_EncryptInit (&ctx
, EVP_bf_cbc (), p
->key
, p
->iv
);
536 if (EVP_EncryptUpdate (&ctx
, outbuf
, &olen
, data
, len
) != 1)
538 fprintf (stderr
,"error in encrypt update\n");
543 if (EVP_EncryptFinal (&ctx
, outbuf
+ olen
, &tlen
) != 1)
545 fprintf (stderr
,"error in encrypt final\n");
548 EVP_CIPHER_CTX_cleanup(&ctx
);
553 sendto(nfd
, outpkt
, olen
+1, 0, (struct sockaddr
*) destination
,
554 sizeof(struct sockaddr_in
));
558 * Generate a new blowfish key, store it in a local file and fill the fields
563 *generate_key (struct peer
*ret
, char *pre_shared
)
565 int i
, fd
=-1, od
=-1, createnow
=0;
566 unsigned char key
[16];
570 char random
[]="/dev/urandom";
577 ret
=malloc(sizeof(struct peer
));
578 bzero(ret
,sizeof(struct peer
));
581 if ( ((fd
= open (path
, O_RDONLY
)) == -1)||
582 ((read (fd
, key
, 16)) == -1) ||
583 ((read (fd
, iv
, 8)) == -1) )
586 perror ("Error Creating key.\n");
590 //fprintf(stderr,"128 bit key stored.\n");
592 //fprintf(stderr,"64 bit Initialization vector stored.\n");
594 for(i
=0; i
<FILENAMESIZE
-1;i
++){
597 //fprintf(stderr,"c=%u\n",c);
598 ret
->id
[i
]=(char)('a' + c
);
600 ret
->id
[FILENAMESIZE
-1]='\0';
604 if ((od
= creat ("/tmp/.blowfish.key",0600)) == -1){
605 perror ("blowfish.key creat error");
608 memcpy(ret
->key
,key
,16);
609 memcpy(ret
->iv
,iv
,8);
627 * Send a "Challenge" 4WHS packet.
630 send_challenge(struct peer
*p
)
633 if ( ((fd
= open ("/dev/urandom", O_RDONLY
)) == -1)||
634 ((read (fd
, p
->challenge
, 128)) != -1))
636 send_udp((unsigned char *)p
->challenge
,128,p
,PKT_CTL
|CMD_CHALLENGE
);
638 p
->state
=ST_CHALLENGE
;
643 * Send a "Auth OK" 4WHS packet.
646 send_auth_ok(struct peer
*p
, void (*callback
)(struct peer
*))
648 send_udp(NULL
,0,p
,CMD_AUTH_OK
);
655 * Receive a challenge. Try to send response encrypted with local blowfish key.
658 rcv_challenge(struct datagram
*pkt
, struct peer
*p
)
660 send_udp(pkt
->data
+1,pkt
->len
-1,p
,CMD_RESPONSE
);
661 p
->state
=ST_WAIT_AUTH
;
666 * Receive a login request. Send challenge.
669 rcv_login(struct datagram
*pkt
, struct peer
*p
, char *pre_shared
)
674 snprintf(filename
,127,"/tmp/.%s.key",pkt
->data
+1);
676 snprintf(filename
,127,"%s",pre_shared
);
679 fprintf(stderr
,"Filename:%s\n",filename
);
680 if (((fd
= open (filename
, O_RDONLY
)) == -1)||
681 ((read (fd
, p
->key
, 16)) == -1) ||
682 ((read (fd
, p
->iv
, 8)) == -1) ){
683 perror ("blowfish.key open error");
688 memcpy(p
->id
,pkt
->data
+1,FILENAMESIZE
);
689 fprintf(stderr
,"Sending challenge... ");
691 fprintf(stderr
,"OK.\n");
696 * Receive a response from challenge. Validate encryption and send "ok auth"
700 rcv_response(struct datagram
*pkt
, struct peer
*p
, void (*callback
)(struct peer
*))
702 unsigned char response
[MAXPKT
];
705 EVP_DecryptInit (&ctx
, EVP_bf_cbc (), p
->key
, p
->iv
);
707 if (EVP_DecryptUpdate (&ctx
, response
, &rlen
, pkt
->data
+1, pkt
->len
-1) != 1)
709 fprintf (stderr
,"error in decrypt update\n");
713 if (EVP_DecryptFinal (&ctx
, response
+ rlen
, &tlen
) != 1)
715 fprintf (stderr
,"error in decrypt final\n");
718 EVP_CIPHER_CTX_cleanup(&ctx
);
720 if (strncmp((char *)response
,p
->challenge
,128)==0){
722 send_auth_ok(p
, callback
);
733 * Send a login packet. This is the first phase of 4WHS
736 blowfish_login(struct peer
*p
)
738 send_udp((unsigned char*)p
->id
,FILENAMESIZE
,p
,CMD_LOGIN
);
742 * Initialize blowfish module.
743 * Set udp socket and initialize crypto engine & CRC32.
746 blowfish_init(int socketfd
)
749 EVP_CIPHER_CTX_init (&ctx
);
750 chksum_crc32gentab ();