1 /*
2  * Various comparison functions
3  */
4 
5 #include <errno.h>
6 #include <stdio.h> /* For NULL */
7 
8 #include <libcidr.h>
9 
10 
11 /* Is one block entirely contained in another? */
12 int
cidr_contains(const CIDR * big,const CIDR * little)13 cidr_contains(const CIDR *big, const CIDR *little)
14 {
15 	int i, oct, bit;
16 	int pflen;
17 
18 	/* Sanity */
19 	if(big==NULL || little==NULL)
20 	{
21 		errno = EFAULT;
22 		return(-1);
23 	}
24 
25 	/* First off, they better be the same type */
26 	if(big->proto != little->proto)
27 	{
28 		errno = EPROTO;
29 		return(-1);
30 	}
31 
32 	/* We better understand the protocol, too */
33 	if(big->proto!=CIDR_IPV4 && big->proto!=CIDR_IPV6)
34 	{
35 		errno = EINVAL;
36 		return(-1);
37 	}
38 
39 	/*
40 	 * little better be SMALL enough to fit in big.  Note: The prefix
41 	 * lengths CAN be the same, and little could still 'fit' in big if
42 	 * the network bits are all the same.  No need to special-case it, as
43 	 * the normal tests below will DTRT.  Save big's pflen for the test
44 	 * loop.
45 	 */
46 	if(cidr_get_pflen(little) < (pflen = cidr_get_pflen(big)))
47 	{
48 		errno = 0;
49 		return(-1);
50 	}
51 
52 	/*
53 	 * Now let's compare.  Note that for IPv4 addresses, the first 12
54 	 * octets are irrelevant.  We take care throughout to keep them
55 	 * zero'd out, so we don't _need_ to explicitly ignore them.  But,
56 	 * it's wasteful; it quadrules the amount of work needed to be done
57 	 * to compare to v4 blocks, and this function may be useful in fairly
58 	 * performance-sensitive parts of the application.  Sure, an extra 12
59 	 * uint8_t compares better not be the make-or-break perforamnce point
60 	 * for anything real, but why make it harder unnecessarily?
61 	 */
62 	if(big->proto==CIDR_IPV4)
63 	{
64 		i = 96;
65 		pflen += 96;
66 	}
67 	else if(big->proto==CIDR_IPV6)
68 		i = 0;
69 	else
70 	{
71 		/* Shouldn't happen */
72 		errno = ENOENT; /* This is a really bad choice of errno */
73 		return(-1);
74 	}
75 
76 	/* Start comparing */
77 	for( /* i */ ; i < pflen ; i++ )
78 	{
79 		/* For convenience, set temp. vars to the octet/bit */
80 		oct = i/8;
81 		bit = 7-(i%8);
82 
83 		if((big->addr[oct] & (1<<bit)) != (little->addr[oct] & (1<<bit)))
84 		{
85 			errno = 0;
86 			return(-1);
87 		}
88 	}
89 
90 	/* If we get here, all their network bits are the same */
91 	return(0);
92 }
93 
94 
95 /* Are two CIDR's the same? */
96 int
cidr_equals(const CIDR * one,const CIDR * two)97 cidr_equals(const CIDR *one, const CIDR *two)
98 {
99 	int i;
100 
101 	/* Check protocols */
102 	if(one->proto != two->proto)
103 		return(-1);
104 
105 	/* Check addresses/masks */
106 	if(one->proto==CIDR_IPV4)
107 		i = 12;
108 	else
109 		i = 0;
110 	for(/* i */ ; i<=15 ; i++)
111 	{
112 		if(one->addr[i] != two->addr[i])
113 			return(-1);
114 		if(one->mask[i] != two->mask[i])
115 			return(-1);
116 	}
117 
118 	/* If we make it here, they're the same */
119 	return(0);
120 }
121