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