1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <ifaddrs.h> 30 31#include <errno.h> 32#include <linux/if_packet.h> 33#include <net/if.h> 34#include <netinet/in.h> 35#include <stdint.h> 36#include <stdio.h> 37#include <stdlib.h> 38#include <string.h> 39#include <unistd.h> 40 41#include "private/ErrnoRestorer.h" 42 43#include "bionic_netlink.h" 44 45// The public ifaddrs struct is full of pointers. Rather than track several 46// different allocations, we use a maximally-sized structure with the public 47// part at offset 0, and pointers into its hidden tail. 48struct ifaddrs_storage { 49 // Must come first, so that `ifaddrs_storage` is-a `ifaddrs`. 50 ifaddrs ifa; 51 52 // The interface index, so we can match RTM_NEWADDR messages with 53 // earlier RTM_NEWLINK messages (to copy the interface flags). 54 int interface_index; 55 56 // Storage for the pointers in `ifa`. 57 sockaddr_storage addr; 58 sockaddr_storage netmask; 59 sockaddr_storage ifa_ifu; 60 char name[IFNAMSIZ + 1]; 61 62 ifaddrs_storage(ifaddrs** list) { 63 memset(this, 0, sizeof(*this)); 64 65 // push_front onto `list`. 66 ifa.ifa_next = *list; 67 *list = reinterpret_cast<ifaddrs*>(this); 68 } 69 70 void SetAddress(int family, const void* data, size_t byteCount) { 71 // The kernel currently uses the order IFA_ADDRESS, IFA_LOCAL, IFA_BROADCAST 72 // in inet_fill_ifaddr, but let's not assume that will always be true... 73 if (ifa.ifa_addr == nullptr) { 74 // This is an IFA_ADDRESS and haven't seen an IFA_LOCAL yet, so assume this is the 75 // local address. SetLocalAddress will fix things if we later see an IFA_LOCAL. 76 ifa.ifa_addr = CopyAddress(family, data, byteCount, &addr); 77 } else { 78 // We already saw an IFA_LOCAL, which implies this is a destination address. 79 ifa.ifa_dstaddr = CopyAddress(family, data, byteCount, &ifa_ifu); 80 } 81 } 82 83 void SetBroadcastAddress(int family, const void* data, size_t byteCount) { 84 // ifa_broadaddr and ifa_dstaddr overlap in a union. Unfortunately, it's possible 85 // to have an interface with both. Keeping the last thing the kernel gives us seems 86 // to be glibc 2.19's behavior too, so our choice is being source compatible with 87 // badly-written code that assumes ifa_broadaddr and ifa_dstaddr are interchangeable 88 // or supporting interfaces with both addresses configured. My assumption is that 89 // bad code is more common than weird network interfaces... 90 ifa.ifa_broadaddr = CopyAddress(family, data, byteCount, &ifa_ifu); 91 } 92 93 void SetLocalAddress(int family, const void* data, size_t byteCount) { 94 // The kernel source says "for point-to-point IFA_ADDRESS is DESTINATION address, 95 // local address is supplied in IFA_LOCAL attribute". 96 // -- http://lxr.free-electrons.com/source/include/uapi/linux/if_addr.h#L17 97 98 // So copy any existing IFA_ADDRESS into ifa_dstaddr... 99 if (ifa.ifa_addr != nullptr) { 100 ifa.ifa_dstaddr = reinterpret_cast<sockaddr*>(memcpy(&ifa_ifu, &addr, sizeof(addr))); 101 } 102 // ...and then put this IFA_LOCAL into ifa_addr. 103 ifa.ifa_addr = CopyAddress(family, data, byteCount, &addr); 104 } 105 106 // Netlink gives us the prefix length as a bit count. We need to turn 107 // that into a BSD-compatible netmask represented by a sockaddr*. 108 void SetNetmask(int family, size_t prefix_length) { 109 // ...and work out the netmask from the prefix length. 110 netmask.ss_family = family; 111 uint8_t* dst = SockaddrBytes(family, &netmask); 112 memset(dst, 0xff, prefix_length / 8); 113 if ((prefix_length % 8) != 0) { 114 dst[prefix_length/8] = (0xff << (8 - (prefix_length % 8))); 115 } 116 ifa.ifa_netmask = reinterpret_cast<sockaddr*>(&netmask); 117 } 118 119 void SetPacketAttributes(int ifindex, unsigned short hatype, unsigned char halen) { 120 sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(&addr); 121 sll->sll_ifindex = ifindex; 122 sll->sll_hatype = hatype; 123 sll->sll_halen = halen; 124 } 125 126 private: 127 sockaddr* CopyAddress(int family, const void* data, size_t byteCount, sockaddr_storage* ss) { 128 // Netlink gives us the address family in the header, and the 129 // sockaddr_in or sockaddr_in6 bytes as the payload. We need to 130 // stitch the two bits together into the sockaddr that's part of 131 // our portable interface. 132 ss->ss_family = family; 133 memcpy(SockaddrBytes(family, ss), data, byteCount); 134 135 // For IPv6 we might also have to set the scope id. 136 if (family == AF_INET6 && (IN6_IS_ADDR_LINKLOCAL(data) || IN6_IS_ADDR_MC_LINKLOCAL(data))) { 137 reinterpret_cast<sockaddr_in6*>(ss)->sin6_scope_id = interface_index; 138 } 139 140 return reinterpret_cast<sockaddr*>(ss); 141 } 142 143 // Returns a pointer to the first byte in the address data (which is 144 // stored in network byte order). 145 uint8_t* SockaddrBytes(int family, sockaddr_storage* ss) { 146 if (family == AF_INET) { 147 sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss); 148 return reinterpret_cast<uint8_t*>(&ss4->sin_addr); 149 } else if (family == AF_INET6) { 150 sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss); 151 return reinterpret_cast<uint8_t*>(&ss6->sin6_addr); 152 } else if (family == AF_PACKET) { 153 sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(ss); 154 return reinterpret_cast<uint8_t*>(&sll->sll_addr); 155 } 156 return nullptr; 157 } 158}; 159 160static void __getifaddrs_callback(void* context, nlmsghdr* hdr) { 161 ifaddrs** out = reinterpret_cast<ifaddrs**>(context); 162 163 if (hdr->nlmsg_type == RTM_NEWLINK) { 164 ifinfomsg* ifi = reinterpret_cast<ifinfomsg*>(NLMSG_DATA(hdr)); 165 166 // Create a new ifaddr entry, and set the interface index and flags. 167 ifaddrs_storage* new_addr = new ifaddrs_storage(out); 168 new_addr->interface_index = ifi->ifi_index; 169 new_addr->ifa.ifa_flags = ifi->ifi_flags; 170 171 // Go through the various bits of information and find the name. 172 rtattr* rta = IFLA_RTA(ifi); 173 size_t rta_len = IFLA_PAYLOAD(hdr); 174 while (RTA_OK(rta, rta_len)) { 175 if (rta->rta_type == IFLA_ADDRESS) { 176 if (RTA_PAYLOAD(rta) < sizeof(new_addr->addr)) { 177 new_addr->SetAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); 178 new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); 179 } 180 } else if (rta->rta_type == IFLA_BROADCAST) { 181 if (RTA_PAYLOAD(rta) < sizeof(new_addr->ifa_ifu)) { 182 new_addr->SetBroadcastAddress(AF_PACKET, RTA_DATA(rta), RTA_PAYLOAD(rta)); 183 new_addr->SetPacketAttributes(ifi->ifi_index, ifi->ifi_type, RTA_PAYLOAD(rta)); 184 } 185 } else if (rta->rta_type == IFLA_IFNAME) { 186 if (RTA_PAYLOAD(rta) < sizeof(new_addr->name)) { 187 memcpy(new_addr->name, RTA_DATA(rta), RTA_PAYLOAD(rta)); 188 new_addr->ifa.ifa_name = new_addr->name; 189 } 190 } 191 rta = RTA_NEXT(rta, rta_len); 192 } 193 } else if (hdr->nlmsg_type == RTM_NEWADDR) { 194 ifaddrmsg* msg = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr)); 195 196 // We should already know about this from an RTM_NEWLINK message. 197 const ifaddrs_storage* addr = reinterpret_cast<const ifaddrs_storage*>(*out); 198 while (addr != nullptr && addr->interface_index != static_cast<int>(msg->ifa_index)) { 199 addr = reinterpret_cast<const ifaddrs_storage*>(addr->ifa.ifa_next); 200 } 201 // If this is an unknown interface, ignore whatever we're being told about it. 202 if (addr == nullptr) return; 203 204 // Create a new ifaddr entry and copy what we already know. 205 ifaddrs_storage* new_addr = new ifaddrs_storage(out); 206 // We can just copy the name rather than look for IFA_LABEL. 207 strcpy(new_addr->name, addr->name); 208 new_addr->ifa.ifa_name = new_addr->name; 209 new_addr->ifa.ifa_flags = addr->ifa.ifa_flags; 210 new_addr->interface_index = addr->interface_index; 211 212 // Go through the various bits of information and find the address 213 // and any broadcast/destination address. 214 rtattr* rta = IFA_RTA(msg); 215 size_t rta_len = IFA_PAYLOAD(hdr); 216 while (RTA_OK(rta, rta_len)) { 217 if (rta->rta_type == IFA_ADDRESS) { 218 if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { 219 new_addr->SetAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); 220 new_addr->SetNetmask(msg->ifa_family, msg->ifa_prefixlen); 221 } 222 } else if (rta->rta_type == IFA_BROADCAST) { 223 if (msg->ifa_family == AF_INET) { 224 new_addr->SetBroadcastAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); 225 } 226 } else if (rta->rta_type == IFA_LOCAL) { 227 if (msg->ifa_family == AF_INET || msg->ifa_family == AF_INET6) { 228 new_addr->SetLocalAddress(msg->ifa_family, RTA_DATA(rta), RTA_PAYLOAD(rta)); 229 } 230 } 231 rta = RTA_NEXT(rta, rta_len); 232 } 233 } 234} 235 236int getifaddrs(ifaddrs** out) { 237 // We construct the result directly into `out`, so terminate the list. 238 *out = nullptr; 239 240 // Open the netlink socket and ask for all the links and addresses. 241 NetlinkConnection nc; 242 bool okay = nc.SendRequest(RTM_GETLINK) && nc.ReadResponses(__getifaddrs_callback, out) && 243 nc.SendRequest(RTM_GETADDR) && nc.ReadResponses(__getifaddrs_callback, out); 244 if (!okay) { 245 freeifaddrs(*out); 246 // Ensure that callers crash if they forget to check for success. 247 *out = nullptr; 248 return -1; 249 } 250 251 return 0; 252} 253 254void freeifaddrs(ifaddrs* list) { 255 while (list != nullptr) { 256 ifaddrs* current = list; 257 list = list->ifa_next; 258 free(current); 259 } 260} 261