Annotation of embedaddon/quagga/lib/sockopt.c, revision 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>