1 /*
2 * VDE Cryptcab
3 * Copyright © 2006-2008 Daniele Lacamera
4 * from an idea by Renzo Davoli
5 *
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.
10 *
11 */
12
13 #include "cryptcab.h"
14 #define KEEPALIVE_INTERVAL 30
15
16 static unsigned char keepalives = 0;
17 static char *remoteusr, *remotehost;
18 static unsigned short remoteport;
19 static char *plugname, *pre_shared;
20 static struct timeval last_out_time;
21 static enum e_enc_type enc_type = ENC_SSH;
22 static char *scp_extra_options = NULL;
23
send_keepalive(struct peer * p)24 static void send_keepalive(struct peer *p){
25 if (!keepalives)
26 return;
27 vc_printlog(4,"Sending keepalive");
28 send_udp(NULL,0,p,CMD_KEEPALIVE);
29 gettimeofday(&last_out_time, NULL);
30 }
31
32
33 /*
34 * Send a login packet. This is the first phase of 4WHS
35 */
36 static void
blowfish_login(struct peer * p)37 blowfish_login(struct peer *p)
38 {
39 send_udp((unsigned char*)p->id,FILENAMESIZE,p,CMD_LOGIN);
40 }
41
try_to_login(struct peer * p)42 static void try_to_login(struct peer *p)
43 {
44 static struct timeval last_login_time;
45 struct timeval now;
46 gettimeofday(&now, 0);
47 if (now.tv_sec < last_login_time.tv_sec || now.tv_sec - last_login_time.tv_sec < 5) {
48 vc_printlog(4,"Attempt to login to %s (udp port %hu): please wait, login in progress...",remotehost,remoteport);
49 return;
50 }
51
52 vc_printlog(2,"Logging in to %s (udp port %hu)",remotehost,remoteport);
53 blowfish_login(p);
54 gettimeofday(&last_login_time, 0);
55 }
56
57
58 /*
59 * Receive a challenge. Try to send response encrypted with local blowfish key.
60 */
61 static void
rcv_challenge(struct datagram * pkt,struct peer * p)62 rcv_challenge(struct datagram *pkt, struct peer *p)
63 {
64 send_udp(pkt->data+1,pkt->len-1,p,CMD_RESPONSE);
65 p->state=ST_WAIT_AUTH;
66 }
67
68 /*
69 * Generate a new blowfish key, store it in a local file and fill the fields
70 * of peer structure.
71 * Client only.
72 */
73 static struct peer
generate_key(struct peer * ret)74 *generate_key (struct peer *ret)
75 {
76 int i, fd=-1, od=-1;
77 unsigned char key[16];
78 unsigned char iv[8];
79 unsigned char c;
80 char *path;
81 char random[]="/dev/urandom";
82 if (pre_shared){
83 path=pre_shared;
84 vc_printlog(2,"Reading pre-shared Blowfish key...");
85 }else{
86 path=random;
87 vc_printlog(2,"Generating Blowfish key...");
88 }
89
90 if ( ((fd = open (path, O_RDONLY)) == -1)||
91 ((read (fd, key, 16)) == -1) ||
92 ((read (fd, iv, 8)) == -1) )
93 {
94
95 perror ("Error Creating key.\n");
96 goto failure;
97 }
98
99 memset(ret,0, sizeof(struct peer));
100
101 for(i=0; i<FILENAMESIZE-1;i++){
102 if (read(fd,&c,1) < 0) {
103 perror("could not read filename ");
104 goto failure;
105 }
106 c=(c%25);
107 //fprintf(stderr,"c=%u\n",c);
108 ret->id[i]=(char)('a' + c);
109 }
110 ret->id[FILENAMESIZE-1]='\0';
111
112 close (fd);
113
114 if ((od = creat ("/tmp/.blowfish.key",0600)) == -1){
115 perror ("blowfish.key creat error");
116 goto failure;
117 }
118 memcpy(ret->key,key,16);
119 memcpy(ret->iv,iv,8);
120 if (write(od,key,16) < 0 || write(od,iv,8) < 0) {
121 perror("Could not write blowfish key");
122 goto failure;
123 }
124 close (od);
125 vc_printlog(2,"Done.");
126 return ret;
127
128 failure:
129 if (fd != -1)
130 close(fd);
131 if (od != -1)
132 close(od);
133 return NULL;
134 }
135
136
137 /*
138 * Call the generate_key() and then transmit the key to the server via
139 * OpenSSH secure copy.
140 */
generate_and_xmit(struct peer * ret)141 static struct peer *generate_and_xmit(struct peer *ret){
142 char command[255];
143 int res;
144 struct hostent *target;
145
146 ret=generate_key(ret);
147
148 if(!ret){
149 fprintf(stderr,"Couldn't create the secret key.\n");
150 exit(255);
151 }
152
153 target=gethostbyname(remotehost);
154 if (target == NULL)
155 {
156 fprintf(stderr,"%s not found.\n", remotehost);
157 exit(2);
158 }
159 ret->in_a.sin_family = AF_INET;
160 ret->in_a.sin_port = htons(remoteport);
161 ret->in_a.sin_addr.s_addr=((struct in_addr *)(target->h_addr))->s_addr;
162 if(!pre_shared){
163 vc_printlog(2,"Sending key over ssh channel:");
164 if(remoteusr)
165 sprintf(command,"scp %s /tmp/.blowfish.key %s@%s:/tmp/.%s.key 2>&1",
166 scp_extra_options?scp_extra_options:"",
167 remoteusr, remotehost, ret->id);
168 else
169 sprintf(command,"scp %s /tmp/.blowfish.key %s:/tmp/.%s.key 2>&1",
170 scp_extra_options?scp_extra_options:"",
171 remotehost, ret->id);
172
173 //fprintf(stderr,"Contacting host: %s ",remotehost);
174 res=system(command);
175
176 if(res==0){
177 vc_printlog(2,"Key successfully transferred using a secure channel.");
178 }else{
179 fprintf(stderr,"Couldn't transfer the secret key.\n");
180 exit(253);
181 }
182 }
183 vc_printlog(2,"Done.");
184 return ret;
185 }
186
recv_datagram(struct datagram * pkt,int nfd,struct peer * p1)187 static int recv_datagram(struct datagram *pkt, int nfd, struct peer *p1)
188 {
189 int pollret;
190 static struct pollfd pfd[2];
191 socklen_t peerlen;
192 int datafd;
193 struct timeval now;
194
195 datafd = vde_datafd(p1->plug);
196 while(datafd < 0) {
197 vc_printlog(4,"waiting for vde_libs...");
198 vde_plug(p1, plugname);
199 sleep(1);
200 datafd = vde_datafd(p1->plug);
201 }
202
203 pfd[0].fd=nfd;
204 pfd[0].events=POLLIN|POLLHUP;
205 pfd[1].fd = datafd;
206 pfd[1].events = POLLIN|POLLHUP;
207
208 do{
209 pollret = poll(pfd,2,1000);
210 if(pollret<0){
211 if(errno==EINTR)
212 return 0;
213 perror("poll");
214 exit(1);
215 }
216
217 gettimeofday(&now,NULL);
218 now.tv_sec -= KEEPALIVE_INTERVAL;
219 if (after(now,last_out_time) && p1->state == ST_AUTH){
220 send_keepalive(p1);
221 }
222 } while (pollret==0);
223
224
225 for(;;){
226 if (pfd[0].revents&POLLIN) {
227 struct sockaddr_in ipaddress;
228 peerlen = sizeof(struct sockaddr_in);
229 pkt->len = recvfrom(nfd, pkt->data, MAXPKT, 0,
230 (struct sockaddr *) &ipaddress, &peerlen);
231 if(ipaddress.sin_addr.s_addr == p1->in_a.sin_addr.s_addr){
232 pkt->orig=p1;
233 pkt->src = SRC_UDP;
234 return 1;
235 } else {
236 vc_printlog(1,"Warning: received packet from unknown address %s, dropping",inet_ntoa(ipaddress.sin_addr));
237 return 0;
238 }
239 }
240
241 if (pfd[1].revents&POLLHUP){
242 vc_printlog(1,"VDE Error");
243 }
244 if (pfd[1].revents&POLLIN) {
245 vc_printlog(4,"VDE Pkt");
246 pkt->len = vde_recv(p1->plug, pkt->data, MAXPKT,0);
247 if(pkt->len<1)
248 return 0;
249 pkt->src = SRC_VDE;
250 pkt->orig = p1;
251 return 1;
252 }
253 }
254 return 0;
255 }
256
cryptcab_client(char * _plugname,unsigned short udp_port,enum e_enc_type _enc_type,char * _pre_shared,char * _remoteusr,char * _remotehost,unsigned short _remoteport,unsigned char _keepalives,char * _scp_extra_options)257 void cryptcab_client(char *_plugname, unsigned short udp_port, enum e_enc_type _enc_type, char *_pre_shared, char *_remoteusr, char *_remotehost, unsigned short _remoteport, unsigned char _keepalives, char *_scp_extra_options)
258 {
259 int wire, r;
260 struct sockaddr_in myaddr;
261 struct datagram pkt, pkt_dec;
262 struct peer _peer;
263 struct peer *p1 = &_peer;
264
265 plugname = _plugname;
266 remoteusr = _remoteusr;
267 remotehost = _remotehost;
268 remoteport = _remoteport;
269 pre_shared = _pre_shared;
270 keepalives = _keepalives;
271 enc_type = _enc_type;
272 scp_extra_options = _scp_extra_options;
273
274 memset(&last_out_time,0, sizeof(struct timeval));
275
276 if(enc_type == ENC_PRESHARED && (!pre_shared || access(pre_shared,R_OK)!=0)){
277 vc_printlog(0,"Error accessing pre-shared key %s: %s\n",pre_shared,strerror(errno));
278 exit(1);
279 }
280
281 if (enc_type == ENC_NOENC)
282 disable_encryption();
283
284 memset ((char *)&myaddr, 0, sizeof(myaddr));
285 myaddr.sin_family = AF_INET;
286 myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
287 myaddr.sin_port = htons(udp_port);
288
289 wire = socket(PF_INET,SOCK_DGRAM,0);
290 if (bind(wire,(struct sockaddr *) &myaddr, sizeof(myaddr))<0)
291 {perror("bind socket"); exit(3);}
292
293 set_nfd(wire);
294
295 p1 = generate_and_xmit(p1);
296 p1->state = ST_OPENING;
297 p1->next = NULL;
298 try_to_login(p1);
299 usleep(100000);
300
301 for(;;){
302 r = recv_datagram(&pkt, wire, p1);
303 if (r == 0)
304 continue;
305
306 if(pkt.src==SRC_VDE){
307 if(p1->state==ST_AUTH){
308 vc_printlog(4,"VDE pkt received (%d Bytes)",pkt.len);
309 send_udp(pkt.data, pkt.len, p1, PKT_DATA);
310 gettimeofday(&last_out_time,NULL);
311 }else{
312 try_to_login(p1);
313 }
314 continue;
315 }
316 else if(pkt.src==SRC_UDP){
317 switch(p1->state + pkt.data[0]) {
318 case ST_OPENING + CMD_CHALLENGE:
319 vc_printlog(2,"Received Challenge packet, replying:");
320 rcv_challenge(&pkt, p1);
321 break;
322 case ST_WAIT_AUTH + CMD_AUTH_OK:
323 p1->state = ST_AUTH;
324 vc_printlog(2,"Successfully authenticated.");
325 break;
326 case ST_AUTH + PKT_DATA:
327 vc_printlog(4,"Data pkt received (%d Bytes)",pkt.len);
328 pkt_dec.len = data_decrypt(pkt.data+1, pkt_dec.data, pkt.len-1, p1);
329
330 vde_send(p1->plug,pkt_dec.data,pkt_dec.len,0);
331 break;
332 case ST_OPENING + CMD_DENY:
333 case ST_WAIT_AUTH + CMD_DENY:
334 case ST_AUTH + CMD_DENY:
335 vc_printlog(2,"Received access denied from server, sending identification.");
336 vde_close(p1->plug);
337 p1 = (struct peer *)generate_and_xmit(p1);
338 p1->state = ST_OPENING;
339 try_to_login(p1);
340 break;
341 default:
342 vc_printlog(4,"Unknown/undesired pkt received. (state: 0x%X code: 0x%X )", p1->state, (unsigned char)pkt.data[0]);
343 }
344
345 }
346
347 }
348 exit (0);
349 }
350
351