Annotation of embedaddon/strongswan/src/libstrongswan/networking/tun_device.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2012 Tobias Brunner
        !             3:  * Copyright (C) 2012 Giuliano Grassi
        !             4:  * Copyright (C) 2012 Ralf Sager
        !             5:  * HSR Hochschule fuer Technik Rapperswil
        !             6:  * Copyright (C) 2012 Martin Willi
        !             7:  *
        !             8:  * This program is free software; you can redistribute it and/or modify it
        !             9:  * under the terms of the GNU General Public License as published by the
        !            10:  * Free Software Foundation; either version 2 of the License, or (at your
        !            11:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            12:  *
        !            13:  * This program is distributed in the hope that it will be useful, but
        !            14:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            15:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            16:  * for more details.
        !            17:  */
        !            18: 
        !            19: #include "tun_device.h"
        !            20: 
        !            21: #include <utils/debug.h>
        !            22: #include <threading/thread.h>
        !            23: 
        !            24: #if defined(__APPLE__)
        !            25: #include "TargetConditionals.h"
        !            26: #if !TARGET_OS_OSX
        !            27: #define TUN_DEVICE_NOT_SUPPORTED
        !            28: #endif
        !            29: #elif !defined(__linux__) && !defined(HAVE_NET_IF_TUN_H)
        !            30: #define TUN_DEVICE_NOT_SUPPORTED
        !            31: #endif
        !            32: 
        !            33: #ifdef TUN_DEVICE_NOT_SUPPORTED
        !            34: 
        !            35: tun_device_t *tun_device_create(const char *name_tmpl)
        !            36: {
        !            37:        DBG1(DBG_LIB, "TUN devices are not supported");
        !            38:        return NULL;
        !            39: }
        !            40: 
        !            41: #else /* TUN devices supported */
        !            42: 
        !            43: #include <errno.h>
        !            44: #include <fcntl.h>
        !            45: #include <netinet/in.h>
        !            46: #include <string.h>
        !            47: #include <sys/ioctl.h>
        !            48: #include <sys/types.h>
        !            49: #include <sys/socket.h>
        !            50: #include <sys/stat.h>
        !            51: #include <unistd.h>
        !            52: #include <net/if.h>
        !            53: 
        !            54: #ifdef __APPLE__
        !            55: #include <net/if_utun.h>
        !            56: #include <netinet/in_var.h>
        !            57: #include <sys/kern_control.h>
        !            58: #elif defined(__linux__)
        !            59: #include <linux/types.h>
        !            60: #include <linux/if_tun.h>
        !            61: #elif __FreeBSD__ >= 10
        !            62: #include <net/if_tun.h>
        !            63: #include <net/if_var.h>
        !            64: #include <netinet/in_var.h>
        !            65: #else
        !            66: #include <net/if_tun.h>
        !            67: #endif
        !            68: 
        !            69: #define TUN_DEFAULT_MTU 1500
        !            70: 
        !            71: typedef struct private_tun_device_t private_tun_device_t;
        !            72: 
        !            73: struct private_tun_device_t {
        !            74: 
        !            75:        /**
        !            76:         * Public interface
        !            77:         */
        !            78:        tun_device_t public;
        !            79: 
        !            80:        /**
        !            81:         * The TUN device's file descriptor
        !            82:         */
        !            83:        int tunfd;
        !            84: 
        !            85:        /**
        !            86:         * Name of the TUN device
        !            87:         */
        !            88:        char if_name[IFNAMSIZ];
        !            89: 
        !            90:        /**
        !            91:         * Socket used for ioctl() to set interface addr, ...
        !            92:         */
        !            93:        int sock;
        !            94: 
        !            95:        /**
        !            96:         * The current MTU
        !            97:         */
        !            98:        int mtu;
        !            99: 
        !           100:        /**
        !           101:         * Associated address
        !           102:         */
        !           103:        host_t *address;
        !           104: 
        !           105:        /**
        !           106:         * Netmask for address
        !           107:         */
        !           108:        uint8_t netmask;
        !           109: };
        !           110: 
        !           111: /**
        !           112:  * FreeBSD 10 deprecated the SIOCSIFADDR etc. commands.
        !           113:  */
        !           114: #if __FreeBSD__ >= 10
        !           115: 
        !           116: static bool set_address_and_mask(struct in_aliasreq *ifra, host_t *addr,
        !           117:                                                                 uint8_t netmask)
        !           118: {
        !           119:        host_t *mask;
        !           120: 
        !           121:        memcpy(&ifra->ifra_addr, addr->get_sockaddr(addr),
        !           122:                   *addr->get_sockaddr_len(addr));
        !           123:        /* set the same address as destination address */
        !           124:        memcpy(&ifra->ifra_dstaddr, addr->get_sockaddr(addr),
        !           125:                   *addr->get_sockaddr_len(addr));
        !           126: 
        !           127:        mask = host_create_netmask(addr->get_family(addr), netmask);
        !           128:        if (!mask)
        !           129:        {
        !           130:                DBG1(DBG_LIB, "invalid netmask: %d", netmask);
        !           131:                return FALSE;
        !           132:        }
        !           133:        memcpy(&ifra->ifra_mask, mask->get_sockaddr(mask),
        !           134:                   *mask->get_sockaddr_len(mask));
        !           135:        mask->destroy(mask);
        !           136:        return TRUE;
        !           137: }
        !           138: 
        !           139: /**
        !           140:  * Set the address using the more flexible SIOCAIFADDR/SIOCDIFADDR commands
        !           141:  * on FreeBSD 10 an newer.
        !           142:  */
        !           143: static bool set_address_impl(private_tun_device_t *this, host_t *addr,
        !           144:                                                         uint8_t netmask)
        !           145: {
        !           146:        struct in_aliasreq ifra;
        !           147: 
        !           148:        memset(&ifra, 0, sizeof(ifra));
        !           149:        strncpy(ifra.ifra_name, this->if_name, IFNAMSIZ);
        !           150: 
        !           151:        if (this->address)
        !           152:        {       /* remove the existing address first */
        !           153:                if (!set_address_and_mask(&ifra, this->address, this->netmask))
        !           154:                {
        !           155:                        return FALSE;
        !           156:                }
        !           157:                if (ioctl(this->sock, SIOCDIFADDR, &ifra) < 0)
        !           158:                {
        !           159:                        DBG1(DBG_LIB, "failed to remove existing address on %s: %s",
        !           160:                                 this->if_name, strerror(errno));
        !           161:                        return FALSE;
        !           162:                }
        !           163:        }
        !           164:        if (!set_address_and_mask(&ifra, addr, netmask))
        !           165:        {
        !           166:                return FALSE;
        !           167:        }
        !           168:        if (ioctl(this->sock, SIOCAIFADDR, &ifra) < 0)
        !           169:        {
        !           170:                DBG1(DBG_LIB, "failed to add address on %s: %s",
        !           171:                         this->if_name, strerror(errno));
        !           172:                return FALSE;
        !           173:        }
        !           174:        return TRUE;
        !           175: }
        !           176: 
        !           177: #else /* __FreeBSD__ */
        !           178: 
        !           179: /**
        !           180:  * Set the address using the classic SIOCSIFADDR etc. commands on other systems.
        !           181:  */
        !           182: static bool set_address_impl(private_tun_device_t *this, host_t *addr,
        !           183:                                                         uint8_t netmask)
        !           184: {
        !           185:        struct ifreq ifr;
        !           186:        host_t *mask;
        !           187: 
        !           188:        memset(&ifr, 0, sizeof(ifr));
        !           189:        strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
        !           190:        memcpy(&ifr.ifr_addr, addr->get_sockaddr(addr),
        !           191:                   *addr->get_sockaddr_len(addr));
        !           192: 
        !           193:        if (ioctl(this->sock, SIOCSIFADDR, &ifr) < 0)
        !           194:        {
        !           195:                DBG1(DBG_LIB, "failed to set address on %s: %s",
        !           196:                         this->if_name, strerror(errno));
        !           197:                return FALSE;
        !           198:        }
        !           199: #ifdef __APPLE__
        !           200:        if (ioctl(this->sock, SIOCSIFDSTADDR, &ifr) < 0)
        !           201:        {
        !           202:                DBG1(DBG_LIB, "failed to set dest address on %s: %s",
        !           203:                         this->if_name, strerror(errno));
        !           204:                return FALSE;
        !           205:        }
        !           206: #endif /* __APPLE__ */
        !           207: 
        !           208:        mask = host_create_netmask(addr->get_family(addr), netmask);
        !           209:        if (!mask)
        !           210:        {
        !           211:                DBG1(DBG_LIB, "invalid netmask: %d", netmask);
        !           212:                return FALSE;
        !           213:        }
        !           214:        memcpy(&ifr.ifr_addr, mask->get_sockaddr(mask),
        !           215:                   *mask->get_sockaddr_len(mask));
        !           216:        mask->destroy(mask);
        !           217: 
        !           218:        if (ioctl(this->sock, SIOCSIFNETMASK, &ifr) < 0)
        !           219:        {
        !           220:                DBG1(DBG_LIB, "failed to set netmask on %s: %s",
        !           221:                         this->if_name, strerror(errno));
        !           222:                return FALSE;
        !           223:        }
        !           224:        return TRUE;
        !           225: }
        !           226: 
        !           227: #endif /* __FreeBSD__ */
        !           228: 
        !           229: METHOD(tun_device_t, set_address, bool,
        !           230:        private_tun_device_t *this, host_t *addr, uint8_t netmask)
        !           231: {
        !           232:        if (!set_address_impl(this, addr, netmask))
        !           233:        {
        !           234:                return FALSE;
        !           235:        }
        !           236:        DESTROY_IF(this->address);
        !           237:        this->address = addr->clone(addr);
        !           238:        this->netmask = netmask;
        !           239:        return TRUE;
        !           240: }
        !           241: 
        !           242: METHOD(tun_device_t, get_address, host_t*,
        !           243:        private_tun_device_t *this, uint8_t *netmask)
        !           244: {
        !           245:        if (netmask && this->address)
        !           246:        {
        !           247:                *netmask = this->netmask;
        !           248:        }
        !           249:        return this->address;
        !           250: }
        !           251: 
        !           252: METHOD(tun_device_t, up, bool,
        !           253:        private_tun_device_t *this)
        !           254: {
        !           255:        struct ifreq ifr;
        !           256: 
        !           257:        memset(&ifr, 0, sizeof(ifr));
        !           258:        strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
        !           259: 
        !           260:        if (ioctl(this->sock, SIOCGIFFLAGS, &ifr) < 0)
        !           261:        {
        !           262:                DBG1(DBG_LIB, "failed to get interface flags for %s: %s", this->if_name,
        !           263:                         strerror(errno));
        !           264:                return FALSE;
        !           265:        }
        !           266: 
        !           267:        ifr.ifr_flags |= IFF_RUNNING | IFF_UP;
        !           268: 
        !           269:        if (ioctl(this->sock, SIOCSIFFLAGS, &ifr) < 0)
        !           270:        {
        !           271:                DBG1(DBG_LIB, "failed to set interface flags on %s: %s", this->if_name,
        !           272:                         strerror(errno));
        !           273:                return FALSE;
        !           274:        }
        !           275:        return TRUE;
        !           276: }
        !           277: 
        !           278: METHOD(tun_device_t, set_mtu, bool,
        !           279:        private_tun_device_t *this, int mtu)
        !           280: {
        !           281:        struct ifreq ifr;
        !           282: 
        !           283:        memset(&ifr, 0, sizeof(ifr));
        !           284:        strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
        !           285:        ifr.ifr_mtu = mtu;
        !           286: 
        !           287:        if (ioctl(this->sock, SIOCSIFMTU, &ifr) < 0)
        !           288:        {
        !           289:                DBG1(DBG_LIB, "failed to set MTU on %s: %s", this->if_name,
        !           290:                         strerror(errno));
        !           291:                return FALSE;
        !           292:        }
        !           293:        this->mtu = mtu;
        !           294:        return TRUE;
        !           295: }
        !           296: 
        !           297: METHOD(tun_device_t, get_mtu, int,
        !           298:        private_tun_device_t *this)
        !           299: {
        !           300:        struct ifreq ifr;
        !           301: 
        !           302:        if (this->mtu > 0)
        !           303:        {
        !           304:                return this->mtu;
        !           305:        }
        !           306: 
        !           307:        memset(&ifr, 0, sizeof(ifr));
        !           308:        strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
        !           309:        this->mtu = TUN_DEFAULT_MTU;
        !           310: 
        !           311:        if (ioctl(this->sock, SIOCGIFMTU, &ifr) == 0)
        !           312:        {
        !           313:                this->mtu = ifr.ifr_mtu;
        !           314:        }
        !           315:        return this->mtu;
        !           316: }
        !           317: 
        !           318: METHOD(tun_device_t, get_name, char*,
        !           319:        private_tun_device_t *this)
        !           320: {
        !           321:        return this->if_name;
        !           322: }
        !           323: 
        !           324: METHOD(tun_device_t, get_fd, int,
        !           325:        private_tun_device_t *this)
        !           326: {
        !           327:        return this->tunfd;
        !           328: }
        !           329: 
        !           330: METHOD(tun_device_t, write_packet, bool,
        !           331:        private_tun_device_t *this, chunk_t packet)
        !           332: {
        !           333:        ssize_t s;
        !           334: 
        !           335: #ifdef __APPLE__
        !           336:        /* UTUN's expect the packets to be prepended by a 32-bit protocol number
        !           337:         * instead of parsing the packet again, we assume IPv4 for now */
        !           338:        uint32_t proto = htonl(AF_INET);
        !           339:        packet = chunk_cata("cc", chunk_from_thing(proto), packet);
        !           340: #endif
        !           341:        s = write(this->tunfd, packet.ptr, packet.len);
        !           342:        if (s < 0)
        !           343:        {
        !           344:                DBG1(DBG_LIB, "failed to write packet to TUN device %s: %s",
        !           345:                         this->if_name, strerror(errno));
        !           346:                return FALSE;
        !           347:        }
        !           348:        else if (s != packet.len)
        !           349:        {
        !           350:                return FALSE;
        !           351:        }
        !           352:        return TRUE;
        !           353: }
        !           354: 
        !           355: METHOD(tun_device_t, read_packet, bool,
        !           356:        private_tun_device_t *this, chunk_t *packet)
        !           357: {
        !           358:        chunk_t data;
        !           359:        ssize_t len;
        !           360:        bool old;
        !           361: 
        !           362:        data = chunk_alloca(get_mtu(this));
        !           363: 
        !           364:        old = thread_cancelability(TRUE);
        !           365:        len = read(this->tunfd, data.ptr, data.len);
        !           366:        thread_cancelability(old);
        !           367:        if (len < 0)
        !           368:        {
        !           369:                DBG1(DBG_LIB, "reading from TUN device %s failed: %s", this->if_name,
        !           370:                         strerror(errno));
        !           371:                return FALSE;
        !           372:        }
        !           373:        data.len = len;
        !           374: #ifdef __APPLE__
        !           375:        /* UTUN's prepend packets with a 32-bit protocol number */
        !           376:        data = chunk_skip(data, sizeof(uint32_t));
        !           377: #endif
        !           378:        *packet = chunk_clone(data);
        !           379:        return TRUE;
        !           380: }
        !           381: 
        !           382: METHOD(tun_device_t, destroy, void,
        !           383:        private_tun_device_t *this)
        !           384: {
        !           385:        if (this->tunfd > 0)
        !           386:        {
        !           387:                close(this->tunfd);
        !           388: #ifdef __FreeBSD__
        !           389:                /* tun(4) says the following: "These network interfaces persist until
        !           390:                 * the if_tun.ko module is unloaded, or until removed with the
        !           391:                 * ifconfig(8) command."  So simply closing the FD is not enough. */
        !           392:                struct ifreq ifr;
        !           393: 
        !           394:                memset(&ifr, 0, sizeof(ifr));
        !           395:                strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
        !           396:                if (ioctl(this->sock, SIOCIFDESTROY, &ifr) < 0)
        !           397:                {
        !           398:                        DBG1(DBG_LIB, "failed to destroy %s: %s", this->if_name,
        !           399:                                 strerror(errno));
        !           400:                }
        !           401: #endif /* __FreeBSD__ */
        !           402:        }
        !           403:        if (this->sock > 0)
        !           404:        {
        !           405:                close(this->sock);
        !           406:        }
        !           407:        DESTROY_IF(this->address);
        !           408:        free(this);
        !           409: }
        !           410: 
        !           411: /**
        !           412:  * Initialize the tun device
        !           413:  */
        !           414: static bool init_tun(private_tun_device_t *this, const char *name_tmpl)
        !           415: {
        !           416: #ifdef __APPLE__
        !           417: 
        !           418:        struct ctl_info info;
        !           419:        struct sockaddr_ctl addr;
        !           420:        socklen_t size = IFNAMSIZ;
        !           421: 
        !           422:        memset(&info, 0, sizeof(info));
        !           423:        memset(&addr, 0, sizeof(addr));
        !           424: 
        !           425:        this->tunfd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
        !           426:        if (this->tunfd < 0)
        !           427:        {
        !           428:                DBG1(DBG_LIB, "failed to open tundevice PF_SYSTEM socket: %s",
        !           429:                         strerror(errno));
        !           430:                return FALSE;
        !           431:        }
        !           432: 
        !           433:        /* get a control identifier for the utun kernel extension */
        !           434:        strncpy(info.ctl_name, UTUN_CONTROL_NAME, strlen(UTUN_CONTROL_NAME));
        !           435:        if (ioctl(this->tunfd, CTLIOCGINFO, &info) < 0)
        !           436:        {
        !           437:                DBG1(DBG_LIB, "failed to ioctl tundevice: %s", strerror(errno));
        !           438:                close(this->tunfd);
        !           439:                return FALSE;
        !           440:        }
        !           441: 
        !           442:        addr.sc_id = info.ctl_id;
        !           443:        addr.sc_len = sizeof(addr);
        !           444:        addr.sc_family = AF_SYSTEM;
        !           445:        addr.ss_sysaddr = AF_SYS_CONTROL;
        !           446:        /* allocate identifier dynamically */
        !           447:        addr.sc_unit = 0;
        !           448: 
        !           449:        if (connect(this->tunfd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
        !           450:        {
        !           451:                DBG1(DBG_LIB, "failed to connect tundevice: %s", strerror(errno));
        !           452:                close(this->tunfd);
        !           453:                return FALSE;
        !           454:        }
        !           455:        if (getsockopt(this->tunfd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME,
        !           456:                                   this->if_name, &size) < 0)
        !           457:        {
        !           458:                DBG1(DBG_LIB, "getting tundevice name failed: %s", strerror(errno));
        !           459:                close(this->tunfd);
        !           460:                return FALSE;
        !           461:        }
        !           462:        return TRUE;
        !           463: 
        !           464: #elif defined(IFF_TUN)
        !           465: 
        !           466:        struct ifreq ifr;
        !           467: 
        !           468:        strncpy(this->if_name, name_tmpl ?: "tun%d", IFNAMSIZ);
        !           469:        this->if_name[IFNAMSIZ-1] = '\0';
        !           470: 
        !           471:        this->tunfd = open("/dev/net/tun", O_RDWR);
        !           472:        if (this->tunfd < 0)
        !           473:        {
        !           474:                DBG1(DBG_LIB, "failed to open /dev/net/tun: %s", strerror(errno));
        !           475:                return FALSE;
        !           476:        }
        !           477: 
        !           478:        memset(&ifr, 0, sizeof(ifr));
        !           479: 
        !           480:        /* TUN device, no packet info */
        !           481:        ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
        !           482: 
        !           483:        strncpy(ifr.ifr_name, this->if_name, IFNAMSIZ);
        !           484:        if (ioctl(this->tunfd, TUNSETIFF, (void*)&ifr) < 0)
        !           485:        {
        !           486:                DBG1(DBG_LIB, "failed to configure TUN device: %s", strerror(errno));
        !           487:                close(this->tunfd);
        !           488:                return FALSE;
        !           489:        }
        !           490:        strncpy(this->if_name, ifr.ifr_name, IFNAMSIZ);
        !           491:        return TRUE;
        !           492: 
        !           493: #elif defined(__FreeBSD__)
        !           494: 
        !           495:        if (name_tmpl)
        !           496:        {
        !           497:                DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported");
        !           498:        }
        !           499: 
        !           500:        this->tunfd = open("/dev/tun", O_RDWR);
        !           501:        if (this->tunfd < 0)
        !           502:        {
        !           503:                DBG1(DBG_LIB, "failed to open /dev/tun: %s", strerror(errno));
        !           504:                return FALSE;
        !           505:        }
        !           506:        fdevname_r(this->tunfd, this->if_name, IFNAMSIZ);
        !           507:        return TRUE;
        !           508: 
        !           509: #else /* !__FreeBSD__ */
        !           510: 
        !           511:        /* this might work on Linux with older TUN driver versions (no IFF_TUN) */
        !           512:        char devname[IFNAMSIZ];
        !           513:        /* the same process is allowed to open a device again, but that's not what
        !           514:         * we want (unless we previously closed a device, which we don't know at
        !           515:         * this point).  therefore, this counter is static so we don't accidentally
        !           516:         * open a device twice */
        !           517:        static int i = -1;
        !           518: 
        !           519:        if (name_tmpl)
        !           520:        {
        !           521:                DBG1(DBG_LIB, "arbitrary naming of TUN devices is not supported");
        !           522:        }
        !           523: 
        !           524:        for (; ++i < 256; )
        !           525:        {
        !           526:                snprintf(devname, IFNAMSIZ, "/dev/tun%d", i);
        !           527:                this->tunfd = open(devname, O_RDWR);
        !           528:                if (this->tunfd > 0)
        !           529:                {       /* for ioctl(2) calls only the interface name is used */
        !           530:                        snprintf(this->if_name, IFNAMSIZ, "tun%d", i);
        !           531:                        break;
        !           532:                }
        !           533:                DBG1(DBG_LIB, "failed to open %s: %s", this->if_name, strerror(errno));
        !           534:        }
        !           535:        return this->tunfd > 0;
        !           536: 
        !           537: #endif /* !__APPLE__ */
        !           538: }
        !           539: 
        !           540: /*
        !           541:  * Described in header
        !           542:  */
        !           543: tun_device_t *tun_device_create(const char *name_tmpl)
        !           544: {
        !           545:        private_tun_device_t *this;
        !           546: 
        !           547:        INIT(this,
        !           548:                .public = {
        !           549:                        .read_packet = _read_packet,
        !           550:                        .write_packet = _write_packet,
        !           551:                        .get_mtu = _get_mtu,
        !           552:                        .set_mtu = _set_mtu,
        !           553:                        .get_name = _get_name,
        !           554:                        .get_fd = _get_fd,
        !           555:                        .set_address = _set_address,
        !           556:                        .get_address = _get_address,
        !           557:                        .up = _up,
        !           558:                        .destroy = _destroy,
        !           559:                },
        !           560:                .tunfd = -1,
        !           561:                .sock = -1,
        !           562:        );
        !           563: 
        !           564:        if (!init_tun(this, name_tmpl))
        !           565:        {
        !           566:                free(this);
        !           567:                return NULL;
        !           568:        }
        !           569:        DBG1(DBG_LIB, "created TUN device: %s", this->if_name);
        !           570: 
        !           571:        this->sock = socket(AF_INET, SOCK_DGRAM, 0);
        !           572:        if (this->sock < 0)
        !           573:        {
        !           574:                DBG1(DBG_LIB, "failed to open socket to configure TUN device");
        !           575:                destroy(this);
        !           576:                return NULL;
        !           577:        }
        !           578:        return &this->public;
        !           579: }
        !           580: 
        !           581: #endif /* TUN devices supported */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>