~ubuntu-branches/ubuntu/karmic/dante/karmic

« back to all changes in this revision

Viewing changes to sockd/addressmatch.c

  • Committer: Bazaar Package Importer
  • Author(s): Thijs Kinkhorst
  • Date: 2006-10-19 12:09:39 UTC
  • mfrom: (3.1.1 dapper)
  • Revision ID: james.westby@ubuntu.com-20061019120939-t818x24e2tn8be5k
Tags: 1.1.18-2.1
* Non-maintainer upload for RC bug.
* Make sure changelogs are installed into all packages (Closes: #393568).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003
3
 
 *      Inferno Nettverk A/S, Norway.  All rights reserved.
4
 
 *
5
 
 * Redistribution and use in source and binary forms, with or without
6
 
 * modification, are permitted provided that the following conditions
7
 
 * are met:
8
 
 * 1. The above copyright notice, this list of conditions and the following
9
 
 *    disclaimer must appear in all copies of the software, derivative works
10
 
 *    or modified versions, and any portions thereof, aswell as in all
11
 
 *    supporting documentation.
12
 
 * 2. All advertising materials mentioning features or use of this software
13
 
 *    must display the following acknowledgement:
14
 
 *      This product includes software developed by
15
 
 *      Inferno Nettverk A/S, Norway.
16
 
 * 3. The name of the author may not be used to endorse or promote products
17
 
 *    derived from this software without specific prior written permission.
18
 
 *
19
 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20
 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21
 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22
 
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23
 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24
 
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28
 
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
 
 *
30
 
 * Inferno Nettverk A/S requests users of this software to return to
31
 
 *
32
 
 *  Software Distribution Coordinator  or  sdc@inet.no
33
 
 *  Inferno Nettverk A/S
34
 
 *  Oslo Research Park
35
 
 *  Gaustadall�en 21
36
 
 *  NO-0349 Oslo
37
 
 *  Norway
38
 
 *
39
 
 * any improvements or extensions that they make and grant Inferno Nettverk A/S
40
 
 * the rights to redistribute these changes.
41
 
 *
42
 
 */
43
 
 
44
 
#include "common.h"
45
 
 
46
 
static const char rcsid[] =
47
 
"$Id: addressmatch.c,v 1.8 2003/07/01 13:21:25 michaels Exp $";
48
 
 
49
 
__BEGIN_DECLS
50
 
 
51
 
static int
52
 
addrisinlist __P((const struct in_addr *addr, const struct in_addr *mask,
53
 
                                          const struct in_addr **list));
54
 
/*
55
 
 * Compares "addr" bitwise anded with "mask" against each element in
56
 
 * "list" bitwise anded with "mask".  "list" is NULL terminated.
57
 
 * Returns:
58
 
 *              If "list" contains a element matching "addr" and "mask": true
59
 
 *              else: false
60
 
 */
61
 
 
62
 
static int
63
 
addrareeq __P((const struct in_addr *addr, const struct in_addr *mask,
64
 
                                        const struct in_addr *against));
65
 
/*
66
 
 * Compares "addr" bitwise anded with "mask" against "against" bitwise
67
 
 * anded with "mask".
68
 
 * Returns:
69
 
 *              If "against" matches "addr" and "mask": true
70
 
 *              else: false
71
 
 */
72
 
 
73
 
static int
74
 
hostisinlist __P((const char *host, const char **list));
75
 
/*
76
 
 * Compares "host" against each element in "list", which is NULL
77
 
 * terminated.
78
 
 * Note that if "host" starts with a dot, it will match "list" if the
79
 
 * last part of "list" matches the part after the dot in "host".
80
 
 * Returns:
81
 
 *              If "list" contains a element matching "host": true
82
 
 *              else: false
83
 
 */
84
 
 
85
 
static int
86
 
hostareeq __P((const char *domain, const char *remotedomain));
87
 
/*
88
 
 * Compares the rulegiven domain "domain" against "remotedomain".
89
 
 * Note that if "domain" starts with a dot, it will match
90
 
 * "remotedomain" if the last part of "remotedomain" matches
91
 
 * the part after the dot in "domain".
92
 
 * Returns:
93
 
 *              on match: true
94
 
 *              else: false
95
 
 */
96
 
 
97
 
 
98
 
__END_DECLS
99
 
 
100
 
int
101
 
addressmatch(rule, address, protocol, alias)
102
 
        const struct ruleaddress_t *rule;
103
 
        const struct sockshost_t *address;
104
 
        int protocol;
105
 
        int alias;
106
 
{
107
 
        const char *function = "addressmatch()";
108
 
        struct hostent *hostent;
109
 
        in_port_t ruleport;
110
 
        int matched, doresolve;
111
 
        char rstring[MAXRULEADDRSTRING], astring[MAXSOCKSHOSTSTRING];
112
 
 
113
 
        slog(LOG_DEBUG, "%s: %s, %s, %s, %d",
114
 
        function,
115
 
        ruleaddress2string(rule, rstring, sizeof(rstring)),
116
 
        sockshost2string(address, astring, sizeof(astring)),
117
 
        protocol2string(protocol),
118
 
        alias);
119
 
 
120
 
        /* test port first since we always have all info needed for that locally. */
121
 
        switch (protocol) {
122
 
                case SOCKS_TCP:
123
 
                        ruleport = rule->port.tcp;
124
 
                        break;
125
 
 
126
 
                case SOCKS_UDP:
127
 
                        ruleport = rule->port.udp;
128
 
                        break;
129
 
 
130
 
                default:
131
 
                        SERRX(protocol);
132
 
        }
133
 
 
134
 
        switch (rule->operator) {
135
 
                case none:
136
 
                        break;
137
 
 
138
 
                case eq:
139
 
                        if (address->port == ruleport)
140
 
                                break;
141
 
                        return 0;
142
 
 
143
 
                case neq:
144
 
                        if (address->port != ruleport)
145
 
                                break;
146
 
                        return 0;
147
 
 
148
 
                case ge:
149
 
                        if (ntohs(address->port) >= ntohs(ruleport))
150
 
                                break;
151
 
                        return 0;
152
 
 
153
 
                case le:
154
 
                        if (ntohs(address->port) <= ntohs(ruleport))
155
 
                                break;
156
 
                        return 0;
157
 
 
158
 
                case gt:
159
 
                        if (ntohs(address->port) > ntohs(ruleport))
160
 
                                break;
161
 
                        return 0;
162
 
 
163
 
                case lt:
164
 
                        if (ntohs(address->port) < ntohs(ruleport))
165
 
                                break;
166
 
                        return 0;
167
 
 
168
 
                case range:
169
 
                        if (ntohs(address->port) >= ntohs(ruleport)
170
 
                        &&  ntohs(address->port) <= ntohs(rule->portend))
171
 
                                break;
172
 
                        return 0;
173
 
 
174
 
                default:
175
 
                        SERRX(rule->operator);
176
 
        }
177
 
 
178
 
        /* only needed for client really... */
179
 
        switch (sockscf.resolveprotocol) {
180
 
                case RESOLVEPROTOCOL_TCP:
181
 
                case RESOLVEPROTOCOL_UDP:
182
 
                        doresolve = 1;
183
 
                        break;
184
 
 
185
 
                case RESOLVEPROTOCOL_FAKE:
186
 
                        doresolve = 0;
187
 
                        break;
188
 
 
189
 
                default:
190
 
                        SERRX(sockscf.resolveprotocol);
191
 
        }
192
 
 
193
 
        /*
194
 
         * The hard work begins.
195
 
         */
196
 
 
197
 
        matched = 0;
198
 
        if (rule->atype == SOCKS_ADDR_IPV4 && address->atype == SOCKS_ADDR_DOMAIN) {
199
 
                /*
200
 
                 * match(rule.ipaddress, address.hostname)
201
 
                 * resolve address to ipaddress(es) and try to match each
202
 
                 *      resolved IP address against rule.
203
 
                 *              rule isin address->ipaddress(es)
204
 
                 *              .
205
 
                 */
206
 
 
207
 
                if (!doresolve)
208
 
                        return 0;
209
 
 
210
 
                /* LINTED pointer casts may be troublesome */
211
 
                if ((hostent = gethostbyname(address->addr.domain)) == NULL) {
212
 
                        char *name;
213
 
 
214
 
                        slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
215
 
                        function, strcheck(name = str2vis(address->addr.domain,
216
 
                        strlen(address->addr.domain))), hstrerror(h_errno));
217
 
                        free(name);
218
 
                        return 0;
219
 
                }
220
 
 
221
 
                matched = addrisinlist(&rule->addr.ipv4.ip, &rule->addr.ipv4.mask,
222
 
                (const struct in_addr **)hostent->h_addr_list);
223
 
        }
224
 
        else if (rule->atype == SOCKS_ADDR_IPV4
225
 
        && address->atype == SOCKS_ADDR_IPV4) {
226
 
                /*
227
 
                 * match(rule.ipaddress, address.ipaddress)
228
 
                 * try first a simple comparison, address against rule.
229
 
                 */
230
 
                if (!(matched = addrareeq(&rule->addr.ipv4.ip, &rule->addr.ipv4.mask,
231
 
                &address->addr.ipv4))) {
232
 
                        /*
233
 
                         * Didn't match.  If alias is set, try to resolve address
234
 
                         * to hostname(s), the hostname back to IP address(es) and
235
 
                         * then match those IP address(es) against rule.
236
 
                         *              rule isin address->hostname(s)->ipaddress(es)
237
 
                         *              .
238
 
                         */
239
 
 
240
 
                        if (!doresolve)
241
 
                                return 0;
242
 
 
243
 
                        if (alias) {
244
 
                                char *nexthost;
245
 
                                int i;
246
 
 
247
 
                                /* LINTED pointer casts may be troublesome */
248
 
                                if ((hostent = gethostbyaddr((const char *)&address->addr.ipv4,
249
 
                                sizeof(address->addr.ipv4), AF_INET)) == NULL) {
250
 
                                        slog(LOG_DEBUG, "%s: %s: %s",
251
 
                                        function, inet_ntoa(address->addr.ipv4), hstrerror(h_errno));
252
 
                                        return 0;
253
 
                                }
254
 
 
255
 
                                if ((hostent = hostentdup(hostent)) == NULL) {
256
 
                                        swarnx("%s: hostentdup()", function);
257
 
                                        return 0;
258
 
                                }
259
 
 
260
 
                                nexthost = hostent->h_name;
261
 
                                i = 0;
262
 
                                do {
263
 
                                        struct hostent *iphostent;
264
 
 
265
 
                                        /* iphostent = address->hostname(s)->ipaddress(es) */
266
 
                                        if ((iphostent = gethostbyname(nexthost)) == NULL) {
267
 
                                                slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
268
 
                                                function, nexthost, hstrerror(h_errno));
269
 
                                                continue;
270
 
                                        }
271
 
 
272
 
                                        /* rule isin address->hostname(s)->ipaddress(es) */
273
 
                                        if (addrisinlist(&rule->addr.ipv4.ip, &rule->addr.ipv4.mask,
274
 
                                        (const struct in_addr **)iphostent->h_addr_list)) {
275
 
                                                matched = 1;
276
 
                                                break;
277
 
                                        }
278
 
                                } while (hostent->h_aliases != NULL
279
 
                                && (nexthost = hostent->h_aliases[i++]) != NULL);
280
 
 
281
 
                                hostentfree(hostent);
282
 
                        }
283
 
 
284
 
                        if (!matched)
285
 
                                return 0;
286
 
                }
287
 
        }
