diff options
author | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2001-08-11 12:05:01 +0000 |
---|---|---|
committer | Daniel Hartmeier <dhartmei@cvs.openbsd.org> | 2001-08-11 12:05:01 +0000 |
commit | b7d10a986fcd6d83d5e1febbc145b267b8f7152c (patch) | |
tree | 0f12670233f634c76dcd2185748b78126f6f55c2 /sys/net/pf.c | |
parent | 117e49e4fe673065b85ff3a47f437f8b43ff1baa (diff) |
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'.
Diffstat (limited to 'sys/net/pf.c')
-rw-r--r-- | sys/net/pf.c | 169 |
1 files changed, 119 insertions, 50 deletions
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); } |