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