288
 
        else if (rule->atype == SOCKS_ADDR_DOMAIN
289
 
        && address->atype == SOCKS_ADDR_DOMAIN) {
290
 
                /*
291
 
                 * match(rule.hostname, address.hostname)
292
 
                 * Try simple match first.
293
 
                 *
294
 
                 * If no go and rule is a hostname rather than a domain,
295
 
                 * resolve both rule and address to IP address(es) and compare
296
 
                 * each IP address of resolved rule against each IP address of
297
 
                 * resolved address.
298
 
                 *              rule->ipaddress(es) isin address->ipaddress(es)
299
 
                 *              .
300
 
                 *
301
 
                 */
302
 
                if (hostareeq(rule->addr.domain, address->addr.domain))
303
 
                        matched = 1;
304
 
                else if (doresolve && *rule->addr.domain != '.') {
305
 
                        struct hostent *addresshostent;
306
 
                        struct in_addr mask;
307
 
                        int i;
308
 
 
309
 
                        if ((hostent = gethostbyname(rule->addr.domain)) == NULL) {
310
 
                                        slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
311
 
                                        function, rule->addr.domain, hstrerror(h_errno));
312
 
                                        return 0;
313
 
                        }
314
 
 
315
 
                        if ((hostent = hostentdup(hostent)) == NULL) {
316
 
                                swarnx("%s: hostentdup()", function);
317
 
                                return 0;
318
 
                        }
319
 
 
320
 
                        if ((addresshostent = gethostbyname(address->addr.domain)) == NULL) {
321
 
                                slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
322
 
                                function, address->addr.domain, hstrerror(h_errno));
323
 
                                hostentfree(hostent);
324
 
                                return 0;
325
 
                        }
