PostgreSQL Source Code  git master
inet_net_pton.c
Go to the documentation of this file.
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  * pg_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 pg_inet_net_pton(int af, const char *src, void *dst, size_t size)
63 {
64  switch (af)
65  {
66  case PGSQL_AF_INET:
67  return size == -1 ?
68  inet_net_pton_ipv4(src, dst) :
69  inet_cidr_pton_ipv4(src, dst, size);
70  case PGSQL_AF_INET6:
71  return size == -1 ?
72  inet_net_pton_ipv6(src, dst) :
73  inet_cidr_pton_ipv6(src, dst, size);
74  default:
75  errno = EAFNOSUPPORT;
76  return -1;
77  }
78 }
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 {
99  static const char xdigits[] = "0123456789abcdef";
100  static const char digits[] = "0123456789";
101  int n,
102  ch,
103  tmp = 0,
104  dirty,
105  bits;
106  const u_char *odst = dst;
107 
108  ch = *src++;
109  if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
110  && isxdigit((unsigned char) src[1]))
111  {
112  /* Hexadecimal: Eat nybble string. */
113  if (size <= 0U)
114  goto emsgsize;
115  dirty = 0;
116  src++; /* skip x or X. */
117  while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch))
118  {
119  if (isupper((unsigned char) ch))
120  ch = tolower((unsigned char) ch);
121  n = strchr(xdigits, ch) - xdigits;
122  assert(n >= 0 && n <= 15);
123  if (dirty == 0)
124  tmp = n;
125  else
126  tmp = (tmp << 4) | n;
127  if (++dirty == 2)
128  {
129  if (size-- <= 0U)
130  goto emsgsize;
131  *dst++ = (u_char) tmp;
132  dirty = 0;
133  }
134  }
135  if (dirty)
136  { /* Odd trailing nybble? */
137  if (size-- <= 0U)
138  goto emsgsize;
139  *dst++ = (u_char) (tmp << 4);
140  }
141  }
142  else if (isdigit((unsigned char) ch))
143  {
144  /* Decimal: eat dotted digit string. */
145  for (;;)
146  {
147  tmp = 0;
148  do
149  {
150  n = strchr(digits, ch) - digits;
151  assert(n >= 0 && n <= 9);
152  tmp *= 10;
153  tmp += n;
154  if (tmp > 255)
155  goto enoent;
156  } while ((ch = *src++) != '\0' &&
157  isdigit((unsigned char) ch));
158  if (size-- <= 0U)
159  goto emsgsize;
160  *dst++ = (u_char) tmp;
161  if (ch == '\0' || ch == '/')
162  break;
163  if (ch != '.')
164  goto enoent;
165  ch = *src++;
166  if (!isdigit((unsigned char) ch))
167  goto enoent;
168  }
169  }
170  else
171  goto enoent;
172 
173  bits = -1;
174  if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
175  {
176  /* CIDR width specifier. Nothing can follow it. */
177  ch = *src++; /* Skip over the /. */
178  bits = 0;
179  do
180  {
181  n = strchr(digits, ch) - digits;
182  assert(n >= 0 && n <= 9);
183  bits *= 10;
184  bits += n;
185  } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
186  if (ch != '\0')
187  goto enoent;
188  if (bits > 32)
189  goto emsgsize;
190  }
191 
192  /* Fiery death and destruction unless we prefetched EOS. */
193  if (ch != '\0')
194  goto enoent;
195 
196  /* If nothing was written to the destination, we found no address. */
197  if (dst == odst)
198  goto enoent;
199  /* If no CIDR spec was given, infer width from net class. */
200  if (bits == -1)
201  {
202  if (*odst >= 240) /* Class E */
203  bits = 32;
204  else if (*odst >= 224) /* Class D */
205  bits = 8;
206  else if (*odst >= 192) /* Class C */
207  bits = 24;
208  else if (*odst >= 128) /* Class B */
209  bits = 16;
210  else
211  /* Class A */
212  bits = 8;
213  /* If imputed mask is narrower than specified octets, widen. */
214  if (bits < ((dst - odst) * 8))
215  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  if (bits == 8 && *odst == 224)
222  bits = 4;
223  }
224  /* Extend network to cover the actual mask. */
225  while (bits > ((dst - odst) * 8))
226  {
227  if (size-- <= 0U)
228  goto emsgsize;
229  *dst++ = '\0';
230  }
231  return bits;
232 
233 enoent:
234  errno = ENOENT;
235  return -1;
236 
237 emsgsize:
238  errno = EMSGSIZE;
239  return -1;
240 }
241 
242 /*
243  * int
244  * inet_net_pton_ipv4(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 {
262  static const char digits[] = "0123456789";
263  const u_char *odst = dst;
264  int n,
265  ch,
266  tmp,
267  bits;
268  size_t size = 4;
269 
270  /* Get the mantissa. */
271  while (ch = *src++, isdigit((unsigned char) ch))
272  {
273  tmp = 0;
274  do
275  {
276  n = strchr(digits, ch) - digits;
277  assert(n >= 0 && n <= 9);
278  tmp *= 10;
279  tmp += n;
280  if (tmp > 255)
281  goto enoent;
282  } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
283  if (size-- == 0)
284  goto emsgsize;
285  *dst++ = (u_char) tmp;
286  if (ch == '\0' || ch == '/')
287  break;
288  if (ch != '.')
289  goto enoent;
290  }
291 
292  /* Get the prefix length if any. */
293  bits = -1;
294  if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
295  {
296  /* CIDR width specifier. Nothing can follow it. */
297  ch = *src++; /* Skip over the /. */
298  bits = 0;
299  do
300  {
301  n = strchr(digits, ch) - digits;
302  assert(n >= 0 && n <= 9);
303  bits *= 10;
304  bits += n;
305  } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
306  if (ch != '\0')
307  goto enoent;
308  if (bits > 32)
309  goto emsgsize;
310  }
311 
312  /* Fiery death and destruction unless we prefetched EOS. */
313  if (ch != '\0')
314  goto enoent;
315 
316  /* Prefix length can default to /32 only if all four octets spec'd. */
317  if (bits == -1)
318  {
319  if (dst - odst == 4)
320  bits = 32;
321  else
322  goto enoent;
323  }
324 
325  /* If nothing was written to the destination, we found no address. */
326  if (dst == odst)
327  goto enoent;
328 
329  /* If prefix length overspecifies mantissa, life is bad. */
330  if ((bits / 8) > (dst - odst))
331  goto enoent;
332 
333  /* Extend address to four octets. */
334  while (size-- > 0)
335  *dst++ = 0;
336 
337  return bits;
338 
339 enoent:
340  errno = ENOENT;
341  return -1;
342 
343 emsgsize:
344  errno = EMSGSIZE;
345  return -1;
346 }
347 
348 static int
349 getbits(const char *src, int *bitsp)
350 {
351  static const char digits[] = "0123456789";
352  int n;
353  int val;
354  char ch;
355 
356  val = 0;
357  n = 0;
358  while ((ch = *src++) != '\0')
359  {
360  const char *pch;
361 
362  pch = strchr(digits, ch);
363  if (pch != NULL)
364  {
365  if (n++ != 0 && val == 0) /* no leading zeros */
366  return 0;
367  val *= 10;
368  val += (pch - digits);
369  if (val > 128) /* range */
370  return 0;
371  continue;
372  }
373  return 0;
374  }
375  if (n == 0)
376  return 0;
377  *bitsp = val;
378  return 1;
379 }
380 
381 static int
382 getv4(const char *src, u_char *dst, int *bitsp)
383 {
384  static const char digits[] = "0123456789";
385  u_char *odst = dst;
386  int n;
387  u_int val;
388  char ch;
389 
390  val = 0;
391  n = 0;
392  while ((ch = *src++) != '\0')
393  {
394  const char *pch;
395 
396  pch = strchr(digits, ch);
397  if (pch != NULL)
398  {
399  if (n++ != 0 && val == 0) /* no leading zeros */
400  return 0;
401  val *= 10;
402  val += (pch - digits);
403  if (val > 255) /* range */
404  return 0;
405  continue;
406  }
407  if (ch == '.' || ch == '/')
408  {
409  if (dst - odst > 3) /* too many octets? */
410  return 0;
411  *dst++ = val;
412  if (ch == '/')
413  return getbits(src, bitsp);
414  val = 0;
415  n = 0;
416  continue;
417  }
418  return 0;
419  }
420  if (n == 0)
421  return 0;
422  if (dst - odst > 3) /* too many octets? */
423  return 0;
424  *dst++ = val;
425  return 1;
426 }
427 
428 static int
429 inet_net_pton_ipv6(const char *src, u_char *dst)
430 {
431  return inet_cidr_pton_ipv6(src, dst, 16);
432 }
433 
434 #define NS_IN6ADDRSZ 16
435 #define NS_INT16SZ 2
436 #define NS_INADDRSZ 4
437 
438 static int
439 inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size)
440 {
441  static const char xdigits_l[] = "0123456789abcdef",
442  xdigits_u[] = "0123456789ABCDEF";
443  u_char tmp[NS_IN6ADDRSZ],
444  *tp,
445  *endp,
446  *colonp;
447  const char *xdigits,
448  *curtok;
449  int ch,
450  saw_xdigit;
451  u_int val;
452  int digits;
453  int bits;
454 
455  if (size < NS_IN6ADDRSZ)
456  goto emsgsize;
457 
458  memset((tp = tmp), '\0', NS_IN6ADDRSZ);
459  endp = tp + NS_IN6ADDRSZ;
460  colonp = NULL;
461  /* Leading :: requires some special handling. */
462  if (*src == ':')
463  if (*++src != ':')
464  goto enoent;
465  curtok = src;
466  saw_xdigit = 0;
467  val = 0;
468  digits = 0;
469  bits = -1;
470  while ((ch = *src++) != '\0')
471  {
472  const char *pch;
473 
474  if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
475  pch = strchr((xdigits = xdigits_u), ch);
476  if (pch != NULL)
477  {
478  val <<= 4;
479  val |= (pch - xdigits);
480  if (++digits > 4)
481  goto enoent;
482  saw_xdigit = 1;
483  continue;
484  }
485  if (ch == ':')
486  {
487  curtok = src;
488  if (!saw_xdigit)
489  {
490  if (colonp)
491  goto enoent;
492  colonp = tp;
493  continue;
494  }
495  else if (*src == '\0')
496  goto enoent;
497  if (tp + NS_INT16SZ > endp)
498  goto enoent;
499  *tp++ = (u_char) (val >> 8) & 0xff;
500  *tp++ = (u_char) val & 0xff;
501  saw_xdigit = 0;
502  digits = 0;
503  val = 0;
504  continue;
505  }
506  if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
507  getv4(curtok, tp, &bits) > 0)
508  {
509  tp += NS_INADDRSZ;
510  saw_xdigit = 0;
511  break; /* '\0' was seen by inet_pton4(). */
512  }
513  if (ch == '/' && getbits(src, &bits) > 0)
514  break;
515  goto enoent;
516  }
517  if (saw_xdigit)
518  {
519  if (tp + NS_INT16SZ > endp)
520  goto enoent;
521  *tp++ = (u_char) (val >> 8) & 0xff;
522  *tp++ = (u_char) val & 0xff;
523  }
524  if (bits == -1)
525  bits = 128;
526 
527  endp = tmp + 16;
528 
529  if (colonp != NULL)
530  {
531  /*
532  * Since some memmove()'s erroneously fail to handle overlapping
533  * regions, we'll do the shift by hand.
534  */
535  const int n = tp - colonp;
536  int i;
537 
538  if (tp == endp)
539  goto enoent;
540  for (i = 1; i <= n; i++)
541  {
542  endp[-i] = colonp[n - i];
543  colonp[n - i] = 0;
544  }
545  tp = endp;
546  }
547  if (tp != endp)
548  goto enoent;
549 
550  /*
551  * Copy out the result.
552  */
553  memcpy(dst, tmp, NS_IN6ADDRSZ);
554 
555  return bits;
556 
557 enoent:
558  errno = ENOENT;
559  return -1;
560 
561 emsgsize:
562  errno = EMSGSIZE;
563  return -1;
564 }
int pg_inet_net_pton(int af, const char *src, void *dst, size_t size)
Definition: inet_net_pton.c:62
static int inet_net_pton_ipv6(const char *src, u_char *dst)
static int inet_net_pton_ipv4(const char *src, u_char *dst)
#define NS_IN6ADDRSZ
#define NS_INT16SZ
static int getbits(const char *src, int *bitsp)
static int getv4(const char *src, u_char *dst, int *bitsp)
#define NS_INADDRSZ
static int inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size)
static int inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size)
Definition: inet_net_pton.c:97
long val
Definition: informix.c:670
int digits
Definition: informix.c:672
int i
Definition: isn.c:73
#define assert(x)
Definition: regcustom.h:56
static pg_noinline void Size size
Definition: slab.c:607
#define PGSQL_AF_INET
Definition: inet.h:39
#define PGSQL_AF_INET6
Definition: inet.h:40
#define EAFNOSUPPORT
Definition: win32_port.h:378
#define EMSGSIZE
Definition: win32_port.h:376