3 * Copyright © 2006-2008 Daniele Lacamera
4 * from an idea by Renzo Davoli
6 * Released under the terms of GNU GPL v.2
7 * (http://www.gnu.org/licenses/old-licenses/gpl-2.0.html)
8 * with the additional exemption that
9 * compiling, linking, and/or using OpenSSL is allowed.
15 static struct peer
*list
= NULL
;
16 static char *plugname
;
17 static enum e_enc_type enc_type
= ENC_SSH
;
20 * Add a peer to the main list.
21 * Client will have a list of one peer only,
22 * server will have a peer in the list for each "connection"
26 static void addpeer(struct peer
*np
)
34 * Internal, recursive functions:
36 static int _peers(struct peer
*iter
)
41 return 1+_peers(iter
->next
);
44 static void _populatepoll(struct pollfd
*pfd
, struct peer
*iter
,int index
, struct peer
*peerlist
)
49 memcpy(&(peerlist
[index
]),iter
,sizeof(struct peer
));
51 datafd
=vde_datafd(iter
->plug
);
53 pfd
[index
++].events
=POLLIN
|POLLHUP
|POLLNVAL
;
54 } else if(iter
->state
== ST_AUTH
) {
55 vde_plug(iter
, plugname
);
57 _populatepoll(pfd
,iter
->next
,index
, peerlist
);
61 _populatepoll(pfd
,iter
->next
,index
, peerlist
);
65 struct peer
*_getpeer(struct sockaddr_in saddr
, struct peer
*sublist
)
69 if(sublist
->in_a
.sin_addr
.s_addr
==saddr
.sin_addr
.s_addr
&& sublist
->in_a
.sin_port
==saddr
.sin_port
)
71 return _getpeer(saddr
,sublist
->next
);
77 * Returns peer list length.
80 static int numberofpeers(){
81 struct peer
*iter
=list
;
85 static void remove_peerlist(struct peer
*sublist
)
90 vde_close(sublist
->plug
);
92 if (sublist
->state
== ST_AUTH
&& enc_type
== ENC_SSH
){
93 snprintf(filename
,127,"/tmp/.%s.key",sublist
->id
);
94 if (unlink(filename
) == 0){
95 vc_printlog(2,"Successfully removed key file %s", filename
);
97 vc_printlog(2,"Could not remove key file %s", filename
);
100 remove_peerlist(sublist
->next
);
105 static struct peer
*clean_peerlist(struct peer
*sublist
)
111 if (sublist
== list
) {
112 vc_printlog(4, "Cleaning list of peer from expired clients....");
118 gettimeofday(&now
,NULL
);
119 if(after(now
,sublist
->expire
)
120 // || (sublist->state == ST_AUTH && sublist->plug)
122 vc_printlog(1,"Client %s : expired.",inet_ntoa(sublist
->in_a
.sin_addr
));
123 vc_printlog(4,"Client %s : expire time: %lu, now= %lu.",inet_ntoa(sublist
->in_a
.sin_addr
),sublist
->expire
.tv_sec
,now
.tv_sec
);
125 vde_close(sublist
->plug
);
128 if (sublist
->state
== ST_AUTH
&& enc_type
== ENC_SSH
){
129 snprintf(filename
,127,"/tmp/.%s.key",sublist
->id
);
130 if (unlink(filename
) == 0){
131 vc_printlog(2,"Successfully removed key file %s", filename
);
133 vc_printlog(2,"Could not remove key file %s", filename
);
139 sublist
->next
=clean_peerlist(sublist
->next
);
146 * Returns a list of all the peer in the peer list, adding their
147 * network socket to pollfd.
148 * This is called in blowfish_select, to populate the pollfd structure.
150 static struct peer
*populate_peerlist(struct pollfd
*pfd
)
152 static struct peer
*iter
, *peerlist
;
153 iter
=list
; //=clean_peerlist(list);
156 peerlist
=(struct peer
*) malloc( (numberofpeers()+1)*sizeof(struct peer
) );
157 _populatepoll(pfd
,iter
,1,peerlist
);
163 * Get a pointer to the peer in the list which has the given udp address.
165 static struct peer
*getpeer(struct sockaddr_in saddr
)
167 struct peer
*iter
=list
;
168 return (_getpeer(saddr
,iter
));
174 * Get a pointer to the peer in the list which key filename is the same of that in the login datagram.
179 vc_printlog(1,"Caught signal, exiting.");
180 remove_peerlist(list
);
186 set_expire(struct peer
*p
, unsigned char cmd
)
189 gettimeofday(&now
,NULL
);
190 p
->expire
.tv_usec
= 0;
194 p
->expire
.tv_sec
= now
.tv_sec
+ PRELOGIN_TIMEOUT
;
198 p
->expire
.tv_sec
= now
.tv_sec
+ CHALLENGE_TIMEOUT
;
202 p
->expire
.tv_sec
= now
.tv_sec
+ PRELOGIN_TIMEOUT
;
206 p
->expire
.tv_sec
= now
.tv_sec
+ SESSION_TIMEOUT
;
213 deny_access(struct peer
*p
)
215 send_udp((unsigned char *)"Access Denied.\0",15,p
,CMD_DENY
);
216 p
->state
= ST_CLOSED
;
217 set_expire(p
, EXPIRE_NOW
);
221 * Send a "Challenge" 4WHS packet.
224 send_challenge(struct peer
*p
)
227 if ( ((fd
= open ("/dev/urandom", O_RDONLY
)) == -1)||
228 ((read (fd
, p
->challenge
, 128)) != -1))
230 send_udp((unsigned char *)p
->challenge
,128,p
,PKT_CTL
|CMD_CHALLENGE
);
232 p
->state
=ST_CHALLENGE
;
237 * Send a "Auth OK" 4WHS packet.
240 send_auth_ok(struct peer
*p
)
242 send_udp(NULL
,0,p
,CMD_AUTH_OK
);
245 vde_plug(p
, plugname
);
246 set_expire(p
,CMD_AUTH_OK
);
249 * Receive a login request. Send challenge.
252 rcv_login(struct datagram
*pkt
, char *pre_shared
)
257 snprintf(filename
,127,"/tmp/.%s.key",pkt
->data
+1);
259 snprintf(filename
,127,"%s",pre_shared
);
262 if (((fd
= open (filename
, O_RDONLY
)) == -1)||
263 ((read (fd
, pkt
->orig
->key
, 16)) == -1) ||
264 ((read (fd
, pkt
->orig
->iv
, 8)) == -1) ){
265 perror ("blowfish.key open error");
266 deny_access(pkt
->orig
);
271 memcpy(pkt
->orig
->id
,pkt
->data
+1,FILENAMESIZE
);
272 vc_printlog(2,"Sending challenge... ");
273 send_challenge(pkt
->orig
);
274 set_expire(pkt
->orig
, CMD_CHALLENGE
);
275 vc_printlog(2,"OK.\n");
280 * Receive a response from challenge. Validate encryption and send "ok auth"
284 rcv_response(struct datagram
*pkt
)
286 unsigned char response
[MAXPKT
];
288 struct peer
*p
= pkt
->orig
;
290 rlen
= data_decrypt(pkt
->data
+ 1, response
, pkt
->len
- 1, p
);
292 if (rlen
> 0 && strncmp((char *)response
, p
->challenge
,128)==0){
300 * Main select routine.
301 * A poll will wake up whenever a new packet is available to read, either from one
302 * of the vde_plug attached, or from udp socket.
303 * Returns a struct datagram aware of its own source.
305 static int recv_datagram_srv(struct datagram
*pkt
, int nfd
)
309 static struct pollfd
*pfd
= NULL
;
310 static struct peer
*peerlist
= NULL
;
316 pfd
=malloc((1+numberofpeers())*sizeof(struct pollfd
));
319 pfd
[0].events
=POLLIN
|POLLHUP
;
320 peerlist
= populate_peerlist(pfd
);
322 pollret
= poll(pfd
,1+numberofpeers(),1000);
330 list
= clean_peerlist(list
);
336 if (pfd
[0].revents
&POLLIN
) {
337 struct sockaddr_in ipaddress
;
338 peerlen
= sizeof(struct sockaddr_in
);
339 pkt
->len
= recvfrom(nfd
, pkt
->data
, MAXPKT
, 0,
340 (struct sockaddr
*) &ipaddress
, &peerlen
);
342 pkt
->orig
=getpeer(ipaddress
);
344 pkt
->orig
=malloc(sizeof(struct peer
));
345 memset(pkt
->orig
,0,sizeof(struct peer
));
346 pkt
->orig
->in_a
.sin_family
= AF_INET
;
347 pkt
->orig
->in_a
.sin_port
= ipaddress
.sin_port
;
348 pkt
->orig
->in_a
.sin_addr
.s_addr
= ipaddress
.sin_addr
.s_addr
;
349 pkt
->orig
->state
=ST_CLOSED
;
351 set_expire(pkt
->orig
, CMD_LOGIN
);
357 // This increment comes with "static int i" def, to ensure fairness among peers.
359 if(i
>numberofpeers()) {
363 if (pfd
[i
].revents
&POLLNVAL
|| pfd
[i
].revents
&POLLHUP
){
368 if (pfd
[i
].revents
&POLLIN
&& peerlist
[i
].plug
!= NULL
) {
369 pkt
->len
= vde_recv(peerlist
[i
].plug
, pkt
->data
, MAXPKT
,0);
373 pkt
->orig
= &(peerlist
[i
]);
381 void cryptcab_server(char *_plugname
, unsigned short udp_port
, enum e_enc_type _enc_type
, char *pre_shared
)
384 struct sockaddr_in myaddr
;
385 struct datagram pkt
, pkt_dec
;
386 struct sigaction sa_timer
;
387 struct sigaction sa_exit
;
390 enc_type
= _enc_type
;
391 plugname
= _plugname
;
394 sigemptyset(&sa_timer
.sa_mask
);
395 sigemptyset(&sa_exit
.sa_mask
);
396 sa_exit
.sa_handler
= do_exit
;
397 sigaction(SIGINT
, &sa_exit
, NULL
);
398 sigaction(SIGTERM
, &sa_exit
, NULL
);
400 if(enc_type
== ENC_PRESHARED
&& (!pre_shared
|| access(pre_shared
,R_OK
)!=0)){
401 fprintf(stderr
,"Error accessing pre-shared key %s\n",pre_shared
);
406 if (enc_type
== ENC_NOENC
)
407 disable_encryption();
409 memset ((char *)&myaddr
, 0, sizeof(myaddr
));
410 myaddr
.sin_family
= AF_INET
;
411 myaddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
412 myaddr
.sin_port
= htons(udp_port
);
414 wire
= socket(PF_INET
,SOCK_DGRAM
,0);
415 if (bind(wire
,(struct sockaddr
*) &myaddr
, sizeof(myaddr
))<0)
416 {perror("bind socket"); exit(3);}
421 r
= recv_datagram_srv(&pkt
, wire
);
425 // fprintf(stderr,".");
427 if(pkt
.src
==SRC_VDE
){
428 if(p1
->state
==ST_AUTH
){
429 send_udp(pkt
.data
, pkt
.len
, p1
, PKT_DATA
);
433 else if(pkt
.src
==SRC_UDP
){
434 switch(p1
->state
+ pkt
.data
[0]) {
435 case (ST_AUTH
+ PKT_DATA
):
436 vc_printlog(4,"Data pkt received (%d Bytes)",pkt
.len
);
437 pkt_dec
.len
= data_decrypt(pkt
.data
+1, pkt_dec
.data
, pkt
.len
-1, p1
);
438 set_expire(p1
, CMD_KEEPALIVE
);
439 vde_send(p1
->plug
,pkt_dec
.data
,pkt_dec
.len
,0);
441 case (ST_AUTH
+ CMD_KEEPALIVE
):
442 vc_printlog(4,"Keepalive received from %s",inet_ntoa(p1
->in_a
.sin_addr
));
443 set_expire(p1
, CMD_KEEPALIVE
);
446 case ST_AUTH
+ CMD_LOGIN
:
447 set_expire(p1
, EXPIRE_NOW
);
448 case ST_CLOSED
+ CMD_LOGIN
:
449 vc_printlog(4,"Login pkt received.");
450 p1
->state
=ST_OPENING
;
452 rcv_login(&pkt
,pre_shared
);
455 case ST_CHALLENGE
+ CMD_RESPONSE
:
456 vc_printlog(4,"Response pkt received.");
457 //fprintf(stderr, "Receiving response\n");
462 vc_printlog(4,"Unknown/undesired pkt received. (state: 0x%X code: 0x%X )", p1
->state
, (unsigned char)pkt
.data
[0]);
463 if (p1
->state
!= ST_AUTH
)
464 deny_access(pkt
.orig
);
466 send_auth_ok(pkt
.orig
);