• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018, 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 "address_assigner.h"
18 
19 #include "log.h"
20 
21 #include <errno.h>
22 #include <net/if.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 
AddressAssigner(const char * interfacePrefix,in_addr_t baseAddress,uint32_t maskLength)28 AddressAssigner::AddressAssigner(const char* interfacePrefix,
29                                  in_addr_t baseAddress,
30                                  uint32_t maskLength) :
31     mInterfacePrefix(interfacePrefix),
32     mPrefixLength(strlen(interfacePrefix)),
33     mBaseAddress(baseAddress),
34     mMaskLength(maskLength) {
35 
36 }
37 
onInterfaceState(unsigned int,const char * name,InterfaceState state)38 void AddressAssigner::onInterfaceState(unsigned int /*index*/,
39                                        const char* name,
40                                        InterfaceState state) {
41     if (strncmp(name, mInterfacePrefix, mPrefixLength) != 0) {
42         // The interface does not match the prefix, ignore this change
43         return;
44     }
45 
46     switch (state) {
47         case InterfaceState::Up:
48             assignAddress(name);
49             break;
50         case InterfaceState::Down:
51             freeAddress(name);
52             break;
53     }
54 }
55 
assignAddress(const char * interfaceName)56 void AddressAssigner::assignAddress(const char* interfaceName) {
57     if (mMaskLength > 30) {
58         // The mask length is too long, we can't assign enough IP addresses from
59         // this. A maximum of 30 bits is supported, leaving 4 remaining
60         // addresses, one is network, one is broadcast, one is gateway, one is
61         // client.
62         return;
63     }
64     // Each subnet will have an amount of bits available to it that equals
65     // 32-bits - <mask length>, so if mask length is 29 there will be 3
66     // remaining bits for each subnet. Then the distance between each subnet
67     // is 2 to the power of this number, in our example 2^3 = 8 so to get to the
68     // next subnet we add 8 to the network address.
69     in_addr_t increment = 1 << (32 - mMaskLength);
70 
71     // Convert the address to host byte-order first so we can do math on it.
72     for (in_addr_t addr = ntohl(mBaseAddress); true; addr += increment) {
73         // Take the reference of this lookup, that way we can assign a name to
74         // it if needed.
75         auto& usedName = mUsedIpAddresses[addr];
76         if (usedName.empty()) {
77             // This address is not in use, let's use it
78             usedName = interfaceName;
79             // Make sure we convert back to network byte-order when setting it.
80             setIpAddress(interfaceName, htonl(addr));
81             break;
82         }
83     }
84 }
85 
setIpAddress(const char * interfaceName,in_addr_t address)86 void AddressAssigner::setIpAddress(const char* interfaceName,
87                                    in_addr_t address) {
88     int sock = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
89     if (sock == -1) {
90         LOGE("AddressAssigner unable to open IP socket: %s", strerror(errno));
91         return;
92     }
93     if (!setAddress(sock, SIOCSIFADDR, interfaceName, address)) {
94         LOGE("AddressAssigner unable to set interface address: %s",
95              strerror(errno));
96         ::close(sock);
97         return;
98     }
99 
100     // The netmask is the inverted maximum value of the lower bits. That is if
101     // the mask length is 29 then the the largest value of the 3 (32-29) lowest
102     // bits is 7 (2^3 - 1) (111 binary). Inverting this value gives the netmask
103     // because it excludes those three bits and sets every other bit.
104     in_addr_t netmask = htonl(~((1 << (32 - mMaskLength)) - 1));
105 
106     if (!setAddress(sock, SIOCSIFNETMASK, interfaceName, netmask)) {
107         LOGE("AddressAssigner unable to set interface netmask: %s",
108              strerror(errno));
109         ::close(sock);
110         return;
111     }
112 
113     // The broadcast address is just the assigned address with all bits outside
114     // of the netmask set to one.
115     in_addr_t broadcast = address | ~netmask;
116 
117     if (!setAddress(sock, SIOCSIFBRDADDR, interfaceName, broadcast)) {
118         LOGE("AddressAssigner unable to set interface broadcast: %s",
119              strerror(errno));
120         ::close(sock);
121         return;
122     }
123     ::close(sock);
124 }
125 
setAddress(int sock,int type,const char * interfaceName,in_addr_t address)126 bool AddressAssigner::setAddress(int sock,
127                                  int type,
128                                  const char* interfaceName,
129                                  in_addr_t address) {
130     struct ifreq request;
131     memset(&request, 0, sizeof(request));
132     strlcpy(request.ifr_name, interfaceName, sizeof(request.ifr_name));
133     auto addr = reinterpret_cast<struct sockaddr_in*>(&request.ifr_addr);
134     addr->sin_family = AF_INET;
135     addr->sin_addr.s_addr = address;
136 
137     if (::ioctl(sock, type, &request) != 0) {
138         return false;
139     }
140     return true;
141 }
142 
freeAddress(const char * interfaceName)143 void AddressAssigner::freeAddress(const char* interfaceName) {
144     for (auto& ipName : mUsedIpAddresses) {
145         if (ipName.second == interfaceName) {
146             // This is the one, free it up for future use
147             mUsedIpAddresses.erase(ipName.first);
148         }
149     }
150 }
151 
152