[BACK]Return to hosts_access.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libwrap

Annotation of src/lib/libwrap/hosts_access.c, Revision 1.19.10.2

1.19.10.2! riz         1: /*     $NetBSD: hosts_access.c,v 1.19.10.1 2012/04/23 16:48:53 riz Exp $       */
1.2       christos    2:
1.1       mrg         3:  /*
                      4:   * This module implements a simple access control language that is based on
                      5:   * host (or domain) names, NIS (host) netgroup names, IP addresses (or
                      6:   * network numbers) and daemon process names. When a match is found the
                      7:   * search is terminated, and depending on whether PROCESS_OPTIONS is defined,
                      8:   * a list of options is executed or an optional shell command is executed.
1.8       simonb      9:   *
1.1       mrg        10:   * Host and user names are looked up on demand, provided that suitable endpoint
                     11:   * information is available as sockaddr_in structures or TLI netbufs. As a
                     12:   * side effect, the pattern matching process may change the contents of
                     13:   * request structure fields.
1.8       simonb     14:   *
1.1       mrg        15:   * Diagnostics are reported through syslog(3).
1.8       simonb     16:   *
1.1       mrg        17:   * Compile with -DNETGROUP if your library provides support for netgroups.
1.8       simonb     18:   *
1.1       mrg        19:   * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
                     20:   */
                     21:
1.2       christos   22: #include <sys/cdefs.h>
1.1       mrg        23: #ifndef lint
1.2       christos   24: #if 0
1.9       itojun     25: static char sccsid[] = "@(#) hosts_access.c 1.21 97/02/12 02:13:22";
1.2       christos   26: #else
1.19.10.2! riz        27: __RCSID("$NetBSD: hosts_access.c,v 1.19.10.1 2012/04/23 16:48:53 riz Exp $");
1.2       christos   28: #endif
1.1       mrg        29: #endif
                     30:
                     31: /* System libraries. */
                     32:
                     33: #include <sys/types.h>
                     34: #include <sys/param.h>
1.10      itojun     35: #ifdef INET6
                     36: #include <sys/socket.h>
                     37: #endif
1.1       mrg        38: #include <netinet/in.h>
                     39: #include <arpa/inet.h>
                     40: #include <stdio.h>
1.4       christos   41: #include <stdlib.h>
1.1       mrg        42: #include <syslog.h>
                     43: #include <ctype.h>
                     44: #include <errno.h>
                     45: #include <setjmp.h>
                     46: #include <string.h>
1.4       christos   47: #include <netdb.h>
1.3       christos   48: #ifdef  NETGROUP
                     49: #include <netgroup.h>
                     50: #include <rpcsvc/ypclnt.h>
1.1       mrg        51: #endif
                     52:
                     53: /* Local stuff. */
                     54:
                     55: #include "tcpd.h"
                     56:
                     57: /* Error handling. */
                     58:
                     59: extern jmp_buf tcpd_buf;
                     60:
                     61: /* Delimiters for lists of daemons or clients. */
                     62:
                     63: static char sep[] = ", \t\r\n";
                     64:
                     65: /* Constants to be used in assignments only, not in comparisons... */
                     66:
                     67: #define        YES             1
                     68: #define        NO              0
                     69:
                     70:  /*
                     71:   * These variables are globally visible so that they can be redirected in
                     72:   * verification mode.
                     73:   */
                     74:
1.19.10.2! riz        75: char   *hosts_allow_table = HOSTS_ALLOW;
        !            76: char   *hosts_deny_table = HOSTS_DENY;
1.1       mrg        77: int     hosts_access_verbose = 0;
                     78:
                     79:  /*
                     80:   * In a long-running process, we are not at liberty to just go away.
                     81:   */
                     82:
                     83: int     resident = (-1);               /* -1, 0: unknown; +1: yes */
                     84:
                     85: /* Forward declarations. */
                     86:
