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

# User Rev Content
1 pippijn 1.1 /**
2     * cidr.C: CIDR matching.
3 pippijn 1.5 *
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 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
10 pippijn 1.1 *
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 pippijn 1.4 * 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 pippijn 1.1 */
19    
20 pippijn 1.5 static char const rcsid[] = "$Id: cidr.C,v 1.4 2007-08-28 17:08:12 pippijn Exp $";
21 pippijn 1.1
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 pippijn 1.4 * Copyright © 1996-1999 by Internet Software Consortium.
54 pippijn 1.1 *
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 pippijn 1.4 char const *curtok;
144 pippijn 1.1 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 pippijn 1.4 char const *pch;
160 pippijn 1.1
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 pippijn 1.4 match_ips (char const * const s1, char const * const s2)
246 pippijn 1.1 {
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 pippijn 1.4 match_cidr (char const * const s1, char const * const s2)
298 pippijn 1.1 {
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     */