Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <base/address.h>
7 :
8 : #include <map>
9 : #include <boost/assign/list_of.hpp>
10 :
11 : using namespace std;
12 :
13 0 : Address::Address() {
14 0 : }
15 :
16 : static const std::map<string, Address::Family>
17 : fromString = boost::assign::map_list_of
18 : ("unspecified", Address::UNSPEC)
19 : ("inet", Address::INET)
20 : ("inet-labeled", Address::INETMPLS)
21 : ("inet6", Address::INET6)
22 : ("inet-vpn", Address::INETVPN)
23 : ("inet6-vpn", Address::INET6VPN)
24 : ("route-target", Address::RTARGET)
25 : ("e-vpn", Address::EVPN)
26 : ("inet-mvpn", Address::MVPN)
27 : ("erm-vpn", Address::ERMVPN);
28 :
29 : static const std::map<Address::Family, string>
30 : toString = boost::assign::map_list_of
31 : (Address::UNSPEC, "unspecified")
32 : (Address::INET, "inet")
33 : (Address::INETMPLS, "inet-labeled")
34 : (Address::INET6, "inet6")
35 : (Address::INETVPN, "inet-vpn")
36 : (Address::INET6VPN, "inet6-vpn")
37 : (Address::RTARGET, "route-target")
38 : (Address::EVPN, "e-vpn")
39 : (Address::MVPN, "inet-mvpn")
40 : (Address::ERMVPN, "erm-vpn");
41 :
42 : static const std::map<Address::Family, string>
43 : toTableName = boost::assign::map_list_of
44 : (Address::UNSPEC, "unspecified")
45 : (Address::INET, "inet")
46 : (Address::INETMPLS, "inet")
47 : (Address::INET6, "inet6")
48 : (Address::INETVPN, "l3vpn")
49 : (Address::INET6VPN, "l3vpn-inet6")
50 : (Address::RTARGET, "rtarget")
51 : (Address::EVPN, "evpn")
52 : (Address::MVPN, "mvpn")
53 : (Address::ERMVPN, "ermvpn");
54 :
55 34711 : Address::Family Address::FamilyFromString(const std::string &family) {
56 : std::map<string, Address::Family>::const_iterator loc =
57 34711 : fromString.find(family);
58 34711 : if (loc != fromString.end()) {
59 34711 : return loc->second;
60 : }
61 0 : return Address::UNSPEC;
62 : }
63 :
64 3499165 : std::string Address::FamilyToString(Address::Family family) {
65 6998246 : return toString.find(family)->second;
66 : }
67 :
68 257505 : std::string Address::FamilyToTableString(Address::Family family) {
69 514853 : return toTableName.find(family)->second;
70 : }
71 :
72 5550 : Address::Family Address::VpnFamilyFromFamily(Address::Family family) {
73 5550 : switch (family) {
74 5267 : case Address::INET:
75 : case Address::INETVPN:
76 5267 : return Address::INETVPN;
77 87 : case Address::INET6:
78 : case Address::INET6VPN:
79 87 : return Address::INET6VPN;
80 97 : case Address::EVPN:
81 97 : return Address::EVPN;
82 8 : case Address::MVPN:
83 8 : return Address::MVPN;
84 17 : case Address::ERMVPN:
85 17 : return Address::ERMVPN;
86 74 : default:
87 74 : return Address::UNSPEC;
88 : }
89 : return Address::UNSPEC;
90 : }
91 :
92 157797 : static int CountDots(const string &str) {
93 157797 : int count = 0;
94 157797 : size_t pos = 0;
95 618599 : while (pos < str.size()) {
96 618592 : pos = str.find('.', pos);
97 618597 : if (pos == string::npos) {
98 157795 : break;
99 : }
100 460802 : count++;
101 460802 : pos++;
102 : }
103 157799 : return count;
104 : }
105 :
106 : // Return the IP address part as it is i.e. 1.2.3.4/24 will return 1.2.3.4 and
107 : // 24.
108 178421 : boost::system::error_code Ip4PrefixParse(const string &str, Ip4Address *addr,
109 : int *plen) {
110 178421 : size_t pos = str.find('/');
111 178422 : if (pos == string::npos) {
112 34 : return make_error_code(boost::system::errc::invalid_argument);
113 : }
114 178388 : *plen = atoi(str.c_str() + pos + 1);
115 178388 : if ((*plen < 0) || (*plen > Address::kMaxV4PrefixLen)) {
116 20590 : return make_error_code(boost::system::errc::invalid_argument);
117 : }
118 :
119 157798 : string addrstr = str.substr(0, pos);
120 157798 : int dots = CountDots(addrstr);
121 170398 : while (dots < 3) {
122 12599 : addrstr.append(".0");
123 12599 : dots++;
124 : }
125 :
126 157799 : boost::system::error_code err;
127 157799 : *addr = Ip4Address::from_string(addrstr, err);
128 157798 : return err;
129 157798 : }
130 :
131 : // Return the bitwise and of IP and mask.
132 174599 : boost::system::error_code Ip4SubnetParse(const string &str, Ip4Address *addr,
133 : int *plen) {
134 174599 : Ip4Address address;
135 174599 : boost::system::error_code err;
136 174599 : err = Ip4PrefixParse(str, &address, plen);
137 174605 : if (!err) {
138 152493 : *addr = Address::GetIp4SubnetAddress(address, *plen);
139 : }
140 174605 : return err;
141 : }
142 :
143 : // Return the IP address part as it is i.e. 2001:db8:85a3:aaaa::b:c:d/64 will
144 : // return 2001:db8:85a3:aaaa::b:c:d and 64.
145 75445 : boost::system::error_code Inet6PrefixParse(const string &str, Ip6Address *addr,
146 : int *plen) {
147 75445 : size_t pos = str.find('/');
148 75445 : if (pos == string::npos) {
149 24 : return make_error_code(boost::system::errc::invalid_argument);
150 : }
151 75421 : *plen = atoi(str.c_str() + pos + 1);
152 75421 : if ((*plen < 0) || (*plen > Address::kMaxV6PrefixLen)) {
153 5 : return make_error_code(boost::system::errc::invalid_argument);
154 : }
155 :
156 75416 : string addrstr = str.substr(0, pos);
157 75416 : boost::system::error_code err;
158 75416 : *addr = Ip6Address::from_string(addrstr, err);
159 75416 : return err;
160 75416 : }
161 :
162 : // Return the bitwise and of IP and mask.
163 75009 : boost::system::error_code Inet6SubnetParse(const string &str, Ip6Address *addr,
164 : int *plen) {
165 75009 : Ip6Address address;
166 75009 : boost::system::error_code err;
167 75009 : err = Inet6PrefixParse(str, &address, plen);
168 75009 : if (!err) {
169 74977 : *addr = Address::GetIp6SubnetAddress(address, *plen);
170 : }
171 75009 : return err;
172 : }
173 :
174 : /* Returns IPv4 subnet address for a given IPv4 address and prefix length. The
175 : * IPv4 address and prefix lengths are converted to u32 numbers and then bitwise
176 : * AND operation is performed between those 2 numbers and the resulting u32
177 : * number is converted to IPv4Address object and returned. If prefix length is 0
178 : * then 0 is converted to IPv4Address object and returned.
179 : */
180 1006506 : Ip4Address Address::GetIp4SubnetAddress(const Ip4Address &prefix, uint16_t plen) {
181 1006506 : if (plen == 0) {
182 25787 : return boost::asio::ip::address_v4(0);
183 : }
184 :
185 980719 : Ip4Address subnet(prefix.to_ulong() & (0xFFFFFFFF << (32 - plen)));
186 980719 : return subnet;
187 : }
188 :
189 : /* Returns IPv6 subnet address for a given IPv6 address and prefix length. The
190 : * input IPv6 address is first converted into an array of 8 two byte integers.
191 : * Based on prefix length we first figure out the array index position from
192 : * where the masking of bits needs to start. Once the array index is found we
193 : * have 16 possible bit positions from where masking has to start. For each of
194 : * the 16 positions we have a unique 16 byte constant that we use to mask the
195 : * two byte integer. Once the array position is appropriately masked we mask
196 : * the rest of two byte integers till the array ends. The resulting array is
197 : * converted to IPv6 object and returned. If the prefix length is 0 then we
198 : * return an IPv6 object constructed using its default constructors which
199 : * assumes all bits as 0s.
200 : */
201 1505351 : Ip6Address Address::GetIp6SubnetAddress(const Ip6Address &prefix, uint16_t plen) {
202 1505351 : if (plen == 0) {
203 10233 : return boost::asio::ip::address_v6();
204 : }
205 :
206 1495118 : if (plen == 128) {
207 178232 : return prefix;
208 : }
209 :
210 : uint16_t ip6[8], in_ip6[8];
211 : unsigned char bytes[16];
212 :
213 1316886 : inet_pton(AF_INET6, prefix.to_string().c_str(), ip6);
214 :
215 11851974 : for (int i = 0; i < 8; ++i) {
216 10535088 : in_ip6[i] = ntohs(ip6[i]);
217 : }
218 :
219 1316886 : int index = (int) (plen / 16);
220 1316886 : int remain_mask = plen % 16;
221 :
222 1316886 : switch (remain_mask) {
223 84273 : case 0:
224 84273 : in_ip6[index++] = 0;
225 84273 : break;
226 79363 : case 1:
227 79363 : in_ip6[index++] &= 0x8000;
228 79363 : break;
229 79359 : case 2:
230 79359 : in_ip6[index++] &= 0xc000;
231 79359 : break;
232 79359 : case 3:
233 79359 : in_ip6[index++] &= 0xe000;
234 79359 : break;
235 79374 : case 4:
236 79374 : in_ip6[index++] &= 0xf000;
237 79374 : break;
238 79359 : case 5:
239 79359 : in_ip6[index++] &= 0xf800;
240 79359 : break;
241 79360 : case 6:
242 79360 : in_ip6[index++] &= 0xfc00;
243 79360 : break;
244 79362 : case 7:
245 79362 : in_ip6[index++] &= 0xfe00;
246 79362 : break;
247 112886 : case 8:
248 112886 : in_ip6[index++] &= 0xff00;
249 112886 : break;
250 79393 : case 9:
251 79393 : in_ip6[index++] &= 0xff80;
252 79393 : break;
253 79394 : case 10:
254 79394 : in_ip6[index++] &= 0xffc0;
255 79394 : break;
256 79605 : case 11:
257 79605 : in_ip6[index++] &= 0xffe0;
258 79605 : break;
259 79477 : case 12:
260 79477 : in_ip6[index++] &= 0xfff0;
261 79477 : break;
262 79393 : case 13:
263 79393 : in_ip6[index++] &= 0xfff8;
264 79393 : break;
265 79529 : case 14:
266 79529 : in_ip6[index++] &= 0xfffc;
267 79529 : break;
268 87400 : case 15:
269 87400 : in_ip6[index++] &= 0xfffe;
270 87400 : break;
271 : }
272 :
273 5760866 : for (int i = index; i < 8; ++i) {
274 4443980 : in_ip6[i] = 0;
275 : }
276 :
277 11851974 : for (int i = 0; i < 8; ++i) {
278 10535088 : ip6[i] = htons(in_ip6[i]);
279 : }
280 1316886 : memcpy(bytes, ip6, sizeof(ip6));
281 : Ip6Address::bytes_type to_bytes;
282 22387062 : for (int i = 0; i < 16; ++i) {
283 21070176 : to_bytes.at(i) = bytes[i];
284 : }
285 1316886 : return boost::asio::ip::address_v6(to_bytes);
286 : }
287 :
288 : // Ip6Address.to_v4() has exceptions. Plus, we dont have a to_v4() version
289 : // without exceptions that takes an boost::error_code.
290 : // If the v6-address is v4_mapped, return the ipv4 equivalent address. Else
291 : // return a 'zero' ipv4 address.
292 31480 : Ip4Address Address::V4FromV4MappedV6(const Ip6Address &v6_address) {
293 31480 : Ip4Address v4_address;
294 31480 : if (v6_address.is_v4_mapped()) {
295 31480 : Ip6Address::bytes_type v6_bt = v6_address.to_bytes();
296 : Ip4Address::bytes_type v4_bt =
297 31480 : { { v6_bt[12], v6_bt[13], v6_bt[14], v6_bt[15] } };
298 31480 : v4_address = Ip4Address(v4_bt);
299 : }
300 31480 : return v4_address;
301 : }
|