1.19.10.2! riz        87: static int table_match __P((char *, struct request_info *));
        !            88: static int list_match __P((char *, struct request_info *,
        !            89:     int (*)(char *, struct request_info *)));
        !            90: static int server_match __P((char *, struct request_info *));
        !            91: static int client_match __P((char *, struct request_info *));
        !            92: static int host_match __P((char *, struct host_info *));
        !            93: static int hostfile_match __P((char *, struct host_info *));
        !            94: static int rbl_match __P((char *, char *));
        !            95: static int string_match __P((char *, char *));
        !            96: static int masked_match __P((char *, char *, char *));
        !            97: static int masked_match4 __P((char *, char *, char *));
1.10      itojun     98: #ifdef INET6
1.19.10.2! riz        99: static int masked_match6 __P((char *, char *, char *));
1.10      itojun    100: #endif
1.1       mrg       101:
                    102: /* Size of logical line buffer. */
                    103:
                    104: #define        BUFLEN 2048
                    105:
                    106: /* hosts_access - host access control facility */
                    107:
1.19.10.2! riz       108: int     hosts_access(request)
        !           109: struct request_info *request;
1.1       mrg       110: {
                    111:     int     verdict;
                    112:
                    113:     /*
                    114:      * If the (daemon, client) pair is matched by an entry in the file
                    115:      * /etc/hosts.allow, access is granted. Otherwise, if the (daemon,
                    116:      * client) pair is matched by an entry in the file /etc/hosts.deny,
                    117:      * access is denied. Otherwise, access is granted. A non-existent
                    118:      * access-control file is treated as an empty file.
1.8       simonb    119:      *
1.1       mrg       120:      * After a rule has been matched, the optional language extensions may
                    121:      * decide to grant or refuse service anyway. Or, while a rule is being
                    122:      * processed, a serious error is found, and it seems better to play safe
                    123:      * and deny service. All this is done by jumping back into the
                    124:      * hosts_access() routine, bypassing the regular return from the
                    125:      * table_match() function calls below.
                    126:      */
                    127:
                    128:     if (resident <= 0)
                    129:        resident++;
1.9       itojun    130:     verdict = setjmp(tcpd_buf);
                    131:     if (verdict != 0)
1.1       mrg       132:        return (verdict == AC_PERMIT);
                    133:     if (table_match(hosts_allow_table, request))
                    134:        return (YES);
                    135:     if (table_match(hosts_deny_table, request))
                    136:        return (NO);
                    137:     return (YES);
                    138: }
                    139:
                    140: /* table_match - match table entries with (daemon, client) pair */
                    141:
1.19.10.2! riz       142: static int table_match(table, request)
        !           143: char   *table;
        !           144: struct request_info *request;
1.1       mrg       145: {
                    146:     FILE   *fp;
                    147:     char    sv_list[BUFLEN];           /* becomes list of daemons */
                    148:     char   *cl_list;                   /* becomes list of clients */
1.2       christos  149:     char   *sh_cmd = NULL;             /* becomes optional shell command */
1.1       mrg       150:     int     match = NO;
                    151:     struct tcpd_context saved_context;
                    152:
                    153:     saved_context = tcpd_context;              /* stupid compilers */
                    154:
                    155:     /*
                    156:      * Between the fopen() and fclose() calls, avoid jumps that may cause
                    157:      * file descriptor leaks.
                    158:      */
                    159:
                    160:     if ((fp = fopen(table, "r")) != 0) {
                    161:        tcpd_context.file = table;
                    162:        tcpd_context.line = 0;
                    163:        while (match == NO && xgets(sv_list, sizeof(sv_list), fp) != 0) {
                    164:            if (sv_list[strlen(sv_list) - 1] != '\n') {
                    165:                tcpd_warn("missing newline or line too long");
                    166:                continue;
                    167:            }
                    168:            if (sv_list[0] == '#' || sv_list[strspn(sv_list, " \t\r\n")] == 0)
                    169:                continue;
                    170:            if ((cl_list = split_at(sv_list, ':')) == 0) {
                    171:                tcpd_warn("missing \":\" separator");
                    172:                continue;
                    173:            }
                    174:            sh_cmd = split_at(cl_list, ':');
                    175:            match = list_match(sv_list, request, server_match)
                    176:                && list_match(cl_list, request, client_match);
                    177:        }
                    178:        (void) fclose(fp);
                    179:     } else if (errno != ENOENT) {
                    180:        tcpd_warn("cannot open %s: %m", table);
                    181:     }
                    182:     if (match) {
                    183:        if (hosts_access_verbose > 1)
                    184:            syslog(LOG_DEBUG, "matched:  %s line %d",
                    185:                   tcpd_context.file, tcpd_context.line);
                    186:        if (sh_cmd) {
                    187: #ifdef PROCESS_OPTIONS
                    188:            process_options(sh_cmd, request);
                    189: #else
                    190:            char    cmd[BUFSIZ];
                    191:            shell_cmd(percent_x(cmd, sizeof(cmd), sh_cmd, request));
                    192: #endif
                    193:        }
                    194:     }
                    195:     tcpd_context = saved_context;
                    196:     return (match);
                    197: }
                    198:
                    199: /* list_match - match a request against a list of patterns with exceptions */
                    200:
