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