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 (unsignedint a1 ,unsignedint 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 (unsignedint a1 ,unsignedint a2 ,int bits )
479
+ v4bitncmp (unsignedlong a1 ,unsignedlong 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
+ }