1 /* Copyright 2006 Renzo Davoli
2  * from vde_plug Davoli Gardenghi
3  * Modified 2010 Renzo Davoli, vdestream added
4  * Licensed under the GPLv2
5  */
6 
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <signal.h>
12 #include <syslog.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <stdarg.h>
19 #include <syslog.h>
20 #include <libgen.h>
21 #define _GNU_SOURCE
22 #include <getopt.h>
23 #include <limits.h>
24 
25 #include <config.h>
26 #include <vde.h>
27 #include <vdecommon.h>
28 #include <libvdeplug.h>
29 
30 #define BUFSIZE 2048
31 
32 #ifdef VDE_LINUX
33 #include <net/if.h>
34 #include <linux/if_tun.h>
35 #endif
36 
37 #ifdef VDE_FREEBSD
38 #include <sys/socket.h>
39 #include <net/if.h>
40 #include <net/tun/if_tun.h>
41 #endif
42 
43 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
44 #	define TAP_PREFIX "/dev/"
45 #	if defined HAVE_SYSLIMITS_H
46 #		include <syslimits.h>
47 #	elif defined HAVE_SYS_SYSLIMITS_H
48 #		include <sys/syslimits.h>
49 #	else
50 #		error "No syslimits.h found"
51 #	endif
52 #endif
53 
54 VDECONN *conn;
55 VDESTREAM *vdestream;
56 
57 char *prog;
58 int logok;
59 static char *pidfile = NULL;
60 static char pidfile_path[PATH_MAX];
61 
printlog(int priority,const char * format,...)62 void printlog(int priority, const char *format, ...)
63 {
64 	va_list arg;
65 
66 	va_start (arg, format);
67 
68 	if (logok)
69 		vsyslog(priority,format,arg);
70 	else {
71 		fprintf(stderr,"%s: ",prog);
72 		vfprintf(stderr,format,arg);
73 		fprintf(stderr,"\n");
74 	}
75 	va_end (arg);
76 }
77 
cleanup(void)78 static void cleanup(void)
79 {
80 	if((pidfile != NULL) && unlink(pidfile_path) < 0) {
81 		printlog(LOG_WARNING,"Couldn't remove pidfile '%s': %s", pidfile, strerror(errno));
82 	}
83 
84 	if (vdestream != NULL)
85 		vdestream_close(vdestream);
86 	if (conn != NULL)
87 		vde_close(conn);
88 }
89 
sig_handler(int sig)90 static void sig_handler(int sig)
91 {
92 	cleanup();
93 	signal(sig, SIG_DFL);
94 	if (sig == SIGTERM)
95 		_exit(0);
96 	else
97 		kill(getpid(), sig);
98 }
99 
setsighandlers()100 static void setsighandlers()
101 {
102 	/* setting signal handlers.
103 	 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
104 	 * ignores all the others signals which could cause termination. */
105 	struct { int sig; const char *name; int ignore; } signals[] = {
106 		{ SIGHUP, "SIGHUP", 0 },
107 		{ SIGINT, "SIGINT", 0 },
108 		{ SIGPIPE, "SIGPIPE", 1 },
109 		{ SIGALRM, "SIGALRM", 1 },
110 		{ SIGTERM, "SIGTERM", 0 },
111 		{ SIGUSR1, "SIGUSR1", 1 },
112 		{ SIGUSR2, "SIGUSR2", 1 },
113 		{ SIGPROF, "SIGPROF", 1 },
114 		{ SIGVTALRM, "SIGVTALRM", 1 },
115 #ifdef VDE_LINUX
116 		{ SIGPOLL, "SIGPOLL", 1 },
117 #ifdef SIGSTKFLT
118 		{ SIGSTKFLT, "SIGSTKFLT", 1 },
119 #endif
120 		{ SIGIO, "SIGIO", 1 },
121 		{ SIGPWR, "SIGPWR", 1 },
122 #ifdef SIGUNUSED
123 		{ SIGUNUSED, "SIGUNUSED", 1 },
124 #endif
125 #endif
126 #ifdef VDE_DARWIN
127 		{ SIGXCPU, "SIGXCPU", 1 },
128 		{ SIGXFSZ, "SIGXFSZ", 1 },
129 #endif
130 		{ 0, NULL, 0 }
131 	};
132 
133 	int i;
134 	for(i = 0; signals[i].sig != 0; i++)
135 		if(signal(signals[i].sig,
136 					signals[i].ignore ? SIG_IGN : sig_handler) < 0)
137 			perror("Setting handler");
138 }
139 
usage(void)140 static void usage(void) {
141 	fprintf(stderr, "Usage: %s [OPTION]... tap_name\n\n", prog);
142 	fprintf(stderr, "  -p, --port=portnum          Port number in the VDE switch\n"
143 			        "  -g, --group=group           Group for the socket\n"
144 					"  -m, --mode=mode             Octal mode for the socket\n"
145 					"  -s, --sock=socket           VDE switch control socket or dir\n"
146 					"  -d, --daemon                Launch in background\n"
147 					"  -P, --pidfile=pidfile       Create pidfile with our PID\n"
148 					"  -h, --help                  This help\n");
149 	exit(-1);
150 }
151 
152 #ifdef VDE_LINUX
open_tap(char * dev)153 int open_tap(char *dev)
154 {
155 	struct ifreq ifr;
156 	int fd;
157 
158 	if((fd = open("/dev/net/tun", O_RDWR)) < 0){
159 		printlog(LOG_ERR,"Failed to open /dev/net/tun %s",strerror(errno));
160 		return(-1);
161 	}
162 	memset(&ifr, 0, sizeof(ifr));
163 	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
164 	strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
165 	/*printf("dev=\"%s\", ifr.ifr_name=\"%s\"\n", ifr.ifr_name, dev);*/
166 	if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0){
167 		printlog(LOG_ERR,"TUNSETIFF failed %s",strerror(errno));
168 		close(fd);
169 		return(-1);
170 	}
171 	return(fd);
172 }
173 #endif
174 
175 #if defined(VDE_DARWIN) || defined(VDE_FREEBSD)
open_tap(char * dev)176 int open_tap(char *dev)
177 {
178 	int fd;
179 	int prefixlen = strlen(TAP_PREFIX);
180 	char *path = NULL;
181 	if (*dev == '/')
182 		fd=open(dev, O_RDWR);
183 	else
184 	{
185 		path = malloc(strlen(dev) + prefixlen + 1);
186 		if (path != NULL)
187 		{
188 			snprintf(path, strlen(dev) + prefixlen + 1, "%s%s", TAP_PREFIX, dev);
189 			fd=open(path, O_RDWR);
190 			free(path);
191 		}
192 		else
193 			fd = -1;
194 	}
195 
196 	if (fd < 0)
197 	{
198 		printlog(LOG_ERR,"Failed to open tap device %s: %s", (*dev == '/') ? dev : path, strerror(errno));
199 		return(-1);
200 	}
201 	return fd;
202 }
203 #endif
204 
205 unsigned char bufin[BUFSIZE];
206 
save_pidfile()207 static void save_pidfile()
208 {
209 	if(pidfile[0] != '/')
210 		strncat(pidfile_path, pidfile, PATH_MAX - strlen(pidfile_path));
211 	else
212 		strcpy(pidfile_path, pidfile);
213 
214 	int fd = open(pidfile_path,
215 			O_WRONLY | O_CREAT | O_EXCL,
216 			S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
217 	FILE *f;
218 
219 	if(fd == -1) {
220 		printlog(LOG_ERR, "Error in pidfile creation: %s", strerror(errno));
221 		exit(1);
222 	}
223 
224 	if((f = fdopen(fd, "w")) == NULL) {
225 		printlog(LOG_ERR, "Error in FILE* construction: %s", strerror(errno));
226 		exit(1);
227 	}
228 
229 	if(fprintf(f, "%ld\n", (long int)getpid()) <= 0) {
230 		printlog(LOG_ERR, "Error in writing pidfile");
231 		exit(1);
232 	}
233 
234 	fclose(f);
235 }
236 
vde_plug2tap_recv(void * opaque,void * buf,size_t count)237 static ssize_t vde_plug2tap_recv(void *opaque, void *buf, size_t count)
238 {
239 	int *tapfdp=opaque;
240 	return write(*tapfdp,buf,count);
241 }
242 
main(int argc,char ** argv)243 int main(int argc, char **argv)
244 {
245 	static char *sockname=NULL;
246 	static char *tapname=NULL;
247 	int daemonize=0;
248 	int tapfd;
249 	register ssize_t nx;
250 	struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
251 	int c;
252 	static struct pollfd pollv[]={{0,POLLIN|POLLHUP},
253 		{0,POLLIN|POLLHUP},
254 		{0,POLLIN|POLLHUP}};
255 	int npollv;
256 
257 	prog=argv[0];
258 	while (1) {
259 		int option_index = 0;
260 
261 		static struct option long_options[] = {
262 			{"sock", 1, 0, 's'},
263 			{"port", 1, 0, 'p'},
264 			{"help",0,0,'h'},
265 			{"mod",1,0,'m'},
266 			{"group",1,0,'g'},
267 			{"daemon",0,0,'d'},
268 			{"pidfile", 1, 0, 'P'},
269 			{0, 0, 0, 0}
270 		};
271 		c = GETOPT_LONG (argc, argv, "hdP:p:s:m:g:",
272 				long_options, &option_index);
273 		if (c == -1)
274 			break;
275 
276 		switch (c) {
277 			case 'p':
278 				open_args.port=atoi(optarg);
279 				if (open_args.port <= 0)
280 					usage(); //implies exit
281 				break;
282 
283 			case 'h':
284 				usage(); //implies exit
285 				break;
286 
287 			case 's':
288 				sockname=strdup(optarg);
289 				break;
290 
291 			case 'm':
292 				sscanf(optarg,"%o",(unsigned int *)&(open_args.mode));
293 				break;
294 
295 			case 'g':
296 				open_args.group=strdup(optarg);
297 				break;
298 
299 			case 'd':
300 				daemonize=1;
301 				break;
302 
303 			case 'P':
304 				pidfile=strdup(optarg);
305 				break;
306 
307 			default:
308 				usage(); //implies exit
309 		}
310 	}
311 
312 	if (daemonize) {
313 		openlog(basename(prog), LOG_PID, 0);
314 		logok=1;
315 		syslog(LOG_INFO,"VDE_PLUG2TAP started");
316 	}
317 	/* saves current path in pidfile_path, because otherwise with daemonize() we
318 	 * forget it */
319 	if(getcwd(pidfile_path, PATH_MAX-1) == NULL) {
320 		printlog(LOG_ERR, "getcwd: %s", strerror(errno));
321 		exit(1);
322 	}
323 	strcat(pidfile_path, "/");
324 	if (daemonize && daemon(0, 0)) {
325 		printlog(LOG_ERR,"daemon: %s",strerror(errno));
326 		exit(1);
327 	}
328 
329 	/* once here, we're sure we're the true process which will continue as a
330 	 * server: save PID file if needed */
331 	if(pidfile) save_pidfile();
332 
333 	if (optind < argc)
334 		tapname=argv[optind];
335 	else
336 		usage(); // implies exit
337 
338 	atexit(cleanup);
339 	setsighandlers();
340 
341 	tapfd=open_tap(tapname);
342 	if(tapfd<0)
343 		exit(1);
344 	pollv[0].fd=tapfd;
345 
346 	if (sockname==NULL || strcmp(sockname,"-") != 0) {
347 		conn=vde_open(sockname,"vde_plug:",&open_args);
348 		if (conn == NULL)
349 			exit(1);
350 		pollv[1].fd=vde_datafd(conn);
351 		pollv[2].fd=vde_ctlfd(conn);
352 		npollv=3;
353 	} else {
354 		vdestream=vdestream_open(&tapfd,STDOUT_FILENO,vde_plug2tap_recv,NULL);
355 		if (vdestream == NULL)
356 			exit(1);
357 		pollv[1].fd=STDIN_FILENO;
358 		npollv=2;
359 	}
360 
361 	for(;;) {
362 		poll(pollv,3,-1);
363 		if ((pollv[0].revents | pollv[1].revents | pollv[2].revents) & POLLHUP ||
364 				(npollv > 2 && pollv[2].revents & POLLIN))
365 			break;
366 		if (pollv[0].revents & POLLIN) {
367 			nx=read(tapfd,bufin,sizeof(bufin));
368 			/* if POLLIN but not data it means that the stream has been
369 			 * closed at the other end */
370 			//fprintf(stderr,"%s: RECV %d %x %x \n",prog,nx,bufin[0],bufin[1]);
371 			if (nx<=0)
372 				break;
373 			if (conn != NULL)
374 				vde_send(conn,bufin,nx,0);
375 			else
376 				vdestream_send(vdestream, bufin, nx);
377 		}
378 		if (pollv[1].revents & POLLIN) {
379 			if (conn != NULL) {
380 				nx=vde_recv(conn,bufin,sizeof(bufin),0);
381 				if (nx<=0)
382 					break;
383 				write(tapfd,bufin,nx);
384 			} else {
385 				nx=read(STDIN_FILENO,bufin,sizeof(bufin));
386 				if (nx<=0)
387 					break;
388 				vdestream_recv(vdestream,bufin,nx);
389 			}
390 			//fprintf(stderr,"%s: SENT %d %x %x \n",prog,nx,bufin[0],bufin[1]);
391 		}
392 
393 	}
394 	return(0);
395 }
396