vknetd - Fix a bug in previous commit.
[dragonfly.git] / usr.sbin / vknetd / vknetd.c
blob22e7581a9ca5cda9726e26121d075ca1cf7e0e42
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:
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.
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.
35 * vknet [-cdU] [-b bridgeN] [-p socket_path] [-t tapN] [address/cidrbits]
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.
42 #include "vknetd.h"
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);
54 pthread_mutex_t BridgeMutex;
56 int SecureOpt = 1;
57 int DebugOpt = 0;
58 int SetAddrOpt = 0;
59 const char *pidfile = "/var/run/vknetd.pid";
61 struct in_addr NetAddress;
62 struct in_addr NetMask;
64 int
65 main(int ac, char **av)
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;
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();
103 av += optind;
104 ac -= optind;
105 if (ac)
106 SetAddrOpt = 1;
109 * Special connect/debug mode
111 if (connectOpt) {
112 net_fd = vknet_connect(pathName);
113 if (net_fd < 0) {
114 perror("connect");
115 exit(1);
117 vknet_monitor(net_fd);
118 exit(0);
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.
126 * If non-secure mode the network address/mask is optional.
128 if (SecureOpt || SetAddrOpt) {
129 char *str;
130 int masklen;
131 u_int32_t mask;
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);
144 * Normal operation, create the tap/bridge and listener. This
145 * part is not threaded.
147 mac_init();
149 if ((tap_info = vknet_tap(tapName, bridgeName)) == NULL) {
150 perror("tap: ");
151 exit(1);
153 if ((net_fd = vknet_listener(pathName)) < 0) {
154 perror("listener: ");
155 exit(1);
159 * Now make us a demon and start the threads going.
161 if (DebugOpt == 0)
162 daemon(1, 0);
164 writepid();
166 signal(SIGINT, cleanup);
167 signal(SIGHUP, cleanup);
168 signal(SIGTERM, cleanup);
170 pthread_mutex_init(&BridgeMutex, NULL);
171 pthread_create(&dummy_td, NULL, vknet_io, tap_info);
172 vknet_acceptor(net_fd);
174 exit(0);
177 #define TAPDEV_MINOR(x) ((int)((x) & 0xffff00ff))
179 static ioinfo_t
180 vknet_tap(const char *tapName, const char *bridgeName)
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;
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;
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);
208 if (tap_fd < 0)
209 return(NULL);
212 * Figure out the tap unit number
214 if (fstat(tap_fd, &st) < 0) {
215 close(tap_fd);
216 return(NULL);
218 tap_unit = TAPDEV_MINOR(st.st_rdev);
221 * Setup for ioctls
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);
229 s = socket(AF_INET, SOCK_DGRAM, 0);
232 * Set the interface address if in Secure mode.
234 if (SetAddrOpt) {
235 struct sockaddr_in *in;
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);
252 * Turn up the interface
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);
266 if (bridgeName) {
267 struct ifbreq ifbr;
268 struct ifdrv ifd;
271 * Create the bridge if necessary.
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);
284 * Add the tap interface to the bridge
286 bzero(&ifbr, sizeof(ifbr));
287 snprintf(ifbr.ifbr_ifsname, sizeof(ifbr.ifbr_ifsname),
288 "tap%d", tap_unit);
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;
296 if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
297 if (errno != EEXIST) {
298 perror("Unable to add tap ifc to bridge!");
299 exit(1);
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);
312 #undef TAPDEV_MINOR
314 static int
315 vknet_listener(const char *pathName)
317 struct sockaddr_un sunx;
318 int net_fd;
319 int len;
320 gid_t gid;
321 struct group *grp;
324 * Group access to our named unix domain socket.
326 if ((grp = getgrnam("vknet")) == NULL) {
327 fprintf(stderr, "The 'vknet' group must exist\n");
328 exit(1);
330 gid = grp->gr_gid;
331 endgrent();
334 * Socket setup
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;
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);
350 if (listen(net_fd, 1024) < 0) {
351 close(net_fd);
352 return(-1);
354 if (chown(pathName, (uid_t)-1, gid) < 0) {
355 close(net_fd);
356 return(-1);
358 if (chmod(pathName, 0660) < 0) {
359 close(net_fd);
360 return(-1);
362 return(net_fd);
365 static
366 void
367 vknet_acceptor(int net_fd)
369 struct sockaddr_un sunx;
370 pthread_t dummy_td;
371 int sunx_len;
372 int rfd;
373 ioinfo_t info;
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);
389 * This I/O thread implements the core of the bridging code.
391 static
392 void *
393 vknet_io(void *arg)
395 ioinfo_t info = arg;
396 bridge_t bridge;
397 u_int8_t *pkt;
398 int bytes;
400 pthread_detach(pthread_self());
403 * Assign as a bridge slot using our thread id.
405 pthread_mutex_lock(&BridgeMutex);
406 bridge = bridge_add(info);
407 pthread_mutex_unlock(&BridgeMutex);
410 * Read packet loop. Writing is handled by the bridge code.
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);
420 * Cleanup
422 pthread_mutex_lock(&BridgeMutex);
423 bridge_del(bridge);
424 pthread_mutex_unlock(&BridgeMutex);
426 close(info->fd);
427 free(pkt);
428 pthread_exit(NULL);
432 * Debugging
434 static int
435 vknet_connect(const char *pathName)
437 struct sockaddr_un sunx;
438 int len;
439 int net_fd;
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;
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);
454 return(net_fd);
457 static void
458 vknet_monitor(int net_fd)
460 u_int8_t *pkt;
461 int bytes;
462 int i;
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");
474 printf(" %02x", pkt[i]);
476 printf("\n");
478 free(pkt);
482 * Misc
484 static void
485 writepid(void)
487 FILE *pf;
489 if ((pf = fopen(pidfile, "w+")) == NULL)
490 errx(1, "Failed to create pidfile %s", pidfile);
492 if ((fprintf(pf, "%d\n", getpid())) < 1)
493 err(1, "fprintf");
495 fclose(pf);
498 static void
499 cleanup(int __unused sig)
501 if (pidfile)
502 unlink(pidfile);
505 static
506 void
507 usage(void)
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);