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
15 /*
16 * Usage implies exit.
17 */
Usage(char * programname)18 static void Usage(char *programname)
19 {
20
21 fprintf(stderr,"Usage: %s [-s socketname] [-c [remoteuser@]remotehost[:remoteport]] [-p localport] [-P pre-shared/key/path] [-d] [-x] [-v]\n",programname);
22 exit(1);
23 }
24
25 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
26 static EVP_CIPHER_CTX *ctx;
27 #else
28 static EVP_CIPHER_CTX ctx;
29 #endif
30 static int ctx_initialized = 0;
31 static int encryption_disabled = 0;
32 static int nfd;
33 static unsigned long long mycounter=1;
34 static struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
35 static int verbose = 0;
36
vc_printlog(int priority,const char * format,...)37 void vc_printlog(int priority, const char *format, ...)
38 {
39 va_list arg;
40 if(verbose >= priority){
41 va_start (arg, format);
42
43 fprintf(stderr,"vde_cryptcab: ");
44 vfprintf(stderr,format,arg);
45 fprintf(stderr,"\n");
46 va_end (arg);
47 }
48 }
49
disable_encryption(void)50 void disable_encryption(void) {
51 encryption_disabled = 1;
52 vc_printlog(3,"Encryption Disabled.");
53 }
54
set_nfd(int fd)55 void set_nfd(int fd){
56 nfd = fd;
57 }
58
59 /*
60 * Check progressive number validity in incoming datagram
61 */
62 int
isvalid_timestamp(unsigned char * block,int size,struct peer * p)63 isvalid_timestamp(unsigned char *block, int size, struct peer *p)
64 {
65
66
67 int i;
68 unsigned long long pktcounter=0;
69 for(i=0;i<8;i++){
70 pktcounter+=block[size-12+i]<<(i*8);
71 }
72 if(pktcounter>p->counter){
73 p->counter=pktcounter;
74 return 1;
75 }else{
76 //fprintf(stderr,"bad timestamp!\n");
77 return 0;
78 }
79
80 }
81
82 /*
83 * Check CRC32 Checksum from incoming datagram
84 */
85 int
isvalid_crc32(unsigned char * block,int len)86 isvalid_crc32(unsigned char *block, int len)
87 {
88 unsigned char *crc=(unsigned char *)crc32(block,len-4);
89 if(strncmp((char*)block+(len-4),(char*)crc,4)==0){
90 free(crc);
91 return 1;
92 }else{
93
94 //fprintf(stderr,"bad crc32!\n");
95 free(crc);
96 return 0;
97 }
98 }
99
data_encrypt(unsigned char * src,unsigned char * dst,int len,struct peer * p)100 int data_encrypt(unsigned char *src, unsigned char *dst, int len, struct peer *p)
101 {
102 int tlen, olen;
103
104 if (encryption_disabled){
105 memcpy(dst,src,len);
106 return len;
107 }
108
109 if (!ctx_initialized) {
110 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
111 ctx = EVP_CIPHER_CTX_new();
112 EVP_CIPHER_CTX_init (ctx);
113 #else
114 EVP_CIPHER_CTX_init (&ctx);
115 #endif
116 ctx_initialized = 1;
117 }
118
119 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
120 EVP_EncryptInit (ctx, EVP_bf_cbc (), p->key, p->iv);
121 if (EVP_EncryptUpdate (ctx, dst, &olen, src, len) != 1)
122 #else
123 EVP_EncryptInit (&ctx, EVP_bf_cbc (), p->key, p->iv);
124 if (EVP_EncryptUpdate (&ctx, dst, &olen, src, len) != 1)
125 #endif
126 {
127 fprintf (stderr,"error in encrypt update\n");
128 olen = -1;
129 goto cleanup;
130 }
131
132 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
133 if (EVP_EncryptFinal (ctx, dst + olen, &tlen) != 1)
134 #else
135 if (EVP_EncryptFinal (&ctx, dst + olen, &tlen) != 1)
136 #endif
137 {
138 fprintf (stderr,"error in encrypt final\n");
139 olen = -1;
140 goto cleanup;
141 }
142 olen += tlen;
143
144 cleanup:
145 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
146 EVP_CIPHER_CTX_cleanup(ctx);
147 EVP_CIPHER_CTX_free(ctx);
148 #else
149 EVP_CIPHER_CTX_cleanup(&ctx);
150 #endif
151 return olen;
152 }
153
data_decrypt(unsigned char * src,unsigned char * dst,int len,struct peer * p)154 int data_decrypt(unsigned char *src, unsigned char *dst, int len, struct peer *p)
155 {
156 int tlen, olen;
157
158 if (encryption_disabled){
159 memcpy(dst,src,len);
160 return len;
161 }
162
163 if (!ctx_initialized) {
164 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
165 ctx = EVP_CIPHER_CTX_new();
166 EVP_CIPHER_CTX_init(ctx);
167 #else
168 EVP_CIPHER_CTX_init (&ctx);
169 #endif
170 ctx_initialized = 1;
171 }
172
173 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
174 EVP_DecryptInit (ctx, EVP_bf_cbc (), p->key, p->iv);
175 if (EVP_DecryptUpdate (ctx, dst, &olen, src, len) != 1)
176 #else
177 EVP_DecryptInit (&ctx, EVP_bf_cbc (), p->key, p->iv);
178 if (EVP_DecryptUpdate (&ctx, dst, &olen, src, len) != 1)
179 #endif
180 {
181 fprintf (stderr,"error in decrypt update\n");
182 olen = -1;
183 goto cleanup;
184 }
185
186 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
187 if (EVP_DecryptFinal (ctx, dst + olen, &tlen) != 1)
188 #else
189 if (EVP_DecryptFinal (&ctx, dst + olen, &tlen) != 1)
190 #endif
191 {
192 fprintf (stderr,"error in decrypt final\n");
193 olen = -1;
194 goto cleanup;
195 }
196 olen += tlen;
197
198 cleanup:
199 #if OPENSSL_VERSION_NUMBER >= 0x1010100fL
200 EVP_CIPHER_CTX_cleanup(ctx);
201 EVP_CIPHER_CTX_free(ctx);
202 #else
203 EVP_CIPHER_CTX_cleanup(&ctx);
204 #endif
205 return olen;
206 }
207
208 /*
209 * Include a progressive number into outgoing datagram,
210 * to prevent packet replication/injection attack.
211 *
212 */
213 void
set_timestamp(unsigned char * block)214 set_timestamp(unsigned char *block)
215 {
216 int i;
217 for(i=0;i<8;i++){
218 block[i]=(unsigned char)(mycounter>>(i*8))&(0x00000000000000FF);
219 }
220 mycounter++;
221
222
223 }
224
225
226 /*
227 * Send an udp datagram to specified peer.
228 */
229 void
send_udp(unsigned char * data,size_t len,struct peer * p,unsigned char flags)230 send_udp (unsigned char *data, size_t len, struct peer *p, unsigned char flags)
231 {
232
233 unsigned char outpkt[MAXPKT];
234 unsigned char *outbuf=outpkt+1;
235 int olen;
236 struct sockaddr_in *destination=&(p->in_a);
237 unsigned char *crc;
238 if (encryption_disabled || (flags==CMD_CHALLENGE || flags==CMD_LOGIN || flags==CMD_DENY || flags==CMD_AUTH_OK || flags == CMD_KEEPALIVE)){
239 memcpy(outbuf,data,len);
240 olen=len;
241 }else{
242 if(flags==PKT_DATA){
243 set_timestamp(data+len);
244 len+=8;
245
246 crc = crc32(data,len);
247 memcpy(data+len,crc,4);
248 free(crc);
249 len+=4;
250
251 }
252 olen = data_encrypt(data,outbuf,len,p);
253 }
254 outpkt[0]=flags;
255 sendto(nfd, outpkt, olen + 1, 0, (struct sockaddr *) destination,
256 sizeof(struct sockaddr_in));
257 vc_printlog(4,"UDP Sent %dB datagram.",olen+1);
258 }
259
260 void
vde_plug(struct peer * p,char * plugname)261 vde_plug(struct peer *p, char *plugname)
262 {
263 p->plug=vde_open(plugname,"vde_cryptcab",&open_args);
264 if(!p->plug)
265 {
266 perror ("libvdeplug");
267 exit(1);
268 }
269 vc_printlog(3,"Socket to local switch created: fd=%d",vde_datafd(p->plug));
270 }
271
272 /*
273 * Send a virtual frame to the vde_plug process associated
274 * with the peer
275 */
276 void
send_vdeplug(const char * data,size_t len,struct peer * p)277 send_vdeplug(const char *data, size_t len, struct peer *p)
278 {
279 static unsigned int outbuf[MAXPKT];
280 static int outp=0;
281 static u_int16_t outlen;
282 if(len<=0)
283 return;
284
285 if(outp==0 && (len >=2) ){
286 outlen=2;
287 outlen+=(unsigned char)data[1];
288 outlen+=((unsigned char)(data[0]))<<8;
289 }
290
291 if(len>=outlen){
292 vde_send(p->plug,data,outlen,0);
293 send_vdeplug(data+outlen,len-outlen, p);
294 return;
295 }
296
297 memcpy(outbuf+outp,data,len);
298 outp+=len;
299 if(outp>=outlen){
300 vde_send(p->plug,(char *)outbuf,outlen,0);
301 }
302 vc_printlog(3,"VDE - Sent a %dB datagram.",outlen);
303 }
304
305 /*
306 * Main.
307 */
main(int argc,char ** argv,char ** env)308 int main(int argc, char **argv, char **env)
309 {
310 int c;
311 char *programname=argv[0];
312 char *plugname="/tmp/vde.ctl";
313 char *remotehost = NULL;
314 char *remoteusr = NULL;
315 char *pre_shared = NULL;
316 enum e_enc_type enc_type = ENC_SSH;
317 unsigned short udp_port = PORTNO;
318 unsigned short remoteport = PORTNO;
319 unsigned char keepalives=0;
320 char *scp_extra_options;
321 int daemonize = 0;
322
323 scp_extra_options=getenv("SCP_EXTRA_OPTIONS");
324
325
326 while (1) {
327 int option_index = 0;
328 char *ctl_socket;
329 const char sepusr='@';
330 const char sepport=':';
331 char *pusr,*pport, *vvv=NULL;
332
333 static struct option long_options[] = {
334 {"sock", 1, 0, 's'},
335 {"vdesock", 1, 0, 's'},
336 {"unix", 1, 0, 's'},
337 {"localport", 1, 0, 'p'},
338 {"connect",1,0,'c'},
339 {"preshared ",1,0,'P'},
340 {"noencrypt",0,0,'x'},
341 {"keepalive",0,0,'k'},
342 {"verbose",optional_argument,0,'v'},
343 {"help",0,0,'h'},
344 {"daemon",0,0,'d'},
345 {0, 0, 0, 0}
346 };
347 c = GETOPT_LONG (argc, argv, "s:p:c:P:hv::xkd",
348 long_options, &option_index);
349 if (c == -1)
350 break;
351 switch (c) {
352 case 's':
353 plugname=strdup(optarg);
354 break;
355 case 'v':
356 verbose=1;
357 if(optarg)
358 vvv=strdup(optarg);
359 while(vvv && *vvv++ == 'v')
360 verbose++;
361 break;
362 case 'x':
363 enc_type = ENC_NOENC;
364 break;
365 case 'c':
366 ctl_socket=strdup(optarg);
367
368 pusr=strchr(ctl_socket,sepusr);
369 pport=strchr(ctl_socket,sepport);
370
371 if( ( pusr != strrchr(ctl_socket,sepusr)) ||
372 (pport != strrchr(ctl_socket,sepport)) ||
373 (pport && pusr>pport) )
374 Usage(programname);
375
376 if(!pusr && !pport){
377 remoteusr=NULL;
378 remoteport=PORTNO;
379 remotehost=strdup(ctl_socket);
380 break;
381 }
382 if(!pport){
383 remoteusr=(char *)strndup(ctl_socket,pusr-ctl_socket);
384 remotehost=(char *)strndup(pusr+1,strlen(ctl_socket)-strlen(remoteusr)-1);
385 remoteport=PORTNO;
386 break;
387 }
388 if(!pusr){
389 remoteusr=NULL;
390 remotehost=(char *)strndup(ctl_socket,pport-ctl_socket);
391 remoteport=atoi((char *)strndup(pport+1,strlen(ctl_socket)-strlen(remotehost)-1));
392 break;
393 }
394 remoteusr=(char *)strndup(ctl_socket,pusr-ctl_socket);
395 remotehost=(char *)strndup(pusr+1,pport-pusr-1);
396 remoteport=atoi((char *)strndup(pport+1,strlen(ctl_socket)-strlen(remotehost)-strlen(remoteusr)-2));
397 break;
398
399 case 'p':
400 udp_port=atoi(optarg);
401 break;
402
403 case 'P':
404 pre_shared=strdup(optarg);
405 fprintf(stderr,"Using pre-shared key %s\n",pre_shared);
406 enc_type = ENC_PRESHARED;
407 break;
408 case 'k':
409 keepalives=1;
410 break;
411 case 'd':
412 daemonize=1;
413 break;
414
415 case 'h':
416 default:
417 Usage(programname);
418 }
419 }
420 if(optind < argc)
421 Usage(programname);
422 if (keepalives && remotehost==NULL){
423 fprintf(stderr,"\nkeepalive option is valid in client mode only.\n\n");
424 Usage(programname);
425 }
426 if (pre_shared && enc_type == ENC_NOENC){
427 fprintf(stderr,"\nWarning: Not using pre-shared key mode, encryption disabled.\n\n");
428 pre_shared = NULL;
429 }
430
431
432 vc_printlog(1,"Verbosity: %d", verbose);
433 chksum_crc32gentab();
434
435 switch(enc_type){
436 case ENC_NOENC:
437 vc_printlog(1,"Encryption Disabled.");
438 break;
439 case ENC_PRESHARED:
440 vc_printlog(1,"Using pre-shared key %s",pre_shared);
441 break;
442 case ENC_SSH:
443 vc_printlog(1,"Using ssh key exchange for authentication");
444 break;
445 }
446
447 if (daemonize) {
448 if (fork() == 0) {
449 setsid();
450 close(STDIN_FILENO);
451 close(STDOUT_FILENO);
452 if (fork() > 0)
453 exit(0);
454 } else exit(0);
455 }
456
457 if(!remotehost){
458 cryptcab_server(plugname, udp_port, enc_type, pre_shared);
459 } else {
460 cryptcab_client(plugname, udp_port, enc_type, pre_shared, remoteusr, remotehost, remoteport, keepalives, scp_extra_options);
461 }
462 exit(0);
463 }
464
465