Annotation of embedaddon/coova-chilli/src/tun.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Tunnel Interface Functions.
! 3: * Copyright (C) 2002, 2003, 2004 Mondru AB.
! 4: * Copyright (c) 2006-2007 David Bird <david@coova.com>
! 5: *
! 6: * The contents of this file may be used under the terms of the GNU
! 7: * General Public License Version 2, provided that the above copyright
! 8: * notice and this permission notice is included in all copies or
! 9: * substantial portions of the software.
! 10: *
! 11: */
! 12:
! 13: /*
! 14: * A tunnel is the back-haul link which chilli sends traffic. Typically,
! 15: * this is a single tun/tap interface allowing chilli to simply pass on
! 16: * packets to the kernel for processing (iptables) and routing. Without the
! 17: * tun/tap interface, chilli must decide for itself how to route traffic,
! 18: * maintaining a socket into each back-haul interface. One or more tunnels
! 19: * are required.
! 20: *
! 21: */
! 22:
! 23: #include "system.h"
! 24: #include "tun.h"
! 25: #include "ippool.h"
! 26: #include "radius.h"
! 27: #include "radius_wispr.h"
! 28: #include "radius_chillispot.h"
! 29: #include "redir.h"
! 30: #include "syserr.h"
! 31: #include "dhcp.h"
! 32: #include "cmdline.h"
! 33: #include "chilli.h"
! 34: #include "options.h"
! 35: #include "net.h"
! 36:
! 37: #define inaddr(x) (((struct sockaddr_in *)&ifr->x)->sin_addr)
! 38: #define inaddr2(p,x) (((struct sockaddr_in *)&(p)->x)->sin_addr)
! 39:
! 40: int tun_discover(struct tun_t *this) {
! 41: net_interface netif;
! 42: struct ifconf ic;
! 43: int fd, len, i;
! 44:
! 45: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 46: log_err(errno, "socket() failed");
! 47: return -1;
! 48: }
! 49:
! 50: ic.ifc_buf=0;
! 51: ic.ifc_len=0;
! 52:
! 53: if (ioctl(fd, SIOCGIFCONF, &ic) < 0) {
! 54: log_err(errno, "ioctl(SIOCGIFCONF)");
! 55: close(fd);
! 56: return -1;
! 57: }
! 58:
! 59: ic.ifc_buf = calloc((size_t)ic.ifc_len, 1);
! 60: if (ioctl(fd, SIOCGIFCONF, &ic) < 0) {
! 61: log_err(errno, "ioctl(SIOCGIFCONF)");
! 62: close(fd);
! 63: return -1;
! 64: }
! 65:
! 66: len = (ic.ifc_len/sizeof(struct ifreq));
! 67:
! 68: for (i=0; i<len; ++i) {
! 69: struct ifreq *ifr = (struct ifreq *)&ic.ifc_req[i];
! 70: memset(&netif, 0, sizeof(netif));
! 71:
! 72:
! 73: /* device name and address */
! 74: strncpy(netif.devname, ifr->ifr_name, sizeof(netif.devname));
! 75: netif.address = inaddr(ifr_addr);
! 76:
! 77: log_dbg("Interface: %s", ifr->ifr_name);
! 78: log_dbg("\tIP Address:\t%s", inet_ntoa(inaddr(ifr_addr)));
! 79:
! 80:
! 81: /* netmask */
! 82: if (-1 < ioctl(fd, SIOCGIFNETMASK, (caddr_t)ifr)) {
! 83:
! 84: netif.netmask = inaddr(ifr_addr);
! 85: log_dbg("\tNetmask:\t%s", inet_ntoa(inaddr(ifr_addr)));
! 86:
! 87: } else log_err(errno, "ioctl(SIOCGIFNETMASK)");
! 88:
! 89:
! 90: /* hardware address */
! 91: #ifdef SIOCGIFHWADDR
! 92: if (-1 < ioctl(fd, SIOCGIFHWADDR, (caddr_t)ifr)) {
! 93: switch (ifr->ifr_hwaddr.sa_family) {
! 94: case ARPHRD_NETROM:
! 95: case ARPHRD_ETHER:
! 96: case ARPHRD_PPP:
! 97: case ARPHRD_EETHER:
! 98: case ARPHRD_IEEE802:
! 99: {
! 100: unsigned char *u = (unsigned char *)&ifr->ifr_addr.sa_data;
! 101:
! 102: memcpy(netif.hwaddr, u, 6);
! 103:
! 104: log_dbg("\tHW Address:\t%2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2x",
! 105: u[0], u[1], u[2], u[3], u[4], u[5]);
! 106: }
! 107: break;
! 108: }
! 109: } else log_err(errno, "ioctl(SIOCGIFHWADDR)");
! 110: #else
! 111: #ifdef SIOCGENADDR
! 112: if (-1 < ioctl(fd, SIOCGENADDR, (caddr_t)ifr)) {
! 113: unsigned char *u = (unsigned char *)&ifr->ifr_enaddr;
! 114:
! 115: memcpy(netif.hwaddr, u, 6);
! 116:
! 117: log_dbg("\tHW Address:\t%2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2x",
! 118: u[0], u[1], u[2], u[3], u[4], u[5]);
! 119: } else log_err(errno, "ioctl(SIOCGENADDR)");
! 120: #else
! 121: #warning Do not know how to find interface hardware address
! 122: #endif /* SIOCGENADDR */
! 123: #endif /* SIOCGIFHWADDR */
! 124:
! 125:
! 126: /* flags */
! 127: if (-1 < ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr)) {
! 128:
! 129: netif.devflags = ifr->ifr_flags;
! 130:
! 131: } else log_err(errno, "ioctl(SIOCGIFFLAGS)");
! 132:
! 133:
! 134: /* point-to-point gateway */
! 135: if (netif.devflags & IFF_POINTOPOINT) {
! 136: if (-1 < ioctl(fd, SIOCGIFDSTADDR, (caddr_t)ifr)) {
! 137:
! 138: netif.gateway = inaddr(ifr_addr);
! 139: log_dbg("\tPoint-to-Point:\t%s", inet_ntoa(inaddr(ifr_dstaddr)));
! 140:
! 141: } else log_err(errno, "ioctl(SIOCGIFDSTADDR)");
! 142: }
! 143:
! 144:
! 145: /* broadcast address */
! 146: if (netif.devflags & IFF_BROADCAST) {
! 147: if (-1 < ioctl(fd, SIOCGIFBRDADDR, (caddr_t)ifr)) {
! 148:
! 149: netif.broadcast = inaddr(ifr_addr);
! 150: log_dbg("\tBroadcast:\t%s", inet_ntoa(inaddr(ifr_addr)));
! 151:
! 152: } else log_err(errno, "ioctl(SIOCGIFBRDADDR)");
! 153: }
! 154:
! 155:
! 156: /* mtu */
! 157: if (-1 < ioctl(fd, SIOCGIFMTU, (caddr_t)ifr)) {
! 158:
! 159: netif.mtu = ifr->ifr_mtu;
! 160: log_dbg("\tMTU: \t%u", ifr->ifr_mtu);
! 161:
! 162: } else log_err(errno, "ioctl(SIOCGIFMTU)");
! 163:
! 164:
! 165: /* if (0 == ioctl(fd, SIOCGIFMETRIC, ifr)) */
! 166:
! 167: if (netif.address.s_addr == htonl(INADDR_LOOPBACK) ||
! 168: netif.address.s_addr == INADDR_ANY ||
! 169: netif.address.s_addr == INADDR_NONE)
! 170: continue;
! 171:
! 172: else {
! 173: net_interface *newif = tun_nextif(tun);
! 174: if (newif) {
! 175: memcpy(newif, &netif, sizeof(netif));
! 176: net_open(newif);
! 177:
! 178: if (!strcmp(options.routeif, netif.devname))
! 179: tun->routeidx = newif->idx;
! 180: } else {
! 181: log_dbg("no room for interface %s", netif.devname);
! 182: }
! 183: }
! 184: }
! 185:
! 186: close(fd);
! 187: return 0;
! 188: }
! 189:
! 190: net_interface * tun_nextif(struct tun_t *tun) {
! 191: net_interface *netif;
! 192:
! 193: if (tun->_interface_count == TUN_MAX_INTERFACES)
! 194: return 0;
! 195:
! 196: netif = &tun->_interfaces[tun->_interface_count];
! 197: netif->idx = tun->_interface_count;
! 198:
! 199: tun->_interface_count++;
! 200:
! 201: return netif;
! 202: }
! 203:
! 204: int tun_name2idx(struct tun_t *tun, char *name) {
! 205: int i;
! 206:
! 207: for (i=0; i<tun->_interface_count; i++)
! 208: if (!strcmp(name, tun->_interfaces[i].devname))
! 209: return i;
! 210:
! 211: return 0; /* tun/tap index */
! 212: }
! 213:
! 214: #if defined(__linux__)
! 215:
! 216: int tun_nlattr(struct nlmsghdr *n, int nsize, int type, void *d, size_t dlen) {
! 217: size_t len = RTA_LENGTH(dlen);
! 218: size_t alen = NLMSG_ALIGN(n->nlmsg_len);
! 219: struct rtattr *rta = (struct rtattr*) (((void*)n) + alen);
! 220: if (alen + len > nsize)
! 221: return -1;
! 222: rta->rta_len = len;
! 223: rta->rta_type = type;
! 224: memcpy(RTA_DATA(rta), d, dlen);
! 225: n->nlmsg_len = alen + len;
! 226: return 0;
! 227: }
! 228:
! 229: int tun_gifindex(struct tun_t *this, int *index) {
! 230: struct ifreq ifr;
! 231: int fd;
! 232:
! 233: memset (&ifr, '\0', sizeof (ifr));
! 234: ifr.ifr_addr.sa_family = AF_INET;
! 235: ifr.ifr_dstaddr.sa_family = AF_INET;
! 236: ifr.ifr_netmask.sa_family = AF_INET;
! 237: strncpy(ifr.ifr_name, tuntap(this).devname, IFNAMSIZ);
! 238: ifr.ifr_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
! 239: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 240: log_err(errno, "socket() failed");
! 241: }
! 242: if (ioctl(fd, SIOCGIFINDEX, &ifr)) {
! 243: log_err(errno,"ioctl() failed");
! 244: close(fd);
! 245: return -1;
! 246: }
! 247: close(fd);
! 248: *index = ifr.ifr_ifindex;
! 249: return 0;
! 250: }
! 251: #endif
! 252:
! 253: int tun_addaddr(struct tun_t *this, struct in_addr *addr,
! 254: struct in_addr *dstaddr, struct in_addr *netmask) {
! 255:
! 256: #if defined(__linux__)
! 257: struct {
! 258: struct nlmsghdr n;
! 259: struct ifaddrmsg i;
! 260: char buf[TUN_NLBUFSIZE];
! 261: } req;
! 262:
! 263: struct sockaddr_nl local;
! 264: size_t addr_len;
! 265: int fd;
! 266: int status;
! 267:
! 268: struct sockaddr_nl nladdr;
! 269: struct iovec iov;
! 270: struct msghdr msg;
! 271:
! 272: if (!this->addrs) /* Use ioctl for first addr to make ping work */
! 273: return tun_setaddr(this, addr, dstaddr, netmask);
! 274:
! 275: memset(&req, 0, sizeof(req));
! 276: req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
! 277: req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
! 278: req.n.nlmsg_type = RTM_NEWADDR;
! 279: req.i.ifa_family = AF_INET;
! 280: req.i.ifa_prefixlen = 32; /* 32 FOR IPv4 */
! 281: req.i.ifa_flags = 0;
! 282: req.i.ifa_scope = RT_SCOPE_HOST; /* TODO or 0 */
! 283:
! 284: if (tun_gifindex(this, &req.i.ifa_index)) {
! 285: log_err(errno,"tun_gifindex() failed");
! 286: return -1;
! 287: }
! 288:
! 289: tun_nlattr(&req.n, sizeof(req), IFA_ADDRESS, addr, sizeof(addr));
! 290: tun_nlattr(&req.n, sizeof(req), IFA_LOCAL, dstaddr, sizeof(dstaddr));
! 291:
! 292: if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
! 293: log_err(errno,"socket() failed");
! 294: return -1;
! 295: }
! 296:
! 297: memset(&local, 0, sizeof(local));
! 298: local.nl_family = AF_NETLINK;
! 299: local.nl_groups = 0;
! 300:
! 301: if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
! 302: log_err(errno, "bind() failed");
! 303: close(fd);
! 304: return -1;
! 305: }
! 306:
! 307: addr_len = sizeof(local);
! 308: if (getsockname(fd, (struct sockaddr*)&local, (socklen_t *) &addr_len) < 0) {
! 309: log_err(errno, "getsockname() failed");
! 310: close(fd);
! 311: return -1;
! 312: }
! 313:
! 314: if (addr_len != sizeof(local)) {
! 315: log_err(0, "Wrong address length %d", addr_len);
! 316: close(fd);
! 317: return -1;
! 318: }
! 319:
! 320: if (local.nl_family != AF_NETLINK) {
! 321: log_err(0, "Wrong address family %d", local.nl_family);
! 322: close(fd);
! 323: return -1;
! 324: }
! 325:
! 326: iov.iov_base = (void*)&req.n;
! 327: iov.iov_len = req.n.nlmsg_len;
! 328:
! 329: msg.msg_name = (void*)&nladdr;
! 330: msg.msg_namelen = sizeof(nladdr),
! 331: msg.msg_iov = &iov;
! 332: msg.msg_iovlen = 1;
! 333: msg.msg_control = NULL;
! 334: msg.msg_controllen = 0;
! 335: msg.msg_flags = 0;
! 336:
! 337: memset(&nladdr, 0, sizeof(nladdr));
! 338: nladdr.nl_family = AF_NETLINK;
! 339: nladdr.nl_pid = 0;
! 340: nladdr.nl_groups = 0;
! 341:
! 342: req.n.nlmsg_seq = 0;
! 343: req.n.nlmsg_flags |= NLM_F_ACK;
! 344:
! 345: status = sendmsg(fd, &msg, 0);
! 346:
! 347: dev_set_flags(tuntap(this).devname, IFF_UP | IFF_RUNNING);
! 348:
! 349: close(fd);
! 350: this->addrs++;
! 351:
! 352: return 0;
! 353:
! 354: #elif defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 355:
! 356: int fd;
! 357: struct ifaliasreq areq;
! 358:
! 359: /* TODO: Is this needed on FreeBSD? */
! 360: if (!this->addrs) /* Use ioctl for first addr to make ping work */
! 361: return tun_setaddr(this, addr, dstaddr, netmask); /* TODO dstaddr */
! 362:
! 363: memset(&areq, 0, sizeof(areq));
! 364:
! 365: /* Set up interface name */
! 366: strncpy(areq.ifra_name, tuntap(this).devname, IFNAMSIZ);
! 367: areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
! 368:
! 369: ((struct sockaddr_in*) &areq.ifra_addr)->sin_family = AF_INET;
! 370: ((struct sockaddr_in*) &areq.ifra_addr)->sin_len = sizeof(areq.ifra_addr);
! 371: ((struct sockaddr_in*) &areq.ifra_addr)->sin_addr.s_addr = addr->s_addr;
! 372:
! 373: ((struct sockaddr_in*) &areq.ifra_mask)->sin_family = AF_INET;
! 374: ((struct sockaddr_in*) &areq.ifra_mask)->sin_len = sizeof(areq.ifra_mask);
! 375: ((struct sockaddr_in*) &areq.ifra_mask)->sin_addr.s_addr = netmask->s_addr;
! 376:
! 377: /* For some reason FreeBSD uses ifra_broadcast for specifying dstaddr */
! 378: ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_family = AF_INET;
! 379: ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_len = sizeof(areq.ifra_broadaddr);
! 380: ((struct sockaddr_in*) &areq.ifra_broadaddr)->sin_addr.s_addr = dstaddr->s_addr;
! 381:
! 382: /* Create a channel to the NET kernel. */
! 383: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 384: log_err(errno,
! 385: "socket() failed");
! 386: return -1;
! 387: }
! 388:
! 389: if (ioctl(fd, SIOCAIFADDR, (void *) &areq) < 0) {
! 390: log_err(errno,
! 391: "ioctl(SIOCAIFADDR) failed");
! 392: close(fd);
! 393: return -1;
! 394: }
! 395:
! 396: close(fd);
! 397: this->addrs++;
! 398: return 0;
! 399:
! 400: #elif defined (__sun__)
! 401:
! 402: if (!this->addrs) /* Use ioctl for first addr to make ping work */
! 403: return tun_setaddr(this, addr, dstaddr, netmask);
! 404:
! 405: log_err(errno, "Setting multiple addresses not possible on Solaris");
! 406: return -1;
! 407:
! 408: #else
! 409: #error "Unknown platform!"
! 410: #endif
! 411:
! 412: }
! 413:
! 414:
! 415: int tun_setaddr(struct tun_t *this, struct in_addr *addr, struct in_addr *dstaddr, struct in_addr *netmask) {
! 416: net_set_address(&tuntap(this), addr, dstaddr, netmask);
! 417:
! 418: #if defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 419: net_add_route(dstaddr, addr, netmask);
! 420: this->routes = 1;
! 421: #endif
! 422:
! 423: return 0;
! 424: }
! 425:
! 426: static int tuntap_interface(struct _net_interface *netif) {
! 427: #if defined(__linux__)
! 428: struct ifreq ifr;
! 429:
! 430: #elif defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 431: char devname[IFNAMSIZ+5]; /* "/dev/" + ifname */
! 432: int devnum;
! 433: struct ifaliasreq areq;
! 434: int fd;
! 435:
! 436: #elif defined(__sun__)
! 437: int if_fd, ppa = -1;
! 438: static int ip_fd = 0;
! 439: int muxid;
! 440: struct ifreq ifr;
! 441:
! 442: #else
! 443: #error "Unknown platform!"
! 444: #endif
! 445:
! 446:
! 447: #if defined(__linux__)
! 448: /* Open the actual tun device */
! 449: if ((netif->fd = open("/dev/net/tun", O_RDWR)) < 0) {
! 450: log_err(errno, "open() failed");
! 451: return -1;
! 452: }
! 453:
! 454: /* Set device flags. For some weird reason this is also the method
! 455: used to obtain the network interface name */
! 456: memset(&ifr, 0, sizeof(ifr));
! 457: ifr.ifr_flags = (options.usetap ? IFF_TAP : IFF_TUN) | IFF_NO_PI; /* Tun device, no packet info */
! 458: #if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)
! 459: ifr.ifr_flags |= IFF_ONE_QUEUE;
! 460: #endif
! 461:
! 462: if (options.tundev && *options.tundev &&
! 463: strcmp(options.tundev, "tap") && strcmp(options.tundev, "tun"))
! 464: strncpy(ifr.ifr_name, options.tundev, IFNAMSIZ);
! 465:
! 466: if (ioctl(netif->fd, TUNSETIFF, (void *) &ifr) < 0) {
! 467: log_err(errno, "ioctl() failed");
! 468: close(netif->fd);
! 469: return -1;
! 470: }
! 471:
! 472: #if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN)
! 473: {
! 474: struct ifreq nifr;
! 475: int nfd;
! 476: memset(&nifr, 0, sizeof(nifr));
! 477: if ((nfd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0) {
! 478: strncpy(nifr.ifr_name, ifr.ifr_name, IFNAMSIZ);
! 479: nifr.ifr_qlen = options.txqlen;
! 480:
! 481: if (ioctl(nfd, SIOCSIFTXQLEN, (void *) &nifr) >= 0)
! 482: log_info("TX queue length set to %d", options.txqlen);
! 483: else
! 484: log_err(errno, "Cannot set tx queue length on %s", ifr.ifr_name);
! 485:
! 486: close (nfd);
! 487: } else {
! 488: log_err(errno, "Cannot open socket on %s", ifr.ifr_name);
! 489: }
! 490: }
! 491: #endif
! 492:
! 493: strncpy(netif->devname, ifr.ifr_name, IFNAMSIZ);
! 494: netif->devname[IFNAMSIZ-1] = 0;
! 495:
! 496: ioctl(netif->fd, TUNSETNOCSUM, 1); /* Disable checksums */
! 497:
! 498: /* Get the MAC address of our tap interface */
! 499: if (options.usetap) {
! 500: int fd;
! 501: netif->flags |= NET_ETHHDR;
! 502: if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0) {
! 503: memset(&ifr, 0, sizeof(ifr));
! 504: strncpy(ifr.ifr_name, netif->devname, IFNAMSIZ);
! 505: if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
! 506: log_err(errno, "ioctl(d=%d, request=%d) failed", fd, SIOCGIFHWADDR);
! 507: }
! 508: memcpy(netif->hwaddr, ifr.ifr_hwaddr.sa_data, PKT_ETH_ALEN);
! 509: log_dbg("tap-mac: %s %.2X-%.2X-%.2X-%.2X-%.2X-%.2X", ifr.ifr_name,
! 510: netif->hwaddr[0],netif->hwaddr[1],netif->hwaddr[2],
! 511: netif->hwaddr[3],netif->hwaddr[4],netif->hwaddr[5]);
! 512: close(fd);
! 513: }
! 514: }
! 515:
! 516: return 0;
! 517:
! 518: #elif defined(__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 519:
! 520: /* Find suitable device */
! 521: for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
! 522: snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
! 523: devname[sizeof(devname)] = 0;
! 524: if ((netif->fd = open(devname, O_RDWR)) >= 0) break;
! 525: if (errno != EBUSY) break;
! 526: }
! 527: if (netif->fd < 0) {
! 528: log_err(errno, "Can't find tunnel device");
! 529: return -1;
! 530: }
! 531:
! 532: snprintf(netif->devname, sizeof(netif->devname), "tun%d", devnum);
! 533: netif->devname[sizeof(netif->devname)-1] = 0;
! 534:
! 535: /* The tun device we found might have "old" IP addresses allocated */
! 536: /* We need to delete those. This problem is not present on Linux */
! 537:
! 538: memset(&areq, 0, sizeof(areq));
! 539:
! 540: /* Set up interface name */
! 541: strncpy(areq.ifra_name, netif->devname, IFNAMSIZ);
! 542: areq.ifra_name[IFNAMSIZ-1] = 0; /* Make sure to terminate */
! 543:
! 544: /* Create a channel to the NET kernel. */
! 545: if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
! 546: log_err(errno,
! 547: "socket() failed");
! 548: return -1;
! 549: }
! 550:
! 551: /* Delete any IP addresses until SIOCDIFADDR fails */
! 552: while (ioctl(fd, SIOCDIFADDR, (void *) &areq) != -1);
! 553:
! 554: close(fd);
! 555: return 0;
! 556:
! 557: #elif defined(__sun__)
! 558:
! 559: if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
! 560: log_err(errno, "Can't open /dev/udp");
! 561: return -1;
! 562: }
! 563:
! 564: if( (netif->fd = open("/dev/tun", O_RDWR, 0)) < 0){
! 565: log_err(errno, "Can't open /dev/tun");
! 566: return -1;
! 567: }
! 568:
! 569: /* Assign a new PPA and get its unit number. */
! 570: if( (ppa = ioctl(netif->fd, TUNNEWPPA, -1)) < 0){
! 571: log_err(errno, "Can't assign new interface");
! 572: return -1;
! 573: }
! 574:
! 575: if( (if_fd = open("/dev/tun", O_RDWR, 0)) < 0){
! 576: log_err(errno, "Can't open /dev/tun (2)");
! 577: return -1;
! 578: }
! 579: if(ioctl(if_fd, I_PUSH, "ip") < 0){
! 580: log_err(errno, "Can't push IP module");
! 581: return -1;
! 582: }
! 583:
! 584: /* Assign ppa according to the unit number returned by tun device */
! 585: if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
! 586: log_err(errno, "Can't set PPA %d", ppa);
! 587: return -1;
! 588: }
! 589:
! 590: /* Link the two streams */
! 591: if ((muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0) {
! 592: log_err(errno, "Can't link TUN device to IP");
! 593: return -1;
! 594: }
! 595:
! 596: close (if_fd);
! 597:
! 598: snprintf(netif->devname, sizeof(netif->devname), "tun%d", ppa);
! 599: netif->devname[sizeof(netif->devname)-1] = 0;
! 600:
! 601: memset(&ifr, 0, sizeof(ifr));
! 602: strcpy(ifr.ifr_name, netif->devname);
! 603: ifr.ifr_ip_muxid = muxid;
! 604:
! 605: if (ioctl(ip_fd, SIOCSIFMUXID, &ifr) < 0) {
! 606: ioctl(ip_fd, I_PUNLINK, muxid);
! 607: log_err(errno, "Can't set multiplexor id");
! 608: return -1;
! 609: }
! 610:
! 611: /* if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
! 612: msg (M_ERR, "Set file descriptor to non-blocking failed"); */
! 613:
! 614: return 0;
! 615:
! 616: #else
! 617: #error "Unknown platform!"
! 618: #endif
! 619:
! 620: }
! 621:
! 622: int tun_new(struct tun_t **ptun) {
! 623: struct tun_t *tun;
! 624:
! 625: if (!(tun = *ptun = calloc(1, sizeof(struct tun_t)))) {
! 626: log_err(errno, "calloc() failed");
! 627: return EOF;
! 628: }
! 629:
! 630: tuntap_interface(tun_nextif(tun));
! 631:
! 632: if (options.routeif) {
! 633: tun_discover(tun);
! 634: }
! 635:
! 636: return 0;
! 637: }
! 638:
! 639: int tun_free(struct tun_t *tun) {
! 640:
! 641: if (tun->routes) {
! 642: #warning fix this
! 643: /*XXX: todo! net_delete_route(&tuntap(tun)); */
! 644: }
! 645:
! 646: tun_close(tun);
! 647:
! 648: /* TODO: For solaris we need to unlink streams */
! 649:
! 650: free(tun);
! 651: return 0;
! 652: }
! 653:
! 654: int tun_set_cb_ind(struct tun_t *this,
! 655: int (*cb_ind) (struct tun_t *tun, void *pack, size_t len, int idx)) {
! 656: this->cb_ind = cb_ind;
! 657: return 0;
! 658: }
! 659:
! 660: int tun_decaps(struct tun_t *this, int idx) {
! 661:
! 662: #if defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__) || defined (__OpenBSD__) || defined (__NetBSD__)
! 663: unsigned char buffer[PACKET_MAX];
! 664: ssize_t status;
! 665:
! 666: if ((status = net_read(&tun(this, idx), buffer, sizeof(buffer))) <= 0) {
! 667: log_err(errno, "read() failed");
! 668: return -1;
! 669: }
! 670:
! 671: if (this->debug)
! 672: log_dbg("tun_decaps(%d) %s",status,tun(tun,idx).devname);
! 673:
! 674: if (0) { /* if we wanted to do nat'ing, it would could be done here */
! 675: struct in_addr a;
! 676: struct pkt_iphdr_t *iph = (struct pkt_iphdr_t *)buffer;
! 677: inet_aton("10.1.0.1", &a);
! 678: iph->daddr = a.s_addr;
! 679: chksum(iph);
! 680: }
! 681:
! 682: if (this->cb_ind)
! 683: #if defined (__OpenBSD__)
! 684: /* tun interface adds 4 bytes to front of packet under OpenBSD */
! 685: return this->cb_ind(this, buffer+4, status, idx);
! 686: #else
! 687: return this->cb_ind(this, buffer, status, idx);
! 688: #endif
! 689:
! 690: return 0;
! 691:
! 692: #elif defined (__sun__)
! 693: unsigned char buffer[PACKET_MAX];
! 694: struct strbuf sbuf;
! 695: int f = 0;
! 696:
! 697: sbuf.maxlen = PACKET_MAX;
! 698: sbuf.buf = buffer;
! 699: if (getmsg(tun(this, idx).fd, NULL, &sbuf, &f) < 0) {
! 700: log_err(errno, "getmsg() failed");
! 701: return -1;
! 702: }
! 703:
! 704: if (this->cb_ind)
! 705: return this->cb_ind(this, &packet, sbuf.len);
! 706:
! 707: return 0;
! 708:
! 709: #endif
! 710: }
! 711:
! 712: static uint32_t dnatip[1024];
! 713: static uint16_t dnatport[1024];
! 714:
! 715: int tun_encaps(struct tun_t *tun, void *pack, size_t len, int idx) {
! 716:
! 717: if (tun(tun, idx).flags & NET_ETHHDR) {
! 718:
! 719: struct pkt_ethhdr_t *ethh = (struct pkt_ethhdr_t *)pack;
! 720: /*memcpy(ethh->src, tun->tap_hwaddr, PKT_ETH_ALEN); */
! 721:
! 722: /** XXX **/
! 723: if (1) {
! 724: ethh->src[0]=0x00;
! 725: ethh->src[1]=0x17;
! 726: ethh->src[2]=0x3f;
! 727: ethh->src[3]=0x99;
! 728: ethh->src[4]=0xf4;
! 729: ethh->src[5]=0x46;
! 730:
! 731: ethh->dst[0]=0x00;
! 732: ethh->dst[1]=0x14;
! 733: ethh->dst[2]=0xBF;
! 734: ethh->dst[3]=0xE2;
! 735: ethh->dst[4]=0xC1;
! 736: ethh->dst[5]=0x75;
! 737: }
! 738:
! 739: log_dbg("writing to tun/tap src=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x dst=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
! 740: ethh->src[0],ethh->src[1],ethh->src[2],ethh->src[3],ethh->src[4],ethh->src[5],
! 741: ethh->dst[0],ethh->dst[1],ethh->dst[2],ethh->dst[3],ethh->dst[4],ethh->dst[5]);
! 742: } else {
! 743: pack += PKT_ETH_HLEN;
! 744: len -= PKT_ETH_HLEN;
! 745: }
! 746:
! 747: if (tun->debug)
! 748: log_dbg("tun_encaps(%d) %s",len,tun(tun,idx).devname);
! 749:
! 750: #if defined (__OpenBSD__)
! 751:
! 752: unsigned char buffer[PACKET_MAX+4];
! 753:
! 754: /* Can we user writev here to be more efficient??? */
! 755: *((uint32_t *)(&buffer))=htonl(AF_INET);
! 756: memcpy(&buffer[4], pack, PACKET_MAX);
! 757:
! 758: return net_write(&tun(tun, idx), buffer, len+4);
! 759:
! 760: #elif defined(__linux__) || defined (__FreeBSD__) || defined (__APPLE__) || defined (__NetBSD__)
! 761:
! 762: if (0) { /* if we wanted to do nat'ing we could do it here */
! 763: struct in_addr a;
! 764: struct pkt_iphdr_t *iph = (struct pkt_iphdr_t *)pack;
! 765: inet_aton("172.30.97.2", &a);
! 766: iph->saddr = a.s_addr;
! 767: chksum(iph);
! 768: }
! 769:
! 770: return net_write(&tun(tun, idx), pack, len);
! 771:
! 772: #elif defined (__sun__)
! 773:
! 774: struct strbuf sbuf;
! 775: sbuf.len = len;
! 776: sbuf.buf = pack;
! 777: return putmsg(tun(tun, idx).fd, NULL, &sbuf, 0);
! 778:
! 779: #endif
! 780: }
! 781:
! 782: int tun_runscript(struct tun_t *tun, char* script) {
! 783: char saddr[TUN_ADDRSIZE];
! 784: char smask[TUN_ADDRSIZE];
! 785: char b[TUN_ADDRSIZE];
! 786: struct in_addr net;
! 787: int status;
! 788:
! 789: net.s_addr = tuntap(tun).address.s_addr & tuntap(tun).netmask.s_addr;
! 790:
! 791: if ((status = fork()) < 0) {
! 792: log_err(errno, "fork() returned -1!");
! 793: return 0;
! 794: }
! 795:
! 796: if (status > 0) { /* Parent */
! 797: return 0;
! 798: }
! 799:
! 800: /*
! 801: #ifdef HAVE_CLEARENV
! 802: if (clearenv() != 0) {
! 803: log_err(errno,
! 804: "clearenv() did not return 0!");
! 805: exit(0);
! 806: }
! 807: #endif
! 808: */
! 809:
! 810: if (setenv("DEV", tuntap(tun).devname, 1) != 0) {
! 811: log_err(errno, "setenv() did not return 0!");
! 812: exit(0);
! 813: }
! 814:
! 815: strncpy(saddr, inet_ntoa(tuntap(tun).address), sizeof(saddr));
! 816: saddr[sizeof(saddr)-1] = 0;
! 817: if (setenv("ADDR", saddr, 1 ) != 0) {
! 818: log_err(errno, "setenv() did not return 0!");
! 819: exit(0);
! 820: }
! 821:
! 822: strncpy(smask, inet_ntoa(tuntap(tun).netmask), sizeof(smask));
! 823: smask[sizeof(smask)-1] = 0;
! 824: if (setenv("MASK", smask, 1) != 0) {
! 825: log_err(errno, "setenv() did not return 0!");
! 826: exit(0);
! 827: }
! 828:
! 829: strncpy(b, inet_ntoa(net), sizeof(b));
! 830: b[sizeof(b)-1] = 0;
! 831: if (setenv("NET", b, 1 ) != 0) {
! 832: log_err(errno, "setenv() did not return 0!");
! 833: exit(0);
! 834: }
! 835:
! 836: snprintf(b, sizeof(b), "%d", options.uamport);
! 837: if (setenv("UAMPORT", b, 1 ) != 0) {
! 838: log_err(errno, "setenv() did not return 0!");
! 839: exit(0);
! 840: }
! 841:
! 842: snprintf(b, sizeof(b), "%d", options.uamuiport);
! 843: if (setenv("UAMUIPORT", b, 1 ) != 0) {
! 844: log_err(errno, "setenv() did not return 0!");
! 845: exit(0);
! 846: }
! 847:
! 848: if (setenv("DHCPIF", options.dhcpif ? options.dhcpif : "", 1 ) != 0) {
! 849: log_err(errno, "setenv() did not return 0!");
! 850: exit(0);
! 851: }
! 852:
! 853: if (execl(script, script, tuntap(tun).devname, saddr, smask, (char *) 0) != 0) {
! 854: log_err(errno, "execl() did not return 0!");
! 855: exit(0);
! 856: }
! 857:
! 858: exit(0);
! 859: }
! 860:
! 861:
! 862: /* Currently unused
! 863: int tun_addroute2(struct tun_t *this,
! 864: struct in_addr *dst,
! 865: struct in_addr *gateway,
! 866: struct in_addr *mask) {
! 867:
! 868: struct {
! 869: struct nlmsghdr n;
! 870: struct rtmsg r;
! 871: char buf[TUN_NLBUFSIZE];
! 872: } req;
! 873:
! 874: struct sockaddr_nl local;
! 875: int addr_len;
! 876: int fd;
! 877: int status;
! 878: struct sockaddr_nl nladdr;
! 879: struct iovec iov;
! 880: struct msghdr msg;
! 881:
! 882: memset(&req, 0, sizeof(req));
! 883: req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
! 884: req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
! 885: req.n.nlmsg_type = RTM_NEWROUTE;
! 886: req.r.rtm_family = AF_INET;
! 887: req.r.rtm_table = RT_TABLE_MAIN;
! 888: req.r.rtm_protocol = RTPROT_BOOT;
! 889: req.r.rtm_scope = RT_SCOPE_UNIVERSE;
! 890: req.r.rtm_type = RTN_UNICAST;
! 891: tun_nlattr(&req.n, sizeof(req), RTA_DST, dst, 4);
! 892: tun_nlattr(&req.n, sizeof(req), RTA_GATEWAY, gateway, 4);
! 893:
! 894: if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) {
! 895: sys_err(LOG_ERR, __FILE__, __LINE__, errno,
! 896: "socket() failed");
! 897: return -1;
! 898: }
! 899:
! 900: memset(&local, 0, sizeof(local));
! 901: local.nl_family = AF_NETLINK;
! 902: local.nl_groups = 0;
! 903:
! 904: if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
! 905: sys_err(LOG_ERR, __FILE__, __LINE__, errno,
! 906: "bind() failed");
! 907: close(fd);
! 908: return -1;
! 909: }
! 910:
! 911: addr_len = sizeof(local);
! 912: if (getsockname(fd, (struct sockaddr*)&local, &addr_len) < 0) {
! 913: sys_err(LOG_ERR, __FILE__, __LINE__, errno,
! 914: "getsockname() failed");
! 915: close(fd);
! 916: return -1;
! 917: }
! 918:
! 919: if (addr_len != sizeof(local)) {
! 920: sys_err(LOG_ERR, __FILE__, __LINE__, 0,
! 921: "Wrong address length %d", addr_len);
! 922: close(fd);
! 923: return -1;
! 924: }
! 925:
! 926: if (local.nl_family != AF_NETLINK) {
! 927: sys_err(LOG_ERR, __FILE__, __LINE__, 0,
! 928: "Wrong address family %d", local.nl_family);
! 929: close(fd);
! 930: return -1;
! 931: }
! 932:
! 933: iov.iov_base = (void*)&req.n;
! 934: iov.iov_len = req.n.nlmsg_len;
! 935:
! 936: msg.msg_name = (void*)&nladdr;
! 937: msg.msg_namelen = sizeof(nladdr),
! 938: msg.msg_iov = &iov;
! 939: msg.msg_iovlen = 1;
! 940: msg.msg_control = NULL;
! 941: msg.msg_controllen = 0;
! 942: msg.msg_flags = 0;
! 943:
! 944: memset(&nladdr, 0, sizeof(nladdr));
! 945: nladdr.nl_family = AF_NETLINK;
! 946: nladdr.nl_pid = 0;
! 947: nladdr.nl_groups = 0;
! 948:
! 949: req.n.nlmsg_seq = 0;
! 950: req.n.nlmsg_flags |= NLM_F_ACK;
! 951:
! 952: status = sendmsg(fd, &msg, 0); * TODO: Error check *
! 953: close(fd);
! 954: return 0;
! 955: }
! 956: */
! 957:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>