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