3
3
* is for IP V4 CIDR notation, but prepared for V6: just
4
4
* add the necessary bits where the comments indicate.
5
5
*
6
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.24 2000/08/03 23:07:46 tgl Exp $
6
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.25 2000/10/27 01:52:15 tgl Exp $
7
7
*
8
8
* Jon Postel RIP 16 Oct 1998
9
9
*/
20
20
#include "utils/inet.h"
21
21
22
22
23
- static int v4bitncmp (unsigned int a1 , unsigned int a2 , int bits );
24
23
static int32 network_cmp_internal (inet * a1 , inet * a2 );
24
+ static int v4bitncmp (unsigned long a1 , unsigned long a2 , int bits );
25
+ static bool v4addressOK (unsigned long a1 , int bits );
25
26
26
27
/*
27
28
* Access macros. Add IPV6 support.
@@ -50,14 +51,29 @@ network_in(char *src, int type)
50
51
inet * dst ;
51
52
52
53
dst = (inet * ) palloc (VARHDRSZ + sizeof (inet_struct ));
54
+ /* make sure any unused bits in a CIDR value are zeroed */
55
+ MemSet (dst , 0 , VARHDRSZ + sizeof (inet_struct ));
53
56
54
57
/* First, try for an IP V4 address: */
55
58
ip_family (dst ) = AF_INET ;
56
59
bits = inet_net_pton (ip_family (dst ), src , & ip_v4addr (dst ),
57
60
type ? ip_addrsize (dst ) : -1 );
58
61
if ((bits < 0 ) || (bits > 32 ))
62
+ {
59
63
/* Go for an IPV6 address here, before faulting out: */
60
- elog (ERROR , "could not parse \"%s\"" , src );
64
+ elog (ERROR , "invalid %s value '%s'" ,
65
+ type ? "CIDR" : "INET" , src );
66
+ }
67
+
68
+ /*
69
+ * Error check: CIDR values must not have any bits set beyond the masklen.
70
+ * XXX this code not IPV6 ready.
71
+ */
72
+ if (type )
73
+ {
74
+ if (! v4addressOK (ip_v4addr (dst ), bits ))
75
+ elog (ERROR , "invalid CIDR value '%s': width too small" , src );
76
+ }
61
77
62
78
VARATT_SIZEP (dst ) = VARHDRSZ
63
79
+ ((char * ) & ip_v4addr (dst ) - (char * ) VARDATA (dst ))
@@ -128,24 +144,29 @@ cidr_out(PG_FUNCTION_ARGS)
128
144
/*
129
145
* Basic comparison function for sorting and inet/cidr comparisons.
130
146
*
131
- * XXX this ignores bits to the right of the mask. That's probably
132
- * correct for CIDR, almost certainly wrong for INET. We need to have
133
- * two sets of comparator routines, not just one. Note that suggests
134
- * that CIDR and INET should not be considered binary-equivalent by
135
- * the parser?
147
+ * Comparison is first on the common bits of the network part, then on
148
+ * the length of the network part, and then on the whole unmasked address.
149
+ * The effect is that the network part is the major sort key, and for
150
+ * equal network parts we sort on the host part. Note this is only sane
151
+ * for CIDR if address bits to the right of the mask are guaranteed zero;
152
+ * otherwise logically-equal CIDRs might compare different.
136
153
*/
137
154
138
155
static int32
139
156
network_cmp_internal (inet * a1 , inet * a2 )
140
157
{
141
158
if (ip_family (a1 ) == AF_INET && ip_family (a2 ) == AF_INET )
142
159
{
143
- int order = v4bitncmp (ip_v4addr (a1 ), ip_v4addr (a2 ),
144
- Min (ip_bits (a1 ), ip_bits (a2 )));
160
+ int order ;
145
161
162
+ order = v4bitncmp (ip_v4addr (a1 ), ip_v4addr (a2 ),
163
+ Min (ip_bits (a1 ), ip_bits (a2 )));
164
+ if (order != 0 )
165
+ return order ;
166
+ order = ((int ) ip_bits (a1 )) - ((int ) ip_bits (a2 ));
146
167
if (order != 0 )
147
168
return order ;
148
- return (( int32 ) ip_bits ( a1 )) - (( int32 ) ip_bits ( a2 ));
169
+ return v4bitncmp ( ip_v4addr ( a1 ), ip_v4addr ( a2 ), 32 );
149
170
}
150
171
else
151
172
{
@@ -455,13 +476,11 @@ network_netmask(PG_FUNCTION_ARGS)
455
476
*/
456
477
457
478
static int
458
- v4bitncmp (unsigned int a1 , unsigned int a2 , int bits )
479
+ v4bitncmp (unsigned long a1 , unsigned long a2 , int bits )
459
480
{
460
- unsigned long mask = 0 ;
461
- int i ;
481
+ unsigned long mask ;
462
482
463
- for (i = 0 ; i < bits ; i ++ )
464
- mask = (mask >> 1 ) | 0x80000000 ;
483
+ mask = (0xFFFFFFFFL << (32 - bits )) & 0xFFFFFFFFL ;
465
484
a1 = ntohl (a1 );
466
485
a2 = ntohl (a2 );
467
486
if ((a1 & mask ) < (a2 & mask ))
@@ -470,3 +489,18 @@ v4bitncmp(unsigned int a1, unsigned int a2, int bits)
470
489
return (1 );
471
490
return (0 );
472
491
}
492
+
493
+ /*
494
+ * Returns true if given address fits fully within the specified bit width.
495
+ */
496
+ static bool
497
+ v4addressOK (unsigned long a1 , int bits )
498
+ {
499
+ unsigned long mask ;
500
+
501
+ mask = (0xFFFFFFFFL << (32 - bits )) & 0xFFFFFFFFL ;
502
+ a1 = ntohl (a1 );
503
+ if ((a1 & mask ) == a1 )
504
+ return true;
505
+ return false;
506
+ }
0 commit comments