]>
Commit | Line | Data |
---|---|---|
41d93087 | 1 | /* |
b510f3a1 | 2 | * DEBUG: section 14 IP Storage and Handling |
41d93087 | 3 | * AUTHOR: Amos Jeffries |
4 | * | |
5 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
6 | * ---------------------------------------------------------- | |
7 | * | |
8 | * Squid is the result of efforts by numerous individuals from the | |
9 | * Internet community. Development is led by Duane Wessels of the | |
10 | * National Laboratory for Applied Network Research and funded by the | |
11 | * National Science Foundation. Squid is Copyrighted (C) 1998 by | |
12 | * the Regents of the University of California. Please see the | |
13 | * COPYRIGHT file for full details. Squid incorporates software | |
14 | * developed and/or copyrighted by other sources. Please see the | |
15 | * CREDITS file for full details. | |
16 | * | |
b7ac5457 | 17 | * This Ip::Address code is copyright (C) 2007 by Treehouse Networks Ltd |
41d93087 | 18 | * of New Zealand. It is published and Lisenced as an extension of |
19 | * squid under the same conditions as the main squid application. | |
20 | * | |
21 | * This program is free software; you can redistribute it and/or modify | |
22 | * it under the terms of the GNU General Public License as published by | |
23 | * the Free Software Foundation; either version 2 of the License, or | |
24 | * (at your option) any later version. | |
26ac0430 | 25 | * |
41d93087 | 26 | * This program is distributed in the hope that it will be useful, |
27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
29 | * GNU General Public License for more details. | |
26ac0430 | 30 | * |
41d93087 | 31 | * You should have received a copy of the GNU General Public License |
32 | * along with this program; if not, write to the Free Software | |
33 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
34 | * | |
35 | */ | |
36 | ||
37 | #include "config.h" | |
27bc2077 AJ |
38 | #include "compat/inet_ntop.h" |
39 | #include "compat/getaddrinfo.h" | |
82b7abe3 | 40 | #include "Debug.h" |
96d89ea0 | 41 | #include "ip/Address.h" |
055421ee | 42 | #include "ip/tools.h" |
1ef0b9ce AJ |
43 | #include "util.h" |
44 | ||
41d93087 | 45 | #if HAVE_ASSERT_H |
46 | #include <assert.h> | |
47 | #endif | |
41d93087 | 48 | #if HAVE_STRING_H |
49 | #include <string.h> | |
50 | #endif | |
51 | #if HAVE_ARPA_INET_H | |
489520a9 AJ |
52 | /* for inet_ntoa() */ |
53 | #include <arpa/inet.h> | |
41d93087 | 54 | #endif |
55 | ||
41d93087 | 56 | /* Debugging only. Dump the address content when a fatal assert is encountered. */ |
41d93087 | 57 | #define IASSERT(a,b) \ |
68b313c2 | 58 | if(!(b)){ printf("assert \"%s\" at line %d\n", a, __LINE__); \ |
b7ac5457 | 59 | printf("Ip::Address invalid? with IsIPv4()=%c, IsIPv6()=%c\n",(IsIPv4()?'T':'F'),(IsIPv6()?'T':'F')); \ |
41d93087 | 60 | printf("ADDRESS:"); \ |
61 | for(unsigned int i = 0; i < sizeof(m_SocketAddr.sin6_addr); i++) { \ | |
62 | printf(" %x", m_SocketAddr.sin6_addr.s6_addr[i]); \ | |
63 | } printf("\n"); assert(b); \ | |
64 | } | |
41d93087 | 65 | |
41d93087 | 66 | int |
b7ac5457 | 67 | Ip::Address::GetCIDR() const |
41d93087 | 68 | { |
69 | uint8_t shift,byte; | |
70 | uint8_t bit,caught; | |
71 | int len = 0; | |
df9617b9 | 72 | const uint8_t *ptr= m_SocketAddr.sin6_addr.s6_addr; |
41d93087 | 73 | |
74 | /* Let's scan all the bits from Most Significant to Least */ | |
75 | /* Until we find an "0" bit. Then, we return */ | |
76 | shift=0; | |
77 | ||
41d93087 | 78 | /* return IPv4 CIDR for any Mapped address */ |
79 | /* Thus only check the mapped bit */ | |
80 | ||
26ac0430 | 81 | if ( !IsIPv6() ) { |
41d93087 | 82 | shift = 12; |
83 | } | |
84 | ||
e1381638 | 85 | for (; shift<sizeof(m_SocketAddr.sin6_addr) ; shift++) { |
41d93087 | 86 | byte= *(ptr+shift); |
87 | ||
88 | if (byte == 0xFF) { | |
89 | len += 8; | |
90 | continue ; /* A short-cut */ | |
91 | } | |
92 | ||
93 | for (caught = 0 , bit= 7 ; !caught && (bit <= 7); bit--) { | |
94 | caught = ((byte & 0x80) == 0x00); /* Found a '0' at 'bit' ? */ | |
95 | ||
96 | if (!caught) | |
97 | len++; | |
98 | ||
99 | byte <<= 1; | |
100 | } | |
101 | ||
102 | if (caught) | |
103 | break; /* We have found the most significant "0" bit. */ | |
104 | } | |
105 | ||
106 | return len; | |
107 | } | |
108 | ||
881c4733 | 109 | int |
b7ac5457 | 110 | Ip::Address::ApplyMask(Ip::Address const &mask_addr) |
41d93087 | 111 | { |
112 | uint32_t *p1 = (uint32_t*)(&m_SocketAddr.sin6_addr); | |
113 | uint32_t const *p2 = (uint32_t const *)(&mask_addr.m_SocketAddr.sin6_addr); | |
114 | unsigned int blen = sizeof(m_SocketAddr.sin6_addr)/sizeof(uint32_t); | |
115 | unsigned int changes = 0; | |
116 | ||
117 | for (unsigned int i = 0; i < blen; i++) { | |
26ac0430 | 118 | if ((p1[i] & p2[i]) != p1[i]) |
41d93087 | 119 | changes++; |
120 | ||
121 | p1[i] &= p2[i]; | |
122 | } | |
123 | ||
41d93087 | 124 | return changes; |
125 | } | |
126 | ||
b7ac5457 AJ |
127 | bool |
128 | Ip::Address::ApplyMask(const unsigned int cidr, int mtype) | |
41d93087 | 129 | { |
130 | uint8_t clearbits = 0; | |
131 | uint8_t* p = NULL; | |
132 | ||
41d93087 | 133 | // validation and short-cuts. |
134 | if (cidr > 128) | |
135 | return false; | |
136 | ||
137 | if (cidr > 32 && mtype == AF_INET) | |
138 | return false; | |
139 | ||
2c1b9590 AJ |
140 | if (cidr == 0) { |
141 | /* CIDR /0 is NoAddr regardless of the IPv4/IPv6 protocol */ | |
142 | SetNoAddr(); | |
143 | return true; | |
144 | } | |
145 | ||
41d93087 | 146 | clearbits = (uint8_t)( (mtype==AF_INET6?128:32) -cidr); |
147 | ||
148 | // short-cut | |
26ac0430 | 149 | if (clearbits == 0) |
41d93087 | 150 | return true; |
151 | ||
41d93087 | 152 | p = (uint8_t*)(&m_SocketAddr.sin6_addr) + 15; |
153 | ||
41d93087 | 154 | for (; clearbits>0 && p >= (uint8_t*)&m_SocketAddr.sin6_addr ; p-- ) { |
26ac0430 | 155 | if (clearbits < 8) { |
41d93087 | 156 | *p &= ((0xFF << clearbits) & 0xFF); |
157 | clearbits = 0; | |
158 | } else { | |
159 | *p &= 0x00; | |
160 | clearbits -= 8; | |
161 | } | |
162 | } | |
163 | ||
164 | return true; | |
165 | } | |
166 | ||
b7ac5457 AJ |
167 | bool |
168 | Ip::Address::IsSockAddr() const | |
41d93087 | 169 | { |
170 | return (m_SocketAddr.sin6_port != 0); | |
171 | } | |
172 | ||
b7ac5457 AJ |
173 | bool |
174 | Ip::Address::IsIPv4() const | |
41d93087 | 175 | { |
0906f01d | 176 | return IN6_IS_ADDR_V4MAPPED( &m_SocketAddr.sin6_addr ); |
41d93087 | 177 | } |
178 | ||
b7ac5457 AJ |
179 | bool |
180 | Ip::Address::IsIPv6() const | |
41d93087 | 181 | { |
0906f01d | 182 | return !IsIPv4(); |
41d93087 | 183 | } |
184 | ||
b7ac5457 AJ |
185 | bool |
186 | Ip::Address::IsAnyAddr() const | |
41d93087 | 187 | { |
0906f01d | 188 | return IN6_IS_ADDR_UNSPECIFIED( &m_SocketAddr.sin6_addr ) || IN6_ARE_ADDR_EQUAL( &m_SocketAddr.sin6_addr, &v4_anyaddr); ; |
41d93087 | 189 | } |
190 | ||
191 | /// NOTE: Does NOT clear the Port stored. Ony the Address and Type. | |
b7ac5457 AJ |
192 | void |
193 | Ip::Address::SetAnyAddr() | |
41d93087 | 194 | { |
41d93087 | 195 | memset(&m_SocketAddr.sin6_addr, 0, sizeof(struct in6_addr) ); |
41d93087 | 196 | } |
197 | ||
b7ac5457 AJ |
198 | /// NOTE: completely empties the Ip::Address structure. Address, Port, Type, everything. |
199 | void | |
200 | Ip::Address::SetEmpty() | |
41d93087 | 201 | { |
202 | memset(&m_SocketAddr, 0, sizeof(m_SocketAddr) ); | |
203 | } | |
204 | ||
349a322f | 205 | #if _SQUID_AIX_ |
d48a52bf A |
206 | // Bug 2885 comment 78 explains. |
207 | // In short AIX has a different netinet/in.h union definition | |
349a322f AJ |
208 | const struct in6_addr Ip::Address::v4_localhost = {{{ 0x00000000, 0x00000000, 0x0000ffff, 0x7f000001 }}}; |
209 | const struct in6_addr Ip::Address::v4_anyaddr = {{{ 0x00000000, 0x00000000, 0x0000ffff, 0x00000000 }}}; | |
210 | const struct in6_addr Ip::Address::v4_noaddr = {{{ 0x00000000, 0x00000000, 0x0000ffff, 0xffffffff }}}; | |
211 | const struct in6_addr Ip::Address::v6_noaddr = {{{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }}}; | |
212 | #else | |
b7ac5457 | 213 | const struct in6_addr Ip::Address::v4_localhost = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
d5b4b6c7 | 214 | 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01 }} |
c0248e14 | 215 | }; |
b7ac5457 | 216 | const struct in6_addr Ip::Address::v4_anyaddr = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
d5b4b6c7 | 217 | 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }} |
c0248e14 | 218 | }; |
0eb08770 HN |
219 | const struct in6_addr Ip::Address::v4_noaddr = {{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
220 | 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }} | |
221 | }; | |
b7ac5457 | 222 | const struct in6_addr Ip::Address::v6_noaddr = {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
d5b4b6c7 | 223 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }} |
c0248e14 | 224 | }; |
349a322f | 225 | #endif |
41d93087 | 226 | |
b7ac5457 AJ |
227 | bool |
228 | Ip::Address::SetIPv4() | |
c0248e14 | 229 | { |
26ac0430 | 230 | if ( IsLocalhost() ) { |
2c8fff41 | 231 | m_SocketAddr.sin6_addr = v4_localhost; |
41d93087 | 232 | return true; |
233 | } | |
41d93087 | 234 | |
26ac0430 | 235 | if ( IsAnyAddr() ) { |
c0248e14 | 236 | m_SocketAddr.sin6_addr = v4_anyaddr; |
41d93087 | 237 | return true; |
238 | } | |
239 | ||
0906f01d CT |
240 | if ( IsNoAddr() ) { |
241 | m_SocketAddr.sin6_addr = v4_noaddr; | |
242 | return true; | |
243 | } | |
244 | ||
26ac0430 | 245 | if ( IsIPv4()) |
41d93087 | 246 | return true; |
247 | ||
248 | // anything non-IPv4 and non-convertable is BAD. | |
249 | return false; | |
41d93087 | 250 | } |
251 | ||
b7ac5457 AJ |
252 | bool |
253 | Ip::Address::IsLocalhost() const | |
41d93087 | 254 | { |
2c8fff41 | 255 | return IN6_IS_ADDR_LOOPBACK( &m_SocketAddr.sin6_addr ) || IN6_ARE_ADDR_EQUAL( &m_SocketAddr.sin6_addr, &v4_localhost ); |
41d93087 | 256 | } |
257 | ||
b7ac5457 AJ |
258 | void |
259 | Ip::Address::SetLocalhost() | |
41d93087 | 260 | { |
055421ee AJ |
261 | if (Ip::EnableIpv6) { |
262 | m_SocketAddr.sin6_addr = in6addr_loopback; | |
263 | m_SocketAddr.sin6_family = AF_INET6; | |
264 | } else { | |
265 | m_SocketAddr.sin6_addr = v4_localhost; | |
266 | m_SocketAddr.sin6_family = AF_INET; | |
267 | } | |
41d93087 | 268 | } |
269 | ||
b7ac5457 AJ |
270 | bool |
271 | Ip::Address::IsSiteLocal6() const | |
a98c2da5 | 272 | { |
01ed4c98 | 273 | return IN6_IS_ADDR_SITELOCAL( &m_SocketAddr.sin6_addr ); |
a98c2da5 AJ |
274 | } |
275 | ||
b7ac5457 AJ |
276 | bool |
277 | Ip::Address::IsSlaac() const | |
a98c2da5 | 278 | { |
65581b3e AJ |
279 | return m_SocketAddr.sin6_addr.s6_addr[10] == static_cast<uint8_t>(0xff) && |
280 | m_SocketAddr.sin6_addr.s6_addr[11] == static_cast<uint8_t>(0xfe); | |
a98c2da5 AJ |
281 | } |
282 | ||
b7ac5457 AJ |
283 | bool |
284 | Ip::Address::IsNoAddr() const | |
41d93087 | 285 | { |
286 | // IFF the address == 0xff..ff (all ones) | |
0906f01d | 287 | return IN6_ARE_ADDR_EQUAL( &m_SocketAddr.sin6_addr, &v6_noaddr ) |
ee561c44 | 288 | || IN6_ARE_ADDR_EQUAL( &m_SocketAddr.sin6_addr, &v4_noaddr ); |
41d93087 | 289 | } |
290 | ||
b7ac5457 AJ |
291 | void |
292 | Ip::Address::SetNoAddr() | |
41d93087 | 293 | { |
c0248e14 | 294 | memset(&m_SocketAddr.sin6_addr, 0xFF, sizeof(struct in6_addr) ); |
41d93087 | 295 | m_SocketAddr.sin6_family = AF_INET6; |
41d93087 | 296 | } |
297 | ||
b7ac5457 AJ |
298 | bool |
299 | Ip::Address::GetReverseString6(char buf[MAX_IPSTRLEN], const struct in6_addr &dat) const | |
41d93087 | 300 | { |
301 | char *p = buf; | |
302 | unsigned char const *r = dat.s6_addr; | |
303 | ||
304 | /* RFC1886 says: */ | |
305 | /* 4321:0:1:2:3:4:567:89ab */ | |
306 | /* must be sent */ | |
307 | /* b.a.9.8.7.6.5.0.4.0.0.0.3.0.0.0.2.0.0.0.1.0.0.0.0.0.0.0.1.2.3.4.ip6.int. */ | |
308 | ||
309 | /* Work from the binary field. Anything else may have representation changes. */ | |
310 | /* The sin6_port and sin6_addr members shall be in network byte order. */ | |
311 | ||
312 | /* Compile Err: 'Too many arguments for format. */ | |
313 | ||
26ac0430 | 314 | for (int i = 15; i >= 0; i--, p+=4) { |
41d93087 | 315 | snprintf(p, 5, "%x.%x.", ((r[i])&0xf), (((r[i])>>4)&0xf) ); |
316 | } | |
317 | ||
318 | /* RFC3152 says: */ | |
319 | /* ip6.int is now deprecated TLD, use ip6.arpa instead. */ | |
320 | snprintf(p,10,"ip6.arpa."); | |
321 | ||
322 | return true; | |
323 | } | |
41d93087 | 324 | |
b7ac5457 AJ |
325 | bool |
326 | Ip::Address::GetReverseString4(char buf[MAX_IPSTRLEN], const struct in_addr &dat) const | |
41d93087 | 327 | { |
328 | unsigned int i = (unsigned int) ntohl(dat.s_addr); | |
329 | snprintf(buf, 32, "%u.%u.%u.%u.in-addr.arpa.", | |
330 | i & 255, | |
331 | (i >> 8) & 255, | |
332 | (i >> 16) & 255, | |
333 | (i >> 24) & 255); | |
334 | return true; | |
335 | } | |
336 | ||
b7ac5457 AJ |
337 | bool |
338 | Ip::Address::GetReverseString(char buf[MAX_IPSTRLEN], int show_type) const | |
41d93087 | 339 | { |
340 | ||
26ac0430 | 341 | if (show_type == AF_UNSPEC) { |
41d93087 | 342 | show_type = IsIPv6() ? AF_INET6 : AF_INET ; |
41d93087 | 343 | } |
344 | ||
345 | if (show_type == AF_INET && IsIPv4()) { | |
2c8fff41 AJ |
346 | struct in_addr* tmp = (struct in_addr*)&m_SocketAddr.sin6_addr.s6_addr[12]; |
347 | return GetReverseString4(buf, *tmp); | |
41d93087 | 348 | } else if ( show_type == AF_INET6 && IsIPv6() ) { |
349 | return GetReverseString6(buf, m_SocketAddr.sin6_addr); | |
41d93087 | 350 | } |
351 | ||
352 | debugs(14,0, "Unable to convert '" << NtoA(buf,MAX_IPSTRLEN) << "' to the rDNS type requested."); | |
353 | ||
354 | buf[0] = '\0'; | |
355 | ||
356 | return false; | |
357 | } | |
358 | ||
b7ac5457 AJ |
359 | Ip::Address& |
360 | Ip::Address::operator =(const Ip::Address &s) | |
41d93087 | 361 | { |
b7ac5457 | 362 | memcpy(this, &s, sizeof(Ip::Address)); |
41d93087 | 363 | return *this; |
364 | }; | |
365 | ||
b7ac5457 | 366 | Ip::Address::Address(const char*s) |
41d93087 | 367 | { |
368 | SetEmpty(); | |
055421ee | 369 | LookupHostIP(s, true); |
41d93087 | 370 | } |
371 | ||
b7ac5457 AJ |
372 | bool |
373 | Ip::Address::operator =(const char* s) | |
41d93087 | 374 | { |
375 | return LookupHostIP(s, true); | |
376 | } | |
377 | ||
b7ac5457 AJ |
378 | bool |
379 | Ip::Address::GetHostByName(const char* s) | |
41d93087 | 380 | { |
381 | return LookupHostIP(s, false); | |
382 | } | |
383 | ||
b7ac5457 AJ |
384 | bool |
385 | Ip::Address::LookupHostIP(const char *s, bool nodns) | |
41d93087 | 386 | { |
387 | int err = 0; | |
388 | ||
389 | short port = 0; | |
390 | ||
391 | struct addrinfo *res = NULL; | |
392 | ||
393 | struct addrinfo want; | |
394 | ||
395 | memset(&want, 0, sizeof(struct addrinfo)); | |
26ac0430 | 396 | if (nodns) { |
41d93087 | 397 | want.ai_flags = AI_NUMERICHOST; // prevent actual DNS lookups! |
398 | } | |
055421ee AJ |
399 | #if 0 |
400 | else if (!Ip::EnableIpv6) | |
401 | want.ai_family = AF_INET; // maybe prevent IPv6 DNS lookups. | |
41d93087 | 402 | #endif |
403 | ||
27bc2077 | 404 | if ( (err = getaddrinfo(s, NULL, &want, &res)) != 0) { |
380de14e | 405 | debugs(14,3, HERE << "Given Non-IP '" << s << "': " << gai_strerror(err) ); |
27bc2077 | 406 | /* free the memory getaddrinfo() dynamically allocated. */ |
26ac0430 | 407 | if (res) { |
27bc2077 | 408 | freeaddrinfo(res); |
41d93087 | 409 | res = NULL; |
410 | } | |
411 | return false; | |
412 | } | |
413 | ||
414 | /* | |
415 | * NP: =(sockaddr_*) may alter the port. we don't want that. | |
416 | * all we have been given as input was an IPA. | |
417 | */ | |
418 | port = GetPort(); | |
419 | operator=(*res); | |
420 | SetPort(port); | |
421 | ||
27bc2077 AJ |
422 | /* free the memory getaddrinfo() dynamically allocated. */ |
423 | freeaddrinfo(res); | |
41d93087 | 424 | |
425 | res = NULL; | |
426 | ||
427 | return true; | |
428 | } | |
429 | ||
b7ac5457 | 430 | Ip::Address::Address(struct sockaddr_in const &s) |
41d93087 | 431 | { |
432 | SetEmpty(); | |
433 | operator=(s); | |
434 | }; | |
435 | ||
b7ac5457 AJ |
436 | Ip::Address & |
437 | Ip::Address::operator =(struct sockaddr_in const &s) | |
41d93087 | 438 | { |
41d93087 | 439 | Map4to6((const in_addr)s.sin_addr, m_SocketAddr.sin6_addr); |
440 | m_SocketAddr.sin6_port = s.sin_port; | |
441 | m_SocketAddr.sin6_family = AF_INET6; | |
41d93087 | 442 | return *this; |
443 | }; | |
444 | ||
b7ac5457 AJ |
445 | Ip::Address & |
446 | Ip::Address::operator =(const struct sockaddr_storage &s) | |
0e1a47f0 | 447 | { |
0e1a47f0 | 448 | /* some AF_* magic to tell socket types apart and what we need to do */ |
26ac0430 | 449 | if (s.ss_family == AF_INET6) { |
0e1a47f0 | 450 | memcpy(&m_SocketAddr, &s, sizeof(struct sockaddr_in)); |
26ac0430 | 451 | } else { // convert it to our storage mapping. |
0e1a47f0 AJ |
452 | struct sockaddr_in *sin = (struct sockaddr_in*)&s; |
453 | m_SocketAddr.sin6_port = sin->sin_port; | |
454 | Map4to6( sin->sin_addr, m_SocketAddr.sin6_addr); | |
455 | } | |
0e1a47f0 AJ |
456 | return *this; |
457 | }; | |
458 | ||
b7ac5457 | 459 | Ip::Address::Address(struct sockaddr_in6 const &s) |
41d93087 | 460 | { |
461 | SetEmpty(); | |
462 | operator=(s); | |
463 | }; | |
464 | ||
b7ac5457 AJ |
465 | Ip::Address & |
466 | Ip::Address::operator =(struct sockaddr_in6 const &s) | |
41d93087 | 467 | { |
468 | memcpy(&m_SocketAddr, &s, sizeof(struct sockaddr_in6)); | |
b5587d15 | 469 | |
41d93087 | 470 | return *this; |
471 | }; | |
41d93087 | 472 | |
b7ac5457 | 473 | Ip::Address::Address(struct in_addr const &s) |
41d93087 | 474 | { |
475 | SetEmpty(); | |
476 | operator=(s); | |
477 | }; | |
478 | ||
b7ac5457 AJ |
479 | Ip::Address & |
480 | Ip::Address::operator =(struct in_addr const &s) | |
41d93087 | 481 | { |
41d93087 | 482 | Map4to6((const in_addr)s, m_SocketAddr.sin6_addr); |
483 | m_SocketAddr.sin6_family = AF_INET6; | |
41d93087 | 484 | return *this; |
485 | }; | |
486 | ||
b7ac5457 | 487 | Ip::Address::Address(struct in6_addr const &s) |
41d93087 | 488 | { |
489 | SetEmpty(); | |
490 | operator=(s); | |
491 | }; | |
492 | ||
b7ac5457 AJ |
493 | Ip::Address & |
494 | Ip::Address::operator =(struct in6_addr const &s) | |
41d93087 | 495 | { |
b5587d15 | 496 | |
41d93087 | 497 | memcpy(&m_SocketAddr.sin6_addr, &s, sizeof(struct in6_addr)); |
498 | m_SocketAddr.sin6_family = AF_INET6; | |
b5587d15 | 499 | |
41d93087 | 500 | return *this; |
501 | }; | |
41d93087 | 502 | |
b7ac5457 | 503 | Ip::Address::Address(const Ip::Address &s) |
41d93087 | 504 | { |
505 | SetEmpty(); | |
506 | operator=(s); | |
507 | } | |
508 | ||
b7ac5457 | 509 | Ip::Address::Address(Ip::Address *s) |
41d93087 | 510 | { |
511 | SetEmpty(); | |
1a1f4104 | 512 | if (s) |
b7ac5457 | 513 | memcpy(this, s, sizeof(Ip::Address)); |
41d93087 | 514 | } |
515 | ||
b7ac5457 | 516 | Ip::Address::Address(const struct hostent &s) |
41d93087 | 517 | { |
518 | SetEmpty(); | |
519 | operator=(s); | |
520 | } | |
521 | ||
b7ac5457 AJ |
522 | bool |
523 | Ip::Address::operator =(const struct hostent &s) | |
41d93087 | 524 | { |
525 | ||
526 | struct in_addr* ipv4 = NULL; | |
527 | ||
528 | struct in6_addr* ipv6 = NULL; | |
529 | ||
530 | //struct hostent { | |
531 | // char *h_name; /* official name of host */ | |
532 | // char **h_aliases; /* alias list */ | |
533 | // int h_addrtype; /* host address type */ | |
534 | // int h_length; /* length of address */ | |
535 | // char **h_addr_list; /* list of addresses */ | |
536 | //} | |
537 | ||
26ac0430 | 538 | switch (s.h_addrtype) { |
41d93087 | 539 | |
540 | case AF_INET: | |
541 | ipv4 = (in_addr*)(s.h_addr_list[0]); | |
542 | /* this */ | |
543 | operator=(*ipv4); | |
544 | break; | |
545 | ||
546 | case AF_INET6: | |
547 | ipv6 = (in6_addr*)(s.h_addr_list[0]); | |
41d93087 | 548 | /* this */ |
549 | operator=(*ipv6); | |
41d93087 | 550 | break; |
551 | ||
552 | default: | |
26ac0430 AJ |
553 | IASSERT("false",false); |
554 | return false; | |
41d93087 | 555 | } |
556 | ||
557 | return true; | |
558 | } | |
559 | ||
b7ac5457 | 560 | Ip::Address::Address(const struct addrinfo &s) |
41d93087 | 561 | { |
562 | SetEmpty(); | |
563 | operator=(s); | |
564 | } | |
565 | ||
b7ac5457 AJ |
566 | bool |
567 | Ip::Address::operator =(const struct addrinfo &s) | |
41d93087 | 568 | { |
569 | ||
570 | struct sockaddr_in* ipv4 = NULL; | |
571 | ||
572 | struct sockaddr_in6* ipv6 = NULL; | |
573 | ||
574 | //struct addrinfo { | |
575 | // int ai_flags; /* input flags */ | |
576 | // int ai_family; /* protocol family for socket */ | |
577 | // int ai_socktype; /* socket type */ | |
578 | // int ai_protocol; /* protocol for socket */ | |
579 | // socklen_t ai_addrlen; /* length of socket-address */ | |
580 | // struct sockaddr *ai_addr; /* socket-address for socket */ | |
581 | // char *ai_canonname; /* canonical name for service location */ | |
582 | // struct addrinfo *ai_next; /* pointer to next in list */ | |
583 | //} | |
584 | ||
26ac0430 | 585 | switch (s.ai_family) { |
41d93087 | 586 | |
587 | case AF_INET: | |
588 | ipv4 = (sockaddr_in*)(s.ai_addr); | |
589 | /* this */ | |
590 | assert(ipv4); | |
591 | operator=(*ipv4); | |
592 | break; | |
593 | ||
594 | case AF_INET6: | |
595 | ipv6 = (sockaddr_in6*)(s.ai_addr); | |
41d93087 | 596 | /* this */ |
597 | assert(ipv6); | |
598 | operator=(*ipv6); | |
41d93087 | 599 | break; |
600 | ||
601 | case AF_UNSPEC: | |
602 | default: | |
603 | // attempt to handle partially initialised addrinfo. | |
604 | // such as those where data only comes from getsockopt() | |
26ac0430 | 605 | if (s.ai_addr != NULL) { |
26ac0430 | 606 | if (s.ai_addrlen == sizeof(struct sockaddr_in6)) { |
41d93087 | 607 | operator=(*((struct sockaddr_in6*)s.ai_addr)); |
608 | return true; | |
055421ee AJ |
609 | } else if (s.ai_addrlen == sizeof(struct sockaddr_in)) { |
610 | operator=(*((struct sockaddr_in*)s.ai_addr)); | |
611 | return true; | |
612 | } | |
41d93087 | 613 | } |
614 | return false; | |
615 | } | |
616 | ||
617 | return true; | |
618 | } | |
619 | ||
b7ac5457 AJ |
620 | void |
621 | Ip::Address::GetAddrInfo(struct addrinfo *&dst, int force) const | |
41d93087 | 622 | { |
26ac0430 | 623 | if (dst == NULL) { |
41d93087 | 624 | dst = new addrinfo; |
625 | } | |
626 | ||
627 | memset(dst, 0, sizeof(struct addrinfo)); | |
628 | ||
629 | // set defaults | |
630 | dst->ai_flags = AI_NUMERICHOST; | |
631 | ||
26ac0430 | 632 | if (dst->ai_socktype == 0) |
41d93087 | 633 | dst->ai_socktype = SOCK_STREAM; |
634 | ||
26ac0430 | 635 | if (dst->ai_socktype == SOCK_STREAM // implies TCP |
41d93087 | 636 | && dst->ai_protocol == 0) |
637 | dst->ai_protocol = IPPROTO_TCP; | |
638 | ||
26ac0430 | 639 | if (dst->ai_socktype == SOCK_DGRAM // implies UDP |
41d93087 | 640 | && dst->ai_protocol == 0) |
641 | dst->ai_protocol = IPPROTO_UDP; | |
642 | ||
055421ee | 643 | if (force == AF_INET6 || (force == AF_UNSPEC && IsIPv6()) ) { |
41d93087 | 644 | dst->ai_addr = (struct sockaddr*)new sockaddr_in6; |
645 | ||
646 | memset(dst->ai_addr,0,sizeof(struct sockaddr_in6)); | |
647 | ||
648 | GetSockAddr(*((struct sockaddr_in6*)dst->ai_addr)); | |
649 | ||
650 | dst->ai_addrlen = sizeof(struct sockaddr_in6); | |
651 | ||
652 | dst->ai_family = ((struct sockaddr_in6*)dst->ai_addr)->sin6_family; | |
9d92af86 AJ |
653 | |
654 | #if 0 | |
655 | /** | |
656 | * Enable only if you must and please report to squid-dev if you find a need for this. | |
657 | * | |
658 | * Vista may need this to cope with dual-stack (unsetting IP6_V6ONLY). | |
659 | * http://msdn.microsoft.com/en-us/library/ms738574(VS.85).aspx | |
660 | * Linux appears to only do some things when its present. | |
661 | * (93) Bad Protocol | |
662 | * FreeBSD dies horribly when using dual-stack with it set. | |
663 | * (43) Protocol not supported | |
664 | */ | |
41d93087 | 665 | dst->ai_protocol = IPPROTO_IPV6; |
9d92af86 AJ |
666 | #endif |
667 | ||
055421ee | 668 | } else if ( force == AF_INET || (force == AF_UNSPEC && IsIPv4()) ) { |
41d93087 | 669 | |
055421ee | 670 | dst->ai_addr = (struct sockaddr*)new sockaddr_in; |
41d93087 | 671 | |
055421ee | 672 | memset(dst->ai_addr,0,sizeof(struct sockaddr_in)); |
41d93087 | 673 | |
055421ee | 674 | GetSockAddr(*((struct sockaddr_in*)dst->ai_addr)); |
41d93087 | 675 | |
055421ee | 676 | dst->ai_addrlen = sizeof(struct sockaddr_in); |
41d93087 | 677 | |
055421ee AJ |
678 | dst->ai_family = ((struct sockaddr_in*)dst->ai_addr)->sin_family; |
679 | } else { | |
680 | IASSERT("false",false); | |
681 | } | |
41d93087 | 682 | } |
683 | ||
b7ac5457 AJ |
684 | void |
685 | Ip::Address::InitAddrInfo(struct addrinfo *&ai) | |
41d93087 | 686 | { |
26ac0430 | 687 | if (ai == NULL) { |
41d93087 | 688 | ai = new addrinfo; |
689 | memset(ai,0,sizeof(struct addrinfo)); | |
690 | } | |
691 | ||
692 | // remove any existing data. | |
26ac0430 | 693 | if (ai->ai_addr) delete ai->ai_addr; |
41d93087 | 694 | |
695 | ai->ai_addr = (struct sockaddr*)new sockaddr_in6; | |
696 | memset(ai->ai_addr, 0, sizeof(struct sockaddr_in6)); | |
697 | ||
698 | ai->ai_addrlen = sizeof(struct sockaddr_in6); | |
699 | ||
700 | } | |
701 | ||
b7ac5457 AJ |
702 | void |
703 | Ip::Address::FreeAddrInfo(struct addrinfo *&ai) | |
41d93087 | 704 | { |
26ac0430 | 705 | if (ai == NULL) return; |
41d93087 | 706 | |
26ac0430 | 707 | if (ai->ai_addr) delete ai->ai_addr; |
41d93087 | 708 | |
709 | ai->ai_addr = NULL; | |
710 | ||
711 | ai->ai_addrlen = 0; | |
712 | ||
713 | // NP: name fields are NOT allocated at present. | |
714 | delete ai; | |
715 | ||
716 | ai = NULL; | |
717 | } | |
718 | ||
b7ac5457 AJ |
719 | int |
720 | Ip::Address::matchIPAddr(const Ip::Address &rhs) const | |
41d93087 | 721 | { |
41d93087 | 722 | uint8_t *l = (uint8_t*)m_SocketAddr.sin6_addr.s6_addr; |
723 | uint8_t *r = (uint8_t*)rhs.m_SocketAddr.sin6_addr.s6_addr; | |
41d93087 | 724 | |
725 | // loop a byte-wise compare | |
726 | // NP: match MUST be R-to-L : L-to-R produces inconsistent gt/lt results at varying CIDR | |
727 | // expected difference on CIDR is gt/eq or lt/eq ONLY. | |
26ac0430 | 728 | for (unsigned int i = 0 ; i < sizeof(m_SocketAddr.sin6_addr) ; i++) { |
41d93087 | 729 | |
26ac0430 | 730 | if (l[i] < r[i]) |
41d93087 | 731 | return -1; |
732 | ||
26ac0430 | 733 | if (l[i] > r[i]) |
41d93087 | 734 | return 1; |
735 | } | |
736 | ||
737 | return 0; | |
738 | } | |
739 | ||
a67d2b2e AR |
740 | int |
741 | Ip::Address::compareWhole(const Ip::Address &rhs) const | |
607a7bd4 AR |
742 | { |
743 | return memcmp(this, &rhs, sizeof(*this)); | |
744 | } | |
745 | ||
b7ac5457 AJ |
746 | bool |
747 | Ip::Address::operator ==(const Ip::Address &s) const | |
41d93087 | 748 | { |
749 | return (0 == matchIPAddr(s)); | |
750 | } | |
751 | ||
b7ac5457 AJ |
752 | bool |
753 | Ip::Address::operator !=(const Ip::Address &s) const | |
41d93087 | 754 | { |
755 | return ! ( operator==(s) ); | |
756 | } | |
757 | ||
b7ac5457 AJ |
758 | bool |
759 | Ip::Address::operator <=(const Ip::Address &rhs) const | |
41d93087 | 760 | { |
26ac0430 | 761 | if (IsAnyAddr() && !rhs.IsAnyAddr()) |
41d93087 | 762 | return true; |
763 | ||
764 | return (matchIPAddr(rhs) <= 0); | |
765 | } | |
766 | ||
b7ac5457 AJ |
767 | bool |
768 | Ip::Address::operator >=(const Ip::Address &rhs) const | |
41d93087 | 769 | { |
26ac0430 | 770 | if (IsNoAddr() && !rhs.IsNoAddr()) |
41d93087 | 771 | return true; |
772 | ||
773 | return ( matchIPAddr(rhs) >= 0); | |
774 | } | |
775 | ||
b7ac5457 AJ |
776 | bool |
777 | Ip::Address::operator >(const Ip::Address &rhs) const | |
41d93087 | 778 | { |
26ac0430 | 779 | if (IsNoAddr() && !rhs.IsNoAddr()) |
41d93087 | 780 | return true; |
781 | ||
782 | return ( matchIPAddr(rhs) > 0); | |
783 | } | |
784 | ||
b7ac5457 AJ |
785 | bool |
786 | Ip::Address::operator <(const Ip::Address &rhs) const | |
41d93087 | 787 | { |
6232d0a7 | 788 | if (IsAnyAddr() && !rhs.IsAnyAddr()) |
41d93087 | 789 | return true; |
790 | ||
791 | return ( matchIPAddr(rhs) < 0); | |
792 | } | |
793 | ||
b7ac5457 AJ |
794 | u_short |
795 | Ip::Address::GetPort() const | |
41d93087 | 796 | { |
797 | return ntohs( m_SocketAddr.sin6_port ); | |
798 | } | |
799 | ||
b7ac5457 AJ |
800 | u_short |
801 | Ip::Address::SetPort(u_short prt) | |
41d93087 | 802 | { |
803 | m_SocketAddr.sin6_port = htons(prt); | |
804 | ||
805 | return prt; | |
806 | } | |
807 | ||
808 | /** | |
809 | * NtoA Given a buffer writes a readable ascii version of the IPA and/or port stored | |
810 | * | |
811 | * Buffer must be of a size large enough to hold the converted address. | |
812 | * This size is provided in the form of a global defined variable MAX_IPSTRLEN | |
813 | * Should a buffer shorter be provided the string result will be truncated | |
814 | * at the length of the available buffer. | |
815 | * | |
816 | * A copy of the buffer is also returned for simple immediate display. | |
817 | */ | |
b7ac5457 AJ |
818 | char * |
819 | Ip::Address::NtoA(char* buf, const unsigned int blen, int force) const | |
41d93087 | 820 | { |
821 | // Ensure we have a buffer. | |
26ac0430 | 822 | if (buf == NULL) { |
41d93087 | 823 | return NULL; |
824 | } | |
825 | ||
826 | /* some external code may have blindly memset a parent. */ | |
827 | /* thats okay, our default is known */ | |
26ac0430 | 828 | if ( IsAnyAddr() ) { |
1dc746da | 829 | memcpy(buf,"::\0", min(static_cast<unsigned int>(3),blen)); |
41d93087 | 830 | return buf; |
831 | } | |
832 | ||
833 | memset(buf,0,blen); // clear buffer before write | |
834 | ||
835 | /* Pure-IPv6 CANNOT be displayed in IPv4 format. */ | |
836 | /* However IPv4 CAN. */ | |
26ac0430 AJ |
837 | if ( force == AF_INET && !IsIPv4() ) { |
838 | if ( IsIPv6() ) { | |
1dc746da | 839 | memcpy(buf, "{!IPv4}\0", min(static_cast<unsigned int>(8),blen)); |
41d93087 | 840 | } |
841 | return buf; | |
842 | } | |
843 | ||
26ac0430 | 844 | if ( force == AF_INET6 || (force == AF_UNSPEC && IsIPv6()) ) { |
41d93087 | 845 | |
27bc2077 | 846 | inet_ntop(AF_INET6, &m_SocketAddr.sin6_addr, buf, blen); |
41d93087 | 847 | |
848 | } else if ( force == AF_INET || (force == AF_UNSPEC && IsIPv4()) ) { | |
849 | ||
850 | struct in_addr tmp; | |
851 | GetInAddr(tmp); | |
27bc2077 | 852 | inet_ntop(AF_INET, &tmp, buf, blen); |
41d93087 | 853 | } else { |
854 | debugs(14,0,"WARNING: Corrupt IP Address details OR required to display in unknown format (" << | |
26ac0430 | 855 | force << "). accepted={" << AF_UNSPEC << "," << AF_INET << "," << AF_INET6 << "}"); |
41d93087 | 856 | fprintf(stderr,"WARNING: Corrupt IP Address details OR required to display in unknown format (%d). accepted={%d,%d,%d} ", |
857 | force, AF_UNSPEC, AF_INET, AF_INET6); | |
1dc746da | 858 | memcpy(buf,"dead:beef::\0", min(static_cast<unsigned int>(13),blen)); |
41d93087 | 859 | assert(false); |
860 | } | |
861 | ||
862 | return buf; | |
863 | } | |
864 | ||
b7ac5457 AJ |
865 | unsigned int |
866 | Ip::Address::ToHostname(char *buf, const unsigned int blen) const | |
e1381638 | 867 | { |
41d93087 | 868 | char *p = buf; |
869 | ||
26ac0430 | 870 | if (IsIPv6() && blen > 0) { |
41d93087 | 871 | *p = '['; |
872 | p++; | |
873 | } | |
874 | ||
188a640f | 875 | /* 8 being space for [ ] : and port digits */ |
26ac0430 | 876 | if ( IsIPv6() ) |
188a640f | 877 | NtoA(p, blen-8, AF_INET6); |
41d93087 | 878 | else |
188a640f | 879 | NtoA(p, blen-8, AF_INET); |
41d93087 | 880 | |
881 | // find the end of the new string | |
26ac0430 | 882 | while (*p != '\0' && p < buf+blen) |
41d93087 | 883 | p++; |
884 | ||
26ac0430 | 885 | if (IsIPv6() && p < (buf+blen-1) ) { |
41d93087 | 886 | *p = ']'; |
887 | p++; | |
888 | } | |
889 | ||
890 | /* terminate just in case. */ | |
891 | *p = '\0'; | |
892 | ||
893 | /* return size of buffer now used */ | |
894 | return (p - buf); | |
895 | } | |
896 | ||
b7ac5457 AJ |
897 | char * |
898 | Ip::Address::ToURL(char* buf, unsigned int blen) const | |
e1381638 | 899 | { |
41d93087 | 900 | char *p = buf; |
901 | ||
902 | // Ensure we have a buffer. | |
903 | ||
26ac0430 | 904 | if (buf == NULL) { |
41d93087 | 905 | return NULL; |
906 | } | |
907 | ||
908 | p += ToHostname(p, blen); | |
909 | ||
842fe4cc AR |
910 | if (m_SocketAddr.sin6_port > 0 && p <= (buf+blen-7) ) { |
911 | // ':port' (short int) needs at most 6 bytes plus 1 for 0-terminator | |
912 | snprintf(p, 7, ":%d", GetPort() ); | |
41d93087 | 913 | } |
914 | ||
915 | // force a null-terminated string | |
303bfd76 | 916 | buf[blen-1] = '\0'; |
41d93087 | 917 | |
918 | return buf; | |
919 | } | |
920 | ||
b7ac5457 AJ |
921 | void |
922 | Ip::Address::GetSockAddr(struct sockaddr_storage &addr, const int family) const | |
e1381638 | 923 | { |
52b694c2 AJ |
924 | struct sockaddr_in *sin = NULL; |
925 | ||
26ac0430 | 926 | if ( family == AF_INET && !IsIPv4()) { |
0e1a47f0 | 927 | // FIXME INET6: caller using the wrong socket type! |
b7ac5457 | 928 | debugs(14, DBG_CRITICAL, HERE << "Ip::Address::GetSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this); |
0e1a47f0 AJ |
929 | assert(false); |
930 | } | |
931 | ||
26ac0430 | 932 | if ( family == AF_INET6 || (family == AF_UNSPEC && IsIPv6()) ) { |
1ef0b9ce AJ |
933 | struct sockaddr_in6 *ss6 = (struct sockaddr_in6*)&addr; |
934 | GetSockAddr(*ss6); | |
26ac0430 | 935 | } else if ( family == AF_INET || (family == AF_UNSPEC && IsIPv4()) ) { |
52b694c2 | 936 | sin = (struct sockaddr_in*)&addr; |
1ef0b9ce | 937 | GetSockAddr(*sin); |
52b694c2 AJ |
938 | } else { |
939 | IASSERT("false",false); | |
0e1a47f0 | 940 | } |
0e1a47f0 AJ |
941 | } |
942 | ||
b7ac5457 AJ |
943 | void |
944 | Ip::Address::GetSockAddr(struct sockaddr_in &buf) const | |
e1381638 | 945 | { |
26ac0430 | 946 | if ( IsIPv4() ) { |
41d93087 | 947 | buf.sin_family = AF_INET; |
948 | buf.sin_port = m_SocketAddr.sin6_port; | |
949 | Map6to4( m_SocketAddr.sin6_addr, buf.sin_addr); | |
26ac0430 | 950 | } else { |
b7ac5457 | 951 | debugs(14, DBG_CRITICAL, HERE << "Ip::Address::GetSockAddr : Cannot convert non-IPv4 to IPv4. from " << *this ); |
41d93087 | 952 | |
953 | memset(&buf,0xFFFFFFFF,sizeof(struct sockaddr_in)); | |
954 | assert(false); | |
955 | } | |
956 | ||
12f45551 AJ |
957 | #if HAVE_SIN_LEN_IN_SAI |
958 | /* not all OS have this field, BUT when they do it can be a problem if set wrong */ | |
1ef0b9ce | 959 | buf.sin_len = sizeof(struct sockaddr_in); |
12f45551 | 960 | #endif |
41d93087 | 961 | } |
962 | ||
b7ac5457 AJ |
963 | void |
964 | Ip::Address::GetSockAddr(struct sockaddr_in6 &buf) const | |
e1381638 | 965 | { |
41d93087 | 966 | memcpy(&buf, &m_SocketAddr, sizeof(struct sockaddr_in6)); |
967 | /* maintain address family. It may have changed inside us. */ | |
968 | buf.sin6_family = AF_INET6; | |
12f45551 AJ |
969 | |
970 | #if HAVE_SIN6_LEN_IN_SAI | |
971 | /* not all OS have this field, BUT when they do it can be a problem if set wrong */ | |
1ef0b9ce | 972 | buf.sin6_len = sizeof(struct sockaddr_in6); |
12f45551 | 973 | #endif |
41d93087 | 974 | } |
41d93087 | 975 | |
b7ac5457 AJ |
976 | void |
977 | Ip::Address::Map4to6(const struct in_addr &in, struct in6_addr &out) const | |
e1381638 | 978 | { |
41d93087 | 979 | /* check for special cases */ |
980 | ||
26ac0430 | 981 | if ( in.s_addr == 0x00000000) { |
41d93087 | 982 | /* ANYADDR */ |
0eb08770 | 983 | out = v4_anyaddr; |
26ac0430 | 984 | } else if ( in.s_addr == 0xFFFFFFFF) { |
41d93087 | 985 | /* NOADDR */ |
0eb08770 | 986 | out = v4_noaddr; |
26ac0430 | 987 | } else { |
41d93087 | 988 | /* general */ |
0eb08770 | 989 | out = v4_anyaddr; |
2c8fff41 AJ |
990 | out.s6_addr[12] = ((uint8_t *)&in.s_addr)[0]; |
991 | out.s6_addr[13] = ((uint8_t *)&in.s_addr)[1]; | |
992 | out.s6_addr[14] = ((uint8_t *)&in.s_addr)[2]; | |
993 | out.s6_addr[15] = ((uint8_t *)&in.s_addr)[3]; | |
41d93087 | 994 | } |
995 | } | |
996 | ||
b7ac5457 AJ |
997 | void |
998 | Ip::Address::Map6to4(const struct in6_addr &in, struct in_addr &out) const | |
e1381638 | 999 | { |
41d93087 | 1000 | /* ANYADDR */ |
1001 | /* NOADDR */ | |
1002 | /* general */ | |
1003 | ||
1004 | memset(&out, 0, sizeof(struct in_addr)); | |
2c8fff41 AJ |
1005 | ((uint8_t *)&out.s_addr)[0] = in.s6_addr[12]; |
1006 | ((uint8_t *)&out.s_addr)[1] = in.s6_addr[13]; | |
1007 | ((uint8_t *)&out.s_addr)[2] = in.s6_addr[14]; | |
1008 | ((uint8_t *)&out.s_addr)[3] = in.s6_addr[15]; | |
41d93087 | 1009 | } |
1010 | ||
b7ac5457 AJ |
1011 | void |
1012 | Ip::Address::GetInAddr(in6_addr &buf) const | |
e1381638 | 1013 | { |
41d93087 | 1014 | memcpy(&buf, &m_SocketAddr.sin6_addr, sizeof(struct in6_addr)); |
1015 | } | |
41d93087 | 1016 | |
b7ac5457 AJ |
1017 | bool |
1018 | Ip::Address::GetInAddr(struct in_addr &buf) const | |
e1381638 | 1019 | { |
26ac0430 | 1020 | if ( IsIPv4() ) { |
41d93087 | 1021 | Map6to4((const in6_addr)m_SocketAddr.sin6_addr, buf); |
1022 | return true; | |
1023 | } | |
41d93087 | 1024 | |
1025 | // default: | |
1026 | // non-compatible IPv6 Pure Address | |
1027 | ||
b7ac5457 | 1028 | debugs(14,1, HERE << "Ip::Address::GetInAddr : Cannot convert non-IPv4 to IPv4. IPA=" << *this); |
41d93087 | 1029 | memset(&buf,0xFFFFFFFF,sizeof(struct in_addr)); |
1030 | assert(false); | |
1031 | return false; | |
1032 | } |