YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/postgres/src/backend/utils/adt/inet_net_pton.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3
 * Copyright (c) 1996,1999 by Internet Software Consortium.
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 *
17
 *    src/backend/utils/adt/inet_net_pton.c
18
 */
19
20
#if defined(LIBC_SCCS) && !defined(lint)
21
static const char rcsid[] = "Id: inet_net_pton.c,v 1.4.2.3 2004/03/17 00:40:11 marka Exp $";
22
#endif
23
24
#include "postgres.h"
25
26
#include <sys/socket.h>
27
#include <netinet/in.h>
28
#include <arpa/inet.h>
29
#include <assert.h>
30
#include <ctype.h>
31
32
#include "utils/builtins.h" /* pgrminclude ignore */  /* needed on some
33
                             * platforms */
34
#include "utils/inet.h"
35
36
37
static int  inet_net_pton_ipv4(const char *src, u_char *dst);
38
static int  inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size);
39
static int  inet_net_pton_ipv6(const char *src, u_char *dst);
40
static int  inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size);
41
42
43
/*
44
 * int
45
 * inet_net_pton(af, src, dst, size)
46
 *  convert network number from presentation to network format.
47
 *  accepts hex octets, hex strings, decimal octets, and /CIDR.
48
 *  "size" is in bytes and describes "dst".
49
 * return:
50
 *  number of bits, either imputed classfully or specified with /CIDR,
51
 *  or -1 if some failure occurred (check errno).  ENOENT means it was
52
 *  not a valid network specification.
53
 * author:
54
 *  Paul Vixie (ISC), June 1996
55
 *
56
 * Changes:
57
 *  I added the inet_cidr_pton function (also from Paul) and changed
58
 *  the names to reflect their current use.
59
 *
60
 */
61
int
62
inet_net_pton(int af, const char *src, void *dst, size_t size)
63
25
{
64
25
  switch (af)
65
25
  {
66
25
    case PGSQL_AF_INET:
67
25
      return size == -1 ?
68
13
        inet_net_pton_ipv4(src, dst) :
69
12
        inet_cidr_pton_ipv4(src, dst, size);
70
0
    case PGSQL_AF_INET6:
71
0
      return size == -1 ?
72
0
        inet_net_pton_ipv6(src, dst) :
73
0
        inet_cidr_pton_ipv6(src, dst, size);
74
0
    default:
75
0
      errno = EAFNOSUPPORT;
76
0
      return -1;
77
25
  }
78
25
}
79
80
/*
81
 * static int
82
 * inet_cidr_pton_ipv4(src, dst, size)
83
 *  convert IPv4 network number from presentation to network format.
84
 *  accepts hex octets, hex strings, decimal octets, and /CIDR.
85
 *  "size" is in bytes and describes "dst".
86
 * return:
87
 *  number of bits, either imputed classfully or specified with /CIDR,
88
 *  or -1 if some failure occurred (check errno).  ENOENT means it was
89
 *  not an IPv4 network specification.
90
 * note:
91
 *  network byte order assumed.  this means 192.5.5.240/28 has
92
 *  0b11110000 in its fourth octet.
93
 * author:
94
 *  Paul Vixie (ISC), June 1996
95
 */
96
static int
97
inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size)
98
12
{
99
12
  static const char xdigits[] = "0123456789abcdef";
100
12
  static const char digits[] = "0123456789";
101
12
  int     n,
102
12
        ch,
103
12
        tmp = 0,
104
12
        dirty,
105
12
        bits;
106
12
  const u_char *odst = dst;
107
108
12
  ch = *src++;
109
12
  if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
110
0
    && isxdigit((unsigned char) src[1]))
111
0
  {
112
    /* Hexadecimal: Eat nybble string. */
113
0
    if (size <= 0U)
114
0
      goto emsgsize;
115
0
    dirty = 0;
116
0
    src++;          /* skip x or X. */
117
0
    while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch))
118
0
    {
119
0
      if (isupper((unsigned char) ch))
120
0
        ch = tolower((unsigned char) ch);
121
0
      n = strchr(xdigits, ch) - xdigits;
122
0
      assert(n >= 0 && n <= 15);
123
0
      if (dirty == 0)
124
0
        tmp = n;
125
0
      else
126
0
        tmp = (tmp << 4) | n;
127
0
      if (++dirty == 2)
128
0
      {
129
0
        if (size-- <= 0U)
130
0
          goto emsgsize;
131
0
        *dst++ = (u_char) tmp;
132
0
        dirty = 0;
133
0
      }
134
0
    }
135
0
    if (dirty)
