• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ipaddr_to_string(uint32_t addr)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 
ifc_init(void)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 
ifc_close(void)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 
ifc_init_ifr(const char * name,struct ifreq * ifr)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 
ifc_get_hwaddr(const char * name,void * ptr)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 
ifc_get_ifindex(const char * name,int * if_indexp)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 
ifc_set_flags(const char * name,unsigned set,unsigned clr)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 
ifc_up(const char * name)118 int ifc_up(const char *name)
119 {
120     return ifc_set_flags(name, IFF_UP, 0);
121 }
122 
ifc_down(const char * name)123 int ifc_down(const char *name)
124 {
125     return ifc_set_flags(name, 0, IFF_UP);
126 }
127 
init_sockaddr_in(struct sockaddr * sa,in_addr_t addr)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 
ifc_set_addr(const char * name,in_addr_t addr)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 
ifc_set_mask(const char * name,in_addr_t mask)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 
ifc_get_info(const char * name,in_addr_t * addr,in_addr_t * mask,unsigned * flags)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 
ifc_create_default_route(const char * name,in_addr_t addr)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 
ifc_add_host_route(const char * name,in_addr_t addr)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 
ifc_enable(const char * ifname)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 
ifc_disable(const char * ifname)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 
ifc_reset_connections(const char * ifname)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  */
ifc_remove_host_routes(const char * name)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  */
ifc_get_default_route(const char * ifname)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  */
ifc_set_default_route(const char * ifname,in_addr_t gateway)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  */
ifc_remove_default_route(const char * ifname)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
ifc_configure(const char * ifname,in_addr_t address,in_addr_t netmask,in_addr_t gateway,in_addr_t dns1,in_addr_t dns2)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