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