diff options
Diffstat (limited to 'sbin/pfctl/pfctl_parser.c')
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 644 |
1 files changed, 352 insertions, 292 deletions
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 936c5ec53759..b8531067d3f6 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -33,18 +33,19 @@ * */ -#include <sys/cdefs.h> #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/param.h> #include <sys/proc.h> +#include <net/if_dl.h> #include <net/if.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <netinet/icmp6.h> +#include <netinet/tcp.h> #include <net/pfvar.h> #include <arpa/inet.h> @@ -59,6 +60,7 @@ #include <errno.h> #include <err.h> #include <ifaddrs.h> +#include <inttypes.h> #include <unistd.h> #include "pfctl_parser.h" @@ -66,18 +68,17 @@ void print_op (u_int8_t, const char *, const char *); void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int); -void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); -void print_flags (u_int8_t); +void print_ugid (u_int8_t, id_t, id_t, const char *); +void print_flags (uint16_t); void print_fromto(struct pf_rule_addr *, pf_osfp_t, struct pf_rule_addr *, sa_family_t, u_int8_t, int, int); int ifa_skip_if(const char *filter, struct node_host *p); -struct node_host *host_if(const char *, int, int *); -struct node_host *host_v4(const char *, int); -struct node_host *host_v6(const char *, int); +struct node_host *host_if(const char *, int); +struct node_host *host_ip(const char *, int); struct node_host *host_dns(const char *, int, int); -const char * const tcpflags = "FSRPAUEW"; +const char * const tcpflags = "FSRPAUEWe"; static const struct icmptypeent icmp_type[] = { { "echoreq", ICMP_ECHO }, @@ -133,7 +134,8 @@ static const struct icmptypeent icmp6_type[] = { { "niqry", ICMP6_NI_QUERY }, { "nirep", ICMP6_NI_REPLY }, { "mtraceresp", MLD_MTRACE_RESP }, - { "mtrace", MLD_MTRACE } + { "mtrace", MLD_MTRACE }, + { "listenrepv2", MLDV2_LISTENER_REPORT }, }; static const struct icmpcodeent icmp_code[] = { @@ -192,6 +194,11 @@ const struct pf_timeout pf_timeouts[] = { { "tcp.finwait", PFTM_TCP_FIN_WAIT }, { "tcp.closed", PFTM_TCP_CLOSED }, { "tcp.tsdiff", PFTM_TS_DIFF }, + { "sctp.first", PFTM_SCTP_FIRST_PACKET }, + { "sctp.opening", PFTM_SCTP_OPENING }, + { "sctp.established", PFTM_SCTP_ESTABLISHED }, + { "sctp.closing", PFTM_SCTP_CLOSING }, + { "sctp.closed", PFTM_SCTP_CLOSED }, { "udp.first", PFTM_UDP_FIRST_PACKET }, { "udp.single", PFTM_UDP_SINGLE }, { "udp.multiple", PFTM_UDP_MULTIPLE }, @@ -221,10 +228,21 @@ pfctl_parser_init(void) err(1, "Failed to create interface group query response map"); } +void +copy_satopfaddr(struct pf_addr *pfa, struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET6) + pfa->v6 = ((struct sockaddr_in6 *)sa)->sin6_addr; + else if (sa->sa_family == AF_INET) + pfa->v4 = ((struct sockaddr_in *)sa)->sin_addr; + else + warnx("unhandled af %d", sa->sa_family); +} + const struct icmptypeent * geticmptypebynumber(u_int8_t type, sa_family_t af) { - unsigned int i; + size_t i; if (af != AF_INET6) { for (i=0; i < nitems(icmp_type); i++) { @@ -243,7 +261,7 @@ geticmptypebynumber(u_int8_t type, sa_family_t af) const struct icmptypeent * geticmptypebyname(char *w, sa_family_t af) { - unsigned int i; + size_t i; if (af != AF_INET6) { for (i=0; i < nitems(icmp_type); i++) { @@ -262,7 +280,7 @@ geticmptypebyname(char *w, sa_family_t af) const struct icmpcodeent * geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af) { - unsigned int i; + size_t i; if (af != AF_INET6) { for (i=0; i < nitems(icmp_code); i++) { @@ -283,7 +301,7 @@ geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af) const struct icmpcodeent * geticmpcodebyname(u_long type, char *w, sa_family_t af) { - unsigned int i; + size_t i; if (af != AF_INET6) { for (i=0; i < nitems(icmp_code); i++) { @@ -346,21 +364,21 @@ print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numer } void -print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax) +print_ugid(u_int8_t op, id_t i1, id_t i2, const char *t) { char a1[11], a2[11]; - snprintf(a1, sizeof(a1), "%u", u1); - snprintf(a2, sizeof(a2), "%u", u2); + snprintf(a1, sizeof(a1), "%ju", (uintmax_t)i1); + snprintf(a2, sizeof(a2), "%ju", (uintmax_t)i2); printf(" %s", t); - if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) + if (i1 == -1 && (op == PF_OP_EQ || op == PF_OP_NE)) print_op(op, "unknown", a2); else print_op(op, a1, a2); } void -print_flags(u_int8_t f) +print_flags(uint16_t f) { int i; @@ -371,9 +389,11 @@ print_flags(u_int8_t f) void print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst, - sa_family_t af, u_int8_t proto, int verbose, int numeric) + sa_family_t af, u_int8_t proto, int opts, int numeric) { char buf[PF_OSFP_LEN*3]; + int verbose = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); + if (src->addr.type == PF_ADDR_ADDRMASK && dst->addr.type == PF_ADDR_ADDRMASK && PF_AZERO(&src->addr.v.a.addr, AF_INET6) && @@ -411,10 +431,9 @@ print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst, } void -print_pool(struct pfctl_pool *pool, u_int16_t p1, u_int16_t p2, - sa_family_t af, int id) +print_pool(struct pfctl_pool *pool, u_int16_t p1, u_int16_t p2, int id) { - struct pf_pooladdr *pooladdr; + struct pfctl_pooladdr *pooladdr; if ((TAILQ_FIRST(&pool->list) != NULL) && TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) @@ -424,15 +443,15 @@ print_pool(struct pfctl_pool *pool, u_int16_t p1, u_int16_t p2, case PF_NAT: case PF_RDR: case PF_BINAT: - print_addr(&pooladdr->addr, af, 0); + print_addr(&pooladdr->addr, pooladdr->af, 0); break; case PF_PASS: case PF_MATCH: - if (PF_AZERO(&pooladdr->addr.v.a.addr, af)) + if (PF_AZERO(&pooladdr->addr.v.a.addr, pooladdr->af)) printf("%s", pooladdr->ifname); else { printf("(%s ", pooladdr->ifname); - print_addr(&pooladdr->addr, af, 0); + print_addr(&pooladdr->addr, pooladdr->af, 0); printf(")"); } break; @@ -484,18 +503,17 @@ print_pool(struct pfctl_pool *pool, u_int16_t p1, u_int16_t p2, } if (pool->opts & PF_POOL_STICKYADDR) printf(" sticky-address"); + if (pool->opts & PF_POOL_ENDPI) + printf(" endpoint-independent"); if (id == PF_NAT && p1 == 0 && p2 == 0) printf(" static-port"); if (pool->mape.offset > 0) printf(" map-e-portset %u/%u/%u", pool->mape.offset, pool->mape.psidlen, pool->mape.psid); + if (pool->opts & PF_POOL_IPV6NH) + printf(" prefer-ipv6-nexthop"); } -const char * const pf_reasons[PFRES_MAX+1] = PFRES_NAMES; -const char * const pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; -const char * const pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; -const char * const pf_scounters[FCNT_MAX+1] = FCNT_NAMES; - void print_status(struct pfctl_status *s, struct pfctl_syncookies *cookies, int opts) { @@ -510,7 +528,8 @@ print_status(struct pfctl_status *s, struct pfctl_syncookies *cookies, int opts) running = s->running ? "Enabled" : "Disabled"; if (s->since) { - unsigned int sec, min, hrs, day = runtime; + unsigned int sec, min, hrs; + time_t day = runtime; sec = day % 60; day /= 60; @@ -519,8 +538,8 @@ print_status(struct pfctl_status *s, struct pfctl_syncookies *cookies, int opts) hrs = day % 24; day /= 24; snprintf(statline, sizeof(statline), - "Status: %s for %u days %.2u:%.2u:%.2u", - running, day, hrs, min, sec); + "Status: %s for %lld days %.2u:%.2u:%.2u", + running, (long long)day, hrs, min, sec); } else snprintf(statline, sizeof(statline), "Status: %s", running); printf("%-44s", statline); @@ -597,6 +616,20 @@ print_status(struct pfctl_status *s, struct pfctl_syncookies *cookies, int opts) printf("%14s\n", ""); } } + if (opts & PF_OPT_VERBOSE) { + printf("Fragments\n"); + printf(" %-25s %14ju %14s\n", "current entries", + s->fragments, ""); + TAILQ_FOREACH(c, &s->ncounters, entry) { + printf(" %-25s %14ju ", c->name, + c->counter); + if (runtime > 0) + printf("%14.1f/s\n", + (double)c->counter / (double)runtime); + else + printf("%14s\n", ""); + } + } printf("Counters\n"); TAILQ_FOREACH(c, &s->counters, entry) { printf(" %-25s %14ju ", c->name, c->counter); @@ -623,6 +656,11 @@ print_status(struct pfctl_status *s, struct pfctl_syncookies *cookies, int opts) PFCTL_SYNCOOKIES_MODE_NAMES[cookies->mode]); printf(" %-25s %s\n", "active", s->syncookies_active ? "active" : "inactive"); + if (opts & PF_OPT_VERBOSE2) { + printf(" %-25s %d %%\n", "highwater", cookies->highwater); + printf(" %-25s %d %%\n", "lowwater", cookies->lowwater); + printf(" %-25s %d\n", "halfopen states", cookies->halfopen_states); + } printf("Reassemble %24s %s\n", s->reass & PF_REASS_ENABLED ? "yes" : "no", s->reass & PF_REASS_NODF ? "no-df" : "" @@ -637,10 +675,11 @@ print_running(struct pfctl_status *status) } void -print_src_node(struct pf_src_node *sn, int opts) +print_src_node(struct pfctl_src_node *sn, int opts) { struct pf_addr_wrap aw; - int min, sec; + uint64_t min, sec; + const char *sn_type_names[] = PF_SN_TYPE_NAMES; memset(&aw, 0, sizeof(aw)); if (sn->af == AF_INET) @@ -652,7 +691,7 @@ print_src_node(struct pf_src_node *sn, int opts) print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); printf(" -> "); aw.v.a.addr = sn->raddr; - print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); + print_addr(&aw, sn->raf, opts & PF_OPT_VERBOSE2); printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states, sn->conn, sn->conn_rate.count / 1000, (sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds); @@ -661,38 +700,35 @@ print_src_node(struct pf_src_node *sn, int opts) sn->creation /= 60; min = sn->creation % 60; sn->creation /= 60; - printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec); + printf(" age %.2" PRIu64 ":%.2" PRIu64 ":%.2" PRIu64, + sn->creation, min, sec); if (sn->states == 0) { sec = sn->expire % 60; sn->expire /= 60; min = sn->expire % 60; sn->expire /= 60; - printf(", expires in %.2u:%.2u:%.2u", + printf(", expires in %.2" PRIu64 ":%.2" PRIu64 ":%.2" PRIu64, sn->expire, min, sec); } - printf(", %llu pkts, %llu bytes", -#ifdef __FreeBSD__ - (unsigned long long)(sn->packets[0] + sn->packets[1]), - (unsigned long long)(sn->bytes[0] + sn->bytes[1])); -#else + printf(", %" PRIu64 " pkts, %" PRIu64 " bytes", sn->packets[0] + sn->packets[1], sn->bytes[0] + sn->bytes[1]); -#endif switch (sn->ruletype) { case PF_NAT: - if (sn->rule.nr != -1) - printf(", nat rule %u", sn->rule.nr); + if (sn->rule != -1) + printf(", nat rule %u", sn->rule); break; case PF_RDR: - if (sn->rule.nr != -1) - printf(", rdr rule %u", sn->rule.nr); + if (sn->rule != -1) + printf(", rdr rule %u", sn->rule); break; case PF_PASS: case PF_MATCH: - if (sn->rule.nr != -1) - printf(", filter rule %u", sn->rule.nr); + if (sn->rule != -1) + printf(", filter rule %u", sn->rule); break; } + printf(", %s", sn_type_names[sn->type]); printf("\n"); } } @@ -820,34 +856,39 @@ print_eth_rule(struct pfctl_eth_rule *r, const char *anchor_call, } void -print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numeric) +print_rule(struct pfctl_rule *r, const char *anchor_call, int opts, int numeric) { static const char *actiontypes[] = { "pass", "block", "scrub", "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr", - "", "", "match"}; + "synproxy drop", "defer", "match", "af-rt", "route-to" }; static const char *anchortypes[] = { "anchor", "anchor", "anchor", "anchor", "nat-anchor", "nat-anchor", "binat-anchor", "binat-anchor", "rdr-anchor", "rdr-anchor" }; - int i, opts; + int i, ropts; + int verbose = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); char *p; + if ((r->rule_flag & PFRULE_EXPIRED) && (!verbose)) + return; + if (verbose) printf("@%d ", r->nr); - if (r->action == PF_MATCH) - printf("match"); - else if (r->action > PF_NORDR) - printf("action(%d)", r->action); - else if (anchor_call[0]) { - p = strrchr(anchor_call, '/'); - if (p ? p[1] == '_' : anchor_call[0] == '_') - printf("%s", anchortypes[r->action]); - else - printf("%s \"%s\"", anchortypes[r->action], - anchor_call); + if (anchor_call[0]) { + if (r->action >= nitems(anchortypes)) { + printf("anchor(%d)", r->action); + } else { + p = strrchr(anchor_call, '/'); + if (p ? p[1] == '_' : anchor_call[0] == '_') + printf("%s", anchortypes[r->action]); + else + printf("%s \"%s\"", anchortypes[r->action], + anchor_call); + } } else { - printf("%s", actiontypes[r->action]); - if (r->natpass) - printf(" pass"); + if (r->action >= nitems(actiontypes)) + printf("action(%d)", r->action); + else + printf("%s", actiontypes[r->action]); } if (r->action == PF_DROP) { if (r->rule_flag & PFRULE_RETURN) @@ -907,7 +948,9 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer printf(" ("); if (r->log & PF_LOG_ALL) printf("%sall", count++ ? ", " : ""); - if (r->log & PF_LOG_SOCKET_LOOKUP) + if (r->log & PF_LOG_MATCHES) + printf("%smatches", count++ ? ", " : ""); + if (r->log & PF_LOG_USER) printf("%suser", count++ ? ", " : ""); if (r->logif) printf("%sto pflog%u", count++ ? ", " : "", @@ -931,7 +974,7 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer else if (r->rt == PF_DUPTO) printf(" dup-to"); printf(" "); - print_pool(&r->rpool, 0, 0, r->af, PF_PASS); + print_pool(&r->route, 0, 0, PF_PASS); } if (r->af) { if (r->af == AF_INET) @@ -948,13 +991,14 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer printf(" proto %u", r->proto); } print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto, - verbose, numeric); + opts, numeric); + if (r->rcv_ifname[0]) + printf(" %sreceived-on %s", r->rcvifnot ? "!" : "", + r->rcv_ifname); if (r->uid.op) - print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user", - UID_MAX); + print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user"); if (r->gid.op) - print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group", - GID_MAX); + print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group"); if (r->flags || r->flagset) { printf(" flags "); print_flags(r->flags); @@ -991,6 +1035,11 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer printf(" tos 0x%2.2x", r->tos); if (r->prio) printf(" prio %u", r->prio == PF_PRIO_ZERO ? 0 : r->prio); + if (r->pktrate.limit) + printf(" max-pkt-rate %u/%u", r->pktrate.limit, + r->pktrate.seconds); + if (r->max_pkt_size) + printf( " max-pkt-size %u", r->max_pkt_size); if (r->scrub_flags & PFSTATE_SETMASK) { char *comma = ""; printf(" set ("); @@ -1031,70 +1080,72 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer } printf(" probability %s%%", buf); } - opts = 0; + ropts = 0; if (r->max_states || r->max_src_nodes || r->max_src_states) - opts = 1; + ropts = 1; if (r->rule_flag & PFRULE_NOSYNC) - opts = 1; + ropts = 1; if (r->rule_flag & PFRULE_SRCTRACK) - opts = 1; + ropts = 1; if (r->rule_flag & PFRULE_IFBOUND) - opts = 1; + ropts = 1; if (r->rule_flag & PFRULE_STATESLOPPY) - opts = 1; - for (i = 0; !opts && i < PFTM_MAX; ++i) + ropts = 1; + if (r->rule_flag & PFRULE_PFLOW) + ropts = 1; + for (i = 0; !ropts && i < PFTM_MAX; ++i) if (r->timeout[i]) - opts = 1; - if (opts) { + ropts = 1; + if (ropts) { printf(" ("); if (r->max_states) { printf("max %u", r->max_states); - opts = 0; + ropts = 0; } if (r->rule_flag & PFRULE_NOSYNC) { - if (!opts) + if (!ropts) printf(", "); printf("no-sync"); - opts = 0; + ropts = 0; } if (r->rule_flag & PFRULE_SRCTRACK) { - if (!opts) + if (!ropts) printf(", "); printf("source-track"); if (r->rule_flag & PFRULE_RULESRCTRACK) printf(" rule"); else printf(" global"); - opts = 0; + ropts = 0; } if (r->max_src_states) { - if (!opts) + if (!ropts) printf(", "); printf("max-src-states %u", r->max_src_states); - opts = 0; + ropts = 0; } if (r->max_src_conn) { - if (!opts) + if (!ropts) printf(", "); printf("max-src-conn %u", r->max_src_conn); - opts = 0; + ropts = 0; } if (r->max_src_conn_rate.limit) { - if (!opts) + if (!ropts) printf(", "); printf("max-src-conn-rate %u/%u", r->max_src_conn_rate.limit, r->max_src_conn_rate.seconds); - opts = 0; + ropts = 0; } if (r->max_src_nodes) { - if (!opts) + if (!ropts) printf(", "); printf("max-src-nodes %u", r->max_src_nodes); - opts = 0; + ropts = 0; } if (r->overload_tblname[0]) { - if (!opts) + if (!ropts) printf(", "); printf("overload <%s>", r->overload_tblname); if (r->flush) @@ -1103,24 +1154,30 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer printf(" global"); } if (r->rule_flag & PFRULE_IFBOUND) { - if (!opts) + if (!ropts) printf(", "); printf("if-bound"); - opts = 0; + ropts = 0; } if (r->rule_flag & PFRULE_STATESLOPPY) { - if (!opts) + if (!ropts) printf(", "); printf("sloppy"); - opts = 0; + ropts = 0; + } + if (r->rule_flag & PFRULE_PFLOW) { + if (!ropts) + printf(", "); + printf("pflow"); + ropts = 0; } for (i = 0; i < PFTM_MAX; ++i) if (r->timeout[i]) { int j; - if (!opts) + if (!ropts) printf(", "); - opts = 0; + ropts = 0; for (j = 0; pf_timeouts[j].name != NULL; ++j) if (pf_timeouts[j].timeout == i) @@ -1183,6 +1240,8 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer printf(" %s %d", r->free_flags & PFRULE_DN_IS_PIPE ? "dnpipe" : "dnqueue", r->dnpipe); + if (r->rule_flag & PFRULE_ONCE) + printf(" once"); if (r->qname[0] && r->pqname[0]) printf(" queue(%s, %s)", r->qname, r->pqname); else if (r->qname[0]) @@ -1203,24 +1262,44 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer if (PF_AZERO(&r->divert.addr, r->af)) { printf(" divert-reply"); } else { - /* XXX cut&paste from print_addr */ - char buf[48]; - printf(" divert-to "); - if (inet_ntop(r->af, &r->divert.addr, buf, - sizeof(buf)) == NULL) - printf("?"); - else - printf("%s", buf); + print_addr_str(r->af, &r->divert.addr); printf(" port %u", ntohs(r->divert.port)); } #endif } - if (!anchor_call[0] && (r->action == PF_NAT || - r->action == PF_BINAT || r->action == PF_RDR)) { + if (anchor_call[0]) + return; + if (r->action == PF_NAT || r->action == PF_BINAT || r->action == PF_RDR) { printf(" -> "); - print_pool(&r->rpool, r->rpool.proxy_port[0], - r->rpool.proxy_port[1], r->af, r->action); + print_pool(&r->rdr, r->rdr.proxy_port[0], + r->rdr.proxy_port[1], r->action); + } else { + if (!TAILQ_EMPTY(&r->nat.list)) { + if (r->rule_flag & PFRULE_AFTO) { + printf(" af-to %s from ", r->naf == AF_INET ? "inet" : (r->naf == AF_INET6 ? "inet6" : "? ")); + } else { + printf(" nat-to "); + } + print_pool(&r->nat, r->nat.proxy_port[0], + r->nat.proxy_port[1], PF_NAT); + } + if (!TAILQ_EMPTY(&r->rdr.list)) { + if (r->rule_flag & PFRULE_AFTO) { + printf(" to "); + } else { + printf(" rdr-to "); + } + print_pool(&r->rdr, r->rdr.proxy_port[0], + r->rdr.proxy_port[1], PF_RDR); + } + } + + if (r->rule_flag & PFRULE_EXPIRED) { + printf(" # expired"); + + if (r->exptime != 0) + printf(" %s", ctime(&r->exptime)); } } @@ -1266,7 +1345,7 @@ int parse_flags(char *s) { char *p, *q; - u_int8_t f = 0; + uint16_t f = 0; for (p = s; *p; p++) { if ((q = strchr(tcpflags, *p)) == NULL) @@ -1274,18 +1353,24 @@ parse_flags(char *s) else f |= 1 << (q - tcpflags); } - return (f ? f : PF_TH_ALL); + return (f ? f : TH_FLAGS); } void -set_ipmask(struct node_host *h, u_int8_t b) +set_ipmask(struct node_host *h, int bb) { struct pf_addr *m, *n; int i, j = 0; + uint8_t b; m = &h->addr.v.a.mask; memset(m, 0, sizeof(*m)); + if (bb == -1) + b = h->af == AF_INET ? 32 : 128; + else + b = bb; + while (b >= 32) { m->addr32[j++] = 0xffffffff; b -= 32; @@ -1306,27 +1391,45 @@ int check_netmask(struct node_host *h, sa_family_t af) { struct node_host *n = NULL; - struct pf_addr *m; + struct pf_addr *m; for (n = h; n != NULL; n = n->next) { if (h->addr.type == PF_ADDR_TABLE) continue; m = &h->addr.v.a.mask; - /* fix up netmask for dynaddr */ - if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL && - unmask(m, AF_INET6) > 32) - set_ipmask(n, 32); /* netmasks > 32 bit are invalid on v4 */ if (af == AF_INET && (m->addr32[1] || m->addr32[2] || m->addr32[3])) { fprintf(stderr, "netmask %u invalid for IPv4 address\n", - unmask(m, AF_INET6)); + unmask(m)); return (1); } } return (0); } +struct node_host * +gen_dynnode(struct node_host *h, sa_family_t af) +{ + struct node_host *n; + + if (h->addr.type != PF_ADDR_DYNIFTL) + return (NULL); + + if ((n = calloc(1, sizeof(*n))) == NULL) + return (NULL); + bcopy(h, n, sizeof(*n)); + n->ifname = NULL; + n->next = NULL; + n->tail = NULL; + + /* fix up netmask */ + if (af == AF_INET && unmask(&n->addr.v.a.mask) > 32) + set_ipmask(n, 32); + + return (n); +} + /* interface lookup routines */ static struct node_host *iftab; @@ -1367,7 +1470,7 @@ ifa_add_groups_to_map(char *ifa_name) ENTRY item; ENTRY *ret_item; int *answer; - + item.key = ifg->ifgrq_group; if (hsearch_r(item, FIND, &ret_item, &isgroup_map) == 0) { struct ifgroupreq ifgr2; @@ -1406,13 +1509,14 @@ ifa_load(void) err(1, "getifaddrs"); for (ifa = ifap; ifa; ifa = ifa->ifa_next) { - if (!(ifa->ifa_addr->sa_family == AF_INET || + if (ifa->ifa_addr == NULL || + !(ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6 || ifa->ifa_addr->sa_family == AF_LINK)) continue; n = calloc(1, sizeof(struct node_host)); if (n == NULL) - err(1, "address: calloc"); + err(1, "%s: calloc", __func__); n->af = ifa->ifa_addr->sa_family; n->ifa_flags = ifa->ifa_flags; #ifdef __KAME__ @@ -1431,43 +1535,28 @@ ifa_load(void) } #endif n->ifindex = 0; - if (n->af == AF_INET) { - memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *) - ifa->ifa_addr)->sin_addr.s_addr, - sizeof(struct in_addr)); - memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *) - ifa->ifa_netmask)->sin_addr.s_addr, - sizeof(struct in_addr)); - if (ifa->ifa_broadaddr != NULL) - memcpy(&n->bcast, &((struct sockaddr_in *) - ifa->ifa_broadaddr)->sin_addr.s_addr, - sizeof(struct in_addr)); - if (ifa->ifa_dstaddr != NULL) - memcpy(&n->peer, &((struct sockaddr_in *) - ifa->ifa_dstaddr)->sin_addr.s_addr, - sizeof(struct in_addr)); - } else if (n->af == AF_INET6) { - memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *) - ifa->ifa_addr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *) - ifa->ifa_netmask)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - if (ifa->ifa_broadaddr != NULL) - memcpy(&n->bcast, &((struct sockaddr_in6 *) - ifa->ifa_broadaddr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - if (ifa->ifa_dstaddr != NULL) - memcpy(&n->peer, &((struct sockaddr_in6 *) - ifa->ifa_dstaddr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); - n->ifindex = ((struct sockaddr_in6 *) - ifa->ifa_addr)->sin6_scope_id; - } else if (n->af == AF_LINK) { + if (n->af == AF_LINK) { + n->ifindex = ((struct sockaddr_dl *) + ifa->ifa_addr)->sdl_index; ifa_add_groups_to_map(ifa->ifa_name); + } else { + copy_satopfaddr(&n->addr.v.a.addr, ifa->ifa_addr); + ifa->ifa_netmask->sa_family = ifa->ifa_addr->sa_family; + copy_satopfaddr(&n->addr.v.a.mask, ifa->ifa_netmask); + if (ifa->ifa_broadaddr != NULL) { + ifa->ifa_broadaddr->sa_family = ifa->ifa_addr->sa_family; + copy_satopfaddr(&n->bcast, ifa->ifa_broadaddr); + } + if (ifa->ifa_dstaddr != NULL) { + ifa->ifa_dstaddr->sa_family = ifa->ifa_addr->sa_family; + copy_satopfaddr(&n->peer, ifa->ifa_dstaddr); + } + if (n->af == AF_INET6) + n->ifindex = ((struct sockaddr_in6 *) + ifa->ifa_addr) ->sin6_scope_id; } if ((n->ifname = strdup(ifa->ifa_name)) == NULL) - err(1, "ifa_load: strdup"); + err(1, "%s: strdup", __func__); n->next = NULL; n->tail = n; if (h == NULL) @@ -1523,7 +1612,7 @@ is_a_group(char *name) { ENTRY item; ENTRY *ret_item; - + item.key = name; if (hsearch_r(item, FIND, &ret_item, &isgroup_map) == 0) return (0); @@ -1531,6 +1620,34 @@ is_a_group(char *name) return (*(int *)ret_item->data); } +unsigned int +ifa_nametoindex(const char *ifa_name) +{ + struct node_host *p; + + for (p = iftab; p; p = p->next) { + if (p->af == AF_LINK && strcmp(p->ifname, ifa_name) == 0) + return (p->ifindex); + } + errno = ENXIO; + return (0); +} + +char * +ifa_indextoname(unsigned int ifindex, char *ifa_name) +{ + struct node_host *p; + + for (p = iftab; p; p = p->next) { + if (p->af == AF_LINK && ifindex == p->ifindex) { + strlcpy(ifa_name, p->ifname, IFNAMSIZ); + return (ifa_name); + } + } + errno = ENXIO; + return (NULL); +} + struct node_host * ifa_exists(char *ifa_name) { @@ -1619,6 +1736,8 @@ ifa_lookup(char *ifa_name, int flags) if ((flags & PFI_AFLAG_BROADCAST) && !(p->ifa_flags & IFF_BROADCAST)) continue; + if ((flags & PFI_AFLAG_BROADCAST) && p->bcast.v4.s_addr == 0) + continue; if ((flags & PFI_AFLAG_PEER) && !(p->ifa_flags & IFF_POINTOPOINT)) continue; @@ -1640,7 +1759,7 @@ ifa_lookup(char *ifa_name, int flags) got6 = 1; n = calloc(1, sizeof(struct node_host)); if (n == NULL) - err(1, "address: calloc"); + err(1, "%s: calloc", __func__); n->af = p->af; if (flags & PFI_AFLAG_BROADCAST) memcpy(&n->addr.v.a.addr, &p->bcast, @@ -1652,19 +1771,9 @@ ifa_lookup(char *ifa_name, int flags) memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr, sizeof(struct pf_addr)); if (flags & PFI_AFLAG_NETWORK) - set_ipmask(n, unmask(&p->addr.v.a.mask, n->af)); - else { - if (n->af == AF_INET) { - if (p->ifa_flags & IFF_LOOPBACK && - p->ifa_flags & IFF_LINK1) - memcpy(&n->addr.v.a.mask, - &p->addr.v.a.mask, - sizeof(struct pf_addr)); - else - set_ipmask(n, 32); - } else - set_ipmask(n, 128); - } + set_ipmask(n, unmask(&p->addr.v.a.mask)); + else + set_ipmask(n, -1); n->ifindex = p->ifindex; n->ifname = strdup(p->ifname); @@ -1703,57 +1812,41 @@ ifa_skip_if(const char *filter, struct node_host *p) struct node_host * -host(const char *s) +host(const char *s, int opts) { struct node_host *h = NULL; - int mask, v4mask, v6mask, cont = 1; - char *p, *q, *ps; - - if ((p = strrchr(s, '/')) != NULL) { - mask = strtol(p+1, &q, 0); - if (!q || *q || mask > 128 || q == (p+1)) { - fprintf(stderr, "invalid netmask '%s'\n", p); - return (NULL); + int mask = -1; + char *p, *ps; + const char *errstr; + + if ((p = strchr(s, '/')) != NULL) { + mask = strtonum(p+1, 0, 128, &errstr); + if (errstr) { + fprintf(stderr, "netmask is %s: %s\n", errstr, p); + goto error; } if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) - err(1, "host: malloc"); + err(1, "%s: malloc", __func__); strlcpy(ps, s, strlen(s) - strlen(p) + 1); - v4mask = v6mask = mask; } else { if ((ps = strdup(s)) == NULL) - err(1, "host: strdup"); - v4mask = 32; - v6mask = 128; - mask = -1; + err(1, "%s: strdup", __func__); } - /* IPv4 address? */ - if (cont && (h = host_v4(s, mask)) != NULL) - cont = 0; - - /* IPv6 address? */ - if (cont && (h = host_v6(ps, v6mask)) != NULL) - cont = 0; - - /* interface with this name exists? */ - /* expensive with thousands of interfaces - prioritze IPv4/6 check */ - if (cont && (h = host_if(ps, mask, &cont)) != NULL) - cont = 0; - - /* dns lookup */ - if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL) - cont = 0; - free(ps); - - if (h == NULL || cont == 1) { + if ((h = host_ip(ps, mask)) == NULL && + (h = host_if(ps, mask)) == NULL && + (h = host_dns(ps, mask, (opts & PF_OPT_NODNS))) == NULL) { fprintf(stderr, "no IP address found for %s\n", s); - return (NULL); + goto error; } + +error: + free(ps); return (h); } struct node_host * -host_if(const char *s, int mask, int *cont) +host_if(const char *s, int mask) { struct node_host *n, *h = NULL; char *p, *ps; @@ -1770,101 +1863,79 @@ host_if(const char *s, int mask, int *cont) flags |= PFI_AFLAG_PEER; else if (!strcmp(p+1, "0")) flags |= PFI_AFLAG_NOALIAS; - else { - free(ps); - return (NULL); - } + else + goto error; *p = '\0'; - *cont = 0; } if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */ fprintf(stderr, "illegal combination of interface modifiers\n"); - free(ps); - return (NULL); + goto error; } if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) { fprintf(stderr, "network or broadcast lookup, but " "extra netmask given\n"); - free(ps); - return (NULL); + goto error; } if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { /* interface with this name exists */ h = ifa_lookup(ps, flags); - for (n = h; n != NULL && mask > -1; n = n->next) - set_ipmask(n, mask); + if (mask > -1) + for (n = h; n != NULL; n = n->next) + set_ipmask(n, mask); } +error: free(ps); return (h); } struct node_host * -host_v4(const char *s, int mask) +host_ip(const char *s, int mask) { + struct addrinfo hints, *res; struct node_host *h = NULL; - struct in_addr ina; - int bits = 32; - memset(&ina, 0, sizeof(struct in_addr)); - if (strrchr(s, '/') != NULL) { - if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) - return (NULL); - } else { - if (inet_pton(AF_INET, s, &ina) != 1) - return (NULL); - } - - h = calloc(1, sizeof(struct node_host)); + h = calloc(1, sizeof(*h)); if (h == NULL) - err(1, "address: calloc"); - h->ifname = NULL; - h->af = AF_INET; - h->addr.v.a.addr.addr32[0] = ina.s_addr; - set_ipmask(h, bits); - h->next = NULL; - h->tail = h; - - return (h); -} - -struct node_host * -host_v6(const char *s, int mask) -{ - struct addrinfo hints, *res; - struct node_host *h = NULL; + err(1, "%s: calloc", __func__); + if (mask != -1) { + /* Try to parse 10/8 */ + h->af = AF_INET; + if (inet_net_pton(AF_INET, s, &h->addr.v.a.addr.v4, + sizeof(h->addr.v.a.addr.v4)) != -1) + goto out; + } memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET6; + hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_NUMERICHOST; - if (getaddrinfo(s, "0", &hints, &res) == 0) { - h = calloc(1, sizeof(struct node_host)); - if (h == NULL) - err(1, "address: calloc"); - h->ifname = NULL; - h->af = AF_INET6; - memcpy(&h->addr.v.a.addr, - &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, - sizeof(h->addr.v.a.addr)); - h->ifindex = - ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; - set_ipmask(h, mask); + if (getaddrinfo(s, NULL, &hints, &res) == 0) { + h->af = res->ai_family; + copy_satopfaddr(&h->addr.v.a.addr, res->ai_addr); + if (h->af == AF_INET6) + h->ifindex = + ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; freeaddrinfo(res); - h->next = NULL; - h->tail = h; + } else { + free(h); + return (NULL); } +out: + set_ipmask(h, mask); + h->ifname = NULL; + h->next = NULL; + h->tail = h; return (h); } struct node_host * -host_dns(const char *s, int v4mask, int v6mask) +host_dns(const char *s, int mask, int numeric) { struct addrinfo hints, *res0, *res; struct node_host *n, *h = NULL; - int error, noalias = 0; - int got4 = 0, got6 = 0; + int noalias = 0, got4 = 0, got6 = 0; char *p, *ps; if ((ps = strdup(s)) == NULL) @@ -1876,11 +1947,10 @@ host_dns(const char *s, int v4mask, int v6mask) memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; /* DUMMY */ - error = getaddrinfo(ps, NULL, &hints, &res0); - if (error) { - free(ps); - return (h); - } + if (numeric) + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(ps, NULL, &hints, &res0) != 0) + goto error; for (res = res0; res; res = res->ai_next) { if (res->ai_family != AF_INET && @@ -1902,22 +1972,11 @@ host_dns(const char *s, int v4mask, int v6mask) err(1, "host_dns: calloc"); n->ifname = NULL; n->af = res->ai_family; - if (res->ai_family == AF_INET) { - memcpy(&n->addr.v.a.addr, - &((struct sockaddr_in *) - res->ai_addr)->sin_addr.s_addr, - sizeof(struct in_addr)); - set_ipmask(n, v4mask); - } else { - memcpy(&n->addr.v.a.addr, - &((struct sockaddr_in6 *) - res->ai_addr)->sin6_addr.s6_addr, - sizeof(struct in6_addr)); + copy_satopfaddr(&n->addr.v.a.addr, res->ai_addr); + if (res->ai_family == AF_INET6) n->ifindex = - ((struct sockaddr_in6 *) - res->ai_addr)->sin6_scope_id; - set_ipmask(n, v6mask); - } + ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; + set_ipmask(n, mask); n->next = NULL; n->tail = n; if (h == NULL) @@ -1928,6 +1987,7 @@ host_dns(const char *s, int v4mask, int v6mask) } } freeaddrinfo(res0); +error: free(ps); return (h); @@ -1939,7 +1999,7 @@ host_dns(const char *s, int v4mask, int v6mask) * if set to 1, only simple addresses are accepted (no netblock, no "!"). */ int -append_addr(struct pfr_buffer *b, char *s, int test) +append_addr(struct pfr_buffer *b, char *s, int test, int opts) { char *r; struct node_host *h, *n; @@ -1947,7 +2007,7 @@ append_addr(struct pfr_buffer *b, char *s, int test) for (r = s; *r == '!'; r++) not = !not; - if ((n = host(r)) == NULL) { + if ((n = host(r, opts)) == NULL) { errno = 0; return (-1); } @@ -1976,7 +2036,7 @@ append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not) bzero(&addr, sizeof(addr)); addr.pfra_not = n->not ^ not; addr.pfra_af = n->af; - addr.pfra_net = unmask(&n->addr.v.a.mask, n->af); + addr.pfra_net = unmask(&n->addr.v.a.mask); switch (n->af) { case AF_INET: addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0]; |