blob: 1cc63fe9f315936c330bb96fcec97d0f4c03265a [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
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)
Steve Anton10542f22019-01-11 17:11:0012#include "rtc_base/ifaddrs_android.h"
Jonas Olssona4d87372019-07-05 17:08:3313
henrike@webrtc.orgf0488722014-05-13 18:00:2614#include <errno.h>
15#include <linux/netlink.h>
16#include <linux/rtnetlink.h>
kjellandere96c45b2017-06-30 17:45:2117#include <net/if.h>
18#include <netinet/in.h>
19#include <stdlib.h>
20#include <string.h>
21#include <sys/ioctl.h>
22#include <sys/socket.h>
23#include <sys/types.h>
24#include <sys/utsname.h>
25#include <unistd.h>
henrike@webrtc.orgf0488722014-05-13 18:00:2626
henrike@webrtc.orgc50bf7c2014-05-14 18:24:1327namespace {
28
henrike@webrtc.orgf0488722014-05-13 18:00:2629struct netlinkrequest {
30 nlmsghdr header;
31 ifaddrmsg msg;
32};
33
henrike@webrtc.orgf0488722014-05-13 18:00:2634const int kMaxReadSize = 4096;
henrike@webrtc.orgc50bf7c2014-05-14 18:24:1335
36} // namespace
37
38namespace rtc {
henrike@webrtc.orgf0488722014-05-13 18:00:2639
40int set_ifname(struct ifaddrs* ifaddr, int interface) {
41 char buf[IFNAMSIZ] = {0};
42 char* name = if_indextoname(interface, buf);
deadbeef37f5ecf2017-02-27 22:06:4143 if (name == nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:2644 return -1;
45 }
46 ifaddr->ifa_name = new char[strlen(name) + 1];
47 strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
48 return 0;
49}
50
51int set_flags(struct ifaddrs* ifaddr) {
52 int fd = socket(AF_INET, SOCK_DGRAM, 0);
53 if (fd == -1) {
54 return -1;
55 }
56 ifreq ifr;
57 memset(&ifr, 0, sizeof(ifr));
58 strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
59 int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
60 close(fd);
61 if (rc == -1) {
62 return -1;
63 }
64 ifaddr->ifa_flags = ifr.ifr_flags;
65 return 0;
66}
67
Yves Gerey665174f2018-06-19 13:03:0568int set_addresses(struct ifaddrs* ifaddr,
69 ifaddrmsg* msg,
70 void* data,
henrike@webrtc.orgf0488722014-05-13 18:00:2671 size_t len) {
72 if (msg->ifa_family == AF_INET) {
73 sockaddr_in* sa = new sockaddr_in;
74 sa->sin_family = AF_INET;
75 memcpy(&sa->sin_addr, data, len);
76 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
77 } else if (msg->ifa_family == AF_INET6) {
78 sockaddr_in6* sa = new sockaddr_in6;
79 sa->sin6_family = AF_INET6;
80 sa->sin6_scope_id = msg->ifa_index;
81 memcpy(&sa->sin6_addr, data, len);
82 ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
83 } else {
84 return -1;
85 }
86 return 0;
87}
88
89int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
deadbeef37f5ecf2017-02-27 22:06:4190 char* prefix = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2691 if (family == AF_INET) {
92 sockaddr_in* mask = new sockaddr_in;
93 mask->sin_family = AF_INET;
94 memset(&mask->sin_addr, 0, sizeof(in_addr));
95 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
96 if (prefixlen > 32) {
97 prefixlen = 32;
98 }
99 prefix = reinterpret_cast<char*>(&mask->sin_addr);
100 } else if (family == AF_INET6) {
101 sockaddr_in6* mask = new sockaddr_in6;
102 mask->sin6_family = AF_INET6;
103 memset(&mask->sin6_addr, 0, sizeof(in6_addr));
104 ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
105 if (prefixlen > 128) {
106 prefixlen = 128;
107 }
108 prefix = reinterpret_cast<char*>(&mask->sin6_addr);
109 } else {
110 return -1;
111 }
112 for (int i = 0; i < (prefixlen / 8); i++) {
113 *prefix++ = 0xFF;
114 }
115 char remainder = 0xff;
116 remainder <<= (8 - prefixlen % 8);
117 *prefix = remainder;
118 return 0;
119}
120
Yves Gerey665174f2018-06-19 13:03:05121int populate_ifaddrs(struct ifaddrs* ifaddr,
122 ifaddrmsg* msg,
123 void* bytes,
henrike@webrtc.orgf0488722014-05-13 18:00:26124 size_t len) {
125 if (set_ifname(ifaddr, msg->ifa_index) != 0) {
126 return -1;
127 }
128 if (set_flags(ifaddr) != 0) {
129 return -1;
130 }
131 if (set_addresses(ifaddr, msg, bytes, len) != 0) {
132 return -1;
133 }
134 if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
135 return -1;
136 }
137 return 0;
138}
139
140int getifaddrs(struct ifaddrs** result) {
141 int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
142 if (fd < 0) {
143 return -1;
144 }
145
146 netlinkrequest ifaddr_request;
147 memset(&ifaddr_request, 0, sizeof(ifaddr_request));
148 ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
149 ifaddr_request.header.nlmsg_type = RTM_GETADDR;
150 ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
151
152 ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
153 if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
154 close(fd);
155 return -1;
156 }
deadbeef37f5ecf2017-02-27 22:06:41157 struct ifaddrs* start = nullptr;
158 struct ifaddrs* current = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26159 char buf[kMaxReadSize];
160 ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
161 while (amount_read > 0) {
162 nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
163 size_t header_size = static_cast<size_t>(amount_read);
Yves Gerey665174f2018-06-19 13:03:05164 for (; NLMSG_OK(header, header_size);
165 header = NLMSG_NEXT(header, header_size)) {
henrike@webrtc.orgf0488722014-05-13 18:00:26166 switch (header->nlmsg_type) {
167 case NLMSG_DONE:
168 // Success. Return.
169 *result = start;
170 close(fd);
171 return 0;
172 case NLMSG_ERROR:
173 close(fd);
174 freeifaddrs(start);
175 return -1;
176 case RTM_NEWADDR: {
177 ifaddrmsg* address_msg =
178 reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
179 rtattr* rta = IFA_RTA(address_msg);
180 ssize_t payload_len = IFA_PAYLOAD(header);
181 while (RTA_OK(rta, payload_len)) {
Yongje Leeebd9abc2018-04-27 00:47:07182 if ((address_msg->ifa_family == AF_INET &&
Yves Gerey665174f2018-06-19 13:03:05183 rta->rta_type == IFA_LOCAL) ||
Yongje Leeebd9abc2018-04-27 00:47:07184 (address_msg->ifa_family == AF_INET6 &&
185 rta->rta_type == IFA_ADDRESS)) {
186 ifaddrs* newest = new ifaddrs;
187 memset(newest, 0, sizeof(ifaddrs));
188 if (current) {
189 current->ifa_next = newest;
190 } else {
191 start = newest;
henrike@webrtc.orgf0488722014-05-13 18:00:26192 }
Yongje Leeebd9abc2018-04-27 00:47:07193 if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
194 RTA_PAYLOAD(rta)) != 0) {
195 freeifaddrs(start);
196 *result = nullptr;
197 return -1;
198 }
199 current = newest;
henrike@webrtc.orgf0488722014-05-13 18:00:26200 }
201 rta = RTA_NEXT(rta, payload_len);
202 }
203 break;
204 }
205 }
206 }
207 amount_read = recv(fd, &buf, kMaxReadSize, 0);
208 }
209 close(fd);
210 freeifaddrs(start);
211 return -1;
212}
213
214void freeifaddrs(struct ifaddrs* addrs) {
deadbeef37f5ecf2017-02-27 22:06:41215 struct ifaddrs* last = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26216 struct ifaddrs* cursor = addrs;
217 while (cursor) {
218 delete[] cursor->ifa_name;
219 delete cursor->ifa_addr;
220 delete cursor->ifa_netmask;
221 last = cursor;
222 cursor = cursor->ifa_next;
223 delete last;
224 }
225}
henrike@webrtc.orgc50bf7c2014-05-14 18:24:13226
227} // namespace rtc
henrik.lundin@webrtc.org18584fc2014-08-27 10:17:22228#endif // defined(WEBRTC_ANDROID)