1.19.10.2! riz       201: static int list_match(list, request, match_fn)
        !           202: char   *list;
        !           203: struct request_info *request;
        !           204: int   (*match_fn) __P((char *, struct request_info *));
1.1       mrg       205: {
1.17      lukem     206:     char   *tok;
                    207:     static char *last;
1.10      itojun    208:     int l;
1.1       mrg       209:
                    210:     /*
                    211:      * Process tokens one at a time. We have exhausted all possible matches
                    212:      * when we reach an "EXCEPT" token or the end of the list. If we do find
                    213:      * a match, look for an "EXCEPT" list and recurse to determine whether
                    214:      * the match is affected by any exceptions.
                    215:      */
                    216:
1.16      itojun    217:     for (tok = strtok_r(list, sep, &last); tok != 0;
                    218:       tok = strtok_r(NULL, sep, &last)) {
1.1       mrg       219:        if (STR_EQ(tok, "EXCEPT"))              /* EXCEPT: give up */
                    220:            return (NO);
1.10      itojun    221:        l = strlen(tok);
                    222:        if (*tok == '[' && tok[l - 1] == ']') {
                    223:            tok[l - 1] = '\0';
                    224:            tok++;
                    225:        }
1.1       mrg       226:        if (match_fn(tok, request)) {           /* YES: look for exceptions */
1.16      itojun    227:            while ((tok = strtok_r(NULL, sep, &last)) && STR_NE(tok, "EXCEPT"))
1.1       mrg       228:                 /* VOID */ ;
1.16      itojun    229:            return (tok == 0 || list_match(NULL, request, match_fn) == 0);
1.1       mrg       230:        }
                    231:     }
                    232:     return (NO);
                    233: }
                    234:
                    235: /* server_match - match server information */
                    236:
1.19.10.2! riz       237: static int server_match(tok, request)
        !           238: char   *tok;
        !           239: struct request_info *request;
1.1       mrg       240: {
                    241:     char   *host;
                    242:
                    243:     if ((host = split_at(tok + 1, '@')) == 0) {        /* plain daemon */
                    244:        return (string_match(tok, eval_daemon(request)));
                    245:     } else {                                   /* daemon@host */
                    246:        return (string_match(tok, eval_daemon(request))
                    247:                && host_match(host, request->server));
                    248:     }
                    249: }
                    250:
                    251: /* client_match - match client information */
                    252:
1.19.10.2! riz       253: static int client_match(tok, request)
        !           254: char   *tok;
        !           255: struct request_info *request;
1.1       mrg       256: {
                    257:     char   *host;
                    258:
                    259:     if ((host = split_at(tok + 1, '@')) == 0) {        /* plain host */
                    260:        return (host_match(tok, request->client));
                    261:     } else {                                   /* user@host */
                    262:        return (host_match(host, request->client)
                    263:                && string_match(tok, eval_user(request)));
                    264:     }
                    265: }
                    266:
                    267: /* host_match - match host name and/or address against pattern */
                    268:
