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>