326
 
 
327
 
                        /*
328
 
                         *      rule->ipaddress(es) isin address->ipaddress(es)
329
 
                         */
330
 
 
331
 
                        if (hostent->h_addr_list == NULL) {
332
 
                                hostentfree(hostent);
333
 
                                return 0;
334
 
                        }
335
 
 
336
 
                        mask.s_addr = htonl(0xffffffff);
337
 
                        for (i = 0; !matched && hostent->h_addr_list[i] != NULL; ++i)
338
 
                                /* LINTED pointer casts may be troublesome */
339
 
                                matched
340
 
                                = addrisinlist((const struct in_addr *)hostent->h_addr_list[i],
341
 
                                &mask, (const struct in_addr **)addresshostent->h_addr_list);
342
 
 
343
 
                        hostentfree(hostent);
344
 
                }
345
 
 
346
 
                if (!matched)
347
 
                        return 0;
348
 
        }
349
 
        else if (rule->atype == SOCKS_ADDR_DOMAIN
350
 
        && address->atype == SOCKS_ADDR_IPV4) {
351
 
                /*
352
 
                 * match(rule.hostname, address.ipaddress)
353
 
                 * If rule is not a domain, try resolving rule to IP address(es)
354
 
                 * and match against address.
355
 
                 *              address isin rule->ipaddress
356
 
                 *              .
357
 
                 *
358
 
                 * If no match, resolve address to hostname(s) and match each
359
 
                 * against rule.
360
 
                 *              rule isin address->hostname
361
 
                 *              .
362
 
                 *
363
 
                 * If still no match and alias is set, resolve all IP addresses
364
 
                 * of all hostname(s) resolved from address back to hostname(s)
365
 
                 * and match them against rule.
366
 
                 *              rule isin address->hostname->ipaddress->hostname
367
 
                 *              .
368
 
                 */
369
 
 
370
 
                if (!doresolve)
371
 
                        return 0;
372
 
 
373
 
                if (*rule->addr.domain != '.') {
374
 
                        /* address isin rule->ipaddress */
375
 
                        struct in_addr mask;
376
 
 
377
 
                        if ((hostent = gethostbyname(rule->addr.domain)) == NULL) {
378
 
                                slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
379
 
                                function, rule->addr.domain, hstrerror(h_errno));
380
 
                                return 0;
381
 
                        }
382
 
 
383
 
                        mask.s_addr = htonl(0xffffffff);
384
 
                        matched = addrisinlist(&address->addr.ipv4, &mask,
385
 
                        (const struct in_addr **)hostent->h_addr_list);
386
 
                }
