LCOV - code coverage report
Current view: top level - lib - sockopt.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 20 150 13.3 %
Date: 2015-11-19 Functions: 5 22 22.7 %

          Line data    Source code
       1             : /* setsockopt functions
       2             :  * Copyright (C) 1999 Kunihiro Ishiguro
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * GNU Zebra is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
      18             :  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      19             :  * 02111-1307, USA.  
      20             :  */
      21             : 
      22             : #include <zebra.h>
      23             : #include "log.h"
      24             : #include "sockopt.h"
      25             : #include "sockunion.h"
      26             : 
      27             : int
      28           0 : setsockopt_so_recvbuf (int sock, int size)
      29             : {
      30             :   int ret;
      31             :   
      32           0 :   if ( (ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *)
      33             :                           &size, sizeof (int))) < 0)
      34           0 :     zlog_err ("fd %d: can't setsockopt SO_RCVBUF to %d: %s",
      35           0 :               sock,size,safe_strerror(errno));
      36             : 
      37           0 :   return ret;
      38             : }
      39             : 
      40             : int
      41           0 : setsockopt_so_sendbuf (const int sock, int size)
      42             : {
      43           0 :   int ret = setsockopt (sock, SOL_SOCKET, SO_SNDBUF,
      44             :     (char *)&size, sizeof (int));
      45             :   
      46           0 :   if (ret < 0)
      47           0 :     zlog_err ("fd %d: can't setsockopt SO_SNDBUF to %d: %s",
      48           0 :       sock, size, safe_strerror (errno));
      49             : 
      50           0 :   return ret;
      51             : }
      52             : 
      53             : int
      54           0 : getsockopt_so_sendbuf (const int sock)
      55             : {
      56             :   u_int32_t optval;
      57           0 :   socklen_t optlen = sizeof (optval);
      58           0 :   int ret = getsockopt (sock, SOL_SOCKET, SO_SNDBUF,
      59             :     (char *)&optval, &optlen);
      60           0 :   if (ret < 0)
      61             :   {
      62           0 :     zlog_err ("fd %d: can't getsockopt SO_SNDBUF: %d (%s)",
      63           0 :       sock, errno, safe_strerror (errno));
      64           0 :     return ret;
      65             :   }
      66           0 :   return optval;
      67             : }
      68             : 
      69             : static void *
      70           0 : getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
      71             : {
      72             :   struct cmsghdr *cmsg;
      73           0 :   void *ptr = NULL;
      74             :   
      75           0 :   for (cmsg = ZCMSG_FIRSTHDR(msgh); 
      76             :        cmsg != NULL;
      77           0 :        cmsg = CMSG_NXTHDR(msgh, cmsg))
      78           0 :     if (cmsg->cmsg_level == level && cmsg->cmsg_type)
      79           0 :       return (ptr = CMSG_DATA(cmsg));
      80             : 
      81           0 :   return NULL;
      82             : }
      83             : 
      84             : #ifdef HAVE_IPV6
      85             : /* Set IPv6 packet info to the socket. */
      86             : int
      87          45 : setsockopt_ipv6_pktinfo (int sock, int val)
      88             : {
      89             :   int ret;
      90             :     
      91             : #ifdef IPV6_RECVPKTINFO         /*2292bis-01*/
      92          45 :   ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
      93          45 :   if (ret < 0)
      94           0 :     zlog_warn ("can't setsockopt IPV6_RECVPKTINFO : %s", safe_strerror (errno));
      95             : #else   /*RFC2292*/
      96             :   ret = setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &val, sizeof(val));
      97             :   if (ret < 0)
      98             :     zlog_warn ("can't setsockopt IPV6_PKTINFO : %s", safe_strerror (errno));
      99             : #endif /* INIA_IPV6 */
     100          45 :   return ret;
     101             : }
     102             : 
     103             : /* Set multicast hops val to the socket. */
     104             : int
     105           0 : setsockopt_ipv6_checksum (int sock, int val)
     106             : {
     107             :   int ret;
     108             : 
     109             : #ifdef GNU_LINUX
     110           0 :   ret = setsockopt(sock, IPPROTO_RAW, IPV6_CHECKSUM, &val, sizeof(val));
     111             : #else
     112             :   ret = setsockopt(sock, IPPROTO_IPV6, IPV6_CHECKSUM, &val, sizeof(val));
     113             : #endif /* GNU_LINUX */
     114           0 :   if (ret < 0)
     115           0 :     zlog_warn ("can't setsockopt IPV6_CHECKSUM");
     116           0 :   return ret;
     117             : }
     118             : 
     119             : /* Set multicast hops val to the socket. */
     120             : int
     121          45 : setsockopt_ipv6_multicast_hops (int sock, int val)
     122             : {
     123             :   int ret;
     124             : 
     125          45 :   ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
     126          45 :   if (ret < 0)
     127           0 :     zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS");
     128          45 :   return ret;
     129             : }
     130             : 
     131             : /* Set multicast hops val to the socket. */
     132             : int
     133          45 : setsockopt_ipv6_unicast_hops (int sock, int val)
     134             : {
     135             :   int ret;
     136             : 
     137          45 :   ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
     138          45 :   if (ret < 0)
     139           0 :     zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS");
     140          45 :   return ret;
     141             : }
     142             : 
     143             : int
     144          45 : setsockopt_ipv6_hoplimit (int sock, int val)
     145             : {
     146             :   int ret;
     147             : 
     148             : #ifdef IPV6_RECVHOPLIMIT        /*2292bis-01*/
     149          45 :   ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
     150          45 :   if (ret < 0)
     151           0 :     zlog_warn ("can't setsockopt IPV6_RECVHOPLIMIT");
     152             : #else   /*RFC2292*/
     153             :   ret = setsockopt (sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &val, sizeof(val));
     154             :   if (ret < 0)
     155             :     zlog_warn ("can't setsockopt IPV6_HOPLIMIT");
     156             : #endif
     157          45 :   return ret;
     158             : }
     159             : 
     160             : /* Set multicast loop zero to the socket. */
     161             : int
     162          45 : setsockopt_ipv6_multicast_loop (int sock, int val)
     163             : {
     164             :   int ret;
     165             :     
     166          45 :   ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
     167             :                     sizeof (val));
     168          45 :   if (ret < 0)
     169           0 :     zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP");
     170          45 :   return ret;
     171             : }
     172             : 
     173             : static int
     174           0 : getsockopt_ipv6_ifindex (struct msghdr *msgh)
     175             : {
     176             :   struct in6_pktinfo *pktinfo;
     177             :   
     178           0 :   pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO);
     179             :   
     180           0 :   return pktinfo->ipi6_ifindex;
     181             : }
     182             : 
     183             : int
     184           0 : setsockopt_ipv6_tclass(int sock, int tclass)
     185             : {
     186           0 :   int ret = 0;
     187             : 
     188             : #ifdef IPV6_TCLASS /* RFC3542 */
     189           0 :   ret = setsockopt (sock, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof (tclass));
     190           0 :   if (ret < 0)
     191           0 :     zlog_warn ("Can't set IPV6_TCLASS option for fd %d to %#x: %s",
     192           0 :                sock, tclass, safe_strerror(errno));
     193             : #endif
     194           0 :   return ret;
     195             : }
     196             : #endif /* HAVE_IPV6 */
     197             : 
     198             : /*
     199             :  * Process multicast socket options for IPv4 in an OS-dependent manner.
     200             :  * Supported options are IP_{ADD,DROP}_MEMBERSHIP.
     201             :  *
     202             :  * Many operating systems have a limit on the number of groups that
     203             :  * can be joined per socket (where each group and local address
     204             :  * counts).  This impacts OSPF, which joins groups on each interface
     205             :  * using a single socket.  The limit is typically 20, derived from the
     206             :  * original BSD multicast implementation.  Some systems have
     207             :  * mechanisms for increasing this limit.
     208             :  *
     209             :  * In many 4.4BSD-derived systems, multicast group operations are not
     210             :  * allowed on interfaces that are not UP.  Thus, a previous attempt to
     211             :  * leave the group may have failed, leaving it still joined, and we
     212             :  * drop/join quietly to recover.  This may not be necessary, but aims to
     213             :  * defend against unknown behavior in that we will still return an error
     214             :  * if the second join fails.  It is not clear how other systems
     215             :  * (e.g. Linux, Solaris) behave when leaving groups on down interfaces,
     216             :  * but this behavior should not be harmful if they behave the same way,
     217             :  * allow leaves, or implicitly leave all groups joined to down interfaces.
     218             :  */
     219             : int
     220           0 : setsockopt_ipv4_multicast(int sock,
     221             :                         int optname, 
     222             :                         unsigned int mcast_addr,
     223             :                         unsigned int ifindex)
     224             : {
     225             : #ifdef HAVE_RFC3678
     226             :   struct group_req gr;
     227             :   struct sockaddr_in *si;
     228             :   int ret;
     229           0 :   memset (&gr, 0, sizeof(gr));
     230           0 :   si = (struct sockaddr_in *)&gr.gr_group;
     231           0 :   gr.gr_interface = ifindex;
     232           0 :   si->sin_family = AF_INET;
     233             : #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
     234             :   si->sin_len = sizeof(struct sockaddr_in);
     235             : #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
     236           0 :   si->sin_addr.s_addr = mcast_addr;
     237           0 :   ret = setsockopt(sock, IPPROTO_IP, (optname == IP_ADD_MEMBERSHIP) ? 
     238             :     MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
     239           0 :   if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
     240             :     {
     241           0 :       setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
     242           0 :       ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, sizeof(gr));
     243             :     }
     244           0 :   return ret;
     245             : 
     246             : #elif defined(HAVE_STRUCT_IP_MREQN_IMR_IFINDEX) && !defined(__FreeBSD__)
     247             :   struct ip_mreqn mreqn;
     248             :   int ret;
     249             :   
     250             :   assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
     251             :   memset (&mreqn, 0, sizeof(mreqn));
     252             : 
     253             :   mreqn.imr_multiaddr.s_addr = mcast_addr;
     254             :   mreqn.imr_ifindex = ifindex;
     255             :   
     256             :   ret = setsockopt(sock, IPPROTO_IP, optname,
     257             :                    (void *)&mreqn, sizeof(mreqn));
     258             :   if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
     259             :     {
     260             :       /* see above: handle possible problem when interface comes back up */
     261             :       char buf[1][INET_ADDRSTRLEN];
     262             :       zlog_info("setsockopt_ipv4_multicast attempting to drop and "
     263             :                 "re-add (fd %d, mcast %s, ifindex %u)",
     264             :                 sock,
     265             :                 inet_ntop(AF_INET, &mreqn.imr_multiaddr,
     266             :                           buf[0], sizeof(buf[0])), ifindex);
     267             :       setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
     268             :                  (void *)&mreqn, sizeof(mreqn));
     269             :       ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
     270             :                        (void *)&mreqn, sizeof(mreqn));
     271             :     }
     272             :   return ret;
     273             : 
     274             :   /* Example defines for another OS, boilerplate off other code in this
     275             :      function, AND handle optname as per other sections for consistency !! */
     276             :   /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
     277             :   /* Add your favourite OS here! */
     278             : 
     279             : #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) /* #if OS_TYPE */ 
     280             :   /* standard BSD API */
     281             : 
     282             :   struct in_addr m;
     283             :   struct ip_mreq mreq;
     284             :   int ret;
     285             : 
     286             :   assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
     287             : 
     288             :   m.s_addr = htonl(ifindex);
     289             : 
     290             :   memset (&mreq, 0, sizeof(mreq));
     291             :   mreq.imr_multiaddr.s_addr = mcast_addr;
     292             :   mreq.imr_interface = m;
     293             :   
     294             :   ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq));
     295             :   if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
     296             :     {
     297             :       /* see above: handle possible problem when interface comes back up */
     298             :       char buf[1][INET_ADDRSTRLEN];
     299             :       zlog_info("setsockopt_ipv4_multicast attempting to drop and "
     300             :                 "re-add (fd %d, mcast %s, ifindex %u)",
     301             :                 sock,
     302             :                 inet_ntop(AF_INET, &mreq.imr_multiaddr,
     303             :                           buf[0], sizeof(buf[0])), ifindex);
     304             :       setsockopt (sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
     305             :                   (void *)&mreq, sizeof(mreq));
     306             :       ret = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
     307             :                         (void *)&mreq, sizeof(mreq));
     308             :     }
     309             :   return ret;
     310             : 
     311             : #else
     312             :   #error "Unsupported multicast API"
     313             : #endif /* #if OS_TYPE */
     314             : 
     315             : }
     316             : 
     317             : /*
     318             :  * Set IP_MULTICAST_IF socket option in an OS-dependent manner.
     319             :  */
     320             : int
     321           0 : setsockopt_ipv4_multicast_if(int sock,
     322             :                         unsigned int ifindex)
     323             : {
     324             : 
     325             : #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
     326             :   struct ip_mreqn mreqn;
     327           0 :   memset (&mreqn, 0, sizeof(mreqn));
     328             : 
     329           0 :   mreqn.imr_ifindex = ifindex;
     330           0 :   return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, sizeof(mreqn));
     331             : 
     332             :   /* Example defines for another OS, boilerplate off other code in this
     333             :      function */
     334             :   /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
     335             :   /* Add your favourite OS here! */
     336             : #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK)
     337             :   struct in_addr m;
     338             : 
     339             :   m.s_addr = htonl(ifindex);
     340             : 
     341             :   return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m));
     342             : #else
     343             :   #error "Unsupported multicast API"
     344             : #endif
     345             : }
     346             :   
     347             : static int
     348           0 : setsockopt_ipv4_ifindex (int sock, int val)
     349             : {
     350             :   int ret;
     351             : 
     352             : #if defined (IP_PKTINFO)
     353           0 :   if ((ret = setsockopt (sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val))) < 0)
     354           0 :     zlog_warn ("Can't set IP_PKTINFO option for fd %d to %d: %s",
     355           0 :                sock,val,safe_strerror(errno));
     356             : #elif defined (IP_RECVIF)
     357             :   if ((ret = setsockopt (sock, IPPROTO_IP, IP_RECVIF, &val, sizeof (val))) < 0)
     358             :     zlog_warn ("Can't set IP_RECVIF option for fd %d to %d: %s",
     359             :                sock,val,safe_strerror(errno));
     360             : #else
     361             : #warning "Neither IP_PKTINFO nor IP_RECVIF is available."
     362             : #warning "Will not be able to receive link info."
     363             : #warning "Things might be seriously broken.."
     364             :   /* XXX Does this ever happen?  Should there be a zlog_warn message here? */
     365             :   ret = -1;
     366             : #endif
     367           0 :   return ret;
     368             : }
     369             : 
     370             : int
     371           0 : setsockopt_ipv4_tos(int sock, int tos)
     372             : {
     373             :   int ret;
     374             : 
     375           0 :   ret = setsockopt (sock, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
     376           0 :   if (ret < 0)
     377           0 :     zlog_warn ("Can't set IP_TOS option for fd %d to %#x: %s",
     378           0 :                sock, tos, safe_strerror(errno));
     379           0 :   return ret;
     380             : }
     381             : 
     382             : 
     383             : int
     384           0 : setsockopt_ifindex (int af, int sock, int val)
     385             : {
     386           0 :   int ret = -1;
     387             :   
     388           0 :   switch (af)
     389             :     {
     390             :       case AF_INET:
     391           0 :         ret = setsockopt_ipv4_ifindex (sock, val);
     392           0 :         break;
     393             : #ifdef HAVE_IPV6
     394             :       case AF_INET6:
     395           0 :         ret = setsockopt_ipv6_pktinfo (sock, val);
     396           0 :         break;
     397             : #endif
     398             :       default:
     399           0 :         zlog_warn ("setsockopt_ifindex: unknown address family %d", af);
     400             :     }
     401           0 :   return ret;
     402             : }
     403             :   
     404             : /*
     405             :  * Requires: msgh is not NULL and points to a valid struct msghdr, which
     406             :  * may or may not have control data about the incoming interface.
     407             :  *
     408             :  * Returns the interface index (small integer >= 1) if it can be
     409             :  * determined, or else 0.
     410             :  */
     411             : static int
     412           0 : getsockopt_ipv4_ifindex (struct msghdr *msgh)
     413             : {
     414             :   /* XXX: initialize to zero?  (Always overwritten, so just cosmetic.) */
     415           0 :   int ifindex = -1;
     416             : 
     417             : #if defined(IP_PKTINFO)
     418             : /* Linux pktinfo based ifindex retrieval */
     419             :   struct in_pktinfo *pktinfo;
     420             :   
     421           0 :   pktinfo = 
     422             :     (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
     423             :   /* XXX Can pktinfo be NULL?  Clean up post 0.98. */
     424           0 :   ifindex = pktinfo->ipi_ifindex;
     425             :   
     426             : #elif defined(IP_RECVIF)
     427             : 
     428             :   /* retrieval based on IP_RECVIF */
     429             : 
     430             : #ifndef SUNOS_5
     431             :   /* BSD systems use a sockaddr_dl as the control message payload. */
     432             :   struct sockaddr_dl *sdl;
     433             : #else
     434             :   /* SUNOS_5 uses an integer with the index. */
     435             :   int *ifindex_p;
     436             : #endif /* SUNOS_5 */
     437             : 
     438             : #ifndef SUNOS_5
     439             :   /* BSD */
     440             :   sdl = 
     441             :     (struct sockaddr_dl *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF);
     442             :   if (sdl != NULL)
     443             :     ifindex = sdl->sdl_index;
     444             :   else
     445             :     ifindex = 0;
     446             : #else
     447             :   /*
     448             :    * Solaris.  On Solaris 8, IP_RECVIF is defined, but the call to
     449             :    * enable it fails with errno=99, and the struct msghdr has
     450             :    * controllen 0.
     451             :    */
     452             :   ifindex_p = (uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); 
     453             :   if (ifindex_p != NULL)
     454             :     ifindex = *ifindex_p;
     455             :   else
     456             :     ifindex = 0;
     457             : #endif /* SUNOS_5 */
     458             : 
     459             : #else
     460             :   /*
     461             :    * Neither IP_PKTINFO nor IP_RECVIF defined - warn at compile time.
     462             :    * XXX Decide if this is a core service, or if daemons have to cope.
     463             :    * Since Solaris 8 and OpenBSD seem not to provide it, it seems that
     464             :    * daemons have to cope.
     465             :    */
     466             : #warning "getsockopt_ipv4_ifindex: Neither IP_PKTINFO nor IP_RECVIF defined."
     467             : #warning "Some daemons may fail to operate correctly!"
     468             :   ifindex = 0;
     469             : 
     470             : #endif /* IP_PKTINFO */ 
     471             : 
     472           0 :   return ifindex;
     473             : }
     474             : 
     475             : /* return ifindex, 0 if none found */
     476             : int
     477           0 : getsockopt_ifindex (int af, struct msghdr *msgh)
     478             : {
     479           0 :   switch (af)
     480             :     {
     481             :       case AF_INET:
     482           0 :         return (getsockopt_ipv4_ifindex (msgh));
     483             :         break;
     484             : #ifdef HAVE_IPV6
     485             :       case AF_INET6:
     486           0 :         return (getsockopt_ipv6_ifindex (msgh));
     487             :         break;
     488             : #endif
     489             :       default:
     490           0 :         zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
     491           0 :         return 0;
     492             :     }
     493             : }
     494             : 
     495             : /* swab iph between order system uses for IP_HDRINCL and host order */
     496             : void
     497           0 : sockopt_iphdrincl_swab_htosys (struct ip *iph)
     498             : {
     499             :   /* BSD and derived take iph in network order, except for 
     500             :    * ip_len and ip_off
     501             :    */
     502             : #ifndef HAVE_IP_HDRINCL_BSD_ORDER
     503           0 :   iph->ip_len = htons(iph->ip_len);
     504           0 :   iph->ip_off = htons(iph->ip_off);
     505             : #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
     506             : 
     507           0 :   iph->ip_id = htons(iph->ip_id);
     508           0 : }
     509             : 
     510             : void
     511           0 : sockopt_iphdrincl_swab_systoh (struct ip *iph)
     512             : {
     513             : #ifndef HAVE_IP_HDRINCL_BSD_ORDER
     514           0 :   iph->ip_len = ntohs(iph->ip_len);
     515           0 :   iph->ip_off = ntohs(iph->ip_off);
     516             : #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
     517             : 
     518           0 :   iph->ip_id = ntohs(iph->ip_id);
     519           0 : }
     520             : 
     521             : int
     522           0 : sockopt_tcp_signature (int sock, union sockunion *su, const char *password)
     523             : {
     524             : #if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
     525             :   /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
     526             :    * version of the Quagga patch (based on work by Rick Payne, and Bruce
     527             :    * Simpson)
     528             :    */
     529             : #define TCP_MD5_AUTH 13
     530             : #define TCP_MD5_AUTH_ADD 1
     531             : #define TCP_MD5_AUTH_DEL 2
     532             :   struct tcp_rfc2385_cmd {
     533             :     u_int8_t     command;    /* Command - Add/Delete */
     534             :     u_int32_t    address;    /* IPV4 address associated */
     535             :     u_int8_t     keylen;     /* MD5 Key len (do NOT assume 0 terminated ascii) */
     536             :     void         *key;       /* MD5 Key */
     537             :   } cmd;
     538             :   struct in_addr *addr = &su->sin.sin_addr;
     539             :   
     540             :   cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
     541             :   cmd.address = addr->s_addr;
     542             :   cmd.keylen = (password != NULL ? strlen (password) : 0);
     543             :   cmd.key = password;
     544             :   
     545             :   return setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd);
     546             :   
     547             : #elif HAVE_DECL_TCP_MD5SIG
     548             :   int ret;
     549             : #ifndef GNU_LINUX
     550             :   /*
     551             :    * XXX Need to do PF_KEY operation here to add/remove an SA entry,
     552             :    * and add/remove an SP entry for this peer's packet flows also.
     553             :    */
     554             :   int md5sig = password && *password ? 1 : 0;
     555             : #else
     556           0 :   int keylen = password ? strlen (password) : 0;
     557             :   struct tcp_md5sig md5sig;
     558             :   union sockunion *su2, *susock;
     559             :   
     560             :   /* Figure out whether the socket and the sockunion are the same family..
     561             :    * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think..
     562             :    */
     563           0 :   if (!(susock = sockunion_getsockname (sock)))
     564           0 :     return -1;
     565             :   
     566           0 :   if (susock->sa.sa_family == su->sa.sa_family)
     567           0 :     su2 = su;
     568             :   else
     569             :     {
     570             :       /* oops.. */
     571           0 :       su2 = susock;
     572             :       
     573           0 :       if (su2->sa.sa_family == AF_INET)
     574             :         {
     575           0 :           sockunion_free (susock);
     576           0 :           return 0;
     577             :         }
     578             :       
     579             : #ifdef HAVE_IPV6
     580             :       /* If this does not work, then all users of this sockopt will need to
     581             :        * differentiate between IPv4 and IPv6, and keep seperate sockets for
     582             :        * each. 
     583             :        *
     584             :        * Sadly, it doesn't seem to work at present. It's unknown whether
     585             :        * this is a bug or not.
     586             :        */
     587           0 :       if (su2->sa.sa_family == AF_INET6
     588           0 :           && su->sa.sa_family == AF_INET)
     589             :         {
     590           0 :            su2->sin6.sin6_family = AF_INET6;
     591             :            /* V4Map the address */
     592           0 :            memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
     593           0 :            su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
     594           0 :            memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4);
     595             :         }
     596             : #endif
     597             :     }
     598             :   
     599           0 :   memset (&md5sig, 0, sizeof (md5sig));
     600           0 :   memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2));
     601           0 :   md5sig.tcpm_keylen = keylen;
     602           0 :   if (keylen)
     603           0 :     memcpy (md5sig.tcpm_key, password, keylen);
     604           0 :   sockunion_free (susock);
     605             : #endif /* GNU_LINUX */
     606           0 :   if ((ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig)) < 0)
     607             :     {
     608             :       /* ENOENT is harmless.  It is returned when we clear a password for which
     609             :          one was not previously set. */
     610           0 :       if (ENOENT == errno)
     611           0 :         ret = 0;
     612             :       else
     613           0 :         zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s",
     614           0 :                   sock, safe_strerror(errno));
     615             :     }
     616           0 :   return ret;
     617             : #else /* HAVE_TCP_MD5SIG */
     618             :   return -2;
     619             : #endif /* !HAVE_TCP_MD5SIG */
     620             : }

Generated by: LCOV version 1.10