136
0
    {           /* Odd trailing nybble? */
137
0
      if (size-- <= 0U)
138
0
        goto emsgsize;
139
0
      *dst++ = (u_char) (tmp << 4);
140
0
    }
141
0
  }
142
12
  else if (isdigit((unsigned char) ch))
143
12
  {
144
    /* Decimal: eat dotted digit string. */
145
12
    for (;;)
146
48
    {
147
48
      tmp = 0;
148
48
      do
149
60
      {
150
60
        n = strchr(digits, ch) - digits;
151
60
        assert(n >= 0 && n <= 9);
152
60
        tmp *= 10;
153
60
        tmp += n;
154
60
        if (tmp > 255)
155
0
          goto enoent;
156
60
      } while ((ch = *src++) != '\0' &&
157
60
           isdigit((unsigned char) ch));
158
48
      if (size-- <= 0U)
159
0
        goto emsgsize;
160
48
      *dst++ = (u_char) tmp;
161
48
      if (ch == '\0' || ch == '/')
162
12
        break;
163
36
      if (ch != '.')
164
0
        goto enoent;
165
36
      ch = *src++;
166
36
      if (!isdigit((unsigned char) ch))
167
0
        goto enoent;
168
36
    }
169
12
  }
170
0
  else
171
0
    goto enoent;
172
173
12
  bits = -1;
174
12
  if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
175
12
  {
176
    /* CIDR width specifier.  Nothing can follow it. */
177
12
    ch = *src++;      /* Skip over the /. */
178
12
    bits = 0;
179
12
    do
180
24
    {
181
24
      n = strchr(digits, ch) - digits;
182
24
      assert(n >= 0 && n <= 9);
183
24
      bits *= 10;
184
24
      bits += n;
185
24
    } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
186
12
    if (ch != '\0')
187
0
      goto enoent;
188
12
    if (bits > 32)
189
0
      goto emsgsize;
190
12
  }
191
192
  /* Firey death and destruction unless we prefetched EOS. */
193
12
  if (ch != '\0')
194
0
    goto enoent;
195
196
  /* If nothing was written to the destination, we found no address. */
197
12
  if (dst == odst)
198
0
    goto enoent;
199
  /* If no CIDR spec was given, infer width from net class. */
200
12
  if (bits == -1)
201
0
  {
202
0
    if (*odst >= 240)   /* Class E */
203
0
      bits = 32;
204
0
    else if (*odst >= 224) /* Class D */
205
0
      bits = 8;
206
0
    else if (*odst >= 192) /* Class C */
207
0
      bits = 24;
208
0
    else if (*odst >= 128) /* Class B */
209
0
      bits = 16;
210
0
    else
211
      /* Class A */
212
0
      bits = 8;
213
    /* If imputed mask is narrower than specified octets, widen. */
214
0
    if (bits < ((dst - odst) * 8))
215
0
      bits = (dst - odst) * 8;
216
217
    /*
218
     * If there are no additional bits specified for a class D address
219
     * adjust bits to 4.
220
     */
221
0
    if (bits == 8 && *odst == 224)
222
0
      bits = 4;
223
0
  }
224
  /* Extend network to cover the actual mask. */
225
12
  while (bits > ((dst - odst) * 8))
226
0
  {
227
0
    if (size-- <= 0U)
228
0
      goto emsgsize;
229
0
    *dst++ = '\0';
230
0
  }
231
12
  return bits;
232
233
0
enoent:
234
0
  errno = ENOENT;
235
0
  return -1;
236
237
0
emsgsize:
238
0
  errno = EMSGSIZE;
239
0
  return -1;
240
12
}
241
242
/*
243
 * int
244
 * inet_net_pton(af, src, dst, *bits)
245
 *  convert network address from presentation to network format.
246
 *  accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
247
 *  "dst" is assumed large enough for its "af".  "bits" is set to the
248
 *  /CIDR prefix length, which can have defaults (like /32 for IPv4).
249
 * return:
250
 *  -1 if an error occurred (inspect errno; ENOENT means bad format).
251
 *  0 if successful conversion occurred.
252
 * note:
253
 *  192.5.5.1/28 has a nonzero host part, which means it isn't a network
254
 *  as called for by inet_cidr_pton() but it can be a host address with
255
 *  an included netmask.
256
 * author:
257
 *  Paul Vixie (ISC), October 1998
258
 */
