Merge branch 'vendor/BIND' into bind_vendor2
[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  * $DragonFly: src/usr.sbin/vknetd/vknetd.c,v 1.2 2008/06/02 20:03:22 dillon Exp $
35  */
36 /*
37  * vknet [-p path] [-t tapdev] network/mask
38  *
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.
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);
53
54 pthread_mutex_t BridgeMutex;
55
56 int SecureOpt = 1;
57 int DebugOpt = 0;
58 int SetAddrOpt = 0;
59 struct in_addr NetAddress;
60 struct in_addr NetMask;
61
62 int
63 main(int ac, char **av)
64 {
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;
73
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();
96                 }
97         }
98         av += optind;
99         ac -= optind;
100         if (ac)
101                 SetAddrOpt = 1;
102
103         /*
104          * Special connect/debug mode
105          */
106         if (connectOpt) {
107                 net_fd = vknet_connect(pathName);
108                 if (net_fd < 0) {
109                         perror("connect");
110                         exit(1);
111                 }
112                 vknet_monitor(net_fd);
113                 exit(0);
114         }
115
116         /*
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.
120          *
121          * If non-secure mode the network address/mask is optional.
122          */
123         if (SecureOpt || SetAddrOpt) {
124                 char *str;
125                 int masklen;
126                 u_int32_t mask;
127
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);
136         }
137
138         /*
139          * Normal operation, create the tap/bridge and listener.  This
140          * part is not threaded.
141          */
142         mac_init();
143
144         if ((tap_info = vknet_tap(tapName, bridgeName)) == NULL) {
145                 perror("tap: ");
146                 exit(1);
147         }
148         if ((net_fd = vknet_listener(pathName)) < 0) {
149                 perror("listener: ");
150                 exit(1);
151         }
152
153         /*
154          * Now make us a demon and start the threads going.
155          */
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);
161
162         exit(0);
163 }
164
165 #define TAPDEV_MINOR(x) ((int)((x) & 0xffff00ff))
166
167 static ioinfo_t
168 vknet_tap(const char *tapName, const char *bridgeName)
169 {
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;
180
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;
188                 }
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);
195         }
196         if (tap_fd < 0)
197                 return(NULL);
198
199         /*
200          * Figure out the tap unit number
201          */
202         if (fstat(tap_fd, &st) < 0) {
203                 close(tap_fd);
204                 return(NULL);
205         }
206         tap_unit = TAPDEV_MINOR(st.st_rdev);
207
208         /*
209          * Setup for ioctls
210          */
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);
216
217         s = socket(AF_INET, SOCK_DGRAM, 0);
218
219         /*
220          * Set the interface address if in Secure mode.
221          */
222         if (SetAddrOpt) {
223                 struct sockaddr_in *in;
224
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);
236                 }
237         }
238
239         /*
240          * Turn up the interface
241          */
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);
251                 }
252         }
253
254         if (bridgeName) {
255                 struct ifbreq ifbr;
256                 struct ifdrv ifd;
257
258                 /*
259                  * Create the bridge if necessary.
260                  */
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);
267                         }
268                 }
269
270
271                 /*
272                  * Add the tap interface to the bridge
273                  */
274                 bzero(&ifbr, sizeof(ifbr));
275                 snprintf(ifbr.ifbr_ifsname, sizeof(ifbr.ifbr_ifsname),
276                          "tap%d", tap_unit);
277
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;
283
284                 if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
285                         if (errno != EEXIST) {
286                                 perror("Unable to add tap ifc to bridge!");
287                                 exit(1);
288                         }
289                 }
290         }
291
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);
298 }
299
300 #undef TAPDEV_MINOR
301
302 static int
303 vknet_listener(const char *pathName)
304 {
305         struct sockaddr_un sunx;
306         int net_fd;
307         int len;
308         gid_t gid;
309         struct group *grp;
310
311         /*
312          * Group access to our named unix domain socket.
313          */
314         if ((grp = getgrnam("vknet")) == NULL) {
315                 fprintf(stderr, "The 'vknet' group must exist\n");
316                 exit(1);
317         }
318         gid = grp->gr_gid;
319         endgrent();
320
321         /*
322          * Socket setup
323          */
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;
329
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);
337         }
338         if (listen(net_fd, 1024) < 0) {
339                 close(net_fd);
340                 return(-1);
341         }
342         if (chown(pathName, (uid_t)-1, gid) < 0) {
343                 close(net_fd);
344                 return(-1);
345         }
346         if (chmod(pathName, 0660) < 0) {
347                 close(net_fd);
348                 return(-1);
349         }
350         return(net_fd);
351 }
352
353 static
354 void
355 vknet_acceptor(int net_fd)
356 {
357         struct sockaddr_un sunx;
358         pthread_t dummy_td;
359         int sunx_len;
360         int rfd;
361         ioinfo_t info;
362
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);
373         }
374 }
375
376 /*
377  * This I/O thread implements the core of the bridging code.
378  */
379 static
380 void *
381 vknet_io(void *arg)
382 {
383         ioinfo_t info = arg;
384         bridge_t bridge;
385         u_int8_t *pkt;
386         int bytes;
387
388         pthread_detach(pthread_self());
389
390         /*
391          * Assign as a bridge slot using our thread id.
392          */
393         pthread_mutex_lock(&BridgeMutex);
394         bridge = bridge_add(info);
395         pthread_mutex_unlock(&BridgeMutex);
396
397         /*
398          * Read packet loop.  Writing is handled by the bridge code.
399          */
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);
405         }
406
407         /*
408          * Cleanup
409          */
410         pthread_mutex_lock(&BridgeMutex);
411         bridge_del(bridge);
412         pthread_mutex_unlock(&BridgeMutex);
413
414         close(info->fd);
415         free(pkt);
416         pthread_exit(NULL);
417 }
418
419 /*
420  * Debugging
421  */
422 static int
423 vknet_connect(const char *pathName) 
424 {
425         struct sockaddr_un sunx;
426         int len;
427         int net_fd;
428
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;
434
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);
441         }
442         return(net_fd);
443 }
444
445 static void
446 vknet_monitor(int net_fd)
447 {
448         u_int8_t *pkt;
449         int bytes;
450         int i;
451
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");
461                         }
462                         printf(" %02x", pkt[i]);
463                 }
464                 printf("\n");
465         }
466         free(pkt);
467 }
468
469 /*
470  * Misc
471  */
472 static
473 void
474 usage(void)
475 {
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);
479 }
480