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 481