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