1 /** @file
2
3 A brief file description
4
5 @section license License
6
7 Licensed to the Apache Software Foundation (ASF) under one
8 or more contributor license agreements. See the NOTICE file
9 distributed with this work for additional information
10 regarding copyright ownership. The ASF licenses this file
11 to you under the Apache License, Version 2.0 (the
12 "License"); you may not use this file except in compliance
13 with the License. You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22
23 */
24
25 #pragma once
26
27 #include <netinet/in.h>
28 #include <netdb.h>
29 #include <sys/socket.h>
30 #include <string_view>
31
32 #include "tscore/ink_memory.h"
33 #include "tscore/ink_apidefs.h"
34 #include "tscore/BufferWriterForward.h"
35
36 #if !TS_HAS_IN6_IS_ADDR_UNSPECIFIED
37 #if defined(IN6_IS_ADDR_UNSPECIFIED)
38 #undef IN6_IS_ADDR_UNSPECIFIED
39 #endif
40 static inline bool
IN6_IS_ADDR_UNSPECIFIED(in6_addr const * addr)41 IN6_IS_ADDR_UNSPECIFIED(in6_addr const *addr)
42 {
43 uint64_t const *w = reinterpret_cast<uint64_t const *>(addr);
44 return 0 == w[0] && 0 == w[1];
45 }
46 #endif
47
48 /*
49 * IP protocol stack tags.
50 *
51 * When adding support for an additional protocol, the following minimum steps
52 * should be done:
53 *
54 * 1. This set of string_views should be updated with the new tag.
55 * 2. A populate_protocol function overload should be implemented for the
56 * appropriate VConnection or ProxySession virtual function.
57 * 3. Traffic Dump should be updated to handle the new tag in:
58 * plugins/experimental/traffic_dump/session_data.cc
59 */
60 extern const std::string_view IP_PROTO_TAG_IPV4;
61 extern const std::string_view IP_PROTO_TAG_IPV6;
62 extern const std::string_view IP_PROTO_TAG_UDP;
63 extern const std::string_view IP_PROTO_TAG_TCP;
64 extern const std::string_view IP_PROTO_TAG_QUIC;
65 extern const std::string_view IP_PROTO_TAG_TLS_1_0;
66 extern const std::string_view IP_PROTO_TAG_TLS_1_1;
67 extern const std::string_view IP_PROTO_TAG_TLS_1_2;
68 extern const std::string_view IP_PROTO_TAG_TLS_1_3;
69 extern const std::string_view IP_PROTO_TAG_HTTP_0_9;
70 extern const std::string_view IP_PROTO_TAG_HTTP_1_0;
71 extern const std::string_view IP_PROTO_TAG_HTTP_1_1;
72 extern const std::string_view IP_PROTO_TAG_HTTP_2_0;
73 extern const std::string_view IP_PROTO_TAG_HTTP_QUIC;
74 extern const std::string_view IP_PROTO_TAG_HTTP_3;
75 extern const std::string_view IP_PROTO_TAG_HTTP_QUIC_D27;
76 extern const std::string_view IP_PROTO_TAG_HTTP_3_D27;
77
78 struct IpAddr; // forward declare.
79
80 /** A union to hold the standard IP address structures.
81 By standard we mean @c sockaddr compliant.
82
83 We use the term "endpoint" because these contain more than just the
84 raw address, all of the data for an IP endpoint is present.
85
86 @internal This might be useful to promote to avoid strict aliasing
87 problems. Experiment with it here to see how it works in the
88 field.
89
90 @internal @c sockaddr_storage is not present because it is so
91 large and the benefits of including it are small. Use of this
92 structure will make it easy to add if that becomes necessary.
93
94 */
95 union IpEndpoint {
96 typedef IpEndpoint self; ///< Self reference type.
97
98 struct sockaddr sa; ///< Generic address.
99 struct sockaddr_in sin; ///< IPv4
100 struct sockaddr_in6 sin6; ///< IPv6
101
102 /** Assign from a socket address.
103 The entire address (all parts) are copied if the @a ip is valid.
104 */
105 self &assign(sockaddr const *ip ///< Source address, family, port.
106 );
107 /// Assign from an @a addr and @a port.
108 self &assign(IpAddr const &addr, ///< Address and address family.
109 in_port_t port = 0 ///< Port (network order).
110 );
111
112 /// Test for valid IP address.
113 bool isValid() const;
114 /// Test for IPv4.
115 bool isIp4() const;
116 /// Test for IPv6.
117 bool isIp6() const;
118
119 uint16_t family() const;
120
121 /// Set to be any address for family @a family.
122 /// @a family must be @c AF_INET or @c AF_INET6.
123 /// @return This object.
124 self &setToAnyAddr(int family ///< Address family.
125 );
126 /// Set to be loopback for family @a family.
127 /// @a family must be @c AF_INET or @c AF_INET6.
128 /// @return This object.
129 self &setToLoopback(int family ///< Address family.
130 );
131
132 /// Port in network order.
133 in_port_t &port();
134 /// Port in network order.
135 in_port_t port() const;
136 /// Port in host order.
137 in_port_t host_order_port() const;
138
139 operator sockaddr *() { return &sa; }
140 operator sockaddr const *() const { return &sa; }
141 };
142
143 /** Return the detected maximum listen(2) backlog for TCP. */
144 int ats_tcp_somaxconn();
145
146 /** Parse a string for pieces of an IP address.
147
148 This doesn't parse the actual IP address, but picks it out from @a
149 src. It is intended to deal with the brackets that can optionally
150 surround an IP address (usually IPv6) which in turn are used to
151 differentiate between an address and an attached port. E.g.
152 @code
153 [FE80:9312::192:168:1:1]:80
154 @endcode
155 @a addr or @a port can be @c nullptr in which case that value isn't returned.
156
157 @return 0 if an address was found, non-zero otherwise.
158 */
159 int ats_ip_parse(std::string_view src, ///< [in] String to search.
160 std::string_view *addr, ///< [out] Range containing IP address.
161 std::string_view *port, ///< [out] Range containing port.
162 std::string_view *rest = nullptr ///< [out] Remnant past the addr/port if any.
163 );
164
165 /** Check to see if a buffer contains only IP address characters.
166 @return
167 - AF_UNSPEC - not a numeric address.
168 - AF_INET - only digits and dots.
169 - AF_INET6 - colons found.
170 */
171 int ats_ip_check_characters(std::string_view text);
172
173 /**
174 Wrapper for inet_addr().
175
176 @param s IP address in the Internet standard dot notation.
177
178 */
179 inkcoreapi uint32_t ats_inet_addr(const char *s);
180
181 const char *ats_ip_ntop(const struct sockaddr *addr, char *dst, size_t size);
182
183 // --
184 /// Size in bytes of an port and IPv4/IPv6 address.
185 static constexpr size_t TS_IP4_SIZE = sizeof(in_addr_t); ///< 4
186 static constexpr size_t TS_IP6_SIZE = sizeof(in6_addr); ///< 16
187 static constexpr size_t TS_PORT_SIZE = sizeof(in_port_t); ///< 2
188
189 /// Reset an address to invalid.
190 /// @note Useful for marking a member as not yet set.
191 inline void
ats_ip_invalidate(sockaddr * addr)192 ats_ip_invalidate(sockaddr *addr)
193 {
194 addr->sa_family = AF_UNSPEC;
195 }
196 inline void
ats_ip_invalidate(sockaddr_in6 * addr)197 ats_ip_invalidate(sockaddr_in6 *addr)
198 {
199 addr->sin6_family = AF_UNSPEC;
200 }
201 inline void
ats_ip_invalidate(IpEndpoint * ip)202 ats_ip_invalidate(IpEndpoint *ip)
203 {
204 ip->sa.sa_family = AF_UNSPEC;
205 }
206
207 /** Get a string name for an IP address family.
208 @return The string name (never @c nullptr).
209 */
210 std::string_view ats_ip_family_name(int family);
211
212 /// Test for IP protocol.
213 /// @return @c true if the address is IP, @c false otherwise.
214 inline bool
ats_is_ip(sockaddr const * addr)215 ats_is_ip(sockaddr const *addr)
216 {
217 return addr && (AF_INET == addr->sa_family || AF_INET6 == addr->sa_family);
218 }
219 /// @return @c true if the address is IP, @c false otherwise.
220 inline bool
ats_is_ip(IpEndpoint const * addr)221 ats_is_ip(IpEndpoint const *addr)
222 {
223 return addr && (AF_INET == addr->sa.sa_family || AF_INET6 == addr->sa.sa_family);
224 }
225 /// Test for IP protocol.
226 /// @return @c true if the value is an IP address family, @c false otherwise.
227 inline bool
ats_is_ip(int family)228 ats_is_ip(int family)
229 {
230 return AF_INET == family || AF_INET6 == family;
231 }
232 /// Test for IPv4 protocol.
233 /// @return @c true if the address is IPv4, @c false otherwise.
234 inline bool
ats_is_ip4(sockaddr const * addr)235 ats_is_ip4(sockaddr const *addr)
236 {
237 return addr && AF_INET == addr->sa_family;
238 }
239 /// Test for IPv4 protocol.
240 /// @note Convenience overload.
241 /// @return @c true if the address is IPv4, @c false otherwise.
242 inline bool
ats_is_ip4(IpEndpoint const * addr)243 ats_is_ip4(IpEndpoint const *addr)
244 {
245 return addr && AF_INET == addr->sa.sa_family;
246 }
247 /// Test for IPv6 protocol.
248 /// @return @c true if the address is IPv6, @c false otherwise.
249 inline bool
ats_is_ip6(sockaddr const * addr)250 ats_is_ip6(sockaddr const *addr)
251 {
252 return addr && AF_INET6 == addr->sa_family;
253 }
254 /// Test for IPv6 protocol.
255 /// @note Convenience overload.
256 /// @return @c true if the address is IPv6, @c false otherwise.
257 inline bool
ats_is_ip6(IpEndpoint const * addr)258 ats_is_ip6(IpEndpoint const *addr)
259 {
260 return addr && AF_INET6 == addr->sa.sa_family;
261 }
262
263 /// @return @c true if the address families are compatible.
264 inline bool
ats_ip_are_compatible(sockaddr const * lhs,sockaddr const * rhs)265 ats_ip_are_compatible(sockaddr const *lhs, ///< Address to test.
266 sockaddr const *rhs ///< Address to test.
267 )
268 {
269 return lhs->sa_family == rhs->sa_family;
270 }
271 /// @return @c true if the address families are compatible.
272 inline bool
ats_ip_are_compatible(IpEndpoint const * lhs,IpEndpoint const * rhs)273 ats_ip_are_compatible(IpEndpoint const *lhs, ///< Address to test.
274 IpEndpoint const *rhs ///< Address to test.
275 )
276 {
277 return ats_ip_are_compatible(&lhs->sa, &rhs->sa);
278 }
279 /// @return @c true if the address families are compatible.
280 inline bool
ats_ip_are_compatible(int lhs,sockaddr const * rhs)281 ats_ip_are_compatible(int lhs, ///< Address family to test.
282 sockaddr const *rhs ///< Address to test.
283 )
284 {
285 return lhs == rhs->sa_family;
286 }
287 /// @return @c true if the address families are compatible.
288 inline bool
ats_ip_are_compatible(sockaddr const * lhs,int rhs)289 ats_ip_are_compatible(sockaddr const *lhs, ///< Address to test.
290 int rhs ///< Family to test.
291 )
292 {
293 return lhs->sa_family == rhs;
294 }
295
296 // IP address casting.
297 // sa_cast to cast to sockaddr*.
298 // ss_cast to cast to sockaddr_storage*.
299 // ip4_cast converts to sockaddr_in (because that's effectively an IPv4 addr).
300 // ip6_cast converts to sockaddr_in6
301
302 inline sockaddr *
ats_ip_sa_cast(sockaddr_storage * a)303 ats_ip_sa_cast(sockaddr_storage *a)
304 {
305 return static_cast<sockaddr *>(static_cast<void *>(a));
306 }
307 inline sockaddr const *
ats_ip_sa_cast(sockaddr_storage const * a)308 ats_ip_sa_cast(sockaddr_storage const *a)
309 {
310 return static_cast<sockaddr const *>(static_cast<void const *>(a));
311 }
312
313 inline sockaddr *
ats_ip_sa_cast(sockaddr_in * a)314 ats_ip_sa_cast(sockaddr_in *a)
315 {
316 return static_cast<sockaddr *>(static_cast<void *>(a));
317 }
318 inline sockaddr const *
ats_ip_sa_cast(sockaddr_in const * a)319 ats_ip_sa_cast(sockaddr_in const *a)
320 {
321 return static_cast<sockaddr const *>(static_cast<void const *>(a));
322 }
323
324 inline sockaddr *
ats_ip_sa_cast(sockaddr_in6 * a)325 ats_ip_sa_cast(sockaddr_in6 *a)
326 {
327 return static_cast<sockaddr *>(static_cast<void *>(a));
328 }
329 inline sockaddr const *
ats_ip_sa_cast(sockaddr_in6 const * a)330 ats_ip_sa_cast(sockaddr_in6 const *a)
331 {
332 return static_cast<sockaddr const *>(static_cast<void const *>(a));
333 }
334
335 inline sockaddr_storage *
ats_ip_ss_cast(sockaddr * a)336 ats_ip_ss_cast(sockaddr *a)
337 {
338 return static_cast<sockaddr_storage *>(static_cast<void *>(a));
339 }
340 inline sockaddr_storage const *
ats_ip_ss_cast(sockaddr const * a)341 ats_ip_ss_cast(sockaddr const *a)
342 {
343 return static_cast<sockaddr_storage const *>(static_cast<void const *>(a));
344 }
345
346 inline sockaddr_in *
ats_ip4_cast(sockaddr * a)347 ats_ip4_cast(sockaddr *a)
348 {
349 return static_cast<sockaddr_in *>(static_cast<void *>(a));
350 }
351 inline sockaddr_in const *
ats_ip4_cast(sockaddr const * a)352 ats_ip4_cast(sockaddr const *a)
353 {
354 return static_cast<sockaddr_in const *>(static_cast<void const *>(a));
355 }
356
357 inline sockaddr_in &
ats_ip4_cast(sockaddr & a)358 ats_ip4_cast(sockaddr &a)
359 {
360 return *static_cast<sockaddr_in *>(static_cast<void *>(&a));
361 }
362 inline sockaddr_in const &
ats_ip4_cast(sockaddr const & a)363 ats_ip4_cast(sockaddr const &a)
364 {
365 return *static_cast<sockaddr_in const *>(static_cast<void const *>(&a));
366 }
367
368 inline sockaddr_in *
ats_ip4_cast(sockaddr_in6 * a)369 ats_ip4_cast(sockaddr_in6 *a)
370 {
371 return static_cast<sockaddr_in *>(static_cast<void *>(a));
372 }
373 inline sockaddr_in const *
ats_ip4_cast(sockaddr_in6 const * a)374 ats_ip4_cast(sockaddr_in6 const *a)
375 {
376 return static_cast<sockaddr_in const *>(static_cast<void const *>(a));
377 }
378
379 inline sockaddr_in &
ats_ip4_cast(sockaddr_in6 & a)380 ats_ip4_cast(sockaddr_in6 &a)
381 {
382 return *static_cast<sockaddr_in *>(static_cast<void *>(&a));
383 }
384 inline sockaddr_in const &
ats_ip4_cast(sockaddr_in6 const & a)385 ats_ip4_cast(sockaddr_in6 const &a)
386 {
387 return *static_cast<sockaddr_in const *>(static_cast<void const *>(&a));
388 }
389
390 inline sockaddr_in6 *
ats_ip6_cast(sockaddr * a)391 ats_ip6_cast(sockaddr *a)
392 {
393 return static_cast<sockaddr_in6 *>(static_cast<void *>(a));
394 }
395 inline sockaddr_in6 const *
ats_ip6_cast(sockaddr const * a)396 ats_ip6_cast(sockaddr const *a)
397 {
398 return static_cast<sockaddr_in6 const *>(static_cast<void const *>(a));
399 }
400 inline sockaddr_in6 &
ats_ip6_cast(sockaddr & a)401 ats_ip6_cast(sockaddr &a)
402 {
403 return *static_cast<sockaddr_in6 *>(static_cast<void *>(&a));
404 }
405 inline sockaddr_in6 const &
ats_ip6_cast(sockaddr const & a)406 ats_ip6_cast(sockaddr const &a)
407 {
408 return *static_cast<sockaddr_in6 const *>(static_cast<void const *>(&a));
409 }
410
411 /// @return The @c sockaddr size for the family of @a addr.
412 inline size_t
ats_ip_size(sockaddr const * addr)413 ats_ip_size(sockaddr const *addr ///< Address object.
414 )
415 {
416 return AF_INET == addr->sa_family ? sizeof(sockaddr_in) : AF_INET6 == addr->sa_family ? sizeof(sockaddr_in6) : 0;
417 }
418 inline size_t
ats_ip_size(IpEndpoint const * addr)419 ats_ip_size(IpEndpoint const *addr ///< Address object.
420 )
421 {
422 return AF_INET == addr->sa.sa_family ? sizeof(sockaddr_in) : AF_INET6 == addr->sa.sa_family ? sizeof(sockaddr_in6) : 0;
423 }
424 /// @return The size of the IP address only.
425 inline size_t
ats_ip_addr_size(sockaddr const * addr)426 ats_ip_addr_size(sockaddr const *addr ///< Address object.
427 )
428 {
429 return AF_INET == addr->sa_family ? sizeof(in_addr_t) : AF_INET6 == addr->sa_family ? sizeof(in6_addr) : 0;
430 }
431 inline size_t
ats_ip_addr_size(IpEndpoint const * addr)432 ats_ip_addr_size(IpEndpoint const *addr ///< Address object.
433 )
434 {
435 return AF_INET == addr->sa.sa_family ? sizeof(in_addr_t) : AF_INET6 == addr->sa.sa_family ? sizeof(in6_addr) : 0;
436 }
437
438 /** Get a reference to the port in an address.
439 @note Because this is direct access, the port value is in network order.
440 @see ats_ip_port_host_order.
441 @return A reference to the port value in an IPv4 or IPv6 address.
442 @internal This is primarily for internal use but it might be handy for
443 clients so it is exposed.
444 */
445 inline in_port_t &
ats_ip_port_cast(sockaddr * sa)446 ats_ip_port_cast(sockaddr *sa)
447 {
448 static in_port_t dummy = 0;
449 return ats_is_ip4(sa) ? ats_ip4_cast(sa)->sin_port : ats_is_ip6(sa) ? ats_ip6_cast(sa)->sin6_port : (dummy = 0);
450 }
451 inline in_port_t const &
ats_ip_port_cast(sockaddr const * sa)452 ats_ip_port_cast(sockaddr const *sa)
453 {
454 return ats_ip_port_cast(const_cast<sockaddr *>(sa));
455 }
456 inline in_port_t const &
ats_ip_port_cast(IpEndpoint const * ip)457 ats_ip_port_cast(IpEndpoint const *ip)
458 {
459 return ats_ip_port_cast(const_cast<sockaddr *>(&ip->sa));
460 }
461 inline in_port_t &
ats_ip_port_cast(IpEndpoint * ip)462 ats_ip_port_cast(IpEndpoint *ip)
463 {
464 return ats_ip_port_cast(&ip->sa);
465 }
466
467 /** Access the IPv4 address.
468
469 If this is not an IPv4 address a zero valued address is returned.
470 @note This is direct access to the address so it will be in
471 network order.
472
473 @return A reference to the IPv4 address in @a addr.
474 */
475 inline in_addr_t &
ats_ip4_addr_cast(sockaddr * addr)476 ats_ip4_addr_cast(sockaddr *addr)
477 {
478 static in_addr_t dummy = 0;
479 return ats_is_ip4(addr) ? ats_ip4_cast(addr)->sin_addr.s_addr : (dummy = 0);
480 }
481
482 /** Access the IPv4 address.
483
484 If this is not an IPv4 address a zero valued address is returned.
485 @note This is direct access to the address so it will be in
486 network order.
487
488 @return A reference to the IPv4 address in @a addr.
489 */
490 inline in_addr_t const &
ats_ip4_addr_cast(sockaddr const * addr)491 ats_ip4_addr_cast(sockaddr const *addr)
492 {
493 static in_addr_t dummy = 0;
494 return ats_is_ip4(addr) ? ats_ip4_cast(addr)->sin_addr.s_addr : static_cast<in_addr_t const &>(dummy = 0);
495 }
496
497 /** Access the IPv4 address.
498
499 If this is not an IPv4 address a zero valued address is returned.
500 @note This is direct access to the address so it will be in
501 network order.
502 @note Convenience overload.
503
504 @return A reference to the IPv4 address in @a addr.
505 */
506 inline in_addr_t &
ats_ip4_addr_cast(IpEndpoint * ip)507 ats_ip4_addr_cast(IpEndpoint *ip)
508 {
509 return ats_ip4_addr_cast(&ip->sa);
510 }
511
512 /** Access the IPv4 address.
513
514 If this is not an IPv4 address a zero valued address is returned.
515 @note This is direct access to the address so it will be in
516 network order.
517 @note Convenience overload.
518
519 @return A reference to the IPv4 address in @a addr.
520 */
521 inline in_addr_t const &
ats_ip4_addr_cast(IpEndpoint const * ip)522 ats_ip4_addr_cast(IpEndpoint const *ip)
523 {
524 return ats_ip4_addr_cast(&ip->sa);
525 }
526
527 /** Access the IPv6 address.
528
529 If this is not an IPv6 address a zero valued address is returned.
530 @note This is direct access to the address so it will be in
531 network order.
532
533 @return A reference to the IPv6 address in @a addr.
534 */
535 inline in6_addr &
ats_ip6_addr_cast(sockaddr * addr)536 ats_ip6_addr_cast(sockaddr *addr)
537 {
538 return ats_ip6_cast(addr)->sin6_addr;
539 }
540 inline in6_addr const &
ats_ip6_addr_cast(sockaddr const * addr)541 ats_ip6_addr_cast(sockaddr const *addr)
542 {
543 return ats_ip6_cast(addr)->sin6_addr;
544 }
545 inline in6_addr &
ats_ip6_addr_cast(IpEndpoint * ip)546 ats_ip6_addr_cast(IpEndpoint *ip)
547 {
548 return ip->sin6.sin6_addr;
549 }
550 inline in6_addr const &
ats_ip6_addr_cast(IpEndpoint const * ip)551 ats_ip6_addr_cast(IpEndpoint const *ip)
552 {
553 return ip->sin6.sin6_addr;
554 }
555
556 /** Cast an IP address to an array of @c uint32_t.
557 @note The size of the array is dependent on the address type which
558 must be checked independently of this function.
559 @return A pointer to the address information in @a addr or @c nullptr
560 if @a addr is not an IP address.
561 */
562 inline uint32_t *
ats_ip_addr32_cast(sockaddr * addr)563 ats_ip_addr32_cast(sockaddr *addr)
564 {
565 uint32_t *zret = nullptr;
566 switch (addr->sa_family) {
567 case AF_INET:
568 zret = reinterpret_cast<uint32_t *>(&ats_ip4_addr_cast(addr));
569 break;
570 case AF_INET6:
571 zret = reinterpret_cast<uint32_t *>(&ats_ip6_addr_cast(addr));
572 break;
573 }
574 return zret;
575 }
576 inline uint32_t const *
ats_ip_addr32_cast(sockaddr const * addr)577 ats_ip_addr32_cast(sockaddr const *addr)
578 {
579 return ats_ip_addr32_cast(const_cast<sockaddr *>(addr));
580 }
581
582 /** Cast an IP address to an array of @c uint8_t.
583 @note The size of the array is dependent on the address type which
584 must be checked independently of this function.
585 @return A pointer to the address information in @a addr or @c nullptr
586 if @a addr is not an IP address.
587 @see ats_ip_addr_size
588 */
589 inline uint8_t *
ats_ip_addr8_cast(sockaddr * addr)590 ats_ip_addr8_cast(sockaddr *addr)
591 {
592 uint8_t *zret = nullptr;
593 switch (addr->sa_family) {
594 case AF_INET:
595 zret = reinterpret_cast<uint8_t *>(&ats_ip4_addr_cast(addr));
596 break;
597 case AF_INET6:
598 zret = reinterpret_cast<uint8_t *>(&ats_ip6_addr_cast(addr));
599 break;
600 }
601 return zret;
602 }
603 inline uint8_t const *
ats_ip_addr8_cast(sockaddr const * addr)604 ats_ip_addr8_cast(sockaddr const *addr)
605 {
606 return ats_ip_addr8_cast(const_cast<sockaddr *>(addr));
607 }
608 inline uint8_t *
ats_ip_addr8_cast(IpEndpoint * ip)609 ats_ip_addr8_cast(IpEndpoint *ip)
610 {
611 return ats_ip_addr8_cast(&ip->sa);
612 }
613 inline uint8_t const *
ats_ip_addr8_cast(IpEndpoint const * ip)614 ats_ip_addr8_cast(IpEndpoint const *ip)
615 {
616 return ats_ip_addr8_cast(&ip->sa);
617 }
618
619 /// Check for loopback.
620 /// @return @c true if this is an IP loopback address, @c false otherwise.
621 inline bool
ats_is_ip_loopback(sockaddr const * ip)622 ats_is_ip_loopback(sockaddr const *ip)
623 {
624 return ip && ((AF_INET == ip->sa_family && 0x7F == ats_ip_addr8_cast(ip)[0]) ||
625 (AF_INET6 == ip->sa_family && IN6_IS_ADDR_LOOPBACK(&ats_ip6_addr_cast(ip))));
626 }
627
628 /// Check for loopback.
629 /// @return @c true if this is an IP loopback address, @c false otherwise.
630 inline bool
ats_is_ip_loopback(IpEndpoint const * ip)631 ats_is_ip_loopback(IpEndpoint const *ip)
632 {
633 return ats_is_ip_loopback(&ip->sa);
634 }
635
636 /// Check for multicast.
637 /// @return @true if @a ip is multicast.
638 inline bool
ats_is_ip_multicast(sockaddr const * ip)639 ats_is_ip_multicast(sockaddr const *ip)
640 {
641 return ip && ((AF_INET == ip->sa_family && 0xe == (ats_ip_addr8_cast(ip)[0] >> 4)) ||
642 (AF_INET6 == ip->sa_family && IN6_IS_ADDR_MULTICAST(&ats_ip6_addr_cast(ip))));
643 }
644 /// Check for multicast.
645 /// @return @true if @a ip is multicast.
646 inline bool
ats_is_ip_multicast(IpEndpoint const * ip)647 ats_is_ip_multicast(IpEndpoint const *ip)
648 {
649 return ats_is_ip_multicast(&ip->sa);
650 }
651
652 /// Check for Private.
653 /// @return @true if @a ip is private.
654 inline bool
ats_is_ip_private(sockaddr const * ip)655 ats_is_ip_private(sockaddr const *ip)
656 {
657 bool zret = false;
658 if (ats_is_ip4(ip)) {
659 in_addr_t a = ats_ip4_addr_cast(ip);
660 zret = ((a & htonl(0xFF000000)) == htonl(0x0A000000)) || // 10.0.0.0/8
661 ((a & htonl(0xFFC00000)) == htonl(0x64400000)) || // 100.64.0.0/10
662 ((a & htonl(0xFFF00000)) == htonl(0xAC100000)) || // 172.16.0.0/12
663 ((a & htonl(0xFFFF0000)) == htonl(0xC0A80000)) // 192.168.0.0/16
664 ;
665 } else if (ats_is_ip6(ip)) {
666 in6_addr a = ats_ip6_addr_cast(ip);
667 zret = ((a.s6_addr[0] & 0xFE) == 0xFC) // fc00::/7
668 ;
669 }
670 return zret;
671 }
672
673 /// Check for Private.
674 /// @return @true if @a ip is private.
675 inline bool
ats_is_ip_private(IpEndpoint const * ip)676 ats_is_ip_private(IpEndpoint const *ip)
677 {
678 return ats_is_ip_private(&ip->sa);
679 }
680
681 /// Check for Link Local.
682 /// @return @true if @a ip is link local.
683 inline bool
ats_is_ip_linklocal(sockaddr const * ip)684 ats_is_ip_linklocal(sockaddr const *ip)
685 {
686 bool zret = false;
687 if (ats_is_ip4(ip)) {
688 in_addr_t a = ats_ip4_addr_cast(ip);
689 zret = ((a & htonl(0xFFFF0000)) == htonl(0xA9FE0000)) // 169.254.0.0/16
690 ;
691 } else if (ats_is_ip6(ip)) {
692 in6_addr a = ats_ip6_addr_cast(ip);
693 zret = ((a.s6_addr[0] == 0xFE) && ((a.s6_addr[1] & 0xC0) == 0x80)) // fe80::/10
694 ;
695 }
696 return zret;
697 }
698
699 /// Check for Link Local.
700 /// @return @true if @a ip is link local.
701 inline bool
ats_is_ip_linklocal(IpEndpoint const * ip)702 ats_is_ip_linklocal(IpEndpoint const *ip)
703 {
704 return ats_is_ip_linklocal(&ip->sa);
705 }
706
707 /// Check for being "any" address.
708 /// @return @c true if @a ip is the any / unspecified address.
709 inline bool
ats_is_ip_any(sockaddr const * ip)710 ats_is_ip_any(sockaddr const *ip)
711 {
712 return (ats_is_ip4(ip) && INADDR_ANY == ats_ip4_addr_cast(ip)) ||
713 (ats_is_ip6(ip) && IN6_IS_ADDR_UNSPECIFIED(&ats_ip6_addr_cast(ip)));
714 }
715
716 /// @name Address operators
717 //@{
718
719 /** Copy the address from @a src to @a dst if it's IP.
720 This attempts to do a minimal copy based on the type of @a src.
721 If @a src is not an IP address type it is @b not copied and
722 @a dst is marked as invalid.
723 @return @c true if @a src was an IP address, @c false otherwise.
724 */
725 inline bool
ats_ip_copy(sockaddr * dst,sockaddr const * src)726 ats_ip_copy(sockaddr *dst, ///< Destination object.
727 sockaddr const *src ///< Source object.
728 )
729 {
730 size_t n = 0;
731 if (src) {
732 switch (src->sa_family) {
733 case AF_INET:
734 n = sizeof(sockaddr_in);
735 break;
736 case AF_INET6:
737 n = sizeof(sockaddr_in6);
738 break;
739 }
740 }
741 if (n) {
742 if (src != dst) {
743 memcpy(dst, src, n);
744 #if HAVE_STRUCT_SOCKADDR_SA_LEN
745 dst->sa_len = n;
746 #endif
747 }
748 } else {
749 ats_ip_invalidate(dst);
750 }
751 return n != 0;
752 }
753
754 inline bool
ats_ip_copy(IpEndpoint * dst,sockaddr const * src)755 ats_ip_copy(IpEndpoint *dst, ///< Destination object.
756 sockaddr const *src ///< Source object.
757 )
758 {
759 return ats_ip_copy(&dst->sa, src);
760 }
761 inline bool
ats_ip_copy(IpEndpoint * dst,IpEndpoint const * src)762 ats_ip_copy(IpEndpoint *dst, ///< Destination object.
763 IpEndpoint const *src ///< Source object.
764 )
765 {
766 return ats_ip_copy(&dst->sa, &src->sa);
767 }
768 inline bool
ats_ip_copy(sockaddr * dst,IpEndpoint const * src)769 ats_ip_copy(sockaddr *dst, IpEndpoint const *src)
770 {
771 return ats_ip_copy(dst, &src->sa);
772 }
773
774 /** Compare two addresses.
775 This is useful for IPv4, IPv6, and the unspecified address type.
776 If the addresses are of different types they are ordered
777
778 Non-IP < IPv4 < IPv6
779
780 - all non-IP addresses are the same ( including @c AF_UNSPEC )
781 - IPv4 addresses are compared numerically (host order)
782 - IPv6 addresses are compared byte wise in network order (MSB to LSB)
783
784 @return
785 - -1 if @a lhs is less than @a rhs.
786 - 0 if @a lhs is identical to @a rhs.
787 - 1 if @a lhs is greater than @a rhs.
788
789 @internal This looks like a lot of code for an inline but I think it
790 should compile down to something reasonable.
791 */
792 inline int
ats_ip_addr_cmp(sockaddr const * lhs,sockaddr const * rhs)793 ats_ip_addr_cmp(sockaddr const *lhs, ///< Left hand operand.
794 sockaddr const *rhs ///< Right hand operand.
795 )
796 {
797 int zret = 0;
798 uint16_t rtype = rhs->sa_family;
799 uint16_t ltype = lhs->sa_family;
800
801 // We lump all non-IP addresses into a single equivalence class
802 // that is less than an IP address. This includes AF_UNSPEC.
803 if (AF_INET == ltype) {
804 if (AF_INET == rtype) {
805 in_addr_t la = ntohl(ats_ip4_cast(lhs)->sin_addr.s_addr);
806 in_addr_t ra = ntohl(ats_ip4_cast(rhs)->sin_addr.s_addr);
807 if (la < ra)
808 zret = -1;
809 else if (la > ra)
810 zret = 1;
811 else
812 zret = 0;
813 } else if (AF_INET6 == rtype) { // IPv4 < IPv6
814 zret = -1;
815 } else { // IP > not IP
816 zret = 1;
817 }
818 } else if (AF_INET6 == ltype) {
819 if (AF_INET6 == rtype) {
820 sockaddr_in6 const *lhs_in6 = ats_ip6_cast(lhs);
821 zret = memcmp(&lhs_in6->sin6_addr, &ats_ip6_cast(rhs)->sin6_addr, sizeof(lhs_in6->sin6_addr));
822 } else {
823 zret = 1; // IPv6 greater than any other type.
824 }
825 } else if (AF_INET == rtype || AF_INET6 == rtype) {
826 // ltype is non-IP so it's less than either IP type.
827 zret = -1;
828 } else {
829 // Both types are non-IP so they're equal.
830 zret = 0;
831 }
832
833 return zret;
834 }
835
836 /** Compare two addresses.
837 @note Convenience overload.
838 @see ats_ip_addr_cmp(sockaddr const* lhs, sockaddr const* rhs)
839 */
840 inline int
ats_ip_addr_cmp(IpEndpoint const * lhs,IpEndpoint const * rhs)841 ats_ip_addr_cmp(IpEndpoint const *lhs, IpEndpoint const *rhs)
842 {
843 return ats_ip_addr_cmp(&lhs->sa, &rhs->sa);
844 }
845
846 /** Check if two addresses are equal.
847 @return @c true if @a lhs and @a rhs point to equal addresses,
848 @c false otherwise.
849 */
850 inline bool
ats_ip_addr_eq(sockaddr const * lhs,sockaddr const * rhs)851 ats_ip_addr_eq(sockaddr const *lhs, sockaddr const *rhs)
852 {
853 return 0 == ats_ip_addr_cmp(lhs, rhs);
854 }
855 inline bool
ats_ip_addr_eq(IpEndpoint const * lhs,IpEndpoint const * rhs)856 ats_ip_addr_eq(IpEndpoint const *lhs, IpEndpoint const *rhs)
857 {
858 return 0 == ats_ip_addr_cmp(&lhs->sa, &rhs->sa);
859 }
860
861 inline bool
862 operator==(IpEndpoint const &lhs, IpEndpoint const &rhs)
863 {
864 return 0 == ats_ip_addr_cmp(&lhs.sa, &rhs.sa);
865 }
866 inline bool
867 operator!=(IpEndpoint const &lhs, IpEndpoint const &rhs)
868 {
869 return 0 != ats_ip_addr_cmp(&lhs.sa, &rhs.sa);
870 }
871
872 /// Compare address and port for equality.
873 inline bool
ats_ip_addr_port_eq(sockaddr const * lhs,sockaddr const * rhs)874 ats_ip_addr_port_eq(sockaddr const *lhs, sockaddr const *rhs)
875 {
876 bool zret = false;
877 if (lhs->sa_family == rhs->sa_family && ats_ip_port_cast(lhs) == ats_ip_port_cast(rhs)) {
878 if (AF_INET == lhs->sa_family)
879 zret = ats_ip4_cast(lhs)->sin_addr.s_addr == ats_ip4_cast(rhs)->sin_addr.s_addr;
880 else if (AF_INET6 == lhs->sa_family)
881 zret = 0 == memcmp(&ats_ip6_cast(lhs)->sin6_addr, &ats_ip6_cast(rhs)->sin6_addr, sizeof(in6_addr));
882 }
883 return zret;
884 }
885
886 //@}
887
888 /// Get IP TCP/UDP port.
889 /// @return The port in host order for an IPv4 or IPv6 address,
890 /// or zero if neither.
891 inline in_port_t
ats_ip_port_host_order(sockaddr const * addr)892 ats_ip_port_host_order(sockaddr const *addr ///< Address with port.
893 )
894 {
895 // We can discard the const because this function returns
896 // by value.
897 return ntohs(ats_ip_port_cast(const_cast<sockaddr *>(addr)));
898 }
899
900 /// Get IP TCP/UDP port.
901 /// @return The port in host order for an IPv4 or IPv6 address,
902 /// or zero if neither.
903 inline in_port_t
ats_ip_port_host_order(IpEndpoint const * ip)904 ats_ip_port_host_order(IpEndpoint const *ip ///< Address with port.
905 )
906 {
907 // We can discard the const because this function returns
908 // by value.
909 return ntohs(ats_ip_port_cast(const_cast<sockaddr *>(&ip->sa)));
910 }
911
912 /** Extract the IPv4 address.
913 @return Host order IPv4 address.
914 */
915 inline in_addr_t
ats_ip4_addr_host_order(sockaddr const * addr)916 ats_ip4_addr_host_order(sockaddr const *addr ///< Address object.
917 )
918 {
919 return ntohl(ats_ip4_addr_cast(const_cast<sockaddr *>(addr)));
920 }
921
922 /// Write IPv4 data to storage @a dst.
923 inline sockaddr *
924 ats_ip4_set(sockaddr_in *dst, ///< Destination storage.
925 in_addr_t addr, ///< address, IPv4 network order.
926 in_port_t port = 0 ///< port, network order.
927 )
928 {
929 ink_zero(*dst);
930 #if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
931 dst->sin_len = sizeof(sockaddr_in);
932 #endif
933 dst->sin_family = AF_INET;
934 dst->sin_addr.s_addr = addr;
935 dst->sin_port = port;
936 return ats_ip_sa_cast(dst);
937 }
938
939 /** Write IPv4 data to @a dst.
940 @note Convenience overload.
941 */
942 inline sockaddr *
943 ats_ip4_set(IpEndpoint *dst, ///< Destination storage.
944 in_addr_t ip4, ///< address, IPv4 network order.
945 in_port_t port = 0 ///< port, network order.
946 )
947 {
948 return ats_ip4_set(&dst->sin, ip4, port);
949 }
950
951 /** Write IPv4 data to storage @a dst.
952
953 This is the generic overload. Caller must verify that @a dst is at
954 least @c sizeof(sockaddr_in) bytes.
955 */
956 inline sockaddr *
957 ats_ip4_set(sockaddr *dst, ///< Destination storage.
958 in_addr_t ip4, ///< address, IPv4 network order.
959 in_port_t port = 0 ///< port, network order.
960 )
961 {
962 return ats_ip4_set(ats_ip4_cast(dst), ip4, port);
963 }
964 /** Write IPv6 data to storage @a dst.
965 @return @a dst cast to @c sockaddr*.
966 */
967 inline sockaddr *
968 ats_ip6_set(sockaddr_in6 *dst, ///< Destination storage.
969 in6_addr const &addr, ///< address in network order.
970 in_port_t port = 0 ///< Port, network order.
971 )
972 {
973 ink_zero(*dst);
974 #if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
975 dst->sin6_len = sizeof(sockaddr_in6);
976 #endif
977 dst->sin6_family = AF_INET6;
978 memcpy(&dst->sin6_addr, &addr, sizeof addr);
979 dst->sin6_port = port;
980 return ats_ip_sa_cast(dst);
981 }
982 /** Write IPv6 data to storage @a dst.
983 @return @a dst cast to @c sockaddr*.
984 */
985 inline sockaddr *
986 ats_ip6_set(sockaddr *dst, ///< Destination storage.
987 in6_addr const &addr, ///< address in network order.
988 in_port_t port = 0 ///< Port, network order.
989 )
990 {
991 return ats_ip6_set(ats_ip6_cast(dst), addr, port);
992 }
993 /** Write IPv6 data to storage @a dst.
994 @return @a dst cast to @c sockaddr*.
995 */
996 inline sockaddr *
997 ats_ip6_set(IpEndpoint *dst, ///< Destination storage.
998 in6_addr const &addr, ///< address in network order.
999 in_port_t port = 0 ///< Port, network order.
1000 )
1001 {
1002 return ats_ip6_set(&dst->sin6, addr, port);
1003 }
1004
1005 /** Write a null terminated string for @a addr to @a dst.
1006 A buffer of size INET6_ADDRSTRLEN suffices, including a terminating nul.
1007 */
1008 const char *ats_ip_ntop(const sockaddr *addr, ///< Address.
1009 char *dst, ///< Output buffer.
1010 size_t size ///< Length of buffer.
1011 );
1012
1013 /** Write a null terminated string for @a addr to @a dst.
1014 A buffer of size INET6_ADDRSTRLEN suffices, including a terminating nul.
1015 */
1016 inline const char *
ats_ip_ntop(IpEndpoint const * addr,char * dst,size_t size)1017 ats_ip_ntop(IpEndpoint const *addr, ///< Address.
1018 char *dst, ///< Output buffer.
1019 size_t size ///< Length of buffer.
1020 )
1021 {
1022 return ats_ip_ntop(&addr->sa, dst, size);
1023 }
1024
1025 /// Buffer size sufficient for IPv6 address and port.
1026 static size_t const INET6_ADDRPORTSTRLEN = INET6_ADDRSTRLEN + 6;
1027 /// Convenience type for address formatting.
1028 typedef char ip_text_buffer[INET6_ADDRSTRLEN];
1029 /// Convenience type for address formatting.
1030 typedef char ip_port_text_buffer[INET6_ADDRPORTSTRLEN];
1031
1032 /** Write a null terminated string for @a addr to @a dst with port.
1033 A buffer of size INET6_ADDRPORTSTRLEN suffices, including a terminating nul.
1034 */
1035 const char *ats_ip_nptop(const sockaddr *addr, ///< Address.
1036 char *dst, ///< Output buffer.
1037 size_t size ///< Length of buffer.
1038 );
1039
1040 /** Write a null terminated string for @a addr to @a dst with port.
1041 A buffer of size INET6_ADDRPORTSTRLEN suffices, including a terminating nul.
1042 */
1043 inline const char *
ats_ip_nptop(IpEndpoint const * addr,char * dst,size_t size)1044 ats_ip_nptop(IpEndpoint const *addr, ///< Address.
1045 char *dst, ///< Output buffer.
1046 size_t size ///< Length of buffer.
1047 )
1048 {
1049 return ats_ip_nptop(&addr->sa, dst, size);
1050 }
1051
1052 /** Convert @a text to an IP address and write it to @a addr.
1053
1054 @a text is expected to be an explicit address, not a hostname. No
1055 hostname resolution is done. The call must provide an @a ip large
1056 enough to hold the address value.
1057
1058 This attempts to recognize and process a port value if
1059 present. The port in @a ip is set appropriately, or to zero if no
1060 port was found or it was malformed.
1061
1062 @note The return values are logically reversed from @c inet_pton.
1063 @note This uses @c getaddrinfo internally and so involves memory
1064 allocation.
1065
1066 @return 0 on success, non-zero on failure.
1067 */
1068 int ats_ip_pton(const std::string_view &text, ///< [in] text.
1069 sockaddr *addr ///< [out] address
1070 );
1071
1072 /** Convert @a text to an IP address and write it to @a addr.
1073
1074 @a text is expected to be an explicit address, not a hostname. No
1075 hostname resolution is done.
1076
1077 @note This uses @c getaddrinfo internally and so involves memory
1078 allocation.
1079 @note Convenience overload.
1080
1081 @return 0 on success, non-zero on failure.
1082 */
1083 inline int
ats_ip_pton(const char * text,sockaddr_in6 * addr)1084 ats_ip_pton(const char *text, ///< [in] text.
1085 sockaddr_in6 *addr ///< [out] address
1086 )
1087 {
1088 return ats_ip_pton(std::string_view(text, strlen(text)), ats_ip_sa_cast(addr));
1089 }
1090
1091 inline int
ats_ip_pton(const std::string_view & text,IpEndpoint * addr)1092 ats_ip_pton(const std::string_view &text, ///< [in] text.
1093 IpEndpoint *addr ///< [out] address
1094 )
1095 {
1096 return ats_ip_pton(text, &addr->sa);
1097 }
1098
1099 inline int
ats_ip_pton(const char * text,IpEndpoint * addr)1100 ats_ip_pton(const char *text, ///< [in] text.
1101 IpEndpoint *addr ///< [out] address
1102 )
1103 {
1104 return ats_ip_pton(std::string_view(text, strlen(text)), &addr->sa);
1105 }
1106
1107 inline int
ats_ip_pton(const char * text,sockaddr * addr)1108 ats_ip_pton(const char *text, ///< [in] text.
1109 sockaddr *addr ///< [out] address
1110 )
1111 {
1112 return ats_ip_pton(std::string_view(text, strlen(text)), addr);
1113 }
1114
1115 /** Get the best address info for @a name.
1116
1117 @name is passed to @c getaddrinfo which does a host lookup if @a
1118 name is not in IP address format. The results are examined for the
1119 "best" addresses. This is only significant for the host name case
1120 (for IP address data, there is at most one result). The preference is
1121 Global > Non-Routable > Multicast > Loopback.
1122
1123 IPv4 and IPv4 results are handled independently and stored in @a
1124 ip4 and @a ip6 respectively. If @a name is known to be a numeric
1125 IP address @c ats_ip_pton is a better choice. Use this function
1126 if the type of @a name is not known. If you want to look at the
1127 addresses and not just get the "best", use @c getaddrinfo
1128 directly.
1129
1130 @a ip4 or @a ip6 can be @c nullptr and the result for that family is
1131 discarded. It is legal for both to be @c nullptr in which case this
1132 is just a format check.
1133
1134 @return 0 if an address was found, non-zero otherwise.
1135
1136 @see ats_ip_pton
1137 @see getaddrinfo
1138 */
1139
1140 int ats_ip_getbestaddrinfo(const char *name, ///< [in] Address name (IPv4, IPv6, or host name)
1141 IpEndpoint *ip4, ///< [out] Storage for IPv4 address.
1142 IpEndpoint *ip6 ///< [out] Storage for IPv6 address
1143 );
1144
1145 /** Generic IP address hash function.
1146 */
1147 uint32_t ats_ip_hash(sockaddr const *addr);
1148
1149 uint64_t ats_ip_port_hash(sockaddr const *addr);
1150
1151 /** Convert address to string as a hexadecimal value.
1152 The string is always nul terminated, the output string is clipped
1153 if @a dst is insufficient.
1154 @return The length of the resulting string (not including nul).
1155 */
1156 int ats_ip_to_hex(sockaddr const *addr, ///< Address to convert. Must be IP.
1157 char *dst, ///< Destination buffer.
1158 size_t len ///< Length of @a dst.
1159 );
1160
1161 /** Storage for an IP address.
1162 In some cases we want to store just the address and not the
1163 ancillary information (such as port, or flow data).
1164 @note This is not easily used as an address for system calls.
1165 */
1166 struct IpAddr {
1167 typedef IpAddr self; ///< Self reference type.
1168
1169 /// Default construct (invalid address).
IpAddrIpAddr1170 IpAddr() {}
1171
1172 /** Construct from IPv4 address.
1173 *
1174 * @param addr Source address.
1175 */
IpAddrIpAddr1176 explicit constexpr IpAddr(in_addr_t addr) : _family(AF_INET), _addr(addr) {}
1177
1178 /** Construct from IPv6 address.
1179 *
1180 * @param addr Source address.
1181 */
IpAddrIpAddr1182 explicit constexpr IpAddr(in6_addr const &addr) : _family(AF_INET6), _addr(addr) {}
1183
1184 /// Construct from @c sockaddr.
IpAddrIpAddr1185 explicit IpAddr(sockaddr const *addr) { this->assign(addr); }
1186 /// Construct from @c sockaddr_in6.
IpAddrIpAddr1187 explicit IpAddr(sockaddr_in6 const &addr) { this->assign(ats_ip_sa_cast(&addr)); }
1188 /// Construct from @c sockaddr_in6.
IpAddrIpAddr1189 explicit IpAddr(sockaddr_in6 const *addr) { this->assign(ats_ip_sa_cast(addr)); }
1190 /// Construct from @c IpEndpoint.
IpAddrIpAddr1191 explicit IpAddr(IpEndpoint const &addr) { this->assign(&addr.sa); }
1192 /// Construct from @c IpEndpoint.
IpAddrIpAddr1193 explicit IpAddr(IpEndpoint const *addr) { this->assign(&addr->sa); }
1194 /// Assign sockaddr storage.
1195 self &assign(sockaddr const *addr ///< May be @c nullptr
1196 );
1197
1198 /// Assign from end point.
1199 self &
1200 operator=(IpEndpoint const &ip)
1201 {
1202 return this->assign(&ip.sa);
1203 }
1204 /// Assign from IPv4 raw address.
1205 /// @param ip Network order IPv4 address.
1206 self &operator=(in_addr_t ip);
1207
1208 /// Assign from IPv6 raw address.
1209 self &operator=(in6_addr const &ip);
1210
1211 /** Load from string.
1212 The address is copied to this object if the conversion is successful,
1213 otherwise this object is invalidated.
1214 @return 0 on success, non-zero on failure.
1215 */
1216 int load(const char *str ///< Nul terminated input string.
1217 );
1218
1219 /** Load from string.
1220 The address is copied to this object if the conversion is successful,
1221 otherwise this object is invalidated.
1222 @return 0 on success, non-zero on failure.
1223 */
1224 int load(std::string_view const &str ///< Text of IP address.
1225 );
1226
1227 /** Output to a string.
1228 @return The string @a dest.
1229 */
1230 char *toString(char *dest, ///< [out] Destination string buffer.
1231 size_t len ///< [in] Size of buffer.
1232 ) const;
1233
1234 /// Equality.
1235 bool
1236 operator==(self const &that) const
1237 {
1238 return _family == AF_INET ?
1239 (that._family == AF_INET && _addr._ip4 == that._addr._ip4) :
1240 _family == AF_INET6 ? (that._family == AF_INET6 && 0 == memcmp(&_addr._ip6, &that._addr._ip6, TS_IP6_SIZE)) :
1241 (_family == AF_UNSPEC && that._family == AF_UNSPEC);
1242 }
1243
1244 /// Inequality.
1245 bool
1246 operator!=(self const &that) const
1247 {
1248 return !(*this == that);
1249 }
1250
1251 /// Generic compare.
1252 int cmp(self const &that) const;
1253
1254 /** Return a normalized hash value.
1255 - Ipv4: the address in host order.
1256 - Ipv6: folded 32 bit of the address.
1257 - Else: 0.
1258 */
1259 uint32_t hash() const;
1260
1261 /** The hashing function embedded in a functor.
1262 @see hash
1263 */
1264 struct Hasher {
1265 uint32_t
operatorIpAddr::Hasher1266 operator()(self const &ip) const
1267 {
1268 return ip.hash();
1269 }
1270 };
1271
1272 /// Test for same address family.
1273 /// @c return @c true if @a that is the same address family as @a this.
1274 bool isCompatibleWith(self const &that);
1275
1276 /// Get the address family.
1277 /// @return The address family.
1278 uint16_t family() const;
1279 /// Test for IPv4.
1280 bool isIp4() const;
1281 /// Test for IPv6.
1282 bool isIp6() const;
1283
1284 /// Test for validity.
1285 bool
isValidIpAddr1286 isValid() const
1287 {
1288 return _family == AF_INET || _family == AF_INET6;
1289 }
1290 /// Make invalid.
1291 self &
invalidateIpAddr1292 invalidate()
1293 {
1294 _family = AF_UNSPEC;
1295 return *this;
1296 }
1297 /// Test for multicast
1298 bool isMulticast() const;
1299 /// Test for loopback
1300 bool isLoopback() const;
1301
1302 /// Test for any addr
1303 bool isAnyAddr() const;
1304
1305 uint16_t _family = AF_UNSPEC; ///< Protocol family.
1306 /// Address data.
1307 union Addr {
1308 in_addr_t _ip4; ///< IPv4 address storage.
1309 in6_addr _ip6; ///< IPv6 address storage.
1310 uint8_t _byte[TS_IP6_SIZE]; ///< As raw bytes.
1311 uint32_t _u32[TS_IP6_SIZE / (sizeof(uint32_t) / sizeof(uint8_t))]; ///< As 32 bit chunks.
1312 uint64_t _u64[TS_IP6_SIZE / (sizeof(uint64_t) / sizeof(uint8_t))]; ///< As 64 bit chunks.
1313
1314 // This is required by the @c constexpr constructor.
Addr()1315 constexpr Addr() : _ip4(0) {}
Addr(in_addr_t addr)1316 constexpr Addr(in_addr_t addr) : _ip4(addr) {}
Addr(in6_addr const & addr)1317 constexpr Addr(in6_addr const &addr) : _ip6(addr) {}
1318 } _addr;
1319
1320 ///< Pre-constructed invalid instance.
1321 static self const INVALID;
1322 };
1323
1324 inline IpAddr &
1325 IpAddr::operator=(in_addr_t ip)
1326 {
1327 _family = AF_INET;
1328 _addr._ip4 = ip;
1329 return *this;
1330 }
1331
1332 inline IpAddr &
1333 IpAddr::operator=(in6_addr const &ip)
1334 {
1335 _family = AF_INET6;
1336 _addr._ip6 = ip;
1337 return *this;
1338 }
1339
1340 inline uint16_t
family()1341 IpAddr::family() const
1342 {
1343 return _family;
1344 }
1345
1346 inline bool
isCompatibleWith(self const & that)1347 IpAddr::isCompatibleWith(self const &that)
1348 {
1349 return this->isValid() && _family == that._family;
1350 }
1351
1352 inline bool
isIp4()1353 IpAddr::isIp4() const
1354 {
1355 return AF_INET == _family;
1356 }
1357 inline bool
isIp6()1358 IpAddr::isIp6() const
1359 {
1360 return AF_INET6 == _family;
1361 }
1362
1363 inline bool
isLoopback()1364 IpAddr::isLoopback() const
1365 {
1366 return (AF_INET == _family && 0x7F == _addr._byte[0]) || (AF_INET6 == _family && IN6_IS_ADDR_LOOPBACK(&_addr._ip6));
1367 }
1368
1369 inline bool
isAnyAddr()1370 IpAddr::isAnyAddr() const
1371 {
1372 return (AF_INET == _family && INADDR_ANY == _addr._ip4) || (AF_INET6 == _family && IN6_IS_ADDR_UNSPECIFIED(&_addr._ip6));
1373 }
1374
1375 /// Assign sockaddr storage.
1376 inline IpAddr &
assign(sockaddr const * addr)1377 IpAddr::assign(sockaddr const *addr)
1378 {
1379 if (addr) {
1380 _family = addr->sa_family;
1381 if (ats_is_ip4(addr)) {
1382 _addr._ip4 = ats_ip4_addr_cast(addr);
1383 } else if (ats_is_ip6(addr)) {
1384 _addr._ip6 = ats_ip6_addr_cast(addr);
1385 } else {
1386 _family = AF_UNSPEC;
1387 }
1388 } else {
1389 _family = AF_UNSPEC;
1390 }
1391 return *this;
1392 }
1393
1394 // Associated operators.
1395 bool operator==(IpAddr const &lhs, sockaddr const *rhs);
1396 inline bool
1397 operator==(sockaddr const *lhs, IpAddr const &rhs)
1398 {
1399 return rhs == lhs;
1400 }
1401 inline bool
1402 operator!=(IpAddr const &lhs, sockaddr const *rhs)
1403 {
1404 return !(lhs == rhs);
1405 }
1406 inline bool
1407 operator!=(sockaddr const *lhs, IpAddr const &rhs)
1408 {
1409 return !(rhs == lhs);
1410 }
1411 inline bool
1412 operator==(IpAddr const &lhs, IpEndpoint const &rhs)
1413 {
1414 return lhs == &rhs.sa;
1415 }
1416 inline bool
1417 operator==(IpEndpoint const &lhs, IpAddr const &rhs)
1418 {
1419 return &lhs.sa == rhs;
1420 }
1421 inline bool
1422 operator!=(IpAddr const &lhs, IpEndpoint const &rhs)
1423 {
1424 return !(lhs == &rhs.sa);
1425 }
1426 inline bool
1427 operator!=(IpEndpoint const &lhs, IpAddr const &rhs)
1428 {
1429 return !(rhs == &lhs.sa);
1430 }
1431
1432 inline bool
1433 operator<(IpAddr const &lhs, IpAddr const &rhs)
1434 {
1435 return -1 == lhs.cmp(rhs);
1436 }
1437
1438 inline bool
1439 operator>=(IpAddr const &lhs, IpAddr const &rhs)
1440 {
1441 return lhs.cmp(rhs) >= 0;
1442 }
1443
1444 inline bool
1445 operator>(IpAddr const &lhs, IpAddr const &rhs)
1446 {
1447 return 1 == lhs.cmp(rhs);
1448 }
1449
1450 inline bool
1451 operator<=(IpAddr const &lhs, IpAddr const &rhs)
1452 {
1453 return lhs.cmp(rhs) <= 0;
1454 }
1455
1456 inline uint32_t
hash()1457 IpAddr::hash() const
1458 {
1459 uint32_t zret = 0;
1460 if (this->isIp4()) {
1461 zret = ntohl(_addr._ip4);
1462 } else if (this->isIp6()) {
1463 zret = _addr._u32[0] ^ _addr._u32[1] ^ _addr._u32[2] ^ _addr._u32[3];
1464 }
1465 return zret;
1466 }
1467
1468 /// Write IP @a addr to storage @a dst.
1469 /// @return @s dst.
1470 sockaddr *ats_ip_set(sockaddr *dst, ///< Destination storage.
1471 IpAddr const &addr, ///< source address.
1472 in_port_t port = 0 ///< port, network order.
1473 );
1474
1475 /** Convert @a text to an IP address and write it to @a addr.
1476 Convenience overload.
1477 @return 0 on success, non-zero on failure.
1478 */
1479 inline int
ats_ip_pton(const char * text,IpAddr & addr)1480 ats_ip_pton(const char *text, ///< [in] text.
1481 IpAddr &addr ///< [out] address
1482 )
1483 {
1484 return addr.load(text) ? 0 : -1;
1485 }
1486
1487 int ats_ip_range_parse(std::string_view src, IpAddr &lower, IpAddr &upper);
1488
1489 inline IpEndpoint &
assign(IpAddr const & addr,in_port_t port)1490 IpEndpoint::assign(IpAddr const &addr, in_port_t port)
1491 {
1492 ats_ip_set(&sa, addr, port);
1493 return *this;
1494 }
1495
1496 inline IpEndpoint &
assign(sockaddr const * ip)1497 IpEndpoint::assign(sockaddr const *ip)
1498 {
1499 ats_ip_copy(&sa, ip);
1500 return *this;
1501 }
1502
1503 inline in_port_t &
port()1504 IpEndpoint::port()
1505 {
1506 return ats_ip_port_cast(&sa);
1507 }
1508
1509 inline in_port_t
port()1510 IpEndpoint::port() const
1511 {
1512 return ats_ip_port_cast(&sa);
1513 }
1514
1515 inline in_port_t
host_order_port()1516 IpEndpoint::host_order_port() const
1517 {
1518 return ntohs(this->port());
1519 }
1520
1521 inline bool
isValid()1522 IpEndpoint::isValid() const
1523 {
1524 return ats_is_ip(this);
1525 }
1526
1527 inline bool
isIp4()1528 IpEndpoint::isIp4() const
1529 {
1530 return AF_INET == sa.sa_family;
1531 }
1532 inline bool
isIp6()1533 IpEndpoint::isIp6() const
1534 {
1535 return AF_INET6 == sa.sa_family;
1536 }
1537 inline uint16_t
family()1538 IpEndpoint::family() const
1539 {
1540 return sa.sa_family;
1541 }
1542
1543 inline IpEndpoint &
setToAnyAddr(int family)1544 IpEndpoint::setToAnyAddr(int family)
1545 {
1546 ink_zero(*this);
1547 sa.sa_family = family;
1548 if (AF_INET == family) {
1549 sin.sin_addr.s_addr = INADDR_ANY;
1550 #if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
1551 sin.sin_len = sizeof(sockaddr_in);
1552 #endif
1553 } else if (AF_INET6 == family) {
1554 sin6.sin6_addr = in6addr_any;
1555 #if HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
1556 sin6.sin6_len = sizeof(sockaddr_in6);
1557 #endif
1558 }
1559 return *this;
1560 }
1561
1562 inline IpEndpoint &
setToLoopback(int family)1563 IpEndpoint::setToLoopback(int family)
1564 {
1565 ink_zero(*this);
1566 sa.sa_family = family;
1567 if (AF_INET == family) {
1568 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1569 #if HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
1570 sin.sin_len = sizeof(sockaddr_in);
1571 #endif
1572 } else if (AF_INET6 == family) {
1573 static const struct in6_addr init = IN6ADDR_LOOPBACK_INIT;
1574 sin6.sin6_addr = init;
1575 #if HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN
1576 sin6.sin6_len = sizeof(sockaddr_in6);
1577 #endif
1578 }
1579 return *this;
1580 }
1581
1582 // BufferWriter formatting support.
1583 namespace ts
1584 {
1585 BufferWriter &bwformat(BufferWriter &w, BWFSpec const &spec, IpAddr const &addr);
1586 BufferWriter &bwformat(BufferWriter &w, BWFSpec const &spec, sockaddr const *addr);
1587 inline BufferWriter &
bwformat(BufferWriter & w,BWFSpec const & spec,IpEndpoint const & addr)1588 bwformat(BufferWriter &w, BWFSpec const &spec, IpEndpoint const &addr)
1589 {
1590 return bwformat(w, spec, &addr.sa);
1591 }
1592
1593 namespace bwf
1594 {
1595 namespace detail
1596 {
1597 struct MemDump;
1598 } // namespace detail
1599
1600 detail::MemDump Hex_Dump(IpEndpoint const &addr);
1601 } // namespace bwf
1602 } // namespace ts
1603