1.19.10.2! riz       269: static int host_match(tok, host)
        !           270: char   *tok;
        !           271: struct host_info *host;
1.1       mrg       272: {
                    273:     char   *mask;
                    274:
                    275:     /*
                    276:      * This code looks a little hairy because we want to avoid unnecessary
                    277:      * hostname lookups.
1.8       simonb    278:      *
1.1       mrg       279:      * The KNOWN pattern requires that both address AND name be known; some
                    280:      * patterns are specific to host names or to host addresses; all other
                    281:      * patterns are satisfied when either the address OR the name match.
                    282:      */
                    283:
                    284:     if (tok[0] == '@') {                       /* netgroup: look it up */
                    285: #ifdef  NETGROUP
                    286:        static char *mydomain = 0;
                    287:        if (mydomain == 0)
                    288:            yp_get_default_domain(&mydomain);
1.16      itojun    289:        return (innetgr(tok + 1, eval_hostname(host), NULL, mydomain));
1.1       mrg       290: #else
                    291:        tcpd_warn("netgroup support is disabled");      /* not tcpd_jump() */
                    292:        return (NO);
                    293: #endif
1.19      christos  294:     } else if (tok[0] == '/') {                        /* /file hack */
                    295:        return (hostfile_match(tok, host));
1.1       mrg       296:     } else if (STR_EQ(tok, "KNOWN")) {         /* check address and name */
                    297:        char   *name = eval_hostname(host);
                    298:        return (STR_NE(eval_hostaddr(host), unknown) && HOSTNAME_KNOWN(name));
                    299:     } else if (STR_EQ(tok, "LOCAL")) {         /* local: no dots in name */
                    300:        char   *name = eval_hostname(host);
                    301:        return (strchr(name, '.') == 0 && HOSTNAME_KNOWN(name));
1.4       christos  302:     } else if (strncmp(tok, "{RBL}.", 6) == 0) { /* RBL lookup in domain */
                    303:        return rbl_match(tok+6, eval_hostaddr(host));
1.1       mrg       304:     } else if ((mask = split_at(tok, '/')) != 0) {     /* net/mask */
                    305:        return (masked_match(tok, mask, eval_hostaddr(host)));
                    306:     } else {                                   /* anything else */
                    307:        return (string_match(tok, eval_hostaddr(host))
                    308:            || (NOT_INADDR(tok) && string_match(tok, eval_hostname(host))));
                    309:     }
1.4       christos  310: }
                    311:
1.19      christos  312: /* hostfile_match - look up host patterns from file */
                    313:
1.19.10.2! riz       314: static int hostfile_match(path, host)
        !           315: char   *path;
        !           316: struct host_info *host;
1.19      christos  317: {
                    318:     char    tok[BUFSIZ];
                    319:     int     match = NO;
                    320:     FILE   *fp;
                    321:
                    322:     if ((fp = fopen(path, "r")) != 0) {
                    323:        while (fscanf(fp, "%s", tok) == 1 && !(match = host_match(tok, host)))
                    324:             /* void */ ;
                    325:        fclose(fp);
                    326:     } else if (errno != ENOENT) {
                    327:        tcpd_warn("open %s: %m", path);
                    328:     }
                    329:     return (match);
                    330: }
                    331:
1.4       christos  332: /* rbl_match() - match host by looking up in RBL domain */
                    333:
1.19.10.2! riz       334: static int rbl_match(rbl_domain, rbl_hostaddr)
        !           335: char   *rbl_domain;                            /* RBL domain */
        !           336: char   *rbl_hostaddr;                          /* hostaddr */
