NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/56052: NPF: block return... processes the return packet again
>Number: 56052
>Category: kern
>Synopsis: NPF: block return... processes the return packet again
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Mar 12 09:00:00 +0000 2021
>Originator: Frank Kardel
>Release: NetBSD 9.99.81
>Organization:
>Environment:
System: NetBSD gateway 9.99.81 NetBSD 9.99.81 (GATEWAY) #9: Fri Mar 12 07:41:46 UTC 2021 kardel@gateway:/src/NetBSD/cur/src/obj.amd64/sys/arch/amd64/compile/GATEWAY amd64
Architecture: x86_64
Machine: amd64
>Description:
A ruleset like
group "name" on <interface> {
pass in final ...
pass in final ...
block return in final all apply "log"
}
will not send out any TCP-RST or ICMP(,6} unreachable pakets as the
block-return packets pass again through the NPF filter engine on
their way out. block-return packets are sent via ip{,6}_output() and
icmp{,6}_error().
This can be observed via the npflogX interface.
block-return packets must skip outgoing packet rules to avoid
to add workaround rules like
# allow for block return packets
pass out final proto tcp all apply "log"
pass out final proto icmp all apply "log"
before the block-return rule. this workaround allows also unwanted
communication. more precise rules require pcap-filter
rules and may still be incomplete.
as the workarounds are hard to manage and hard to explain to
users NPF needs to be fixed to work like other packet filters
so that is does not examine its own block-return packets.
see Fix: below
I will commit the fix if no objections arise.
>How-To-Repeat:
Have a ruleset like
group "name" on <interface> {
pass in final ...
pass in final ...
block return in final all apply "log"
}
send packets that are not matched by the pass in rules. observe
via npflogX that the block-return packet pass the filter rules
in out direct and they get finally dropped.
>Fix:
to fix the iss the block-return packets need to be marked
with the PACKET_TAG_NPF tag so the NPF filter engine will
automatically pass these packets without rule processing.
there is an issue in ip_icmp.c (IPv4 ICMP) in icmp_error.
as it create a new packet the tags must be transferred. the
the current code only knows about PACKAGE_TAG_PF. This needs to
be extended.
see the following patch for fixing the NPF block-return
functionality.
Index: sys/net/npf/npf.h
===================================================================
RCS file: /cvsroot/src/sys/net/npf/npf.h,v
retrieving revision 1.63
diff -u -r1.63 npf.h
--- sys/net/npf/npf.h 30 May 2020 14:16:56 -0000 1.63
+++ sys/net/npf/npf.h 12 Mar 2021 08:00:18 -0000
@@ -121,7 +121,9 @@
void * nbuf_ensure_writable(nbuf_t *, size_t);
bool nbuf_cksum_barrier(nbuf_t *, int);
+int mbuf_add_tag(nbuf_t *, struct mbuf *, uint32_t);
int nbuf_add_tag(nbuf_t *, uint32_t);
+int mbuf_find_tag(nbuf_t *, struct mbuf *, uint32_t *);
int nbuf_find_tag(nbuf_t *, uint32_t *);
/*
Index: sys/net/npf/npf_mbuf.c
===================================================================
RCS file: /cvsroot/src/sys/net/npf/npf_mbuf.c,v
retrieving revision 1.24
diff -u -r1.24 npf_mbuf.c
--- sys/net/npf/npf_mbuf.c 30 May 2020 14:16:56 -0000 1.24
+++ sys/net/npf/npf_mbuf.c 12 Mar 2021 08:00:18 -0000
@@ -297,14 +297,13 @@
}
/*
- * nbuf_add_tag: associate a tag with the network buffer.
+ * mbuf_add_tag: associate a tag with the network buffer.
*
* => Returns 0 on success or error number on failure.
*/
int
-nbuf_add_tag(nbuf_t *nbuf, uint32_t val)
+mbuf_add_tag(nbuf_t *nbuf, struct mbuf *m, uint32_t val)
{
- struct mbuf *m = nbuf->nb_mbuf0;
#ifdef _KERNEL
struct m_tag *mt;
uint32_t *dat;
@@ -328,14 +327,25 @@
}
/*
- * nbuf_find_tag: find a tag associated with a network buffer.
+ * nbuf_add_tag: associate a tag with the network buffer.
*
* => Returns 0 on success or error number on failure.
*/
int
-nbuf_find_tag(nbuf_t *nbuf, uint32_t *val)
+nbuf_add_tag(nbuf_t *nbuf, uint32_t val)
{
struct mbuf *m = nbuf->nb_mbuf0;
+ return mbuf_add_tag(nbuf, m, val);
+}
+
+/*
+ * mbuf_find_tag: find a tag associated with a network buffer.
+ *
+ * => Returns 0 on success or error number on failure.
+ */
+int
+mbuf_find_tag(nbuf_t *nbuf, struct mbuf *m, uint32_t *val)
+{
#ifdef _KERNEL
struct m_tag *mt;
@@ -354,3 +364,15 @@
return nbuf->nb_mops->get_tag(m, val);
#endif
}
+
+/*
+ * nbuf_find_tag: find a tag associated with a network buffer.
+ *
+ * => Returns 0 on success or error number on failure.
+ */
+int
+nbuf_find_tag(nbuf_t *nbuf, uint32_t *val)
+{
+ struct mbuf *m = nbuf->nb_mbuf0;
+ return mbuf_find_tag(nbuf, m, val);
+}
Index: sys/net/npf/npf_sendpkt.c
===================================================================
RCS file: /cvsroot/src/sys/net/npf/npf_sendpkt.c,v
retrieving revision 1.22
diff -u -r1.22 npf_sendpkt.c
--- sys/net/npf/npf_sendpkt.c 30 May 2020 14:16:56 -0000 1.22
+++ sys/net/npf/npf_sendpkt.c 12 Mar 2021 08:00:18 -0000
@@ -197,6 +197,9 @@
}
}
+ /* don't look at our generated reject packets going out */
+ (void)mbuf_add_tag(npc->npc_nbuf, m, NPF_NTAG_PASS);
+
/* Pass to IP layer. */
if (npf_iscached(npc, NPC_IP4)) {
return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
@@ -215,6 +218,9 @@
{
struct mbuf *m = nbuf_head_mbuf(npc->npc_nbuf);
+ /* don't look at our generated reject packets going out */
+ (void)mbuf_add_tag(npc->npc_nbuf, m, NPF_NTAG_PASS);
+
if (npf_iscached(npc, NPC_IP4)) {
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_ADMIN_PROHIBIT, 0, 0);
return 0;
Index: sys/netinet/ip_icmp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.177
diff -u -r1.177 ip_icmp.c
--- sys/netinet/ip_icmp.c 22 Dec 2018 14:28:57 -0000 1.177
+++ sys/netinet/ip_icmp.c 12 Mar 2021 08:00:19 -0000
@@ -165,6 +165,10 @@
static int icmp_redirtimeout = 600;
static struct rttimer_queue *icmp_redirect_timeout_q = NULL;
+/* packet filter m_tag helpers */
+static void move_mtag(int, struct mbuf*, struct mbuf *);
+static void clear_non_pf_mtags(struct mbuf *);
+
/* Protect mtudisc and redirect stuff */
static kmutex_t icmp_mtx __cacheline_aligned;
@@ -237,6 +241,22 @@
}
/*
+ * Move a specified m_tag from soure mbuf to target mbuf
+ */
+static void
+move_mtag(int type, struct mbuf *s, struct mbuf *t)
+{
+ struct m_tag *mtag;
+
+ mtag = m_tag_find(s, type);
+
+ if (mtag != NULL) {
+ m_tag_unlink(s, mtag);
+ m_tag_prepend(t, mtag);
+ }
+}
+
+/*
* Generate an error packet of type error in response to a bad IP packet. 'n'
* contains this packet. We create 'm' and send it.
*
@@ -254,7 +274,6 @@
const unsigned oiphlen = oip->ip_hl << 2;
struct icmp *icp;
struct mbuf *m;
- struct m_tag *mtag;
unsigned datalen, mblen;
int totlen;
@@ -381,12 +400,10 @@
nip->ip_p = IPPROTO_ICMP;
nip->ip_src = oip->ip_src;
nip->ip_dst = oip->ip_dst;
- /* move PF m_tag to new packet, if it exists */
- mtag = m_tag_find(n, PACKET_TAG_PF);
- if (mtag != NULL) {
- m_tag_unlink(n, mtag);
- m_tag_prepend(m, mtag);
- }
+
+ /* move packet filter tags */
+ move_mtag(PACKET_TAG_NPF, n, m);
+ move_mtag(PACKET_TAG_PF, n, m);
icmp_reflect(m);
@@ -699,6 +716,39 @@
}
/*
+ * clear all non packet filter mtags
+ */
+static void
+clear_non_pf_mtags(struct mbuf *m)
+{
+ struct m_tag * mtag_npf = NULL;
+ struct m_tag * mtag_pf = NULL;
+
+ mtag_npf = m_tag_find(m, PACKET_TAG_NPF);
+ if (mtag_npf != NULL) {
+ m_tag_unlink(m, mtag_npf);
+ }
+
+ mtag_pf = m_tag_find(m, PACKET_TAG_PF);
+ if (mtag_pf != NULL) {
+ m_tag_unlink(m, mtag_pf);
+ }
+
+ /* remove all other tags */
+ m_tag_delete_chain(m);
+
+ /* recover tag for PF */
+ if (mtag_pf != NULL) {
+ m_tag_prepend(m, mtag_pf);
+ }
+
+ /* recover tag for NPF */
+ if (mtag_npf != NULL) {
+ m_tag_prepend(m, mtag_npf);
+ }
+}
+
+/*
* Reflect the ip packet back to the source
*/
void
@@ -919,7 +969,10 @@
memmove(ip + 1, (char *)ip + optlen,
(unsigned)(m->m_len - sizeof(struct ip)));
}
- m_tag_delete_chain(m);
+
+ /* remove all non packet filter mtags */
+ clear_non_pf_mtags(m);
+
m->m_flags &= ~(M_BCAST|M_MCAST);
/*
>Unformatted:
Home |
Main Index |
Thread Index |
Old Index