22e7581a9ca5cda9726e26121d075ca1cf7e0e42
[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          * 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