diff options
author | 2001-08-11 12:04:59 +0000 | |
---|---|---|
committer | 2001-08-11 12:04:59 +0000 | |
commit | ae58c8ac5920a8830fb6fb32809d61bde09297fd (patch) | |
tree | 1826a82bcde2b2ff2c8270709747442ced080903 | |
parent | Some fixes from NetBSD. (diff) | |
download | wireguard-openbsd-ae58c8ac5920a8830fb6fb32809d61bde09297fd.tar.xz wireguard-openbsd-ae58c8ac5920a8830fb6fb32809d61bde09297fd.zip |
Add support for ICMP errors referring to ICMP queries/replies. Fixes
'ICMP error message for bad proto' messages. Reported by Mark Grimes
and Steve Rumble.
Add debugging level with ioctl interface and pfctl switch. Default
is 'None'.
-rw-r--r-- | sbin/pfctl/pfctl.8 | 13 | ||||
-rw-r--r-- | sbin/pfctl/pfctl.c | 56 | ||||
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 17 | ||||
-rw-r--r-- | sys/net/pf.c | 169 | ||||
-rw-r--r-- | sys/net/pf_norm.c | 4 | ||||
-rw-r--r-- | sys/net/pfvar.h | 6 |
6 files changed, 203 insertions, 62 deletions
diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8 index eb01bc71a6f..9fa525bdd20 100644 --- a/sbin/pfctl/pfctl.8 +++ b/sbin/pfctl/pfctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: pfctl.8,v 1.26 2001/08/03 16:03:02 mpech Exp $ +.\" $OpenBSD: pfctl.8,v 1.27 2001/08/11 12:05:00 dhartmei Exp $ .\" .\" Copyright (c) 2001 Kjell Wooding. All rights reserved. .\" @@ -38,6 +38,7 @@ .Op Fl N Ar file .Op Fl R Ar file .Op Fl s Ar modifier +.Op Fl x Ar level .Sh DESCRIPTION The .Nm @@ -125,6 +126,16 @@ Show all of the above. .El .It Fl v Show rules as they are parsed. +.It Fl x Ar level +Set the debug level to one of the following. +Level names may be abbreviated: +.Bl -tag -width "x urgent " -compact +.It Fl x Ar none +Don't generate debug messages. +.It Fl x Ar urgent +Generate debug messages only for serious errors. +.It Fl x Ar misc +Generate debug messages for various errors. .El .Sh FILES .Bl -tag -width "/etc/nat.conf" -compact diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c index 79edf2e06e4..b405e19d0f2 100644 --- a/sbin/pfctl/pfctl.c +++ b/sbin/pfctl/pfctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl.c,v 1.31 2001/08/11 09:54:59 deraadt Exp $ */ +/* $OpenBSD: pfctl.c,v 1.32 2001/08/11 12:05:00 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -67,6 +67,7 @@ int pfctl_show_status(int); int pfctl_rules(int, char *, int); int pfctl_nat(int, char *, int); int pfctl_log(int, char *, int); +int pfctl_debug(int, u_int32_t, int); int opts = 0; char *clearopt; @@ -74,6 +75,7 @@ char *logopt; char *natopt; char *rulesopt; char *showopt; +char *debugopt; char *infile; @@ -84,7 +86,7 @@ usage() fprintf(stderr, "usage: %s [-dehnqv] [-F set] [-l interface] ", __progname); - fprintf(stderr, "[-N file] [-R file] [-s set]\n"); + fprintf(stderr, "[-N file] [-R file] [-s set] [-x level]\n"); exit(1); } @@ -383,6 +385,32 @@ pfctl_log(int dev, char *ifname, int opts) } int +pfctl_debug(int dev, u_int32_t level, int opts) +{ + if (ioctl(dev, DIOCSETDEBUG, &level)) + err(1, "DIOCSETDEBUG"); + if ((opts & PF_OPT_QUIET) == 0) { + printf("debug level set to '"); + switch (level) { + case PF_DEBUG_NONE: + printf("none"); + break; + case PF_DEBUG_URGENT: + printf("urgent"); + break; + case PF_DEBUG_MISC: + printf("misc"); + break; + default: + printf("<invalid>"); + break; + } + printf("'\n"); + } + return (0); +} + +int main(int argc, char *argv[]) { extern char *optarg; @@ -394,7 +422,7 @@ main(int argc, char *argv[]) if (argc < 2) usage(); - while ((ch = getopt(argc, argv, "deqF:hl:nN:R:s:v")) != -1) { + while ((ch = getopt(argc, argv, "deqF:hl:nN:R:s:vx:")) != -1) { switch (ch) { case 'd': opts |= PF_OPT_DISABLE; @@ -426,6 +454,9 @@ main(int argc, char *argv[]) case 'v': opts |= PF_OPT_VERBOSE; break; + case 'x': + debugopt = optarg; + break; case 'h': default: usage(); @@ -446,7 +477,7 @@ main(int argc, char *argv[]) } else { /* turn off options */ opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); - clearopt = logopt = showopt = NULL; + clearopt = logopt = showopt = debugopt = NULL; } if (opts & PF_OPT_DISABLE) @@ -522,6 +553,23 @@ main(int argc, char *argv[]) if (pfctl_enable(dev, opts)) error = 1; + if (debugopt != NULL) { + switch (*debugopt) { + case 'n': + pfctl_debug(dev, PF_DEBUG_NONE, opts); + break; + case 'u': + pfctl_debug(dev, PF_DEBUG_URGENT, opts); + break; + case 'm': + pfctl_debug(dev, PF_DEBUG_MISC, opts); + break; + default: + warnx("Unknown debug level '%s'", debugopt); + error = 1; + } + } + close(dev); exit(error); diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index f9f4266eb92..1fff22a4774 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.39 2001/07/19 00:07:36 krw Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.40 2001/08/11 12:05:00 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -348,10 +348,21 @@ print_status(struct pf_status *s) time_t t = time(NULL); int i; - printf("Status: %s Time: %u Since: %u\n", + printf("Status: %s Time: %u Since: %u Debug: ", s->running ? "Enabled" : "Disabled", t, s->since); - printf("Bytes In: %-10llu Bytes Out: %-10llu\n", + switch (s->debug) { + case 0: + printf("None"); + break; + case 1: + printf("Urgent"); + break; + case 2: + printf("Misc"); + break; + } + printf("\nBytes In: %-10llu Bytes Out: %-10llu\n", s->bcounters[PF_IN], s->bcounters[PF_OUT]); printf("Inbound Packets: Passed: %-10llu Dropped: %-10llu\n", s->pcounters[PF_IN][PF_PASS], diff --git a/sys/net/pf.c b/sys/net/pf.c index be4fa7cc86f..909ab981a66 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.122 2001/08/01 23:07:36 provos Exp $ */ +/* $OpenBSD: pf.c,v 1.123 2001/08/11 12:05:00 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -63,8 +63,7 @@ #include "bpfilter.h" #include "pflog.h" -int pf_debug = 0; -#define DPFPRINTF(x) if (pf_debug) printf x +#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x /* * Tree data structure @@ -498,19 +497,22 @@ pf_insert_state(struct pf_state *state) key.port[1] = state->ext.port; /* sanity checks can be removed later, should never occur */ if ((s = pf_find_state(tree_lan_ext, &key)) != NULL) { - printf("pf: ERROR! insert invalid\n"); - printf(" key already in tree_lan_ext\n"); - printf(" key: proto = %u, lan = ", state->proto); - pf_print_host(key.addr[0].s_addr, key.port[0]); - printf(", ext = "); - pf_print_host(key.addr[1].s_addr, key.port[1]); - printf("\n state: "); - pf_print_state(s); - printf("\n"); + if (pf_status.debug >= PF_DEBUG_URGENT) { + printf("pf: ERROR! insert invalid\n"); + printf(" key already in tree_lan_ext\n"); + printf(" key: proto = %u, lan = ", state->proto); + pf_print_host(key.addr[0].s_addr, key.port[0]); + printf(", ext = "); + pf_print_host(key.addr[1].s_addr, key.port[1]); + printf("\n state: "); + pf_print_state(s); + printf("\n"); + } } else { pf_tree_insert(&tree_lan_ext, NULL, &key, state); if (pf_find_state(tree_lan_ext, &key) != state) - printf("pf: ERROR! insert failed\n"); + DPFPRINTF(PF_DEBUG_URGENT, + ("pf: ERROR! insert failed\n")); } key.proto = state->proto; @@ -519,19 +521,22 @@ pf_insert_state(struct pf_state *state) key.addr[1].s_addr = state->gwy.addr; key.port[1] = state->gwy.port; if ((s = pf_find_state(tree_ext_gwy, &key)) != NULL) { - printf("pf: ERROR! insert invalid\n"); - printf(" key already in tree_ext_gwy\n"); - printf(" key: proto = %u, ext = ", state->proto); - pf_print_host(key.addr[0].s_addr, key.port[0]); - printf(", gwy = "); - pf_print_host(key.addr[1].s_addr, key.port[1]); - printf("\n state: "); - pf_print_state(s); - printf("\n"); + if (pf_status.debug >= PF_DEBUG_URGENT) { + printf("pf: ERROR! insert invalid\n"); + printf(" key already in tree_ext_gwy\n"); + printf(" key: proto = %u, ext = ", state->proto); + pf_print_host(key.addr[0].s_addr, key.port[0]); + printf(", gwy = "); + pf_print_host(key.addr[1].s_addr, key.port[1]); + printf("\n state: "); + pf_print_state(s); + printf("\n"); + } } else { pf_tree_insert(&tree_ext_gwy, NULL, &key, state); if (pf_find_state(tree_ext_gwy, &key) != state) - printf("pf: ERROR! insert failed\n"); + DPFPRINTF(PF_DEBUG_URGENT, + ("pf: ERROR! insert failed\n")); } pf_status.fcounters[FCNT_STATE_INSERT]++; pf_status.states++; @@ -553,10 +558,12 @@ pf_purge_expired_states(void) key.port[1] = cur->state->ext.port; /* remove state from second tree */ if (pf_find_state(tree_lan_ext, &key) != cur->state) - printf("pf: ERROR: remove invalid!\n"); + DPFPRINTF(PF_DEBUG_URGENT, + ("pf: ERROR: remove invalid!\n")); pf_tree_remove(&tree_lan_ext, NULL, &key); if (pf_find_state(tree_lan_ext, &key) != NULL) - printf("pf: ERROR: remove failed\n"); + DPFPRINTF(PF_DEBUG_URGENT, + ("pf: ERROR: remove failed\n")); if (STATE_TRANSLATE(cur->state)) pf_put_sport(cur->state->proto, htons(cur->state->gwy.port)); @@ -573,8 +580,8 @@ pf_purge_expired_states(void) pf_tree_remove(&tree_ext_gwy, NULL, &cur->key); cur = pf_tree_search(tree_ext_gwy, &key); if (cur == NULL) - printf( - "pf: ERROR: next not refound\n"); + DPFPRINTF(PF_DEBUG_URGENT, + ("pf: ERROR: next not found\n")); } else { pf_tree_remove(&tree_ext_gwy, NULL, &cur->key); cur = NULL; @@ -733,7 +740,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pf_status.states = states; microtime(&pftv); pf_status.since = pftv.tv_sec; - printf("pf: started\n"); + DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n")); } break; @@ -742,7 +749,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) error = ENOENT; else { pf_status.running = 0; - printf("pf: stopped\n"); + DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n")); } break; @@ -1136,6 +1143,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pf_status.states = states; break; } + case DIOCNATLOOK: { struct pf_natlook *pnl = (struct pf_natlook *)addr; struct pf_state *st; @@ -1181,6 +1189,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } break; } + + case DIOCSETDEBUG: { + u_int32_t *level = (u_int32_t *)addr; + pf_status.debug = *level; + break; + } + default: error = ENODEV; break; @@ -2238,18 +2253,18 @@ pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, return (PF_PASS); } else { - /* XXX Remove these printfs before release */ - printf("pf: BAD state: "); - pf_print_state(*state); - pf_print_flags(th->th_flags); - printf(" seq=%lu ack=%lu len=%u ", seq, ack, len); - printf("\n"); - printf("State failure: %c %c %c %c\n", - SEQ_GEQ(src->seqhi, end) ? ' ' : '1', - SEQ_GEQ(seq, src->seqlo - dst->max_win) ? ' ': '2', - (ackskew >= -MAXACKWINDOW) ? ' ' : '3', - (ackskew <= MAXACKWINDOW) ? ' ' : '4'); - + if (pf_status.debug >= PF_DEBUG_MISC) { + printf("pf: BAD state: "); + pf_print_state(*state); + pf_print_flags(th->th_flags); + printf(" seq=%lu ack=%lu len=%u ", seq, ack, len); + printf("\n"); + printf("State failure: %c %c %c %c\n", + SEQ_GEQ(src->seqhi, end) ? ' ' : '1', + SEQ_GEQ(seq, src->seqlo - dst->max_win) ? ' ': '2', + (ackskew >= -MAXACKWINDOW) ? ' ' : '3', + (ackskew <= MAXACKWINDOW) ? ' ' : '4'); + } return (PF_DROP); } } @@ -2374,7 +2389,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, ipoff2 = off + ICMP_MINLEN; /* offset of h2 in mbuf chain */ if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2), NULL, NULL)) { - printf("pf: ICMP error message too short (ip)\n"); + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message too short (ip)\n")); return (PF_DROP); } @@ -2398,8 +2414,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, * th_seq, an ackskew test is not possible. */ if (!pf_pull_hdr(m, off2, &th, 8, NULL, NULL)) { - printf("pf: " - "ICMP error message too short (tcp)\n"); + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message too short (tcp)\n")); return (PF_DROP); } seq = ntohl(th.th_seq); @@ -2427,10 +2443,11 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (!SEQ_GEQ(src->seqhi, seq) || !SEQ_GEQ(seq, src->seqlo - dst->max_win)) { - - printf("pf: BAD ICMP state: "); - pf_print_state(*state); - printf(" seq=%lu\n", seq); + if (pf_status.debug >= PF_DEBUG_MISC) { + printf("pf: BAD ICMP state: "); + pf_print_state(*state); + printf(" seq=%lu\n", seq); + } return (PF_DROP); } @@ -2466,7 +2483,8 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, if (!pf_pull_hdr(m, off2, &uh, sizeof(uh), NULL, NULL)) { - printf("pf: ICMP error message too short (udp)\n"); + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message too short (udp)\n")); return (PF_DROP); } @@ -2509,8 +2527,59 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, return (PF_PASS); break; } + case IPPROTO_ICMP: { + struct icmp iih; + struct pf_tree_key key; + + if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, + NULL, NULL)) { + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message too short (icmp)\n")); + return (PF_DROP); + } + + key.proto = IPPROTO_ICMP; + key.addr[0] = h2.ip_dst; + key.port[0] = iih.icmp_id; + key.addr[1] = h2.ip_src; + key.port[1] = iih.icmp_id; + + if (direction == PF_IN) + *state = pf_find_state(tree_ext_gwy, &key); + else + *state = pf_find_state(tree_lan_ext, &key); + if (*state == NULL) + return (PF_DROP); + + if (STATE_TRANSLATE(*state)) { + if (direction == PF_IN) { + pf_change_icmp(&h2.ip_src.s_addr, + &iih.icmp_id, &h->ip_dst.s_addr, + (*state)->lan.addr, + (*state)->lan.port, NULL, + &h2.ip_sum, &ih->icmp_cksum, + &h->ip_sum); + } else { + pf_change_icmp(&h2.ip_dst.s_addr, + &iih.icmp_id, &h->ip_src.s_addr, + (*state)->gwy.addr, + (*state)->gwy.port, NULL, + &h2.ip_sum, &ih->icmp_cksum, + &h->ip_sum); + } + m_copyback(m, off, ICMP_MINLEN, (caddr_t)ih); + m_copyback(m, ipoff2, sizeof(h2), + (caddr_t)&h2); + m_copyback(m, off2, ICMP_MINLEN, + (caddr_t)&iih); + } + + return (PF_PASS); + break; + } default: - printf("pf: ICMP error message for bad proto\n"); + DPFPRINTF(PF_DEBUG_MISC, + ("pf: ICMP error message for bad proto\n")); return (PF_DROP); } diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index 53e99c59717..2d847cf497f 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.5 2001/08/02 06:59:25 deraadt Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.6 2001/08/11 12:05:00 dhartmei Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -93,7 +93,7 @@ int pf_normalize_tcp(int, struct ifnet *, struct mbuf *, #define PFFRAG_FRENT_HIWAT 5000 /* Number of fragment entries */ #define PFFRAG_FRAG_HIWAT 1000 /* Number of fragmented packets */ -#define DPFPRINTF(x) if (pf_debug) printf x +#define DPFPRINTF(x) if (pf_status.debug) printf x #if NPFLOG > 0 #define PFLOG_PACKET(x,a,b,c,d,e) \ diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index fff97b45bf0..2724ffdc7ce 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.38 2001/08/01 23:07:36 provos Exp $ */ +/* $OpenBSD: pfvar.h,v 1.39 2001/08/11 12:04:59 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -40,6 +40,7 @@ enum { PF_IN=0, PF_OUT=1 }; enum { PF_PASS=0, PF_DROP=1, PF_SCRUB=2 }; enum { PF_OP_IRG=1, PF_OP_EQ=2, PF_OP_NE=3, PF_OP_LT=4, PF_OP_LE=5, PF_OP_GT=6, PF_OP_GE=7, PF_OP_XRG=8 }; +enum { PF_DEBUG_NONE=0, PF_DEBUG_URGENT=1, PF_DEBUG_MISC=2 }; struct pf_rule_addr { u_int32_t addr; @@ -233,6 +234,7 @@ struct pf_status { u_int32_t running; u_int32_t states; u_int32_t since; + u_int32_t debug; }; /* @@ -293,6 +295,7 @@ struct pfioc_if { #define DIOCGETSTATUS _IOWR('D', 21, struct pf_status) #define DIOCCLRSTATUS _IO ('D', 22) #define DIOCNATLOOK _IOWR('D', 23, struct pf_natlook) +#define DIOCSETDEBUG _IOWR('D', 24, u_int32_t) #ifdef _KERNEL @@ -316,7 +319,6 @@ void pf_purge_expired_fragments(void); extern struct pf_rulequeue *pf_rules_active; extern struct pf_status pf_status; -extern int pf_debug; #endif /* _KERNEL */ #endif /* _NET_PFVAR_H_ */ |