387
 
 
388
 
                if (!matched) {
389
 
                        /* rule isin address->hostname */
390
 
 
391
 
                        /* LINTED pointer casts may be troublesome */
392
 
                        if ((hostent = gethostbyaddr((const char *)&address->addr.ipv4,
393
 
                        sizeof(address->addr.ipv4), AF_INET)) == NULL) {
394
 
                                slog(LOG_DEBUG, "%s: gethostbyaddr(%s): %s",
395
 
                                function, inet_ntoa(address->addr.ipv4), hstrerror(h_errno));
396
 
                                return 0;
397
 
                        }
398
 
 
399
 
                        if (hostareeq(rule->addr.domain, hostent->h_name)
400
 
                        ||  hostisinlist(rule->addr.domain, (const char **)hostent->h_aliases))
401
 
                                matched = 1;
402
 
                }
403
 
 
404
 
                if (!matched && alias) {
405
 
                        /*
406
 
                         * rule isin address->hostname->ipaddress->hostname.
407
 
                         * hostent is already address->hostname due to above.
408
 
                         */
409
 
                        char *nexthost;
410
 
                        int i;
411
 
 
412
 
                        if ((hostent = hostentdup(hostent)) == NULL) {
413
 
                                swarnx("%s: hostentdup()", function);
414
 
                                return 0;
415
 
                        }
416
 
 
417
 
                        nexthost = hostent->h_name;
418
 
                        i = 0;
419
 
                        do {
420
 
                                int ii;
421
 
                                struct hostent *host;
422
 
 
423
 
                                /* host; address->hostname->ipaddress */
424
 
                                if ((host = gethostbyname(nexthost)) == NULL) {
425
 
                                        slog(LOG_DEBUG, "%s: gethostbyname(%s): %s",
426
 
                                        function, nexthost, hstrerror(h_errno));
427
 
                                        continue;
428
 
                                }
429
 
 
430
 
                                if ((host = hostentdup(host)) == NULL) {
431
 
                                        swarnx("%s: hostentdup()", function);
432
 
                                        break;
433
 
                                }
434
 
 
435
 
                                /* LINTED pointer casts may be troublesome */
436
 
                                for (ii = 0;
437
 
                                host->h_addr_list != NULL && host->h_addr_list[ii] != NULL;
438
 
                                ++ii) {
439
 
                                        struct hostent *ip;
440
 
 
441
 
                                        /* ip; address->hostname->ipaddress->hostname */
442
 
                                        if ((ip = gethostbyaddr(host->h_addr_list[ii],
443
 
                                        sizeof(struct in_addr), AF_INET)) == NULL) {
444
 
                                                /* LINTED pointer casts may be troublesome */
445
 
                                                slog(LOG_DEBUG, "%s: gethostbyaddr(%s): %s",
446
 
                                                function, inet_ntoa(*(struct in_addr *)host->h_addr_list[ii]),
447
 
                                                hstrerror(h_errno));
448
 
                                                continue;
449
 
                                        }
450
 
 
451
 
                                        if (hostareeq(rule->addr.domain, ip->h_name)
452
 
                                        ||  hostisinlist(rule->addr.domain,
453
 
                                        (const char **)ip->h_aliases)) {
454
 
                                                matched = 1;
455
 
                                                break;
456
 
                                        }
457
 
                                }
458
 
 
459
 
                                hostentfree(host);
460
 
                        } while (!matched && hostent->h_aliases != NULL
461
 
                        && (nexthost = hostent->h_aliases[i++]) != NULL);
462
 
 
463
 
                        hostentfree(hostent);
464
 
                }
