PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 433 of file inet_net_pton.c.

◆ NS_INADDRSZ

#define NS_INADDRSZ   4

Definition at line 435 of file inet_net_pton.c.

◆ NS_INT16SZ

#define NS_INT16SZ   2

Definition at line 434 of file inet_net_pton.c.

Function Documentation

◆ getbits()

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

Definition at line 348 of file inet_net_pton.c.

349{
350 static const char digits[] = "0123456789";
351 int n;
352 int val;
353 char ch;
354
355 val = 0;
356 n = 0;
357 while ((ch = *src++) != '\0')
358 {
359 const char *pch;
360
361 pch = strchr(digits, ch);
362 if (pch != NULL)
363 {
364 if (n++ != 0 && val == 0) /* no leading zeros */
365 return 0;
366 val *= 10;
367 val += (pch - digits);
368 if (val > 128) /* range */
369 return 0;
370 continue;
371 }
372 return 0;
373 }
374 if (n == 0)
375 return 0;
376 *bitsp = val;
377 return 1;
378}
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 381 of file inet_net_pton.c.

382{
383 static const char digits[] = "0123456789";
384 u_char *odst = dst;
385 int n;
386 u_int val;
387 char ch;
388
389 val = 0;
390 n = 0;
391 while ((ch = *src++) != '\0')
392 {
393 const char *pch;
394
395 pch = strchr(digits, ch);
396 if (pch != NULL)
397 {
398 if (n++ != 0 && val == 0) /* no leading zeros */
399 return 0;
400 val *= 10;
401 val += (pch - digits);
402 if (val > 255) /* range */
403 return 0;
404 continue;
405 }
406 if (ch == '.' || ch == '/')
407 {
408 if (dst - odst > 3) /* too many octets? */
409 return 0;
410 *dst++ = val;
411 if (ch == '/')
412 return getbits(src, bitsp);
413 val = 0;
414 n = 0;
415 continue;
416 }
417 return 0;
418 }
419 if (n == 0)
420 return 0;
421 if (dst - odst > 3) /* too many octets? */
422 return 0;
423 *dst++ = val;
424 return 1;
425}
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 96 of file inet_net_pton.c.

97{
98 static const char xdigits[] = "0123456789abcdef";
99 static const char digits[] = "0123456789";
100 int n,
101 ch,
102 tmp = 0,
103 dirty,
104 bits;
105 const u_char *odst = dst;
106
107 ch = *src++;
108 if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
109 && isxdigit((unsigned char) src[1]))
110 {
111 /* Hexadecimal: Eat nybble string. */
112 if (size <= 0U)
113 goto emsgsize;
114 dirty = 0;
115 src++; /* skip x or X. */
116 while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch))
117 {
118 if (isupper((unsigned char) ch))
119 ch = tolower((unsigned char) ch);
120 n = strchr(xdigits, ch) - xdigits;
121 assert(n >= 0 && n <= 15);
122 if (dirty == 0)
123 tmp = n;
124 else
125 tmp = (tmp << 4) | n;
126 if (++dirty == 2)
127 {
128 if (size-- <= 0U)
129 goto emsgsize;
130 *dst++ = (u_char) tmp;
131 dirty = 0;
132 }
133 }
134 if (dirty)
135 { /* Odd trailing nybble? */
136 if (size-- <= 0U)
137 goto emsgsize;
138 *dst++ = (u_char) (tmp << 4);
139 }
140 }
141 else if (isdigit((unsigned char) ch))
142 {
143 /* Decimal: eat dotted digit string. */
144 for (;;)
145 {
146 tmp = 0;
147 do
148 {
149 n = strchr(digits, ch) - digits;
150 assert(n >= 0 && n <= 9);
151 tmp *= 10;
152 tmp += n;
153 if (tmp > 255)
154 goto enoent;
155 } while ((ch = *src++) != '\0' &&
156 isdigit((unsigned char) ch));
157 if (size-- <= 0U)
158 goto emsgsize;
159 *dst++ = (u_char) tmp;
160 if (ch == '\0' || ch == '/')
161 break;
162 if (ch != '.')
163 goto enoent;
164 ch = *src++;
165 if (!isdigit((unsigned char) ch))
166 goto enoent;
167 }
168 }
169 else
170 goto enoent;
171
172 bits = -1;
173 if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
174 {
175 /* CIDR width specifier. Nothing can follow it. */
176 ch = *src++; /* Skip over the /. */
177 bits = 0;
178 do
179 {
180 n = strchr(digits, ch) - digits;
181 assert(n >= 0 && n <= 9);
182 bits *= 10;
183 bits += n;
184 } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
185 if (ch != '\0')
186 goto enoent;
187 if (bits > 32)
188 goto emsgsize;
189 }
190
191 /* Fiery death and destruction unless we prefetched EOS. */
192 if (ch != '\0')
193 goto enoent;
194
195 /* If nothing was written to the destination, we found no address. */
196 if (dst == odst)
197 goto enoent;
198 /* If no CIDR spec was given, infer width from net class. */
199 if (bits == -1)
200 {
201 if (*odst >= 240) /* Class E */
202 bits = 32;
203 else if (*odst >= 224) /* Class D */
204 bits = 8;
205 else if (*odst >= 192) /* Class C */
206 bits = 24;
207 else if (*odst >= 128) /* Class B */
208 bits = 16;
209 else
210 /* Class A */
211 bits = 8;
212 /* If imputed mask is narrower than specified octets, widen. */
213 if (bits < ((dst - odst) * 8))
214 bits = (dst - odst) * 8;
215
216 /*
217 * If there are no additional bits specified for a class D address
218 * adjust bits to 4.
219 */
220 if (bits == 8 && *odst == 224)
221 bits = 4;
222 }
223 /* Extend network to cover the actual mask. */
224 while (bits > ((dst - odst) * 8))
225 {
226 if (size-- <= 0U)
227 goto emsgsize;
228 *dst++ = '\0';
229 }
230 return bits;
231
232enoent:
233 errno = ENOENT;
234 return -1;
235
236emsgsize:
237 errno = EMSGSIZE;
238 return -1;
239}
#define assert(x)
Definition: regcustom.h:56
#define EMSGSIZE
Definition: win32_port.h:366

