inet_net_pton.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:8k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1996 by Internet Software Consortium.
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software for any
  5.  * purpose with or without fee is hereby granted, provided that the above
  6.  * copyright notice and this permission notice appear in all copies.
  7.  *
  8.  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
  9.  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
  10.  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
  11.  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12.  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  13.  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  14.  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  15.  * SOFTWARE.
  16.  */
  17. #if defined(LIBC_SCCS) && !defined(lint)
  18. static const char rcsid[] = "$Id: inet_net_pton.c,v 1.8.2.1 1999/08/02 05:24:53 scrappy Exp $";
  19. #endif
  20. #include <sys/types.h>
  21. #include <sys/socket.h>
  22. #include <netinet/in.h>
  23. #include <arpa/inet.h>
  24. #include <assert.h>
  25. #include <ctype.h>
  26. #include <errno.h>
  27. #include "postgres.h"
  28. #include "utils/builtins.h"
  29. #ifdef SPRINTF_CHAR
  30. #define SPRINTF(x) strlen(sprintf/**/x)
  31. #else
  32. #define SPRINTF(x) ((size_t)sprintf x)
  33. #endif
  34. static int inet_net_pton_ipv4(const char *src, u_char *dst);
  35. static int inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size);
  36. /*
  37.  * static int
  38.  * inet_net_pton(af, src, dst, size)
  39.  * convert network number from presentation to network format.
  40.  * accepts hex octets, hex strings, decimal octets, and /CIDR.
  41.  * "size" is in bytes and describes "dst".
  42.  * return:
  43.  * number of bits, either imputed classfully or specified with /CIDR,
  44.  * or -1 if some failure occurred (check errno).  ENOENT means it was
  45.  * not a valid network specification.
  46.  * author:
  47.  * Paul Vixie (ISC), June 1996
  48.  *
  49.  * Changes:
  50.  * I added the inet_cidr_pton function (also from Paul) and changed
  51.  * the names to reflect their current use.
  52.  *
  53.  */
  54. int
  55. inet_net_pton(int af, const char *src, void *dst, size_t size)
  56. {
  57. switch (af)
  58. {
  59. case AF_INET:
  60. return size == -1 ?
  61. inet_net_pton_ipv4(src, dst) :
  62. inet_cidr_pton_ipv4(src, dst, size);
  63. default:
  64. errno = EAFNOSUPPORT;
  65. return (-1);
  66. }
  67. }
  68. /*
  69.  * static int
  70.  * inet_cidr_pton_ipv4(src, dst, size)
  71.  * convert IPv4 network number from presentation to network format.
  72.  * accepts hex octets, hex strings, decimal octets, and /CIDR.
  73.  * "size" is in bytes and describes "dst".
  74.  * return:
  75.  * number of bits, either imputed classfully or specified with /CIDR,
  76.  * or -1 if some failure occurred (check errno).  ENOENT means it was
  77.  * not an IPv4 network specification.
  78.  * note:
  79.  * network byte order assumed.  this means 192.5.5.240/28 has
  80.  * 0x11110000 in its fourth octet.
  81.  * author:
  82.  * Paul Vixie (ISC), June 1996
  83.  */
  84. static int
  85. inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size)
  86. {
  87. static const char
  88. xdigits[] = "0123456789abcdef",
  89. digits[] = "0123456789";
  90. int n,
  91. ch,
  92. tmp,
  93. dirty,
  94. bits;
  95. const u_char *odst = dst;
  96. ch = *src++;
  97. if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
  98. && isascii(src[1]) && isxdigit(src[1]))
  99. {
  100. /* Hexadecimal: Eat nybble string. */
  101. if (size <= 0)
  102. goto emsgsize;
  103. dirty = 0;
  104. tmp = 0;
  105. src++; /* skip x or X. */
  106. while ((ch = *src++) != '' && isascii(ch) && isxdigit(ch))
  107. {
  108. if (isupper(ch))
  109. ch = tolower(ch);
  110. n = strchr(xdigits, ch) - xdigits;
  111. assert(n >= 0 && n <= 15);
  112. if (dirty == 0)
  113. tmp = n;
  114. else
  115. tmp = (tmp << 4) | n;
  116. if (++dirty == 2)
  117. {
  118. if (size-- <= 0)
  119. goto emsgsize;
  120. *dst++ = (u_char) tmp;
  121. dirty = 0;
  122. }
  123. }
  124. if (dirty)
  125. { /* Odd trailing nybble? */
  126. if (size-- <= 0)
  127. goto emsgsize;
  128. *dst++ = (u_char) (tmp << 4);
  129. }
  130. }
  131. else if (isascii(ch) && isdigit(ch))
  132. {
  133. /* Decimal: eat dotted digit string. */
  134. for (;;)
  135. {
  136. tmp = 0;
  137. do
  138. {
  139. n = strchr(digits, ch) - digits;
  140. assert(n >= 0 && n <= 9);
  141. tmp *= 10;
  142. tmp += n;
  143. if (tmp > 255)
  144. goto enoent;
  145. } while ((ch = *src++) != '' &&
  146.  isascii(ch) && isdigit(ch));
  147. if (size-- <= 0)
  148. goto emsgsize;
  149. *dst++ = (u_char) tmp;
  150. if (ch == '' || ch == '/')
  151. break;
  152. if (ch != '.')
  153. goto enoent;
  154. ch = *src++;
  155. if (!isascii(ch) || !isdigit(ch))
  156. goto enoent;
  157. }
  158. }
  159. else
  160. goto enoent;
  161. bits = -1;
  162. if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst)
  163. {
  164. /* CIDR width specifier.  Nothing can follow it. */
  165. ch = *src++; /* Skip over the /. */
  166. bits = 0;
  167. do
  168. {
  169. n = strchr(digits, ch) - digits;
  170. assert(n >= 0 && n <= 9);
  171. bits *= 10;
  172. bits += n;
  173. } while ((ch = *src++) != '' &&
  174.  isascii(ch) && isdigit(ch));
  175. if (ch != '')
  176. goto enoent;
  177. if (bits > 32)
  178. goto emsgsize;
  179. }
  180. /* Firey death and destruction unless we prefetched EOS. */
  181. if (ch != '')
  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 = 4;
  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 >= 8 && bits < ((dst - odst) * 8))
  202. bits = (dst - odst) * 8;
  203. }
  204. /* Extend network to cover the actual mask. */
  205. while (bits > ((dst - odst) * 8))
  206. {
  207. if (size-- <= 0)
  208. goto emsgsize;
  209. *dst++ = '';
  210. }
  211. return (bits);
  212. enoent:
  213. errno = ENOENT;
  214. return (-1);
  215. emsgsize:
  216. errno = EMSGSIZE;
  217. return (-1);
  218. }
  219. /*
  220.  * int
  221.  * inet_net_pton(af, src, dst, *bits)
  222.  * convert network address from presentation to network format.
  223.  * accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
  224.  * "dst" is assumed large enough for its "af".  "bits" is set to the
  225.  * /CIDR prefix length, which can have defaults (like /32 for IPv4).
  226.  * return:
  227.  * -1 if an error occurred (inspect errno; ENOENT means bad format).
  228.  * 0 if successful conversion occurred.
  229.  * note:
  230.  * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
  231.  * as called for by inet_cidr_pton() but it can be a host address with
  232.  * an included netmask.
  233.  * author:
  234.  * Paul Vixie (ISC), October 1998
  235.  */
  236. static int
  237. inet_net_pton_ipv4(const char *src, u_char *dst)
  238. {
  239. static const char digits[] = "0123456789";
  240. const u_char *odst = dst;
  241. int n,
  242. ch,
  243. tmp,
  244. bits;
  245. size_t size = 4;
  246. /* Get the mantissa. */
  247. while (ch = *src++, (isascii(ch) && isdigit(ch)))
  248. {
  249. tmp = 0;
  250. do
  251. {
  252. n = strchr(digits, ch) - digits;
  253. assert(n >= 0 && n <= 9);
  254. tmp *= 10;
  255. tmp += n;
  256. if (tmp > 255)
  257. goto enoent;
  258. } while ((ch = *src++) != '' && isascii(ch) && isdigit(ch));
  259. if (size-- == 0)
  260. goto emsgsize;
  261. *dst++ = (u_char) tmp;
  262. if (ch == '' || ch == '/')
  263. break;
  264. if (ch != '.')
  265. goto enoent;
  266. }
  267. /* Get the prefix length if any. */
  268. bits = -1;
  269. if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst)
  270. {
  271. /* CIDR width specifier.  Nothing can follow it. */
  272. ch = *src++; /* Skip over the /. */
  273. bits = 0;
  274. do
  275. {
  276. n = strchr(digits, ch) - digits;
  277. assert(n >= 0 && n <= 9);
  278. bits *= 10;
  279. bits += n;
  280. } while ((ch = *src++) != '' && isascii(ch) && isdigit(ch));
  281. if (ch != '')
  282. goto enoent;
  283. if (bits > 32)
  284. goto emsgsize;
  285. }
  286. /* Firey death and destruction unless we prefetched EOS. */
  287. if (ch != '')
  288. goto enoent;
  289. /* Prefix length can default to /32 only if all four octets spec'd. */
  290. if (bits == -1)
  291. {
  292. if (dst - odst == 4)
  293. bits = 32;
  294. else
  295. goto enoent;
  296. }
  297. /* If nothing was written to the destination, we found no address. */
  298. if (dst == odst)
  299. goto enoent;
  300. /* If prefix length overspecifies mantissa, life is bad. */
  301. if ((bits / 8) > (dst - odst))
  302. goto enoent;
  303. /* Extend address to four octets. */
  304. while (size-- > 0)
  305. *dst++ = 0;
  306. return bits;
  307. enoent:
  308. errno = ENOENT;
  309. return (-1);
  310. emsgsize:
  311. errno = EMSGSIZE;
  312. return (-1);
  313. }