tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

inaddr.c (8558B)


      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 tor_inet_aton(const char *str, struct in_addr *addr)
     41 {
     42  unsigned a, b, c, d;
     43  char more;
     44  bool is_octal = false;
     45  smartlist_t *sl = NULL;
     46 
     47  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  sl = smartlist_new();
     52  smartlist_split_string(sl, str, ".", 0, 0);
     53  SMARTLIST_FOREACH(sl, const char *, octet, {
     54    is_octal = (strlen(octet) > 1 && octet[0] == '0');
     55    if (is_octal) {
     56        break;
     57    }
     58  });
     59  SMARTLIST_FOREACH(sl, char *, octet, tor_free(octet));
     60  smartlist_free(sl);
     61 
     62  if (is_octal)
     63    return 0;
     64 
     65  if (a > 255) return 0;
     66  if (b > 255) return 0;
     67  if (c > 255) return 0;
     68  if (d > 255) return 0;
     69  addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d);
     70  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 tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len)
     80 {
     81  uint32_t a = ntohl(in->s_addr);
     82  return tor_snprintf(buf, buf_len, "%d.%d.%d.%d",
     83                      (int)(uint8_t)((a>>24)&0xff),
     84                      (int)(uint8_t)((a>>16)&0xff),
     85                      (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 tor_inet_ntop(int af, const void *src, char *dst, size_t len)
     99 {
    100  if (af == AF_INET) {
    101    if (tor_inet_ntoa(src, dst, len) < 0)
    102      return NULL;
    103    else
    104      return dst;
    105  } else if (af == AF_INET6) {
    106    const struct in6_addr *addr = src;
    107    char buf[64], *cp;
    108    int longestGapLen = 0, longestGapPos = -1, i,
    109      curGapPos = -1, curGapLen = 0;
    110    uint16_t words[8];
    111    for (i = 0; i < 8; ++i) {
    112      words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1];
    113    }
    114    if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 &&
    115        words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) ||
    116                          (words[5] == 0xffff))) {
    117      /* This is an IPv4 address. */
    118      if (words[5] == 0) {
    119        tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d",
    120                     addr->s6_addr[12], addr->s6_addr[13],
    121                     addr->s6_addr[14], addr->s6_addr[15]);
    122      } else {
    123        tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5],
    124                     addr->s6_addr[12], addr->s6_addr[13],
    125                     addr->s6_addr[14], addr->s6_addr[15]);
    126      }
    127      if ((strlen(buf) + 1) > len) /* +1 for \0 */
    128        return NULL;
    129      strlcpy(dst, buf, len);
    130      return dst;
    131    }
    132    i = 0;
    133    while (i < 8) {
    134      if (words[i] == 0) {
    135        curGapPos = i++;
    136        curGapLen = 1;
    137        while (i<8 && words[i] == 0) {
    138          ++i; ++curGapLen;
    139        }
    140        if (curGapLen > longestGapLen) {
    141          longestGapPos = curGapPos;
    142          longestGapLen = curGapLen;
    143        }
    144      } else {
    145        ++i;
    146      }
    147    }
    148    if (longestGapLen<=1)
    149      longestGapPos = -1;
    150 
    151    cp = buf;
    152    for (i = 0; i < 8; ++i) {
    153      if (words[i] == 0 && longestGapPos == i) {
    154        if (i == 0)
    155          *cp++ = ':';
    156        *cp++ = ':';
    157        while (i < 8 && words[i] == 0)
    158          ++i;
    159        --i; /* to compensate for loop increment. */
    160      } else {
    161        tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]);
    162        cp += strlen(cp);
    163        if (i != 7)
    164          *cp++ = ':';
    165      }
    166    }
    167    *cp = '\0';
    168    if ((strlen(buf) + 1) > len) /* +1 for \0 */
    169      return NULL;
    170    strlcpy(dst, buf, len);
    171    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 tor_inet_pton(int af, const char *src, void *dst)
    188 {
    189  if (af == AF_INET) {
    190    return tor_inet_aton(src, dst);
    191  } else if (af == AF_INET6) {
    192    ssize_t len = strlen(src);
    193 
    194    /* Reject if src has needless trailing ':'. */
    195    if (len > 2 && src[len - 1] == ':' && src[len - 2] != ':') {
    196      return 0;
    197    }
    198 
    199    struct in6_addr *out = dst;
    200    uint16_t words[8];
    201    int gapPos = -1, i, setWords=0;
    202    const char *dot = strchr(src, '.');
    203    const char *eow; /* end of words. */
    204    memset(words, 0xf8, sizeof(words));
    205    if (dot == src)
    206      return 0;
    207    else if (!dot)
    208      eow = src+strlen(src);
    209    else {
    210      unsigned byte1,byte2,byte3,byte4;
    211      char more;
    212      for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow)
    213        ;
    214      if (*eow != ':')
    215        return 0;
    216      ++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      if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c",
    221                     &byte1,&byte2,&byte3,&byte4,&more) != 4)
    222        return 0;
    223 
    224      if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255)
    225        return 0;
    226 
    227      words[6] = (byte1<<8) | byte2;
    228      words[7] = (byte3<<8) | byte4;
    229      setWords += 2;
    230    }
    231 
    232    i = 0;
    233    while (src < eow) {
    234      if (i > 7)
    235        return 0;
    236      if (TOR_ISXDIGIT(*src)) {
    237        char *next;
    238        long r = strtol(src, &next, 16);
    239        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          return 0;
    244        }
    245 
    246        len = *next == '\0' ? eow - src : next - src;
    247        if (len > 4)
    248          return 0;
    249        if (len > 1 && !TOR_ISXDIGIT(src[1]))
    250          return 0; /* 0x is not valid */
    251 
    252        tor_assert(r >= 0);
    253        tor_assert(r < 65536);
    254        words[i++] = (uint16_t)r;
    255        setWords++;
    256        src = next;
    257        if (*src != ':' && src != eow)
    258          return 0;
    259        ++src;
    260      } else if (*src == ':' && i > 0 && gapPos == -1) {
    261        gapPos = i;
    262        ++src;
    263      } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' &&
    264                 gapPos == -1) {
    265        gapPos = i;
    266        src += 2;
    267      } else {
    268        return 0;
    269      }
    270    }
    271 
    272    if (setWords > 8 ||
    273        (setWords == 8 && gapPos != -1) ||
    274        (setWords < 8 && gapPos == -1))
    275      return 0;
    276 
    277    if (gapPos >= 0) {
    278      int nToMove = setWords - (dot ? 2 : 0) - gapPos;
    279      int gapLen = 8 - setWords;
    280      tor_assert(nToMove >= 0);
    281      memmove(&words[gapPos+gapLen], &words[gapPos],
    282              sizeof(uint16_t)*nToMove);
    283      memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen);
    284    }
    285    for (i = 0; i < 8; ++i) {
    286      out->s6_addr[2*i  ] = words[i] >> 8;
    287      out->s6_addr[2*i+1] = words[i] & 0xff;
    288    }
    289 
    290    return 1;
    291  } else {
    292    return -1;
    293  }
    294 }