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

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,
1.1.1.3 ! misho     223:                        ifindex_t ifindex)
1.1       misho     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
1.1.1.3 ! misho     321: setsockopt_ipv4_multicast_if(int sock, ifindex_t ifindex)
1.1       misho     322: {
                    323: 
                    324: #ifdef HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
                    325:   struct ip_mreqn mreqn;
                    326:   memset (&mreqn, 0, sizeof(mreqn));
                    327: 
                    328:   mreqn.imr_ifindex = ifindex;
                    329:   return setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, sizeof(mreqn));
                    330: 
                    331:   /* Example defines for another OS, boilerplate off other code in this
                    332:      function */
                    333:   /* #elif  defined(BOGON_NIX) && EXAMPLE_VERSION_CODE > -100000 */
                    334:   /* Add your favourite OS here! */
                    335: #elif defined(HAVE_BSD_STRUCT_IP_MREQ_HACK)
                    336:   struct in_addr m;
                    337: 
                    338:   m.s_addr = htonl(ifindex);
                    339: 
                    340:   return setsockopt (sock, IPPROTO_IP, IP_MULTICAST_IF, (void *)&m, sizeof(m));
                    341: #else
                    342:   #error "Unsupported multicast API"
                    343: #endif
                    344: }
                    345:   
                    346: static int
1.1.1.3 ! misho     347: setsockopt_ipv4_ifindex (int sock, ifindex_t val)
1.1       misho     348: {
                    349:   int ret;
                    350: 
                    351: #if defined (IP_PKTINFO)
                    352:   if ((ret = setsockopt (sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof (val))) < 0)
                    353:     zlog_warn ("Can't set IP_PKTINFO option for fd %d to %d: %s",
                    354:               sock,val,safe_strerror(errno));
                    355: #elif defined (IP_RECVIF)
                    356:   if ((ret = setsockopt (sock, IPPROTO_IP, IP_RECVIF, &val, sizeof (val))) < 0)
                    357:     zlog_warn ("Can't set IP_RECVIF option for fd %d to %d: %s",
                    358:               sock,val,safe_strerror(errno));
                    359: #else
                    360: #warning "Neither IP_PKTINFO nor IP_RECVIF is available."
                    361: #warning "Will not be able to receive link info."
                    362: #warning "Things might be seriously broken.."
                    363:   /* XXX Does this ever happen?  Should there be a zlog_warn message here? */
                    364:   ret = -1;
                    365: #endif
                    366:   return ret;
                    367: }
                    368: 
                    369: int
                    370: setsockopt_ipv4_tos(int sock, int tos)
                    371: {
                    372:   int ret;
                    373: 
                    374:   ret = setsockopt (sock, IPPROTO_IP, IP_TOS, &tos, sizeof (tos));
                    375:   if (ret < 0)
                    376:     zlog_warn ("Can't set IP_TOS option for fd %d to %#x: %s",
                    377:               sock, tos, safe_strerror(errno));
                    378:   return ret;
                    379: }
                    380: 
                    381: 
                    382: int
1.1.1.3 ! misho     383: setsockopt_ifindex (int af, int sock, ifindex_t val)
1.1       misho     384: {
                    385:   int ret = -1;
                    386:   
                    387:   switch (af)
                    388:     {
                    389:       case AF_INET:
                    390:         ret = setsockopt_ipv4_ifindex (sock, val);
                    391:         break;
                    392: #ifdef HAVE_IPV6
                    393:       case AF_INET6:
                    394:         ret = setsockopt_ipv6_pktinfo (sock, val);
                    395:         break;
                    396: #endif
                    397:       default:
                    398:         zlog_warn ("setsockopt_ifindex: unknown address family %d", af);
                    399:     }
                    400:   return ret;
                    401: }
                    402:   
                    403: /*
                    404:  * Requires: msgh is not NULL and points to a valid struct msghdr, which
                    405:  * may or may not have control data about the incoming interface.
                    406:  *
                    407:  * Returns the interface index (small integer >= 1) if it can be
                    408:  * determined, or else 0.
                    409:  */
