summaryrefslogtreecommitdiff
path: root/sys/net/pf.c
diff options
context:
space:
mode:
authorMike Frantzen <frantzen@cvs.openbsd.org>2003-08-21 19:12:10 +0000
committerMike Frantzen <frantzen@cvs.openbsd.org>2003-08-21 19:12:10 +0000
commitb52022c22d0099a7ee4fac807fbc3cf0d1ed41dd (patch)
treeee69abaecaf37fc21178586105aec99dbe4500db /sys/net/pf.c
parentac8ea66182cc0e72f3c2b0178333b53707008bbc (diff)
Add Michal Zalewski's p0f v2 style passive OS fingerprinting to PF.
Exposes the source IP's operating system to the filter language. Interesting policy decisions are now enforceable: . block proto tcp from any os SCO . block proto tcp from any os Windows to any port smtp . rdr ... from any os "Windows 98" to port WWW -> 127.0.0.1 port 8001
Diffstat (limited to 'sys/net/pf.c')
-rw-r--r--sys/net/pf.c118
1 files changed, 68 insertions, 50 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 1a06af8df12..593ed77af13 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.385 2003/08/18 11:01:41 dhartmei Exp $ */
+/* $OpenBSD: pf.c,v 1.386 2003/08/21 19:12:07 frantzen Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -134,13 +134,15 @@ void pf_send_tcp(const struct pf_rule *, sa_family_t,
u_int8_t, u_int16_t, u_int16_t, u_int8_t);
void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
sa_family_t, struct pf_rule *);
-struct pf_rule *pf_match_translation(int, struct ifnet *, u_int8_t,
+struct pf_rule *pf_match_translation(struct pf_pdesc *, struct mbuf *,
+ int, int, struct ifnet *,
struct pf_addr *, u_int16_t, struct pf_addr *,
- u_int16_t, sa_family_t, int);
-struct pf_rule *pf_get_translation(int, struct ifnet *, u_int8_t,
+ u_int16_t, int);
+struct pf_rule *pf_get_translation(struct pf_pdesc *, struct mbuf *,
+ int, int, struct ifnet *,
struct pf_addr *, u_int16_t,
struct pf_addr *, u_int16_t,
- struct pf_addr *, u_int16_t *, sa_family_t);
+ struct pf_addr *, u_int16_t *);
int pf_test_tcp(struct pf_rule **, struct pf_state **,
int, struct ifnet *, struct mbuf *, int, int,
void *, struct pf_pdesc *, struct pf_rule **,
@@ -154,7 +156,7 @@ int pf_test_icmp(struct pf_rule **, struct pf_state **,
void *, struct pf_pdesc *, struct pf_rule **,
struct pf_ruleset **);
int pf_test_other(struct pf_rule **, struct pf_state **,
- int, struct ifnet *, struct mbuf *, void *,
+ int, struct ifnet *, struct mbuf *, int, void *,
struct pf_pdesc *, struct pf_rule **,
struct pf_ruleset **);
int pf_test_fragment(struct pf_rule **, int,
@@ -1761,9 +1763,9 @@ pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_pool *rpool,
}
struct pf_rule *
-pf_match_translation(int direction, struct ifnet *ifp, u_int8_t proto,
- struct pf_addr *saddr, u_int16_t sport, struct pf_addr *daddr,
- u_int16_t dport, sa_family_t af, int rs_num)
+pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
+ int direction, struct ifnet *ifp, struct pf_addr *saddr, u_int16_t sport,
+ struct pf_addr *daddr, u_int16_t dport, int rs_num)
{
struct pf_rule *r, *rm = NULL, *anchorrule = NULL;
struct pf_ruleset *ruleset = NULL;
@@ -1788,11 +1790,11 @@ pf_match_translation(int direction, struct ifnet *ifp, u_int8_t proto,
r = r->skip[PF_SKIP_IFP].ptr;
else if (r->direction && r->direction != direction)
r = r->skip[PF_SKIP_DIR].ptr;
- else if (r->af && r->af != af)
+ else if (r->af && r->af != pd->af)
r = r->skip[PF_SKIP_AF].ptr;
- else if (r->proto && r->proto != proto)
+ else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
- else if (PF_MISMATCHAW(&src->addr, saddr, af, src->not))
+ else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->not))
r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
PF_SKIP_DST_ADDR].ptr;
else if (src->port_op && !pf_match_port(src->port_op,
@@ -1800,14 +1802,18 @@ pf_match_translation(int direction, struct ifnet *ifp, u_int8_t proto,
r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
PF_SKIP_DST_PORT].ptr;
else if (dst != NULL &&
- PF_MISMATCHAW(&dst->addr, daddr, af, dst->not))
+ PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->not))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
- else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, af, 0))
+ else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
r = TAILQ_NEXT(r, entries);
else if (dst != NULL && dst->port_op &&
!pf_match_port(dst->port_op, dst->port[0],
dst->port[1], dport))
r = r->skip[PF_SKIP_DST_PORT].ptr;
+ else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
+ IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
+ off, pd->hdr.tcp), r->os_fingerprint)))
+ r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
else if (r->anchor == NULL)
@@ -1825,25 +1831,26 @@ pf_match_translation(int direction, struct ifnet *ifp, u_int8_t proto,
}
struct pf_rule *
-pf_get_translation(int direction, struct ifnet *ifp, u_int8_t proto,
+pf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
+ struct ifnet *ifp,
struct pf_addr *saddr, u_int16_t sport,
struct pf_addr *daddr, u_int16_t dport,
- struct pf_addr *naddr, u_int16_t *nport, sa_family_t af)
+ struct pf_addr *naddr, u_int16_t *nport)
{
struct pf_rule *r = NULL;
if (direction == PF_OUT) {
- r = pf_match_translation(direction, ifp, proto,
- saddr, sport, daddr, dport, af, PF_RULESET_BINAT);
+ r = pf_match_translation(pd, m, off, direction, ifp, saddr,
+ sport, daddr, dport, PF_RULESET_BINAT);
if (r == NULL)
- r = pf_match_translation(direction, ifp, proto,
- saddr, sport, daddr, dport, af, PF_RULESET_NAT);
+ r = pf_match_translation(pd, m, off, direction, ifp,
+ saddr, sport, daddr, dport, PF_RULESET_NAT);
} else {
- r = pf_match_translation(direction, ifp, proto,
- saddr, sport, daddr, dport, af, PF_RULESET_RDR);
+ r = pf_match_translation(pd, m, off, direction, ifp, saddr,
+ sport, daddr, dport, PF_RULESET_RDR);
if (r == NULL)
- r = pf_match_translation(direction, ifp, proto,
- saddr, sport, daddr, dport, af, PF_RULESET_BINAT);
+ r = pf_match_translation(pd, m, off, direction, ifp,
+ saddr, sport, daddr, dport, PF_RULESET_BINAT);
}
if (r != NULL) {
@@ -1854,8 +1861,8 @@ pf_get_translation(int direction, struct ifnet *ifp, u_int8_t proto,
return (NULL);
break;
case PF_NAT:
- if (pf_get_sport(af, proto, &r->rpool, saddr, daddr,
- dport, naddr, nport, r->rpool.proxy_port[0],
+ if (pf_get_sport(pd->af, pd->proto, &r->rpool, saddr,
+ daddr, dport, naddr, nport, r->rpool.proxy_port[0],
r->rpool.proxy_port[1])) {
DPFPRINTF(PF_DEBUG_MISC,
("pf: NAT proxy port allocation "
@@ -1876,7 +1883,7 @@ pf_get_translation(int direction, struct ifnet *ifp, u_int8_t proto,
PF_POOLMASK(naddr,
&r->rpool.cur->addr.v.a.addr,
&r->rpool.cur->addr.v.a.mask,
- saddr, af);
+ saddr, pd->af);
break;
case PF_IN:
if (r->src.addr.type == PF_ADDR_DYNIFTL &&
@@ -1885,7 +1892,8 @@ pf_get_translation(int direction, struct ifnet *ifp, u_int8_t proto,
else
PF_POOLMASK(naddr,
&r->src.addr.v.a.addr,
- &r->src.addr.v.a.mask, saddr, af);
+ &r->src.addr.v.a.mask, saddr,
+ pd->af);
break;
}
break;
@@ -2167,9 +2175,9 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
if (direction == PF_OUT) {
bport = nport = th->th_sport;
/* check outgoing packet for BINAT/NAT */
- if ((nat = pf_get_translation(PF_OUT, ifp, IPPROTO_TCP,
+ if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp,
saddr, th->th_sport, daddr, th->th_dport,
- &naddr, &nport, af)) != NULL) {
+ &naddr, &nport)) != NULL) {
PF_ACPY(&baddr, saddr, af);
pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
&th->th_sum, &naddr, nport, 0, af);
@@ -2180,9 +2188,9 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
} else {
bport = nport = th->th_dport;
/* check incoming packet for BINAT/RDR */
- if ((rdr = pf_get_translation(PF_IN, ifp, IPPROTO_TCP,
- saddr, th->th_sport, daddr, th->th_dport,
- &naddr, &nport, af)) != NULL) {
+ if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr,
+ th->th_sport, daddr, th->th_dport,
+ &naddr, &nport)) != NULL) {
PF_ACPY(&baddr, daddr, af);
pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
&th->th_sum, &naddr, nport, 0, af);
@@ -2236,6 +2244,9 @@ pf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
+ else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
+ pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
+ r = TAILQ_NEXT(r, entries);
else {
if (r->tag)
tag = r->tag;
@@ -2487,9 +2498,9 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
if (direction == PF_OUT) {
bport = nport = uh->uh_sport;
/* check outgoing packet for BINAT/NAT */
- if ((nat = pf_get_translation(PF_OUT, ifp, IPPROTO_UDP,
+ if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp,
saddr, uh->uh_sport, daddr, uh->uh_dport,
- &naddr, &nport, af)) != NULL) {
+ &naddr, &nport)) != NULL) {
PF_ACPY(&baddr, saddr, af);
pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
&uh->uh_sum, &naddr, nport, 1, af);
@@ -2500,9 +2511,9 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
} else {
bport = nport = uh->uh_dport;
/* check incoming packet for BINAT/RDR */
- if ((rdr = pf_get_translation(PF_IN, ifp, IPPROTO_UDP,
- saddr, uh->uh_sport, daddr, uh->uh_dport,
- &naddr, &nport, af)) != NULL) {
+ if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr,
+ uh->uh_sport, daddr, uh->uh_dport, &naddr, &nport))
+ != NULL) {
PF_ACPY(&baddr, daddr, af);
pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
&uh->uh_sum, &naddr, nport, 1, af);
@@ -2554,6 +2565,8 @@ pf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
+ else if (r->os_fingerprint != PF_OSFP_ANY)
+ r = TAILQ_NEXT(r, entries);
else {
if (r->tag)
tag = r->tag;
@@ -2757,8 +2770,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
if (direction == PF_OUT) {
/* check outgoing packet for BINAT/NAT */
- if ((nat = pf_get_translation(PF_OUT, ifp, pd->proto,
- saddr, 0, daddr, 0, &naddr, NULL, af)) != NULL) {
+ if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp, saddr, 0,
+ daddr, 0, &naddr, NULL)) != NULL) {
PF_ACPY(&baddr, saddr, af);
switch (af) {
#ifdef INET
@@ -2780,8 +2793,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
}
} else {
/* check incoming packet for BINAT/RDR */
- if ((rdr = pf_get_translation(PF_IN, ifp, pd->proto,
- saddr, 0, daddr, 0, &naddr, NULL, af)) != NULL) {
+ if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr, 0,
+ daddr, 0, &naddr, NULL)) != NULL) {
PF_ACPY(&baddr, daddr, af);
switch (af) {
#ifdef INET
@@ -2831,6 +2844,8 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
+ else if (r->os_fingerprint != PF_OSFP_ANY)
+ r = TAILQ_NEXT(r, entries);
else {
if (r->tag)
tag = r->tag;
@@ -2963,7 +2978,7 @@ pf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
int
pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
- struct ifnet *ifp, struct mbuf *m, void *h, struct pf_pdesc *pd,
+ struct ifnet *ifp, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
struct pf_rule **am, struct pf_ruleset **rsm)
{
struct pf_rule *nat = NULL, *rdr = NULL;
@@ -2980,8 +2995,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
if (direction == PF_OUT) {
/* check outgoing packet for BINAT/NAT */
- if ((nat = pf_get_translation(PF_OUT, ifp, pd->proto,
- saddr, 0, daddr, 0, &naddr, NULL, af)) != NULL) {
+ if ((nat = pf_get_translation(pd, m, off, PF_OUT, ifp, saddr, 0,
+ daddr, 0, &naddr, NULL)) != NULL) {
PF_ACPY(&baddr, saddr, af);
switch (af) {
#ifdef INET
@@ -3001,8 +3016,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
}
} else {
/* check incoming packet for BINAT/RDR */
- if ((rdr = pf_get_translation(PF_IN, ifp, pd->proto,
- saddr, 0, daddr, 0, &naddr, NULL, af)) != NULL) {
+ if ((rdr = pf_get_translation(pd, m, off, PF_IN, ifp, saddr, 0,
+ daddr, 0, &naddr, NULL)) != NULL) {
PF_ACPY(&baddr, daddr, af);
switch (af) {
#ifdef INET
@@ -3046,6 +3061,8 @@ pf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
r = TAILQ_NEXT(r, entries);
else if (r->anchorname[0] && r->anchor == NULL)
r = TAILQ_NEXT(r, entries);
+ else if (r->os_fingerprint != PF_OSFP_ANY)
+ r = TAILQ_NEXT(r, entries);
else {
if (r->tag)
tag = r->tag;
@@ -3227,7 +3244,8 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp,
else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
else if (r->src.port_op || r->dst.port_op ||
- r->flagset || r->type || r->code)
+ r->flagset || r->type || r->code ||
+ r->os_fingerprint != PF_OSFP_ANY)
r = TAILQ_NEXT(r, entries);
else if (r->match_tag &&
!pf_match_tag(m, r, NULL, NULL, pftag, &tag))
@@ -4974,7 +4992,7 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0)
a = s->anchor.ptr;
log = s->log;
} else if (s == NULL)
- action = pf_test_other(&r, &s, dir, ifp, m, h,
+ action = pf_test_other(&r, &s, dir, ifp, m, off, h,
&pd, &a, &ruleset);
break;
}
@@ -5208,7 +5226,7 @@ pf_test6(int dir, struct ifnet *ifp, struct mbuf **m0)
}
default:
- action = pf_test_other(&r, &s, dir, ifp, m, h,
+ action = pf_test_other(&r, &s, dir, ifp, m, off, h,
&pd, &a, &ruleset);
break;
}