ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/cidr.C
Revision: 1.5
Committed: Sun Sep 16 18:54:44 2007 UTC (16 years, 8 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +7 -1 lines
Log Message:
#defines to enum

File Contents

# Content
1 /**
2 * cidr.C: CIDR matching.
3 *
4 * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5 * Rights to this code are as documented in COPYING.
6 *
7 *
8 * Portions of this file were derived from sources bearing the following license:
9 * Rights to this code are documented in doc/pod/license.pod.
10 *
11 * Most code in this file has been copied from ratbox, src/match.c and
12 * src/irc_string.c. It provides CIDR matching for IPv4 and IPv6 without
13 * special OS support.
14 *
15 * Copyright © 1996-2002 Hybrid Development Team
16 * Copyright © 2002-2005 ircd-ratbox development team
17 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
18 */
19
20 static char const rcsid[] = "$Id: cidr.C,v 1.4 2007-08-28 17:08:12 pippijn Exp $";
21
22 #include "atheme.h"
23
24 #ifndef INADDRSZ
25 #define INADDRSZ 4
26 #endif
27 #ifndef IN6ADDRSZ
28 #define IN6ADDRSZ 16
29 #endif
30 #ifndef INT16SZ
31 #define INT16SZ 2
32 #endif
33
34 /* compares the first 'mask' bits
35 * returns 1 if equal, 0 if not */
36 static int
37 comp_with_mask (void *addr, void *dest, unsigned mask)
38 {
39 if (memcmp (addr, dest, mask / 8) == 0)
40 {
41 int n = mask / 8;
42 int m = ((-1) << (8 - (mask % 8)));
43 if (mask % 8 == 0 || (((unsigned char *) addr)[n] & m) == (((unsigned char *) dest)[n] & m))
44 {
45 return (1);
46 }
47 }
48 return (0);
49 }
50
51 /*
52 * inet_pton4() and inet_pton6() are
53 * Copyright © 1996-1999 by Internet Software Consortium.
54 *
55 * Permission to use, copy, modify, and distribute this software for any
56 * purpose with or without fee is hereby granted, provided that the above
57 * copyright notice and this permission notice appear in all copies.
58 *
59 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
60 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
61 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
62 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
63 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
64 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
65 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
66 * SOFTWARE.
67 */
68
69 /*
70 * WARNING: Don't even consider trying to compile this on a system where
71 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
72 */
73
74 /* int
75 * inet_pton4(src, dst)
76 * like inet_aton() but without all the hexadecimal and shorthand.
77 * return:
78 * 1 if `src' is a valid dotted quad, else 0.
79 * notice:
80 * does not touch `dst' unless it's returning 1.
81 * author:
82 * Paul Vixie, 1996.
83 */
84 static int
85 inet_pton4 (char const *src, unsigned char *dst)
86 {
87 int saw_digit, octets, ch;
88 unsigned char tmp[INADDRSZ], *tp;
89
90 saw_digit = 0;
91 octets = 0;
92 *(tp = tmp) = 0;
93 while ((ch = *src++) != '\0')
94 {
95 if (ch >= '0' && ch <= '9')
96 {
97 unsigned newtp = *tp * 10 + (ch - '0');
98
99 if (newtp > 255)
100 return (0);
101 *tp = newtp;
102 if (!saw_digit)
103 {
104 if (++octets > 4)
105 return (0);
106 saw_digit = 1;
107 }
108 }
109 else if (ch == '.' && saw_digit)
110 {
111 if (octets == 4)
112 return (0);
113 *++tp = 0;
114 saw_digit = 0;
115 }
116 else
117 return (0);
118 }
119 if (octets < 4)
120 return (0);
121 memcpy (dst, tmp, INADDRSZ);
122 return (1);
123 }
124
125 /* int
126 * inet_pton6(src, dst)
127 * convert presentation level address to network order binary form.
128 * return:
129 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
130 * notice:
131 * (1) does not touch `dst' unless it's returning 1.
132 * (2) :: in a full address is silently ignored.
133 * credit:
134 * inspired by Mark Andrews.
135 * author:
136 * Paul Vixie, 1996.
137 */
138 static int
139 inet_pton6 (char const *src, unsigned char *dst)
140 {
141 static const char xdigits[] = "0123456789abcdef";
142 unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
143 char const *curtok;
144 int ch, saw_xdigit;
145 unsigned val;
146
147 tp = static_cast<unsigned char *> (memset (tmp, '\0', IN6ADDRSZ));
148 endp = tp + IN6ADDRSZ;
149 colonp = NULL;
150 /* Leading :: requires some special handling. */
151 if (*src == ':')
152 if (*++src != ':')
153 return (0);
154 curtok = src;
155 saw_xdigit = 0;
156 val = 0;
157 while ((ch = tolower (*src++)) != '\0')
158 {
159 char const *pch;
160
161 pch = strchr (xdigits, ch);
162 if (pch != NULL)
163 {
164 val <<= 4;
165 val |= (pch - xdigits);
166 if (val > 0xffff)
167 return (0);
168 saw_xdigit = 1;
169 continue;
170 }
171 if (ch == ':')
172 {
173 curtok = src;
174 if (!saw_xdigit)
175 {
176 if (colonp)
177 return (0);
178 colonp = tp;
179 continue;
180 }
181 else if (*src == '\0')
182 {
183 return (0);
184 }
185 if (tp + INT16SZ > endp)
186 return (0);
187 *tp++ = (unsigned char) (val >> 8) & 0xff;
188 *tp++ = (unsigned char) val & 0xff;
189 saw_xdigit = 0;
190 val = 0;
191 continue;
192 }
193 if (*src != '\0' && ch == '.')
194 {
195 if (((tp + INADDRSZ) <= endp) && inet_pton4 (curtok, tp) > 0)
196 {
197 tp += INADDRSZ;
198 saw_xdigit = 0;
199 break; /* '\0' was seen by inet_pton4(). */
200 }
201 }
202 else
203 continue;
204 return (0);
205 }
206 if (saw_xdigit)
207 {
208 if (tp + INT16SZ > endp)
209 return (0);
210 *tp++ = (unsigned char) (val >> 8) & 0xff;
211 *tp++ = (unsigned char) val & 0xff;
212 }
213 if (colonp != NULL)
214 {
215 /*
216 * Since some memmove()'s erroneously fail to handle
217 * overlapping regions, we'll do the shift by hand.
218 */
219 const int n = tp - colonp;
220 int i;
221
222 if (tp == endp)
223 return (0);
224 for (i = 1; i <= n; i++)
225 {
226 endp[-i] = colonp[n - i];
227 colonp[n - i] = 0;
228 }
229 tp = endp;
230 }
231 if (tp != endp)
232 return (0);
233 memcpy (dst, tmp, IN6ADDRSZ);
234 return (1);
235 }
236
237 /*
238 * match_ips()
239 *
240 * Input - cidr ip mask, address
241 * Output - 0 = Matched 1 = Did not match
242 * switched 0 and 1 to be consistent with match() -- jilles
243 */
244 int
245 match_ips (char const * const s1, char const * const s2)
246 {
247 unsigned char ipaddr[IN6ADDRSZ], maskaddr[IN6ADDRSZ];
248 char ipmask[BUFSIZE];
249 char ip[HOSTLEN + 1];
250 char *len;
251 int cidrlen;
252
253 strlcpy (ipmask, s1, sizeof ipmask);
254 strlcpy (ip, s2, sizeof ip);
255
256 len = strrchr (ipmask, '/');
257 if (len == NULL)
258 return 1;
259
260 *len++ = '\0';
261
262 cidrlen = atoi (len);
263 if (cidrlen == 0)
264 return 1;
265
266 if (strchr (ip, ':') && strchr (ipmask, ':'))
267 {
268 if (cidrlen > 128)
269 return 1;
270 if (!inet_pton6 (ip, ipaddr))
271 return 1;
272 if (!inet_pton6 (ipmask, maskaddr))
273 return 1;
274 return !comp_with_mask (ipaddr, maskaddr, cidrlen);
275 }
276 else if (!strchr (ip, ':') && !strchr (ipmask, ':'))
277 {
278 if (cidrlen > 32)
279 return 1;
280 if (!inet_pton4 (ip, ipaddr))
281 return 1;
282 if (!inet_pton4 (ipmask, maskaddr))
283 return 1;
284 return !comp_with_mask (ipaddr, maskaddr, cidrlen);
285 }
286 else
287 return 1;
288 }
289
290 /* match_cidr()
291 *
292 * Input - mask n!u@i/c, address n!u@i
293 * Output - 0 = Matched 1 = Did not match
294 * switched 0 and 1 to be consistent with match() -- jilles
295 */
296 int
297 match_cidr (char const * const s1, char const * const s2)
298 {
299 unsigned char ipaddr[IN6ADDRSZ], maskaddr[IN6ADDRSZ];
300 char mask[BUFSIZE];
301 char address[NICKLEN + USERLEN + HOSTLEN + 6];
302 char *ipmask;
303 char *ip;
304 char *len;
305 int cidrlen;
306
307 strlcpy (mask, s1, sizeof mask);
308 strlcpy (address, s2, sizeof address);
309
310 ipmask = strrchr (mask, '@');
311 if (ipmask == NULL)
312 return 1;
313
314 *ipmask++ = '\0';
315
316 ip = strrchr (address, '@');
317 if (ip == NULL)
318 return 1;
319 *ip++ = '\0';
320
321 len = strrchr (ipmask, '/');
322 if (len == NULL)
323 return 1;
324
325 *len++ = '\0';
326
327 cidrlen = atoi (len);
328 if (cidrlen == 0)
329 return 1;
330
331 if (strchr (ip, ':') && strchr (ipmask, ':'))
332 {
333 if (cidrlen > 128)
334 return 1;
335 if (!inet_pton6 (ip, ipaddr))
336 return 1;
337 if (!inet_pton6 (ipmask, maskaddr))
338 return 1;
339 return !comp_with_mask (ipaddr, maskaddr, cidrlen) || match (mask, address);
340 }
341 else if (!strchr (ip, ':') && !strchr (ipmask, ':'))
342 {
343 if (cidrlen > 32)
344 return 1;
345 if (!inet_pton4 (ip, ipaddr))
346 return 1;
347 if (!inet_pton4 (ipmask, maskaddr))
348 return 1;
349 return !comp_with_mask (ipaddr, maskaddr, cidrlen) || match (mask, address);
350 }
351 else
352 return 1;
353 }
354
355 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
356 * vim:ts=8
357 * vim:sw=8
358 * vim:noexpandtab
359 */