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 52 pthread_mutex_t BridgeMutex; 53 54 int SecureOpt = 1; 55 int DebugOpt = 0; 56 int SetAddrOpt = 0; 57 struct in_addr NetAddress; 58 struct in_addr NetMask; 59 60 int 61 main(int ac, char **av) 62 { 63 const char *pathName = "/var/run/vknet"; 64 const char *tapName = "auto"; 65 const char *bridgeName = NULL; 66 int net_fd; 67 int connectOpt = 0; 68 int c; 69 ioinfo_t tap_info; 70 pthread_t dummy_td; 71 72 while ((c = getopt(ac, av, "b:cdp:t:U")) != -1) { 73 switch (c) { 74 case 'U': 75 SecureOpt = 0; 76 break; 77 case 'b': 78 bridgeName = optarg; 79 break; 80 case 'd': 81 DebugOpt = 1; 82 break; 83 case 'p': 84 pathName = optarg; 85 break; 86 case 't': 87 tapName = optarg; 88 break; 89 case 'c': 90 connectOpt = 1; 91 break; 92 default: 93 usage(); 94 } 95 } 96 av += optind; 97 ac -= optind; 98 if (ac) 99 SetAddrOpt = 1; 100 101 /* 102 * Special connect/debug mode 103 */ 104 if (connectOpt) { 105 net_fd = vknet_connect(pathName); 106 if (net_fd < 0) { 107 perror("connect"); 108 exit(1); 109 } 110 vknet_monitor(net_fd); 111 exit(0); 112 } 113 114 /* 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. 118 * 119 * If non-secure mode the network address/mask is optional. 120 */ 121 if (SecureOpt || SetAddrOpt) { 122 char *str; 123 int masklen; 124 u_int32_t mask; 125 126 if (ac == 0 || strchr(av[0], '/') == NULL) 127 usage(); 128 str = strdup(av[0]); 129 if (inet_pton(AF_INET, strtok(str, "/"), &NetAddress) <= 0) 130 usage(); 131 masklen = strtoul(strtok(NULL, "/"), NULL, 10); 132 mask = (1 << (32 - masklen)) - 1; 133 NetMask.s_addr = htonl(~mask); 134 } 135 136 /* 137 * Normal operation, create the tap/bridge and listener. This 138 * part is not threaded. 139 */ 140 mac_init(); 141 142 if ((tap_info = vknet_tap(tapName, bridgeName)) == NULL) { 143 perror("tap: "); 144 exit(1); 145 } 146 if ((net_fd = vknet_listener(pathName)) < 0) { 147 perror("listener: "); 148 exit(1); 149 } 150 151 /* 152 * Now make us a demon and start the threads going. 153 */ 154 if (DebugOpt == 0) 155 daemon(1, 0); 156 pthread_mutex_init(&BridgeMutex, NULL); 157 pthread_create(&dummy_td, NULL, vknet_io, tap_info); 158 vknet_acceptor(net_fd); 159 160 exit(0); 161 } 162 163 #define TAPDEV_MINOR(x) ((int)((x) & 0xffff00ff)) 164 165 static ioinfo_t 166 vknet_tap(const char *tapName, const char *bridgeName) 167 { 168 struct ifreq ifr; 169 struct ifaliasreq ifra; 170 struct stat st; 171 char *buf = NULL; 172 int tap_fd; 173 int tap_unit; 174 int i; 175 int s; 176 int flags; 177 ioinfo_t info; 178 179 if (strcmp(tapName, "auto") == 0) { 180 for (i = 0; ; ++i) { 181 asprintf(&buf, "/dev/tap%d", i); 182 tap_fd = open(buf, O_RDWR | O_NONBLOCK); 183 free(buf); 184 if (tap_fd >= 0 || errno == ENOENT) 185 break; 186 } 187 } else if (strncmp(tapName, "tap", 3) == 0) { 188 asprintf(&buf, "/dev/%s", tapName); 189 tap_fd = open(buf, O_RDWR | O_NONBLOCK); 190 free(buf); 191 } else { 192 tap_fd = open(tapName, O_RDWR | O_NONBLOCK); 193 } 194 if (tap_fd < 0) 195 return(NULL); 196 197 /* 198 * Figure out the tap unit number 199 */ 200 if (fstat(tap_fd, &st) < 0) { 201 close(tap_fd); 202 return(NULL); 203 } 204 tap_unit = TAPDEV_MINOR(st.st_rdev); 205 206 /* 207 * Setup for ioctls 208 */ 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); 214 215 s = socket(AF_INET, SOCK_DGRAM, 0); 216 217 /* 218 * Set the interface address if in Secure mode. 219 */ 220 if (SetAddrOpt) { 221 struct sockaddr_in *in; 222 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"); 233 exit(1); 234 } 235 } 236 237 /* 238 * Turn up the interface 239 */ 240 flags = IFF_UP; 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"); 248 exit(1); 249 } 250 } 251 252 if (bridgeName) { 253 struct ifbreq ifbr; 254 struct ifdrv ifd; 255 256 /* 257 * Create the bridge if necessary. 258 */ 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"); 264 exit(1); 265 } 266 } 267 268 269 /* 270 * Add the tap interface to the bridge 271 */ 272 bzero(&ifbr, sizeof(ifbr)); 273 snprintf(ifbr.ifbr_ifsname, sizeof(ifbr.ifbr_ifsname), 274 "tap%d", tap_unit); 275 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; 281 282 if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) { 283 if (errno != EEXIST) { 284 perror("Unable to add tap ifc to bridge!"); 285 exit(1); 286 } 287 } 288 } 289 290 close(s); 291 info = malloc(sizeof(*info)); 292 bzero(info, sizeof(*info)); 293 info->fd = tap_fd; 294 info->istap = 1; 295 return(info); 296 } 297 298 #undef TAPDEV_MINOR 299 300 static int 301 vknet_listener(const char *pathName) 302 { 303 struct sockaddr_un sunx; 304 int net_fd; 305 int len; 306 gid_t gid; 307 struct group *grp; 308 309 /* 310 * Group access to our named unix domain socket. 311 */ 312 if ((grp = getgrnam("vknet")) == NULL) { 313 fprintf(stderr, "The 'vknet' group must exist\n"); 314 exit(1); 315 } 316 gid = grp->gr_gid; 317 endgrent(); 318 319 /* 320 * Socket setup 321 */ 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; 326 sunx.sun_len = len; 327 328 net_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 329 if (net_fd < 0) 330 return(-1); 331 remove(pathName); 332 if (bind(net_fd, (void *)&sunx, len) < 0) { 333 close(net_fd); 334 return(-1); 335 } 336 if (listen(net_fd, 1024) < 0) { 337 close(net_fd); 338 return(-1); 339 } 340 if (chown(pathName, (uid_t)-1, gid) < 0) { 341 close(net_fd); 342 return(-1); 343 } 344 if (chmod(pathName, 0660) < 0) { 345 close(net_fd); 346 return(-1); 347 } 348 return(net_fd); 349 } 350 351 static 352 void 353 vknet_acceptor(int net_fd) 354 { 355 struct sockaddr_un sunx; 356 pthread_t dummy_td; 357 int sunx_len; 358 int rfd; 359 ioinfo_t info; 360 361 for (;;) { 362 sunx_len = sizeof(sunx); 363 rfd = accept(net_fd, (void *)&sunx, &sunx_len); 364 if (rfd < 0) 365 break; 366 info = malloc(sizeof(*info)); 367 bzero(info, sizeof(*info)); 368 info->fd = rfd; 369 info->istap = 0; 370 pthread_create(&dummy_td, NULL, vknet_io, info); 371 } 372 } 373 374 /* 375 * This I/O thread implements the core of the bridging code. 376 */ 377 static 378 void * 379 vknet_io(void *arg) 380 { 381 ioinfo_t info = arg; 382 bridge_t bridge; 383 u_int8_t *pkt; 384 int bytes; 385 386 pthread_detach(pthread_self()); 387 388 /* 389 * Assign as a bridge slot using our thread id. 390 */ 391 pthread_mutex_lock(&BridgeMutex); 392 bridge = bridge_add(info); 393 pthread_mutex_unlock(&BridgeMutex); 394 395 /* 396 * Read packet loop. Writing is handled by the bridge code. 397 */ 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); 403 } 404 405 /* 406 * Cleanup 407 */ 408 pthread_mutex_lock(&BridgeMutex); 409 bridge_del(bridge); 410 pthread_mutex_unlock(&BridgeMutex); 411 412 close(info->fd); 413 free(pkt); 414 pthread_exit(NULL); 415 } 416 417 /* 418 * Debugging 419 */ 420 static int 421 vknet_connect(const char *pathName) 422 { 423 struct sockaddr_un sunx; 424 int len; 425 int net_fd; 426 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; 431 sunx.sun_len = len; 432 433 net_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); 434 if (net_fd < 0) 435 return(-1); 436 if (connect(net_fd, (void *)&sunx, len) < 0) { 437 close(net_fd); 438 return(-1); 439 } 440 return(net_fd); 441 } 442 443 static void 444 vknet_monitor(int net_fd) 445 { 446 u_int8_t *pkt; 447 int bytes; 448 int i; 449 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) { 458 printf("\n\t"); 459 } 460 printf(" %02x", pkt[i]); 461 } 462 printf("\n"); 463 } 464 free(pkt); 465 } 466 467 /* 468 * Misc 469 */ 470 static 471 void 472 usage(void) 473 { 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"); 476 exit(1); 477 } 478 479