xref: /dragonfly/usr.sbin/vknetd/vknetd.c (revision 2295495c)
1 /*
2  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * vknet [-cdU] [-b bridgeN] [-p socket_path] [-t tapN] [address/cidrbits]
36  *
37  * Create a named unix-domain socket which userland vkernels can open
38  * to gain access to a local network.  All connections to the socket
39  * are bridged together and the local network can also be bridged onto
40  * a TAP interface by specifying the -t option.
41  */
42 #include "vknetd.h"
43 
44 static ioinfo_t vknet_tap(const char *tapName, const char *bridgeName);
45 static int vknet_listener(const char *pathName);
46 static void vknet_acceptor(int net_fd);
47 static void *vknet_io(void *arg);
48 static int vknet_connect(const char *pathName);
49 static void vknet_monitor(int net_fd);
50 static void usage(void);
51 static void writepid(void);
52 static void cleanup(int);
53 
54 pthread_mutex_t BridgeMutex;
55 
56 int SecureOpt = 1;
57 int DebugOpt = 0;
58 int SetAddrOpt = 0;
59 const char *pidfile = "/var/run/vknetd.pid";
60 
61 struct in_addr NetAddress;
62 struct in_addr NetMask;
63 
64 int
65 main(int ac, char **av)
66 {
67 	const char *pathName = "/var/run/vknet";
68 	const char *tapName = "auto";
69 	const char *bridgeName = NULL;
70 	int net_fd;
71 	int connectOpt = 0;
72 	int c;
73 	ioinfo_t tap_info;
74 	pthread_t dummy_td;
75 
76 	while ((c = getopt(ac, av, "b:cdp:i:t:U")) != -1) {
77 		switch (c) {
78 		case 'U':
79 			SecureOpt = 0;
80 			break;
81 		case 'b':
82 			bridgeName = optarg;
83 			break;
84 		case 'd':
85 			DebugOpt = 1;
86 			break;
87 		case 'p':
88 			pathName = optarg;
89 			break;
90 		case 'i':
91 			pidfile = optarg;
92 			break;
93 		case 't':
94 			tapName = optarg;
95 			break;
96 		case 'c':
97 			connectOpt = 1;
98 			break;
99 		default:
100 			usage();
101 		}
102 	}
103 	av += optind;
104 	ac -= optind;
105 	if (ac)
106 		SetAddrOpt = 1;
107 
108 	/*
109 	 * Special connect/debug mode
110 	 */
111 	if (connectOpt) {
112 		net_fd = vknet_connect(pathName);
113 		if (net_fd < 0) {
114 			perror("connect");
115 			exit(1);
116 		}
117 		vknet_monitor(net_fd);
118 		exit(0);
119 	}
120 
121 	/*
122 	 * In secure mode (the default), a network address/mask must be
123 	 * specified.  e.g. 10.1.0.0/16.  Any traffic going out the TAP
124 	 * interface will be filtered.
125 	 *
126 	 * If non-secure mode the network address/mask is optional.
127 	 */
128 	if (SecureOpt || SetAddrOpt) {
129 		char *str;
130 		int masklen;
131 		u_int32_t mask;
132 
133 		if (ac == 0 || strchr(av[0], '/') == NULL)
134 			usage();
135 		str = strdup(av[0]);
136 		if (inet_pton(AF_INET, strtok(str, "/"), &NetAddress) <= 0)
137 			usage();
138 		masklen = strtoul(strtok(NULL, "/"), NULL, 10);
139 		mask = (1 << (32 - masklen)) - 1;
140 		NetMask.s_addr = htonl(~mask);
141 	}
142 
143 	/*
144 	 * Normal operation, create the tap/bridge and listener.  This
145 	 * part is not threaded.
146 	 */
147 	mac_init();
148 
149 	if ((tap_info = vknet_tap(tapName, bridgeName)) == NULL) {
150 		perror("tap: ");
151 		exit(1);
152 	}
153 	if ((net_fd = vknet_listener(pathName)) < 0) {
154 		perror("listener: ");
155 		exit(1);
156 	}
157 
158 	/*
159 	 * Now make us a demon and start the threads going.
160 	 */
161 	if (DebugOpt == 0)
162 		daemon(1, 0);
163 
164 	writepid();
165 
166 	signal(SIGINT, cleanup);
167 	signal(SIGHUP, cleanup);
168 	signal(SIGTERM, cleanup);
169 
170 	pthread_mutex_init(&BridgeMutex, NULL);
171 	pthread_create(&dummy_td, NULL, vknet_io, tap_info);
172 	vknet_acceptor(net_fd);
173 
174 	exit(0);
175 }
176 
177 #define TAPDEV_MINOR(x) ((int)((x) & 0xffff00ff))
178 
179 static ioinfo_t
180 vknet_tap(const char *tapName, const char *bridgeName)
181 {
182 	struct ifreq ifr;
183 	struct ifaliasreq ifra;
184 	struct stat st;
185 	char *buf = NULL;
186 	int tap_fd;
187 	int tap_unit;
188 	int i;
189 	int s;
190 	int flags;
191 	ioinfo_t info;
192 
193 	if (strcmp(tapName, "auto") == 0) {
194 		for (i = 0; ; ++i) {
195 			asprintf(&buf, "/dev/tap%d", i);
196 			tap_fd = open(buf, O_RDWR | O_NONBLOCK);
197 			free(buf);
198 			if (tap_fd >= 0 || errno == ENOENT)
199 				break;
200 		}
201 	} else if (strncmp(tapName, "tap", 3) == 0) {
202 		asprintf(&buf, "/dev/%s", tapName);
203 		tap_fd = open(buf, O_RDWR | O_NONBLOCK);
204 		free(buf);
205 	} else {
206 		tap_fd = open(tapName, O_RDWR | O_NONBLOCK);
207 	}
208 	if (tap_fd < 0)
209 		return(NULL);
210 
211 	/*
212 	 * Figure out the tap unit number
213 	 */
214 	if (fstat(tap_fd, &st) < 0) {
215 		close(tap_fd);
216 		return(NULL);
217 	}
218 	tap_unit = TAPDEV_MINOR(st.st_rdev);
219 
220 	/*
221 	 * Setup for ioctls
222 	 */
223 	fcntl(tap_fd, F_SETFL, 0);
224 	bzero(&ifr, sizeof(ifr));
225 	bzero(&ifra, sizeof(ifra));
226 	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
227 	snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "tap%d", tap_unit);
228 
229 	s = socket(AF_INET, SOCK_DGRAM, 0);
230 
231 	/*
232 	 * Set the interface address if in Secure mode.
233 	 */
234 	if (SetAddrOpt) {
235 		struct sockaddr_in *in;
236 
237 		in = (void *)&ifra.ifra_addr;
238 		in->sin_family = AF_INET;
239 		in->sin_len = sizeof(ifra.ifra_addr);
240 		in->sin_addr = NetAddress;
241 		in = (void *)&ifra.ifra_mask;
242 		in->sin_family = AF_INET;
243 		in->sin_len = sizeof(ifra.ifra_mask);
244 		in->sin_addr = NetMask;
245 		if (ioctl(s, SIOCAIFADDR, &ifra) < 0) {
246 			perror("Unable to set address on tap interface");
247 			exit(1);
248 		}
249 	}
250 
251 	/*
252 	 * Turn up the interface
253 	 */
254 	flags = IFF_UP;
255 	if (ioctl(s, SIOCGIFFLAGS, &ifr) >= 0) {
256 		bzero(&ifr, sizeof(ifr));
257 		snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
258 		ifr.ifr_flags |= flags & 0xFFFF;
259 		ifr.ifr_flagshigh |= flags >> 16;
260 		if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
261 			perror("Unable to set IFF_UP on tap interface");
262 			exit(1);
263 		}
264 	}
265 
266 	if (bridgeName) {
267 		struct ifbreq ifbr;
268 		struct ifdrv ifd;
269 
270 		/*
271 		 * Create the bridge if necessary.
272 		 */
273 		bzero(&ifr, sizeof(ifr));
274 		snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", bridgeName);
275 		if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
276 			if (errno != EEXIST) {
277 				perror("Unable to create bridge interface");
278 				exit(1);
279 			}
280 		}
281 
282 
283 		/*
284 		 * Add the tap interface to the bridge
285 		 */
286 		bzero(&ifbr, sizeof(ifbr));
287 		snprintf(ifbr.ifbr_ifsname, sizeof(ifbr.ifbr_ifsname),
288 			 "tap%d", tap_unit);
289 
290 		bzero(&ifd, sizeof(ifd));
291 		snprintf(ifd.ifd_name, sizeof(ifd.ifd_name), "%s", bridgeName);
292 		ifd.ifd_cmd = BRDGADD;
293 		ifd.ifd_len = sizeof(ifbr);
294 		ifd.ifd_data = &ifbr;
295 
296 		if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
297 			if (errno != EEXIST) {
298 				perror("Unable to add tap ifc to bridge!");
299 				exit(1);
300 			}
301 		}
302 	}
303 
304 	close(s);
305 	info = malloc(sizeof(*info));
306 	bzero(info, sizeof(*info));
307 	info->fd = tap_fd;
308 	info->istap = 1;
309 	return(info);
310 }
311 
312 #undef TAPDEV_MINOR
313 
314 static int
315 vknet_listener(const char *pathName)
316 {
317 	struct sockaddr_un sunx;
318 	int net_fd;
319 	int len;
320 	gid_t gid;
321 	struct group *grp;
322 
323 	/*
324 	 * Group access to our named unix domain socket.
325 	 */
326 	if ((grp = getgrnam("vknet")) == NULL) {
327 		fprintf(stderr, "The 'vknet' group must exist\n");
328 		exit(1);
329 	}
330 	gid = grp->gr_gid;
331 	endgrent();
332 
333 	/*
334 	 * Socket setup
335 	 */
336 	snprintf(sunx.sun_path, sizeof(sunx.sun_path), "%s", pathName);
337 	len = offsetof(struct sockaddr_un, sun_path[strlen(sunx.sun_path)]);
338 	++len;	/* include nul */
339 	sunx.sun_family = AF_UNIX;
340 	sunx.sun_len = len;
341 
342 	net_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
343 	if (net_fd < 0)
344 		return(-1);
345 	remove(pathName);
346 	if (bind(net_fd, (void *)&sunx, len) < 0) {
347 		close(net_fd);
348 		return(-1);
349 	}
350 	if (listen(net_fd, 1024) < 0) {
351 		close(net_fd);
352 		return(-1);
353 	}
354 	if (chown(pathName, (uid_t)-1, gid) < 0) {
355 		close(net_fd);
356 		return(-1);
357 	}
358 	if (chmod(pathName, 0660) < 0) {
359 		close(net_fd);
360 		return(-1);
361 	}
362 	return(net_fd);
363 }
364 
365 static
366 void
367 vknet_acceptor(int net_fd)
368 {
369 	struct sockaddr_un sunx;
370 	pthread_t dummy_td;
371 	int sunx_len;
372 	int rfd;
373 	ioinfo_t info;
374 
375 	for (;;) {
376 		sunx_len = sizeof(sunx);
377 		rfd = accept(net_fd, (void *)&sunx, &sunx_len);
378 		if (rfd < 0)
379 			break;
380 		info = malloc(sizeof(*info));
381 		bzero(info, sizeof(*info));
382 		info->fd = rfd;
383 		info->istap = 0;
384 		pthread_create(&dummy_td, NULL, vknet_io, info);
385 	}
386 }
387 
388 /*
389  * This I/O thread implements the core of the bridging code.
390  */
391 static
392 void *
393 vknet_io(void *arg)
394 {
395 	ioinfo_t info = arg;
396 	bridge_t bridge;
397 	u_int8_t *pkt;
398 	int bytes;
399 
400 	pthread_detach(pthread_self());
401 
402 	/*
403 	 * Assign as a bridge slot using our thread id.
404 	 */
405 	pthread_mutex_lock(&BridgeMutex);
406 	bridge = bridge_add(info);
407 	pthread_mutex_unlock(&BridgeMutex);
408 
409 	/*
410 	 * Read packet loop.  Writing is handled by the bridge code.
411 	 */
412 	pkt = malloc(MAXPKT);
413 	while ((bytes = read(info->fd, pkt, MAXPKT)) > 0) {
414 		pthread_mutex_lock(&BridgeMutex);
415 		bridge_packet(bridge, pkt, bytes);
416 		pthread_mutex_unlock(&BridgeMutex);
417 	}
418 
419 	/*
420 	 * Cleanup
421 	 */
422 	pthread_mutex_lock(&BridgeMutex);
423 	bridge_del(bridge);
424 	pthread_mutex_unlock(&BridgeMutex);
425 
426 	close(info->fd);
427 	free(pkt);
428 	pthread_exit(NULL);
429 }
430 
431 /*
432  * Debugging
433  */
434 static int
435 vknet_connect(const char *pathName)
436 {
437 	struct sockaddr_un sunx;
438 	int len;
439 	int net_fd;
440 
441 	snprintf(sunx.sun_path, sizeof(sunx.sun_path), "%s", pathName);
442 	len = offsetof(struct sockaddr_un, sun_path[strlen(sunx.sun_path)]);
443 	++len;	/* include nul */
444 	sunx.sun_family = AF_UNIX;
445 	sunx.sun_len = len;
446 
447 	net_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
448 	if (net_fd < 0)
449 		return(-1);
450 	if (connect(net_fd, (void *)&sunx, len) < 0) {
451 		close(net_fd);
452 		return(-1);
453 	}
454 	return(net_fd);
455 }
456 
457 static void
458 vknet_monitor(int net_fd)
459 {
460 	u_int8_t *pkt;
461 	int bytes;
462 	int i;
463 
464 	pkt = malloc(MAXPKT);
465 	while ((bytes = read(net_fd, pkt, MAXPKT)) > 0) {
466 		printf("%02x:%02x:%02x:%02x:%02x:%02x <- "
467 		       "%02x:%02x:%02x:%02x:%02x:%02x",
468 		       pkt[0], pkt[1], pkt[2], pkt[3], pkt[4], pkt[5],
469 		       pkt[6], pkt[7], pkt[8], pkt[9], pkt[10], pkt[11]);
470 		for (i = 12; i < bytes; ++i) {
471 			if (((i - 12) & 15) == 0) {
472 				printf("\n\t");
473 			}
474 			printf(" %02x", pkt[i]);
475 		}
476 		printf("\n");
477 	}
478 	free(pkt);
479 }
480 
481 /*
482  * Misc
483  */
484 static void
485 writepid(void)
486 {
487 	FILE *pf;
488 
489 	if ((pf = fopen(pidfile, "w+")) == NULL)
490 		errx(1, "Failed to create pidfile %s", pidfile);
491 
492 	if ((fprintf(pf, "%d\n", getpid())) < 1)
493 		err(1, "fprintf");
494 
495 	fclose(pf);
496 }
497 
498 static void
499 cleanup(int __unused sig)
500 {
501 	if (pidfile)
502 		unlink(pidfile);
503 }
504 
505 static
506 void
507 usage(void)
508 {
509 	fprintf(stderr, "usage: vknet [-cdU] [-b bridgeN] [-p socket_path] [-i pidfile] [-t tapN] [address/cidrbits]\n");
510 	fprintf(stderr, "address/cidrbits must be specified in default secure mode.\n");
511 	exit(1);
512 }
513 
514