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