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