1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /*
4  * Copyright (C) 2009 The Android Open Source Project
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "ifaddrs-android-ext.h"
20 
21 #include <stdlib.h>
22 #include <string.h>
23 #include "ScopedFd.h"
24 #include "LocalArray.h"
25 
26 // Returns a pointer to the first byte in the address data (which is
27 // stored in network byte order).
sockaddrBytes(int family,sockaddr_storage * ss)28 uint8_t* sockaddrBytes(int family, sockaddr_storage* ss) {
29     if (family == AF_INET) {
30         sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss);
31         return reinterpret_cast<uint8_t*>(&ss4->sin_addr);
32     } else if (family == AF_INET6) {
33         sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);
34         return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);
35     }
36     return NULL;
37 }
38 
39 // Sadly, we can't keep the interface index for portability with BSD.
40 // We'll have to keep the name instead, and re-query the index when
41 // we need it later.
ifa_setNameAndFlagsByIndex(ifaddrs * self,int interfaceIndex)42 bool ifa_setNameAndFlagsByIndex(ifaddrs *self, int interfaceIndex) {
43     // Get the name.
44     char buf[IFNAMSIZ];
45     char* name = if_indextoname(interfaceIndex, buf);
46     if (name == NULL) {
47         return false;
48     }
49     self->ifa_name = new char[strlen(name) + 1];
50     strcpy(self->ifa_name, name);
51 
52     // Get the flags.
53     ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0));
54     if (fd.get() == -1) {
55         return false;
56     }
57     ifreq ifr;
58     memset(&ifr, 0, sizeof(ifr));
59     strcpy(ifr.ifr_name, name);
60     int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr);
61     if (rc == -1) {
62         return false;
63     }
64     self->ifa_flags = ifr.ifr_flags;
65     return true;
66 }
67 
68 // Netlink gives us the address family in the header, and the
69 // sockaddr_in or sockaddr_in6 bytes as the payload. We need to
70 // stitch the two bits together into the sockaddr that's part of
71 // our portable interface.
ifa_setAddress(ifaddrs * self,int family,void * data,size_t byteCount)72 void ifa_setAddress(ifaddrs *self, int family, void* data, size_t byteCount) {
73     // Set the address proper...
74     sockaddr_storage* ss = new sockaddr_storage;
75     memset(ss, 0, sizeof(*ss));
76     self->ifa_addr = reinterpret_cast<sockaddr*>(ss);
77     ss->ss_family = family;
78     uint8_t* dst = sockaddrBytes(family, ss);
79     memcpy(dst, data, byteCount);
80 }
81 
82 // Netlink gives us the prefix length as a bit count. We need to turn
83 // that into a BSD-compatible netmask represented by a sockaddr*.
ifa_setNetmask(ifaddrs * self,int family,size_t prefixLength)84 void ifa_setNetmask(ifaddrs *self, int family, size_t prefixLength) {
85     // ...and work out the netmask from the prefix length.
86     sockaddr_storage* ss = new sockaddr_storage;
87     memset(ss, 0, sizeof(*ss));
88     self->ifa_netmask = reinterpret_cast<sockaddr*>(ss);
89     ss->ss_family = family;
90     uint8_t* dst = sockaddrBytes(family, ss);
91     memset(dst, 0xff, prefixLength / 8);
92     if ((prefixLength % 8) != 0) {
93         dst[prefixLength/8] = (0xff << (8 - (prefixLength % 8)));
94     }
95 }
96 
97 // FIXME: use iovec instead.
98 struct addrReq_struct {
99     nlmsghdr netlinkHeader;
100     ifaddrmsg msg;
101 };
102 
sendNetlinkMessage(int fd,const void * data,size_t byteCount)103 inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) {
104     ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0));
105     return (sentByteCount == static_cast<ssize_t>(byteCount));
106 }
107 
recvNetlinkMessage(int fd,char * buf,size_t byteCount)108 inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) {
109     return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0));
110 }
111 
112 // Source-compatible with the BSD function.
getifaddrs(ifaddrs ** result)113 int getifaddrs(ifaddrs** result)
114 {
115     // Simplify cleanup for callers.
116     *result = NULL;
117 
118     // Create a netlink socket.
119     ScopedFd fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE));
120     if (fd.get() < 0) {
121         return -1;
122     }
123 
124     // Ask for the address information.
125     addrReq_struct addrRequest;
126     memset(&addrRequest, 0, sizeof(addrRequest));
127     addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
128     addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR;
129     addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest)));
130     addrRequest.msg.ifa_family = AF_UNSPEC; // All families.
131     addrRequest.msg.ifa_index = 0; // All interfaces.
132     if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) {
133         return -1;
134     }
135 
136     // Read the responses.
137     LocalArray<0> buf(65536); // We don't necessarily have std::vector.
138     ssize_t bytesRead;
139     while ((bytesRead  = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) {
140         nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]);
141         for (; NLMSG_OK(hdr, (size_t)bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) {
142             switch (hdr->nlmsg_type) {
143             case NLMSG_DONE:
144                 return 0;
145             case NLMSG_ERROR:
146                 return -1;
147             case RTM_NEWADDR:
148                 {
149                     ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
150                     rtattr* rta = IFA_RTA(address);
151                     size_t ifaPayloadLength = IFA_PAYLOAD(hdr);
152                     while (RTA_OK(rta, ifaPayloadLength)) {
153                         if (rta->rta_type == IFA_LOCAL) {
154                             int family = address->ifa_family;
155                             if (family == AF_INET || family == AF_INET6) {
156                                 ifaddrs *next = *result;
157                                 *result = new ifaddrs;
158                                 memset(*result, 0, sizeof(ifaddrs));
159                                 (*result)->ifa_next = next;
160                                 if (!ifa_setNameAndFlagsByIndex(*result, address->ifa_index)) {
161                                     return -1;
162                                 }
163                                 ifa_setAddress(*result, family, RTA_DATA(rta), RTA_PAYLOAD(rta));
164                                 ifa_setNetmask(*result, family, address->ifa_prefixlen);
165                             }
166                         }
167                         rta = RTA_NEXT(rta, ifaPayloadLength);
168                     }
169                 }
170                 break;
171             }
172         }
173     }
174     // We only get here if recv fails before we see a NLMSG_DONE.
175     return -1;
176 }
177 
178 // Source-compatible with the BSD function.
freeifaddrs(ifaddrs * addresses)179 void freeifaddrs(ifaddrs* addresses) {
180     ifaddrs* self = addresses;
181     while (self != NULL) {
182         delete[] self->ifa_name;
183         delete self->ifa_addr;
184         delete self->ifa_netmask;
185         ifaddrs* next = self->ifa_next;
186         delete self;
187         self = next;
188     }
189 }
190