1.4       christos  337: {
                    338:     char *rbl_name;
                    339:     unsigned long host_address;
                    340:     int ret = NO;
1.5       christos  341:     size_t len = strlen(rbl_domain) + (4 * 4) + 2;
1.8       simonb    342:
1.6       christos  343:     if (dot_quad_addr(rbl_hostaddr, &host_address) != 0) {
1.4       christos  344:        tcpd_warn("unable to convert %s to address", rbl_hostaddr);
                    345:        return (NO);
                    346:     }
1.18      jdc       347:     host_address = ntohl(host_address);
1.4       christos  348:     /*  construct the rbl name to look up */
1.5       christos  349:     if ((rbl_name = malloc(len)) == NULL) {
1.4       christos  350:        tcpd_jump("not enough memory to build RBL name for %s in %s", rbl_hostaddr, rbl_domain);
                    351:        /* NOTREACHED */
                    352:     }
1.5       christos  353:     snprintf(rbl_name, len, "%u.%u.%u.%u.%s",
1.4       christos  354:            (unsigned int) ((host_address) & 0xff),
                    355:            (unsigned int) ((host_address >> 8) & 0xff),
                    356:            (unsigned int) ((host_address >> 16) & 0xff),
                    357:            (unsigned int) ((host_address >> 24) & 0xff),
                    358:            rbl_domain);
                    359:     /* look it up */
                    360:     if (gethostbyname(rbl_name) != NULL) {
                    361:        /* successful lookup - they're on the RBL list */
                    362:        ret = YES;
                    363:     }
                    364:     free(rbl_name);
                    365:
                    366:     return ret;
1.1       mrg       367: }
                    368:
                    369: /* string_match - match string against pattern */
                    370:
1.19.10.2! riz       371: static int string_match(tok, string)
        !           372: char   *tok;
        !           373: char   *string;
1.1       mrg       374: {
                    375:     int     n;
                    376:
                    377:     if (tok[0] == '.') {                       /* suffix */
                    378:        n = strlen(string) - strlen(tok);
                    379:        return (n > 0 && STR_EQ(tok, string + n));
                    380:     } else if (STR_EQ(tok, "ALL")) {           /* all: match any */
                    381:        return (YES);
                    382:     } else if (STR_EQ(tok, "KNOWN")) {         /* not unknown */
                    383:        return (STR_NE(string, unknown));
                    384:     } else if (tok[(n = strlen(tok)) - 1] == '.') {    /* prefix */
                    385:        return (STRN_EQ(tok, string, n));
                    386:     } else {                                   /* exact match */
                    387:        return (STR_EQ(tok, string));
                    388:     }
                    389: }
                    390:
                    391: /* masked_match - match address against netnumber/netmask */
                    392:
1.19.10.2! riz       393: static int masked_match(net_tok, mask_tok, string)
        !           394: char   *net_tok;
        !           395: char   *mask_tok;
        !           396: char   *string;
1.1       mrg       397: {
1.10      itojun    398: #ifndef INET6
                    399:     return masked_match4(net_tok, mask_tok, string);
                    400: #else
1.15      itojun    401:     /*
                    402:      * masked_match4() is kept just for supporting shortened IPv4 address form.
                    403:      * If we could get rid of shortened IPv4 form, we could just always use
                    404:      * masked_match6().
                    405:      */
1.19.10.2! riz       406:     if (dot_quad_addr(net_tok, NULL) != INADDR_NONE &&
        !           407:         dot_quad_addr(mask_tok, NULL) != INADDR_NONE &&
        !           408:         dot_quad_addr(string, NULL) != INADDR_NONE) {
1.10      itojun    409:        return masked_match4(net_tok, mask_tok, string);
                    410:     } else
                    411:        return masked_match6(net_tok, mask_tok, string);
                    412: #endif
                    413: }
                    414:
1.19.10.2! riz       415: static int masked_match4(net_tok, mask_tok, string)
        !           416: char   *net_tok;
        !           417: char   *mask_tok;
        !           418: char   *string;
