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 34643 : Address::Family Address::FamilyFromString(const std::string &family) {
55 : std::map<string, Address::Family>::const_iterator loc =
56 34643 : fromString.find(family);
57 34643 : if (loc != fromString.end()) {
58 34643 : return loc->second;
59 : }
60 0 : return Address::UNSPEC;
61 : }
62 :
63 3501305 : std::string Address::FamilyToString(Address::Family family) {
64 7002497 : return toString.find(family)->second;
65 : }
66 :
67 257393 : std::string Address::FamilyToTableString(Address::Family family) {
68 514659 : return toTableName.find(family)->second;
69 : }
70 :
71 5555 : Address::Family Address::VpnFamilyFromFamily(Address::Family family) {
72 5555 : switch (family) {
73 5267 : case Address::INET:
74 : case Address::INETVPN:
75 5267 : return Address::INETVPN;
76 87 : case Address::INET6:
77 : case Address::INET6VPN:
78 87 : 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 79 : default:
86 79 : return Address::UNSPEC;
87 : }
88 : return Address::UNSPEC;
89 : }
90 :
91 157594 : static int CountDots(const string &str) {
92 157594 : int count = 0;
93 157594 : size_t pos = 0;
94 617776 : while (pos < str.size()) {
95 617780 : pos = str.find('.', pos);
96 617774 : if (pos == string::npos) {
97 157592 : break;
98 : }
99 460182 : count++;
100 460182 : pos++;
101 : }
102 157594 : 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 178231 : boost::system::error_code Ip4PrefixParse(const string &str, Ip4Address *addr,
108 : int *plen) {
109 178231 : size_t pos = str.find('/');
110 178231 : if (pos == string::npos) {
111 35 : return make_error_code(boost::system::errc::invalid_argument);
112 : }
113 178196 : *plen = atoi(str.c_str() + pos + 1);
114 178196 : if ((*plen < 0) || (*plen > Address::kMaxV4PrefixLen)) {
115 20602 : return make_error_code(boost::system::errc::invalid_argument);
116 : }
117 :
118 157594 : string addrstr = str.substr(0, pos);
119 157594 : int dots = CountDots(addrstr);
120 170193 : while (dots < 3) {
121 12599 : addrstr.append(".0");
122 12599 : dots++;
123 : }
124 :
125 157594 : boost::system::error_code err;
126 157594 : *addr = Ip4Address::from_string(addrstr, err);
127 157594 : return err;
128 157594 : }
129 :
130 : // Return the bitwise and of IP and mask.
131 174334 : boost::system::error_code Ip4SubnetParse(const string &str, Ip4Address *addr,
132 : int *plen) {
133 174334 : Ip4Address address;
134 174334 : boost::system::error_code err;
135 174334 : err = Ip4PrefixParse(str, &address, plen);
136 174336 : if (!err) {
137 152216 : *addr = Address::GetIp4SubnetAddress(address, *plen);
138 : }
139 174336 : 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 75509 : boost::system::error_code Inet6PrefixParse(const string &str, Ip6Address *addr,
145 : int *plen) {
146 75509 : size_t pos = str.find('/');
147 75509 : if (pos == string::npos) {
148 24 : return make_error_code(boost::system::errc::invalid_argument);
149 : }
150 75485 : *plen = atoi(str.c_str() + pos + 1);
151 75485 : if ((*plen < 0) || (*plen > Address::kMaxV6PrefixLen)) {
152 5 : return make_error_code(boost::system::errc::invalid_argument);
153 : }
154 :
155 75480 : string addrstr = str.substr(0, pos);
156 75481 : boost::system::error_code err;
157 75481 : *addr = Ip6Address::from_string(addrstr, err);
158 75481 : return err;
159 75481 : }
160 :
161 : // Return the bitwise and of IP and mask.
162 75071 : boost::system::error_code Inet6SubnetParse(const string &str, Ip6Address *addr,
163 : int *plen) {
164 75071 : Ip6Address address;
165 75073 : boost::system::error_code err;
166 75073 : err = Inet6PrefixParse(str, &address, plen);
167 75074 : if (!err) {
168 75042 : *addr = Address::GetIp6SubnetAddress(address, *plen);
169 : }
170 75074 : 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 930903 : Ip4Address Address::GetIp4SubnetAddress(const Ip4Address &prefix, uint16_t plen) {
180 930903 : if (plen == 0) {
181 23839 : return boost::asio::ip::address_v4(0);
182 : }
183 :
184 907064 : Ip4Address subnet(prefix.to_ulong() & (0xFFFFFFFF << (32 - plen)));
185 907064 : 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 1431280 : Ip6Address Address::GetIp6SubnetAddress(const Ip6Address &prefix, uint16_t plen) {
201 1431280 : if (plen == 0) {
202 9690 : return boost::asio::ip::address_v6();
203 : }
204 :
205 1421590 : if (plen == 128) {
206 173982 : return prefix;
207 : }
208 :
209 : uint16_t ip6[8], in_ip6[8];
210 : unsigned char bytes[16];
211 :
212 1247608 : inet_pton(AF_INET6, prefix.to_string().c_str(), ip6);
213 :
214 11228472 : for (int i = 0; i < 8; ++i) {
215 9980864 : in_ip6[i] = ntohs(ip6[i]);
216 : }
217 :
218 1247608 : int index = (int) (plen / 16);
219 1247608 : int remain_mask = plen % 16;
220 :
221 1247608 : switch (remain_mask) {
222 80484 : case 0:
223 80484 : in_ip6[index++] = 0;
224 80484 : break;
225 75026 : case 1:
226 75026 : in_ip6[index++] &= 0x8000;
227 75026 : break;
228 75022 : case 2:
229 75022 : in_ip6[index++] &= 0xc000;
230 75022 : break;
231 75022 : case 3:
232 75022 : in_ip6[index++] &= 0xe000;
233 75022 : break;
234 75037 : case 4:
235 75037 : in_ip6[index++] &= 0xf000;
236 75037 : break;
237 75022 : case 5:
238 75022 : in_ip6[index++] &= 0xf800;
239 75022 : break;
240 75023 : case 6:
241 75023 : in_ip6[index++] &= 0xfc00;
242 75023 : break;
243 75025 : case 7:
244 75025 : in_ip6[index++] &= 0xfe00;
245 75025 : break;
246 108104 : case 8:
247 108104 : in_ip6[index++] &= 0xff00;
248 108104 : break;
249 75057 : case 9:
250 75057 : in_ip6[index++] &= 0xff80;
251 75057 : break;
252 75058 : case 10:
253 75058 : in_ip6[index++] &= 0xffc0;
254 75058 : break;
255 75269 : case 11:
256 75269 : in_ip6[index++] &= 0xffe0;
257 75269 : break;
258 75141 : case 12:
259 75141 : in_ip6[index++] &= 0xfff0;
260 75141 : break;
261 75057 : case 13:
262 75057 : in_ip6[index++] &= 0xfff8;
263 75057 : break;
264 75193 : case 14:
265 75193 : in_ip6[index++] &= 0xfffc;
266 75193 : break;
267 83068 : case 15:
268 83068 : in_ip6[index++] &= 0xfffe;
269 83068 : break;
270 : }
271 :
272 5448876 : for (int i = index; i < 8; ++i) {
273 4201268 : in_ip6[i] = 0;
274 : }
275 :
276 11228472 : for (int i = 0; i < 8; ++i) {
277 9980864 : ip6[i] = htons(in_ip6[i]);
278 : }
279 1247608 : memcpy(bytes, ip6, sizeof(ip6));
280 : Ip6Address::bytes_type to_bytes;
281 21209336 : for (int i = 0; i < 16; ++i) {
282 19961728 : to_bytes.at(i) = bytes[i];
283 : }
284 1247608 : 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 31428 : Ip4Address Address::V4FromV4MappedV6(const Ip6Address &v6_address) {
292 31428 : Ip4Address v4_address;
293 31428 : if (v6_address.is_v4_mapped()) {
294 31428 : Ip6Address::bytes_type v6_bt = v6_address.to_bytes();
295 : Ip4Address::bytes_type v4_bt =
296 31428 : { { v6_bt[12], v6_bt[13], v6_bt[14], v6_bt[15] } };
297 31428 : v4_address = Ip4Address(v4_bt);
298 : }
299 31428 : return v4_address;
300 : }
|