References assert, digits, and EMSGSIZE.

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 438 of file inet_net_pton.c.

439{
440 static const char xdigits_l[] = "0123456789abcdef",
441 xdigits_u[] = "0123456789ABCDEF";
442 u_char tmp[NS_IN6ADDRSZ],
443 *tp,
444 *endp,
445 *colonp;
446 const char *xdigits,
447 *curtok;
448 int ch,
449 saw_xdigit;
450 u_int val;
451 int digits;
452 int bits;
453
454 if (size < NS_IN6ADDRSZ)
455 goto emsgsize;
456
457 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
458 endp = tp + NS_IN6ADDRSZ;
459 colonp = NULL;
460 /* Leading :: requires some special handling. */
461 if (*src == ':')
462 if (*++src != ':')
463 goto enoent;
464 curtok = src;
465 saw_xdigit = 0;
466 val = 0;
467 digits = 0;
468 bits = -1;
469 while ((ch = *src++) != '\0')
470 {
471 const char *pch;
472
473 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
474 pch = strchr((xdigits = xdigits_u), ch);
475 if (pch != NULL)
476 {
477 val <<= 4;
478 val |= (pch - xdigits);
479 if (++digits > 4)
480 goto enoent;
481 saw_xdigit = 1;
482 continue;
483 }
484 if (ch == ':')
485 {
486 curtok = src;
487 if (!saw_xdigit)
488 {
489 if (colonp)
490 goto enoent;
491 colonp = tp;
492 continue;
493 }
494 else if (*src == '\0')
495 goto enoent;
496 if (tp + NS_INT16SZ > endp)
497 goto enoent;
498 *tp++ = (u_char) (val >> 8) & 0xff;
499 *tp++ = (u_char) val & 0xff;
500 saw_xdigit = 0;
501 digits = 0;
502 val = 0;
503 continue;
504 }
505 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
506 getv4(curtok, tp, &bits) > 0)
507 {
508 tp += NS_INADDRSZ;
509 saw_xdigit = 0;
510 break; /* '\0' was seen by inet_pton4(). */
511 }
512 if (ch == '/' && getbits(src, &bits) > 0)
513 break;
514 goto enoent;
515 }
516 if (saw_xdigit)
517 {
518 if (tp + NS_INT16SZ > endp)
519 goto enoent;
520 *tp++ = (u_char) (val >> 8) & 0xff;
521 *tp++ = (u_char) val & 0xff;
522 }
523 if (bits == -1)
524 bits = 128;
525
526 endp = tmp + 16;
527
528 if (colonp != NULL)
529 {
530 /*
531 * Since some memmove()'s erroneously fail to handle overlapping
532 * regions, we'll do the shift by hand.
533 */
534 const int n = tp - colonp;
535 int i;
536
537 if (tp == endp)
538 goto enoent;
539 for (i = 1; i <= n; i++)
540 {
541 endp[-i] = colonp[n - i];
542 colonp[n - i] = 0;
543 }
544 tp = endp;
545 }
546 if (tp != endp)
547 goto enoent;
548
549 /*
550 * Copy out the result.
551 */
552 memcpy(dst, tmp, NS_IN6ADDRSZ);
553
554 return bits;
555
556enoent:
557 errno = ENOENT;
558 return -1;
559
560emsgsize:
561 errno = EMSGSIZE;
562 return -1;
563}
#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, 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 259 of file inet_net_pton.c.