1.10      itojun    419: {
1.1       mrg       420:     unsigned long net;
                    421:     unsigned long mask;
                    422:     unsigned long addr;
                    423:
                    424:     /*
                    425:      * Disallow forms other than dotted quad: the treatment that inet_addr()
                    426:      * gives to forms with less than four components is inconsistent with the
                    427:      * access control language. John P. Rouillard <rouilj@cs.umb.edu>.
                    428:      */
                    429:
1.6       christos  430:     if (dot_quad_addr(string, &addr) != 0)
1.1       mrg       431:        return (NO);
1.15      itojun    432:     if (dot_quad_addr(net_tok, &net) != 0 ||
                    433:         dot_quad_addr(mask_tok, &mask) != 0) {
1.1       mrg       434:        tcpd_warn("bad net/mask expression: %s/%s", net_tok, mask_tok);
                    435:        return (NO);                            /* not tcpd_jump() */
                    436:     }
1.12      atatat    437:
                    438:     if ((net & ~mask) != 0)
                    439:        tcpd_warn("host bits not all zero in %s/%s", net_tok, mask_tok);
                    440:
1.1       mrg       441:     return ((addr & mask) == net);
                    442: }
1.10      itojun    443:
                    444: #ifdef INET6
1.19.10.2! riz       445: static int masked_match6(net_tok, mask_tok, string)
        !           446: char   *net_tok;
        !           447: char   *mask_tok;
        !           448: char   *string;
