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

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: 
1.1.1.2 ! misho     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 */
1.1       misho     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:                        unsigned int 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,
                    322:                        unsigned int ifindex)
                    323: {
                    324: 
                    325: #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
                    326:   struct ip_mreqn mreqn;
                    327:   memset (&mreqn, 0, sizeof(mreqn));
                    328: 
                    329:   mreqn.imr_ifindex = ifindex;
                    330:   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: setsockopt_ipv4_ifindex (int sock, int val)
                    349: {
                    350:   int ret;
                    351: 
                    352: #if defined (IP_PKTINFO)
                    353:   if ((ret = setsockopt (sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val))) < 0)
                    354:     zlog_warn ("Can't set IP_PKTINFO option for fd %d to %d: %s",
                    355:               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:   return ret;
                    368: }
                    369: 
                    370: int
                    371: setsockopt_ipv4_tos(int sock, int tos)
                    372: {
                    373:   int ret;
                    374: 
                    375:   ret = setsockopt (sock, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
                    376:   if (ret < 0)
                    377:     zlog_warn ("Can't set IP_TOS option for fd %d to %#x: %s",
                    378:               sock, tos, safe_strerror(errno));
                    379:   return ret;
                    380: }
                    381: 
                    382: 
                    383: int
                    384: setsockopt_ifindex (int af, int sock, int val)
                    385: {
                    386:   int ret = -1;
                    387:   
                    388:   switch (af)
                    389:     {
                    390:       case AF_INET:
                    391:         ret = setsockopt_ipv4_ifindex (sock, val);
                    392:         break;
                    393: #ifdef HAVE_IPV6
                    394:       case AF_INET6:
                    395:         ret = setsockopt_ipv6_pktinfo (sock, val);
                    396:         break;
                    397: #endif
                    398:       default:
                    399:         zlog_warn ("setsockopt_ifindex: unknown address family %d", af);
                    400:     }
                    401:   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: getsockopt_ipv4_ifindex (struct msghdr *msgh)
                    413: {
                    414:   /* XXX: initialize to zero?  (Always overwritten, so just cosmetic.) */
                    415:   int ifindex = -1;
                    416: 
                    417: #if defined(IP_PKTINFO)
                    418: /* Linux pktinfo based ifindex retrieval */
                    419:   struct in_pktinfo *pktinfo;
                    420:   
                    421:   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:   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:   return ifindex;
                    473: }
                    474: 
                    475: /* return ifindex, 0 if none found */
                    476: int
                    477: getsockopt_ifindex (int af, struct msghdr *msgh)
                    478: {
                    479:   switch (af)
                    480:     {
                    481:       case AF_INET:
                    482:         return (getsockopt_ipv4_ifindex (msgh));
                    483:         break;
                    484: #ifdef HAVE_IPV6
                    485:       case AF_INET6:
                    486:         return (getsockopt_ipv6_ifindex (msgh));
                    487:         break;
                    488: #endif
                    489:       default:
                    490:         zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
                    491:         return 0;
                    492:     }
                    493: }
                    494: 
                    495: /* swab iph between order system uses for IP_HDRINCL and host order */
                    496: void
                    497: 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:   iph->ip_len = htons(iph->ip_len);
                    504:   iph->ip_off = htons(iph->ip_off);
                    505: #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
                    506: 
                    507:   iph->ip_id = htons(iph->ip_id);
                    508: }
                    509: 
                    510: void
                    511: sockopt_iphdrincl_swab_systoh (struct ip *iph)
                    512: {
                    513: #ifndef HAVE_IP_HDRINCL_BSD_ORDER
                    514:   iph->ip_len = ntohs(iph->ip_len);
                    515:   iph->ip_off = ntohs(iph->ip_off);
                    516: #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
                    517: 
                    518:   iph->ip_id = ntohs(iph->ip_id);
                    519: }
                    520: 
                    521: int
                    522: 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:   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:   if (!(susock = sockunion_getsockname (sock)))
                    564:     return -1;
                    565:   
                    566:   if (susock->sa.sa_family == su->sa.sa_family)
                    567:     su2 = su;
                    568:   else
                    569:     {
                    570:       /* oops.. */
                    571:       su2 = susock;
                    572:       
                    573:       if (su2->sa.sa_family == AF_INET)
                    574:         {
                    575:           sockunion_free (susock);
                    576:           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:       if (su2->sa.sa_family == AF_INET6
                    588:           && su->sa.sa_family == AF_INET)
                    589:         {
                    590:            su2->sin6.sin6_family = AF_INET6;
                    591:            /* V4Map the address */
                    592:            memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
                    593:            su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
                    594:            memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4);
                    595:         }
                    596: #endif
                    597:     }
                    598:   
                    599:   memset (&md5sig, 0, sizeof (md5sig));
                    600:   memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2));
                    601:   md5sig.tcpm_keylen = keylen;
                    602:   if (keylen)
                    603:     memcpy (md5sig.tcpm_key, password, keylen);
                    604:   sockunion_free (susock);
                    605: #endif /* GNU_LINUX */
                    606:   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:       if (ENOENT == errno)
                    611:        ret = 0;
                    612:       else
                    613:        zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s",
                    614:                  sock, safe_strerror(errno));
                    615:     }
                    616:   return ret;
                    617: #else /* HAVE_TCP_MD5SIG */
                    618:   return -2;
                    619: #endif /* !HAVE_TCP_MD5SIG */
                    620: }

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