PostgreSQL Source Code  git master
inet_net_pton.c File Reference
#include "postgres.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include "utils/builtins.h"
#include "utils/inet.h"
Include dependency graph for inet_net_pton.c:

Go to the source code of this file.

Macros

#define NS_IN6ADDRSZ   16
 
#define NS_INT16SZ   2
 
#define NS_INADDRSZ   4
 

Functions

static int inet_net_pton_ipv4 (const char *src, u_char *dst)
 
static int inet_cidr_pton_ipv4 (const char *src, u_char *dst, size_t size)
 
static int inet_net_pton_ipv6 (const char *src, u_char *dst)
 
static int inet_cidr_pton_ipv6 (const char *src, u_char *dst, size_t size)
 
int pg_inet_net_pton (int af, const char *src, void *dst, size_t size)
 
static int getbits (const char *src, int *bitsp)
 
static int getv4 (const char *src, u_char *dst, int *bitsp)
 

Macro Definition Documentation

◆ NS_IN6ADDRSZ

#define NS_IN6ADDRSZ   16

Definition at line 434 of file inet_net_pton.c.

◆ NS_INADDRSZ

#define NS_INADDRSZ   4

Definition at line 436 of file inet_net_pton.c.

◆ NS_INT16SZ

#define NS_INT16SZ   2

Definition at line 435 of file inet_net_pton.c.

Function Documentation

◆ getbits()

static int getbits ( const char *  src,
int *  bitsp 
)
static

Definition at line 349 of file inet_net_pton.c.

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 }
long val
Definition: informix.c:689
int digits
Definition: informix.c:691

References digits, and val.

Referenced by getv4(), and inet_cidr_pton_ipv6().

◆ getv4()

static int getv4 ( const char *  src,
u_char *  dst,
int *  bitsp 
)
static

Definition at line 382 of file inet_net_pton.c.

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 }
static int getbits(const char *src, int *bitsp)

References digits, getbits(), and val.

Referenced by inet_cidr_pton_ipv6().

◆ inet_cidr_pton_ipv4()

static int inet_cidr_pton_ipv4 ( const char *  src,
u_char *  dst,
size_t  size 
)
static

Definition at line 97 of file inet_net_pton.c.

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 }
#define assert(x)
Definition: regcustom.h:56
static pg_noinline void Size size
Definition: slab.c:607
#define EMSGSIZE
Definition: win32_port.h:376

References assert, digits, EMSGSIZE, and size.

Referenced by pg_inet_net_pton().

◆ inet_cidr_pton_ipv6()

static int inet_cidr_pton_ipv6 ( const char *  src,
u_char *  dst,
size_t  size 
)
static

Definition at line 439 of file inet_net_pton.c.

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 }
#define NS_IN6ADDRSZ
#define NS_INT16SZ
static int getv4(const char *src, u_char *dst, int *bitsp)
#define NS_INADDRSZ
int i
Definition: isn.c:72

References digits, EMSGSIZE, getbits(), getv4(), i, NS_IN6ADDRSZ, NS_INADDRSZ, NS_INT16SZ, size, and val.

Referenced by inet_net_pton_ipv6(), and pg_inet_net_pton().

◆ inet_net_pton_ipv4()

static int inet_net_pton_ipv4 ( const char *  src,
u_char *  dst 
)
static

Definition at line 260 of file inet_net_pton.c.

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 }

References assert, digits, EMSGSIZE, and size.

Referenced by pg_inet_net_pton().

◆ inet_net_pton_ipv6()

static int inet_net_pton_ipv6 ( const char *  src,
u_char *  dst 
)
static

Definition at line 429 of file inet_net_pton.c.

430 {
431  return inet_cidr_pton_ipv6(src, dst, 16);
432 }
static int inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size)

References inet_cidr_pton_ipv6().

Referenced by pg_inet_net_pton().

◆ pg_inet_net_pton()

int pg_inet_net_pton ( int  af,
const char *  src,
void *  dst,
size_t  size 
)

Definition at line 62 of file inet_net_pton.c.

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 }
static int inet_net_pton_ipv6(const char *src, u_char *dst)
static int inet_net_pton_ipv4(const char *src, u_char *dst)
static int inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size)
Definition: inet_net_pton.c:97
#define PGSQL_AF_INET
Definition: inet.h:39
#define PGSQL_AF_INET6
Definition: inet.h:40
#define EAFNOSUPPORT
Definition: win32_port.h:378

References EAFNOSUPPORT, inet_cidr_pton_ipv4(), inet_cidr_pton_ipv6(), inet_net_pton_ipv4(), inet_net_pton_ipv6(), PGSQL_AF_INET, PGSQL_AF_INET6, and size.

Referenced by network_in().