Patch to eliminate infinite recursion via pf_route whilst maintaining reply-to and dup-to's ability to route/duplicate packets onto another interface, and remaining compatibility with OPENBSD_3_5_RELEASE. This is the second revision of this patch - the first handled 'fastroute' incorrectly. Chris Pascoe 2004/05/09 Index: pf.c =================================================================== RCS file: /cvs/src/sys/net/pf.c,v retrieving revision 1.433.2.1 diff -u -r1.433.2.1 pf.c --- pf.c 30 Apr 2004 21:46:33 -0000 1.433.2.1 +++ pf.c 09 May 2004 13:59:15 -0000 @@ -4836,14 +4836,25 @@ (dir != PF_IN && dir != PF_OUT) || oifp == NULL) panic("pf_route: invalid parameters"); - if (r->rt == PF_DUPTO) { + mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL); + if (dir == PF_IN && mtag != NULL) { + /* We are routing a packet on the input side that was + * previously routed and sent back to us. If they'd + * wanted it to end up anywhere valid we wouldn't be + * re-routing it. Break the potential loop. + */ m0 = *m; - mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL); + *m = NULL; + goto bad; + } + + if (r->rt == PF_DUPTO) { if (mtag == NULL) { - mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 0, M_NOWAIT); + mtag = m_tag_get(PACKET_TAG_PF_ROUTED, sizeof(struct pf_rule *), M_NOWAIT); if (mtag == NULL) goto bad; - m_tag_prepend(m0, mtag); + *(struct pf_rule **)(mtag + 1) = NULL; + m_tag_prepend(*m, mtag); } m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT); if (m0 == NULL) @@ -4898,21 +4909,29 @@ 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) { - if (pf_test(PF_OUT, ifp, &m0) != PF_PASS) + if (mtag == NULL) { + mtag = m_tag_get(PACKET_TAG_PF_ROUTED, sizeof(struct pf_rule *), M_NOWAIT); + if (mtag == NULL) goto bad; - else if (m0 == NULL) - goto done; - if (m0->m_len < sizeof(struct ip)) - panic("pf_route: m0->m_len < sizeof(struct ip)"); - ip = mtod(m0, struct ip *); + *(struct pf_rule **)(mtag + 1) = r; + m_tag_prepend(m0, mtag); + + if (oifp != ifp) { + if (pf_test(PF_OUT, ifp, &m0) != PF_PASS) + goto bad; + else if (m0 == NULL) + goto done; + + if (m0->m_len < sizeof(struct ip)) + panic("pf_route: m0->m_len < sizeof(struct ip)"); + ip = mtod(m0, struct ip *); + } + } else if (oifp != ifp && (*(struct pf_rule **)(mtag + 1)) == r) { + /* The same cross-interface rule matched twice - + * this means the packet has made a loop through + * the system and will go the same way again. + * Break the loop. */ + goto bad; } /* Copied from ip_output. */ @@ -4986,6 +5005,18 @@ for (m0 = m1; m0; m0 = m1) { m1 = m0->m_nextpkt; m0->m_nextpkt = 0; + + /* Copy the tag onto the next fragment, so we can drop it + * if it is received again. */ + mtag = m_tag_find(m0, PACKET_TAG_PF_ROUTED, NULL); + if (mtag != NULL && m1 != NULL) { + if ((mtag = m_tag_copy(mtag)) == NULL) { + error = ENOBUFS; + } else { + m_tag_prepend(m1, mtag); + } + } + if (error == 0) error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);