iscontrol(8): Fix synopsis, sync usage() & improve markup
[dragonfly.git] / usr.sbin / vknetd / vknetd.c
blobacac9e090ceea9e9af20f2345b9b87c0f85a4aa4
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.
34 * $DragonFly: src/usr.sbin/vknetd/vknetd.c,v 1.2 2008/06/02 20:03:22 dillon Exp $
37 * vknet [-p path] [-t tapdev] network/mask
39 * Create a named unix-domain socket which userland vkernels can open
40 * to gain access to a local network. All connections to the socket
41 * are bridged together and the local network can also be bridged onto
42 * a TAP interface by specifying the -t option.
44 #include "vknetd.h"
46 static ioinfo_t vknet_tap(const char *tapName, const char *bridgeName);
47 static int vknet_listener(const char *pathName);
48 static void vknet_acceptor(int net_fd);
49 static void *vknet_io(void *arg);
50 static int vknet_connect(const char *pathName);
51 static void vknet_monitor(int net_fd);
52 static void usage(void);
54 pthread_mutex_t BridgeMutex;
56 int SecureOpt = 1;
57 int DebugOpt = 0;
58 int SetAddrOpt = 0;
59 struct in_addr NetAddress;
60 struct in_addr NetMask;
62 int
63 main(int ac, char **av)
65 const char *pathName = "/var/run/vknet";
66 const char *tapName = "auto";
67 const char *bridgeName = NULL;
68 int net_fd, tap_fd;
69 int connectOpt = 0;
70 int c;
71 ioinfo_t tap_info;
72 pthread_t dummy_td;
74 while ((c = getopt(ac, av, "b:cdp:t:U")) != -1) {
75 switch (c) {
76 case 'U':
77 SecureOpt = 0;
78 break;
79 case 'b':
80 bridgeName = optarg;
81 break;
82 case 'd':
83 DebugOpt = 1;
84 break;
85 case 'p':
86 pathName = optarg;
87 break;
88 case 't':
89 tapName = optarg;
90 break;
91 case 'c':
92 connectOpt = 1;
93 break;
94 default:
95 usage();
98 av += optind;
99 ac -= optind;
100 if (ac)
101 SetAddrOpt = 1;
104 * Special connect/debug mode
106 if (connectOpt) {
107 net_fd = vknet_connect(pathName);
108 if (net_fd < 0) {
109 perror("connect");
110 exit(1);
112 vknet_monitor(net_fd);
113 exit(0);
117 * In secure mode (the default), a network address/mask must be
118 * specified. e.g. 10.1.0.0/16. Any traffic going out the TAP
119 * interface will be filtered.
121 * If non-secure mode the network address/mask is optional.
123 if (SecureOpt || SetAddrOpt) {
124 char *str;
125 int masklen;
126 u_int32_t mask;
128 if (ac == 0 || strchr(av[0], '/') == NULL)
129 usage();
130 str = strdup(av[0]);
131 if (inet_pton(AF_INET, strtok(str, "/"), &NetAddress) <= 0)
132 usage();
133 masklen = strtoul(strtok(NULL, "/"), NULL, 10);
134 mask = (1 << (32 - masklen)) - 1;
135 NetMask.s_addr = htonl(~mask);
139 * Normal operation, create the tap/bridge and listener. This
140 * part is not threaded.
142 mac_init();
144 if ((tap_info = vknet_tap(tapName, bridgeName)) == NULL) {
145 perror("tap: ");
146 exit(1);
148 if ((net_fd = vknet_listener(pathName)) < 0) {
149 perror("listener: ");
150 exit(1);
154 * Now make us a demon and start the threads going.
156 if (DebugOpt == 0)
157 daemon(1, 0);
158 pthread_mutex_init(&BridgeMutex, NULL);
159 pthread_create(&dummy_td, NULL, vknet_io, tap_info);
160 vknet_acceptor(net_fd);
162 exit(0);
165 #define TAPDEV_MINOR(x) ((int)((x) & 0xffff00ff))
167 static ioinfo_t
168 vknet_tap(const char *tapName, const char *bridgeName)
170 struct ifreq ifr;
171 struct ifaliasreq ifra;
172 struct stat st;
173 char *buf = NULL;
174 int tap_fd;
175 int tap_unit;
176 int i;
177 int s;
178 int flags;
179 ioinfo_t info;
181 if (strcmp(tapName, "auto") == 0) {
182 for (i = 0; ; ++i) {
183 asprintf(&buf, "/dev/tap%d", i);
184 tap_fd = open(buf, O_RDWR | O_NONBLOCK);
185 free(buf);
186 if (tap_fd >= 0 || errno == ENOENT)
187 break;
189 } else if (strncmp(tapName, "tap", 3) == 0) {
190 asprintf(&buf, "/dev/%s", tapName);
191 tap_fd = open(buf, O_RDWR | O_NONBLOCK);
192 free(buf);
193 } else {
194 tap_fd = open(tapName, O_RDWR | O_NONBLOCK);
196 if (tap_fd < 0)
197 return(NULL);
200 * Figure out the tap unit number
202 if (fstat(tap_fd, &st) < 0) {
203 close(tap_fd);
204 return(NULL);
206 tap_unit = TAPDEV_MINOR(st.st_rdev);
209 * Setup for ioctls
211 fcntl(tap_fd, F_SETFL, 0);
212 bzero(&ifr, sizeof(ifr));
213 bzero(&ifra, sizeof(ifra));
214 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
215 snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "tap%d", tap_unit);
217 s = socket(AF_INET, SOCK_DGRAM, 0);
220 * Set the interface address if in Secure mode.
222 if (SetAddrOpt) {
223 struct sockaddr_in *in;
225 in = (void *)&ifra.ifra_addr;
226 in->sin_family = AF_INET;
227 in->sin_len = sizeof(ifra.ifra_addr);
228 in->sin_addr = NetAddress;
229 in = (void *)&ifra.ifra_mask;
230 in->sin_family = AF_INET;
231 in->sin_len = sizeof(ifra.ifra_mask);
232 in->sin_addr = NetMask;
233 if (ioctl(s, SIOCAIFADDR, &ifra) < 0) {
234 perror("Unable to set address on tap interface");
235 exit(1);
240 * Turn up the interface
242 flags = IFF_UP;
243 if (ioctl(s, SIOCGIFFLAGS, &ifr) >= 0) {
244 bzero(&ifr, sizeof(ifr));
245 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
246 ifr.ifr_flags |= flags & 0xFFFF;
247 ifr.ifr_flagshigh |= flags >> 16;
248 if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
249 perror("Unable to set IFF_UP on tap interface");
250 exit(1);
254 if (bridgeName) {
255 struct ifbreq ifbr;
256 struct ifdrv ifd;
259 * Create the bridge if necessary.
261 bzero(&ifr, sizeof(ifr));
262 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", bridgeName);
263 if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
264 if (errno != EEXIST) {
265 perror("Unable to create bridge interface");
266 exit(1);
272 * Add the tap interface to the bridge
274 bzero(&ifbr, sizeof(ifbr));
275 snprintf(ifbr.ifbr_ifsname, sizeof(ifbr.ifbr_ifsname),
276 "tap%d", tap_unit);
278 bzero(&ifd, sizeof(ifd));
279 snprintf(ifd.ifd_name, sizeof(ifd.ifd_name), "%s", bridgeName);
280 ifd.ifd_cmd = BRDGADD;
281 ifd.ifd_len = sizeof(ifbr);
282 ifd.ifd_data = &ifbr;
284 if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
285 if (errno != EEXIST) {
286 perror("Unable to add tap ifc to bridge!");
287 exit(1);
292 close(s);
293 info = malloc(sizeof(*info));
294 bzero(info, sizeof(*info));
295 info->fd = tap_fd;
296 info->istap = 1;
297 return(info);
300 #undef TAPDEV_MINOR
302 static int
303 vknet_listener(const char *pathName)
305 struct sockaddr_un sunx;
306 int net_fd;
307 int len;
308 gid_t gid;
309 struct group *grp;
312 * Group access to our named unix domain socket.
314 if ((grp = getgrnam("vknet")) == NULL) {
315 fprintf(stderr, "The 'vknet' group must exist\n");
316 exit(1);
318 gid = grp->gr_gid;
319 endgrent();
322 * Socket setup
324 snprintf(sunx.sun_path, sizeof(sunx.sun_path), "%s", pathName);
325 len = offsetof(struct sockaddr_un, sun_path[strlen(sunx.sun_path)]);
326 ++len; /* include nul */
327 sunx.sun_family = AF_UNIX;
328 sunx.sun_len = len;
330 net_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
331 if (net_fd < 0)
332 return(-1);
333 remove(pathName);
334 if (bind(net_fd, (void *)&sunx, len) < 0) {
335 close(net_fd);
336 return(-1);
338 if (listen(net_fd, 1024) < 0) {
339 close(net_fd);
340 return(-1);
342 if (chown(pathName, (uid_t)-1, gid) < 0) {
343 close(net_fd);
344 return(-1);
346 if (chmod(pathName, 0660) < 0) {
347 close(net_fd);
348 return(-1);
350 return(net_fd);
353 static
354 void
355 vknet_acceptor(int net_fd)
357 struct sockaddr_un sunx;
358 pthread_t dummy_td;
359 int sunx_len;
360 int rfd;
361 ioinfo_t info;
363 for (;;) {
364 sunx_len = sizeof(sunx);
365 rfd = accept(net_fd, (void *)&sunx, &sunx_len);
366 if (rfd < 0)
367 break;
368 info = malloc(sizeof(*info));
369 bzero(info, sizeof(*info));
370 info->fd = rfd;
371 info->istap = 0;
372 pthread_create(&dummy_td, NULL, vknet_io, info);
377 * This I/O thread implements the core of the bridging code.
379 static
380 void *
381 vknet_io(void *arg)
383 ioinfo_t info = arg;
384 bridge_t bridge;
385 u_int8_t *pkt;
386 int bytes;
388 pthread_detach(pthread_self());
391 * Assign as a bridge slot using our thread id.
393 pthread_mutex_lock(&BridgeMutex);
394 bridge = bridge_add(info);
395 pthread_mutex_unlock(&BridgeMutex);
398 * Read packet loop. Writing is handled by the bridge code.
400 pkt = malloc(MAXPKT);
401 while ((bytes = read(info->fd, pkt, MAXPKT)) > 0) {
402 pthread_mutex_lock(&BridgeMutex);
403 bridge_packet(bridge, pkt, bytes);
404 pthread_mutex_unlock(&BridgeMutex);
408 * Cleanup
410 pthread_mutex_lock(&BridgeMutex);
411 bridge_del(bridge);
412 pthread_mutex_unlock(&BridgeMutex);
414 close(info->fd);
415 free(pkt);
416 pthread_exit(NULL);
420 * Debugging
422 static int
423 vknet_connect(const char *pathName)
425 struct sockaddr_un sunx;
426 int len;
427 int net_fd;
429 snprintf(sunx.sun_path, sizeof(sunx.sun_path), "%s", pathName);
430 len = offsetof(struct sockaddr_un, sun_path[strlen(sunx.sun_path)]);
431 ++len; /* include nul */
432 sunx.sun_family = AF_UNIX;
433 sunx.sun_len = len;
435 net_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
436 if (net_fd < 0)
437 return(-1);
438 if (connect(net_fd, (void *)&sunx, len) < 0) {
439 close(net_fd);
440 return(-1);
442 return(net_fd);
445 static void
446 vknet_monitor(int net_fd)
448 u_int8_t *pkt;
449 int bytes;
450 int i;
452 pkt = malloc(MAXPKT);
453 while ((bytes = read(net_fd, pkt, MAXPKT)) > 0) {
454 printf("%02x:%02x:%02x:%02x:%02x:%02x <- "
455 "%02x:%02x:%02x:%02x:%02x:%02x",
456 pkt[0], pkt[1], pkt[2], pkt[3], pkt[4], pkt[5],
457 pkt[6], pkt[7], pkt[8], pkt[9], pkt[10], pkt[11]);
458 for (i = 12; i < bytes; ++i) {
459 if (((i - 12) & 15) == 0) {
460 printf("\n\t");
462 printf(" %02x", pkt[i]);
464 printf("\n");
466 free(pkt);
470 * Misc
472 static
473 void
474 usage(void)
476 fprintf(stderr, "vknet [-p path] [-t tapdev] [-U] [network/bits]\n");
477 fprintf(stderr, "network must be specified in default secure mode\n");
478 exit(1);