back to topotato report
topotato coverage report
Current view: top level - lib - sockunion.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 158 374 42.2 %
Date: 2023-11-16 17:19:14 Functions: 25 77 32.5 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /* Socket union related function.
       3             :  * Copyright (c) 1997, 98 Kunihiro Ishiguro
       4             :  */
       5             : 
       6             : #include <zebra.h>
       7             : 
       8             : #include "prefix.h"
       9             : #include "vty.h"
      10             : #include "sockunion.h"
      11             : #include "memory.h"
      12             : #include "log.h"
      13             : #include "jhash.h"
      14             : #include "lib_errors.h"
      15             : #include "printfrr.h"
      16             : 
      17          12 : DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union");
      18             : 
      19           0 : const char *inet_sutop(const union sockunion *su, char *str)
      20             : {
      21           0 :         switch (su->sa.sa_family) {
      22           0 :         case AF_INET:
      23           0 :                 inet_ntop(AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN);
      24           0 :                 break;
      25           0 :         case AF_INET6:
      26           0 :                 inet_ntop(AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN);
      27           0 :                 break;
      28             :         }
      29           0 :         return str;
      30             : }
      31             : 
      32          20 : int str2sockunion(const char *str, union sockunion *su)
      33             : {
      34          20 :         int ret;
      35             : 
      36          20 :         if (str == NULL)
      37             :                 return -1;
      38             : 
      39          20 :         memset(su, 0, sizeof(union sockunion));
      40             : 
      41          20 :         ret = inet_pton(AF_INET, str, &su->sin.sin_addr);
      42          20 :         if (ret > 0) /* Valid IPv4 address format. */
      43             :         {
      44           0 :                 su->sin.sin_family = AF_INET;
      45             : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
      46             :                 su->sin.sin_len = sizeof(struct sockaddr_in);
      47             : #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
      48           0 :                 return 0;
      49             :         }
      50          20 :         ret = inet_pton(AF_INET6, str, &su->sin6.sin6_addr);
      51          20 :         if (ret > 0) /* Valid IPv6 address format. */
      52             :         {
      53          20 :                 su->sin6.sin6_family = AF_INET6;
      54             : #ifdef SIN6_LEN
      55             :                 su->sin6.sin6_len = sizeof(struct sockaddr_in6);
      56             : #endif /* SIN6_LEN */
      57          20 :                 return 0;
      58             :         }
      59             :         return -1;
      60             : }
      61             : 
      62           6 : const char *sockunion2str(const union sockunion *su, char *buf, size_t len)
      63             : {
      64           6 :         switch (sockunion_family(su)) {
      65           0 :         case AF_UNSPEC:
      66           0 :                 snprintf(buf, len, "(unspec)");
      67           0 :                 return buf;
      68           0 :         case AF_INET:
      69           0 :                 return inet_ntop(AF_INET, &su->sin.sin_addr, buf, len);
      70           6 :         case AF_INET6:
      71           6 :                 return inet_ntop(AF_INET6, &su->sin6.sin6_addr, buf, len);
      72             :         }
      73           0 :         snprintf(buf, len, "(af %d)", sockunion_family(su));
      74           0 :         return buf;
      75             : }
      76             : 
      77           0 : union sockunion *sockunion_str2su(const char *str)
      78             : {
      79           0 :         union sockunion *su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
      80             : 
      81           0 :         if (!str2sockunion(str, su))
      82             :                 return su;
      83             : 
      84           0 :         XFREE(MTYPE_SOCKUNION, su);
      85           0 :         return NULL;
      86             : }
      87             : 
      88             : /* Convert IPv4 compatible IPv6 address to IPv4 address. */
      89          22 : static void sockunion_normalise_mapped(union sockunion *su)
      90             : {
      91          22 :         struct sockaddr_in sin;
      92             : 
      93          22 :         if (su->sa.sa_family == AF_INET6
      94          22 :             && IN6_IS_ADDR_V4MAPPED(&su->sin6.sin6_addr)) {
      95           0 :                 memset(&sin, 0, sizeof(sin));
      96           0 :                 sin.sin_family = AF_INET;
      97           0 :                 sin.sin_port = su->sin6.sin6_port;
      98           0 :                 memcpy(&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
      99           0 :                 memcpy(su, &sin, sizeof(struct sockaddr_in));
     100             :         }
     101          22 : }
     102             : 
     103             : /* return sockunion structure : this function should be revised. */
     104           0 : static const char *sockunion_log(const union sockunion *su, char *buf,
     105             :                                  size_t len)
     106             : {
     107           0 :         switch (su->sa.sa_family) {
     108           0 :         case AF_INET:
     109           0 :                 return inet_ntop(AF_INET, &su->sin.sin_addr, buf, len);
     110             : 
     111           0 :         case AF_INET6:
     112           0 :                 return inet_ntop(AF_INET6, &(su->sin6.sin6_addr), buf, len);
     113             : 
     114           0 :         default:
     115           0 :                 snprintf(buf, len, "af_unknown %d ", su->sa.sa_family);
     116           0 :                 return buf;
     117             :         }
     118             : }
     119             : 
     120             : /* Return socket of sockunion. */
     121           2 : int sockunion_socket(const union sockunion *su)
     122             : {
     123           2 :         int sock;
     124             : 
     125           2 :         sock = socket(su->sa.sa_family, SOCK_STREAM, 0);
     126           2 :         if (sock < 0) {
     127           0 :                 char buf[SU_ADDRSTRLEN];
     128           0 :                 flog_err(EC_LIB_SOCKET, "Can't make socket for %s : %s",
     129             :                          sockunion_log(su, buf, SU_ADDRSTRLEN),
     130             :                          safe_strerror(errno));
     131           0 :                 return -1;
     132             :         }
     133             : 
     134             :         return sock;
     135             : }
     136             : 
     137             : /* Return accepted new socket file descriptor. */
     138           2 : int sockunion_accept(int sock, union sockunion *su)
     139             : {
     140           2 :         socklen_t len;
     141           2 :         int client_sock;
     142             : 
     143           2 :         len = sizeof(union sockunion);
     144           2 :         client_sock = accept(sock, (struct sockaddr *)su, &len);
     145             : 
     146           2 :         sockunion_normalise_mapped(su);
     147           2 :         return client_sock;
     148             : }
     149             : 
     150             : /* Return sizeof union sockunion.  */
     151           2 : int sockunion_sizeof(const union sockunion *su)
     152             : {
     153           2 :         int ret;
     154             : 
     155           2 :         ret = 0;
     156           2 :         switch (su->sa.sa_family) {
     157           0 :         case AF_INET:
     158           0 :                 ret = sizeof(struct sockaddr_in);
     159           0 :                 break;
     160           2 :         case AF_INET6:
     161           2 :                 ret = sizeof(struct sockaddr_in6);
     162           2 :                 break;
     163             :         }
     164           2 :         return ret;
     165             : }
     166             : 
     167             : /* Performs a non-blocking connect().  */
     168           2 : enum connect_result sockunion_connect(int fd, const union sockunion *peersu,
     169             :                                       unsigned short port, ifindex_t ifindex)
     170             : {
     171           2 :         int ret;
     172           2 :         union sockunion su;
     173             : 
     174           2 :         memcpy(&su, peersu, sizeof(union sockunion));
     175             : 
     176           2 :         switch (su.sa.sa_family) {
     177           0 :         case AF_INET:
     178           0 :                 su.sin.sin_port = port;
     179           0 :                 break;
     180           2 :         case AF_INET6:
     181           2 :                 su.sin6.sin6_port = port;
     182             : #ifdef KAME
     183             :                 if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex) {
     184             :                         su.sin6.sin6_scope_id = ifindex;
     185             :                         SET_IN6_LINKLOCAL_IFINDEX(su.sin6.sin6_addr, ifindex);
     186             :                 }
     187             : #endif /* KAME */
     188           2 :                 break;
     189             :         }
     190             : 
     191             :         /* Call connect function. */
     192           2 :         ret = connect(fd, (struct sockaddr *)&su, sockunion_sizeof(&su));
     193             : 
     194             :         /* Immediate success */
     195           2 :         if (ret == 0)
     196             :                 return connect_success;
     197             : 
     198             :         /* If connect is in progress then return 1 else it's real error. */
     199           2 :         if (ret < 0) {
     200           2 :                 if (errno != EINPROGRESS) {
     201           0 :                         char str[SU_ADDRSTRLEN];
     202           0 :                         zlog_info("can't connect to %s fd %d : %s",
     203             :                                   sockunion_log(&su, str, sizeof(str)), fd,
     204             :                                   safe_strerror(errno));
     205           0 :                         return connect_error;
     206             :                 }
     207             :         }
     208             : 
     209             :         return connect_in_progress;
     210             : }
     211             : 
     212             : /* Make socket from sockunion union. */
     213           0 : int sockunion_stream_socket(union sockunion *su)
     214             : {
     215           0 :         int sock;
     216             : 
     217           0 :         if (su->sa.sa_family == 0)
     218           0 :                 su->sa.sa_family = AF_INET_UNION;
     219             : 
     220           0 :         sock = socket(su->sa.sa_family, SOCK_STREAM, 0);
     221             : 
     222           0 :         if (sock < 0)
     223           0 :                 flog_err(EC_LIB_SOCKET,
     224             :                          "can't make socket sockunion_stream_socket");
     225             : 
     226           0 :         return sock;
     227             : }
     228             : 
     229             : /* Bind socket to specified address. */
     230           0 : int sockunion_bind(int sock, union sockunion *su, unsigned short port,
     231             :                    union sockunion *su_addr)
     232             : {
     233           0 :         int size = 0;
     234           0 :         int ret;
     235             : 
     236           0 :         if (su->sa.sa_family == AF_INET) {
     237           0 :                 size = sizeof(struct sockaddr_in);
     238           0 :                 su->sin.sin_port = htons(port);
     239             : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
     240             :                 su->sin.sin_len = size;
     241             : #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
     242           0 :                 if (su_addr == NULL)
     243           0 :                         sockunion2ip(su) = htonl(INADDR_ANY);
     244           0 :         } else if (su->sa.sa_family == AF_INET6) {
     245           0 :                 size = sizeof(struct sockaddr_in6);
     246           0 :                 su->sin6.sin6_port = htons(port);
     247             : #ifdef SIN6_LEN
     248             :                 su->sin6.sin6_len = size;
     249             : #endif /* SIN6_LEN */
     250           0 :                 if (su_addr == NULL) {
     251             : #ifdef LINUX_IPV6
     252           0 :                         memset(&su->sin6.sin6_addr, 0, sizeof(struct in6_addr));
     253             : #else
     254             :                         su->sin6.sin6_addr = in6addr_any;
     255             : #endif /* LINUX_IPV6 */
     256             :                 }
     257             :         }
     258             : 
     259           0 :         ret = bind(sock, (struct sockaddr *)su, size);
     260           0 :         if (ret < 0) {
     261           0 :                 char buf[SU_ADDRSTRLEN];
     262           0 :                 flog_err(EC_LIB_SOCKET, "can't bind socket for %s : %s",
     263             :                          sockunion_log(su, buf, SU_ADDRSTRLEN),
     264             :                          safe_strerror(errno));
     265             :         }
     266             : 
     267           0 :         return ret;
     268             : }
     269             : 
     270          14 : int sockopt_reuseaddr(int sock)
     271             : {
     272          14 :         int ret;
     273          14 :         int on = 1;
     274             : 
     275          14 :         ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
     276             :                          sizeof(on));
     277          14 :         if (ret < 0) {
     278           0 :                 flog_err(
     279             :                         EC_LIB_SOCKET,
     280             :                         "can't set sockopt SO_REUSEADDR to socket %d errno=%d: %s",
     281             :                         sock, errno, safe_strerror(errno));
     282           0 :                 return -1;
     283             :         }
     284             :         return 0;
     285             : }
     286             : 
     287             : #ifdef SO_REUSEPORT
     288          14 : int sockopt_reuseport(int sock)
     289             : {
     290          14 :         int ret;
     291          14 :         int on = 1;
     292             : 
     293          14 :         ret = setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *)&on,
     294             :                          sizeof(on));
     295          14 :         if (ret < 0) {
     296           0 :                 flog_err(EC_LIB_SOCKET,
     297             :                          "can't set sockopt SO_REUSEPORT to socket %d", sock);
     298           0 :                 return -1;
     299             :         }
     300             :         return 0;
     301             : }
     302             : #else
     303             : int sockopt_reuseport(int sock)
     304             : {
     305             :         return 0;
     306             : }
     307             : #endif /* 0 */
     308             : 
     309           8 : int sockopt_ttl(int family, int sock, int ttl)
     310             : {
     311           8 :         int ret;
     312             : 
     313             : #ifdef IP_TTL
     314           8 :         if (family == AF_INET) {
     315           2 :                 ret = setsockopt(sock, IPPROTO_IP, IP_TTL, (void *)&ttl,
     316             :                                  sizeof(int));
     317           2 :                 if (ret < 0) {
     318           0 :                         flog_err(EC_LIB_SOCKET,
     319             :                                  "can't set sockopt IP_TTL %d to socket %d",
     320             :                                  ttl, sock);
     321           0 :                         return -1;
     322             :                 }
     323             :                 return 0;
     324             :         }
     325             : #endif /* IP_TTL */
     326           6 :         if (family == AF_INET6) {
     327           6 :                 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
     328             :                                  (void *)&ttl, sizeof(int));
     329           6 :                 if (ret < 0) {
     330           0 :                         flog_err(
     331             :                                 EC_LIB_SOCKET,
     332             :                                 "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
     333             :                                 ttl, sock);
     334           0 :                         return -1;
     335             :                 }
     336             :                 return 0;
     337             :         }
     338             :         return 0;
     339             : }
     340             : 
     341           0 : int sockopt_minttl(int family, int sock, int minttl)
     342             : {
     343             : #ifdef IP_MINTTL
     344           0 :         if (family == AF_INET) {
     345           0 :                 int ret = setsockopt(sock, IPPROTO_IP, IP_MINTTL, &minttl,
     346             :                                      sizeof(minttl));
     347           0 :                 if (ret < 0)
     348           0 :                         flog_err(
     349             :                                 EC_LIB_SOCKET,
     350             :                                 "can't set sockopt IP_MINTTL to %d on socket %d: %s",
     351             :                                 minttl, sock, safe_strerror(errno));
     352           0 :                 return ret;
     353             :         }
     354             : #endif /* IP_MINTTL */
     355             : #ifdef IPV6_MINHOPCOUNT
     356           0 :         if (family == AF_INET6) {
     357           0 :                 int ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
     358             :                                      &minttl, sizeof(minttl));
     359           0 :                 if (ret < 0)
     360           0 :                         flog_err(
     361             :                                 EC_LIB_SOCKET,
     362             :                                 "can't set sockopt IPV6_MINHOPCOUNT to %d on socket %d: %s",
     363             :                                 minttl, sock, safe_strerror(errno));
     364           0 :                 return ret;
     365             :         }
     366             : #endif
     367             : 
     368           0 :         errno = EOPNOTSUPP;
     369           0 :         return -1;
     370             : }
     371             : 
     372          12 : int sockopt_v6only(int family, int sock)
     373             : {
     374          12 :         int ret, on = 1;
     375             : 
     376             : #ifdef IPV6_V6ONLY
     377          12 :         if (family == AF_INET6) {
     378           6 :                 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on,
     379             :                                  sizeof(int));
     380           6 :                 if (ret < 0) {
     381           0 :                         flog_err(EC_LIB_SOCKET,
     382             :                                  "can't set sockopt IPV6_V6ONLY to socket %d",
     383             :                                  sock);
     384           0 :                         return -1;
     385             :                 }
     386             :                 return 0;
     387             :         }
     388             : #endif /* IPV6_V6ONLY */
     389             :         return 0;
     390             : }
     391             : 
     392             : /* If same family and same prefix return 1. */
     393          26 : int sockunion_same(const union sockunion *su1, const union sockunion *su2)
     394             : {
     395          26 :         int ret = 0;
     396             : 
     397          26 :         if (su1->sa.sa_family != su2->sa.sa_family)
     398             :                 return 0;
     399             : 
     400          26 :         switch (su1->sa.sa_family) {
     401           0 :         case AF_INET:
     402           0 :                 ret = memcmp(&su1->sin.sin_addr, &su2->sin.sin_addr,
     403             :                              sizeof(struct in_addr));
     404           0 :                 break;
     405          26 :         case AF_INET6:
     406          26 :                 ret = memcmp(&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
     407             :                              sizeof(struct in6_addr));
     408          26 :                 if ((ret == 0) && IN6_IS_ADDR_LINKLOCAL(&su1->sin6.sin6_addr)) {
     409             :                         /* compare interface indices */
     410          26 :                         if (su1->sin6.sin6_scope_id && su2->sin6.sin6_scope_id)
     411           4 :                                 ret = (su1->sin6.sin6_scope_id
     412             :                                        == su2->sin6.sin6_scope_id)
     413             :                                               ? 0
     414           4 :                                               : 1;
     415             :                 }
     416             :                 break;
     417             :         }
     418          26 :         if (ret == 0)
     419             :                 return 1;
     420             :         else
     421           0 :                 return 0;
     422             : }
     423             : 
     424          38 : unsigned int sockunion_hash(const union sockunion *su)
     425             : {
     426          38 :         switch (sockunion_family(su)) {
     427           0 :         case AF_INET:
     428           0 :                 return jhash_1word(su->sin.sin_addr.s_addr, 0);
     429          38 :         case AF_INET6:
     430          38 :                 return jhash2(su->sin6.sin6_addr.s6_addr32,
     431             :                               array_size(su->sin6.sin6_addr.s6_addr32), 0);
     432             :         }
     433             :         return 0;
     434             : }
     435             : 
     436           0 : size_t family2addrsize(int family)
     437             : {
     438           0 :         switch (family) {
     439             :         case AF_INET:
     440             :                 return sizeof(struct in_addr);
     441           0 :         case AF_INET6:
     442           0 :                 return sizeof(struct in6_addr);
     443             :         }
     444           0 :         return 0;
     445             : }
     446             : 
     447           0 : size_t sockunion_get_addrlen(const union sockunion *su)
     448             : {
     449           0 :         return family2addrsize(sockunion_family(su));
     450             : }
     451             : 
     452           0 : const uint8_t *sockunion_get_addr(const union sockunion *su)
     453             : {
     454           0 :         switch (sockunion_family(su)) {
     455           0 :         case AF_INET:
     456           0 :                 return (const uint8_t *)&su->sin.sin_addr.s_addr;
     457           0 :         case AF_INET6:
     458           0 :                 return (const uint8_t *)&su->sin6.sin6_addr;
     459             :         }
     460             :         return NULL;
     461             : }
     462             : 
     463           0 : void sockunion_set(union sockunion *su, int family, const uint8_t *addr,
     464             :                    size_t bytes)
     465             : {
     466           0 :         if (family2addrsize(family) != bytes)
     467             :                 return;
     468             : 
     469           0 :         sockunion_family(su) = family;
     470           0 :         switch (family) {
     471           0 :         case AF_INET:
     472           0 :                 memcpy(&su->sin.sin_addr.s_addr, addr, bytes);
     473           0 :                 break;
     474           0 :         case AF_INET6:
     475           0 :                 memcpy(&su->sin6.sin6_addr, addr, bytes);
     476           0 :                 break;
     477             :         }
     478             : }
     479             : 
     480             : /* After TCP connection is established.  Get local address and port. */
     481          10 : union sockunion *sockunion_getsockname(int fd)
     482             : {
     483          10 :         int ret;
     484          10 :         socklen_t len;
     485          10 :         union {
     486             :                 struct sockaddr sa;
     487             :                 struct sockaddr_in sin;
     488             :                 struct sockaddr_in6 sin6;
     489             :                 char tmp_buffer[128];
     490             :         } name;
     491          10 :         union sockunion *su;
     492             : 
     493          10 :         memset(&name, 0, sizeof(name));
     494          10 :         len = sizeof(name);
     495             : 
     496          10 :         ret = getsockname(fd, (struct sockaddr *)&name, &len);
     497          10 :         if (ret < 0) {
     498           0 :                 flog_err(EC_LIB_SOCKET,
     499             :                          "Can't get local address and port by getsockname: %s",
     500             :                          safe_strerror(errno));
     501           0 :                 return NULL;
     502             :         }
     503             : 
     504          10 :         if (name.sa.sa_family == AF_INET) {
     505           0 :                 su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
     506           0 :                 memcpy(su, &name, sizeof(struct sockaddr_in));
     507           0 :                 return su;
     508             :         }
     509          10 :         if (name.sa.sa_family == AF_INET6) {
     510          10 :                 su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
     511          10 :                 memcpy(su, &name, sizeof(struct sockaddr_in6));
     512          10 :                 sockunion_normalise_mapped(su);
     513          10 :                 return su;
     514             :         }
     515             : 
     516           0 :         flog_err(
     517             :                 EC_LIB_SOCKET,
     518             :                 "Unexpected AFI received(%d) for sockunion_getsockname call for fd: %d",
     519             :                 name.sa.sa_family, fd);
     520           0 :         return NULL;
     521             : }
     522             : 
     523             : /* After TCP connection is established.  Get remote address and port. */
     524          10 : union sockunion *sockunion_getpeername(int fd)
     525             : {
     526          10 :         int ret;
     527          10 :         socklen_t len;
     528          10 :         union {
     529             :                 struct sockaddr sa;
     530             :                 struct sockaddr_in sin;
     531             :                 struct sockaddr_in6 sin6;
     532             :                 char tmp_buffer[128];
     533             :         } name;
     534          10 :         union sockunion *su;
     535             : 
     536          10 :         memset(&name, 0, sizeof(name));
     537          10 :         len = sizeof(name);
     538          10 :         ret = getpeername(fd, (struct sockaddr *)&name, &len);
     539          10 :         if (ret < 0) {
     540           0 :                 flog_err(EC_LIB_SOCKET, "Can't get remote address and port: %s",
     541             :                          safe_strerror(errno));
     542           0 :                 return NULL;
     543             :         }
     544             : 
     545          10 :         if (name.sa.sa_family == AF_INET) {
     546           0 :                 su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
     547           0 :                 memcpy(su, &name, sizeof(struct sockaddr_in));
     548           0 :                 return su;
     549             :         }
     550          10 :         if (name.sa.sa_family == AF_INET6) {
     551          10 :                 su = XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
     552          10 :                 memcpy(su, &name, sizeof(struct sockaddr_in6));
     553          10 :                 sockunion_normalise_mapped(su);
     554          10 :                 return su;
     555             :         }
     556             : 
     557           0 :         flog_err(
     558             :                 EC_LIB_SOCKET,
     559             :                 "Unexpected AFI received(%d) for sockunion_getpeername call for fd: %d",
     560             :                 name.sa.sa_family, fd);
     561           0 :         return NULL;
     562             : }
     563             : 
     564             : /* Print sockunion structure */
     565             : static void __attribute__((unused)) sockunion_print(const union sockunion *su)
     566             : {
     567             :         if (su == NULL)
     568             :                 return;
     569             : 
     570             :         switch (su->sa.sa_family) {
     571             :         case AF_INET:
     572             :                 printf("%pI4\n", &su->sin.sin_addr);
     573             :                 break;
     574             :         case AF_INET6:
     575             :                 printf("%pI6\n", &su->sin6.sin6_addr);
     576             :                 break;
     577             : #ifdef AF_LINK
     578             :         case AF_LINK: {
     579             :                 struct sockaddr_dl *sdl;
     580             : 
     581             :                 sdl = (struct sockaddr_dl *)&(su->sa);
     582             :                 printf("link#%d\n", sdl->sdl_index);
     583             :         } break;
     584             : #endif /* AF_LINK */
     585             :         default:
     586             :                 printf("af_unknown %d\n", su->sa.sa_family);
     587             :                 break;
     588             :         }
     589             : }
     590             : 
     591          11 : int in6addr_cmp(const struct in6_addr *addr1, const struct in6_addr *addr2)
     592             : {
     593          11 :         unsigned int i;
     594          11 :         const uint8_t *p1, *p2;
     595             : 
     596          11 :         p1 = (const uint8_t *)addr1;
     597          11 :         p2 = (const uint8_t *)addr2;
     598             : 
     599         169 :         for (i = 0; i < sizeof(struct in6_addr); i++) {
     600         167 :                 if (p1[i] > p2[i])
     601             :                         return 1;
     602         161 :                 else if (p1[i] < p2[i])
     603             :                         return -1;
     604             :         }
     605             :         return 0;
     606             : }
     607             : 
     608          11 : int sockunion_cmp(const union sockunion *su1, const union sockunion *su2)
     609             : {
     610          11 :         if (su1->sa.sa_family > su2->sa.sa_family)
     611             :                 return 1;
     612          11 :         if (su1->sa.sa_family < su2->sa.sa_family)
     613             :                 return -1;
     614             : 
     615          11 :         if (su1->sa.sa_family == AF_INET) {
     616           0 :                 if (ntohl(sockunion2ip(su1)) == ntohl(sockunion2ip(su2)))
     617             :                         return 0;
     618           0 :                 if (ntohl(sockunion2ip(su1)) > ntohl(sockunion2ip(su2)))
     619             :                         return 1;
     620             :                 else
     621           0 :                         return -1;
     622             :         }
     623          11 :         if (su1->sa.sa_family == AF_INET6)
     624          11 :                 return in6addr_cmp(&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
     625             :         return 0;
     626             : }
     627             : 
     628             : /* Duplicate sockunion. */
     629           0 : union sockunion *sockunion_dup(const union sockunion *su)
     630             : {
     631           0 :         union sockunion *dup =
     632           0 :                 XCALLOC(MTYPE_SOCKUNION, sizeof(union sockunion));
     633           0 :         memcpy(dup, su, sizeof(union sockunion));
     634           0 :         return dup;
     635             : }
     636             : 
     637          20 : void sockunion_free(union sockunion *su)
     638             : {
     639          20 :         XFREE(MTYPE_SOCKUNION, su);
     640          20 : }
     641             : 
     642           4 : void sockunion_init(union sockunion *su)
     643             : {
     644           4 :         memset(su, 0, sizeof(union sockunion));
     645           4 : }
     646             : 
     647           4 : printfrr_ext_autoreg_p("SU", printfrr_psu);
     648           8 : static ssize_t printfrr_psu(struct fbuf *buf, struct printfrr_eargs *ea,
     649             :                             const void *ptr)
     650             : {
     651           8 :         const union sockunion *su = ptr;
     652           8 :         bool include_port = false, include_scope = false;
     653           8 :         bool endflags = false;
     654           8 :         ssize_t ret = 0;
     655           8 :         char cbuf[INET6_ADDRSTRLEN];
     656             : 
     657           8 :         if (!su)
     658           0 :                 return bputs(buf, "(null)");
     659             : 
     660          16 :         while (!endflags) {
     661           8 :                 switch (*ea->fmt) {
     662           0 :                 case 'p':
     663           0 :                         ea->fmt++;
     664           0 :                         include_port = true;
     665           0 :                         break;
     666           0 :                 case 's':
     667           0 :                         ea->fmt++;
     668           0 :                         include_scope = true;
     669           0 :                         break;
     670             :                 default:
     671             :                         endflags = true;
     672             :                         break;
     673             :                 }
     674             :         }
     675             : 
     676           8 :         switch (sockunion_family(su)) {
     677           0 :         case AF_UNSPEC:
     678           0 :                 ret += bputs(buf, "(unspec)");
     679           0 :                 break;
     680           0 :         case AF_INET:
     681           0 :                 inet_ntop(AF_INET, &su->sin.sin_addr, cbuf, sizeof(cbuf));
     682           0 :                 ret += bputs(buf, cbuf);
     683           0 :                 if (include_port)
     684           0 :                         ret += bprintfrr(buf, ":%d", ntohs(su->sin.sin_port));
     685             :                 break;
     686           8 :         case AF_INET6:
     687           8 :                 if (include_port)
     688           0 :                         ret += bputch(buf, '[');
     689           8 :                 inet_ntop(AF_INET6, &su->sin6.sin6_addr, cbuf, sizeof(cbuf));
     690           8 :                 ret += bputs(buf, cbuf);
     691           8 :                 if (include_scope && su->sin6.sin6_scope_id)
     692           0 :                         ret += bprintfrr(buf, "%%%u",
     693             :                                          (unsigned int)su->sin6.sin6_scope_id);
     694           8 :                 if (include_port)
     695           0 :                         ret += bprintfrr(buf, "]:%d",
     696           0 :                                          ntohs(su->sin6.sin6_port));
     697             :                 break;
     698           0 :         case AF_UNIX: {
     699           0 :                 int len;
     700             : #ifdef __linux__
     701           0 :                 if (su->sun.sun_path[0] == '\0' && su->sun.sun_path[1]) {
     702           0 :                         len = strnlen(su->sun.sun_path + 1,
     703             :                                       sizeof(su->sun.sun_path) - 1);
     704           0 :                         ret += bprintfrr(buf, "@%*pSE", len,
     705             :                                          su->sun.sun_path + 1);
     706           0 :                         break;
     707             :                 }
     708             : #endif
     709           0 :                 len = strnlen(su->sun.sun_path, sizeof(su->sun.sun_path));
     710           0 :                 ret += bprintfrr(buf, "%*pSE", len, su->sun.sun_path);
     711           0 :                 break;
     712             :         }
     713           0 :         default:
     714           0 :                 ret += bprintfrr(buf, "(af %d)", sockunion_family(su));
     715             :         }
     716             : 
     717             :         return ret;
     718             : }
     719             : 
     720           0 : int sockunion_is_null(const union sockunion *su)
     721             : {
     722           0 :         unsigned char null_s6_addr[16] = {0};
     723             : 
     724           0 :         switch (sockunion_family(su)) {
     725             :         case AF_UNSPEC:
     726             :                 return 1;
     727           0 :         case AF_INET:
     728           0 :                 return (su->sin.sin_addr.s_addr == 0);
     729           0 :         case AF_INET6:
     730           0 :                 return !memcmp(su->sin6.sin6_addr.s6_addr, null_s6_addr,
     731             :                                sizeof(null_s6_addr));
     732           0 :         default:
     733           0 :                 return 0;
     734             :         }
     735             : }
     736             : 
     737           4 : printfrr_ext_autoreg_i("PF", printfrr_pf);
     738           0 : static ssize_t printfrr_pf(struct fbuf *buf, struct printfrr_eargs *ea,
     739             :                            uintmax_t val)
     740             : {
     741           0 :         switch (val) {
     742           0 :         case AF_INET:
     743           0 :                 return bputs(buf, "AF_INET");
     744           0 :         case AF_INET6:
     745           0 :                 return bputs(buf, "AF_INET6");
     746           0 :         case AF_UNIX:
     747           0 :                 return bputs(buf, "AF_UNIX");
     748             : #ifdef AF_PACKET
     749           0 :         case AF_PACKET:
     750           0 :                 return bputs(buf, "AF_PACKET");
     751             : #endif
     752             : #ifdef AF_NETLINK
     753           0 :         case AF_NETLINK:
     754           0 :                 return bputs(buf, "AF_NETLINK");
     755             : #endif
     756             :         }
     757           0 :         return bprintfrr(buf, "AF_(%ju)", val);
     758             : }
     759             : 
     760           4 : printfrr_ext_autoreg_i("SO", printfrr_so);
     761           0 : static ssize_t printfrr_so(struct fbuf *buf, struct printfrr_eargs *ea,
     762             :                            uintmax_t val)
     763             : {
     764           0 :         switch (val) {
     765           0 :         case SOCK_STREAM:
     766           0 :                 return bputs(buf, "SOCK_STREAM");
     767           0 :         case SOCK_DGRAM:
     768           0 :                 return bputs(buf, "SOCK_DGRAM");
     769           0 :         case SOCK_SEQPACKET:
     770           0 :                 return bputs(buf, "SOCK_SEQPACKET");
     771             : #ifdef SOCK_RAW
     772           0 :         case SOCK_RAW:
     773           0 :                 return bputs(buf, "SOCK_RAW");
     774             : #endif
     775             : #ifdef SOCK_PACKET
     776           0 :         case SOCK_PACKET:
     777           0 :                 return bputs(buf, "SOCK_PACKET");
     778             : #endif
     779             :         }
     780           0 :         return bprintfrr(buf, "SOCK_(%ju)", val);
     781             : }

Generated by: LCOV version v1.16-topotato