]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/inet_net_pton.c
Big warnings cleanup for Solaris/GCC. Down to about 40 now, but
[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.11 2000/06/14 18:17:44 petere 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
32 #include "postgres.h"
33 #include "utils/builtins.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);
42 static int      inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size);
43
44 /*
45  * static int
46  * inet_net_pton(af, src, dst, size)
47  *      convert network number from presentation to network format.
48  *      accepts hex octets, hex strings, decimal octets, and /CIDR.
49  *      "size" is in bytes and describes "dst".
50  * return:
51  *      number of bits, either imputed classfully or specified with /CIDR,
52  *      or -1 if some failure occurred (check errno).  ENOENT means it was
53  *      not a valid network specification.
54  * author:
55  *      Paul Vixie (ISC), June 1996
56  *
57  * Changes:
58  *      I added the inet_cidr_pton function (also from Paul) and changed
59  *      the names to reflect their current use.
60  *
61  */
62 int
63 inet_net_pton(int af, const char *src, void *dst, size_t size)
64 {
65         switch (af)
66         {
67                         case AF_INET:
68                         return size == -1 ?
69                         inet_net_pton_ipv4(src, dst) :
70                         inet_cidr_pton_ipv4(src, dst, size);
71                 default:
72                         errno = EAFNOSUPPORT;
73                         return (-1);
74         }
75 }
76
77 /*
78  * static int
79  * inet_cidr_pton_ipv4(src, dst, size)
80  *      convert IPv4 network number from presentation to network format.
81  *      accepts hex octets, hex strings, decimal octets, and /CIDR.
82  *      "size" is in bytes and describes "dst".
83  * return:
84  *      number of bits, either imputed classfully or specified with /CIDR,
85  *      or -1 if some failure occurred (check errno).  ENOENT means it was
86  *      not an IPv4 network specification.
87  * note:
88  *      network byte order assumed.  this means 192.5.5.240/28 has
89  *      0x11110000 in its fourth octet.
90  * author:
91  *      Paul Vixie (ISC), June 1996
92  */
93 static int
94 inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size)
95 {
96         static const char
97                                 xdigits[] = "0123456789abcdef",
98                                 digits[] = "0123456789";
99         int                     n,
100                                 ch,
101                                 tmp,
102                                 dirty,
103                                 bits;
104         const u_char *odst = dst;
105
106         ch = *src++;
107         if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
108                 && isascii((int) src[1]) && isxdigit((int) src[1]))
109         {
110                 /* Hexadecimal: Eat nybble string. */
111                 if (size <= 0)
112                         goto emsgsize;
113                 dirty = 0;
114                 tmp = 0;
115                 src++;                                  /* skip x or X. */
116                 while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch))
117                 {
118                         if (isupper(ch))
119                                 ch = tolower(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-- <= 0)
129                                         goto emsgsize;
130                                 *dst++ = (u_char) tmp;
131                                 dirty = 0;
132                         }
133                 }
134                 if (dirty)
135                 {                                               /* Odd trailing nybble? */
136                         if (size-- <= 0)
137                                 goto emsgsize;
138                         *dst++ = (u_char) (tmp << 4);
139                 }
140         }
141         else if (isascii(ch) && isdigit(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                                          isascii(ch) && isdigit(ch));
157                         if (size-- <= 0)
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 (!isascii(ch) || !isdigit(ch))
166                                 goto enoent;
167                 }
168         }
169         else
170                 goto enoent;
171
172         bits = -1;
173         if (ch == '/' && isascii((int) src[0]) && isdigit((int) 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' &&
185                                  isascii(ch) && isdigit(ch));
186                 if (ch != '\0')
187                         goto enoent;
188                 if (bits > 32)
189                         goto emsgsize;
190         }
191
192         /* Firey 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 = 4;
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 >= 8 && bits < ((dst - odst) * 8))
215                         bits = (dst - odst) * 8;
216         }
217         /* Extend network to cover the actual mask. */
218         while (bits > ((dst - odst) * 8))
219         {
220                 if (size-- <= 0)
221                         goto emsgsize;
222                 *dst++ = '\0';
223         }
224         return (bits);
225
226 enoent:
227         errno = ENOENT;
228         return (-1);
229
230 emsgsize:
231         errno = EMSGSIZE;
232         return (-1);
233 }
234
235 /*
236  * int
237  * inet_net_pton(af, src, dst, *bits)
238  *      convert network address from presentation to network format.
239  *      accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
240  *      "dst" is assumed large enough for its "af".  "bits" is set to the
241  *      /CIDR prefix length, which can have defaults (like /32 for IPv4).
242  * return:
243  *      -1 if an error occurred (inspect errno; ENOENT means bad format).
244  *      0 if successful conversion occurred.
245  * note:
246  *      192.5.5.1/28 has a nonzero host part, which means it isn't a network
247  *      as called for by inet_cidr_pton() but it can be a host address with
248  *      an included netmask.
249  * author:
250  *      Paul Vixie (ISC), October 1998
251  */
252 static int
253 inet_net_pton_ipv4(const char *src, u_char *dst)
254 {
255         static const char digits[] = "0123456789";
256         const u_char *odst = dst;
257         int                     n,
258                                 ch,
259                                 tmp,
260                                 bits;
261         size_t          size = 4;
262
263         /* Get the mantissa. */
264         while (ch = *src++, (isascii(ch) && isdigit(ch)))
265         {
266                 tmp = 0;
267                 do
268                 {
269                         n = strchr(digits, ch) - digits;
270                         assert(n >= 0 && n <= 9);
271                         tmp *= 10;
272                         tmp += n;
273                         if (tmp > 255)
274                                 goto enoent;
275                 } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
276                 if (size-- == 0)
277                         goto emsgsize;
278                 *dst++ = (u_char) tmp;
279                 if (ch == '\0' || ch == '/')
280                         break;
281                 if (ch != '.')
282                         goto enoent;
283         }
284
285         /* Get the prefix length if any. */
286         bits = -1;
287         if (ch == '/' && isascii((int) src[0]) && isdigit((int) src[0]) && dst > odst)
288         {
289                 /* CIDR width specifier.  Nothing can follow it. */
290                 ch = *src++;                    /* Skip over the /. */
291                 bits = 0;
292                 do
293                 {
294                         n = strchr(digits, ch) - digits;
295                         assert(n >= 0 && n <= 9);
296                         bits *= 10;
297                         bits += n;
298                 } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
299                 if (ch != '\0')
300                         goto enoent;
301                 if (bits > 32)
302                         goto emsgsize;
303         }
304
305         /* Firey death and destruction unless we prefetched EOS. */
306         if (ch != '\0')
307                 goto enoent;
308
309         /* Prefix length can default to /32 only if all four octets spec'd. */
310         if (bits == -1)
311         {
312                 if (dst - odst == 4)
313                         bits = 32;
314                 else
315                         goto enoent;
316         }
317
318         /* If nothing was written to the destination, we found no address. */
319         if (dst == odst)
320                 goto enoent;
321
322         /* If prefix length overspecifies mantissa, life is bad. */
323         if ((bits / 8) > (dst - odst))
324                 goto enoent;
325
326         /* Extend address to four octets. */
327         while (size-- > 0)
328                 *dst++ = 0;
329
330         return bits;
331
332 enoent:
333         errno = ENOENT;
334         return (-1);
335
336 emsgsize:
337         errno = EMSGSIZE;
338         return (-1);
339 }