1.10      itojun    449: {
1.15      itojun    450:     union {
                    451:        struct sockaddr sa;
                    452:        struct sockaddr_in sin;
                    453:        struct sockaddr_in6 sin6;
                    454:     } net, mask, addr;
                    455:     struct addrinfo hints, *res;
                    456:     unsigned long masklen;
                    457:     char *ep;
1.19.10.2! riz       458:     int i;
1.15      itojun    459:     char *np, *mp, *ap;
1.19.10.2! riz       460:     int alen;
1.10      itojun    461:
1.15      itojun    462:     memset(&hints, 0, sizeof(hints));
                    463:     hints.ai_family = PF_UNSPEC;
                    464:     hints.ai_socktype = SOCK_DGRAM;    /*dummy*/
                    465:     hints.ai_flags = AI_NUMERICHOST;
                    466:     if (getaddrinfo(net_tok, "0", &hints, &res) == 0) {
                    467:        if (res->ai_addrlen > sizeof(net) || res->ai_next) {
                    468:            freeaddrinfo(res);
                    469:            return NO;
                    470:        }
                    471:        memcpy(&net, res->ai_addr, res->ai_addrlen);
                    472:        freeaddrinfo(res);
1.10      itojun    473:     } else
                    474:        return NO;
                    475:
1.15      itojun    476:     memset(&hints, 0, sizeof(hints));
                    477:     hints.ai_family = net.sa.sa_family;
                    478:     hints.ai_socktype = SOCK_DGRAM;    /*dummy*/
                    479:     hints.ai_flags = AI_NUMERICHOST;
                    480:     ep = NULL;
                    481:     if (getaddrinfo(mask_tok, "0", &hints, &res) == 0) {
                    482:        if (res->ai_family == AF_INET6 &&
                    483:            ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id) {
                    484:            freeaddrinfo(res);
                    485:            return NO;
                    486:        }
                    487:        if (res->ai_addrlen > sizeof(mask) || res->ai_next) {
                    488:            freeaddrinfo(res);
                    489:            return NO;
                    490:        }
                    491:        memcpy(&mask, res->ai_addr, res->ai_addrlen);
                    492:        freeaddrinfo(res);
                    493:     } else {
                    494:        ep = NULL;
                    495:        masklen = strtoul(mask_tok, &ep, 10);
                    496:        if (ep && !*ep) {
1.10      itojun    497:            memset(&mask, 0, sizeof(mask));
1.15      itojun    498:            mask.sa.sa_family = net.sa.sa_family;
                    499:            mask.sa.sa_len = net.sa.sa_len;
                    500:            switch (mask.sa.sa_family) {
                    501:            case AF_INET:
                    502:                mp = (char *)&mask.sin.sin_addr;
                    503:                alen = sizeof(mask.sin.sin_addr);
                    504:                break;
                    505:            case AF_INET6:
                    506:                mp = (char *)&mask.sin6.sin6_addr;
                    507:                alen = sizeof(mask.sin6.sin6_addr);
                    508:                break;
                    509:            default:
                    510:                return NO;
1.10      itojun    511:            }
1.15      itojun    512:            if (masklen / 8 > alen)
                    513:                return NO;
                    514:            memset(mp, 0xff, masklen / 8);
                    515:            if (masklen % 8)
                    516:                mp[masklen / 8] = 0xff00 >> (masklen % 8);
1.10      itojun    517:        } else
1.15      itojun    518:            return NO;
                    519:     }
                    520:
                    521:     memset(&hints, 0, sizeof(hints));
                    522:     hints.ai_family = PF_UNSPEC;
                    523:     hints.ai_socktype = SOCK_DGRAM;    /*dummy*/
                    524:     hints.ai_flags = AI_NUMERICHOST;
                    525:     if (getaddrinfo(string, "0", &hints, &res) == 0) {
                    526:        if (res->ai_addrlen > sizeof(addr) || res->ai_next) {
                    527:            freeaddrinfo(res);
                    528:            return NO;
                    529:        }
                    530:        /* special case - IPv4 mapped address */
                    531:        if (net.sa.sa_family == AF_INET && res->ai_family == AF_INET6 &&
                    532:            IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr)) {
                    533:            memset(&addr, 0, sizeof(addr));
                    534:            addr.sa.sa_family = net.sa.sa_family;
                    535:            addr.sa.sa_len = net.sa.sa_len;
                    536:            memcpy(&addr.sin.sin_addr,
                    537:                &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr.s6_addr[12],
                    538:                sizeof(addr.sin.sin_addr));
                    539:        } else
                    540:            memcpy(&addr, res->ai_addr, res->ai_addrlen);
                    541:        freeaddrinfo(res);
1.10      itojun    542:     } else
1.15      itojun    543:        return NO;
                    544:
                    545:     if (net.sa.sa_family != mask.sa.sa_family ||
                    546:         net.sa.sa_family != addr.sa.sa_family) {
                    547:        return NO;
                    548:     }
                    549:
                    550:     switch (net.sa.sa_family) {
                    551:     case AF_INET:
                    552:        np = (char *)&net.sin.sin_addr;
                    553:        mp = (char *)&mask.sin.sin_addr;
                    554:        ap = (char *)&addr.sin.sin_addr;
                    555:        alen = sizeof(net.sin.sin_addr);
                    556:        break;
                    557:     case AF_INET6:
                    558:        np = (char *)&net.sin6.sin6_addr;
                    559:        mp = (char *)&mask.sin6.sin6_addr;
                    560:        ap = (char *)&addr.sin6.sin6_addr;
                    561:        alen = sizeof(net.sin6.sin6_addr);
                    562:        break;
                    563:     default:
                    564:        return NO;
1.10      itojun    565:     }
                    566:
1.15      itojun    567:     for (i = 0; i < alen; i++)
                    568:        if (np[i] & ~mp[i]) {
                    569:            tcpd_warn("host bits not all zero in %s/%s", net_tok, mask_tok);
                    570:            break;
                    571:        }
1.12      atatat    572:
1.15      itojun    573:     for (i = 0; i < alen; i++)
                    574:        ap[i] &= mp[i];
1.12      atatat    575:
1.15      itojun    576:     if (addr.sa.sa_family == AF_INET6 && addr.sin6.sin6_scope_id &&
                    577:         addr.sin6.sin6_scope_id != net.sin6.sin6_scope_id)
                    578:        return NO;
                    579:     return (memcmp(ap, np, alen) == 0);
1.10      itojun    580: }
                    581: #endif

CVSweb <webmaster@jp.NetBSD.org>