File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / sockopt.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:12 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_20_1, v0_99_20, HEAD
quagga

    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: #endif /* HAVE_IPV6 */
  183: 
  184: 
  185: /*
  186:  * Process multicast socket options for IPv4 in an OS-dependent manner.
  187:  * Supported options are IP_{ADD,DROP}_MEMBERSHIP.
  188:  *
  189:  * Many operating systems have a limit on the number of groups that
  190:  * can be joined per socket (where each group and local address
  191:  * counts).  This impacts OSPF, which joins groups on each interface
  192:  * using a single socket.  The limit is typically 20, derived from the
  193:  * original BSD multicast implementation.  Some systems have
  194:  * mechanisms for increasing this limit.
  195:  *
  196:  * In many 4.4BSD-derived systems, multicast group operations are not
  197:  * allowed on interfaces that are not UP.  Thus, a previous attempt to
  198:  * leave the group may have failed, leaving it still joined, and we
  199:  * drop/join quietly to recover.  This may not be necessary, but aims to
  200:  * defend against unknown behavior in that we will still return an error
  201:  * if the second join fails.  It is not clear how other systems
  202:  * (e.g. Linux, Solaris) behave when leaving groups on down interfaces,
  203:  * but this behavior should not be harmful if they behave the same way,
  204:  * allow leaves, or implicitly leave all groups joined to down interfaces.
  205:  */
  206: int
  207: setsockopt_ipv4_multicast(int sock,
  208: 			int optname, 
  209: 			unsigned int mcast_addr,
  210: 			unsigned int ifindex)
  211: {
  212: #ifdef HAVE_RFC3678
  213:   struct group_req gr;
  214:   struct sockaddr_in *si;
  215:   int ret;
  216:   memset (&gr, 0, sizeof(gr));
  217:   si = (struct sockaddr_in *)&gr.gr_group;
  218:   gr.gr_interface = ifindex;
  219:   si->sin_family = AF_INET;
  220: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  221:   si->sin_len = sizeof(struct sockaddr_in);
  222: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  223:   si->sin_addr.s_addr = mcast_addr;
  224:   ret = setsockopt(sock, IPPROTO_IP, (optname == IP_ADD_MEMBERSHIP) ? 
  225:     MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
  226:   if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
  227:     {
  228:       setsockopt(sock, IPPROTO_IP, MCAST_LEAVE_GROUP, (void *)&gr, sizeof(gr));
  229:       ret = setsockopt(sock, IPPROTO_IP, MCAST_JOIN_GROUP, (void *)&gr, sizeof(gr));
  230:     }
  231:   return ret;
  232: 
  233: #elif defined(HAVE_STRUCT_IP_MREQN_IMR_IFINDEX) && !defined(__FreeBSD__)
  234:   struct ip_mreqn mreqn;
  235:   int ret;
  236:   
  237:   assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
  238:   memset (&mreqn, 0, sizeof(mreqn));
  239: 
  240:   mreqn.imr_multiaddr.s_addr = mcast_addr;
  241:   mreqn.imr_ifindex = ifindex;
  242:   
  243:   ret = setsockopt(sock, IPPROTO_IP, optname,
  244:                    (void *)&mreqn, sizeof(mreqn));
  245:   if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
  246:     {
  247:       /* see above: handle possible problem when interface comes back up */
  248:       char buf[1][INET_ADDRSTRLEN];
  249:       zlog_info("setsockopt_ipv4_multicast attempting to drop and "
  250:                 "re-add (fd %d, mcast %s, ifindex %u)",
  251:                 sock,
  252:                 inet_ntop(AF_INET, &mreqn.imr_multiaddr,
  253:                           buf[0], sizeof(buf[0])), ifindex);
  254:       setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
  255:                  (void *)&mreqn, sizeof(mreqn));
  256:       ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  257:                        (void *)&mreqn, sizeof(mreqn));
  258:     }
  259:   return ret;
  260: 
  261:   /* Example defines for another OS, boilerplate off other code in this
  262:      function, AND handle optname as per other sections for consistency !! */
  263:   /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
  264:   /* Add your favourite OS here! */
  265: 
  266: #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK) /* #if OS_TYPE */ 
  267:   /* standard BSD API */
  268: 
  269:   struct in_addr m;
  270:   struct ip_mreq mreq;
  271:   int ret;
  272: 
  273:   assert(optname == IP_ADD_MEMBERSHIP || optname == IP_DROP_MEMBERSHIP);
  274: 
  275:   m.s_addr = htonl(ifindex);
  276: 
  277:   memset (&mreq, 0, sizeof(mreq));
  278:   mreq.imr_multiaddr.s_addr = mcast_addr;
  279:   mreq.imr_interface = m;
  280:   
  281:   ret = setsockopt (sock, IPPROTO_IP, optname, (void *)&mreq, sizeof(mreq));
  282:   if ((ret < 0) && (optname == IP_ADD_MEMBERSHIP) && (errno == EADDRINUSE))
  283:     {
  284:       /* see above: handle possible problem when interface comes back up */
  285:       char buf[1][INET_ADDRSTRLEN];
  286:       zlog_info("setsockopt_ipv4_multicast attempting to drop and "
  287:                 "re-add (fd %d, mcast %s, ifindex %u)",
  288:                 sock,
  289:                 inet_ntop(AF_INET, &mreq.imr_multiaddr,
  290:                           buf[0], sizeof(buf[0])), ifindex);
  291:       setsockopt (sock, IPPROTO_IP, IP_DROP_MEMBERSHIP,
  292:                   (void *)&mreq, sizeof(mreq));
  293:       ret = setsockopt (sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  294:                         (void *)&mreq, sizeof(mreq));
  295:     }
  296:   return ret;
  297: 
  298: #else
  299:   #error "Unsupported multicast API"
  300: #endif /* #if OS_TYPE */
  301: 
  302: }
  303: 
  304: /*
  305:  * Set IP_MULTICAST_IF socket option in an OS-dependent manner.
  306:  */
  307: int
  308: setsockopt_ipv4_multicast_if(int sock,
  309: 			unsigned int ifindex)
  310: {
  311: 
  312: #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
  313:   struct ip_mreqn mreqn;
  314:   memset (&mreqn, 0, sizeof(mreqn));
  315: 
  316:   mreqn.imr_ifindex = ifindex;
  317:   return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, sizeof(mreqn));
  318: 
  319:   /* Example defines for another OS, boilerplate off other code in this
  320:      function */
  321:   /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
  322:   /* Add your favourite OS here! */
  323: #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK)
  324:   struct in_addr m;
  325: 
  326:   m.s_addr = htonl(ifindex);
  327: 
  328:   return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m));
  329: #else
  330:   #error "Unsupported multicast API"
  331: #endif
  332: }
  333:   
  334: static int
  335: setsockopt_ipv4_ifindex (int sock, int val)
  336: {
  337:   int ret;
  338: 
  339: #if defined (IP_PKTINFO)
  340:   if ((ret = setsockopt (sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val))) < 0)
  341:     zlog_warn ("Can't set IP_PKTINFO option for fd %d to %d: %s",
  342: 	       sock,val,safe_strerror(errno));
  343: #elif defined (IP_RECVIF)
  344:   if ((ret = setsockopt (sock, IPPROTO_IP, IP_RECVIF, &val, sizeof (val))) < 0)
  345:     zlog_warn ("Can't set IP_RECVIF option for fd %d to %d: %s",
  346: 	       sock,val,safe_strerror(errno));
  347: #else
  348: #warning "Neither IP_PKTINFO nor IP_RECVIF is available."
  349: #warning "Will not be able to receive link info."
  350: #warning "Things might be seriously broken.."
  351:   /* XXX Does this ever happen?  Should there be a zlog_warn message here? */
  352:   ret = -1;
  353: #endif
  354:   return ret;
  355: }
  356: 
  357: int
  358: setsockopt_ipv4_tos(int sock, int tos)
  359: {
  360:   int ret;
  361: 
  362:   ret = setsockopt (sock, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
  363:   if (ret < 0)
  364:     zlog_warn ("Can't set IP_TOS option for fd %d to %#x: %s",
  365: 	       sock, tos, safe_strerror(errno));
  366:   return ret;
  367: }
  368: 
  369: 
  370: int
  371: setsockopt_ifindex (int af, int sock, int val)
  372: {
  373:   int ret = -1;
  374:   
  375:   switch (af)
  376:     {
  377:       case AF_INET:
  378:         ret = setsockopt_ipv4_ifindex (sock, val);
  379:         break;
  380: #ifdef HAVE_IPV6
  381:       case AF_INET6:
  382:         ret = setsockopt_ipv6_pktinfo (sock, val);
  383:         break;
  384: #endif
  385:       default:
  386:         zlog_warn ("setsockopt_ifindex: unknown address family %d", af);
  387:     }
  388:   return ret;
  389: }
  390:   
  391: /*
  392:  * Requires: msgh is not NULL and points to a valid struct msghdr, which
  393:  * may or may not have control data about the incoming interface.
  394:  *
  395:  * Returns the interface index (small integer >= 1) if it can be
  396:  * determined, or else 0.
  397:  */
  398: static int
  399: getsockopt_ipv4_ifindex (struct msghdr *msgh)
  400: {
  401:   /* XXX: initialize to zero?  (Always overwritten, so just cosmetic.) */
  402:   int ifindex = -1;
  403: 
  404: #if defined(IP_PKTINFO)
  405: /* Linux pktinfo based ifindex retrieval */
  406:   struct in_pktinfo *pktinfo;
  407:   
  408:   pktinfo = 
  409:     (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
  410:   /* XXX Can pktinfo be NULL?  Clean up post 0.98. */
  411:   ifindex = pktinfo->ipi_ifindex;
  412:   
  413: #elif defined(IP_RECVIF)
  414: 
  415:   /* retrieval based on IP_RECVIF */
  416: 
  417: #ifndef SUNOS_5
  418:   /* BSD systems use a sockaddr_dl as the control message payload. */
  419:   struct sockaddr_dl *sdl;
  420: #else
  421:   /* SUNOS_5 uses an integer with the index. */
  422:   int *ifindex_p;
  423: #endif /* SUNOS_5 */
  424: 
  425: #ifndef SUNOS_5
  426:   /* BSD */
  427:   sdl = 
  428:     (struct sockaddr_dl *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF);
  429:   if (sdl != NULL)
  430:     ifindex = sdl->sdl_index;
  431:   else
  432:     ifindex = 0;
  433: #else
  434:   /*
  435:    * Solaris.  On Solaris 8, IP_RECVIF is defined, but the call to
  436:    * enable it fails with errno=99, and the struct msghdr has
  437:    * controllen 0.
  438:    */
  439:   ifindex_p = (uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); 
  440:   if (ifindex_p != NULL)
  441:     ifindex = *ifindex_p;
  442:   else
  443:     ifindex = 0;
  444: #endif /* SUNOS_5 */
  445: 
  446: #else
  447:   /*
  448:    * Neither IP_PKTINFO nor IP_RECVIF defined - warn at compile time.
  449:    * XXX Decide if this is a core service, or if daemons have to cope.
  450:    * Since Solaris 8 and OpenBSD seem not to provide it, it seems that
  451:    * daemons have to cope.
  452:    */
  453: #warning "getsockopt_ipv4_ifindex: Neither IP_PKTINFO nor IP_RECVIF defined."
  454: #warning "Some daemons may fail to operate correctly!"
  455:   ifindex = 0;
  456: 
  457: #endif /* IP_PKTINFO */ 
  458: 
  459:   return ifindex;
  460: }
  461: 
  462: /* return ifindex, 0 if none found */
  463: int
  464: getsockopt_ifindex (int af, struct msghdr *msgh)
  465: {
  466:   switch (af)
  467:     {
  468:       case AF_INET:
  469:         return (getsockopt_ipv4_ifindex (msgh));
  470:         break;
  471: #ifdef HAVE_IPV6
  472:       case AF_INET6:
  473:         return (getsockopt_ipv6_ifindex (msgh));
  474:         break;
  475: #endif
  476:       default:
  477:         zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
  478:         return 0;
  479:     }
  480: }
  481: 
  482: /* swab iph between order system uses for IP_HDRINCL and host order */
  483: void
  484: sockopt_iphdrincl_swab_htosys (struct ip *iph)
  485: {
  486:   /* BSD and derived take iph in network order, except for 
  487:    * ip_len and ip_off
  488:    */
  489: #ifndef HAVE_IP_HDRINCL_BSD_ORDER
  490:   iph->ip_len = htons(iph->ip_len);
  491:   iph->ip_off = htons(iph->ip_off);
  492: #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
  493: 
  494:   iph->ip_id = htons(iph->ip_id);
  495: }
  496: 
  497: void
  498: sockopt_iphdrincl_swab_systoh (struct ip *iph)
  499: {
  500: #ifndef HAVE_IP_HDRINCL_BSD_ORDER
  501:   iph->ip_len = ntohs(iph->ip_len);
  502:   iph->ip_off = ntohs(iph->ip_off);
  503: #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
  504: 
  505:   iph->ip_id = ntohs(iph->ip_id);
  506: }
  507: 
  508: int
  509: sockopt_tcp_signature (int sock, union sockunion *su, const char *password)
  510: {
  511: #if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
  512:   /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
  513:    * version of the Quagga patch (based on work by Rick Payne, and Bruce
  514:    * Simpson)
  515:    */
  516: #define TCP_MD5_AUTH 13
  517: #define TCP_MD5_AUTH_ADD 1
  518: #define TCP_MD5_AUTH_DEL 2
  519:   struct tcp_rfc2385_cmd {
  520:     u_int8_t     command;    /* Command - Add/Delete */
  521:     u_int32_t    address;    /* IPV4 address associated */
  522:     u_int8_t     keylen;     /* MD5 Key len (do NOT assume 0 terminated ascii) */
  523:     void         *key;       /* MD5 Key */
  524:   } cmd;
  525:   struct in_addr *addr = &su->sin.sin_addr;
  526:   
  527:   cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
  528:   cmd.address = addr->s_addr;
  529:   cmd.keylen = (password != NULL ? strlen (password) : 0);
  530:   cmd.key = password;
  531:   
  532:   return setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd);
  533:   
  534: #elif HAVE_DECL_TCP_MD5SIG
  535:   int ret;
  536: #ifndef GNU_LINUX
  537:   /*
  538:    * XXX Need to do PF_KEY operation here to add/remove an SA entry,
  539:    * and add/remove an SP entry for this peer's packet flows also.
  540:    */
  541:   int md5sig = password && *password ? 1 : 0;
  542: #else
  543:   int keylen = password ? strlen (password) : 0;
  544:   struct tcp_md5sig md5sig;
  545:   union sockunion *su2, *susock;
  546:   
  547:   /* Figure out whether the socket and the sockunion are the same family..
  548:    * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think..
  549:    */
  550:   if (!(susock = sockunion_getsockname (sock)))
  551:     return -1;
  552:   
  553:   if (susock->sa.sa_family == su->sa.sa_family)
  554:     su2 = su;
  555:   else
  556:     {
  557:       /* oops.. */
  558:       su2 = susock;
  559:       
  560:       if (su2->sa.sa_family == AF_INET)
  561:         {
  562:           sockunion_free (susock);
  563:           return 0;
  564:         }
  565:       
  566: #ifdef HAVE_IPV6
  567:       /* If this does not work, then all users of this sockopt will need to
  568:        * differentiate between IPv4 and IPv6, and keep seperate sockets for
  569:        * each. 
  570:        *
  571:        * Sadly, it doesn't seem to work at present. It's unknown whether
  572:        * this is a bug or not.
  573:        */
  574:       if (su2->sa.sa_family == AF_INET6
  575:           && su->sa.sa_family == AF_INET)
  576:         {
  577:            su2->sin6.sin6_family = AF_INET6;
  578:            /* V4Map the address */
  579:            memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
  580:            su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
  581:            memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4);
  582:         }
  583: #endif
  584:     }
  585:   
  586:   memset (&md5sig, 0, sizeof (md5sig));
  587:   memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2));
  588:   md5sig.tcpm_keylen = keylen;
  589:   if (keylen)
  590:     memcpy (md5sig.tcpm_key, password, keylen);
  591:   sockunion_free (susock);
  592: #endif /* GNU_LINUX */
  593:   if ((ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig)) < 0)
  594:     {
  595:       /* ENOENT is harmless.  It is returned when we clear a password for which
  596: 	 one was not previously set. */
  597:       if (ENOENT == errno)
  598: 	ret = 0;
  599:       else
  600: 	zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s",
  601: 		  sock, safe_strerror(errno));
  602:     }
  603:   return ret;
  604: #else /* HAVE_TCP_MD5SIG */
  605:   return -2;
  606: #endif /* !HAVE_TCP_MD5SIG */
  607: }

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