// C Code to convert a given Ip range to CIDR notation.
1
2 /* rangeToCidr.c - Convert Ip ranges to CIDR */
3
4 /*
5 modification history
6 --------------------
7 01a,17sep08,karn written
8 */
9
10 /* includes */
11
12
13
14
15
16
17
18
19
20
21 /* defines */
22 //
23
24
25
26
27
28
29
30
31
32
33
34 /* Forward declaratopms */
35 void rangeToCidr(uint32_t from ,uint32_t to,
36 void (callback)(char *cidrNotation));
37 int ipToBin(uint32_t ip , char * pOut);
38
39 void printNotation(char *cidrNotation);
40
41 /* Globals */
42
43
44 /*******************************************************************************
45 *
46 * ipToBin - convert an ipv4 address to binary representation
47 * and pads zeros to the beginning of the string if
48 * the length is not 32
49 * (Important for ranges like 10.10.0.1 - 20.20.20.20 )
50 *
51 * ip - ipv4 address on host order
52 * pOut - Buffer to store binary.
53 *
54 * RETURNS: OK or ERROR
55 */
56
57 int ipToBin(uint32_t ip , char * pOut)
58 {
59 char hex[IP_HEX_LENGTH];
60 int i;
61 int result=0;
62 int len;
63 char pTmp[2];
64 int tmp;
65 /*
66 * XXX: Could use bit operations instead but was easier to debug
67 */
68 char binMap[16][5] = {
69 "0000","0001","0010","0011", "0100",
70 "0101","0110","0111","1000", "1001",
71 "1010","1011","1100", "1101","1110","1111",
72 };
73 pTmp[1]=0x0;
74 memset(hex,0x0,sizeof(hex));
75 len=sprintf(hex,"%x",ip);
76
77 for(i=0;i<len;i++)
78 {
79
80 /* Ugly but to use strtol , we need the last byte as null */
81 pTmp[0]=hex[i];
82
83 errno = 0;
84 tmp = strtol(pTmp, 0x0, 16);
85
86 /* Should not happen */
87 if (errno != 0)
88 {
89 memset(pOut,'0',IP_BINARY_LENGTH -1);
90 DEBUG ("strtol failed for hex 0x%s\n",pTmp);
91 return -1;
92 }
93
94 result+=sprintf(pOut+result,"%s",binMap[tmp]);
95 }
96
97 DEBUG("bits %u printed for ip address for hex len %u\n",result,len);
98 /* if length is not 32 , pad the start with zeros*/
99
100 if(result < IP_BINARY_LENGTH-1)
101 {
102 char pSwap[IP_BINARY_LENGTH];
103 strncpy(pSwap,pOut,IP_BINARY_LENGTH);
104 memset(pOut,'0',IP_BINARY_LENGTH);
105 strncpy(pOut+IP_BINARY_LENGTH-1-result,pSwap,result);
106 DEBUG("corrected length to 32\n");
107 }
108
109 else if (result > IP_BINARY_LENGTH-1)
110 return -1;
111
112 /* Success */
113 return 0;
114 }
115
116 /*******************************************************************************
117 * main :
118 *
119 * arg1 : Start Ip Address
120 * arg2 : End Ip address
121 */
122
123 int main (int argc,char **argv)
124 {
125 long fromIp, toIp;
126 struct in_addr addr;
127 if(argc !=3 )
128 {
129 printf("Usage: %s <from> <to>\n",argv[0]);
130 return(0);
131 }
132
133 /* All operation on host order */
134 if (inet_aton(argv[1],&addr) == 0)
135 goto error;
136 fromIp = ntohl(addr.s_addr);
137
138 if (inet_aton(argv[2],&addr) ==0)
139 goto error;
140 toIp = ntohl(addr.s_addr);
141
142 rangeToCidr(fromIp,toIp,printNotation);
143
144 return 0;
145 error:
146 printf("Invalid Argument\n");
147 return -EINVAL;
148 }
149
150
151 /*******************************************************************************
152 *
153 * rangeToCidr - convert an ip Range to CIDR, and call 'callback' to handle
154 * the value.
155 *
156 * from - IP Range start address
157 * to - IP Range end address
158 * callback - Callback function to handle cidr.
159 * RETURNS: OK or ERROR
160 */
161
162 void rangeToCidr(uint32_t from ,uint32_t to,
163 void (callback)(char *cidrNotation))
164 {
165 int cidrStart = 0;
166 int cidrEnd = MAX_CIDR_MASK - 1;
167 long newfrom;
168 long mask;
169 char fromIp[IP_BINARY_LENGTH];
170 char toIp[IP_BINARY_LENGTH];
171 struct in_addr addr;
172 char cidrNotation[MAX_CIDR_LEN];
173
174 memset (fromIp,0x0,sizeof(fromIp));
175 memset (toIp,0x0,sizeof(toIp));
176
177 if ( ipToBin(from,fromIp) != 0 )
178 return;
179 if ( ipToBin(to,toIp) != 0 )
180 return;
181
182 DEBUG ("from %lu to %lu\n", from,to);
183 DEBUG("from %s\n",fromIp);
184 DEBUG("to %s\n",toIp);
185
186 if(from < to )
187 {
188
189 /* Compare the from and to address ranges to get the first
190 * point of difference
191 */
192
193 while(fromIp[cidrStart]==toIp[cidrStart])
194 cidrStart ++;
195 cidrStart = 32 - cidrStart -1 ;
196 DEBUG("cidrStart is %u\n",cidrStart);
197
198 /* Starting from the found point of difference make all bits on the
199 * right side zero
200 */
201
202 newfrom = from >> cidrStart +1 << cidrStart +1 ;
203
204 /* Starting from the end iterate reverse direction to find
205 * cidrEnd
206 */
207 while( fromIp[cidrEnd] == '0' && toIp[cidrEnd] == '1')
208 cidrEnd --;
209
210 cidrEnd = MAX_CIDR_MASK - 1 - cidrEnd;
211 DEBUG("cidrEnd is %u\n",cidrEnd);
212
213 if(cidrEnd <= cidrStart)
214 {
215 /*
216 * Make all the bit-shifted bits equal to 1, for
217 * iteration
218 */
219
220 mask = pow (2, cidrStart ) - 1;
221 DEBUG("it1 is %lu \n",newfrom | mask );
222 rangeToCidr (from , newfrom | mask, callback);
223 DEBUG("it2 is %lu \n",newfrom | 1 << cidrStart);
224 rangeToCidr (newfrom | 1 << cidrStart ,to ,callback);
225 }
226 else
227 {
228 addr.s_addr = htonl(newfrom);
229 sprintf(cidrNotation,"%s/%d",
230 inet_ntoa(addr), MAX_CIDR_MASK-cidrEnd);
231 if (callback != NULL)
232 callback(cidrNotation);
233 }
234 }
235
236 else
237 {
238 addr.s_addr = htonl(from);
239 sprintf(cidrNotation,"%s/%d",inet_ntoa(addr),MAX_CIDR_MASK);
240 if(callback != NULL)
241 callback(cidrNotation);
242 }
243 }
244
245 /*******************************************************************************
246 *
247 * printNotation - This is an example callback function to handle cidr notation.
248 *
249 * RETURNS:
250 */
251
252 void printNotation(char *cidrNotation)
253 {
254 printf("%s\n",cidrNotation);
255 }