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>