Annotation of embedaddon/quagga/lib/sockopt.c, revision 1.1.1.1

1.1       misho       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>