back to topotato report
topotato coverage report
Current view: top level - lib - sockopt.c (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 71 225 31.6 %
Date: 2023-11-16 17:19:14 Functions: 13 54 24.1 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /* setsockopt functions
       3             :  * Copyright (C) 1999 Kunihiro Ishiguro
       4             :  */
       5             : 
       6             : #include <zebra.h>
       7             : 
       8             : #include "log.h"
       9             : #include "sockopt.h"
      10             : #include "sockunion.h"
      11             : #include "lib_errors.h"
      12             : 
      13             : #if (defined(__FreeBSD__) &&                                                   \
      14             :      ((__FreeBSD_version >= 500022 && __FreeBSD_version < 700000) ||           \
      15             :       (__FreeBSD_version < 500000 && __FreeBSD_version >= 440000))) ||         \
      16             :         (defined(__NetBSD__) && defined(__NetBSD_Version__) &&                 \
      17             :          __NetBSD_Version__ >= 106010000) ||                                   \
      18             :         defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun)
      19             : #define HAVE_BSD_STRUCT_IP_MREQ_HACK
      20             : #endif
      21             : 
      22           2 : void setsockopt_so_recvbuf(int sock, int size)
      23             : {
      24           2 :         int orig_req = size;
      25             : 
      26           2 :         while (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) ==
      27             :                -1) {
      28           0 :                 if (size == 0)
      29             :                         break;
      30           0 :                 size /= 2;
      31             :         }
      32             : 
      33           2 :         if (size != orig_req)
      34           0 :                 flog_err(EC_LIB_SOCKET,
      35             :                          "%s: fd %d: SO_RCVBUF set to %d (requested %d)",
      36             :                          __func__, sock, size, orig_req);
      37           2 : }
      38             : 
      39          10 : void setsockopt_so_sendbuf(const int sock, int size)
      40             : {
      41          10 :         int orig_req = size;
      42             : 
      43          10 :         while (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) ==
      44             :                -1) {
      45           0 :                 if (size == 0)
      46             :                         break;
      47           0 :                 size /= 2;
      48             :         }
      49             : 
      50          10 :         if (size != orig_req)
      51           0 :                 flog_err(EC_LIB_SOCKET,
      52             :                          "%s: fd %d: SO_SNDBUF set to %d (requested %d)",
      53             :                          __func__, sock, size, orig_req);
      54          10 : }
      55             : 
      56           4 : int getsockopt_so_sendbuf(const int sock)
      57             : {
      58           4 :         uint32_t optval;
      59           4 :         socklen_t optlen = sizeof(optval);
      60           4 :         int ret = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&optval,
      61             :                              &optlen);
      62           4 :         if (ret < 0) {
      63           0 :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
      64             :                              "fd %d: can't getsockopt SO_SNDBUF: %d (%s)", sock,
      65             :                              errno, safe_strerror(errno));
      66           0 :                 return ret;
      67             :         }
      68           4 :         return optval;
      69             : }
      70             : 
      71           4 : int getsockopt_so_recvbuf(const int sock)
      72             : {
      73           4 :         uint32_t optval;
      74           4 :         socklen_t optlen = sizeof(optval);
      75           4 :         int ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char *)&optval,
      76             :                              &optlen);
      77           4 :         if (ret < 0) {
      78           0 :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
      79             :                              "fd %d: can't getsockopt SO_RCVBUF: %d (%s)", sock,
      80             :                              errno, safe_strerror(errno));
      81           0 :                 return ret;
      82             :         }
      83           4 :         return optval;
      84             : }
      85             : 
      86           0 : static void *getsockopt_cmsg_data(struct msghdr *msgh, int level, int type)
      87             : {
      88           0 :         struct cmsghdr *cmsg;
      89             : 
      90           0 :         for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != NULL;
      91           0 :              cmsg = CMSG_NXTHDR(msgh, cmsg))
      92           0 :                 if (cmsg->cmsg_level == level && cmsg->cmsg_type == type)
      93           0 :                         return CMSG_DATA(cmsg);
      94             : 
      95             :         return NULL;
      96             : }
      97             : 
      98             : /* Set IPv6 packet info to the socket. */
      99           2 : int setsockopt_ipv6_pktinfo(int sock, int val)
     100             : {
     101           2 :         int ret;
     102             : 
     103             : #ifdef IPV6_RECVPKTINFO /*2292bis-01*/
     104           2 :         ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val,
     105             :                          sizeof(val));
     106           2 :         if (ret < 0)
     107           0 :                 flog_err(EC_LIB_SOCKET,
     108             :                          "can't setsockopt IPV6_RECVPKTINFO : %s",
     109             :                          safe_strerror(errno));
     110             : #else  /*RFC2292*/
     111             :         ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
     112             :         if (ret < 0)
     113             :                 flog_err(EC_LIB_SOCKET, "can't setsockopt IPV6_PKTINFO : %s",
     114             :                          safe_strerror(errno));
     115             : #endif /* IANA_IPV6 */
     116           2 :         return ret;
     117             : }
     118             : 
     119             : /* Set multicast hops val to the socket. */
     120           2 : int setsockopt_ipv6_multicast_hops(int sock, int val)
     121             : {
     122           2 :         int ret;
     123             : 
     124           2 :         ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val,
     125             :                          sizeof(val));
     126           2 :         if (ret < 0)
     127           0 :                 flog_err(EC_LIB_SOCKET, "can't setsockopt IPV6_MULTICAST_HOPS");
     128           2 :         return ret;
     129             : }
     130             : 
     131             : /* Set multicast hops val to the socket. */
     132           2 : int setsockopt_ipv6_unicast_hops(int sock, int val)
     133             : {
     134           2 :         int ret;
     135             : 
     136           2 :         ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val,
     137             :                          sizeof(val));
     138           2 :         if (ret < 0)
     139           0 :                 flog_err(EC_LIB_SOCKET, "can't setsockopt IPV6_UNICAST_HOPS");
     140           2 :         return ret;
     141             : }
     142             : 
     143           2 : int setsockopt_ipv6_hoplimit(int sock, int val)
     144             : {
     145           2 :         int ret;
     146             : 
     147             : #ifdef IPV6_RECVHOPLIMIT /*2292bis-01*/
     148           2 :         ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val,
     149             :                          sizeof(val));
     150           2 :         if (ret < 0)
     151           0 :                 flog_err(EC_LIB_SOCKET, "can't setsockopt IPV6_RECVHOPLIMIT");
     152             : #else /*RFC2292*/
     153             :         ret = setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
     154             :         if (ret < 0)
     155             :                 flog_err(EC_LIB_SOCKET, "can't setsockopt IPV6_HOPLIMIT");
     156             : #endif
     157           2 :         return ret;
     158             : }
     159             : 
     160             : /* Set multicast loop zero to the socket. */
     161           2 : int setsockopt_ipv6_multicast_loop(int sock, int val)
     162             : {
     163           2 :         int ret;
     164             : 
     165           2 :         ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
     166             :                          sizeof(val));
     167           2 :         if (ret < 0)
     168           0 :                 flog_err(EC_LIB_SOCKET, "can't setsockopt IPV6_MULTICAST_LOOP");
     169           2 :         return ret;
     170             : }
     171             : 
     172           0 : static int getsockopt_ipv6_ifindex(struct msghdr *msgh)
     173             : {
     174           0 :         struct in6_pktinfo *pktinfo;
     175             : 
     176           0 :         pktinfo = getsockopt_cmsg_data(msgh, IPPROTO_IPV6, IPV6_PKTINFO);
     177             : 
     178           0 :         return pktinfo->ipi6_ifindex;
     179             : }
     180             : 
     181           4 : int setsockopt_ipv6_tclass(int sock, int tclass)
     182             : {
     183           4 :         int ret = 0;
     184             : 
     185             : #ifdef IPV6_TCLASS /* RFC3542 */
     186           4 :         ret = setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &tclass,
     187             :                          sizeof(tclass));
     188           4 :         if (ret < 0)
     189           0 :                 flog_err(EC_LIB_SOCKET,
     190             :                          "Can't set IPV6_TCLASS option for fd %d to %#x: %s",
     191             :                          sock, tclass, safe_strerror(errno));
     192             : #endif
     193           4 :         return ret;
     194             : }
     195             : 
     196             : /*
     197             :  * Process multicast socket options for IPv4 in an OS-dependent manner.
     198             :  * Supported options are IP_{ADD,DROP}_MEMBERSHIP.
     199             :  *
     200             :  * Many operating systems have a limit on the number of groups that
     201             :  * can be joined per socket (where each group and local address
     202             :  * counts).  This impacts OSPF, which joins groups on each interface
     203             :  * using a single socket.  The limit is typically 20, derived from the
     204             :  * original BSD multicast implementation.  Some systems have
     205             :  * mechanisms for increasing this limit.
     206             :  *
     207             :  * In many 4.4BSD-derived systems, multicast group operations are not
     208             :  * allowed on interfaces that are not UP.  Thus, a previous attempt to
     209             :  * leave the group may have failed, leaving it still joined, and we
     210             :  * drop/join quietly to recover.  This may not be necessary, but aims to
     211             :  * defend against unknown behavior in that we will still return an error
     212             :  * if the second join fails.  It is not clear how other systems
     213             :  * (e.g. Linux, Solaris) behave when leaving groups on down interfaces,
     214             :  * but this behavior should not be harmful if they behave the same way,
     215             :  * allow leaves, or implicitly leave all groups joined to down interfaces.
     216             :  */
     217           0 : int setsockopt_ipv4_multicast(int sock, int optname, struct in_addr if_addr,
     218             :                               unsigned int mcast_addr, ifindex_t ifindex)
     219             : {
     220             : #ifdef HAVE_RFC3678
     221           0 :         struct group_req gr;
     222           0 :         struct sockaddr_in *si;
     223           0 :         int ret;
     224           0 :         memset(&gr, 0, sizeof(gr));
     225           0 :         si = (struct sockaddr_in *)&gr.gr_group;
     226           0 :         gr.gr_interface = ifindex;
     227           0 :         si->sin_family = AF_INET;
     228             : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
     229             :         si->sin_len = sizeof(struct sockaddr_in);
     230             : #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
     231           0 :         si->sin_addr.s_addr = mcast_addr;
     232           0 :         ret = setsockopt(sock, IPPROTO_IP,
     233             :                          (optname == IP_ADD_MEMBERSHIP) ? MCAST_JOIN_GROUP
     234             :                                                         : MCAST_LEAVE_GROUP,
     235             :                          (void *)&gr, sizeof(gr));
     236           0 :         if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP)
     237           0 :             && (errno == EADDRINUSE)) {
     238           0 :                 setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr,
     239             :                            sizeof(gr));
     240           0 :                 ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP,
     241             :                                  (void *)&gr, sizeof(gr));
     242             :         }
     243           0 :         return ret;
     244             : 
     245             : #elif defined(HAVE_STRUCT_IP_MREQN_IMR_IFINDEX) && !defined(__FreeBSD__)
     246             :         struct ip_mreqn mreqn;
     247             :         int ret;
     248             : 
     249             :         assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
     250             :         memset(&mreqn, 0, sizeof(mreqn));
     251             : 
     252             :         mreqn.imr_multiaddr.s_addr = mcast_addr;
     253             :         mreqn.imr_ifindex = ifindex;
     254             : 
     255             :         ret = setsockopt(sock, IPPROTO_IP, optname, (void *)&mreqn,
     256             :                          sizeof(mreqn));
     257             :         if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP)
     258             :             && (errno == EADDRINUSE)) {
     259             :                 /* see above: handle possible problem when interface comes back
     260             :                  * up */
     261             :                 zlog_info(
     262             :                         "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %pI4, ifindex %u)",
     263             :                         sock, &mreqn.imr_multiaddr, ifindex);
     264             :                 setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mreqn,
     265             :                            sizeof(mreqn));
     266             :                 ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
     267             :                                  (void *)&mreqn, sizeof(mreqn));
     268             :         }
     269             :         return ret;
     270             : 
     271             : /* Example defines for another OS, boilerplate off other code in this
     272             :    function, AND handle optname as per other sections for consistency !! */
     273             : /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
     274             : /* Add your favourite OS here! */
     275             : 
     276             : #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) /* #if OS_TYPE */
     277             :         /* standard BSD API */
     278             : 
     279             :         struct ip_mreq mreq;
     280             :         int ret;
     281             : 
     282             :         assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
     283             : 
     284             : 
     285             :         memset(&mreq, 0, sizeof(mreq));
     286             :         mreq.imr_multiaddr.s_addr = mcast_addr;
     287             : #if !defined __OpenBSD__
     288             :         mreq.imr_interface.s_addr = htonl(ifindex);
     289             : #else
     290             :         mreq.imr_interface.s_addr = if_addr.s_addr;
     291             : #endif
     292             : 
     293             :         ret = setsockopt(sock, IPPROTO_IP, optname, (void *)&mreq,
     294             :                          sizeof(mreq));
     295             :         if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP)
     296             :             && (errno == EADDRINUSE)) {
     297             :                 /* see above: handle possible problem when interface comes back
     298             :                  * up */
     299             :                 zlog_info(
     300             :                         "setsockopt_ipv4_multicast attempting to drop and re-add (fd %d, mcast %pI4, ifindex %u)",
     301             :                         sock, &mreq.imr_multiaddr, ifindex);
     302             :                 setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void *)&mreq,
     303             :                            sizeof(mreq));
     304             :                 ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
     305             :                                  (void *)&mreq, sizeof(mreq));
     306             :         }
     307             :         return ret;
     308             : 
     309             : #else
     310             : #error "Unsupported multicast API"
     311             : #endif /* #if OS_TYPE */
     312             : }
     313             : 
     314             : /*
     315             :  * Set IP_MULTICAST_IF socket option in an OS-dependent manner.
     316             :  */
     317           0 : int setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr,
     318             :                                  ifindex_t ifindex)
     319             : {
     320             : 
     321             : #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
     322           0 :         struct ip_mreqn mreqn;
     323           0 :         memset(&mreqn, 0, sizeof(mreqn));
     324             : 
     325           0 :         mreqn.imr_ifindex = ifindex;
     326           0 :         return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn,
     327             :                           sizeof(mreqn));
     328             : 
     329             : /* Example defines for another OS, boilerplate off other code in this
     330             :    function */
     331             : /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
     332             : /* Add your favourite OS here! */
     333             : #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK)
     334             :         struct in_addr m;
     335             : 
     336             : #if !defined __OpenBSD__
     337             :         m.s_addr = htonl(ifindex);
     338             : #else
     339             :         m.s_addr = if_addr.s_addr;
     340             : #endif
     341             : 
     342             :         return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m,
     343             :                           sizeof(m));
     344             : #else
     345             : #error "Unsupported multicast API"
     346             : #endif
     347             : }
     348             : 
     349           0 : int setsockopt_ipv4_multicast_loop(int sock, uint8_t val)
     350             : {
     351           0 :         int ret;
     352             : 
     353           0 :         ret = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val,
     354             :                          sizeof(val));
     355           0 :         if (ret < 0)
     356           0 :                 flog_err(EC_LIB_SOCKET, "can't setsockopt IP_MULTICAST_LOOP");
     357             : 
     358           0 :         return ret;
     359             : }
     360             : 
     361           0 : static int setsockopt_ipv4_ifindex(int sock, ifindex_t val)
     362             : {
     363           0 :         int ret;
     364             : 
     365             : #if defined(IP_PKTINFO)
     366           0 :         ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
     367           0 :         if (ret < 0)
     368           0 :                 flog_err(EC_LIB_SOCKET,
     369             :                          "Can't set IP_PKTINFO option for fd %d to %d: %s",
     370             :                          sock, val, safe_strerror(errno));
     371             : #elif defined(IP_RECVIF)
     372             :         ret = setsockopt(sock, IPPROTO_IP, IP_RECVIF, &val, sizeof(val));
     373             :         if (ret < 0)
     374             :                 flog_err(EC_LIB_SOCKET,
     375             :                          "Can't set IP_RECVIF option for fd %d to %d: %s", sock,
     376             :                          val, safe_strerror(errno));
     377             : #else
     378             : #warning "Neither IP_PKTINFO nor IP_RECVIF is available."
     379             : #warning "Will not be able to receive link info."
     380             : #warning "Things might be seriously broken.."
     381             :         /* XXX Does this ever happen?  Should there be a zlog_warn message here?
     382             :          */
     383             :         ret = -1;
     384             : #endif
     385           0 :         return ret;
     386             : }
     387             : 
     388           2 : int setsockopt_ipv4_tos(int sock, int tos)
     389             : {
     390           2 :         int ret;
     391             : 
     392           2 :         ret = setsockopt(sock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
     393           2 :         if (ret < 0)
     394           0 :                 flog_err(EC_LIB_SOCKET,
     395             :                          "Can't set IP_TOS option for fd %d to %#x: %s", sock,
     396             :                          tos, safe_strerror(errno));
     397           2 :         return ret;
     398             : }
     399             : 
     400             : 
     401           0 : int setsockopt_ifindex(int af, int sock, ifindex_t val)
     402             : {
     403           0 :         int ret = -1;
     404             : 
     405           0 :         switch (af) {
     406           0 :         case AF_INET:
     407           0 :                 ret = setsockopt_ipv4_ifindex(sock, val);
     408           0 :                 break;
     409           0 :         case AF_INET6:
     410           0 :                 ret = setsockopt_ipv6_pktinfo(sock, val);
     411           0 :                 break;
     412           0 :         default:
     413           0 :                 flog_err(EC_LIB_DEVELOPMENT,
     414             :                          "setsockopt_ifindex: unknown address family %d", af);
     415             :         }
     416           0 :         return ret;
     417             : }
     418             : 
     419             : /*
     420             :  * Requires: msgh is not NULL and points to a valid struct msghdr, which
     421             :  * may or may not have control data about the incoming interface.
     422             :  *
     423             :  * Returns the interface index (small integer >= 1) if it can be
     424             :  * determined, or else 0.
     425             :  */
     426           0 : static ifindex_t getsockopt_ipv4_ifindex(struct msghdr *msgh)
     427             : {
     428           0 :         ifindex_t ifindex;
     429             : 
     430             : #if defined(IP_PKTINFO)
     431             :         /* Linux pktinfo based ifindex retrieval */
     432           0 :         struct in_pktinfo *pktinfo;
     433             : 
     434           0 :         pktinfo = (struct in_pktinfo *)getsockopt_cmsg_data(msgh, IPPROTO_IP,
     435             :                                                             IP_PKTINFO);
     436             : 
     437             :         /* getsockopt_ifindex() will forward this, being 0 "not found" */
     438           0 :         if (pktinfo == NULL)
     439             :                 return 0;
     440             : 
     441           0 :         ifindex = pktinfo->ipi_ifindex;
     442             : 
     443             : #elif defined(IP_RECVIF)
     444             : 
     445             : /* retrieval based on IP_RECVIF */
     446             : 
     447             :         /* BSD systems use a sockaddr_dl as the control message payload. */
     448             :         struct sockaddr_dl *sdl;
     449             : 
     450             :         /* BSD */
     451             :         sdl = (struct sockaddr_dl *)getsockopt_cmsg_data(msgh, IPPROTO_IP,
     452             :                                                          IP_RECVIF);
     453             :         if (sdl != NULL)
     454             :                 ifindex = sdl->sdl_index;
     455             :         else
     456             :                 ifindex = 0;
     457             : 
     458             : #else
     459             : /*
     460             :  * Neither IP_PKTINFO nor IP_RECVIF defined - warn at compile time.
     461             :  * XXX Decide if this is a core service, or if daemons have to cope.
     462             :  * Since Solaris 8 and OpenBSD seem not to provide it, it seems that
     463             :  * daemons have to cope.
     464             :  */
     465             : #warning "getsockopt_ipv4_ifindex: Neither IP_PKTINFO nor IP_RECVIF defined."
     466             : #warning "Some daemons may fail to operate correctly!"
     467             :         ifindex = 0;
     468             : 
     469             : #endif /* IP_PKTINFO */
     470             : 
     471           0 :         return ifindex;
     472             : }
     473             : 
     474             : /* return ifindex, 0 if none found */
     475           0 : ifindex_t getsockopt_ifindex(int af, struct msghdr *msgh)
     476             : {
     477           0 :         switch (af) {
     478           0 :         case AF_INET:
     479           0 :                 return (getsockopt_ipv4_ifindex(msgh));
     480             :         case AF_INET6:
     481           0 :                 return (getsockopt_ipv6_ifindex(msgh));
     482           0 :         default:
     483           0 :                 flog_err(EC_LIB_DEVELOPMENT,
     484             :                          "getsockopt_ifindex: unknown address family %d", af);
     485           0 :                 return 0;
     486             :         }
     487             : }
     488             : 
     489             : /* swab iph between order system uses for IP_HDRINCL and host order */
     490           0 : void sockopt_iphdrincl_swab_htosys(struct ip *iph)
     491             : {
     492             : /* BSD and derived take iph in network order, except for
     493             :  * ip_len and ip_off
     494             :  */
     495             : #ifndef HAVE_IP_HDRINCL_BSD_ORDER
     496           0 :         iph->ip_len = htons(iph->ip_len);
     497           0 :         iph->ip_off = htons(iph->ip_off);
     498             : #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
     499             : 
     500           0 :         iph->ip_id = htons(iph->ip_id);
     501           0 : }
     502             : 
     503           0 : void sockopt_iphdrincl_swab_systoh(struct ip *iph)
     504             : {
     505             : #ifndef HAVE_IP_HDRINCL_BSD_ORDER
     506           0 :         iph->ip_len = ntohs(iph->ip_len);
     507           0 :         iph->ip_off = ntohs(iph->ip_off);
     508             : #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
     509             : 
     510           0 :         iph->ip_id = ntohs(iph->ip_id);
     511           0 : }
     512             : 
     513           8 : int sockopt_tcp_rtt(int sock)
     514             : {
     515             : #ifdef TCP_INFO
     516           8 :         struct tcp_info ti;
     517           8 :         socklen_t len = sizeof(ti);
     518             : 
     519           8 :         if (getsockopt(sock, IPPROTO_TCP, TCP_INFO, &ti, &len) != 0)
     520             :                 return 0;
     521             : 
     522           8 :         return ti.tcpi_rtt / 1000;
     523             : #else
     524             :         return 0;
     525             : #endif
     526             : }
     527             : 
     528           0 : int sockopt_tcp_signature_ext(int sock, union sockunion *su, uint16_t prefixlen,
     529             :                               const char *password)
     530             : {
     531             : #ifndef HAVE_DECL_TCP_MD5SIG
     532             :         /*
     533             :          * We have been asked to enable MD5 auth for an address, but our
     534             :          * platform doesn't support that
     535             :          */
     536             :         return -2;
     537             : #endif
     538             : 
     539             : #ifndef TCP_MD5SIG_EXT
     540             :         /*
     541             :          * We have been asked to enable MD5 auth for a prefix, but our platform
     542             :          * doesn't support that
     543             :          */
     544             :         if (prefixlen > 0)
     545             :                 return -2;
     546             : #endif
     547             : 
     548             : #if HAVE_DECL_TCP_MD5SIG
     549           0 :         int ret;
     550             : 
     551           0 :         int optname = TCP_MD5SIG;
     552             : #ifndef GNU_LINUX
     553             :         /*
     554             :          * XXX Need to do PF_KEY operation here to add/remove an SA entry,
     555             :          * and add/remove an SP entry for this peer's packet flows also.
     556             :          */
     557             :         int md5sig = password && *password ? 1 : 0;
     558             : #else
     559           0 :         int keylen = password ? strlen(password) : 0;
     560           0 :         struct tcp_md5sig md5sig;
     561           0 :         union sockunion *su2, *susock;
     562             : 
     563             :         /* Figure out whether the socket and the sockunion are the same family..
     564             :          * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think..
     565             :          */
     566           0 :         if (!(susock = sockunion_getsockname(sock)))
     567             :                 return -1;
     568             : 
     569           0 :         if (susock->sa.sa_family == su->sa.sa_family)
     570             :                 su2 = su;
     571             :         else {
     572             :                 /* oops.. */
     573           0 :                 su2 = susock;
     574             : 
     575           0 :                 if (su2->sa.sa_family == AF_INET) {
     576           0 :                         sockunion_free(susock);
     577           0 :                         return 0;
     578             :                 }
     579             : 
     580             :                 /* If this does not work, then all users of this sockopt will
     581             :                  * need to
     582             :                  * differentiate between IPv4 and IPv6, and keep separate
     583             :                  * sockets for
     584             :                  * each.
     585             :                  *
     586             :                  * Sadly, it doesn't seem to work at present. It's unknown
     587             :                  * whether
     588             :                  * this is a bug or not.
     589             :                  */
     590           0 :                 if (su2->sa.sa_family == AF_INET6
     591           0 :                     && su->sa.sa_family == AF_INET) {
     592           0 :                         su2->sin6.sin6_family = AF_INET6;
     593             :                         /* V4Map the address */
     594           0 :                         memset(&su2->sin6.sin6_addr, 0,
     595             :                                sizeof(struct in6_addr));
     596           0 :                         su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
     597           0 :                         memcpy(&su2->sin6.sin6_addr.s6_addr32[3],
     598             :                                &su->sin.sin_addr, 4);
     599             :                 }
     600             :         }
     601             : 
     602           0 :         memset(&md5sig, 0, sizeof(md5sig));
     603           0 :         memcpy(&md5sig.tcpm_addr, su2, sizeof(*su2));
     604             : 
     605           0 :         md5sig.tcpm_keylen = keylen;
     606           0 :         if (keylen)
     607           0 :                 memcpy(md5sig.tcpm_key, password, keylen);
     608           0 :         sockunion_free(susock);
     609             : 
     610             :         /*
     611             :          * Handle support for MD5 signatures on prefixes, if available and
     612             :          * requested. Technically the #ifdef check below is not needed because
     613             :          * if prefixlen > 0 and we don't have support for this feature we would
     614             :          * have already returned by now, but leaving it there to be explicit.
     615             :          */
     616             : #ifdef TCP_MD5SIG_EXT
     617           0 :         if (prefixlen > 0) {
     618           0 :                 md5sig.tcpm_prefixlen = prefixlen;
     619           0 :                 md5sig.tcpm_flags = TCP_MD5SIG_FLAG_PREFIX;
     620           0 :                 optname = TCP_MD5SIG_EXT;
     621             :         }
     622             : #endif /* TCP_MD5SIG_EXT */
     623             : 
     624             : #endif /* GNU_LINUX */
     625             : 
     626           0 :         ret = setsockopt(sock, IPPROTO_TCP, optname, &md5sig, sizeof(md5sig));
     627           0 :         if (ret < 0) {
     628           0 :                 if (ENOENT == errno)
     629             :                         ret = 0;
     630             :                 else
     631           0 :                         flog_err_sys(
     632             :                                 EC_LIB_SYSTEM_CALL,
     633             :                                 "sockopt_tcp_signature: setsockopt(%d): %s",
     634             :                                 sock, safe_strerror(errno));
     635             :         }
     636             :         return ret;
     637             : #endif /* HAVE_TCP_MD5SIG */
     638             : 
     639             :         /*
     640             :          * Making compiler happy.  If we get to this point we probably
     641             :          * have done something really really wrong.
     642             :          */
     643             :         return -2;
     644             : }
     645             : 
     646           0 : int sockopt_tcp_signature(int sock, union sockunion *su, const char *password)
     647             : {
     648           0 :         return sockopt_tcp_signature_ext(sock, su, 0, password);
     649             : }
     650             : 
     651             : /* set TCP mss value to socket */
     652           0 : int sockopt_tcp_mss_set(int sock, int tcp_maxseg)
     653             : {
     654           0 :         int ret = 0;
     655           0 :         socklen_t tcp_maxseg_len = sizeof(tcp_maxseg);
     656             : 
     657           0 :         ret = setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg,
     658             :                          tcp_maxseg_len);
     659           0 :         if (ret != 0) {
     660           0 :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
     661             :                              "%s failed: setsockopt(%d): %s", __func__, sock,
     662             :                              safe_strerror(errno));
     663             :         }
     664             : 
     665           0 :         return ret;
     666             : }
     667             : 
     668             : /* get TCP mss value synced by socket */
     669          10 : int sockopt_tcp_mss_get(int sock)
     670             : {
     671          10 :         int ret = 0;
     672          10 :         int tcp_maxseg = 0;
     673          10 :         socklen_t tcp_maxseg_len = sizeof(tcp_maxseg);
     674             : 
     675          10 :         ret = getsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg,
     676             :                          &tcp_maxseg_len);
     677          10 :         if (ret != 0) {
     678           6 :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
     679             :                              "%s failed: getsockopt(%d): %s", __func__, sock,
     680             :                              safe_strerror(errno));
     681           6 :                 return 0;
     682             :         }
     683             : 
     684           4 :         return tcp_maxseg;
     685             : }
     686             : 
     687           0 : int setsockopt_tcp_keepalive(int sock, uint16_t keepalive_idle,
     688             :                              uint16_t keepalive_intvl,
     689             :                              uint16_t keepalive_probes)
     690             : {
     691           0 :         int val = 1;
     692             : 
     693           0 :         if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) < 0) {
     694           0 :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
     695             :                              "%s failed: setsockopt SO_KEEPALIVE (%d): %s",
     696             :                              __func__, sock, safe_strerror(errno));
     697           0 :                 return -1;
     698             :         }
     699             : 
     700             : #if defined __OpenBSD__
     701             :         return 0;
     702             : #else
     703             :         /* Send first probe after keepalive_idle seconds */
     704           0 :         val = keepalive_idle;
     705           0 :         if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) <
     706             :             0) {
     707           0 :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
     708             :                              "%s failed: setsockopt TCP_KEEPIDLE (%d): %s",
     709             :                              __func__, sock, safe_strerror(errno));
     710           0 :                 return -1;
     711             :         }
     712             : 
     713             :         /* Set interval between two probes */
     714           0 :         val = keepalive_intvl;
     715           0 :         if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) <
     716             :             0) {
     717           0 :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
     718             :                              "%s failed: setsockopt TCP_KEEPINTVL (%d): %s",
     719             :                              __func__, sock, safe_strerror(errno));
     720           0 :                 return -1;
     721             :         }
     722             : 
     723             :         /* Set maximum probes */
     724           0 :         val = keepalive_probes;
     725           0 :         if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
     726           0 :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
     727             :                              "%s failed: setsockopt TCP_KEEPCNT (%d): %s",
     728             :                              __func__, sock, safe_strerror(errno));
     729           0 :                 return -1;
     730             :         }
     731             : 
     732             :         return 0;
     733             : #endif
     734             : }

Generated by: LCOV version v1.16-topotato