1e66f31c5Sopenharmony_ci/*
2e66f31c5Sopenharmony_ci * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3e66f31c5Sopenharmony_ci * Copyright (c) 1996-1999 by Internet Software Consortium.
4e66f31c5Sopenharmony_ci *
5e66f31c5Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any
6e66f31c5Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
7e66f31c5Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
8e66f31c5Sopenharmony_ci *
9e66f31c5Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10e66f31c5Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11e66f31c5Sopenharmony_ci * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12e66f31c5Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13e66f31c5Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14e66f31c5Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15e66f31c5Sopenharmony_ci * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16e66f31c5Sopenharmony_ci */
17e66f31c5Sopenharmony_ci
18e66f31c5Sopenharmony_ci#include <stdio.h>
19e66f31c5Sopenharmony_ci#include <string.h>
20e66f31c5Sopenharmony_ci#include <stdint.h>
21e66f31c5Sopenharmony_ci
22e66f31c5Sopenharmony_ci#include "uv.h"
23e66f31c5Sopenharmony_ci#include "uv-common.h"
24e66f31c5Sopenharmony_ci
25e66f31c5Sopenharmony_ci#define UV__INET_ADDRSTRLEN         16
26e66f31c5Sopenharmony_ci#define UV__INET6_ADDRSTRLEN        46
27e66f31c5Sopenharmony_ci
28e66f31c5Sopenharmony_ci
29e66f31c5Sopenharmony_cistatic int inet_ntop4(const unsigned char *src, char *dst, size_t size);
30e66f31c5Sopenharmony_cistatic int inet_ntop6(const unsigned char *src, char *dst, size_t size);
31e66f31c5Sopenharmony_cistatic int inet_pton4(const char *src, unsigned char *dst);
32e66f31c5Sopenharmony_cistatic int inet_pton6(const char *src, unsigned char *dst);
33e66f31c5Sopenharmony_ci
34e66f31c5Sopenharmony_ci
35e66f31c5Sopenharmony_ciint uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
36e66f31c5Sopenharmony_ci  switch (af) {
37e66f31c5Sopenharmony_ci  case AF_INET:
38e66f31c5Sopenharmony_ci    return (inet_ntop4(src, dst, size));
39e66f31c5Sopenharmony_ci  case AF_INET6:
40e66f31c5Sopenharmony_ci    return (inet_ntop6(src, dst, size));
41e66f31c5Sopenharmony_ci  default:
42e66f31c5Sopenharmony_ci    return UV_EAFNOSUPPORT;
43e66f31c5Sopenharmony_ci  }
44e66f31c5Sopenharmony_ci  /* NOTREACHED */
45e66f31c5Sopenharmony_ci}
46e66f31c5Sopenharmony_ci
47e66f31c5Sopenharmony_ci
48e66f31c5Sopenharmony_cistatic int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
49e66f31c5Sopenharmony_ci  static const char fmt[] = "%u.%u.%u.%u";
50e66f31c5Sopenharmony_ci  char tmp[UV__INET_ADDRSTRLEN];
51e66f31c5Sopenharmony_ci  int l;
52e66f31c5Sopenharmony_ci
53e66f31c5Sopenharmony_ci  l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
54e66f31c5Sopenharmony_ci  if (l <= 0 || (size_t) l >= size) {
55e66f31c5Sopenharmony_ci    return UV_ENOSPC;
56e66f31c5Sopenharmony_ci  }
57e66f31c5Sopenharmony_ci  uv__strscpy(dst, tmp, size);
58e66f31c5Sopenharmony_ci  return 0;
59e66f31c5Sopenharmony_ci}
60e66f31c5Sopenharmony_ci
61e66f31c5Sopenharmony_ci
62e66f31c5Sopenharmony_cistatic int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
63e66f31c5Sopenharmony_ci  /*
64e66f31c5Sopenharmony_ci   * Note that int32_t and int16_t need only be "at least" large enough
65e66f31c5Sopenharmony_ci   * to contain a value of the specified size.  On some systems, like
66e66f31c5Sopenharmony_ci   * Crays, there is no such thing as an integer variable with 16 bits.
67e66f31c5Sopenharmony_ci   * Keep this in mind if you think this function should have been coded
68e66f31c5Sopenharmony_ci   * to use pointer overlays.  All the world's not a VAX.
69e66f31c5Sopenharmony_ci   */
70e66f31c5Sopenharmony_ci  char tmp[UV__INET6_ADDRSTRLEN], *tp;
71e66f31c5Sopenharmony_ci  struct { int base, len; } best, cur;
72e66f31c5Sopenharmony_ci  unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
73e66f31c5Sopenharmony_ci  int i;
74e66f31c5Sopenharmony_ci
75e66f31c5Sopenharmony_ci  /*
76e66f31c5Sopenharmony_ci   * Preprocess:
77e66f31c5Sopenharmony_ci   *  Copy the input (bytewise) array into a wordwise array.
78e66f31c5Sopenharmony_ci   *  Find the longest run of 0x00's in src[] for :: shorthanding.
79e66f31c5Sopenharmony_ci   */
80e66f31c5Sopenharmony_ci  memset(words, '\0', sizeof words);
81e66f31c5Sopenharmony_ci  for (i = 0; i < (int) sizeof(struct in6_addr); i++)
82e66f31c5Sopenharmony_ci    words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
83e66f31c5Sopenharmony_ci  best.base = -1;
84e66f31c5Sopenharmony_ci  best.len = 0;
85e66f31c5Sopenharmony_ci  cur.base = -1;
86e66f31c5Sopenharmony_ci  cur.len = 0;
87e66f31c5Sopenharmony_ci  for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
88e66f31c5Sopenharmony_ci    if (words[i] == 0) {
89e66f31c5Sopenharmony_ci      if (cur.base == -1)
90e66f31c5Sopenharmony_ci        cur.base = i, cur.len = 1;
91e66f31c5Sopenharmony_ci      else
92e66f31c5Sopenharmony_ci        cur.len++;
93e66f31c5Sopenharmony_ci    } else {
94e66f31c5Sopenharmony_ci      if (cur.base != -1) {
95e66f31c5Sopenharmony_ci        if (best.base == -1 || cur.len > best.len)
96e66f31c5Sopenharmony_ci          best = cur;
97e66f31c5Sopenharmony_ci        cur.base = -1;
98e66f31c5Sopenharmony_ci      }
99e66f31c5Sopenharmony_ci    }
100e66f31c5Sopenharmony_ci  }
101e66f31c5Sopenharmony_ci  if (cur.base != -1) {
102e66f31c5Sopenharmony_ci    if (best.base == -1 || cur.len > best.len)
103e66f31c5Sopenharmony_ci      best = cur;
104e66f31c5Sopenharmony_ci  }
105e66f31c5Sopenharmony_ci  if (best.base != -1 && best.len < 2)
106e66f31c5Sopenharmony_ci    best.base = -1;
107e66f31c5Sopenharmony_ci
108e66f31c5Sopenharmony_ci  /*
109e66f31c5Sopenharmony_ci   * Format the result.
110e66f31c5Sopenharmony_ci   */
111e66f31c5Sopenharmony_ci  tp = tmp;
112e66f31c5Sopenharmony_ci  for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
113e66f31c5Sopenharmony_ci    /* Are we inside the best run of 0x00's? */
114e66f31c5Sopenharmony_ci    if (best.base != -1 && i >= best.base &&
115e66f31c5Sopenharmony_ci        i < (best.base + best.len)) {
116e66f31c5Sopenharmony_ci      if (i == best.base)
117e66f31c5Sopenharmony_ci        *tp++ = ':';
118e66f31c5Sopenharmony_ci      continue;
119e66f31c5Sopenharmony_ci    }
120e66f31c5Sopenharmony_ci    /* Are we following an initial run of 0x00s or any real hex? */
121e66f31c5Sopenharmony_ci    if (i != 0)
122e66f31c5Sopenharmony_ci      *tp++ = ':';
123e66f31c5Sopenharmony_ci    /* Is this address an encapsulated IPv4? */
124e66f31c5Sopenharmony_ci    if (i == 6 && best.base == 0 && (best.len == 6 ||
125e66f31c5Sopenharmony_ci        (best.len == 7 && words[7] != 0x0001) ||
126e66f31c5Sopenharmony_ci        (best.len == 5 && words[5] == 0xffff))) {
127e66f31c5Sopenharmony_ci      int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
128e66f31c5Sopenharmony_ci      if (err)
129e66f31c5Sopenharmony_ci        return err;
130e66f31c5Sopenharmony_ci      tp += strlen(tp);
131e66f31c5Sopenharmony_ci      break;
132e66f31c5Sopenharmony_ci    }
133e66f31c5Sopenharmony_ci    tp += snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]);
134e66f31c5Sopenharmony_ci  }
135e66f31c5Sopenharmony_ci  /* Was it a trailing run of 0x00's? */
136e66f31c5Sopenharmony_ci  if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
137e66f31c5Sopenharmony_ci    *tp++ = ':';
138e66f31c5Sopenharmony_ci  *tp++ = '\0';
139e66f31c5Sopenharmony_ci  if ((size_t) (tp - tmp) > size)
140e66f31c5Sopenharmony_ci    return UV_ENOSPC;
141e66f31c5Sopenharmony_ci  uv__strscpy(dst, tmp, size);
142e66f31c5Sopenharmony_ci  return 0;
143e66f31c5Sopenharmony_ci}
144e66f31c5Sopenharmony_ci
145e66f31c5Sopenharmony_ci
146e66f31c5Sopenharmony_ciint uv_inet_pton(int af, const char* src, void* dst) {
147e66f31c5Sopenharmony_ci  if (src == NULL || dst == NULL)
148e66f31c5Sopenharmony_ci    return UV_EINVAL;
149e66f31c5Sopenharmony_ci
150e66f31c5Sopenharmony_ci  switch (af) {
151e66f31c5Sopenharmony_ci  case AF_INET:
152e66f31c5Sopenharmony_ci    return (inet_pton4(src, dst));
153e66f31c5Sopenharmony_ci  case AF_INET6: {
154e66f31c5Sopenharmony_ci    int len;
155e66f31c5Sopenharmony_ci    char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
156e66f31c5Sopenharmony_ci    s = (char*) src;
157e66f31c5Sopenharmony_ci    p = strchr(src, '%');
158e66f31c5Sopenharmony_ci    if (p != NULL) {
159e66f31c5Sopenharmony_ci      s = tmp;
160e66f31c5Sopenharmony_ci      len = p - src;
161e66f31c5Sopenharmony_ci      if (len > UV__INET6_ADDRSTRLEN-1)
162e66f31c5Sopenharmony_ci        return UV_EINVAL;
163e66f31c5Sopenharmony_ci      memcpy(s, src, len);
164e66f31c5Sopenharmony_ci      s[len] = '\0';
165e66f31c5Sopenharmony_ci    }
166e66f31c5Sopenharmony_ci    return inet_pton6(s, dst);
167e66f31c5Sopenharmony_ci  }
168e66f31c5Sopenharmony_ci  default:
169e66f31c5Sopenharmony_ci    return UV_EAFNOSUPPORT;
170e66f31c5Sopenharmony_ci  }
171e66f31c5Sopenharmony_ci  /* NOTREACHED */
172e66f31c5Sopenharmony_ci}
173e66f31c5Sopenharmony_ci
174e66f31c5Sopenharmony_ci
175e66f31c5Sopenharmony_cistatic int inet_pton4(const char *src, unsigned char *dst) {
176e66f31c5Sopenharmony_ci  static const char digits[] = "0123456789";
177e66f31c5Sopenharmony_ci  int saw_digit, octets, ch;
178e66f31c5Sopenharmony_ci  unsigned char tmp[sizeof(struct in_addr)], *tp;
179e66f31c5Sopenharmony_ci
180e66f31c5Sopenharmony_ci  saw_digit = 0;
181e66f31c5Sopenharmony_ci  octets = 0;
182e66f31c5Sopenharmony_ci  *(tp = tmp) = 0;
183e66f31c5Sopenharmony_ci  while ((ch = *src++) != '\0') {
184e66f31c5Sopenharmony_ci    const char *pch;
185e66f31c5Sopenharmony_ci
186e66f31c5Sopenharmony_ci    if ((pch = strchr(digits, ch)) != NULL) {
187e66f31c5Sopenharmony_ci      unsigned int nw = *tp * 10 + (pch - digits);
188e66f31c5Sopenharmony_ci
189e66f31c5Sopenharmony_ci      if (saw_digit && *tp == 0)
190e66f31c5Sopenharmony_ci        return UV_EINVAL;
191e66f31c5Sopenharmony_ci      if (nw > 255)
192e66f31c5Sopenharmony_ci        return UV_EINVAL;
193e66f31c5Sopenharmony_ci      *tp = nw;
194e66f31c5Sopenharmony_ci      if (!saw_digit) {
195e66f31c5Sopenharmony_ci        if (++octets > 4)
196e66f31c5Sopenharmony_ci          return UV_EINVAL;
197e66f31c5Sopenharmony_ci        saw_digit = 1;
198e66f31c5Sopenharmony_ci      }
199e66f31c5Sopenharmony_ci    } else if (ch == '.' && saw_digit) {
200e66f31c5Sopenharmony_ci      if (octets == 4)
201e66f31c5Sopenharmony_ci        return UV_EINVAL;
202e66f31c5Sopenharmony_ci      *++tp = 0;
203e66f31c5Sopenharmony_ci      saw_digit = 0;
204e66f31c5Sopenharmony_ci    } else
205e66f31c5Sopenharmony_ci      return UV_EINVAL;
206e66f31c5Sopenharmony_ci  }
207e66f31c5Sopenharmony_ci  if (octets < 4)
208e66f31c5Sopenharmony_ci    return UV_EINVAL;
209e66f31c5Sopenharmony_ci  memcpy(dst, tmp, sizeof(struct in_addr));
210e66f31c5Sopenharmony_ci  return 0;
211e66f31c5Sopenharmony_ci}
212e66f31c5Sopenharmony_ci
213e66f31c5Sopenharmony_ci
214e66f31c5Sopenharmony_cistatic int inet_pton6(const char *src, unsigned char *dst) {
215e66f31c5Sopenharmony_ci  static const char xdigits_l[] = "0123456789abcdef",
216e66f31c5Sopenharmony_ci                    xdigits_u[] = "0123456789ABCDEF";
217e66f31c5Sopenharmony_ci  unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
218e66f31c5Sopenharmony_ci  const char *xdigits, *curtok;
219e66f31c5Sopenharmony_ci  int ch, seen_xdigits;
220e66f31c5Sopenharmony_ci  unsigned int val;
221e66f31c5Sopenharmony_ci
222e66f31c5Sopenharmony_ci  memset((tp = tmp), '\0', sizeof tmp);
223e66f31c5Sopenharmony_ci  endp = tp + sizeof tmp;
224e66f31c5Sopenharmony_ci  colonp = NULL;
225e66f31c5Sopenharmony_ci  /* Leading :: requires some special handling. */
226e66f31c5Sopenharmony_ci  if (*src == ':')
227e66f31c5Sopenharmony_ci    if (*++src != ':')
228e66f31c5Sopenharmony_ci      return UV_EINVAL;
229e66f31c5Sopenharmony_ci  curtok = src;
230e66f31c5Sopenharmony_ci  seen_xdigits = 0;
231e66f31c5Sopenharmony_ci  val = 0;
232e66f31c5Sopenharmony_ci  while ((ch = *src++) != '\0') {
233e66f31c5Sopenharmony_ci    const char *pch;
234e66f31c5Sopenharmony_ci
235e66f31c5Sopenharmony_ci    if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
236e66f31c5Sopenharmony_ci      pch = strchr((xdigits = xdigits_u), ch);
237e66f31c5Sopenharmony_ci    if (pch != NULL) {
238e66f31c5Sopenharmony_ci      val <<= 4;
239e66f31c5Sopenharmony_ci      val |= (pch - xdigits);
240e66f31c5Sopenharmony_ci      if (++seen_xdigits > 4)
241e66f31c5Sopenharmony_ci        return UV_EINVAL;
242e66f31c5Sopenharmony_ci      continue;
243e66f31c5Sopenharmony_ci    }
244e66f31c5Sopenharmony_ci    if (ch == ':') {
245e66f31c5Sopenharmony_ci      curtok = src;
246e66f31c5Sopenharmony_ci      if (!seen_xdigits) {
247e66f31c5Sopenharmony_ci        if (colonp)
248e66f31c5Sopenharmony_ci          return UV_EINVAL;
249e66f31c5Sopenharmony_ci        colonp = tp;
250e66f31c5Sopenharmony_ci        continue;
251e66f31c5Sopenharmony_ci      } else if (*src == '\0') {
252e66f31c5Sopenharmony_ci        return UV_EINVAL;
253e66f31c5Sopenharmony_ci      }
254e66f31c5Sopenharmony_ci      if (tp + sizeof(uint16_t) > endp)
255e66f31c5Sopenharmony_ci        return UV_EINVAL;
256e66f31c5Sopenharmony_ci      *tp++ = (unsigned char) (val >> 8) & 0xff;
257e66f31c5Sopenharmony_ci      *tp++ = (unsigned char) val & 0xff;
258e66f31c5Sopenharmony_ci      seen_xdigits = 0;
259e66f31c5Sopenharmony_ci      val = 0;
260e66f31c5Sopenharmony_ci      continue;
261e66f31c5Sopenharmony_ci    }
262e66f31c5Sopenharmony_ci    if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
263e66f31c5Sopenharmony_ci      int err = inet_pton4(curtok, tp);
264e66f31c5Sopenharmony_ci      if (err == 0) {
265e66f31c5Sopenharmony_ci        tp += sizeof(struct in_addr);
266e66f31c5Sopenharmony_ci        seen_xdigits = 0;
267e66f31c5Sopenharmony_ci        break;  /*%< '\\0' was seen by inet_pton4(). */
268e66f31c5Sopenharmony_ci      }
269e66f31c5Sopenharmony_ci    }
270e66f31c5Sopenharmony_ci    return UV_EINVAL;
271e66f31c5Sopenharmony_ci  }
272e66f31c5Sopenharmony_ci  if (seen_xdigits) {
273e66f31c5Sopenharmony_ci    if (tp + sizeof(uint16_t) > endp)
274e66f31c5Sopenharmony_ci      return UV_EINVAL;
275e66f31c5Sopenharmony_ci    *tp++ = (unsigned char) (val >> 8) & 0xff;
276e66f31c5Sopenharmony_ci    *tp++ = (unsigned char) val & 0xff;
277e66f31c5Sopenharmony_ci  }
278e66f31c5Sopenharmony_ci  if (colonp != NULL) {
279e66f31c5Sopenharmony_ci    /*
280e66f31c5Sopenharmony_ci     * Since some memmove()'s erroneously fail to handle
281e66f31c5Sopenharmony_ci     * overlapping regions, we'll do the shift by hand.
282e66f31c5Sopenharmony_ci     */
283e66f31c5Sopenharmony_ci    const int n = tp - colonp;
284e66f31c5Sopenharmony_ci    int i;
285e66f31c5Sopenharmony_ci
286e66f31c5Sopenharmony_ci    if (tp == endp)
287e66f31c5Sopenharmony_ci      return UV_EINVAL;
288e66f31c5Sopenharmony_ci    for (i = 1; i <= n; i++) {
289e66f31c5Sopenharmony_ci      endp[- i] = colonp[n - i];
290e66f31c5Sopenharmony_ci      colonp[n - i] = 0;
291e66f31c5Sopenharmony_ci    }
292e66f31c5Sopenharmony_ci    tp = endp;
293e66f31c5Sopenharmony_ci  }
294e66f31c5Sopenharmony_ci  if (tp != endp)
295e66f31c5Sopenharmony_ci    return UV_EINVAL;
296e66f31c5Sopenharmony_ci  memcpy(dst, tmp, sizeof tmp);
297e66f31c5Sopenharmony_ci  return 0;
298e66f31c5Sopenharmony_ci}
299