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 37224 : Address::Family Address::FamilyFromString(const std::string &family) {
55 : std::map<string, Address::Family>::const_iterator loc =
56 37224 : fromString.find(family);
57 37224 : if (loc != fromString.end()) {
58 37224 : return loc->second;
59 : }
60 0 : return Address::UNSPEC;
61 : }
62 :
63 3529689 : std::string Address::FamilyToString(Address::Family family) {
64 7059273 : return toString.find(family)->second;
65 : }
66 :
67 259783 : std::string Address::FamilyToTableString(Address::Family family) {
68 519394 : return toTableName.find(family)->second;
69 : }
70 :
71 5554 : Address::Family Address::VpnFamilyFromFamily(Address::Family family) {
72 5554 : switch (family) {
73 5265 : case Address::INET:
74 : case Address::INETVPN:
75 5265 : return Address::INETVPN;
76 93 : case Address::INET6:
77 : case Address::INET6VPN:
78 93 : 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 74 : default:
86 74 : return Address::UNSPEC;
87 : }
88 : return Address::UNSPEC;
89 : }
90 :
91 158699 : static int CountDots(const string &str) {
92 158699 : int count = 0;
93 158699 : size_t pos = 0;
94 622206 : while (pos < str.size()) {
95 622199 : pos = str.find('.', pos);
96 622205 : if (pos == string::npos) {
97 158698 : break;
98 : }
99 463507 : count++;
100 463507 : pos++;
101 : }
102 158701 : 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 179331 : boost::system::error_code Ip4PrefixParse(const string &str, Ip4Address *addr,
108 : int *plen) {
109 179331 : size_t pos = str.find('/');
110 179331 : if (pos == string::npos) {
111 34 : return make_error_code(boost::system::errc::invalid_argument);
112 : }
113 179297 : *plen = atoi(str.c_str() + pos + 1);
114 179298 : if ((*plen < 0) || (*plen > Address::kMaxV4PrefixLen)) {
115 20601 : return make_error_code(boost::system::errc::invalid_argument);
116 : }
117 :
118 158697 : string addrstr = str.substr(0, pos);
119 158701 : int dots = CountDots(addrstr);
120 171300 : while (dots < 3) {
121 12599 : addrstr.append(".0");
122 12599 : dots++;
123 : }
124 :
125 158701 : boost::system::error_code err;
126 158701 : *addr = Ip4Address::from_string(addrstr, err);
127 158699 : return err;
128 158699 : }
129 :
130 : // Return the bitwise and of IP and mask.
131 175446 : boost::system::error_code Ip4SubnetParse(const string &str, Ip4Address *addr,
132 : int *plen) {
133 175446 : Ip4Address address;
134 175446 : boost::system::error_code err;
135 175446 : err = Ip4PrefixParse(str, &address, plen);
136 175452 : if (!err) {
137 153330 : *addr = Address::GetIp4SubnetAddress(address, *plen);
138 : }
139 175448 : 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 76727 : boost::system::error_code Inet6PrefixParse(const string &str, Ip6Address *addr,
145 : int *plen) {
146 76727 : size_t pos = str.find('/');
147 76727 : if (pos == string::npos) {
148 24 : return make_error_code(boost::system::errc::invalid_argument);
149 : }
150 76703 : *plen = atoi(str.c_str() + pos + 1);
151 76703 : if ((*plen < 0) || (*plen > Address::kMaxV6PrefixLen)) {
152 5 : return make_error_code(boost::system::errc::invalid_argument);
153 : }
154 :
155 76698 : string addrstr = str.substr(0, pos);
156 76698 : boost::system::error_code err;
157 76698 : *addr = Ip6Address::from_string(addrstr, err);
158 76698 : return err;
159 76698 : }
160 :
161 : // Return the bitwise and of IP and mask.
162 76291 : boost::system::error_code Inet6SubnetParse(const string &str, Ip6Address *addr,
163 : int *plen) {
164 76291 : Ip6Address address;
165 76291 : boost::system::error_code err;
166 76291 : err = Inet6PrefixParse(str, &address, plen);
167 76291 : if (!err) {
168 76259 : *addr = Address::GetIp6SubnetAddress(address, *plen);
169 : }
170 76291 : 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 973037 : Ip4Address Address::GetIp4SubnetAddress(const Ip4Address &prefix, uint16_t plen) {
180 973037 : if (plen == 0) {
181 24711 : return boost::asio::ip::address_v4(0);
182 : }
183 :
184 948326 : Ip4Address subnet(prefix.to_ulong() & (0xFFFFFFFF << (32 - plen)));
185 948325 : 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 1429960 : Ip6Address Address::GetIp6SubnetAddress(const Ip6Address &prefix, uint16_t plen) {
201 1429960 : if (plen == 0) {
202 9672 : return boost::asio::ip::address_v6();
203 : }
204 :
205 1420288 : if (plen == 128) {
206 175091 : return prefix;
207 : }
208 :
209 : uint16_t ip6[8], in_ip6[8];
210 : unsigned char bytes[16];
211 :
212 1245197 : inet_pton(AF_INET6, prefix.to_string().c_str(), ip6);
213 :
214 11206773 : for (int i = 0; i < 8; ++i) {
215 9961576 : in_ip6[i] = ntohs(ip6[i]);
216 : }
217 :
218 1245197 : int index = (int) (plen / 16);
219 1245197 : int remain_mask = plen % 16;
220 :
221 1245197 : switch (remain_mask) {
222 80403 : case 0:
223 80403 : in_ip6[index++] = 0;
224 80403 : break;
225 74869 : case 1:
226 74869 : in_ip6[index++] &= 0x8000;
227 74869 : break;
228 74869 : case 2:
229 74869 : in_ip6[index++] &= 0xc000;
230 74869 : break;
231 74869 : case 3:
232 74869 : in_ip6[index++] &= 0xe000;
233 74869 : break;
234 74884 : case 4:
235 74884 : in_ip6[index++] &= 0xf000;
236 74884 : break;
237 74869 : case 5:
238 74869 : in_ip6[index++] &= 0xf800;
239 74869 : break;
240 74870 : case 6:
241 74870 : in_ip6[index++] &= 0xfc00;
242 74870 : break;
243 74872 : case 7:
244 74872 : in_ip6[index++] &= 0xfe00;
245 74872 : break;
246 107912 : case 8:
247 107912 : in_ip6[index++] &= 0xff00;
248 107912 : break;
249 74905 : case 9:
250 74905 : in_ip6[index++] &= 0xff80;
251 74905 : break;
252 74906 : case 10:
253 74906 : in_ip6[index++] &= 0xffc0;
254 74906 : break;
255 75117 : case 11:
256 75117 : in_ip6[index++] &= 0xffe0;
257 75117 : break;
258 74989 : case 12:
259 74989 : in_ip6[index++] &= 0xfff0;
260 74989 : break;
261 74905 : case 13:
262 74905 : in_ip6[index++] &= 0xfff8;
263 74905 : break;
264 75041 : case 14:
265 75041 : in_ip6[index++] &= 0xfffc;
266 75041 : break;
267 82917 : case 15:
268 82917 : in_ip6[index++] &= 0xfffe;
269 82917 : break;
270 : }
271 :
272 5438861 : for (int i = index; i < 8; ++i) {
273 4193664 : in_ip6[i] = 0;
274 : }
275 :
276 11206773 : for (int i = 0; i < 8; ++i) {
277 9961576 : ip6[i] = htons(in_ip6[i]);
278 : }
279 1245197 : memcpy(bytes, ip6, sizeof(ip6));
280 : Ip6Address::bytes_type to_bytes;
281 21168349 : for (int i = 0; i < 16; ++i) {
282 19923152 : to_bytes.at(i) = bytes[i];
283 : }
284 1245197 : 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 34348 : Ip4Address Address::V4FromV4MappedV6(const Ip6Address &v6_address) {
292 34348 : Ip4Address v4_address;
293 34348 : if (v6_address.is_v4_mapped()) {
294 34348 : Ip6Address::bytes_type v6_bt = v6_address.to_bytes();
295 : Ip4Address::bytes_type v4_bt =
296 34348 : { { v6_bt[12], v6_bt[13], v6_bt[14], v6_bt[15] } };
297 34348 : v4_address = Ip4Address(v4_bt);
298 : }
299 34348 : return v4_address;
300 : }
|