1.1.1.3 ! misho     410: static ifindex_t
1.1       misho     411: getsockopt_ipv4_ifindex (struct msghdr *msgh)
                    412: {
                    413:   /* XXX: initialize to zero?  (Always overwritten, so just cosmetic.) */
1.1.1.3 ! misho     414:   ifindex_t ifindex = -1;
1.1       misho     415: 
                    416: #if defined(IP_PKTINFO)
                    417: /* Linux pktinfo based ifindex retrieval */
                    418:   struct in_pktinfo *pktinfo;
                    419:   
                    420:   pktinfo = 
                    421:     (struct in_pktinfo *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_PKTINFO);
                    422:   /* XXX Can pktinfo be NULL?  Clean up post 0.98. */
                    423:   ifindex = pktinfo->ipi_ifindex;
                    424:   
                    425: #elif defined(IP_RECVIF)
                    426: 
                    427:   /* retrieval based on IP_RECVIF */
                    428: 
                    429: #ifndef SUNOS_5
                    430:   /* BSD systems use a sockaddr_dl as the control message payload. */
                    431:   struct sockaddr_dl *sdl;
                    432: #else
                    433:   /* SUNOS_5 uses an integer with the index. */
1.1.1.3 ! misho     434:   ifindex_t *ifindex_p;
1.1       misho     435: #endif /* SUNOS_5 */
                    436: 
                    437: #ifndef SUNOS_5
                    438:   /* BSD */
                    439:   sdl = 
                    440:     (struct sockaddr_dl *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF);
                    441:   if (sdl != NULL)
                    442:     ifindex = sdl->sdl_index;
                    443:   else
                    444:     ifindex = 0;
                    445: #else
                    446:   /*
                    447:    * Solaris.  On Solaris 8, IP_RECVIF is defined, but the call to
                    448:    * enable it fails with errno=99, and the struct msghdr has
                    449:    * controllen 0.
                    450:    */
                    451:   ifindex_p = (uint_t *)getsockopt_cmsg_data (msgh, IPPROTO_IP, IP_RECVIF); 
                    452:   if (ifindex_p != NULL)
                    453:     ifindex = *ifindex_p;
                    454:   else
                    455:     ifindex = 0;
                    456: #endif /* SUNOS_5 */
                    457: 
                    458: #else
                    459:   /*
                    460:    * Neither IP_PKTINFO nor IP_RECVIF defined - warn at compile time.
                    461:    * XXX Decide if this is a core service, or if daemons have to cope.
                    462:    * Since Solaris 8 and OpenBSD seem not to provide it, it seems that
                    463:    * daemons have to cope.
                    464:    */
                    465: #warning "getsockopt_ipv4_ifindex: Neither IP_PKTINFO nor IP_RECVIF defined."
                    466: #warning "Some daemons may fail to operate correctly!"
                    467:   ifindex = 0;
                    468: 
                    469: #endif /* IP_PKTINFO */ 
                    470: 
                    471:   return ifindex;
                    472: }
                    473: 
                    474: /* return ifindex, 0 if none found */
