Home | History | Annotate | Download | only in libnetutils
      1 /*
      2  * Copyright 2008, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdio.h>
     18 #include <stdlib.h>
     19 #include <unistd.h>
     20 #include <string.h>
     21 #include <errno.h>
     22 
     23 #include <sys/socket.h>
     24 #include <sys/select.h>
     25 #include <sys/types.h>
     26 #include <netinet/in.h>
     27 #include <arpa/inet.h>
     28 
     29 #include <linux/if.h>
     30 #include <linux/sockios.h>
     31 #include <linux/route.h>
     32 #include <linux/wireless.h>
     33 
     34 #ifdef ANDROID
     35 #define LOG_TAG "NetUtils"
     36 #include <cutils/log.h>
     37 #include <cutils/properties.h>
     38 #else
     39 #include <stdio.h>
     40 #include <string.h>
     41 #define LOGD printf
     42 #define LOGW printf
     43 #endif
     44 
     45 static int ifc_ctl_sock = -1;
     46 void printerr(char *fmt, ...);
     47 
     48 static const char *ipaddr_to_string(uint32_t addr)
     49 {
     50     struct in_addr in_addr;
     51 
     52     in_addr.s_addr = addr;
     53     return inet_ntoa(in_addr);
     54 }
     55 
     56 int ifc_init(void)
     57 {
     58     if (ifc_ctl_sock == -1) {
     59         ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
     60         if (ifc_ctl_sock < 0) {
     61             printerr("socket() failed: %s\n", strerror(errno));
     62         }
     63     }
     64     return ifc_ctl_sock < 0 ? -1 : 0;
     65 }
     66 
     67 void ifc_close(void)
     68 {
     69     if (ifc_ctl_sock != -1) {
     70         (void)close(ifc_ctl_sock);
     71         ifc_ctl_sock = -1;
     72     }
     73 }
     74 
     75 static void ifc_init_ifr(const char *name, struct ifreq *ifr)
     76 {
     77     memset(ifr, 0, sizeof(struct ifreq));
     78     strncpy(ifr->ifr_name, name, IFNAMSIZ);
     79     ifr->ifr_name[IFNAMSIZ - 1] = 0;
     80 }
     81 
     82 int ifc_get_hwaddr(const char *name, void *ptr)
     83 {
     84     int r;
     85     struct ifreq ifr;
     86     ifc_init_ifr(name, &ifr);
     87 
     88     r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr);
     89     if(r < 0) return -1;
     90 
     91     memcpy(ptr, &ifr.ifr_hwaddr.sa_data, 6);
     92     return 0;
     93 }
     94 
     95 int ifc_get_ifindex(const char *name, int *if_indexp)
     96 {
     97     int r;
     98     struct ifreq ifr;
     99     ifc_init_ifr(name, &ifr);
    100 
    101     r = ioctl(ifc_ctl_sock, SIOCGIFINDEX, &ifr);
    102     if(r < 0) return -1;
    103 
    104     *if_indexp = ifr.ifr_ifindex;
    105     return 0;
    106 }
    107 
    108 static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
    109 {
    110     struct ifreq ifr;
    111     ifc_init_ifr(name, &ifr);
    112 
    113     if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) return -1;
    114     ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
    115     return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr);
    116 }
    117 
    118 int ifc_up(const char *name)
    119 {
    120     return ifc_set_flags(name, IFF_UP, 0);
    121 }
    122 
    123 int ifc_down(const char *name)
    124 {
    125     return ifc_set_flags(name, 0, IFF_UP);
    126 }
    127 
    128 static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr)
    129 {
    130     struct sockaddr_in *sin = (struct sockaddr_in *) sa;
    131     sin->sin_family = AF_INET;
    132     sin->sin_port = 0;
    133     sin->sin_addr.s_addr = addr;
    134 }
    135 
    136 int ifc_set_addr(const char *name, in_addr_t addr)
    137 {
    138     struct ifreq ifr;
    139 
    140     ifc_init_ifr(name, &ifr);
    141     init_sockaddr_in(&ifr.ifr_addr, addr);
    142 
    143     return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
    144 }
    145 
    146 int ifc_set_mask(const char *name, in_addr_t mask)
    147 {
    148     struct ifreq ifr;
    149 
    150     ifc_init_ifr(name, &ifr);
    151     init_sockaddr_in(&ifr.ifr_addr, mask);
    152 
    153     return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
    154 }
    155 
    156 int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
    157 {
    158     struct ifreq ifr;
    159     ifc_init_ifr(name, &ifr);
    160 
    161     if (addr != NULL) {
    162         if(ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr) < 0) {
    163             *addr = 0;
    164         } else {
    165             *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
    166         }
    167     }
    168 
    169     if (mask != NULL) {
    170         if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
    171             *mask = 0;
    172         } else {
    173             *mask = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
    174         }
    175     }
    176 
    177     if (flags != NULL) {
    178         if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) {
    179             *flags = 0;
    180         } else {
    181             *flags = ifr.ifr_flags;
    182         }
    183     }
    184 
    185     return 0;
    186 }
    187 
    188 
    189 int ifc_create_default_route(const char *name, in_addr_t addr)
    190 {
    191     struct rtentry rt;
    192 
    193     memset(&rt, 0, sizeof(rt));
    194 
    195     rt.rt_dst.sa_family = AF_INET;
    196     rt.rt_flags = RTF_UP | RTF_GATEWAY;
    197     rt.rt_dev = (void*) name;
    198     init_sockaddr_in(&rt.rt_genmask, 0);
    199     init_sockaddr_in(&rt.rt_gateway, addr);
    200 
    201     return ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
    202 }
    203 
    204 int ifc_add_host_route(const char *name, in_addr_t addr)
    205 {
    206     struct rtentry rt;
    207     int result;
    208 
    209     memset(&rt, 0, sizeof(rt));
    210 
    211     rt.rt_dst.sa_family = AF_INET;
    212     rt.rt_flags = RTF_UP | RTF_HOST;
    213     rt.rt_dev = (void*) name;
    214     init_sockaddr_in(&rt.rt_dst, addr);
    215     init_sockaddr_in(&rt.rt_genmask, 0);
    216     init_sockaddr_in(&rt.rt_gateway, 0);
    217 
    218     ifc_init();
    219     result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
    220     if (result < 0 && errno == EEXIST) {
    221         result = 0;
    222     }
    223     ifc_close();
    224     return result;
    225 }
    226 
    227 int ifc_enable(const char *ifname)
    228 {
    229     int result;
    230 
    231     ifc_init();
    232     result = ifc_up(ifname);
    233     ifc_close();
    234     return result;
    235 }
    236 
    237 int ifc_disable(const char *ifname)
    238 {
    239     int result;
    240 
    241     ifc_init();
    242     result = ifc_down(ifname);
    243     ifc_set_addr(ifname, 0);
    244     ifc_close();
    245     return result;
    246 }
    247 
    248 int ifc_reset_connections(const char *ifname)
    249 {
    250 #ifdef HAVE_ANDROID_OS
    251     int result;
    252     in_addr_t myaddr;
    253     struct ifreq ifr;
    254 
    255     ifc_init();
    256     ifc_get_info(ifname, &myaddr, NULL, NULL);
    257     ifc_init_ifr(ifname, &ifr);
    258     init_sockaddr_in(&ifr.ifr_addr, myaddr);
    259     result = ioctl(ifc_ctl_sock, SIOCKILLADDR,  &ifr);
    260     ifc_close();
    261 
    262     return result;
    263 #else
    264     return 0;
    265 #endif
    266 }
    267 
    268 /*
    269  * Remove the routes associated with the named interface.
    270  */
    271 int ifc_remove_host_routes(const char *name)
    272 {
    273     char ifname[64];
    274     in_addr_t dest, gway, mask;
    275     int flags, refcnt, use, metric, mtu, win, irtt;
    276     struct rtentry rt;
    277     FILE *fp;
    278     struct in_addr addr;
    279 
    280     fp = fopen("/proc/net/route", "r");
    281     if (fp == NULL)
    282         return -1;
    283     /* Skip the header line */
    284     if (fscanf(fp, "%*[^\n]\n") < 0) {
    285         fclose(fp);
    286         return -1;
    287     }
    288     ifc_init();
    289     for (;;) {
    290         int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
    291                            ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
    292                            &mtu, &win, &irtt);
    293         if (nread != 11) {
    294             break;
    295         }
    296         if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)
    297                 || strcmp(ifname, name) != 0) {
    298             continue;
    299         }
    300         memset(&rt, 0, sizeof(rt));
    301         rt.rt_dev = (void *)name;
    302         init_sockaddr_in(&rt.rt_dst, dest);
    303         init_sockaddr_in(&rt.rt_gateway, gway);
    304         init_sockaddr_in(&rt.rt_genmask, mask);
    305         addr.s_addr = dest;
    306         if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) {
    307             LOGD("failed to remove route for %s to %s: %s",
    308                  ifname, inet_ntoa(addr), strerror(errno));
    309         }
    310     }
    311     fclose(fp);
    312     ifc_close();
    313     return 0;
    314 }
    315 
    316 /*
    317  * Return the address of the default gateway
    318  *
    319  * TODO: factor out common code from this and remove_host_routes()
    320  * so that we only scan /proc/net/route in one place.
    321  */
    322 int ifc_get_default_route(const char *ifname)
    323 {
    324     char name[64];
    325     in_addr_t dest, gway, mask;
    326     int flags, refcnt, use, metric, mtu, win, irtt;
    327     int result;
    328     FILE *fp;
    329 
    330     fp = fopen("/proc/net/route", "r");
    331     if (fp == NULL)
    332         return 0;
    333     /* Skip the header line */
    334     if (fscanf(fp, "%*[^\n]\n") < 0) {
    335         fclose(fp);
    336         return 0;
    337     }
    338     ifc_init();
    339     result = 0;
    340     for (;;) {
    341         int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
    342                            name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
    343                            &mtu, &win, &irtt);
    344         if (nread != 11) {
    345             break;
    346         }
    347         if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
    348                 && dest == 0
    349                 && strcmp(ifname, name) == 0) {
    350             result = gway;
    351             break;
    352         }
    353     }
    354     fclose(fp);
    355     ifc_close();
    356     return result;
    357 }
    358 
    359 /*
    360  * Sets the specified gateway as the default route for the named interface.
    361  */
    362 int ifc_set_default_route(const char *ifname, in_addr_t gateway)
    363 {
    364     struct in_addr addr;
    365     int result;
    366 
    367     ifc_init();
    368     addr.s_addr = gateway;
    369     if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
    370         LOGD("failed to add %s as default route for %s: %s",
    371              inet_ntoa(addr), ifname, strerror(errno));
    372     }
    373     ifc_close();
    374     return result;
    375 }
    376 
    377 /*
    378  * Removes the default route for the named interface.
    379  */
    380 int ifc_remove_default_route(const char *ifname)
    381 {
    382     struct rtentry rt;
    383     int result;
    384 
    385     ifc_init();
    386     memset(&rt, 0, sizeof(rt));
    387     rt.rt_dev = (void *)ifname;
    388     rt.rt_flags = RTF_UP|RTF_GATEWAY;
    389     init_sockaddr_in(&rt.rt_dst, 0);
    390     if ((result = ioctl(ifc_ctl_sock, SIOCDELRT, &rt)) < 0) {
    391         LOGD("failed to remove default route for %s: %s", ifname, strerror(errno));
    392     }
    393     ifc_close();
    394     return result;
    395 }
    396 
    397 int
    398 ifc_configure(const char *ifname,
    399         in_addr_t address,
    400         in_addr_t netmask,
    401         in_addr_t gateway,
    402         in_addr_t dns1,
    403         in_addr_t dns2) {
    404 
    405     char dns_prop_name[PROPERTY_KEY_MAX];
    406 
    407     ifc_init();
    408 
    409     if (ifc_up(ifname)) {
    410         printerr("failed to turn on interface %s: %s\n", ifname, strerror(errno));
    411         ifc_close();
    412         return -1;
    413     }
    414     if (ifc_set_addr(ifname, address)) {
    415         printerr("failed to set ipaddr %s: %s\n", ipaddr_to_string(address), strerror(errno));
    416         ifc_close();
    417         return -1;
    418     }
    419     if (ifc_set_mask(ifname, netmask)) {
    420         printerr("failed to set netmask %s: %s\n", ipaddr_to_string(netmask), strerror(errno));
    421         ifc_close();
    422         return -1;
    423     }
    424     if (ifc_create_default_route(ifname, gateway)) {
    425         printerr("failed to set default route %s: %s\n", ipaddr_to_string(gateway), strerror(errno));
    426         ifc_close();
    427         return -1;
    428     }
    429 
    430     ifc_close();
    431 
    432     snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns1", ifname);
    433     property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : "");
    434     snprintf(dns_prop_name, sizeof(dns_prop_name), "dhcp.%s.dns2", ifname);
    435     property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : "");
    436 
    437     return 0;
    438 }
    439