PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/src/backend/utils/adt/inet_net_pton.c

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