259
static int
260
inet_net_pton_ipv4(const char *src, u_char *dst)
261
13
{
262
13
  static const char digits[] = "0123456789";
263
13
  const u_char *odst = dst;
264
13
  int     n,
265
13
        ch,
266
13
        tmp,
267
13
        bits;
268
13
  size_t    size = 4;
269
270
  /* Get the mantissa. */
271
52
  while (ch = *src++, isdigit((unsigned char) ch))
272
52
  {
273
52
    tmp = 0;
274
52
    do
275
88
    {
276
88
      n = strchr(digits, ch) - digits;
277
88
      assert(n >= 0 && n <= 9);
278
88
      tmp *= 10;
279
88
      tmp += n;
280
88
      if (tmp > 255)
281
0
        goto enoent;
282
88
    } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
283
52
    if (size-- == 0)
284
0
      goto emsgsize;
285
52
    *dst++ = (u_char) tmp;
286
52
    if (ch == '\0' || ch == '/')
287
13
      break;
288
39
    if (ch != '.')
289
0
      goto enoent;
290
39
  }
291
292
  /* Get the prefix length if any. */
293
13
  bits = -1;
294
13
  if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
295
0
  {
296
    /* CIDR width specifier.  Nothing can follow it. */
297
0
    ch = *src++;      /* Skip over the /. */
298
0
    bits = 0;
299
0
    do
300
0
    {
301
0
      n = strchr(digits, ch) - digits;
302
0
      assert(n >= 0 && n <= 9);
303
0
      bits *= 10;
304
0
      bits += n;
305
0
    } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
306
0
    if (ch != '\0')
307
0
      goto enoent;
308
0
    if (bits > 32)
309
0
      goto emsgsize;
310
13
  }
311
312
  /* Firey death and destruction unless we prefetched EOS. */
313
13
  if (ch != '\0')
314
0
    goto enoent;
315
316
  /* Prefix length can default to /32 only if all four octets spec'd. */
317
13
  if (bits == -1)
318
13
  {
319
13
    if (dst - odst == 4)
320
13
      bits = 32;
321
0
    else
322
0
      goto enoent;
323
13
  }
324
325
  /* If nothing was written to the destination, we found no address. */
326
13
  if (dst == odst)
327
0
    goto enoent;
328
329
  /* If prefix length overspecifies mantissa, life is bad. */
330
13
  if ((bits / 8) > (dst - odst))
331
0
    goto enoent;
332
333
  /* Extend address to four octets. */
334
13
  while (size-- > 0)
335
0
    *dst++ = 0;
336
337
13
  return bits;
338
339
0
enoent:
340
0
  errno = ENOENT;
341
0
  return -1;
342
343
0
emsgsize:
344
0
  errno = EMSGSIZE;
345
0
  return -1;
346
13
}
347
348
static int
349
getbits(const char *src, int *bitsp)
350
0
{
351
0
  static const char digits[] = "0123456789";
352
0
  int     n;
353
0
  int     val;
354
0
  char    ch;
355
356
0
  val = 0;
357
0
  n = 0;
358
0
  while ((ch = *src++) != '\0')
359
0
  {
360
0
    const char *pch;
361
362
0
    pch = strchr(digits, ch);
363
0
    if (pch != NULL)
364
0
    {
365
0
      if (n++ != 0 && val == 0) /* no leading zeros */
366
0
        return 0;
367
0
      val *= 10;
368
0
      val += (pch - digits);
369
0
      if (val > 128)   /* range */
370
0
        return 0;
371
0
      continue;
372
0
    }
373
0
    return 0;
374
0
  }
375
0
  if (n == 0)
376
0
    return 0;
377
0
  *bitsp = val;
378
0
  return 1;
379
0
}
380
381
static int
382
getv4(const char *src, u_char *dst, int *bitsp)
383
0
{
384
0
  static const char digits[] = "0123456789";
385
0
  u_char     *odst = dst;
386
0
  int     n;
387
0
  u_int   val;
388
0
  char    ch;
389
390
0
  val = 0;
391
0
  n = 0;
392
0
  while ((ch = *src++) != '\0')
393
0
  {
394
0
    const char *pch;
395
396
0
    pch = strchr(digits, ch);
397
0
    if (pch != NULL)
398
0
    {
399
0
      if (n++ != 0 && val == 0) /* no leading zeros */
400
0
        return 0;
401
0
      val *= 10;
402
0
      val += (pch - digits);
403
0
      if (val > 255)   /* range */
404
0
        return 0;
405
0
      continue;
406
0
    }
407
0
    if (ch == '.' || ch == '/')
408
0
    {
409
0
      if (dst - odst > 3) /* too many octets? */
410
0
        return 0;
411
0
      *dst++ = val;
412
0
      if (ch == '/')
413
0
        return getbits(src, bitsp);
414
0
      val = 0;
415
0
      n = 0;
416
0
      continue;
417
0
    }
418
0
    return 0;
419
0
  }
420
0
  if (n == 0)
421
0
    return 0;
422
0
  if (dst - odst > 3)     /* too many octets? */
423
0
    return 0;
424
0
  *dst++ = val;
425
0
  return 1;
426
0
}
427
428
static int
429
inet_net_pton_ipv6(const char *src, u_char *dst)
430
0
{
431
0
  return inet_cidr_pton_ipv6(src, dst, 16);
432
0
}
433
434
0
#define NS_IN6ADDRSZ 16
435
0
#define NS_INT16SZ 2
436
0
#define NS_INADDRSZ 4
437
438
static int
439
inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size)
440
0
{
441
0
  static const char xdigits_l[] = "0123456789abcdef",
442
0
        xdigits_u[] = "0123456789ABCDEF";
443
0
  u_char    tmp[NS_IN6ADDRSZ],
444
0
         *tp,
445
0
         *endp,
446
0
         *colonp;
447
0
  const char *xdigits,
448
0
         *curtok;
449
0
  int     ch,
450
0
        saw_xdigit;
451
0
  u_int   val;
452
0
  int     digits;
453
0
  int     bits;
454
455
0
  if (size < NS_IN6ADDRSZ)
456
0
    goto emsgsize;
457
458
0
  memset((tp = tmp), '\0', NS_IN6ADDRSZ);
459
0
  endp = tp + NS_IN6ADDRSZ;
460
0
  colonp = NULL;
461
  /* Leading :: requires some special handling. */
462
0
  if (*src == ':')
463
0
    if (*++src != ':')
464
0
      goto enoent;
465
0
  curtok = src;
466
0
  saw_xdigit = 0;
467
0
  val = 0;
468
0
  digits = 0;
469
0
  bits = -1;
470
0
  while ((ch = *src++) != '\0')
471
0
  {
472
0
    const char *pch;
473
474
0
    if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
475
0
      pch = strchr((xdigits = xdigits_u), ch);
476
0
    if (pch != NULL)
477
0
    {
478
0
      val <<= 4;
479
0
      val |= (pch - xdigits);
480
0
      if (++digits > 4)
481
0
        goto enoent;
482
0
      saw_xdigit = 1;
483
0
      continue;
484
0
    }
485
0
    if (ch == ':')
486
0
    {
487
0
      curtok = src;
488
0
      if (!saw_xdigit)
489
0
      {
490
0
        if (colonp)
491
0
          goto enoent;
492
0
        colonp = tp;
493
0
        continue;
494
0
      }
495
0
      else if (*src == '\0')
496
0
        goto enoent;
497
0
      if (tp + NS_INT16SZ > endp)
498
0
        goto enoent;
499
0
      *tp++ = (u_char) (val >> 8) & 0xff;
500
0
      *tp++ = (u_char) val & 0xff;
501
0
      saw_xdigit = 0;
502
0
      digits = 0;
503
0
      val = 0;
504
0
      continue;
505
0
    }
506
0
    if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
507
0
      getv4(curtok, tp, &bits) > 0)
508
0
    {
509
0
      tp += NS_INADDRSZ;
510
0
      saw_xdigit = 0;
511
0
      break;        /* '\0' was seen by inet_pton4(). */
512
0
    }
513
0
    if (ch == '/' && getbits(src, &bits) > 0)
514
0
      break;
515
0
    goto enoent;
516
0
  }
