1 /*
2     VTun - Virtual Tunnel over TCP/IP network.
3 
4     Copyright (C) 1998-2016  Maxim Krasnyansky <max_mk@yahoo.com>
5 
6     VTun has been derived from VPPP package by Maxim Krasnyansky.
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17  */
18 
19 /*
20  * $Id: linkfd.c,v 1.13.2.7 2016/10/01 21:27:51 mtbishop Exp $
21  */
22 
23 #include "config.h"
24 
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <signal.h>
29 #include <strings.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/time.h>
33 #include <syslog.h>
34 #include <time.h>
35 
36 #ifdef HAVE_SYS_RESOURCE_H
37 #include <sys/resource.h>
38 #endif
39 
40 #ifdef HAVE_SCHED_H
41 #include <sched.h>
42 #endif
43 
44 #ifdef HAVE_NETINET_IN_H
45 #include <netinet/in.h>
46 #endif
47 
48 #include "vtun.h"
49 #include "linkfd.h"
50 #include "lib.h"
51 #include "driver.h"
52 
53 /* used by lfd_encrypt */
54 int send_a_packet = 0;
55 
56 /* Host we are working with.
57  * Used by signal handlers that's why it is global.
58  */
59 static struct vtun_host *lfd_host;
60 
61 static struct lfd_mod *lfd_mod_head = NULL, *lfd_mod_tail = NULL;
62 
63 /* Modules functions*/
64 
65 /* Add module to the end of modules list */
lfd_add_mod(struct lfd_mod * mod)66 static void lfd_add_mod(struct lfd_mod *mod)
67 {
68      if( !lfd_mod_head ){
69         lfd_mod_head = lfd_mod_tail = mod;
70 	mod->next = mod->prev = NULL;
71      } else {
72         lfd_mod_tail->next = mod;
73         mod->prev = lfd_mod_tail;
74         mod->next = NULL;
75         lfd_mod_tail = mod;
76      }
77 }
78 
79 /*  Initialize and allocate each module */
lfd_alloc_mod(struct vtun_host * host)80 static int lfd_alloc_mod(struct vtun_host *host)
81 {
82      struct lfd_mod *mod = lfd_mod_head;
83 
84      while( mod ){
85         if( mod->alloc && (mod->alloc)(host) )
86 	   return 1;
87 	mod = mod->next;
88      }
89 
90      return 0;
91 }
92 
93 /* Free all modules */
lfd_free_mod(void)94 static int lfd_free_mod(void)
95 {
96      struct lfd_mod *mod = lfd_mod_head;
97 
98      while( mod ){
99         if( mod->free && (mod->free)() )
100 	   return 1;
101 	mod = mod->next;
102      }
103      lfd_mod_head = lfd_mod_tail = NULL;
104      return 0;
105 }
106 
107  /* Run modules down (from head to tail) */
lfd_run_down(int len,char * in,char ** out)108 static inline int lfd_run_down(int len, char *in, char **out)
109 {
110      register struct lfd_mod *mod;
111 
112      *out = in;
113      for(mod = lfd_mod_head; mod && len > 0; mod = mod->next )
114         if( mod->encode ){
115            len = (mod->encode)(len, in, out);
116            in = *out;
117         }
118      return len;
119 }
120 
121 /* Run modules up (from tail to head) */
lfd_run_up(int len,char * in,char ** out)122 static inline int lfd_run_up(int len, char *in, char **out)
123 {
124      register struct lfd_mod *mod;
125 
126      *out = in;
127      for(mod = lfd_mod_tail; mod && len > 0; mod = mod->prev )
128         if( mod->decode ){
129 	   len = (mod->decode)(len, in, out);
130            in = *out;
131 	}
132      return len;
133 }
134 
135 /* Check if modules are accepting the data(down) */
lfd_check_down(void)136 static inline int lfd_check_down(void)
137 {
138      register struct lfd_mod *mod;
139      int err = 1;
140 
141      for(mod = lfd_mod_head; mod && err > 0; mod = mod->next )
142         if( mod->avail_encode )
143            err = (mod->avail_encode)();
144      return err;
145 }
146 
147 /* Check if modules are accepting the data(up) */
lfd_check_up(void)148 static inline int lfd_check_up(void)
149 {
150      register struct lfd_mod *mod;
151      int err = 1;
152 
153      for(mod = lfd_mod_tail; mod && err > 0; mod = mod->prev)
154         if( mod->avail_decode )
155            err = (mod->avail_decode)();
156 
157      return err;
158 }
159 
160 /********** Linker *************/
161 /* Termination flag */
162 static volatile sig_atomic_t linker_term;
163 
sig_term(int sig)164 static void sig_term(int sig)
165 {
166      vtun_syslog(LOG_INFO, "Closing connection");
167      io_cancel();
168      linker_term = VTUN_SIG_TERM;
169 }
170 
sig_hup(int sig)171 static void sig_hup(int sig)
172 {
173      vtun_syslog(LOG_INFO, "Reestablishing connection");
174      io_cancel();
175      linker_term = VTUN_SIG_HUP;
176 }
177 
178 /* Statistic dump and keep-alive monitor */
179 static volatile sig_atomic_t ka_need_verify = 0;
180 static time_t stat_timer = 0, ka_timer = 0;
181 
sig_alarm(int sig)182 static void sig_alarm(int sig)
183 {
184      static time_t tm_old, tm = 0;
185      static char stm[20];
186 
187      tm_old = tm;
188      tm = time(NULL);
189 
190      if( (lfd_host->flags & VTUN_KEEP_ALIVE) && (ka_timer -= tm-tm_old) <= 0){
191 	ka_need_verify = 1;
192 	ka_timer = lfd_host->ka_interval
193 	  + 1; /* We have to complete select() on idle */
194      }
195 
196      if( (lfd_host->flags & VTUN_STAT) && (stat_timer -= tm-tm_old) <= 0){
197         strftime(stm, sizeof(stm)-1, "%b %d %H:%M:%S", localtime(&tm));
198         fprintf(lfd_host->stat.file,"%s %lu %lu %lu %lu\n", stm,
199 	   lfd_host->stat.byte_in, lfd_host->stat.byte_out,
200 	   lfd_host->stat.comp_in, lfd_host->stat.comp_out);
201 	stat_timer = VTUN_STAT_IVAL;
202      }
203 
204      if ( ka_timer*stat_timer ){
205        alarm( (ka_timer < stat_timer) ? ka_timer : stat_timer );
206      } else {
207        alarm( (ka_timer) ? ka_timer : stat_timer );
208      }
209 }
210 
sig_usr1(int sig)211 static void sig_usr1(int sig)
212 {
213      /* Reset statistic counters on SIGUSR1 */
214      lfd_host->stat.byte_in = lfd_host->stat.byte_out = 0;
215      lfd_host->stat.comp_in = lfd_host->stat.comp_out = 0;
216 }
217 
lfd_linker(void)218 static int lfd_linker(void)
219 {
220      int fd1 = lfd_host->rmt_fd;
221      int fd2 = lfd_host->loc_fd;
222      register int len, fl;
223      struct timeval tv;
224      char *buf, *out;
225      fd_set fdset;
226      int maxfd, idle = 0, tmplen;
227 
228      if( !(buf = lfd_alloc(VTUN_FRAME_SIZE + VTUN_FRAME_OVERHEAD)) ){
229 	vtun_syslog(LOG_ERR,"Can't allocate buffer for the linker");
230         return 0;
231      }
232 
233      /* Delay sending of first UDP packet over broken NAT routers
234 	because we will probably be disconnected.  Wait for the remote
235 	end to send us something first, and use that connection. */
236      if (!VTUN_USE_NAT_HACK(lfd_host))
237         proto_write(fd1, buf, VTUN_ECHO_REQ);
238 
239      maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
240 
241      linker_term = 0;
242      while( !linker_term ){
243 	errno = 0;
244 
245         /* Wait for data */
246         FD_ZERO(&fdset);
247 	FD_SET(fd1, &fdset);
248 	FD_SET(fd2, &fdset);
249 
250  	tv.tv_sec  = lfd_host->ka_interval;
251 	tv.tv_usec = 0;
252 
253 	if( (len = select(maxfd, &fdset, NULL, NULL, &tv)) < 0 ){
254 	   if( errno != EAGAIN && errno != EINTR )
255 	      break;
256 	   else
257 	      continue;
258 	}
259 
260 	if( ka_need_verify ){
261 	  if( idle > lfd_host->ka_maxfail ){
262 	    vtun_syslog(LOG_INFO,"Session %s network timeout", lfd_host->host);
263 	    break;
264 	  }
265 	  if (idle++ > 0) {  /* No input frames, check connection with ECHO */
266 	    if( proto_write(fd1, buf, VTUN_ECHO_REQ) < 0 ){
267 	      vtun_syslog(LOG_ERR,"Failed to send ECHO_REQ");
268 	      break;
269 	    }
270 	  }
271 	  ka_need_verify = 0;
272 	}
273 
274 	if (send_a_packet)
275         {
276            send_a_packet = 0;
277            tmplen = 1;
278 	   lfd_host->stat.byte_out += tmplen;
279 	   if( (tmplen=lfd_run_down(tmplen,buf,&out)) == -1 )
280 	      break;
281 	   if( tmplen && proto_write(fd1, out, tmplen) < 0 )
282 	      break;
283 	   lfd_host->stat.comp_out += tmplen;
284         }
285 
286 	/* Read frames from network(fd1), decode and pass them to
287          * the local device (fd2) */
288 	if( FD_ISSET(fd1, &fdset) && lfd_check_up() ){
289 	   idle = 0;  ka_need_verify = 0;
290 	   if( (len=proto_read(fd1, buf)) <= 0 )
291 	      break;
292 
293 	   /* Handle frame flags */
294 	   fl = len & ~VTUN_FSIZE_MASK;
295            len = len & VTUN_FSIZE_MASK;
296 	   if( fl ){
297 	      if( fl==VTUN_BAD_FRAME ){
298 		 vtun_syslog(LOG_ERR, "Received bad frame");
299 		 continue;
300 	      }
301 	      if( fl==VTUN_ECHO_REQ ){
302 		 /* Send ECHO reply */
303 	 	 if( proto_write(fd1, buf, VTUN_ECHO_REP) < 0 )
304 		    break;
305 		 continue;
306 	      }
307    	      if( fl==VTUN_ECHO_REP ){
308 		 /* Just ignore ECHO reply, ka_need_verify==0 already */
309 		 continue;
310 	      }
311 	      if( fl==VTUN_CONN_CLOSE ){
312 	         vtun_syslog(LOG_INFO,"Connection closed by other side");
313 		 break;
314 	      }
315 	   }
316 
317 	   lfd_host->stat.comp_in += len;
318 	   if( (len=lfd_run_up(len,buf,&out)) == -1 )
319 	      break;
320 	   if( len && dev_write(fd2,out,len) < 0 ){
321               if( errno != EAGAIN && errno != EINTR )
322                  break;
323               else
324                  continue;
325            }
326 	   lfd_host->stat.byte_in += len;
327 	}
328 
329 	/* Read data from the local device(fd2), encode and pass it to
330          * the network (fd1) */
331 	if( FD_ISSET(fd2, &fdset) && lfd_check_down() ){
332 	   if( (len = dev_read(fd2, buf, VTUN_FRAME_SIZE)) < 0 ){
333 	      if( errno != EAGAIN && errno != EINTR )
334 	         break;
335 	      else
336 		 continue;
337 	   }
338 	   if( !len ) break;
339 
340 	   lfd_host->stat.byte_out += len;
341 	   if( (len=lfd_run_down(len,buf,&out)) == -1 )
342 	      break;
343 	   if( len && proto_write(fd1, out, len) < 0 )
344 	      break;
345 	   lfd_host->stat.comp_out += len;
346 	}
347      }
348      if( !linker_term && errno )
349 	vtun_syslog(LOG_INFO,"%s (%d)", strerror(errno), errno);
350 
351      if (linker_term == VTUN_SIG_TERM) {
352        lfd_host->persist = 0;
353      }
354 
355      /* Notify other end about our close */
356      proto_write(fd1, buf, VTUN_CONN_CLOSE);
357      lfd_free(buf);
358 
359      return 0;
360 }
361 
362 /* Link remote and local file descriptors */
linkfd(struct vtun_host * host)363 int linkfd(struct vtun_host *host)
364 {
365      struct sigaction sa, sa_oldterm, sa_oldint, sa_oldhup;
366      int old_prio;
367 
368      lfd_host = host;
369 
370      old_prio=getpriority(PRIO_PROCESS,0);
371      setpriority(PRIO_PROCESS,0,LINKFD_PRIO);
372 
373      /* Build modules stack */
374      if(host->flags & VTUN_ZLIB)
375 	lfd_add_mod(&lfd_zlib);
376 
377      if(host->flags & VTUN_LZO)
378 	lfd_add_mod(&lfd_lzo);
379 
380      if(host->flags & VTUN_ENCRYPT)
381        if(host->cipher == VTUN_LEGACY_ENCRYPT) {
382 	 lfd_add_mod(&lfd_legacy_encrypt);
383        } else {
384 	 lfd_add_mod(&lfd_encrypt);
385        }
386 
387      if(host->flags & VTUN_SHAPE)
388 	lfd_add_mod(&lfd_shaper);
389 
390      if(lfd_alloc_mod(host))
391 	return 0;
392 
393      memset(&sa, 0, sizeof(sa));
394      sa.sa_handler=sig_term;
395      sigaction(SIGTERM,&sa,&sa_oldterm);
396      sigaction(SIGINT,&sa,&sa_oldint);
397      sa.sa_handler=sig_hup;
398      sigaction(SIGHUP,&sa,&sa_oldhup);
399 
400      /* Initialize keep-alive timer */
401      if( host->flags & (VTUN_STAT|VTUN_KEEP_ALIVE) ){
402         sa.sa_handler=sig_alarm;
403         sigaction(SIGALRM,&sa,NULL);
404 
405 	alarm( (host->ka_interval < VTUN_STAT_IVAL) ?
406 		host->ka_interval : VTUN_STAT_IVAL );
407      }
408 
409      /* Initialize statstic dumps */
410      if( host->flags & VTUN_STAT ){
411 	char file[40];
412 
413         sa.sa_handler=sig_alarm;
414         sigaction(SIGALRM,&sa,NULL);
415         sa.sa_handler=sig_usr1;
416         sigaction(SIGUSR1,&sa,NULL);
417 
418 	sprintf(file,"%s/%.20s", VTUN_STAT_DIR, host->host);
419 	if( (host->stat.file=fopen(file, "a")) ){
420 	   setvbuf(host->stat.file, NULL, _IOLBF, 0);
421 	} else
422 	   vtun_syslog(LOG_ERR, "Can't open stats file %s", file);
423      }
424 
425      io_init();
426 
427      lfd_linker();
428 
429      if( host->flags & (VTUN_STAT|VTUN_KEEP_ALIVE) ){
430         alarm(0);
431 	if (host->stat.file)
432 	  fclose(host->stat.file);
433      }
434 
435      lfd_free_mod();
436 
437      sigaction(SIGTERM,&sa_oldterm,NULL);
438      sigaction(SIGINT,&sa_oldint,NULL);
439      sigaction(SIGHUP,&sa_oldhup,NULL);
440 
441      setpriority(PRIO_PROCESS,0,old_prio);
442 
443      return linker_term;
444 }
445