Merge in a stable fix from OpenBSD:

MFC:
  Fix by dhartmei@

  change pf_route() loop detection: introduce a counter (number of times
  a packet is routed already) in the mbuf tag, allow at most four times.
  Fixes some legitimate cases broken by the previous change.

Reviewed by:	dhartmei
This commit is contained in:
Max Laier 2004-07-17 17:15:15 +00:00
parent ffd446110e
commit 0ad9506fab

View File

@ -1,5 +1,5 @@
/* $FreeBSD$ */
/* $OpenBSD: pf.c,v 1.433.2.1 2004/04/30 21:46:33 brad Exp $ */
/* $OpenBSD: pf.c,v 1.433.2.2 2004/07/17 03:22:34 brad Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@ -5119,12 +5119,12 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
struct pf_state *s)
{
struct mbuf *m0, *m1;
struct m_tag *mtag;
struct route iproute;
struct route *ro = NULL; /* XXX: was uninitialized */
struct sockaddr_in *dst;
struct ip *ip;
struct ifnet *ifp = NULL;
struct m_tag *mtag;
struct pf_addr naddr;
struct pf_src_node *sn = NULL;
int error = 0;
@ -5136,22 +5136,34 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
(dir != PF_IN && dir != PF_OUT) || oifp == NULL)
panic("pf_route: invalid parameters");
if (r->rt == PF_DUPTO) {
m0 = *m;
mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL);
if (mtag == NULL) {
mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT);
if (mtag == NULL)
goto bad;
m_tag_prepend(m0, mtag);
if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
NULL) {
m0 = *m;
*m = NULL;
goto bad;
}
*(char *)(mtag + 1) = 1;
m_tag_prepend(*m, mtag);
} else {
if (*(char *)(mtag + 1) > 3) {
m0 = *m;
*m = NULL;
goto bad;
}
(*(char *)(mtag + 1))++;
}
if (r->rt == PF_DUPTO) {
#ifdef __FreeBSD__
m0 = m_dup(*m, M_DONTWAIT);
if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
#else
m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT);
if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
#endif
if (m0 == NULL)
return;
if ((mtag = m_tag_copy(mtag)) == NULL)
goto bad;
m_tag_prepend(m0, mtag);
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir))
return;
@ -5198,17 +5210,9 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
}
}
if (ifp == NULL)
goto bad;
if (m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL) != NULL)
goto bad;
mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT);
if (mtag == NULL)
goto bad;
m_tag_prepend(m0, mtag);
if (oifp != ifp) {
#ifdef __FreeBSD__
PF_UNLOCK();
@ -5415,22 +5419,34 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
(dir != PF_IN && dir != PF_OUT) || oifp == NULL)
panic("pf_route6: invalid parameters");
if (r->rt == PF_DUPTO) {
m0 = *m;
mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL);
if (mtag == NULL) {
mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT);
if (mtag == NULL)
goto bad;
m_tag_prepend(m0, mtag);
if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
NULL) {
m0 = *m;
*m = NULL;
goto bad;
}
*(char *)(mtag + 1) = 1;
m_tag_prepend(*m, mtag);
} else {
if (*(char *)(mtag + 1) > 3) {
m0 = *m;
*m = NULL;
goto bad;
}
(*(char *)(mtag + 1))++;
}
if (r->rt == PF_DUPTO) {
#ifdef __FreeBSD__
m0 = m_dup(*m, M_DONTWAIT);
if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
#else
m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT);
if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
#endif
if (m0 == NULL)
return;
if ((mtag = m_tag_copy(mtag)) == NULL)
goto bad;
m_tag_prepend(m0, mtag);
} else {
if ((r->rt == PF_REPLYTO) == (r->direction == dir))
return;
@ -5480,34 +5496,29 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
&s->rt_addr, AF_INET6);
ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
}
if (ifp == NULL)
goto bad;
if (oifp != ifp) {
mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL);
if (mtag == NULL) {
mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT);
if (mtag == NULL)
goto bad;
m_tag_prepend(m0, mtag);
#ifdef __FreeBSD__
PF_UNLOCK();
if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS) {
PF_LOCK();
goto bad;
} else if (m0 == NULL) {
PF_LOCK();
goto done;
}
PF_UNLOCK();
if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS) {
PF_LOCK();
#else
if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
#endif
goto bad;
} else if (m0 == NULL) {
PF_LOCK();
goto done;
}
PF_LOCK();
#else
if (pf_test6(PF_OUT, ifp, &m0) != PF_PASS)
goto bad;
else if (m0 == NULL)
goto done;
#endif
if (m0->m_len < sizeof(struct ip6_hdr))
panic("pf_route6: m0->m_len < sizeof(struct ip6_hdr)");
ip6 = mtod(m0, struct ip6_hdr *);
}
/*