File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / lib / sockunion.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:22:28 2012 UTC (11 years, 9 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_21, HEAD
quagga

    1: /* Socket union related function.
    2:  * Copyright (c) 1997, 98 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: 
   24: #include "prefix.h"
   25: #include "vty.h"
   26: #include "sockunion.h"
   27: #include "memory.h"
   28: #include "str.h"
   29: #include "log.h"
   30: 
   31: #ifndef HAVE_INET_ATON
   32: int
   33: inet_aton (const char *cp, struct in_addr *inaddr)
   34: {
   35:   int dots = 0;
   36:   register u_long addr = 0;
   37:   register u_long val = 0, base = 10;
   38: 
   39:   do
   40:     {
   41:       register char c = *cp;
   42: 
   43:       switch (c)
   44: 	{
   45: 	case '0': case '1': case '2': case '3': case '4': case '5':
   46: 	case '6': case '7': case '8': case '9':
   47: 	  val = (val * base) + (c - '0');
   48: 	  break;
   49: 	case '.':
   50: 	  if (++dots > 3)
   51: 	    return 0;
   52: 	case '\0':
   53: 	  if (val > 255)
   54: 	    return 0;
   55: 	  addr = addr << 8 | val;
   56: 	  val = 0;
   57: 	  break;
   58: 	default:
   59: 	  return 0;
   60: 	}
   61:     } while (*cp++) ;
   62: 
   63:   if (dots < 3)
   64:     addr <<= 8 * (3 - dots);
   65:   if (inaddr)
   66:     inaddr->s_addr = htonl (addr);
   67:   return 1;
   68: }
   69: #endif /* ! HAVE_INET_ATON */
   70: 
   71: 
   72: #ifndef HAVE_INET_PTON
   73: int
   74: inet_pton (int family, const char *strptr, void *addrptr)
   75: {
   76:   if (family == AF_INET)
   77:     {
   78:       struct in_addr in_val;
   79: 
   80:       if (inet_aton (strptr, &in_val))
   81: 	{
   82: 	  memcpy (addrptr, &in_val, sizeof (struct in_addr));
   83: 	  return 1;
   84: 	}
   85:       return 0;
   86:     }
   87:   errno = EAFNOSUPPORT;
   88:   return -1;
   89: }
   90: #endif /* ! HAVE_INET_PTON */
   91: 
   92: #ifndef HAVE_INET_NTOP
   93: const char *
   94: inet_ntop (int family, const void *addrptr, char *strptr, size_t len)
   95: {
   96:   unsigned char *p = (unsigned char *) addrptr;
   97: 
   98:   if (family == AF_INET) 
   99:     {
  100:       char temp[INET_ADDRSTRLEN];
  101: 
  102:       snprintf(temp, sizeof(temp), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
  103: 
  104:       if (strlen(temp) >= len) 
  105: 	{
  106: 	  errno = ENOSPC;
  107: 	  return NULL;
  108: 	}
  109:       strcpy(strptr, temp);
  110:       return strptr;
  111:     }
  112: 
  113:   errno = EAFNOSUPPORT;
  114:   return NULL;
  115: }
  116: #endif /* ! HAVE_INET_NTOP */
  117: 
  118: const char *
  119: inet_sutop (union sockunion *su, char *str)
  120: {
  121:   switch (su->sa.sa_family)
  122:     {
  123:     case AF_INET:
  124:       inet_ntop (AF_INET, &su->sin.sin_addr, str, INET_ADDRSTRLEN);
  125:       break;
  126: #ifdef HAVE_IPV6
  127:     case AF_INET6:
  128:       inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, INET6_ADDRSTRLEN);
  129:       break;
  130: #endif /* HAVE_IPV6 */
  131:     }
  132:   return str;
  133: }
  134: 
  135: int
  136: str2sockunion (const char *str, union sockunion *su)
  137: {
  138:   int ret;
  139: 
  140:   memset (su, 0, sizeof (union sockunion));
  141: 
  142:   ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
  143:   if (ret > 0)			/* Valid IPv4 address format. */
  144:     {
  145:       su->sin.sin_family = AF_INET;
  146: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  147:       su->sin.sin_len = sizeof(struct sockaddr_in);
  148: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  149:       return 0;
  150:     }
  151: #ifdef HAVE_IPV6
  152:   ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
  153:   if (ret > 0)			/* Valid IPv6 address format. */
  154:     {
  155:       su->sin6.sin6_family = AF_INET6;
  156: #ifdef SIN6_LEN
  157:       su->sin6.sin6_len = sizeof(struct sockaddr_in6);
  158: #endif /* SIN6_LEN */
  159:       return 0;
  160:     }
  161: #endif /* HAVE_IPV6 */
  162:   return -1;
  163: }
  164: 
  165: const char *
  166: sockunion2str (union sockunion *su, char *buf, size_t len)
  167: {
  168:   if  (su->sa.sa_family == AF_INET)
  169:     return inet_ntop (AF_INET, &su->sin.sin_addr, buf, len);
  170: #ifdef HAVE_IPV6
  171:   else if (su->sa.sa_family == AF_INET6)
  172:     return inet_ntop (AF_INET6, &su->sin6.sin6_addr, buf, len);
  173: #endif /* HAVE_IPV6 */
  174:   return NULL;
  175: }
  176: 
  177: union sockunion *
  178: sockunion_str2su (const char *str)
  179: {
  180:   int ret;
  181:   union sockunion *su;
  182: 
  183:   su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
  184: 
  185:   ret = inet_pton (AF_INET, str, &su->sin.sin_addr);
  186:   if (ret > 0)			/* Valid IPv4 address format. */
  187:     {
  188:       su->sin.sin_family = AF_INET;
  189: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  190:       su->sin.sin_len = sizeof(struct sockaddr_in);
  191: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  192:       return su;
  193:     }
  194: #ifdef HAVE_IPV6
  195:   ret = inet_pton (AF_INET6, str, &su->sin6.sin6_addr);
  196:   if (ret > 0)			/* Valid IPv6 address format. */
  197:     {
  198:       su->sin6.sin6_family = AF_INET6;
  199: #ifdef SIN6_LEN
  200:       su->sin6.sin6_len = sizeof(struct sockaddr_in6);
  201: #endif /* SIN6_LEN */
  202:       return su;
  203:     }
  204: #endif /* HAVE_IPV6 */
  205: 
  206:   XFREE (MTYPE_SOCKUNION, su);
  207:   return NULL;
  208: }
  209: 
  210: char *
  211: sockunion_su2str (union sockunion *su)
  212: {
  213:   char str[SU_ADDRSTRLEN];
  214: 
  215:   switch (su->sa.sa_family)
  216:     {
  217:     case AF_INET:
  218:       inet_ntop (AF_INET, &su->sin.sin_addr, str, sizeof (str));
  219:       break;
  220: #ifdef HAVE_IPV6
  221:     case AF_INET6:
  222:       inet_ntop (AF_INET6, &su->sin6.sin6_addr, str, sizeof (str));
  223:       break;
  224: #endif /* HAVE_IPV6 */
  225:     }
  226:   return XSTRDUP (MTYPE_TMP, str);
  227: }
  228: 
  229: /* Convert IPv4 compatible IPv6 address to IPv4 address. */
  230: static void
  231: sockunion_normalise_mapped (union sockunion *su)
  232: {
  233:   struct sockaddr_in sin;
  234:   
  235: #ifdef HAVE_IPV6
  236:   if (su->sa.sa_family == AF_INET6 
  237:       && IN6_IS_ADDR_V4MAPPED (&su->sin6.sin6_addr))
  238:     {
  239:       memset (&sin, 0, sizeof (struct sockaddr_in));
  240:       sin.sin_family = AF_INET;
  241:       sin.sin_port = su->sin6.sin6_port;
  242:       memcpy (&sin.sin_addr, ((char *)&su->sin6.sin6_addr) + 12, 4);
  243:       memcpy (su, &sin, sizeof (struct sockaddr_in));
  244:     }
  245: #endif /* HAVE_IPV6 */
  246: }
  247: 
  248: /* Return socket of sockunion. */
  249: int
  250: sockunion_socket (union sockunion *su)
  251: {
  252:   int sock;
  253: 
  254:   sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
  255:   if (sock < 0)
  256:     {
  257:       zlog (NULL, LOG_WARNING, "Can't make socket : %s", safe_strerror (errno));
  258:       return -1;
  259:     }
  260: 
  261:   return sock;
  262: }
  263: 
  264: /* Return accepted new socket file descriptor. */
  265: int
  266: sockunion_accept (int sock, union sockunion *su)
  267: {
  268:   socklen_t len;
  269:   int client_sock;
  270: 
  271:   len = sizeof (union sockunion);
  272:   client_sock = accept (sock, (struct sockaddr *) su, &len);
  273:   
  274:   sockunion_normalise_mapped (su);
  275:   return client_sock;
  276: }
  277: 
  278: /* Return sizeof union sockunion.  */
  279: static int
  280: sockunion_sizeof (union sockunion *su)
  281: {
  282:   int ret;
  283: 
  284:   ret = 0;
  285:   switch (su->sa.sa_family)
  286:     {
  287:     case AF_INET:
  288:       ret = sizeof (struct sockaddr_in);
  289:       break;
  290: #ifdef HAVE_IPV6
  291:     case AF_INET6:
  292:       ret = sizeof (struct sockaddr_in6);
  293:       break;
  294: #endif /* AF_INET6 */
  295:     }
  296:   return ret;
  297: }
  298: 
  299: /* return sockunion structure : this function should be revised. */
  300: static const char *
  301: sockunion_log (union sockunion *su, char *buf, size_t len)
  302: {
  303:   switch (su->sa.sa_family) 
  304:     {
  305:     case AF_INET:
  306:       return inet_ntop(AF_INET, &su->sin.sin_addr, buf, len);
  307: 
  308: #ifdef HAVE_IPV6
  309:     case AF_INET6:
  310:       return inet_ntop(AF_INET6, &(su->sin6.sin6_addr), buf, len);
  311:       break;
  312: #endif /* HAVE_IPV6 */
  313: 
  314:     default:
  315:       snprintf (buf, len, "af_unknown %d ", su->sa.sa_family);
  316:       return buf;
  317:     }
  318: }
  319: 
  320: /* sockunion_connect returns
  321:    -1 : error occured
  322:    0 : connect success
  323:    1 : connect is in progress */
  324: enum connect_result
  325: sockunion_connect (int fd, union sockunion *peersu, unsigned short port,
  326: 		   unsigned int ifindex)
  327: {
  328:   int ret;
  329:   int val;
  330:   union sockunion su;
  331: 
  332:   memcpy (&su, peersu, sizeof (union sockunion));
  333: 
  334:   switch (su.sa.sa_family)
  335:     {
  336:     case AF_INET:
  337:       su.sin.sin_port = port;
  338:       break;
  339: #ifdef HAVE_IPV6
  340:     case AF_INET6:
  341:       su.sin6.sin6_port  = port;
  342: #ifdef KAME
  343:       if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr) && ifindex)
  344: 	{
  345: #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
  346: 	  /* su.sin6.sin6_scope_id = ifindex; */
  347: #ifdef MUSICA
  348: 	  su.sin6.sin6_scope_id = ifindex; 
  349: #endif
  350: #endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */
  351: #ifndef MUSICA
  352: 	  SET_IN6_LINKLOCAL_IFINDEX (su.sin6.sin6_addr, ifindex);
  353: #endif
  354: 	}
  355: #endif /* KAME */
  356:       break;
  357: #endif /* HAVE_IPV6 */
  358:     }      
  359: 
  360:   /* Make socket non-block. */
  361:   val = fcntl (fd, F_GETFL, 0);
  362:   fcntl (fd, F_SETFL, val|O_NONBLOCK);
  363: 
  364:   /* Call connect function. */
  365:   ret = connect (fd, (struct sockaddr *) &su, sockunion_sizeof (&su));
  366: 
  367:   /* Immediate success */
  368:   if (ret == 0)
  369:     {
  370:       fcntl (fd, F_SETFL, val);
  371:       return connect_success;
  372:     }
  373: 
  374:   /* If connect is in progress then return 1 else it's real error. */
  375:   if (ret < 0)
  376:     {
  377:       if (errno != EINPROGRESS)
  378: 	{
  379: 	  char str[SU_ADDRSTRLEN];
  380: 	  zlog_info ("can't connect to %s fd %d : %s",
  381: 		     sockunion_log (&su, str, sizeof str),
  382: 		     fd, safe_strerror (errno));
  383: 	  return connect_error;
  384: 	}
  385:     }
  386: 
  387:   fcntl (fd, F_SETFL, val);
  388: 
  389:   return connect_in_progress;
  390: }
  391: 
  392: /* Make socket from sockunion union. */
  393: int
  394: sockunion_stream_socket (union sockunion *su)
  395: {
  396:   int sock;
  397: 
  398:   if (su->sa.sa_family == 0)
  399:     su->sa.sa_family = AF_INET_UNION;
  400: 
  401:   sock = socket (su->sa.sa_family, SOCK_STREAM, 0);
  402: 
  403:   if (sock < 0)
  404:     zlog (NULL, LOG_WARNING, "can't make socket sockunion_stream_socket");
  405: 
  406:   return sock;
  407: }
  408: 
  409: /* Bind socket to specified address. */
  410: int
  411: sockunion_bind (int sock, union sockunion *su, unsigned short port, 
  412: 		union sockunion *su_addr)
  413: {
  414:   int size = 0;
  415:   int ret;
  416: 
  417:   if (su->sa.sa_family == AF_INET)
  418:     {
  419:       size = sizeof (struct sockaddr_in);
  420:       su->sin.sin_port = htons (port);
  421: #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
  422:       su->sin.sin_len = size;
  423: #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
  424:       if (su_addr == NULL)
  425: 	su->sin.sin_addr.s_addr = htonl (INADDR_ANY);
  426:     }
  427: #ifdef HAVE_IPV6
  428:   else if (su->sa.sa_family == AF_INET6)
  429:     {
  430:       size = sizeof (struct sockaddr_in6);
  431:       su->sin6.sin6_port = htons (port);
  432: #ifdef SIN6_LEN
  433:       su->sin6.sin6_len = size;
  434: #endif /* SIN6_LEN */
  435:       if (su_addr == NULL)
  436: 	{
  437: #if defined(LINUX_IPV6) || defined(NRL)
  438: 	  memset (&su->sin6.sin6_addr, 0, sizeof (struct in6_addr));
  439: #else
  440: 	  su->sin6.sin6_addr = in6addr_any;
  441: #endif /* LINUX_IPV6 */
  442: 	}
  443:     }
  444: #endif /* HAVE_IPV6 */
  445:   
  446: 
  447:   ret = bind (sock, (struct sockaddr *)su, size);
  448:   if (ret < 0)
  449:     zlog (NULL, LOG_WARNING, "can't bind socket : %s", safe_strerror (errno));
  450: 
  451:   return ret;
  452: }
  453: 
  454: int
  455: sockopt_reuseaddr (int sock)
  456: {
  457:   int ret;
  458:   int on = 1;
  459: 
  460:   ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, 
  461: 		    (void *) &on, sizeof (on));
  462:   if (ret < 0)
  463:     {
  464:       zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEADDR to socket %d", sock);
  465:       return -1;
  466:     }
  467:   return 0;
  468: }
  469: 
  470: #ifdef SO_REUSEPORT
  471: int
  472: sockopt_reuseport (int sock)
  473: {
  474:   int ret;
  475:   int on = 1;
  476: 
  477:   ret = setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, 
  478: 		    (void *) &on, sizeof (on));
  479:   if (ret < 0)
  480:     {
  481:       zlog (NULL, LOG_WARNING, "can't set sockopt SO_REUSEPORT to socket %d", sock);
  482:       return -1;
  483:     }
  484:   return 0;
  485: }
  486: #else
  487: int
  488: sockopt_reuseport (int sock)
  489: {
  490:   return 0;
  491: }
  492: #endif /* 0 */
  493: 
  494: int
  495: sockopt_ttl (int family, int sock, int ttl)
  496: {
  497:   int ret;
  498: 
  499: #ifdef IP_TTL
  500:   if (family == AF_INET)
  501:     {
  502:       ret = setsockopt (sock, IPPROTO_IP, IP_TTL, 
  503: 			(void *) &ttl, sizeof (int));
  504:       if (ret < 0)
  505: 	{
  506: 	  zlog (NULL, LOG_WARNING, "can't set sockopt IP_TTL %d to socket %d", ttl, sock);
  507: 	  return -1;
  508: 	}
  509:       return 0;
  510:     }
  511: #endif /* IP_TTL */
  512: #ifdef HAVE_IPV6
  513:   if (family == AF_INET6)
  514:     {
  515:       ret = setsockopt (sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 
  516: 			(void *) &ttl, sizeof (int));
  517:       if (ret < 0)
  518: 	{
  519: 	  zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_UNICAST_HOPS %d to socket %d",
  520: 		    ttl, sock);
  521: 	  return -1;
  522: 	}
  523:       return 0;
  524:     }
  525: #endif /* HAVE_IPV6 */
  526:   return 0;
  527: }
  528: 
  529: int
  530: sockopt_cork (int sock, int onoff)
  531: {
  532: #ifdef TCP_CORK
  533:   return setsockopt (sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff));
  534: #else
  535:   return 0;
  536: #endif
  537: }
  538: 
  539: int
  540: sockopt_minttl (int family, int sock, int minttl)
  541: {
  542: #ifdef IP_MINTTL
  543:   if (family == AF_INET)
  544:     {
  545:       int ret = setsockopt (sock, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
  546:       if (ret < 0)
  547: 	  zlog (NULL, LOG_WARNING,
  548: 		"can't set sockopt IP_MINTTL to %d on socket %d: %s",
  549: 		minttl, sock, safe_strerror (errno));
  550:       return ret;
  551:     }
  552: #endif /* IP_MINTTL */
  553: #ifdef IPV6_MINHOPCNT
  554:   if (family == AF_INET6)
  555:     {
  556:       int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCNT, &minttl, sizeof(minttl));
  557:       if (ret < 0)
  558: 	  zlog (NULL, LOG_WARNING,
  559: 		"can't set sockopt IPV6_MINHOPCNT to %d on socket %d: %s",
  560: 		minttl, sock, safe_strerror (errno));
  561:       return ret;
  562:     }
  563: #endif
  564: 
  565:   errno = EOPNOTSUPP;
  566:   return -1;
  567: }
  568: 
  569: int
  570: sockopt_v6only (int family, int sock)
  571: {
  572:   int ret, on = 1;
  573: 
  574: #ifdef HAVE_IPV6
  575: #ifdef IPV6_V6ONLY
  576:   if (family == AF_INET6)
  577:     {
  578:       ret = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY,
  579: 			(void *) &on, sizeof (int));
  580:       if (ret < 0)
  581: 	{
  582: 	  zlog (NULL, LOG_WARNING, "can't set sockopt IPV6_V6ONLY "
  583: 		    "to socket %d", sock);
  584: 	  return -1;
  585: 	}
  586:       return 0;
  587:     }
  588: #endif /* IPV6_V6ONLY */
  589: #endif /* HAVE_IPV6 */
  590:   return 0;
  591: }
  592: 
  593: /* If same family and same prefix return 1. */
  594: int
  595: sockunion_same (union sockunion *su1, union sockunion *su2)
  596: {
  597:   int ret = 0;
  598: 
  599:   if (su1->sa.sa_family != su2->sa.sa_family)
  600:     return 0;
  601: 
  602:   switch (su1->sa.sa_family)
  603:     {
  604:     case AF_INET:
  605:       ret = memcmp (&su1->sin.sin_addr, &su2->sin.sin_addr,
  606: 		    sizeof (struct in_addr));
  607:       break;
  608: #ifdef HAVE_IPV6
  609:     case AF_INET6:
  610:       ret = memcmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr,
  611: 		    sizeof (struct in6_addr));
  612:       break;
  613: #endif /* HAVE_IPV6 */
  614:     }
  615:   if (ret == 0)
  616:     return 1;
  617:   else
  618:     return 0;
  619: }
  620: 
  621: /* After TCP connection is established.  Get local address and port. */
  622: union sockunion *
  623: sockunion_getsockname (int fd)
  624: {
  625:   int ret;
  626:   socklen_t len;
  627:   union
  628:   {
  629:     struct sockaddr sa;
  630:     struct sockaddr_in sin;
  631: #ifdef HAVE_IPV6
  632:     struct sockaddr_in6 sin6;
  633: #endif /* HAVE_IPV6 */
  634:     char tmp_buffer[128];
  635:   } name;
  636:   union sockunion *su;
  637: 
  638:   memset (&name, 0, sizeof name);
  639:   len = sizeof name;
  640: 
  641:   ret = getsockname (fd, (struct sockaddr *)&name, &len);
  642:   if (ret < 0)
  643:     {
  644:       zlog_warn ("Can't get local address and port by getsockname: %s",
  645: 		 safe_strerror (errno));
  646:       return NULL;
  647:     }
  648: 
  649:   if (name.sa.sa_family == AF_INET)
  650:     {
  651:       su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
  652:       memcpy (su, &name, sizeof (struct sockaddr_in));
  653:       return su;
  654:     }
  655: #ifdef HAVE_IPV6
  656:   if (name.sa.sa_family == AF_INET6)
  657:     {
  658:       su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
  659:       memcpy (su, &name, sizeof (struct sockaddr_in6));
  660:       sockunion_normalise_mapped (su);
  661:       return su;
  662:     }
  663: #endif /* HAVE_IPV6 */
  664:   return NULL;
  665: }
  666: 
  667: /* After TCP connection is established.  Get remote address and port. */
  668: union sockunion *
  669: sockunion_getpeername (int fd)
  670: {
  671:   int ret;
  672:   socklen_t len;
  673:   union
  674:   {
  675:     struct sockaddr sa;
  676:     struct sockaddr_in sin;
  677: #ifdef HAVE_IPV6
  678:     struct sockaddr_in6 sin6;
  679: #endif /* HAVE_IPV6 */
  680:     char tmp_buffer[128];
  681:   } name;
  682:   union sockunion *su;
  683: 
  684:   memset (&name, 0, sizeof name);
  685:   len = sizeof name;
  686:   ret = getpeername (fd, (struct sockaddr *)&name, &len);
  687:   if (ret < 0)
  688:     {
  689:       zlog (NULL, LOG_WARNING, "Can't get remote address and port: %s",
  690: 	    safe_strerror (errno));
  691:       return NULL;
  692:     }
  693: 
  694:   if (name.sa.sa_family == AF_INET)
  695:     {
  696:       su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
  697:       memcpy (su, &name, sizeof (struct sockaddr_in));
  698:       return su;
  699:     }
  700: #ifdef HAVE_IPV6
  701:   if (name.sa.sa_family == AF_INET6)
  702:     {
  703:       su = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
  704:       memcpy (su, &name, sizeof (struct sockaddr_in6));
  705:       sockunion_normalise_mapped (su);
  706:       return su;
  707:     }
  708: #endif /* HAVE_IPV6 */
  709:   return NULL;
  710: }
  711: 
  712: /* Print sockunion structure */
  713: static void __attribute__ ((unused))
  714: sockunion_print (union sockunion *su)
  715: {
  716:   if (su == NULL)
  717:     return;
  718: 
  719:   switch (su->sa.sa_family) 
  720:     {
  721:     case AF_INET:
  722:       printf ("%s\n", inet_ntoa (su->sin.sin_addr));
  723:       break;
  724: #ifdef HAVE_IPV6
  725:     case AF_INET6:
  726:       {
  727: 	char buf [SU_ADDRSTRLEN];
  728: 
  729: 	printf ("%s\n", inet_ntop (AF_INET6, &(su->sin6.sin6_addr),
  730: 				 buf, sizeof (buf)));
  731:       }
  732:       break;
  733: #endif /* HAVE_IPV6 */
  734: 
  735: #ifdef AF_LINK
  736:     case AF_LINK:
  737:       {
  738: 	struct sockaddr_dl *sdl;
  739: 
  740: 	sdl = (struct sockaddr_dl *)&(su->sa);
  741: 	printf ("link#%d\n", sdl->sdl_index);
  742:       }
  743:       break;
  744: #endif /* AF_LINK */
  745:     default:
  746:       printf ("af_unknown %d\n", su->sa.sa_family);
  747:       break;
  748:     }
  749: }
  750: 
  751: #ifdef HAVE_IPV6
  752: static int
  753: in6addr_cmp (struct in6_addr *addr1, struct in6_addr *addr2)
  754: {
  755:   unsigned int i;
  756:   u_char *p1, *p2;
  757: 
  758:   p1 = (u_char *)addr1;
  759:   p2 = (u_char *)addr2;
  760: 
  761:   for (i = 0; i < sizeof (struct in6_addr); i++)
  762:     {
  763:       if (p1[i] > p2[i])
  764: 	return 1;
  765:       else if (p1[i] < p2[i])
  766: 	return -1;
  767:     }
  768:   return 0;
  769: }
  770: #endif /* HAVE_IPV6 */
  771: 
  772: int
  773: sockunion_cmp (union sockunion *su1, union sockunion *su2)
  774: {
  775:   if (su1->sa.sa_family > su2->sa.sa_family)
  776:     return 1;
  777:   if (su1->sa.sa_family < su2->sa.sa_family)
  778:     return -1;
  779: 
  780:   if (su1->sa.sa_family == AF_INET)
  781:     {
  782:       if (ntohl (su1->sin.sin_addr.s_addr) == ntohl (su2->sin.sin_addr.s_addr))
  783: 	return 0;
  784:       if (ntohl (su1->sin.sin_addr.s_addr) > ntohl (su2->sin.sin_addr.s_addr))
  785: 	return 1;
  786:       else
  787: 	return -1;
  788:     }
  789: #ifdef HAVE_IPV6
  790:   if (su1->sa.sa_family == AF_INET6)
  791:     return in6addr_cmp (&su1->sin6.sin6_addr, &su2->sin6.sin6_addr);
  792: #endif /* HAVE_IPV6 */
  793:   return 0;
  794: }
  795: 
  796: /* Duplicate sockunion. */
  797: union sockunion *
  798: sockunion_dup (union sockunion *su)
  799: {
  800:   union sockunion *dup = XCALLOC (MTYPE_SOCKUNION, sizeof (union sockunion));
  801:   memcpy (dup, su, sizeof (union sockunion));
  802:   return dup;
  803: }
  804: 
  805: void
  806: sockunion_free (union sockunion *su)
  807: {
  808:   XFREE (MTYPE_SOCKUNION, su);
  809: }

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