diff options
-rw-r--r-- | sbin/pfctl/pfctl_parser.c | 54 | ||||
-rw-r--r-- | sys/net/pf.c | 98 | ||||
-rw-r--r-- | sys/net/pfvar.h | 9 | ||||
-rw-r--r-- | sys/netinet/ip_icmp.c | 9 | ||||
-rw-r--r-- | sys/sys/mbuf.h | 3 |
5 files changed, 117 insertions, 56 deletions
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c index 074407a5640..082719c69d3 100644 --- a/sbin/pfctl/pfctl_parser.c +++ b/sbin/pfctl/pfctl_parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfctl_parser.c,v 1.24 2001/07/01 17:16:02 kjell Exp $ */ +/* $OpenBSD: pfctl_parser.c,v 1.25 2001/07/01 23:04:45 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -405,12 +405,26 @@ print_rule(struct pf_rule *r) printf("@%d ", r->nr + 1); if (r->action == PF_PASS) printf("pass "); - else if (r->action == PF_DROP || r->action == PF_DROP_RST) + else if (r->action == PF_DROP) { printf("block "); - else + if (r->return_rst) + printf("return-rst "); + else if (r->return_icmp) { + struct icmpcodeent *ic; + + printf("return-icmp"); + ic = geticmpcodebynumber(r->return_icmp >> 8, + r->return_icmp & 255); + if ((ic == NULL) || (ic->type != ICMP_UNREACH)) + printf("(%u,%u) ", r->return_icmp >> 8, + r->return_icmp & 255); + else if (ic->code != ICMP_UNREACH_PORT) + printf("(%s) ", ic->name); + else + printf(" "); + } + } else printf("scrub "); - if (r->action == 2) - printf("return-rst "); if (r->direction == 0) printf("in "); else @@ -626,10 +640,32 @@ parse_rule(int n, char *l, struct pf_rule *r) } w = next_word(&l); - /* return-rst */ - if ((r->action == PF_DROP) && !strcmp(w, "return-rst")) { - r->action = PF_DROP_RST; - w = next_word(&l); + /* return-rst/return-icmp */ + if (r->action == PF_DROP) { + if (!strcmp(w, "return-rst")) { + r->return_rst = 1; + w = next_word(&l); + } else if (!strncmp(w, "return-icmp", 11)) { + w += 11; + if ((strlen(w) > 2) && (w[0] == '(') && + (w[strlen(w)-1] == ')')) { + struct icmpcodeent *ic; + + w[strlen(w)-1] = 0; + w++; + ic = geticmpcodebyname(ICMP_UNREACH, w); + if (ic == NULL) { + error(n, "expected icmp code, got %s\n", + w); + return (0); + } + r->return_icmp = ic->type << 8; + r->return_icmp |= ic->code; + } else + r->return_icmp = (ICMP_UNREACH << 8) | + ICMP_UNREACH_PORT; + w = next_word(&l); + } } /* in / out */ diff --git a/sys/net/pf.c b/sys/net/pf.c index acd5f1de851..b32f26807b2 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.91 2001/07/01 17:16:03 kjell Exp $ */ +/* $OpenBSD: pf.c,v 1.92 2001/07/01 23:04:44 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -177,8 +177,8 @@ void pf_change_a(u_int32_t *, u_int16_t *, u_int32_t); void pf_change_icmp(u_int32_t *, u_int16_t *, u_int32_t *, u_int32_t, u_int16_t, u_int16_t *, u_int16_t *, u_int16_t *, u_int16_t *); -void pf_send_reset(int, struct ifnet *, struct ip *, int, - struct tcphdr *); +void pf_send_reset(struct ip *, int, struct tcphdr *); +void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t); int pf_match_addr(u_int8_t, u_int32_t, u_int32_t, u_int32_t); int pf_match_port(u_int8_t, u_int16_t, u_int16_t, @@ -1203,10 +1203,10 @@ pf_change_icmp(u_int32_t *ia, u_int16_t *ip, u_int32_t *oa, u_int32_t na, } void -pf_send_reset(int direction, struct ifnet *ifp, struct ip *h, int off, - struct tcphdr *th) +pf_send_reset(struct ip *h, int off, struct tcphdr *th) { struct mbuf *m; + struct m_tag *mtag; int len = sizeof(struct ip) + sizeof(struct tcphdr); struct ip *h2; struct tcphdr *th2; @@ -1216,9 +1216,13 @@ pf_send_reset(int direction, struct ifnet *ifp, struct ip *h, int off, return; /* create outgoing mbuf */ + mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT); + if (mtag == NULL) + return; m = m_gethdr(M_DONTWAIT, MT_HEADER); if (m == NULL) return; + m_tag_prepend(m, mtag); m->m_data += max_linkhdr; m->m_pkthdr.len = m->m_len = len; m->m_pkthdr.rcvif = NULL; @@ -1260,33 +1264,23 @@ pf_send_reset(int direction, struct ifnet *ifp, struct ip *h, int off, /* IP header checksum */ h2->ip_sum = in_cksum(m, sizeof(struct ip)); - if (direction == PF_IN) { - /* set up route and send RST out through the same interface */ - struct route iproute; - struct route *ro = &iproute; - struct sockaddr_in *dst; - int error; - - bzero(ro, sizeof(*ro)); - dst = (struct sockaddr_in *)&ro->ro_dst; - dst->sin_family = AF_INET; - dst->sin_addr = h2->ip_dst; - dst->sin_len = sizeof(*dst); - rtalloc(ro); - if (ro->ro_rt != NULL) - ro->ro_rt->rt_use++; - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, - ro->ro_rt); - } else { - /* send RST through the loopback interface */ - struct sockaddr_in dst; + ip_output(m, NULL, NULL, 0, NULL); +} - dst.sin_family = AF_INET; - dst.sin_addr = h2->ip_dst; - dst.sin_len = sizeof(struct sockaddr_in); - m->m_pkthdr.rcvif = ifp; - looutput(lo0ifp, m, sintosa(&dst), NULL); - } +void +pf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code) +{ + struct m_tag *mtag; + struct mbuf *m0; + + mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT); + if (mtag == NULL) + return; + m0 = m_copy(m, 0, M_COPYALL); + if (m0 == NULL) + return; + m_tag_prepend(m0, mtag); + icmp_error(m0, type, code, 0, 0); } int @@ -1442,7 +1436,8 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, if (rm->log) PFLOG_PACKET(h, m, AF_INET, direction, reason, rm); - if (rm->action == PF_DROP_RST) { + if ((rm->action == PF_DROP) && + (rm->return_rst || rm->return_icmp)) { /* undo NAT/RST changes, if they have taken place */ if (nat != NULL) { pf_change_ap(&h->ip_src.s_addr, &th->th_sport, @@ -1454,9 +1449,11 @@ pf_test_tcp(int direction, struct ifnet *ifp, struct mbuf *m, &h->ip_sum, &th->th_sum, baddr, bport); rewrite++; } - - pf_send_reset(direction, ifp, h, off, th); - return (PF_DROP); + if (rm->return_rst) + pf_send_reset(h, off, th); + else + pf_send_icmp(m, rm->return_icmp >> 8, + rm->return_icmp & 255); } if (rm->action == PF_DROP) @@ -1594,7 +1591,26 @@ pf_test_udp(int direction, struct ifnet *ifp, struct mbuf *m, if (rm->log) PFLOG_PACKET(h, m, AF_INET, direction, reason, rm); - if (rm->action != PF_PASS) + if ((rm->action == PF_DROP) && rm->return_icmp) { + struct mbuf *m0; + struct m_tag *mtag; + + /* undo NAT/RST changes, if they have taken place */ + if (nat != NULL) { + pf_change_ap(&h->ip_src.s_addr, &uh->uh_sport, + &h->ip_sum, &uh->uh_sum, baddr, bport); + rewrite++; + } + else if (rdr != NULL) { + pf_change_ap(&h->ip_dst.s_addr, &uh->uh_dport, + &h->ip_sum, &uh->uh_sum, baddr, bport); + rewrite++; + } + pf_send_icmp(m, rm->return_icmp >> 8, + rm->return_icmp & 255); + } + + if (rm->action == PF_DROP) return (PF_DROP); } @@ -2081,7 +2097,7 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf *m, switch (h2.ip_p) { case IPPROTO_TCP: { struct tcphdr th; - u_int32_t seq, end; + u_int32_t seq; struct pf_state *s; struct pf_tree_key key; struct pf_state_peer *src, *dst; @@ -2098,9 +2114,6 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf *m, return (NULL); } seq = ntohl(th.th_seq); - end = seq + h2.ip_len - ((h2.ip_hl + th.th_off)<<2) + - ((th.th_flags & TH_SYN) ? 1 : 0) + - ((th.th_flags & TH_FIN) ? 1 : 0); key.proto = IPPROTO_TCP; key.addr[0] = h2.ip_dst; @@ -2116,7 +2129,7 @@ pf_test_state_icmp(int direction, struct ifnet *ifp, struct mbuf *m, src = (direction == s->direction) ? &s->dst : &s->src; dst = (direction == s->direction) ? &s->src : &s->dst; - if (!SEQ_GEQ(src->seqhi, end) || + if (!SEQ_GEQ(src->seqhi, seq) || !SEQ_GEQ(seq, src->seqlo - dst->max_win)) { printf("pf: BAD ICMP state: "); @@ -2664,7 +2677,8 @@ pf_test(int dir, struct ifnet *ifp, struct mbuf **m0) struct pf_state *s; int off; - if (!pf_status.running) + if (!pf_status.running || + (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) return (PF_PASS); #ifdef DIAGNOSTIC diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 0ca01b88afb..a60d86fd6ae 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.27 2001/07/01 17:16:03 kjell Exp $ */ +/* $OpenBSD: pfvar.h,v 1.28 2001/07/01 23:04:44 dhartmei Exp $ */ /* * Copyright (c) 2001, Daniel Hartmeier @@ -37,7 +37,7 @@ #include <sys/queue.h> enum { PF_IN=0, PF_OUT=1 }; -enum { PF_PASS=0, PF_DROP=1, PF_DROP_RST=2, PF_SCRUB=3 }; +enum { PF_PASS=0, PF_DROP=1, PF_SCRUB=2 }; enum { PF_OP_GL=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 }; @@ -56,6 +56,9 @@ struct pf_rule { struct pf_rule_addr dst; TAILQ_ENTRY(pf_rule) entries; + u_int16_t nr; + u_int16_t return_icmp; + u_int8_t action; u_int8_t direction; u_int8_t log; @@ -68,7 +71,7 @@ struct pf_rule { u_int8_t flags; u_int8_t flagset; - u_int16_t nr; + u_int8_t return_rst; }; struct pf_state_host { diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index cc4eb966601..2e38599bfd1 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_icmp.c,v 1.39 2001/06/29 18:08:39 provos Exp $ */ +/* $OpenBSD: ip_icmp.c,v 1.40 2001/07/01 23:04:44 dhartmei Exp $ */ /* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */ /* @@ -127,6 +127,7 @@ icmp_error(n, type, code, dest, destifp) register unsigned oiplen = oip->ip_hl << 2; register struct icmp *icp; struct mbuf *m; + struct m_tag *mtag; unsigned icmplen, mblen; #ifdef ICMPPRINTFS @@ -247,6 +248,12 @@ icmp_error(n, type, code, dest, destifp) nip->ip_p = IPPROTO_ICMP; nip->ip_src = oip->ip_src; nip->ip_dst = oip->ip_dst; + /* move PF_GENERATED m_tag to new packet, if it exists */ + mtag = m_tag_find(n, PACKET_TAG_PF_GENERATED, NULL); + if (mtag != NULL) { + m_tag_unlink(n, mtag); + m_tag_prepend(m, mtag); + } icmp_reflect(m); freeit: diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h index ed3d948784f..c7638afa64b 100644 --- a/sys/sys/mbuf.h +++ b/sys/sys/mbuf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mbuf.h,v 1.48 2001/06/27 03:49:55 angelos Exp $ */ +/* $OpenBSD: mbuf.h,v 1.49 2001/07/01 23:04:44 dhartmei Exp $ */ /* $NetBSD: mbuf.h,v 1.19 1996/02/09 18:25:14 christos Exp $ */ /* @@ -595,6 +595,7 @@ struct m_tag *m_tag_next __P((struct mbuf *, struct m_tag *)); #define PACKET_TAG_GIF 8 /* GIF processing done */ #define PACKET_TAG_GRE 9 /* GRE processing done */ #define PACKET_TAG_IN_PACKET_CHECKSUM 10 /* NIC checksumming done */ +#define PACKET_TAG_PF_GENERATED 11 /* PF generated, pass always */ #ifdef MBTYPES int mbtypes[] = { /* XXX */ |