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.
6 * $Id: network.c,v 1.11 1999/07/14 01:20:06 momjian Exp $
7 * Jon Postel RIP 16 Oct 1998
10 #include <sys/types.h>
11 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
21 #include <utils/palloc.h>
22 #include <utils/builtins.h>
23 #include <utils/inet.h>
24 #include "utils/mcxt.h"
26 static int v4bitncmp(unsigned int a1, unsigned int a2, int bits);
29 * Access macros. Add IPV6 support.
32 #define ip_addrsize(inetptr) \
33 (((inet_struct *)VARDATA(inetptr))->family == AF_INET ? 4 : -1)
35 #define ip_family(inetptr) \
36 (((inet_struct *)VARDATA(inetptr))->family)
38 #define ip_bits(inetptr) \
39 (((inet_struct *)VARDATA(inetptr))->bits)
41 #define ip_type(inetptr) \
42 (((inet_struct *)VARDATA(inetptr))->type)
44 #define ip_v4addr(inetptr) \
45 (((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr)
47 /* Common input routine */
49 network_in(char *src, int type)
57 dst = palloc(VARHDRSZ + sizeof(inet_struct));
59 elog(ERROR, "unable to allocate memory in network_in()");
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);
69 VARSIZE(dst) = VARHDRSZ
70 + ((char *) &ip_v4addr(dst) - (char *) VARDATA(dst))
77 /* INET address reader. */
81 return network_in(src, 0);
84 /* CIDR address reader. */
88 return network_in(src, 1);
92 * INET address output function.
99 tmp[sizeof("255.255.255.255/32")];
101 if (ip_family(src) == AF_INET)
103 /* It's an IP V4 address: */
105 dst = inet_cidr_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
108 dst = inet_net_ntop(AF_INET, &ip_v4addr(src), ip_bits(src),
112 elog(ERROR, "unable to print address (%s)", strerror(errno));
115 /* Go for an IPV6 address here, before faulting out: */
116 elog(ERROR, "unknown address family (%d)", ip_family(src));
118 dst = palloc(strlen(tmp) + 1);
120 elog(ERROR, "unable to allocate memory in inet_out()");
131 return inet_out(src);
135 * Boolean tests for magnitude. Add V4/V6 testing!
139 network_lt(inet *a1, inet *a2)
141 if (!PointerIsValid(a1) || !PointerIsValid(a2))
143 if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
145 int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
147 return ((order < 0) || ((order == 0) && (ip_bits(a1) < ip_bits(a2))));
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));
159 network_le(inet *a1, inet *a2)
161 if (!PointerIsValid(a1) || !PointerIsValid(a2))
163 return (network_lt(a1, a2) || network_eq(a1, a2));
167 network_eq(inet *a1, inet *a2)
169 if (!PointerIsValid(a1) || !PointerIsValid(a2))
171 if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
173 return ((ip_bits(a1) == ip_bits(a2))
174 && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
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));
186 network_ge(inet *a1, inet *a2)
188 if (!PointerIsValid(a1) || !PointerIsValid(a2))
190 return (network_gt(a1, a2) || network_eq(a1, a2));
194 network_gt(inet *a1, inet *a2)
196 if (!PointerIsValid(a1) || !PointerIsValid(a2))
198 if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
200 int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
202 return ((order > 0) || ((order == 0) && (ip_bits(a1) > ip_bits(a2))));
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));
214 network_ne(inet *a1, inet *a2)
216 if (!PointerIsValid(a1) || !PointerIsValid(a2))
218 return (!network_eq(a1, a2));
222 network_sub(inet *a1, inet *a2)
224 if (!PointerIsValid(a1) || !PointerIsValid(a2))
227 if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
229 return ((ip_bits(a1) > ip_bits(a2))
230 && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
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));
242 network_subeq(inet *a1, inet *a2)
244 if (!PointerIsValid(a1) || !PointerIsValid(a2))
247 if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
249 return ((ip_bits(a1) >= ip_bits(a2))
250 && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2)) == 0));
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));
262 network_sup(inet *a1, inet *a2)
264 if (!PointerIsValid(a1) || !PointerIsValid(a2))
267 if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
269 return ((ip_bits(a1) < ip_bits(a2))
270 && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
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));
282 network_supeq(inet *a1, inet *a2)
284 if (!PointerIsValid(a1) || !PointerIsValid(a2))
287 if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
289 return ((ip_bits(a1) <= ip_bits(a2))
290 && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
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));
302 * Comparison function for sorting. Add V4/V6 testing!
306 network_cmp(inet *a1, inet *a2)
308 if (ntohl(ip_v4addr(a1)) < ntohl(ip_v4addr(a2)))
311 if (ntohl(ip_v4addr(a1)) > ntohl(ip_v4addr(a2)))
314 if (ip_bits(a1) < ip_bits(a2))
317 if (ip_bits(a1) > ip_bits(a2))
324 network_host(inet *ip)
329 tmp[sizeof("255.255.255.255/32")];
331 if (!PointerIsValid(ip))
335 elog(ERROR, "CIDR type has no host part");
337 if (ip_family(ip) == AF_INET)
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));
344 /* Go for an IPV6 address here, before faulting out: */
345 elog(ERROR, "unknown address family (%d)", ip_family(ip));
347 if ((ptr = strchr(tmp, '/')) != NULL)
349 len = VARHDRSZ + strlen(tmp) + 1;
352 elog(ERROR, "unable to allocate memory in network_host()");
355 strcpy(VARDATA(ret), tmp);
360 network_masklen(inet *ip)
362 if (!PointerIsValid(ip))
369 network_broadcast(inet *ip)
374 tmp[sizeof("255.255.255.255/32")];
376 if (!PointerIsValid(ip))
379 if (ip_family(ip) == AF_INET)
381 /* It's an IP V4 address: */
383 unsigned long mask = 0xffffffff;
385 if (ip_bits(ip) < 32)
386 mask >>= ip_bits(ip);
387 addr = htonl(ntohl(ip_v4addr(ip)) | mask);
389 if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL)
390 elog(ERROR, "unable to print address (%s)", strerror(errno));
394 /* Go for an IPV6 address here, before faulting out: */
395 elog(ERROR, "unknown address family (%d)", ip_family(ip));
397 if ((ptr = strchr(tmp, '/')) != NULL)
399 len = VARHDRSZ + strlen(tmp) + 1;
402 elog(ERROR, "unable to allocate memory in network_broadcast()");
405 strcpy(VARDATA(ret), tmp);
410 network_network(inet *ip)
414 char tmp[sizeof("255.255.255.255/32")];
416 if (!PointerIsValid(ip))
419 if (ip_family(ip) == AF_INET)
421 /* It's an IP V4 address: */
422 int addr = htonl(ntohl(ip_v4addr(ip)) & (0xffffffff << (32 - ip_bits(ip))));
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));
429 /* Go for an IPV6 address here, before faulting out: */
430 elog(ERROR, "unknown address family (%d)", ip_family(ip));
432 len = VARHDRSZ + strlen(tmp) + 1;
435 elog(ERROR, "unable to allocate memory in network_network()");
438 strcpy(VARDATA(ret), tmp);
443 network_netmask(inet *ip)
448 tmp[sizeof("255.255.255.255/32")];
450 if (!PointerIsValid(ip))
453 if (ip_family(ip) == AF_INET)
455 /* It's an IP V4 address: */
456 int addr = htonl((-1 << (32 - ip_bits(ip))) & 0xffffffff);
458 if (inet_net_ntop(AF_INET, &addr, 32, tmp, sizeof(tmp)) == NULL)
459 elog(ERROR, "unable to print netmask (%s)", strerror(errno));
463 /* Go for an IPV6 address here, before faulting out: */
464 elog(ERROR, "unknown address family (%d)", ip_family(ip));
466 if ((ptr = strchr(tmp, '/')) != NULL)
468 len = VARHDRSZ + strlen(tmp) + 1;
471 elog(ERROR, "unable to allocate memory in network_netmask()");
474 strcpy(VARDATA(ret), tmp);
479 * Bitwise comparison for V4 addresses. Add V6 implementation!
483 v4bitncmp(unsigned int a1, unsigned int a2, int bits)
485 unsigned long mask = 0;
488 for (i = 0; i < bits; i++)
489 mask = (mask >> 1) | 0x80000000;
492 if ((a1 & mask) < (a2 & mask))
494 else if ((a1 & mask) > (a2 & mask))