2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 * vknet [-cdU] [-b bridgeN] [-p socket_path] [-t tapN] [address/cidrbits]
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.
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);
52 pthread_mutex_t BridgeMutex;
57 struct in_addr NetAddress;
58 struct in_addr NetMask;
61 main(int ac, char **av)
63 const char *pathName = "/var/run/vknet";
64 const char *tapName = "auto";
65 const char *bridgeName = NULL;
72 while ((c = getopt(ac, av, "b:cdp:t:U")) != -1) {
102 * Special connect/debug mode
105 net_fd = vknet_connect(pathName);
110 vknet_monitor(net_fd);
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.
119 * If non-secure mode the network address/mask is optional.
121 if (SecureOpt || SetAddrOpt) {
126 if (ac == 0 || strchr(av[0], '/') == NULL)
129 if (inet_pton(AF_INET, strtok(str, "/"), &NetAddress) <= 0)
131 masklen = strtoul(strtok(NULL, "/"), NULL, 10);
132 mask = (1 << (32 - masklen)) - 1;
133 NetMask.s_addr = htonl(~mask);
137 * Normal operation, create the tap/bridge and listener. This
138 * part is not threaded.
142 if ((tap_info = vknet_tap(tapName, bridgeName)) == NULL) {
146 if ((net_fd = vknet_listener(pathName)) < 0) {
147 perror("listener: ");
152 * Now make us a demon and start the threads going.
156 pthread_mutex_init(&BridgeMutex, NULL);
157 pthread_create(&dummy_td, NULL, vknet_io, tap_info);
158 vknet_acceptor(net_fd);
163 #define TAPDEV_MINOR(x) ((int)((x) & 0xffff00ff))
166 vknet_tap(const char *tapName, const char *bridgeName)
169 struct ifaliasreq ifra;
179 if (strcmp(tapName, "auto") == 0) {
181 asprintf(&buf, "/dev/tap%d", i);
182 tap_fd = open(buf, O_RDWR | O_NONBLOCK);
184 if (tap_fd >= 0 || errno == ENOENT)
187 } else if (strncmp(tapName, "tap", 3) == 0) {
188 asprintf(&buf, "/dev/%s", tapName);
189 tap_fd = open(buf, O_RDWR | O_NONBLOCK);
192 tap_fd = open(tapName, O_RDWR | O_NONBLOCK);
198 * Figure out the tap unit number
200 if (fstat(tap_fd, &st) < 0) {
204 tap_unit = TAPDEV_MINOR(st.st_rdev);
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);
215 s = socket(AF_INET, SOCK_DGRAM, 0);
218 * Set the interface address if in Secure mode.
221 struct sockaddr_in *in;
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");
238 * Turn up the interface
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");
257 * Create the bridge if necessary.
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");
270 * Add the tap interface to the bridge
272 bzero(&ifbr, sizeof(ifbr));
273 snprintf(ifbr.ifbr_ifsname, sizeof(ifbr.ifbr_ifsname),
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;
282 if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
283 if (errno != EEXIST) {
284 perror("Unable to add tap ifc to bridge!");
291 info = malloc(sizeof(*info));
292 bzero(info, sizeof(*info));
301 vknet_listener(const char *pathName)
303 struct sockaddr_un sunx;
310 * Group access to our named unix domain socket.
312 if ((grp = getgrnam("vknet")) == NULL) {
313 fprintf(stderr, "The 'vknet' group must exist\n");
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;
328 net_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
332 if (bind(net_fd, (void *)&sunx, len) < 0) {
336 if (listen(net_fd, 1024) < 0) {
340 if (chown(pathName, (uid_t)-1, gid) < 0) {
344 if (chmod(pathName, 0660) < 0) {
353 vknet_acceptor(int net_fd)
355 struct sockaddr_un sunx;
362 sunx_len = sizeof(sunx);
363 rfd = accept(net_fd, (void *)&sunx, &sunx_len);
366 info = malloc(sizeof(*info));
367 bzero(info, sizeof(*info));
370 pthread_create(&dummy_td, NULL, vknet_io, info);
375 * This I/O thread implements the core of the bridging code.
386 pthread_detach(pthread_self());
389 * Assign as a bridge slot using our thread id.
391 pthread_mutex_lock(&BridgeMutex);
392 bridge = bridge_add(info);
393 pthread_mutex_unlock(&BridgeMutex);
396 * Read packet loop. Writing is handled by the bridge code.
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);
408 pthread_mutex_lock(&BridgeMutex);
410 pthread_mutex_unlock(&BridgeMutex);
421 vknet_connect(const char *pathName)
423 struct sockaddr_un sunx;
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;
433 net_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
436 if (connect(net_fd, (void *)&sunx, len) < 0) {
444 vknet_monitor(int net_fd)
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) {
460 printf(" %02x", pkt[i]);
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");