465
 
                if (!matched)
466
 
                        return 0;
467
 
        }
468
 
        else if (rule->atype == SOCKS_ADDR_IFNAME) {
469
 
                /*
470
 
                 * Like ipaddress, just call it for each IP address of interface.
471
 
                 *
472
 
                 * match(rule.ifname2ipaddress, address)
473
 
                 */
474
 
                 int i;
475
 
                 struct sockaddr sa;
476
 
 
477
 
                 i = 0;
478
 
                 while (!matched && ifname2sockaddr(rule->addr.ifname, i++, &sa)
479
 
                 != NULL) {
480
 
                        struct ruleaddress_t ruleaddr;
481
 
 
482
 
                        ruleaddr = *rule;       /* identical except addr field. */
483
 
                        ruleaddr.atype                                                  = SOCKS_ADDR_IPV4;
484
 
                        /* LINTED pointer casts may be troublesome */
485
 
                        ruleaddr.addr.ipv4.ip                           = TOIN(&sa)->sin_addr;
486
 
                        ruleaddr.addr.ipv4.mask.s_addr  = htonl(0xffffffff);
487
 
 
488
 
                        matched = addressmatch(&ruleaddr, address, protocol, alias);
489
 
                }
490
 
        }
491
 
        else
492
 
                SERRX(0);
493
 
 
494
 
        return matched;
495
 
}
496
 
 
497
 
static int
498
 
addrisinlist(addr, mask, list)
499
 
        const struct in_addr *addr;
500
 
        const struct in_addr *mask;
501
 
        const struct in_addr **list;
502
 
{
503
 
 
504
 
        if (list == NULL)
505
 
                return 0;
506
 
 
507
 
        while (*list != NULL)
508
 
                if (addrareeq(addr, mask, *list))
509
 
                        return 1;
510
 
                else
511
 
                        ++list;
512
 
        return 0;
513
 
}
514
 
 
515
 
static int
516
 
addrareeq(addr, mask, against)
517
 
        const struct in_addr *addr;
518
 
        const struct in_addr *mask;
519
 
        const struct in_addr *against;
520
 
{
521
 
 
522
 
        if ((addr->s_addr & mask->s_addr) == (against->s_addr & mask->s_addr))
523
 
                return 1;
524
 
        return 0;
525
 
}
526
 
 
527
 
static int
528
 
hostisinlist(host, list)
529
 
        const char *host;
530
 
        const char **list;
531
 
{
532
 
 
533
 
        if (list == NULL)
534
 
                return 0;
535
 
 
536
 
        while (*list != NULL)
537
 
                if (hostareeq(host, *list))
538
 
                        return 1;
539
 
                else
540
 
                        ++list;
541
 
        return 0;
542
 
}
543
 
 
544
 
static int
545
 
hostareeq(domain, remotedomain)
546
 
        const char *domain;
547
 
        const char *remotedomain;
548
 
{
549
 
        const int domainlen = strlen(domain);
550
 
        const int remotedomainlen = strlen(remotedomain);
551
 
 
552
 
        if      (*domain == '.')        { /* match everything ending in domain */
553
 
                if (domainlen - 1 > remotedomainlen)
554
 
                        return 0;       /* address to compare against too short, can't match. */
555
 
                return strcasecmp(domain + 1,
556
 
                remotedomain + (remotedomainlen - (domainlen - 1))) == 0;
557
 
        }
558
 
        else /* need exact match. */
559
 
                return strcasecmp(domain, remotedomain) == 0;
560
 
}