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