1.1.1.3 ! misho     475: ifindex_t
1.1       misho     476: getsockopt_ifindex (int af, struct msghdr *msgh)
                    477: {
                    478:   switch (af)
                    479:     {
                    480:       case AF_INET:
                    481:         return (getsockopt_ipv4_ifindex (msgh));
                    482:         break;
                    483: #ifdef HAVE_IPV6
                    484:       case AF_INET6:
                    485:         return (getsockopt_ipv6_ifindex (msgh));
                    486:         break;
                    487: #endif
                    488:       default:
                    489:         zlog_warn ("getsockopt_ifindex: unknown address family %d", af);
                    490:         return 0;
                    491:     }
                    492: }
                    493: 
                    494: /* swab iph between order system uses for IP_HDRINCL and host order */
                    495: void
                    496: sockopt_iphdrincl_swab_htosys (struct ip *iph)
                    497: {
                    498:   /* BSD and derived take iph in network order, except for 
                    499:    * ip_len and ip_off
                    500:    */
                    501: #ifndef HAVE_IP_HDRINCL_BSD_ORDER
                    502:   iph->ip_len = htons(iph->ip_len);
                    503:   iph->ip_off = htons(iph->ip_off);
                    504: #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
                    505: 
                    506:   iph->ip_id = htons(iph->ip_id);
                    507: }
                    508: 
                    509: void
                    510: sockopt_iphdrincl_swab_systoh (struct ip *iph)
                    511: {
                    512: #ifndef HAVE_IP_HDRINCL_BSD_ORDER
                    513:   iph->ip_len = ntohs(iph->ip_len);
                    514:   iph->ip_off = ntohs(iph->ip_off);
                    515: #endif /* HAVE_IP_HDRINCL_BSD_ORDER */
                    516: 
                    517:   iph->ip_id = ntohs(iph->ip_id);
1.1.1.3 ! misho     518: }
        !           519: 
        !           520: int
        !           521: sockopt_tcp_rtt (int sock)
        !           522: {
        !           523: #ifdef TCP_INFO
        !           524:   struct tcp_info ti;
        !           525:   socklen_t len = sizeof(ti);
        !           526: 
        !           527:   if (getsockopt (sock, IPPROTO_TCP, TCP_INFO, &ti, &len) != 0)
        !           528:     return 0;
        !           529: 
        !           530:   return ti.tcpi_rtt / 1000;
        !           531: #else
        !           532:   return 0;
        !           533: #endif
1.1       misho     534: }
                    535: 
                    536: int
                    537: sockopt_tcp_signature (int sock, union sockunion *su, const char *password)
                    538: {
                    539: #if defined(HAVE_TCP_MD5_LINUX24) && defined(GNU_LINUX)
                    540:   /* Support for the old Linux 2.4 TCP-MD5 patch, taken from Hasso Tepper's
                    541:    * version of the Quagga patch (based on work by Rick Payne, and Bruce
                    542:    * Simpson)
                    543:    */
                    544: #define TCP_MD5_AUTH 13
                    545: #define TCP_MD5_AUTH_ADD 1
                    546: #define TCP_MD5_AUTH_DEL 2
                    547:   struct tcp_rfc2385_cmd {
                    548:     u_int8_t     command;    /* Command - Add/Delete */
                    549:     u_int32_t    address;    /* IPV4 address associated */
                    550:     u_int8_t     keylen;     /* MD5 Key len (do NOT assume 0 terminated ascii) */
                    551:     void         *key;       /* MD5 Key */
                    552:   } cmd;
                    553:   struct in_addr *addr = &su->sin.sin_addr;
                    554:   
                    555:   cmd.command = (password != NULL ? TCP_MD5_AUTH_ADD : TCP_MD5_AUTH_DEL);
                    556:   cmd.address = addr->s_addr;
                    557:   cmd.keylen = (password != NULL ? strlen (password) : 0);
                    558:   cmd.key = password;
                    559:   
                    560:   return setsockopt (sock, IPPROTO_TCP, TCP_MD5_AUTH, &cmd, sizeof cmd);
                    561:   
                    562: #elif HAVE_DECL_TCP_MD5SIG
                    563:   int ret;
                    564: #ifndef GNU_LINUX
                    565:   /*
                    566:    * XXX Need to do PF_KEY operation here to add/remove an SA entry,
                    567:    * and add/remove an SP entry for this peer's packet flows also.
                    568:    */
                    569:   int md5sig = password && *password ? 1 : 0;
                    570: #else
                    571:   int keylen = password ? strlen (password) : 0;
                    572:   struct tcp_md5sig md5sig;
                    573:   union sockunion *su2, *susock;
                    574:   
                    575:   /* Figure out whether the socket and the sockunion are the same family..
                    576:    * adding AF_INET to AF_INET6 needs to be v4 mapped, you'd think..
                    577:    */
                    578:   if (!(susock = sockunion_getsockname (sock)))
                    579:     return -1;
                    580:   
                    581:   if (susock->sa.sa_family == su->sa.sa_family)
                    582:     su2 = su;
                    583:   else
                    584:     {
                    585:       /* oops.. */
                    586:       su2 = susock;
                    587:       
                    588:       if (su2->sa.sa_family == AF_INET)
                    589:         {
                    590:           sockunion_free (susock);
                    591:           return 0;
                    592:         }
                    593:       
                    594: #ifdef HAVE_IPV6
                    595:       /* If this does not work, then all users of this sockopt will need to
                    596:        * differentiate between IPv4 and IPv6, and keep seperate sockets for
                    597:        * each. 
                    598:        *
                    599:        * Sadly, it doesn't seem to work at present. It's unknown whether
                    600:        * this is a bug or not.
                    601:        */
                    602:       if (su2->sa.sa_family == AF_INET6
                    603:           && su->sa.sa_family == AF_INET)
                    604:         {
                    605:            su2->sin6.sin6_family = AF_INET6;
                    606:            /* V4Map the address */
                    607:            memset (&su2->sin6.sin6_addr, 0, sizeof (struct in6_addr));
                    608:            su2->sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
                    609:            memcpy (&su2->sin6.sin6_addr.s6_addr32[3], &su->sin.sin_addr, 4);
                    610:         }
                    611: #endif
                    612:     }
                    613:   
                    614:   memset (&md5sig, 0, sizeof (md5sig));
                    615:   memcpy (&md5sig.tcpm_addr, su2, sizeof (*su2));
                    616:   md5sig.tcpm_keylen = keylen;
                    617:   if (keylen)
                    618:     memcpy (md5sig.tcpm_key, password, keylen);
                    619:   sockunion_free (susock);
                    620: #endif /* GNU_LINUX */
                    621:   if ((ret = setsockopt (sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof md5sig)) < 0)
                    622:     {
                    623:       /* ENOENT is harmless.  It is returned when we clear a password for which
                    624:         one was not previously set. */
                    625:       if (ENOENT == errno)
                    626:        ret = 0;
                    627:       else
                    628:        zlog_err ("sockopt_tcp_signature: setsockopt(%d): %s",
                    629:                  sock, safe_strerror(errno));
                    630:     }
                    631:   return ret;
                    632: #else /* HAVE_TCP_MD5SIG */
                    633:   return -2;
                    634: #endif /* !HAVE_TCP_MD5SIG */
                    635: }

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