]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/network.c
Cleanup of /include #include's, for 6.6 only.
[postgresql] / src / backend / utils / adt / network.c
1 /*
2  *      PostgreSQL type definitions for the INET type.  This
3  *      is for IP V4 CIDR notation, but prepared for V6: just
4  *      add the necessary bits where the comments indicate.
5  *
6  *      $Id: network.c,v 1.11 1999/07/14 01:20:06 momjian Exp $
7  *      Jon Postel RIP 16 Oct 1998
8  */
9
10 #include <sys/types.h>
11 #include <sys/socket.h>
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <errno.h>
16
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19
20 #include <postgres.h>
21 #include <utils/palloc.h>
22 #include <utils/builtins.h>
23 #include <utils/inet.h>
24 #include "utils/mcxt.h"
25
26 static int      v4bitncmp(unsigned int a1, unsigned int a2, int bits);
27
28 /*
29  *      Access macros.  Add IPV6 support.
30  */
31
32 #define ip_addrsize(inetptr) \
33         (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : -1)
34
35 #define ip_family(inetptr) \
36         (((inet_struct *)VARDATA(inetptr))->family)
37
38 #define ip_bits(inetptr) \
39         (((inet_struct *)VARDATA(inetptr))->bits)
40
41 #define ip_type(inetptr) \
42         (((inet_struct *)VARDATA(inetptr))->type)
43
44 #define ip_v4addr(inetptr) \
45         (((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr)
46
47 /* Common input routine */
48 static inet *
49 network_in(char *src, int type)
50 {
51         int                     bits;
52         inet       *dst;
53
54         if (!src)
55                 return NULL;
56
57         dst = palloc(VARHDRSZ + sizeof(inet_struct));
58         if (dst == NULL)
59                 elog(ERROR, "unable to allocate memory in network_in()");
60
61         /* First, try for an IP V4 address: */
62         ip_family(dst) = AF_INET;
63         bits = inet_net_pton(ip_family(dst), src, &ip_v4addr(dst),
64                                                  type ? ip_addrsize(dst) : -1);
65         if ((bits < 0) || (bits > 32))
66                 /* Go for an IPV6 address here, before faulting out: */
67                 elog(ERROR, "could not parse \"%s\"", src);
68
69         VARSIZE(dst) = VARHDRSZ
70                 + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
71                 + ip_addrsize(dst);
72         ip_bits(dst) = bits;
73         ip_type(dst) = type;
74         return dst;
75 }
76
77 /* INET address reader.  */
78 inet *
79 inet_in(char *src)
80 {
81         return network_in(src, 0);
82 }
83
84 /* CIDR address reader.  */
85 inet *
86 cidr_in(char *src)
87 {
88         return network_in(src, 1);
89 }
90
91 /*
92  *      INET address output function.
93  */
94
95 char *
96 inet_out(inet *src)
97 {
98         char       *dst,
99                                 tmp[sizeof("255.255.255.255/32")];
100
101         if (ip_family(src) == AF_INET)
102         {
103                 /* It's an IP V4 address: */
104                 if (ip_type(src))
105                         dst = inet_cidr_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
106                                                                  tmp, sizeof(tmp));
107                 else
108                         dst = inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
109                                                                 tmp, sizeof(tmp));
110
111                 if (dst == NULL)
112                         elog(ERROR, "unable to print address (%s)", strerror(errno));
113         }
114         else
115                 /* Go for an IPV6 address here, before faulting out: */
116                 elog(ERROR, "unknown address family (%d)", ip_family(src));
117
118         dst = palloc(strlen(tmp) + 1);
119         if (dst == NULL)
120                 elog(ERROR, "unable to allocate memory in inet_out()");
121
122         strcpy(dst, tmp);
123         return dst;
124 }
125
126
127 /* just a stub */
128 char *
129 cidr_out(inet *src)
130 {
131         return inet_out(src);
132 }
133
134 /*
135  *      Boolean tests for magnitude.  Add V4/V6 testing!
136  */
137
138 bool
139 network_lt(inet *a1, inet *a2)
140 {
141         if (!PointerIsValid(a1) || !PointerIsValid(a2))
142                 return FALSE;
143         if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
144         {
145                 int                     order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
146
147                 return ((order < 0) || ((order == 0) && (ip_bits(a1) < ip_bits(a2))));
148         }
149         else
150         {
151                 /* Go for an IPV6 address here, before faulting out: */
152                 elog(ERROR, "cannot compare address families %d and %d",
153                          ip_family(a1), ip_family(a2));
154                 return FALSE;
155         }
156 }
157
158 bool
159 network_le(inet *a1, inet *a2)
160 {
161         if (!PointerIsValid(a1) || !PointerIsValid(a2))
162                 return FALSE;
163         return (network_lt(a1, a2) || network_eq(a1, a2));
164 }
165
166 bool
167 network_eq(inet *a1, inet *a2)
168 {
169         if (!PointerIsValid(a1) || !PointerIsValid(a2))
170                 return FALSE;
171         if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
172         {
173                 return ((ip_bits(a1) == ip_bits(a2))
174                  && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
175         }
176         else
177         {
178                 /* Go for an IPV6 address here, before faulting out: */
179                 elog(ERROR, "cannot compare address families %d and %d",
180                          ip_family(a1), ip_family(a2));
181                 return FALSE;
182         }
183 }
184
185 bool
186 network_ge(inet *a1, inet *a2)
187 {
188         if (!PointerIsValid(a1) || !PointerIsValid(a2))
189                 return FALSE;
190         return (network_gt(a1, a2) || network_eq(a1, a2));
191 }
192
193 bool
194 network_gt(inet *a1, inet *a2)
195 {
196         if (!PointerIsValid(a1) || !PointerIsValid(a2))
197                 return FALSE;
198         if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
199         {
200                 int                     order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
201
202                 return ((order > 0) || ((order == 0) && (ip_bits(a1) > ip_bits(a2))));
203         }
204         else
205         {
206                 /* Go for an IPV6 address here, before faulting out: */
207                 elog(ERROR, "cannot compare address families %d and %d",
208                          ip_family(a1), ip_family(a2));
209                 return FALSE;
210         }
211 }
212
213 bool
214 network_ne(inet *a1, inet *a2)
215 {
216         if (!PointerIsValid(a1) || !PointerIsValid(a2))
217                 return FALSE;
218         return (!network_eq(a1, a2));
219 }
220
221 bool
222 network_sub(inet *a1, inet *a2)
223 {
224         if (!PointerIsValid(a1) || !PointerIsValid(a2))
225                 return FALSE;
226
227         if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
228         {
229                 return ((ip_bits(a1) > ip_bits(a2))
230                  && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
231         }
232         else
233         {
234                 /* Go for an IPV6 address here, before faulting out: */
235                 elog(ERROR, "cannot compare address families %d and %d",
236                          ip_family(a1), ip_family(a2));
237                 return FALSE;
238         }
239 }
240
241 bool
242 network_subeq(inet *a1, inet *a2)
243 {
244         if (!PointerIsValid(a1) || !PointerIsValid(a2))
245                 return FALSE;
246
247         if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
248         {
249                 return ((ip_bits(a1) >= ip_bits(a2))
250                  && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
251         }
252         else
253         {
254                 /* Go for an IPV6 address here, before faulting out: */
255                 elog(ERROR, "cannot compare address families %d and %d",
256                          ip_family(a1), ip_family(a2));
257                 return FALSE;
258         }
259 }
260
261 bool
262 network_sup(inet *a1, inet *a2)
263 {
264         if (!PointerIsValid(a1) || !PointerIsValid(a2))
265                 return FALSE;
266
267         if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
268         {
269                 return ((ip_bits(a1) < ip_bits(a2))
270                  && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
271         }
272         else
273         {
274                 /* Go for an IPV6 address here, before faulting out: */
275                 elog(ERROR, "cannot compare address families %d and %d",
276                          ip_family(a1), ip_family(a2));
277                 return FALSE;
278         }
279 }
280
281 bool
282 network_supeq(inet *a1, inet *a2)
283 {
284         if (!PointerIsValid(a1) || !PointerIsValid(a2))
285                 return FALSE;
286
287         if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
288         {
289                 return ((ip_bits(a1) <= ip_bits(a2))
290                  && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
291         }
292         else
293         {
294                 /* Go for an IPV6 address here, before faulting out: */
295                 elog(ERROR, "cannot compare address families %d and %d",
296                          ip_family(a1), ip_family(a2));
297                 return FALSE;
298         }
299 }
300
301 /*
302  *      Comparison function for sorting.  Add V4/V6 testing!
303  */
304
305 int4
306 network_cmp(inet *a1, inet *a2)
307 {
308         if (ntohl(ip_v4addr(a1)) < ntohl(ip_v4addr(a2)))
309                 return (-1);
310
311         if (ntohl(ip_v4addr(a1)) > ntohl(ip_v4addr(a2)))
312                 return (1);
313
314         if (ip_bits(a1) < ip_bits(a2))
315                 return (-1);
316
317         if (ip_bits(a1) > ip_bits(a2))
318                 return (1);
319
320         return 0;
321 }
322
323 text *
324 network_host(inet *ip)
325 {
326         text       *ret;
327         int                     len;
328         char       *ptr,
329                                 tmp[sizeof("255.255.255.255/32")];
330
331         if (!PointerIsValid(ip))
332                 return NULL;
333
334         if (ip_type(ip))
335                 elog(ERROR, "CIDR type has no host part");
336
337         if (ip_family(ip) == AF_INET)
338         {
339                 /* It's an IP V4 address: */
340                 if (inet_net_ntop(AF_INET, &ip_v4addr(ip), 32, tmp, sizeof(tmp)) == NULL)
341                         elog(ERROR, "unable to print host (%s)", strerror(errno));
342         }
343         else
344                 /* Go for an IPV6 address here, before faulting out: */
345                 elog(ERROR, "unknown address family (%d)", ip_family(ip));
346
347         if ((ptr = strchr(tmp, '/')) != NULL)
348                 *ptr = 0;
349         len = VARHDRSZ + strlen(tmp) + 1;
350         ret = palloc(len);
351         if (ret == NULL)
352                 elog(ERROR, "unable to allocate memory in network_host()");
353
354         VARSIZE(ret) = len;
355         strcpy(VARDATA(ret), tmp);
356         return (ret);
357 }
358
359 int4
360 network_masklen(inet *ip)
361 {
362         if (!PointerIsValid(ip))
363                 return 0;
364
365         return ip_bits(ip);
366 }
367
368 text *
369 network_broadcast(inet *ip)
370 {
371         text       *ret;
372         int                     len;
373         char       *ptr,
374                                 tmp[sizeof("255.255.255.255/32")];
375
376         if (!PointerIsValid(ip))
377                 return NULL;
378
379         if (ip_family(ip) == AF_INET)
380         {
381                 /* It's an IP V4 address: */
382                 int                     addr;
383                 unsigned long mask = 0xffffffff;
384
385                 if (ip_bits(ip) < 32)
386                         mask >>= ip_bits(ip);
387                 addr = htonl(ntohl(ip_v4addr(ip)) | mask);
388
389                 if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL)
390                         elog(ERROR, "unable to print address (%s)", strerror(errno));
391
392         }
393         else
394                 /* Go for an IPV6 address here, before faulting out: */
395                 elog(ERROR, "unknown address family (%d)", ip_family(ip));
396
397         if ((ptr = strchr(tmp, '/')) != NULL)
398                 *ptr = 0;
399         len = VARHDRSZ + strlen(tmp) + 1;
400         ret = palloc(len);
401         if (ret == NULL)
402                 elog(ERROR, "unable to allocate memory in network_broadcast()");
403
404         VARSIZE(ret) = len;
405         strcpy(VARDATA(ret), tmp);
406         return (ret);
407 }
408
409 text *
410 network_network(inet *ip)
411 {
412         text       *ret;
413         int                     len;
414         char            tmp[sizeof("255.255.255.255/32")];
415
416         if (!PointerIsValid(ip))
417                 return NULL;
418
419         if (ip_family(ip) == AF_INET)
420         {
421                 /* It's an IP V4 address: */
422                 int                     addr = htonl(ntohl(ip_v4addr(ip)) & (0xffffffff << (32 - ip_bits(ip))));
423
424                 if (inet_cidr_ntop(AF_INET, &addr, ip_bits(ip), tmp, sizeof(tmp)) == NULL)
425                         elog(ERROR, "unable to print network (%s)", strerror(errno));
426
427         }
428         else
429                 /* Go for an IPV6 address here, before faulting out: */
430                 elog(ERROR, "unknown address family (%d)", ip_family(ip));
431
432         len = VARHDRSZ + strlen(tmp) + 1;
433         ret = palloc(len);
434         if (ret == NULL)
435                 elog(ERROR, "unable to allocate memory in network_network()");
436
437         VARSIZE(ret) = len;
438         strcpy(VARDATA(ret), tmp);
439         return (ret);
440 }
441
442 text *
443 network_netmask(inet *ip)
444 {
445         text       *ret;
446         int                     len;
447         char       *ptr,
448                                 tmp[sizeof("255.255.255.255/32")];
449
450         if (!PointerIsValid(ip))
451                 return NULL;
452
453         if (ip_family(ip) == AF_INET)
454         {
455                 /* It's an IP V4 address: */
456                 int                     addr = htonl((-1 << (32 - ip_bits(ip))) & 0xffffffff);
457
458                 if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL)
459                         elog(ERROR, "unable to print netmask (%s)", strerror(errno));
460
461         }
462         else
463                 /* Go for an IPV6 address here, before faulting out: */
464                 elog(ERROR, "unknown address family (%d)", ip_family(ip));
465
466         if ((ptr = strchr(tmp, '/')) != NULL)
467                 *ptr = 0;
468         len = VARHDRSZ + strlen(tmp) + 1;
469         ret = palloc(len);
470         if (ret == NULL)
471                 elog(ERROR, "unable to allocate memory in network_netmask()");
472
473         VARSIZE(ret) = len;
474         strcpy(VARDATA(ret), tmp);
475         return (ret);
476 }
477
478 /*
479  *      Bitwise comparison for V4 addresses.  Add V6 implementation!
480  */
481
482 static int
483 v4bitncmp(unsigned int a1, unsigned int a2, int bits)
484 {
485         unsigned long mask = 0;
486         int                     i;
487
488         for (i = 0; i < bits; i++)
489                 mask = (mask >> 1) | 0x80000000;
490         a1 = ntohl(a1);
491         a2 = ntohl(a2);
492         if ((a1 & mask) < (a2 & mask))
493                 return (-1);
494         else if ((a1 & mask) > (a2 & mask))
495                 return (1);
496         return (0);
497 }