260{
261 static const char digits[] = "0123456789";
262 const u_char *odst = dst;
263 int n,
264 ch,
265 tmp,
266 bits;
267 size_t size = 4;
268
269 /* Get the mantissa. */
270 while (ch = *src++, isdigit((unsigned char) ch))
271 {
272 tmp = 0;
273 do
274 {
275 n = strchr(digits, ch) - digits;
276 assert(n >= 0 && n <= 9);
277 tmp *= 10;
278 tmp += n;
279 if (tmp > 255)
280 goto enoent;
281 } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
282 if (size-- == 0)
283 goto emsgsize;
284 *dst++ = (u_char) tmp;
285 if (ch == '\0' || ch == '/')
286 break;
287 if (ch != '.')
288 goto enoent;
289 }
290
291 /* Get the prefix length if any. */
292 bits = -1;
293 if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
294 {
295 /* CIDR width specifier. Nothing can follow it. */
296 ch = *src++; /* Skip over the /. */
297 bits = 0;
298 do
299 {
300 n = strchr(digits, ch) - digits;
301 assert(n >= 0 && n <= 9);
302 bits *= 10;
303 bits += n;
304 } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
305 if (ch != '\0')
306 goto enoent;
307 if (bits > 32)
308 goto emsgsize;
309 }
310
311 /* Fiery death and destruction unless we prefetched EOS. */
312 if (ch != '\0')
313 goto enoent;
314
315 /* Prefix length can default to /32 only if all four octets spec'd. */
316 if (bits == -1)
317 {
318 if (dst - odst == 4)
319 bits = 32;
320 else
321 goto enoent;
322 }
323
324 /* If nothing was written to the destination, we found no address. */
325 if (dst == odst)
326 goto enoent;
327
328 /* If prefix length overspecifies mantissa, life is bad. */
329 if ((bits / 8) > (dst - odst))
330 goto enoent;
331
332 /* Extend address to four octets. */
333 while (size-- > 0)
334 *dst++ = 0;
335
336 return bits;
337
338enoent:
339 errno = ENOENT;
340 return -1;
341
342emsgsize:
343 errno = EMSGSIZE;
344 return -1;
345}

References assert, digits, and EMSGSIZE.

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 428 of file inet_net_pton.c.

429{
430 return inet_cidr_pton_ipv6(src, dst, 16);
431}
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 61 of file inet_net_pton.c.

62{
63 switch (af)
64 {
65 case PGSQL_AF_INET:
66 return size == -1 ?
67 inet_net_pton_ipv4(src, dst) :
68 inet_cidr_pton_ipv4(src, dst, size);
69 case PGSQL_AF_INET6:
70 return size == -1 ?
71 inet_net_pton_ipv6(src, dst) :
72 inet_cidr_pton_ipv6(src, dst, size);
73 default:
74 errno = EAFNOSUPPORT;
75 return -1;
76 }
77}
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:96
#define PGSQL_AF_INET
Definition: inet.h:39
#define PGSQL_AF_INET6
Definition: inet.h:40
#define EAFNOSUPPORT
Definition: win32_port.h:368

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

Referenced by network_in().