LCOV - code coverage report
Current view: top level - lib/net - inaddr.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 136 136 100.0 %
Date: 2021-11-24 03:28:48 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* Copyright (c) 2003-2004, Roger Dingledine
       2             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       3             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       4             : /* See LICENSE for licensing information */
       5             : 
       6             : /**
       7             :  * \file inaddr.c
       8             :  * \brief Convert in_addr and in6_addr to and from strings.
       9             :  **/
      10             : 
      11             : #include "lib/net/inaddr.h"
      12             : 
      13             : #include "lib/cc/torint.h"
      14             : #include "lib/container/smartlist.h"
      15             : #include "lib/log/util_bug.h"
      16             : #include "lib/malloc/malloc.h"
      17             : #include "lib/net/inaddr_st.h"
      18             : #include "lib/string/compat_ctype.h"
      19             : #include "lib/string/compat_string.h"
      20             : #include "lib/string/printf.h"
      21             : #include "lib/string/scanf.h"
      22             : #include "lib/string/util_string.h"
      23             : 
      24             : #ifdef HAVE_ARPA_INET_H
      25             : #include <arpa/inet.h>
      26             : #endif
      27             : 
      28             : #include <stdlib.h>
      29             : #include <string.h>
      30             : 
      31             : #ifdef _WIN32
      32             : #include <winsock2.h>
      33             : #endif
      34             : 
      35             : /** Set *addr to the IP address (in dotted-quad notation) stored in *str.
      36             :  * Return 1 on success, 0 if *str is badly formatted.
      37             :  * (Like inet_aton(str,addr), but works on Windows and Solaris.)
      38             :  */
      39             : int
      40      291144 : tor_inet_aton(const char *str, struct in_addr *addr)
      41             : {
      42      291144 :   unsigned a, b, c, d;
      43      291144 :   char more;
      44      291144 :   bool is_octal = false;
      45      291144 :   smartlist_t *sl = NULL;
      46             : 
      47      291144 :   if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a, &b, &c, &d, &more) != 4)
      48             :     return 0;
      49             : 
      50             :   /* Parse the octets and check them for leading zeros. */
      51      271336 :   sl = smartlist_new();
      52      271336 :   smartlist_split_string(sl, str, ".", 0, 0);
      53     1356651 :   SMARTLIST_FOREACH(sl, const char *, octet, {
      54             :     is_octal = (strlen(octet) > 1 && octet[0] == '0');
      55             :     if (is_octal) {
      56             :         break;
      57             :     }
      58             :   });
      59     1356680 :   SMARTLIST_FOREACH(sl, char *, octet, tor_free(octet));
      60      271336 :   smartlist_free(sl);
      61             : 
      62      271336 :   if (is_octal)
      63             :     return 0;
      64             : 
      65      271315 :   if (a > 255) return 0;
      66      271313 :   if (b > 255) return 0;
      67      271311 :   if (c > 255) return 0;
      68      271310 :   if (d > 255) return 0;
      69      271307 :   addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
      70      271307 :   return 1;
      71             : }
      72             : 
      73             : /** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual),
      74             :  *  write it as a string into the <b>buf_len</b>-byte buffer in
      75             :  *  <b>buf</b>. Returns a non-negative integer on success.
      76             :  *  Returns -1 on failure.
      77             :  */
      78             : int
      79       53611 : tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len)
      80             : {
      81       53611 :   uint32_t a = ntohl(in->s_addr);
      82      107222 :   return tor_snprintf(buf, buf_len, "%d.%d.%d.%d",
      83       53611 :                       (int)(uint8_t)((a>>24)&0xff),
      84       53611 :                       (int)(uint8_t)((a>>16)&0xff),
      85       53611 :                       (int)(uint8_t)((a>>8 )&0xff),
      86             :                       (int)(uint8_t)((a    )&0xff));
      87             : }
      88             : 
      89             : /** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or
      90             :  * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the
      91             :  * address and store it in the <b>len</b>-byte buffer <b>dst</b>.  Returns
      92             :  * <b>dst</b> on success, NULL on failure.
      93             :  *
      94             :  * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it:
      95             :  * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6
      96             :  * support.) */
      97             : const char *
      98       54847 : tor_inet_ntop(int af, const void *src, char *dst, size_t len)
      99             : {
     100       54847 :   if (af == AF_INET) {
     101       53609 :     if (tor_inet_ntoa(src, dst, len) < 0)
     102             :       return NULL;
     103             :     else
     104       53606 :       return dst;
     105        1238 :   } else if (af == AF_INET6) {
     106             :     const struct in6_addr *addr = src;
     107             :     char buf[64], *cp;
     108       11142 :     int longestGapLen = 0, longestGapPos = -1, i,
     109       11142 :       curGapPos = -1, curGapLen = 0;
     110             :     uint16_t words[8];
     111       11142 :     for (i = 0; i < 8; ++i) {
     112        9904 :       words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
     113             :     }
     114        1238 :     if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
     115         743 :         words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
     116             :                           (words[5] == 0xffff))) {
     117             :       /* This is an IPv4 address. */
     118           7 :       if (words[5] == 0) {
     119           1 :         tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
     120           1 :                      addr->s6_addr[12], addr->s6_addr[13],
     121           1 :                      addr->s6_addr[14], addr->s6_addr[15]);
     122             :       } else {
     123           6 :         tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
     124           6 :                      addr->s6_addr[12], addr->s6_addr[13],
     125           6 :                      addr->s6_addr[14], addr->s6_addr[15]);
     126             :       }
     127           7 :       if ((strlen(buf) + 1) > len) /* +1 for \0 */
     128             :         return NULL;
     129           6 :       strlcpy(dst, buf, len);
     130           6 :       return dst;
     131             :     }
     132             :     i = 0;
     133        4153 :     while (i < 8) {
     134        2922 :       if (words[i] == 0) {
     135        1185 :         curGapPos = i++;
     136        1185 :         curGapLen = 1;
     137        8111 :         while (i<8 && words[i] == 0) {
     138        6926 :           ++i; ++curGapLen;
     139             :         }
     140        1185 :         if (curGapLen > longestGapLen) {
     141        1180 :           longestGapPos = curGapPos;
     142        1180 :           longestGapLen = curGapLen;
     143             :         }
     144             :       } else {
     145        1737 :         ++i;
     146             :       }
     147             :     }
     148        1231 :     if (longestGapLen<=1)
     149          55 :       longestGapPos = -1;
     150             : 
     151        1231 :     cp = buf;
     152        4154 :     for (i = 0; i < 8; ++i) {
     153        2923 :       if (words[i] == 0 && longestGapPos == i) {
     154        1176 :         if (i == 0)
     155         736 :           *cp++ = ':';
     156        1176 :         *cp++ = ':';
     157        9277 :         while (i < 8 && words[i] == 0)
     158        8101 :           ++i;
     159        1176 :         --i; /* to compensate for loop increment. */
     160             :       } else {
     161        1747 :         tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
     162        1747 :         cp += strlen(cp);
     163        1747 :         if (i != 7)
     164        1196 :           *cp++ = ':';
     165             :       }
     166             :     }
     167        1231 :     *cp = '\0';
     168        1231 :     if ((strlen(buf) + 1) > len) /* +1 for \0 */
     169             :       return NULL;
     170        1228 :     strlcpy(dst, buf, len);
     171        1228 :     return dst;
     172             :   } else {
     173             :     return NULL;
     174             :   }
     175             : }
     176             : 
     177             : /** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b>
     178             :  * encoding an IPv4 address or IPv6 address correspondingly, try to parse the
     179             :  * address and store the result in <b>dst</b> (which must have space for a
     180             :  * struct in_addr or a struct in6_addr, as appropriate).  Return 1 on success,
     181             :  * 0 on a bad parse, and -1 on a bad <b>af</b>.
     182             :  *
     183             :  * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor
     184             :  * sometimes needs to format ipv6 addresses even on platforms without ipv6
     185             :  * support.) */
     186             : int
     187      740640 : tor_inet_pton(int af, const char *src, void *dst)
     188             : {
     189      740640 :   if (af == AF_INET) {
     190      286261 :     return tor_inet_aton(src, dst);
     191      454379 :   } else if (af == AF_INET6) {
     192      454378 :     ssize_t len = strlen(src);
     193             : 
     194             :     /* Reject if src has needless trailing ':'. */
     195      454378 :     if (len > 2 && src[len - 1] == ':' && src[len - 2] != ':') {
     196             :       return 0;
     197             :     }
     198             : 
     199      454346 :     struct in6_addr *out = dst;
     200      454346 :     uint16_t words[8];
     201      454346 :     int gapPos = -1, i, setWords=0;
     202      454346 :     const char *dot = strchr(src, '.');
     203      454346 :     const char *eow; /* end of words. */
     204      454346 :     memset(words, 0xf8, sizeof(words));
     205      454346 :     if (dot == src)
     206             :       return 0;
     207      454344 :     else if (!dot)
     208      187393 :       eow = src+strlen(src);
     209             :     else {
     210      266951 :       unsigned byte1,byte2,byte3,byte4;
     211      266951 :       char more;
     212      656370 :       for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow)
     213             :         ;
     214      266951 :       if (*eow != ':')
     215      266881 :         return 0;
     216          76 :       ++eow;
     217             : 
     218             :       /* We use "scanf" because some platform inet_aton()s are too lax
     219             :        * about IPv4 addresses of the form "1.2.3" */
     220          76 :       if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c",
     221             :                      &byte1,&byte2,&byte3,&byte4,&more) != 4)
     222             :         return 0;
     223             : 
     224          71 :       if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255)
     225             :         return 0;
     226             : 
     227          70 :       words[6] = (byte1<<8) | byte2;
     228          70 :       words[7] = (byte3<<8) | byte4;
     229          70 :       setWords += 2;
     230             :     }
     231             : 
     232      187463 :     i = 0;
     233      543305 :     while (src < eow) {
     234      372363 :       if (i > 7)
     235             :         return 0;
     236      372349 :       if (TOR_ISXDIGIT(*src)) {
     237      187201 :         char *next;
     238      187201 :         long r = strtol(src, &next, 16);
     239      187201 :         if (next == NULL || next == src) {
     240             :           /* The 'next == src' error case can happen on versions of openbsd
     241             :            * which treat "0xfoo" as an error, rather than as "0" followed by
     242             :            * "xfoo". */
     243         120 :           return 0;
     244             :         }
     245             : 
     246      187201 :         len = *next == '\0' ? eow - src : next - src;
     247      187201 :         if (len > 4)
     248             :           return 0;
     249      187148 :         if (len > 1 && !TOR_ISXDIGIT(src[1]))
     250             :           return 0; /* 0x is not valid */
     251             : 
     252      187141 :         tor_assert(r >= 0);
     253      187141 :         tor_assert(r < 65536);
     254      187141 :         words[i++] = (uint16_t)r;
     255      187141 :         setWords++;
     256      187141 :         src = next;
     257      187141 :         if (*src != ':' && src != eow)
     258             :           return 0;
     259      187081 :         ++src;
     260      185148 :       } else if (*src == ':' && i > 0 && gapPos == -1) {
     261      116924 :         gapPos = i;
     262      116924 :         ++src;
     263       68224 :       } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' &&
     264             :                  gapPos == -1) {
     265       51837 :         gapPos = i;
     266       51837 :         src += 2;
     267             :       } else {
     268             :         return 0;
     269             :       }
     270             :     }
     271             : 
     272      170942 :     if (setWords > 8 ||
     273      170932 :         (setWords == 8 && gapPos != -1) ||
     274      170931 :         (setWords < 8 && gapPos == -1))
     275             :       return 0;
     276             : 
     277      170906 :     if (gapPos >= 0) {
     278      168681 :       int nToMove = setWords - (dot ? 2 : 0) - gapPos;
     279      168681 :       int gapLen = 8 - setWords;
     280      168681 :       tor_assert(nToMove >= 0);
     281      168681 :       memmove(&words[gapPos+gapLen], &words[gapPos],
     282             :               sizeof(uint16_t)*nToMove);
     283      168681 :       memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen);
     284             :     }
     285     1538154 :     for (i = 0; i < 8; ++i) {
     286     1367248 :       out->s6_addr[2*i  ] = words[i] >> 8;
     287     1367248 :       out->s6_addr[2*i+1] = words[i] & 0xff;
     288             :     }
     289             : 
     290             :     return 1;
     291             :   } else {
     292             :     return -1;
     293             :   }
     294             : }

Generated by: LCOV version 1.14