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