"Fossies" - the Fresh Open Source Software Archive

Member "n2n-3.1.1/src/tuntap_linux.c" (31 Mar 2022, 8509 Bytes) of package /linux/misc/n2n-3.1.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tuntap_linux.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0_vs_3.1.1.

    1 /**
    2  * (C) 2007-22 - ntop.org and contributors
    3  *
    4  * This program is free software; you can redistribute it and/or modify
    5  * it under the terms of the GNU General Public License as published by
    6  * the Free Software Foundation; either version 3 of the License, or
    7  * (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not see see <http://www.gnu.org/licenses/>
   16  *
   17  */
   18 
   19 
   20 #ifdef __linux__
   21 
   22 
   23 #include "n2n.h"
   24 
   25 
   26 static int setup_ifname (int fd, const char *ifname, const char *ipaddr,
   27                          const char *netmask, uint8_t *mac, int mtu) {
   28 
   29     struct ifreq ifr;
   30 
   31     memset(&ifr, 0, sizeof(ifr));
   32 
   33     strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
   34     ifr.ifr_name[IFNAMSIZ-1] = '\0';
   35 
   36     ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
   37     memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
   38 
   39     if(ioctl(fd, SIOCSIFHWADDR, &ifr) == -1) {
   40         traceEvent(TRACE_ERROR, "ioctl(SIOCSIFHWADDR) failed [%d]: %s", errno, strerror(errno));
   41         return -1;
   42     }
   43 
   44     ifr.ifr_addr.sa_family = AF_INET;
   45 
   46     // interface address
   47     inet_pton(AF_INET, ipaddr, &((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr);
   48     if(ioctl(fd, SIOCSIFADDR, &ifr) == -1) {
   49         traceEvent(TRACE_ERROR, "ioctl(SIOCSIFADDR) failed [%d]: %s", errno, strerror(errno));
   50         return -2;
   51     }
   52 
   53     // netmask
   54     if(netmask && (((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr.s_addr != 0)) {
   55         inet_pton(AF_INET, netmask, &((struct sockaddr_in*)&ifr.ifr_addr)->sin_addr);
   56         if(ioctl(fd, SIOCSIFNETMASK, &ifr) == -1) {
   57             traceEvent(TRACE_ERROR, "ioctl(SIOCSIFNETMASK, %s) failed [%d]: %s", netmask, errno, strerror(errno));
   58             return -3;
   59         }
   60     }
   61 
   62     // MTU
   63     ifr.ifr_mtu = mtu;
   64     if(ioctl(fd, SIOCSIFMTU, &ifr) == -1) {
   65         traceEvent(TRACE_ERROR, "ioctl(SIOCSIFMTU) failed [%d]: %s", errno, strerror(errno));
   66         return -4;
   67     }
   68 
   69     // set up and running
   70     if(ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) {
   71         traceEvent(TRACE_ERROR, "ioctl(SIOCGIFFLAGS) failed [%d]: %s", errno, strerror(errno));
   72         return -5;
   73     }
   74 
   75     ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
   76 
   77     if(ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) {
   78         traceEvent(TRACE_ERROR, "ioctl(SIOCSIFFLAGS) failed [%d]: %s", errno, strerror(errno));
   79         return -6;
   80     }
   81 
   82     return 0;
   83 }
   84 
   85 
   86 /** @brief  Open and configure the TAP device for packet read/write.
   87  *
   88  *  This routine creates the interface via the tuntap driver and then
   89  *  configures it.
   90  *
   91  *  @param device      - [inout] a device info holder object
   92  *  @param dev         - user-defined name for the new iface,
   93  *                       if NULL system will assign a name
   94  *  @param device_ip   - address of iface
   95  *  @param device_mask - netmask for device_ip
   96  *  @param mtu         - MTU for device_ip
   97  *
   98  *  @return - negative value on error
   99  *          - non-negative file-descriptor on success
  100  */
  101 int tuntap_open (tuntap_dev *device,
  102                  char *dev, /* user-definable interface name, eg. edge0 */
  103                  const char *address_mode, /* static or dhcp */
  104                  char *device_ip,
  105                  char *device_mask,
  106                  const char * device_mac,
  107                  int mtu) {
  108 
  109     char *tuntap_device = "/dev/net/tun";
  110     int ioctl_fd;
  111     struct ifreq ifr;
  112     int rc;
  113     int nl_fd;
  114     char nl_buf[8192]; /* >= 8192 to avoid truncation, see "man 7 netlink" */
  115     struct iovec iov;
  116     struct sockaddr_nl sa;
  117     int up_and_running = 0;
  118     struct msghdr msg;
  119 
  120     device->fd = open(tuntap_device, O_RDWR);
  121     if(device->fd < 0) {
  122         traceEvent(TRACE_ERROR, "tuntap open() error: %s[%d]. Is the tun kernel module loaded?\n", strerror(errno), errno);
  123         return -1;
  124     }
  125 
  126     memset(&ifr, 0, sizeof(ifr));
  127 
  128     // want a TAP device for layer 2 frames
  129     ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
  130 
  131     strncpy(ifr.ifr_name, dev, IFNAMSIZ-1);
  132     ifr.ifr_name[IFNAMSIZ-1] = '\0';
  133     rc = ioctl(device->fd, TUNSETIFF, (void *)&ifr);
  134 
  135     if(rc < 0) {
  136         traceEvent(TRACE_ERROR, "tuntap ioctl(TUNSETIFF, IFF_TAP) error: %s[%d]\n", strerror(errno), rc);
  137         close(device->fd);
  138         return -1;
  139     }
  140 
  141     // store the device name for later reuse
  142     strncpy(device->dev_name, ifr.ifr_name, MIN(IFNAMSIZ, N2N_IFNAMSIZ));
  143 
  144     if(device_mac && device_mac[0]) {
  145         // use the user-provided MAC
  146         str2mac(device->mac_addr, device_mac);
  147     } else {
  148         // set an explicit random MAC to know the exact MAC in use, manually
  149         // reading the MAC address is not safe as it may change internally
  150         // also after the TAP interface UP status has been notified
  151 
  152         memrnd(device->mac_addr, N2N_MAC_SIZE);
  153 
  154         // clear multicast bit
  155         device->mac_addr[0] &= ~0x01;
  156 
  157         // set locally-assigned bit
  158         device->mac_addr[0] |= 0x02;
  159     }
  160 
  161     // initialize netlink socket
  162     if((nl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
  163         traceEvent(TRACE_ERROR, "netlink socket creation failed [%d]: %s", errno, strerror(errno));
  164         return -1;
  165     }
  166 
  167     iov.iov_base = nl_buf;
  168     iov.iov_len = sizeof(nl_buf);
  169 
  170     memset(&sa, 0, sizeof(sa));
  171     sa.nl_family = PF_NETLINK;
  172     sa.nl_groups = RTMGRP_LINK;
  173     sa.nl_pid = getpid();
  174 
  175     memset(&msg, 0, sizeof(msg));
  176     msg.msg_name = &sa;
  177     msg.msg_namelen = sizeof(sa);
  178     msg.msg_iov = &iov;
  179     msg.msg_iovlen = 1;
  180 
  181     // subscribe to interface events
  182     if(bind(nl_fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
  183         traceEvent(TRACE_ERROR, "netlink socket bind failed [%d]: %s", errno, strerror(errno));
  184         return -1;
  185     }
  186 
  187     if((ioctl_fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
  188         traceEvent(TRACE_ERROR, "socket creation failed [%d]: %s", errno, strerror(errno));
  189         close(nl_fd);
  190         return -1;
  191     }
  192 
  193     if(setup_ifname(ioctl_fd, device->dev_name, device_ip, device_mask, device->mac_addr, mtu) < 0) {
  194         close(nl_fd);
  195         close(ioctl_fd);
  196         close(device->fd);
  197         return -1;
  198     }
  199 
  200     close(ioctl_fd);
  201 
  202     // wait for the up and running notification
  203     traceEvent(TRACE_INFO, "Waiting for TAP interface to be up and running...");
  204 
  205     while(!up_and_running) {
  206         ssize_t len = recvmsg(nl_fd, &msg, 0);
  207         struct nlmsghdr *nh;
  208 
  209         for(nh = (struct nlmsghdr *)nl_buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) {
  210             if(nh->nlmsg_type == NLMSG_ERROR) {
  211                 traceEvent(TRACE_DEBUG, "nh->nlmsg_type == NLMSG_ERROR");
  212                 break;
  213             }
  214 
  215             if(nh->nlmsg_type == NLMSG_DONE)
  216                 break;
  217 
  218             if(nh->nlmsg_type == NETLINK_GENERIC) {
  219                 struct ifinfomsg *ifi = NLMSG_DATA(nh);
  220 
  221                 // NOTE: skipping interface name check, assuming it's our TAP
  222                 if((ifi->ifi_flags & IFF_UP) && (ifi->ifi_flags & IFF_RUNNING)) {
  223                     up_and_running = 1;
  224                     traceEvent(TRACE_INFO, "Interface is up and running");
  225                     break;
  226                 }
  227             }
  228         }
  229     }
  230 
  231     close(nl_fd);
  232 
  233     device->ip_addr = inet_addr(device_ip);
  234     device->device_mask = inet_addr(device_mask);
  235     device->if_idx = if_nametoindex(dev);
  236 
  237     return device->fd;
  238 }
  239 
  240 
  241 int tuntap_read (struct tuntap_dev *tuntap, unsigned char *buf, int len) {
  242 
  243     return read(tuntap->fd, buf, len);
  244 }
  245 
  246 
  247 int tuntap_write (struct tuntap_dev *tuntap, unsigned char *buf, int len) {
  248 
  249     return write(tuntap->fd, buf, len);
  250 }
  251 
  252 
  253 void tuntap_close (struct tuntap_dev *tuntap) {
  254 
  255     close(tuntap->fd);
  256 }
  257 
  258 
  259 // fill out the ip_addr value from the interface, called to pick up dynamic address changes
  260 void tuntap_get_address (struct tuntap_dev *tuntap) {
  261 
  262     struct ifreq ifr;
  263     int fd;
  264 
  265     if((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
  266         traceEvent(TRACE_ERROR, "socket creation failed [%d]: %s", errno, strerror(errno));
  267         return;
  268     }
  269 
  270     ifr.ifr_addr.sa_family = AF_INET;
  271     strncpy(ifr.ifr_name, tuntap->dev_name, IFNAMSIZ);
  272     ifr.ifr_name[IFNAMSIZ-1] = '\0';
  273 
  274     if(ioctl(fd, SIOCGIFADDR, &ifr) != -1)
  275         tuntap->ip_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;
  276 
  277     close(fd);
  278 }
  279 
  280 
  281 #endif /* #ifdef __linux__ */