LCOV - code coverage report
Current view: top level - lib - sockunion.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 39 243 16.0 %
Date: 2015-11-19 Functions: 8 26 30.8 %

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

Generated by: LCOV version 1.10