summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorDaniel Hartmeier <dhartmei@cvs.openbsd.org>2001-08-11 12:05:01 +0000
committerDaniel Hartmeier <dhartmei@cvs.openbsd.org>2001-08-11 12:05:01 +0000
commitb7d10a986fcd6d83d5e1febbc145b267b8f7152c (patch)
tree0f12670233f634c76dcd2185748b78126f6f55c2 /sys/net
parent117e49e4fe673065b85ff3a47f437f8b43ff1baa (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')
-rw-r--r--sys/net/pf.c169
-rw-r--r--sys/net/pf_norm.c4
-rw-r--r--sys/net/pfvar.h6
3 files changed, 125 insertions, 54 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);
}
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_ */