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