File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / sockopt.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 7 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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: setsockopt_so_recvbuf (int sock, int size)
   29: {
   30:   int ret;
   31:   
   32:   if ( (ret = setsockopt (sock, SOL_SOCKET, SO_RCVBUF, (char *)
   33:                           &size, sizeof (int))) < 0)
   34:     zlog_err ("fd %d: can't setsockopt SO_RCVBUF to %d: %s",
   35: 	      sock,size,safe_strerror(errno));
   36: 
   37:   return ret;
   38: }
   39: 
   40: int
   41: setsockopt_so_sendbuf (const int sock, int size)
   42: {
   43:   int ret = setsockopt (sock, SOL_SOCKET, SO_SNDBUF,
   44:     (char *)&size, sizeof (int));
   45:   
   46:   if (ret < 0)
   47:     zlog_err ("fd %d: can't setsockopt SO_SNDBUF to %d: %s",
   48:       sock, size, safe_strerror (errno));
   49: 
   50:   return ret;
   51: }
   52: 
   53: int
   54: getsockopt_so_sendbuf (const int sock)
   55: {
   56:   u_int32_t optval;
   57:   socklen_t optlen = sizeof (optval);
   58:   int ret = getsockopt (sock, SOL_SOCKET, SO_SNDBUF,
   59:     (char *)&optval, &optlen);
   60:   if (ret < 0)
   61:   {
   62:     zlog_err ("fd %d: can't getsockopt SO_SNDBUF: %d (%s)",
   63:       sock, errno, safe_strerror (errno));
   64:     return ret;
   65:   }
   66:   return optval;
   67: }
   68: 
   69: static void *
   70: getsockopt_cmsg_data (struct msghdr *msgh, int level, int type)
   71: {
   72:   struct cmsghdr *cmsg;
   73:   void *ptr = NULL;
   74:   
   75:   for (cmsg = ZCMSG_FIRSTHDR(msgh); 
   76:        cmsg != NULL;
   77:        cmsg = CMSG_NXTHDR(msgh, cmsg))
   78:     if (cmsg->cmsg_level == level && cmsg->cmsg_type)
   79:       return (ptr = CMSG_DATA(cmsg));
   80: 
   81:   return NULL;
   82: }
   83: 
   84: #ifdef HAVE_IPV6
   85: /* Set IPv6 packet info to the socket. */
   86: int
   87: setsockopt_ipv6_pktinfo (int sock, int val)
   88: {
   89:   int ret;
   90:     
   91: #ifdef IPV6_RECVPKTINFO		/*2292bis-01*/
   92:   ret = setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &val, sizeof(val));
   93:   if (ret < 0)
   94:     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:   return ret;
  101: }
  102: 
  103: /* Set multicast hops val to the socket. */
  104: int
  105: setsockopt_ipv6_checksum (int sock, int val)
  106: {
  107:   int ret;
  108: 
  109: #ifdef GNU_LINUX
  110:   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:   if (ret < 0)
  115:     zlog_warn ("can't setsockopt IPV6_CHECKSUM");
  116:   return ret;
  117: }
  118: 
  119: /* Set multicast hops val to the socket. */
  120: int
  121: setsockopt_ipv6_multicast_hops (int sock, int val)
  122: {
  123:   int ret;
  124: 
  125:   ret = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val));
  126:   if (ret < 0)
  127:     zlog_warn ("can't setsockopt IPV6_MULTICAST_HOPS");
  128:   return ret;
  129: }
  130: 
  131: /* Set multicast hops val to the socket. */
  132: int
  133: setsockopt_ipv6_unicast_hops (int sock, int val)
  134: {
  135:   int ret;
  136: 
  137:   ret = setsockopt(sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val));
  138:   if (ret < 0)
  139:     zlog_warn ("can't setsockopt IPV6_UNICAST_HOPS");
  140:   return ret;
  141: }
  142: 
  143: int
  144: setsockopt_ipv6_hoplimit (int sock, int val)
  145: {
  146:   int ret;
  147: 
  148: #ifdef IPV6_RECVHOPLIMIT	/*2292bis-01*/
  149:   ret = setsockopt (sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &val, sizeof(val));
  150:   if (ret < 0)
  151:     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:   return ret;
  158: }
  159: 
  160: /* Set multicast loop zero to the socket. */
  161: int
  162: setsockopt_ipv6_multicast_loop (int sock, int val)
  163: {
  164:   int ret;
  165:     
  166:   ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &val,
  167: 		    sizeof (val));
  168:   if (ret < 0)
  169:     zlog_warn ("can't setsockopt IPV6_MULTICAST_LOOP");
  170:   return ret;
  171: }
  172: 
  173: static int
  174: getsockopt_ipv6_ifindex (struct msghdr *msgh)
  175: {
  176:   struct in6_pktinfo *pktinfo;
  177:   
  178:   pktinfo = getsockopt_cmsg_data (msgh, IPPROTO_IPV6, IPV6_PKTINFO);
  179:   
  180:   return pktinfo->ipi6_ifindex;
  181: }
  182: 
  183: int
  184: setsockopt_ipv6_tclass(int sock, int tclass)
  185: {
  186:   int ret = 0;
  187: 
  188: #ifdef IPV6_TCLASS /* RFC3542 */
  189:   ret = setsockopt (sock, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof (tclass));
  190:   if (ret < 0)
  191:     zlog_warn ("Can't set IPV6_TCLASS option for fd %d to %#x: %s",
  192: 	       sock, tclass, safe_strerror(errno));
  193: #endif
  194:   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: setsockopt_ipv4_multicast(int sock,
  221: 			int optname, 
  222: 			unsigned int mcast_addr,
  223: 			ifindex_t ifindex)
  224: {
  225: #ifdef HAVE_RFC3678
  226:   struct group_req gr;
  227:   struct sockaddr_in *si;
  228:   int ret;
  229:   memset (&gr, 0, sizeof(gr));
  230:   si = (struct sockaddr_in *)&gr.gr_group;
  231:   gr.gr_interface = ifindex;
  232:   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:   si->sin_addr.s_addr = mcast_addr;
  237:   ret = setsockopt(sock, IPPROTO_IP, (optname == IP_ADD_MEMBERSHIP) ? 
  238:     MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
  239:   if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
  240:     {
  241:       setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
  242:       ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, sizeof(gr));
  243:     }
  244:   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: setsockopt_ipv4_multicast_if(int sock, ifindex_t ifindex)
  322: {
  323: 
  324: #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
  325:   struct ip_mreqn mreqn;
  326:   memset (&mreqn, 0, sizeof(mreqn));
  327: 
  328:   mreqn.imr_ifindex = ifindex;
  329:   return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, sizeof(mreqn));
  330: 
  331:   /* Example defines for another OS, boilerplate off other code in this
  332:      function */
  333:   /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
  334:   /* Add your favourite OS here! */
  335: #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK)
  336:   struct in_addr m;
  337: 
  338:   m.s_addr = htonl(ifindex);
  339: 
  340:   return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m));
  341: #else
  342:   #error "Unsupported multicast API"
  343: #endif
  344: }
  345:   
  346: static int
  347: setsockopt_ipv4_ifindex (int sock, ifindex_t val)
  348: {
  349:   int ret;
  350: 
  351: #if defined (IP_PKTINFO)
  352:   if ((ret = setsockopt (sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val))) < 0)
  353:     zlog_warn ("Can't set IP_PKTINFO option for fd %d to %d: %s",
  354: 	       sock,val,safe_strerror(errno));
  355: #elif defined (IP_RECVIF)
  356:   if ((ret = setsockopt (sock, IPPROTO_IP, IP_RECVIF, &val, sizeof (val))) < 0)
  357:     zlog_warn ("Can't set IP_RECVIF option for fd %d to %d: %s",
  358: 	       sock,val,safe_strerror(errno));
  359: #else
  360: #warning "Neither IP_PKTINFO nor IP_RECVIF is available."
  361: #warning "Will not be able to receive link info."
  362: #warning "Things might be seriously broken.."
  363:   /* XXX Does this ever happen?  Should there be a zlog_warn message here? */
  364:   ret = -1;
  365: #endif
  366:   return ret;
  367: }
  368: 
  369: int
  370: setsockopt_ipv4_tos(int sock, int tos)
  371: {
  372:   int ret;
  373: 
  374:   ret = setsockopt (sock, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
  375:   if (ret < 0)
  376:     zlog_warn ("Can't set IP_TOS option for fd %d to %#x: %s",
  377: 	       sock, tos, safe_strerror(errno));
  378:   return ret;
  379: }
  380: 
  381: 
  382: int
  383: setsockopt_ifindex (int af, int sock, ifindex_t val)
  384: {
  385:   int ret = -1;
  386:   
  387:   switch (af)
  388:     {
  389:       case AF_INET:
  390:         ret = setsockopt_ipv4_ifindex (sock, val);
  391:         break;
  392: #ifdef HAVE_IPV6
  393:       case AF_INET6:
  394:         ret = setsockopt_ipv6_pktinfo (sock, val);
  395:         break;
  396: #endif
  397:       default:
  398:         zlog_warn ("setsockopt_ifindex: unknown address family %d", af);
  399:     }
  400:   return ret;
  401: }
  402:   
  403: /*
  404:  * Requires: msgh is not NULL and points to a valid struct msghdr, which
  405:  * may or may not have control data about the incoming interface.
  406:  *
  407:  * Returns the interface index (small integer >= 1) if it can be
  408:  * determined, or else 0.
  409:  */
  410: static ifindex_t
  411: getsockopt_ipv4_ifindex (struct msghdr *msgh)
  412: {
  413:   /* XXX: initialize to zero?  (Always overwritten, so just cosmetic.) */
  414:   ifindex_t ifindex = -1;
  415: 
  416: #if defined(IP_PKTINFO)
  417: /* Linux pktinfo based ifindex retrieval */
  418:   struct in_pktinfo *pktinfo;
  419:   
  420:   pktinfo = 
  421:     (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
  422:   /* XXX Can pktinfo be NULL?  Clean up post 0.98. */
  423:   ifindex = pktinfo->ipi_ifindex;
  424:   
  425: #elif defined(IP_RECVIF)
  426: 
  427:   /* retrieval based on IP_RECVIF */
  428: 
  429: #ifndef SUNOS_5
  430:   /* BSD systems use a sockaddr_dl as the control message payload. */
  431:   struct sockaddr_dl *sdl;
  432: #else
  433:   /* SUNOS_5 uses an integer with the index. */
  434:   ifindex_t *ifindex_p;
  435: #endif /* SUNOS_5 */
  436: 
  437: #ifndef SUNOS_5
  438:   /* BSD */
  439:   sdl = 
  440:     (struct sockaddr_dl *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF);
  441:   if (sdl != NULL)
  442:     ifindex = sdl->sdl_index;
  443:   else
  444:     ifindex = 0;
  445: #else
  446:   /*
  447:    * Solaris.  On Solaris 8, IP_RECVIF is defined, but the call to
  448:    * enable it fails with errno=99, and the struct msghdr has
  449:    * controllen 0.
  450:    */
  451:   ifindex_p = (uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); 
  452:   if (ifindex_p != NULL)
  453:     ifindex = *ifindex_p;
  454:   else
  455:     ifindex = 0;
  456: #endif /* SUNOS_5 */
  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:   return ifindex;
  472: }
  473: 
  474: /* return ifindex, 0 if none found */
  475: ifindex_t
  476: getsockopt_ifindex (int af, struct msghdr *msgh)
  477: {
  478:   switch (af)
  479:     {
  480:       case AF_INET:
  481:         return (getsockopt_ipv4_ifindex (msgh));
  482:         break;
  483: #ifdef HAVE_IPV6
  484:       case AF_INET6:
  485:         return (getsockopt_ipv6_ifindex (msgh));
  486:         break;
  487: #endif
  488:       default:
  489:         zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
  490:         return 0;
  491:     }
  492: }
  493: 
  494: /* swab iph between order system uses for IP_HDRINCL and host order */
  495: void
  496: sockopt_iphdrincl_swab_htosys (struct ip *iph)
  497: {
  498:   /* BSD and derived take iph in network order, except for 
  499:    * ip_len and ip_off
  500:    */
  501: #ifndef HAVE_IP_HDRINCL_BSD_ORDER
  502:   iph->ip_len = htons(iph->ip_len);
  503:   iph->ip_off = htons(iph->ip_off);
  504: #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
  505: 
  506:   iph->ip_id = htons(iph->ip_id);
  507: }
  508: 
  509: void
  510: sockopt_iphdrincl_swab_systoh (struct ip *iph)
  511: {
  512: #ifndef HAVE_IP_HDRINCL_BSD_ORDER
  513:   iph->ip_len = ntohs(iph->ip_len);
  514:   iph->ip_off = ntohs(iph->ip_off);
  515: #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
  516: 
  517:   iph->ip_id = ntohs(iph->ip_id);
  518: }
  519: 
  520: int
  521: sockopt_tcp_rtt (int sock)
  522: {
  523: #ifdef TCP_INFO
  524:   struct tcp_info ti;
  525:   socklen_t len = sizeof(ti);
  526: 
  527:   if (getsockopt (sock, IPPROTO_TCP, TCP_INFO, &ti, &len) != 0)
  528:     return 0;
  529: 
  530:   return ti.tcpi_rtt / 1000;
  531: #else
  532:   return 0;
  533: #endif
  534: }
  535: 
  536: int
  537: sockopt_tcp_signature (int sock, union sockunion *su, const char *password)
  538: {
  539: #if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
  540:   /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
  541:    * version of the Quagga patch (based on work by Rick Payne, and Bruce
  542:    * Simpson)
  543:    */
  544: #define TCP_MD5_AUTH 13
  545: #define TCP_MD5_AUTH_ADD 1
  546: #define TCP_MD5_AUTH_DEL 2
  547:   struct tcp_rfc2385_cmd {
  548:     u_int8_t     command;    /* Command - Add/Delete */
  549:     u_int32_t    address;    /* IPV4 address associated */
  550:     u_int8_t     keylen;     /* MD5 Key len (do NOT assume 0 terminated ascii) */
  551:     void         *key;       /* MD5 Key */
  552:   } cmd;
  553:   struct in_addr *addr = &su->sin.sin_addr;
  554:   
  555:   cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
  556:   cmd.address = addr->s_addr;
  557:   cmd.keylen = (password != NULL ? strlen (password) : 0);
  558:   cmd.key = password;
  559:   
  560:   return setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd);
  561:   
  562: #elif HAVE_DECL_TCP_MD5SIG
  563:   int ret;
  564: #ifndef GNU_LINUX
  565:   /*
  566:    * XXX Need to do PF_KEY operation here to add/remove an SA entry,
  567:    * and add/remove an SP entry for this peer's packet flows also.
  568:    */
  569:   int md5sig = password && *password ? 1 : 0;
  570: #else
  571:   int keylen = password ? strlen (password) : 0;
  572:   struct tcp_md5sig md5sig;
  573:   union sockunion *su2, *susock;
  574:   
  575:   /* Figure out whether the socket and the sockunion are the same family..
  576:    * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think..
  577:    */
  578:   if (!(susock = sockunion_getsockname (sock)))
  579:     return -1;
  580:   
  581:   if (susock->sa.sa_family == su->sa.sa_family)
  582:     su2 = su;
  583:   else
  584:     {
  585:       /* oops.. */
  586:       su2 = susock;
  587:       
  588:       if (su2->sa.sa_family == AF_INET)
  589:         {
  590:           sockunion_free (susock);
  591:           return 0;
  592:         }
  593:       
  594: #ifdef HAVE_IPV6
  595:       /* If this does not work, then all users of this sockopt will need to
  596:        * differentiate between IPv4 and IPv6, and keep seperate sockets for
  597:        * each. 
  598:        *
  599:        * Sadly, it doesn't seem to work at present. It's unknown whether
  600:        * this is a bug or not.
  601:        */
  602:       if (su2->sa.sa_family == AF_INET6
  603:           && su->sa.sa_family == AF_INET)
  604:         {
  605:            su2->sin6.sin6_family = AF_INET6;
  606:            /* V4Map the address */
  607:            memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
  608:            su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
  609:            memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4);
  610:         }
  611: #endif
  612:     }
  613:   
  614:   memset (&md5sig, 0, sizeof (md5sig));
  615:   memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2));
  616:   md5sig.tcpm_keylen = keylen;
  617:   if (keylen)
  618:     memcpy (md5sig.tcpm_key, password, keylen);
  619:   sockunion_free (susock);
  620: #endif /* GNU_LINUX */
  621:   if ((ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig)) < 0)
  622:     {
  623:       /* ENOENT is harmless.  It is returned when we clear a password for which
  624: 	 one was not previously set. */
  625:       if (ENOENT == errno)
  626: 	ret = 0;
  627:       else
  628: 	zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s",
  629: 		  sock, safe_strerror(errno));
  630:     }
  631:   return ret;
  632: #else /* HAVE_TCP_MD5SIG */
  633:   return -2;
  634: #endif /* !HAVE_TCP_MD5SIG */
  635: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>