tagging vde-2 version 2.3.2
[vde.git] / 2.3.2 / src / vde_cryptcab / cryptcab.c
blobc1f14fd1c0dea2f3b9a62b1f47b303c704f6afdd
1 /*
2 * VDE Cryptcab
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.
13 #include "cryptcab.h"
16 * Usage implies exit.
18 static void Usage(char *programname)
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);
25 static EVP_CIPHER_CTX ctx;
26 static int ctx_initialized = 0;
27 static int encryption_disabled = 0;
28 static int nfd;
29 static unsigned long long mycounter=1;
30 static struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
31 static int verbose = 0;
33 void vc_printlog(int priority, const char *format, ...)
35 va_list arg;
36 if(verbose >= priority){
37 va_start (arg, format);
39 fprintf(stderr,"vde_cryptcab: ");
40 vfprintf(stderr,format,arg);
41 fprintf(stderr,"\n");
42 va_end (arg);
46 void disable_encryption(void) {
47 encryption_disabled = 1;
48 vc_printlog(3,"Encryption Disabled.");
51 void set_nfd(int fd){
52 nfd = fd;
56 * Check progressive number validity in incoming datagram
58 int
59 isvalid_timestamp(unsigned char *block, int size, struct peer *p)
63 int i;
64 unsigned long long pktcounter=0;
65 for(i=0;i<8;i++){
66 pktcounter+=block[size-12+i]<<(i*8);
68 if(pktcounter>p->counter){
69 p->counter=pktcounter;
70 return 1;
71 }else{
72 //fprintf(stderr,"bad timestamp!\n");
73 return 0;
79 * Check CRC32 Checksum from incoming datagram
81 int
82 isvalid_crc32(unsigned char *block, int len)
84 unsigned char *crc=(unsigned char *)crc32(block,len-4);
85 if(strncmp((char*)block+(len-4),(char*)crc,4)==0){
86 free(crc);
87 return 1;
88 }else{
90 //fprintf(stderr,"bad crc32!\n");
91 free(crc);
92 return 0;
96 int data_encrypt(unsigned char *src, unsigned char *dst, int len, struct peer *p)
98 int tlen, olen;
100 if (encryption_disabled){
101 memcpy(dst,src,len);
102 return len;
105 if (!ctx_initialized) {
106 EVP_CIPHER_CTX_init (&ctx);
107 ctx_initialized = 1;
110 EVP_EncryptInit (&ctx, EVP_bf_cbc (), p->key, p->iv);
111 if (EVP_EncryptUpdate (&ctx, dst, &olen, src, len) != 1)
113 fprintf (stderr,"error in encrypt update\n");
114 olen = -1;
115 goto cleanup;
118 if (EVP_EncryptFinal (&ctx, dst + olen, &tlen) != 1)
120 fprintf (stderr,"error in encrypt final\n");
121 olen = -1;
122 goto cleanup;
124 olen += tlen;
126 cleanup:
127 EVP_CIPHER_CTX_cleanup(&ctx);
128 return olen;
131 int data_decrypt(unsigned char *src, unsigned char *dst, int len, struct peer *p)
133 int tlen, olen;
135 if (encryption_disabled){
136 memcpy(dst,src,len);
137 return len;
140 if (!ctx_initialized) {
141 EVP_CIPHER_CTX_init (&ctx);
142 ctx_initialized = 1;
145 EVP_DecryptInit (&ctx, EVP_bf_cbc (), p->key, p->iv);
146 if (EVP_DecryptUpdate (&ctx, dst, &olen, src, len) != 1)
148 fprintf (stderr,"error in decrypt update\n");
149 olen = -1;
150 goto cleanup;
153 if (EVP_DecryptFinal (&ctx, dst + olen, &tlen) != 1)
155 fprintf (stderr,"error in decrypt final\n");
156 olen = -1;
157 goto cleanup;
159 olen += tlen;
161 cleanup:
162 EVP_CIPHER_CTX_cleanup(&ctx);
163 return olen;
167 * Include a progressive number into outgoing datagram,
168 * to prevent packet replication/injection attack.
171 void
172 set_timestamp(unsigned char *block)
174 int i;
175 for(i=0;i<8;i++){
176 block[i]=(unsigned char)(mycounter>>(i*8))&(0x00000000000000FF);
178 mycounter++;
185 * Send an udp datagram to specified peer.
187 void
188 send_udp (unsigned char *data, size_t len, struct peer *p, unsigned char flags)
191 unsigned char outpkt[MAXPKT];
192 unsigned char *outbuf=outpkt+1;
193 int olen;
194 struct sockaddr_in *destination=&(p->in_a);
195 unsigned char *crc;
196 if (encryption_disabled || (flags==CMD_CHALLENGE || flags==CMD_LOGIN || flags==CMD_DENY || flags==CMD_AUTH_OK || flags == CMD_KEEPALIVE)){
197 memcpy(outbuf,data,len);
198 olen=len;
199 }else{
200 if(flags==PKT_DATA){
201 set_timestamp(data+len);
202 len+=8;
204 crc = crc32(data,len);
205 memcpy(data+len,crc,4);
206 free(crc);
207 len+=4;
210 olen = data_encrypt(data,outbuf,len,p);
212 outpkt[0]=flags;
213 sendto(nfd, outpkt, olen + 1, 0, (struct sockaddr *) destination,
214 sizeof(struct sockaddr_in));
215 vc_printlog(4,"UDP Sent %dB datagram.",olen+1);
218 void
219 vde_plug(struct peer *p, char *plugname)
221 p->plug=vde_open(plugname,"vde_cryptcab",&open_args);
222 if(!p->plug)
224 perror ("libvdeplug");
225 exit(1);
227 vc_printlog(3,"Socket to local switch created: fd=%d",vde_datafd(p->plug));
231 * Send a virtual frame to the vde_plug process associated
232 * with the peer
234 void
235 send_vdeplug(const char *data, size_t len, struct peer *p)
237 static unsigned int outbuf[MAXPKT];
238 static int outp=0;
239 static u_int16_t outlen;
240 if(len<=0)
241 return;
243 if(outp==0 && (len >=2) ){
244 outlen=2;
245 outlen+=(unsigned char)data[1];
246 outlen+=((unsigned char)(data[0]))<<8;
249 if(len>=outlen){
250 vde_send(p->plug,data,outlen,0);
251 send_vdeplug(data+outlen,len-outlen, p);
252 return;
255 memcpy(outbuf+outp,data,len);
256 outp+=len;
257 if(outp>=outlen){
258 vde_send(p->plug,(char *)outbuf,outlen,0);
260 vc_printlog(3,"VDE - Sent a %dB datagram.",outlen);
264 * Main.
266 int main(int argc, char **argv, char **env)
268 int c;
269 char *programname=argv[0];
270 char *plugname="/tmp/vde.ctl";
271 char *remotehost = NULL;
272 char *remoteusr = NULL;
273 char *pre_shared = NULL;
274 enum e_enc_type enc_type = ENC_SSH;
275 unsigned short udp_port = PORTNO;
276 unsigned short remoteport = PORTNO;
277 unsigned char keepalives=0;
278 char *scp_extra_options;
279 int daemonize = 0;
281 scp_extra_options=getenv("SCP_EXTRA_OPTIONS");
284 while (1) {
285 int option_index = 0;
286 char *ctl_socket;
287 const char sepusr='@';
288 const char sepport=':';
289 char *pusr,*pport, *vvv=NULL;
291 static struct option long_options[] = {
292 {"sock", 1, 0, 's'},
293 {"vdesock", 1, 0, 's'},
294 {"unix", 1, 0, 's'},
295 {"localport", 1, 0, 'p'},
296 {"connect",1,0,'c'},
297 {"preshared ",1,0,'P'},
298 {"noencrypt",0,0,'x'},
299 {"keepalive",0,0,'k'},
300 {"verbose",optional_argument,0,'v'},
301 {"help",0,0,'h'},
302 {"daemon",0,0,'d'},
303 {0, 0, 0, 0}
305 c = GETOPT_LONG (argc, argv, "s:p:c:P:hv::xkd",
306 long_options, &option_index);
307 if (c == -1)
308 break;
309 switch (c) {
310 case 's':
311 plugname=strdup(optarg);
312 break;
313 case 'v':
314 verbose=1;
315 if(optarg)
316 vvv=strdup(optarg);
317 while(vvv && *vvv++ == 'v')
318 verbose++;
319 break;
320 case 'x':
321 enc_type = ENC_NOENC;
322 break;
323 case 'c':
324 ctl_socket=strdup(optarg);
326 pusr=strchr(ctl_socket,sepusr);
327 pport=strchr(ctl_socket,sepport);
329 if( ( pusr != strrchr(ctl_socket,sepusr)) ||
330 (pport != strrchr(ctl_socket,sepport)) ||
331 (pport && pusr>pport) )
332 Usage(programname);
334 if(!pusr && !pport){
335 remoteusr=NULL;
336 remoteport=PORTNO;
337 remotehost=strdup(ctl_socket);
338 break;
340 if(!pport){
341 remoteusr=(char *)strndup(ctl_socket,pusr-ctl_socket);
342 remotehost=(char *)strndup(pusr+1,strlen(ctl_socket)-strlen(remoteusr)-1);
343 remoteport=PORTNO;
344 break;
346 if(!pusr){
347 remoteusr=NULL;
348 remotehost=(char *)strndup(ctl_socket,pport-ctl_socket);
349 remoteport=atoi((char *)strndup(pport+1,strlen(ctl_socket)-strlen(remotehost)-1));
350 break;
352 remoteusr=(char *)strndup(ctl_socket,pusr-ctl_socket);
353 remotehost=(char *)strndup(pusr+1,pport-pusr-1);
354 remoteport=atoi((char *)strndup(pport+1,strlen(ctl_socket)-strlen(remotehost)-strlen(remoteusr)-2));
355 break;
357 case 'p':
358 udp_port=atoi(optarg);
359 break;
361 case 'P':
362 pre_shared=strdup(optarg);
363 fprintf(stderr,"Using pre-shared key %s\n",pre_shared);
364 enc_type = ENC_PRESHARED;
365 break;
366 case 'k':
367 keepalives=1;
368 break;
369 case 'd':
370 daemonize=1;
371 break;
373 case 'h':
374 default:
375 Usage(programname);
378 if(optind < argc)
379 Usage(programname);
380 if (keepalives && remotehost==NULL){
381 fprintf(stderr,"\nkeepalive option is valid in client mode only.\n\n");
382 Usage(programname);
384 if (pre_shared && enc_type == ENC_NOENC){
385 fprintf(stderr,"\nWarning: Not using pre-shared key mode, encryption disabled.\n\n");
386 pre_shared = NULL;
390 vc_printlog(1,"Verbosity: %d", verbose);
391 chksum_crc32gentab();
393 switch(enc_type){
394 case ENC_NOENC:
395 vc_printlog(1,"Encryption Disabled.");
396 break;
397 case ENC_PRESHARED:
398 vc_printlog(1,"Using pre-shared key %s",pre_shared);
399 break;
400 case ENC_SSH:
401 vc_printlog(1,"Using ssh key exchange for authentication");
402 break;
405 if (daemonize) {
406 if (fork() == 0) {
407 setsid();
408 close(STDIN_FILENO);
409 close(STDOUT_FILENO);
410 if (fork() > 0)
411 exit(0);
412 } else exit(0);
415 if(!remotehost){
416 cryptcab_server(plugname, udp_port, enc_type, pre_shared);
417 } else {
418 cryptcab_client(plugname, udp_port, enc_type, pre_shared, remoteusr, remotehost, remoteport, keepalives, scp_extra_options);
420 exit(0);