]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/inet_net_pton.c
Integrate new IP type from Tom Ivar Helbekkmo.
[postgresql] / src / backend / utils / adt / inet_net_pton.c
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
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static const char rcsid[] = "$Id: inet_net_pton.c,v 1.1 1998/10/03 05:40:49 momjian Exp $";
20
21 #endif
22
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27
28 #include <assert.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34
35 #ifdef SPRINTF_CHAR
36 #define SPRINTF(x) strlen(sprintf/**/x)
37 #else
38 #define SPRINTF(x) ((size_t)sprintf x)
39 #endif
40
41 static int      inet_net_pton_ipv4(const char *src, u_char *dst, size_t size);
42
43 /*
44  * static int
45  * inet_net_pton(af, src, dst, size)
46  *      convert network number from presentation to network format.
47  *      accepts hex octets, hex strings, decimal octets, and /CIDR.
48  *      "size" is in bytes and describes "dst".
49  * return:
50  *      number of bits, either imputed classfully or specified with /CIDR,
51  *      or -1 if some failure occurred (check errno).  ENOENT means it was
52  *      not a valid network specification.
53  * author:
54  *      Paul Vixie (ISC), June 1996
55  */
56 int
57 inet_net_pton(int af, const char *src, void *dst, size_t size)
58 {
59         switch (af)
60         {
61                 case AF_INET:
62                         return (inet_net_pton_ipv4(src, dst, size));
63                 default:
64                         errno = EAFNOSUPPORT;
65                         return (-1);
66         }
67 }
68
69 /*
70  * static int
71  * inet_net_pton_ipv4(src, dst, size)
72  *      convert IPv4 network number from presentation to network format.
73  *      accepts hex octets, hex strings, decimal octets, and /CIDR.
74  *      "size" is in bytes and describes "dst".
75  * return:
76  *      number of bits, either imputed classfully or specified with /CIDR,
77  *      or -1 if some failure occurred (check errno).  ENOENT means it was
78  *      not an IPv4 network specification.
79  * note:
80  *      network byte order assumed.  this means 192.5.5.240/28 has
81  *      0x11110000 in its fourth octet.
82  * author:
83  *      Paul Vixie (ISC), June 1996
84  */
85 static int
86 inet_net_pton_ipv4(const char *src, u_char *dst, size_t size)
87 {
88         static const char
89                                 xdigits[] = "0123456789abcdef",
90                                 digits[] = "0123456789";
91         int                     n,
92                                 ch,
93                                 tmp,
94                                 dirty,
95                                 bits;
96         const u_char *odst = dst;
97
98         ch = *src++;
99         if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
100                 && isascii(src[1]) && isxdigit(src[1]))
101         {
102                 /* Hexadecimal: Eat nybble string. */
103                 if (size <= 0)
104                         goto emsgsize;
105                 *dst = 0, dirty = 0;
106                 src++;                                  /* skip x or X. */
107                 while ((ch = *src++) != '\0' &&
108                            isascii(ch) && isxdigit(ch))
109                 {
110                         if (isupper(ch))
111                                 ch = tolower(ch);
112                         n = strchr(xdigits, ch) - xdigits;
113                         assert(n >= 0 && n <= 15);
114                         *dst |= n;
115                         if (!dirty++)
116                                 *dst <<= 4;
117                         else if (size-- > 0)
118                                 *++dst = 0, dirty = 0;
119                         else
120                                 goto emsgsize;
121                 }
122                 if (dirty)
123                         size--;
124         }
125         else if (isascii(ch) && isdigit(ch))
126         {
127                 /* Decimal: eat dotted digit string. */
128                 for (;;)
129                 {
130                         tmp = 0;
131                         do
132                         {
133                                 n = strchr(digits, ch) - digits;
134                                 assert(n >= 0 && n <= 9);
135                                 tmp *= 10;
136                                 tmp += n;
137                                 if (tmp > 255)
138                                         goto enoent;
139                         } while ((ch = *src++) != '\0' &&
140                                          isascii(ch) && isdigit(ch));
141                         if (size-- <= 0)
142                                 goto emsgsize;
143                         *dst++ = (u_char) tmp;
144                         if (ch == '\0' || ch == '/')
145                                 break;
146                         if (ch != '.')
147                                 goto enoent;
148                         ch = *src++;
149                         if (!isascii(ch) || !isdigit(ch))
150                                 goto enoent;
151                 }
152         }
153         else
154                 goto enoent;
155
156         bits = -1;
157         if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst)
158         {
159                 /* CIDR width specifier.  Nothing can follow it. */
160                 ch = *src++;                    /* Skip over the /. */
161                 bits = 0;
162                 do
163                 {
164                         n = strchr(digits, ch) - digits;
165                         assert(n >= 0 && n <= 9);
166                         bits *= 10;
167                         bits += n;
168                 } while ((ch = *src++) != '\0' &&
169                                  isascii(ch) && isdigit(ch));
170                 if (ch != '\0')
171                         goto enoent;
172                 if (bits > 32)
173                         goto emsgsize;
174         }
175
176         /* Firey death and destruction unless we prefetched EOS. */
177         if (ch != '\0')
178                 goto enoent;
179
180         /* If nothing was written to the destination, we found no address. */
181         if (dst == odst)
182                 goto enoent;
183         /* If no CIDR spec was given, infer width from net class. */
184         if (bits == -1)
185         {
186                 if (*odst >= 240)               /* Class E */
187                         bits = 32;
188                 else if (*odst >= 224)  /* Class D */
189                         bits = 4;
190                 else if (*odst >= 192)  /* Class C */
191                         bits = 24;
192                 else if (*odst >= 128)  /* Class B */
193                         bits = 16;
194                 else
195 /* Class A */
196                         bits = 8;
197                 /* If imputed mask is narrower than specified octets, widen. */
198                 if (bits >= 8 && bits < ((dst - odst) * 8))
199                         bits = (dst - odst) * 8;
200         }
201         /* Extend network to cover the actual mask. */
202         while (bits > ((dst - odst) * 8))
203         {
204                 if (size-- <= 0)
205                         goto emsgsize;
206                 *dst++ = '\0';
207         }
208         return (bits);
209
210 enoent:
211         errno = ENOENT;
212         return (-1);
213
214 emsgsize:
215         errno = EMSGSIZE;
216         return (-1);
217 }