ifc_utils.c revision 36f93f01201bbff4a411c73adfbaf08bd93b1ad2
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/if_ether.h>
31#include <linux/if_arp.h>
32#include <linux/sockios.h>
33#include <linux/route.h>
34#include <linux/ipv6_route.h>
35#include <netdb.h>
36#include <linux/wireless.h>
37
38#ifdef ANDROID
39#define LOG_TAG "NetUtils"
40#include <cutils/log.h>
41#include <cutils/properties.h>
42#else
43#include <stdio.h>
44#include <string.h>
45#define LOGD printf
46#define LOGW printf
47#endif
48
49static int ifc_ctl_sock = -1;
50static int ifc_ctl_sock6 = -1;
51void printerr(char *fmt, ...);
52
53static const char *ipaddr_to_string(in_addr_t addr)
54{
55    struct in_addr in_addr;
56
57    in_addr.s_addr = addr;
58    return inet_ntoa(in_addr);
59}
60
61int ifc_init(void)
62{
63    if (ifc_ctl_sock == -1) {
64        ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
65        if (ifc_ctl_sock < 0) {
66            printerr("socket() failed: %s\n", strerror(errno));
67        }
68    }
69    return ifc_ctl_sock < 0 ? -1 : 0;
70}
71
72int ifc_init6(void)
73{
74    if (ifc_ctl_sock6 == -1) {
75        ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM, 0);
76        if (ifc_ctl_sock6 < 0) {
77            printerr("socket() failed: %s\n", strerror(errno));
78        }
79    }
80    return ifc_ctl_sock6 < 0 ? -1 : 0;
81}
82
83void ifc_close(void)
84{
85    if (ifc_ctl_sock != -1) {
86        (void)close(ifc_ctl_sock);
87        ifc_ctl_sock = -1;
88    }
89}
90
91void ifc_close6(void)
92{
93    if (ifc_ctl_sock6 != -1) {
94        (void)close(ifc_ctl_sock6);
95        ifc_ctl_sock6 = -1;
96    }
97}
98
99static void ifc_init_ifr(const char *name, struct ifreq *ifr)
100{
101    memset(ifr, 0, sizeof(struct ifreq));
102    strncpy(ifr->ifr_name, name, IFNAMSIZ);
103    ifr->ifr_name[IFNAMSIZ - 1] = 0;
104}
105
106int ifc_get_hwaddr(const char *name, void *ptr)
107{
108    int r;
109    struct ifreq ifr;
110    ifc_init_ifr(name, &ifr);
111
112    r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr);
113    if(r < 0) return -1;
114
115    memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
116    return 0;
117}
118
119int ifc_get_ifindex(const char *name, int *if_indexp)
120{
121    int r;
122    struct ifreq ifr;
123    ifc_init_ifr(name, &ifr);
124
125    r = ioctl(ifc_ctl_sock, SIOCGIFINDEX, &ifr);
126    if(r < 0) return -1;
127
128    *if_indexp = ifr.ifr_ifindex;
129    return 0;
130}
131
132static int ifc_set_flags(const char *name, unsigned set, unsigned clr)
133{
134    struct ifreq ifr;
135    ifc_init_ifr(name, &ifr);
136
137    if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) return -1;
138    ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
139    return ioctl(ifc_ctl_sock, SIOCSIFFLAGS, &ifr);
140}
141
142int ifc_up(const char *name)
143{
144    return ifc_set_flags(name, IFF_UP, 0);
145}
146
147int ifc_down(const char *name)
148{
149    return ifc_set_flags(name, 0, IFF_UP);
150}
151
152static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr)
153{
154    struct sockaddr_in *sin = (struct sockaddr_in *) sa;
155    sin->sin_family = AF_INET;
156    sin->sin_port = 0;
157    sin->sin_addr.s_addr = addr;
158}
159
160int ifc_set_addr(const char *name, in_addr_t addr)
161{
162    struct ifreq ifr;
163
164    ifc_init_ifr(name, &ifr);
165    init_sockaddr_in(&ifr.ifr_addr, addr);
166
167    return ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
168}
169
170int ifc_set_hwaddr(const char *name, const void *ptr)
171{
172    int r;
173    struct ifreq ifr;
174    ifc_init_ifr(name, &ifr);
175
176    ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
177    memcpy(&ifr.ifr_hwaddr.sa_data, ptr, ETH_ALEN);
178    return ioctl(ifc_ctl_sock, SIOCSIFHWADDR, &ifr);
179}
180
181int ifc_set_mask(const char *name, in_addr_t mask)
182{
183    struct ifreq ifr;
184
185    ifc_init_ifr(name, &ifr);
186    init_sockaddr_in(&ifr.ifr_addr, mask);
187
188    return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
189}
190
191int ifc_get_info(const char *name, in_addr_t *addr, in_addr_t *mask, unsigned *flags)
192{
193    struct ifreq ifr;
194    ifc_init_ifr(name, &ifr);
195
196    if (addr != NULL) {
197        if(ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr) < 0) {
198            *addr = 0;
199        } else {
200            *addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
201        }
202    }
203
204    if (mask != NULL) {
205        if(ioctl(ifc_ctl_sock, SIOCGIFNETMASK, &ifr) < 0) {
206            *mask = 0;
207        } else {
208            *mask = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
209        }
210    }
211
212    if (flags != NULL) {
213        if(ioctl(ifc_ctl_sock, SIOCGIFFLAGS, &ifr) < 0) {
214            *flags = 0;
215        } else {
216            *flags = ifr.ifr_flags;
217        }
218    }
219
220    return 0;
221}
222
223in_addr_t get_ipv4_netmask(int prefix_length)
224{
225    in_addr_t mask = 0;
226
227    // C99 (6.5.7): shifts of 32 bits have undefined results
228    if (prefix_length == 0) {
229        return 0;
230    }
231
232    mask = ~mask << (32 - prefix_length);
233    mask = htonl(mask);
234
235    return mask;
236}
237
238int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length,
239      struct in_addr gw)
240{
241    struct rtentry rt;
242    int result;
243    in_addr_t netmask;
244
245    memset(&rt, 0, sizeof(rt));
246
247    rt.rt_dst.sa_family = AF_INET;
248    rt.rt_dev = (void*) ifname;
249
250    netmask = get_ipv4_netmask(prefix_length);
251    init_sockaddr_in(&rt.rt_genmask, netmask);
252    init_sockaddr_in(&rt.rt_dst, dst.s_addr);
253    rt.rt_flags = RTF_UP;
254
255    if (prefix_length == 32) {
256        rt.rt_flags |= RTF_HOST;
257    }
258
259    if (gw.s_addr != 0) {
260        rt.rt_flags |= RTF_GATEWAY;
261        init_sockaddr_in(&rt.rt_gateway, gw.s_addr);
262    }
263
264    ifc_init();
265
266    if (ifc_ctl_sock < 0) {
267        return -errno;
268    }
269
270    result = ioctl(ifc_ctl_sock, SIOCADDRT, &rt);
271    if (result < 0) {
272        if (errno == EEXIST) {
273            result = 0;
274        } else {
275            result = -errno;
276        }
277    }
278    ifc_close();
279    return result;
280}
281
282int ifc_create_default_route(const char *name, in_addr_t gw)
283{
284    struct in_addr in_dst, in_gw;
285
286    in_dst.s_addr = 0;
287    in_gw.s_addr = gw;
288
289    return ifc_add_ipv4_route(name, in_dst, 0, in_gw);
290}
291
292int ifc_add_host_route(const char *name, in_addr_t dst)
293{
294    struct in_addr in_dst, in_gw;
295
296    in_dst.s_addr = dst;
297    in_gw.s_addr = 0;
298
299    return ifc_add_ipv4_route(name, in_dst, 32, in_gw);
300}
301
302int ifc_enable(const char *ifname)
303{
304    int result;
305
306    ifc_init();
307    result = ifc_up(ifname);
308    ifc_close();
309    return result;
310}
311
312int ifc_disable(const char *ifname)
313{
314    int result;
315
316    ifc_init();
317    result = ifc_down(ifname);
318    ifc_set_addr(ifname, 0);
319    ifc_close();
320    return result;
321}
322
323int ifc_reset_connections(const char *ifname)
324{
325#ifdef HAVE_ANDROID_OS
326    int result;
327    in_addr_t myaddr;
328    struct ifreq ifr;
329
330    ifc_init();
331    ifc_get_info(ifname, &myaddr, NULL, NULL);
332    ifc_init_ifr(ifname, &ifr);
333    init_sockaddr_in(&ifr.ifr_addr, myaddr);
334    result = ioctl(ifc_ctl_sock, SIOCKILLADDR,  &ifr);
335    ifc_close();
336
337    return result;
338#else
339    return 0;
340#endif
341}
342
343/*
344 * Remove the routes associated with the named interface.
345 */
346int ifc_remove_host_routes(const char *name)
347{
348    char ifname[64];
349    in_addr_t dest, gway, mask;
350    int flags, refcnt, use, metric, mtu, win, irtt;
351    struct rtentry rt;
352    FILE *fp;
353    struct in_addr addr;
354
355    fp = fopen("/proc/net/route", "r");
356    if (fp == NULL)
357        return -1;
358    /* Skip the header line */
359    if (fscanf(fp, "%*[^\n]\n") < 0) {
360        fclose(fp);
361        return -1;
362    }
363    ifc_init();
364    for (;;) {
365        int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
366                           ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
367                           &mtu, &win, &irtt);
368        if (nread != 11) {
369            break;
370        }
371        if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)
372                || strcmp(ifname, name) != 0) {
373            continue;
374        }
375        memset(&rt, 0, sizeof(rt));
376        rt.rt_dev = (void *)name;
377        init_sockaddr_in(&rt.rt_dst, dest);
378        init_sockaddr_in(&rt.rt_gateway, gway);
379        init_sockaddr_in(&rt.rt_genmask, mask);
380        addr.s_addr = dest;
381        if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) {
382            LOGD("failed to remove route for %s to %s: %s",
383                 ifname, inet_ntoa(addr), strerror(errno));
384        }
385    }
386    fclose(fp);
387    ifc_close();
388    return 0;
389}
390
391/*
392 * Return the address of the default gateway
393 *
394 * TODO: factor out common code from this and remove_host_routes()
395 * so that we only scan /proc/net/route in one place.
396 */
397int ifc_get_default_route(const char *ifname)
398{
399    char name[64];
400    in_addr_t dest, gway, mask;
401    int flags, refcnt, use, metric, mtu, win, irtt;
402    int result;
403    FILE *fp;
404
405    fp = fopen("/proc/net/route", "r");
406    if (fp == NULL)
407        return 0;
408    /* Skip the header line */
409    if (fscanf(fp, "%*[^\n]\n") < 0) {
410        fclose(fp);
411        return 0;
412    }
413    ifc_init();
414    result = 0;
415    for (;;) {
416        int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
417                           name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
418                           &mtu, &win, &irtt);
419        if (nread != 11) {
420            break;
421        }
422        if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
423                && dest == 0
424                && strcmp(ifname, name) == 0) {
425            result = gway;
426            break;
427        }
428    }
429    fclose(fp);
430    ifc_close();
431    return result;
432}
433
434/*
435 * Sets the specified gateway as the default route for the named interface.
436 */
437int ifc_set_default_route(const char *ifname, in_addr_t gateway)
438{
439    struct in_addr addr;
440    int result;
441
442    ifc_init();
443    addr.s_addr = gateway;
444    if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
445        LOGD("failed to add %s as default route for %s: %s",
446             inet_ntoa(addr), ifname, strerror(errno));
447    }
448    ifc_close();
449    return result;
450}
451
452/*
453 * Removes the default route for the named interface.
454 */
455int ifc_remove_default_route(const char *ifname)
456{
457    struct rtentry rt;
458    int result;
459
460    ifc_init();
461    memset(&rt, 0, sizeof(rt));
462    rt.rt_dev = (void *)ifname;
463    rt.rt_flags = RTF_UP|RTF_GATEWAY;
464    init_sockaddr_in(&rt.rt_dst, 0);
465    if ((result = ioctl(ifc_ctl_sock, SIOCDELRT, &rt)) < 0) {
466        LOGD("failed to remove default route for %s: %s", ifname, strerror(errno));
467    }
468    ifc_close();
469    return result;
470}
471
472int
473ifc_configure(const char *ifname,
474        in_addr_t address,
475        in_addr_t netmask,
476        in_addr_t gateway,
477        in_addr_t dns1,
478        in_addr_t dns2) {
479
480    char dns_prop_name[PROPERTY_KEY_MAX];
481
482    ifc_init();
483
484    if (ifc_up(ifname)) {
485        printerr("failed to turn on interface %s: %s\n", ifname, strerror(errno));
486        ifc_close();
487        return -1;
488    }
489    if (ifc_set_addr(ifname, address)) {
490        printerr("failed to set ipaddr %s: %s\n", ipaddr_to_string(address), strerror(errno));
491        ifc_close();
492        return -1;
493    }
494    if (ifc_set_mask(ifname, netmask)) {
495        printerr("failed to set netmask %s: %s\n", ipaddr_to_string(netmask), strerror(errno));
496        ifc_close();
497        return -1;
498    }
499    if (ifc_create_default_route(ifname, gateway)) {
500        printerr("failed to set default route %s: %s\n", ipaddr_to_string(gateway), strerror(errno));
501        ifc_close();
502        return -1;
503    }
504
505    ifc_close();
506
507    snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", ifname);
508    property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : "");
509    snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname);
510    property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : "");
511
512    return 0;
513}
514
515int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length,
516      struct in6_addr gw)
517{
518    struct in6_rtmsg rtmsg;
519    int result;
520    int ifindex;
521
522    memset(&rtmsg, 0, sizeof(rtmsg));
523
524    ifindex = if_nametoindex(ifname);
525    if (ifindex == 0) {
526        printerr("if_nametoindex() failed: interface %s\n", ifname);
527        return -ENXIO;
528    }
529
530    rtmsg.rtmsg_ifindex = ifindex;
531    rtmsg.rtmsg_dst = dst;
532    rtmsg.rtmsg_dst_len = prefix_length;
533    rtmsg.rtmsg_flags = RTF_UP;
534
535    if (prefix_length == 128) {
536        rtmsg.rtmsg_flags |= RTF_HOST;
537    }
538
539    if (memcmp(&gw, &in6addr_any, sizeof(in6addr_any))) {
540        rtmsg.rtmsg_flags |= RTF_GATEWAY;
541        rtmsg.rtmsg_gateway = gw;
542    }
543
544    ifc_init6();
545
546    if (ifc_ctl_sock6 < 0) {
547        return -errno;
548    }
549
550    result = ioctl(ifc_ctl_sock6, SIOCADDRT, &rtmsg);
551    if (result < 0) {
552        if (errno == EEXIST) {
553            result = 0;
554        } else {
555            result = -errno;
556        }
557    }
558    ifc_close6();
559    return result;
560}
561
562int ifc_add_route(const char *ifname, const char *dst, int prefix_length,
563      const char *gw)
564{
565    int ret = 0;
566    struct sockaddr_in ipv4_dst, ipv4_gw;
567    struct sockaddr_in6 ipv6_dst, ipv6_gw;
568    struct addrinfo hints, *addr_ai, *gw_ai;
569
570    memset(&hints, 0, sizeof(hints));
571    hints.ai_family = AF_UNSPEC;  /* Allow IPv4 or IPv6 */
572    hints.ai_flags = AI_NUMERICHOST;
573
574    ret = getaddrinfo(dst, NULL, &hints, &addr_ai);
575
576    if (ret != 0) {
577        printerr("getaddrinfo failed: invalid address %s\n", dst);
578        return -EINVAL;
579    }
580
581    if (gw == NULL) {
582        if (addr_ai->ai_family == AF_INET6) {
583            gw = "::";
584        } else if (addr_ai->ai_family == AF_INET) {
585            gw = "0.0.0.0";
586        }
587    }
588
589    ret = getaddrinfo(gw, NULL, &hints, &gw_ai);
590    if (ret != 0) {
591        printerr("getaddrinfo failed: invalid gateway %s\n", gw);
592        freeaddrinfo(addr_ai);
593        return -EINVAL;
594    }
595
596    if (addr_ai->ai_family != gw_ai->ai_family) {
597        printerr("ifc_add_route: different address families: %s and %s\n", dst, gw);
598        freeaddrinfo(addr_ai);
599        freeaddrinfo(gw_ai);
600        return -EINVAL;
601    }
602
603    if (addr_ai->ai_family == AF_INET6) {
604        memcpy(&ipv6_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in6));
605        memcpy(&ipv6_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in6));
606        ret = ifc_add_ipv6_route(ifname, ipv6_dst.sin6_addr, prefix_length,
607              ipv6_gw.sin6_addr);
608    } else if (addr_ai->ai_family == AF_INET) {
609        memcpy(&ipv4_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in));
610        memcpy(&ipv4_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in));
611        ret = ifc_add_ipv4_route(ifname, ipv4_dst.sin_addr, prefix_length,
612              ipv4_gw.sin_addr);
613    } else {
614        printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n",
615                  addr_ai->ai_family);
616        ret = -EAFNOSUPPORT;
617    }
618
619    freeaddrinfo(addr_ai);
620    freeaddrinfo(gw_ai);
621    return ret;
622}
623