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: tunnel.c,v 1.14.2.4 2016/10/01 21:27:51 mtbishop Exp $
21  */
22 
23 #include "config.h"
24 
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stdarg.h>
32 #include <sys/time.h>
33 #include <sys/wait.h>
34 #include <syslog.h>
35 #include <signal.h>
36 
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40 
41 #ifdef HAVE_NETINET_IN_SYSTM_H
42 #include <netinet/in_systm.h>
43 #endif
44 
45 #ifdef HAVE_NETINET_IP_H
46 #include <netinet/ip.h>
47 #endif
48 
49 #ifdef HAVE_NETINET_TCP_H
50 #include <netinet/tcp.h>
51 #endif
52 
53 #include "vtun.h"
54 #include "linkfd.h"
55 #include "lib.h"
56 #include "netlib.h"
57 #include "driver.h"
58 
59 int (*dev_write)(int fd, char *buf, int len);
60 int (*dev_read)(int fd, char *buf, int len);
61 
62 int (*proto_write)(int fd, char *buf, int len);
63 int (*proto_read)(int fd, char *buf);
64 
65 /* Initialize and start the tunnel.
66    Returns:
67       -1 - critical error
68       0  - normal close or noncritical error
69 */
70 
tunnel(struct vtun_host * host)71 int tunnel(struct vtun_host *host)
72 {
73      int null_fd, pid, opt;
74      int fd[2]={-1, -1};
75      char dev[VTUN_DEV_LEN]="";
76      int interface_already_open = 0;
77 
78      if ( (host->persist == VTUN_PERSIST_KEEPIF) &&
79 	  (host->loc_fd >= 0) )
80         interface_already_open = 1;
81 
82      /* Initialize device. */
83      if( host->dev ){
84         strncpy(dev, host->dev, VTUN_DEV_LEN);
85 	dev[VTUN_DEV_LEN-1]='\0';
86      }
87      if( ! interface_already_open ){
88         switch( host->flags & VTUN_TYPE_MASK ){
89            case VTUN_TTY:
90 	      if( (fd[0]=pty_open(dev)) < 0 ){
91 		 vtun_syslog(LOG_ERR,"Can't allocate pseudo tty. %s(%d)", strerror(errno), errno);
92 		 return -1;
93 	      }
94 	      break;
95 
96            case VTUN_PIPE:
97 	      if( pipe_open(fd) < 0 ){
98 		 vtun_syslog(LOG_ERR,"Can't create pipe. %s(%d)", strerror(errno), errno);
99 		 return -1;
100 	      }
101 	      break;
102 
103            case VTUN_ETHER:
104 	      if( (fd[0]=tap_open(dev)) < 0 ){
105 		 vtun_syslog(LOG_ERR,"Can't allocate tap device %s. %s(%d)", dev, strerror(errno), errno);
106 		 return -1;
107 	      }
108 	      break;
109 
110 	   case VTUN_TUN:
111 	      if( (fd[0]=tun_open(dev)) < 0 ){
112 		 vtun_syslog(LOG_ERR,"Can't allocate tun device %s. %s(%d)", dev, strerror(errno), errno);
113 		 return -1;
114 	      }
115 	      break;
116 	}
117 	host->loc_fd = fd[0];
118      }
119      host->sopt.dev = strdup(dev);
120 
121      /* Initialize protocol. */
122      switch( host->flags & VTUN_PROT_MASK ){
123         case VTUN_TCP:
124 	   opt=1;
125 	   setsockopt(host->rmt_fd,SOL_SOCKET,SO_KEEPALIVE,&opt,sizeof(opt) );
126 
127 	   opt=1;
128 	   setsockopt(host->rmt_fd,IPPROTO_TCP,TCP_NODELAY,&opt,sizeof(opt) );
129 
130 	   proto_write = tcp_write;
131 	   proto_read  = tcp_read;
132 
133 	   break;
134 
135         case VTUN_UDP:
136 	   if( (opt = udp_session(host)) == -1){
137 	      vtun_syslog(LOG_ERR,"Can't establish UDP session");
138 	      close(fd[1]);
139 	      if( ! ( host->persist == VTUN_PERSIST_KEEPIF ) )
140 		 close(fd[0]);
141 	      return 0;
142 	   }
143 
144  	   proto_write = udp_write;
145 	   proto_read = udp_read;
146 
147 	   break;
148      }
149 
150 #ifdef HAVE_WORKING_FORK
151         switch( (pid=fork()) ){
152 	   case -1:
153 	      vtun_syslog(LOG_ERR,"Couldn't fork()");
154 	      if( ! ( host->persist == VTUN_PERSIST_KEEPIF ) )
155 		 close(fd[0]);
156 	      close(fd[1]);
157 	      return 0;
158  	   case 0:
159            /* do this only the first time when in persist = keep mode */
160            if( ! interface_already_open ){
161 	      switch( host->flags & VTUN_TYPE_MASK ){
162 	         case VTUN_TTY:
163 		    /* Open pty slave (becomes controlling terminal) */
164 		    if( (fd[1] = open(dev, O_RDWR)) < 0){
165 		       vtun_syslog(LOG_ERR,"Couldn't open slave pty");
166 		       exit(0);
167 		    }
168 		    /* Fall through */
169 	         case VTUN_PIPE:
170 		    null_fd = open("/dev/null", O_RDWR);
171 		    close(fd[0]);
172 		    close(0); dup(fd[1]);
173 		    close(1); dup(fd[1]);
174 		    close(fd[1]);
175 
176 		    /* Route stderr to /dev/null */
177 		    close(2); dup(null_fd);
178 		    close(null_fd);
179 		    break;
180 	         case VTUN_ETHER:
181 	         case VTUN_TUN:
182 		    break;
183 	      }
184            }
185 	   /* Run list of up commands */
186 	   set_title("%s running up commands", host->host);
187 	   llist_trav(&host->up, run_cmd, &host->sopt);
188 
189 	   exit(0);
190 	}
191 #else
192      vtun_syslog(LOG_ERR,"Couldn't run up commands: fork() not available");
193 #endif
194 
195      switch( host->flags & VTUN_TYPE_MASK ){
196         case VTUN_TTY:
197 	   set_title("%s tty", host->host);
198 
199 	   dev_read  = pty_read;
200 	   dev_write = pty_write;
201 	   break;
202 
203         case VTUN_PIPE:
204 	   /* Close second end of the pipe */
205 	   close(fd[1]);
206 	   set_title("%s pipe", host->host);
207 
208 	   dev_read  = pipe_read;
209 	   dev_write = pipe_write;
210 	   break;
211 
212         case VTUN_ETHER:
213 	   set_title("%s ether %s", host->host, dev);
214 
215 	   dev_read  = tap_read;
216 	   dev_write = tap_write;
217 	   break;
218 
219         case VTUN_TUN:
220 	   set_title("%s tun %s", host->host, dev);
221 
222 	   dev_read  = tun_read;
223 	   dev_write = tun_write;
224 	   break;
225      }
226 
227      opt = linkfd(host);
228 
229 #ifdef HAVE_WORKING_FORK
230      set_title("%s running down commands", host->host);
231      llist_trav(&host->down, run_cmd, &host->sopt);
232 #else
233      vtun_syslog(LOG_ERR,"Couldn't run down commands: fork() not available");
234 #endif
235 
236      if(! ( host->persist == VTUN_PERSIST_KEEPIF ) ) {
237         set_title("%s closing", host->host);
238 
239 	/* Gracefully destroy interface */
240 	switch( host->flags & VTUN_TYPE_MASK ){
241            case VTUN_TUN:
242 	      tun_close(fd[0], dev);
243 	      break;
244 
245            case VTUN_ETHER:
246 	      tap_close(fd[0], dev);
247 	      break;
248 	}
249 
250        	close(host->loc_fd);
251      }
252 
253      /* Close all other fds */
254      close(host->rmt_fd);
255      close(fd[1]);
256 
257      return opt;
258 }
259