517
0
  if (saw_xdigit)
518
0
  {
519
0
    if (tp + NS_INT16SZ > endp)
520
0
      goto enoent;
521
0
    *tp++ = (u_char) (val >> 8) & 0xff;
522
0
    *tp++ = (u_char) val & 0xff;
523
0
  }
524
0
  if (bits == -1)
525
0
    bits = 128;
526
527
0
  endp = tmp + 16;
528
529
0
  if (colonp != NULL)
530
0
  {
531
    /*
532
     * Since some memmove()'s erroneously fail to handle overlapping
533
     * regions, we'll do the shift by hand.
534
     */
535
0
    const int n = tp - colonp;
536
0
    int     i;
537
538
0
    if (tp == endp)
539
0
      goto enoent;
540
0
    for (i = 1; i <= n; i++)
541
0
    {
542
0
      endp[-i] = colonp[n - i];
543
0
      colonp[n - i] = 0;
544
0
    }
545
0
    tp = endp;
546
0
  }
547
0
  if (tp != endp)
548
0
    goto enoent;
549
550
  /*
551
   * Copy out the result.
552
   */
553
0
  memcpy(dst, tmp, NS_IN6ADDRSZ);
554
555
0
  return bits;
556
557
0
enoent:
558
0
  errno = ENOENT;
559
0
  return -1;
560
561
0
emsgsize:
562
0
  errno = EMSGSIZE;
563
0
  return -1;
564
0
}