blob: 85a4497fdd99b1595c0a01d82abefba2419b8160 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2012 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#if defined(WEBRTC_ANDROID)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020012#include "rtc_base/ifaddrs-android.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013#include <errno.h>
14#include <linux/netlink.h>
15#include <linux/rtnetlink.h>
kjellandere96c45b2017-06-30 10:45:21 -070016#include <net/if.h>
17#include <netinet/in.h>
18#include <stdlib.h>
19#include <string.h>
20#include <sys/ioctl.h>
21#include <sys/socket.h>
22#include <sys/types.h>
23#include <sys/utsname.h>
24#include <unistd.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025
henrike@webrtc.orgc50bf7c2014-05-14 18:24:13 +000026namespace {
27
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000028struct netlinkrequest {
29 nlmsghdr header;
30 ifaddrmsg msg;
31};
32
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000033const int kMaxReadSize = 4096;
henrike@webrtc.orgc50bf7c2014-05-14 18:24:13 +000034
35} // namespace
36
37namespace rtc {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000038
39int set_ifname(struct ifaddrs* ifaddr, int interface) {
40 char buf[IFNAMSIZ] = {0};
41 char* name = if_indextoname(interface, buf);
deadbeef37f5ecf2017-02-27 14:06:41 -080042 if (name == nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000043 return -1;
44 }
45 ifaddr->ifa_name = new char[strlen(name) + 1];
46 strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
47 return 0;
48}
49
50int set_flags(struct ifaddrs* ifaddr) {
51 int fd = socket(AF_INET, SOCK_DGRAM, 0);
52 if (fd == -1) {
53 return -1;
54 }
55 ifreq ifr;
56 memset(&ifr, 0, sizeof(ifr));
57 strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
58 int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
59 close(fd);
60 if (rc == -1) {
61 return -1;
62 }
63 ifaddr->ifa_flags = ifr.ifr_flags;
64 return 0;
65}
66
67int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
68 size_t len) {
69 if (msg->ifa_family == AF_INET) {
70 sockaddr_in* sa = new sockaddr_in;
71 sa->sin_family = AF_INET;
72 memcpy(&sa->sin_addr, data, len);
73 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
74 } else if (msg->ifa_family == AF_INET6) {
75 sockaddr_in6* sa = new sockaddr_in6;
76 sa->sin6_family = AF_INET6;
77 sa->sin6_scope_id = msg->ifa_index;
78 memcpy(&sa->sin6_addr, data, len);
79 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
80 } else {
81 return -1;
82 }
83 return 0;
84}
85
86int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
deadbeef37f5ecf2017-02-27 14:06:41 -080087 char* prefix = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088 if (family == AF_INET) {
89 sockaddr_in* mask = new sockaddr_in;
90 mask->sin_family = AF_INET;
91 memset(&mask->sin_addr, 0, sizeof(in_addr));
92 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
93 if (prefixlen > 32) {
94 prefixlen = 32;
95 }
96 prefix = reinterpret_cast<char*>(&mask->sin_addr);
97 } else if (family == AF_INET6) {
98 sockaddr_in6* mask = new sockaddr_in6;
99 mask->sin6_family = AF_INET6;
100 memset(&mask->sin6_addr, 0, sizeof(in6_addr));
101 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
102 if (prefixlen > 128) {
103 prefixlen = 128;
104 }
105 prefix = reinterpret_cast<char*>(&mask->sin6_addr);
106 } else {
107 return -1;
108 }
109 for (int i = 0; i < (prefixlen / 8); i++) {
110 *prefix++ = 0xFF;
111 }
112 char remainder = 0xff;
113 remainder <<= (8 - prefixlen % 8);
114 *prefix = remainder;
115 return 0;
116}
117
118int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
119 size_t len) {
120 if (set_ifname(ifaddr, msg->ifa_index) != 0) {
121 return -1;
122 }
123 if (set_flags(ifaddr) != 0) {
124 return -1;
125 }
126 if (set_addresses(ifaddr, msg, bytes, len) != 0) {
127 return -1;
128 }
129 if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
130 return -1;
131 }
132 return 0;
133}
134
135int getifaddrs(struct ifaddrs** result) {
136 int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
137 if (fd < 0) {
138 return -1;
139 }
140
141 netlinkrequest ifaddr_request;
142 memset(&ifaddr_request, 0, sizeof(ifaddr_request));
143 ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
144 ifaddr_request.header.nlmsg_type = RTM_GETADDR;
145 ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
146
147 ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
148 if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
149 close(fd);
150 return -1;
151 }
deadbeef37f5ecf2017-02-27 14:06:41 -0800152 struct ifaddrs* start = nullptr;
153 struct ifaddrs* current = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154 char buf[kMaxReadSize];
155 ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
156 while (amount_read > 0) {
157 nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
158 size_t header_size = static_cast<size_t>(amount_read);
159 for ( ; NLMSG_OK(header, header_size);
160 header = NLMSG_NEXT(header, header_size)) {
161 switch (header->nlmsg_type) {
162 case NLMSG_DONE:
163 // Success. Return.
164 *result = start;
165 close(fd);
166 return 0;
167 case NLMSG_ERROR:
168 close(fd);
169 freeifaddrs(start);
170 return -1;
171 case RTM_NEWADDR: {
172 ifaddrmsg* address_msg =
173 reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
174 rtattr* rta = IFA_RTA(address_msg);
175 ssize_t payload_len = IFA_PAYLOAD(header);
176 while (RTA_OK(rta, payload_len)) {
177 if (rta->rta_type == IFA_ADDRESS) {
178 int family = address_msg->ifa_family;
179 if (family == AF_INET || family == AF_INET6) {
180 ifaddrs* newest = new ifaddrs;
181 memset(newest, 0, sizeof(ifaddrs));
182 if (current) {
183 current->ifa_next = newest;
184 } else {
185 start = newest;
186 }
187 if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
188 RTA_PAYLOAD(rta)) != 0) {
189 freeifaddrs(start);
deadbeef37f5ecf2017-02-27 14:06:41 -0800190 *result = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000191 return -1;
192 }
193 current = newest;
194 }
195 }
196 rta = RTA_NEXT(rta, payload_len);
197 }
198 break;
199 }
200 }
201 }
202 amount_read = recv(fd, &buf, kMaxReadSize, 0);
203 }
204 close(fd);
205 freeifaddrs(start);
206 return -1;
207}
208
209void freeifaddrs(struct ifaddrs* addrs) {
deadbeef37f5ecf2017-02-27 14:06:41 -0800210 struct ifaddrs* last = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000211 struct ifaddrs* cursor = addrs;
212 while (cursor) {
213 delete[] cursor->ifa_name;
214 delete cursor->ifa_addr;
215 delete cursor->ifa_netmask;
216 last = cursor;
217 cursor = cursor->ifa_next;
218 delete last;
219 }
220}
henrike@webrtc.orgc50bf7c2014-05-14 18:24:13 +0000221
222} // namespace rtc
henrik.lundin@webrtc.org18584fc2014-08-27 10:17:22 +0000223#endif // defined(WEBRTC_ANDROID)