ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/cidr.C
Revision: 1.3
Committed: Sat Jul 21 13:23:21 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.2: +1 -1 lines
Log Message:
- added rcsid to some files
- more documentation tweaks
- made most protocol commands local to phandler.C
- added ircd metadata (inspircd only for now)
- added inspircd swhois support

File Contents

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