Date: Tue, 23 Oct 2007 16:25:10 +0400 From: "Andrey V. Elsukov" <bu7cher@yandex.ru> To: Peter Kieser <peter@wingless.org> Cc: Max Laier <mlaier@FreeBSD.org>, freebsd-current@freebsd.org Subject: Re: ipfw2 keep-state + IPv6 on RELENG_7 Message-ID: <471DE826.2050309@yandex.ru> In-Reply-To: <471CFD53.7080608@wingless.org> References: <471CFD53.7080608@wingless.org>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Peter Kieser wrote:
> Any hints? Is IPv6 + keep-state broken on RELENG_7 or have I missed
> something obvious?
There is an issue with IPv6 keep-alives. Max Laier have a patch that
needs testing. You can try it.
--
WBR, Andrey V. Elsukov
[-- Attachment #2 --]
Index: ip_fw2.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.175
diff -u -r1.175 ip_fw2.c
--- ip_fw2.c 7 Oct 2007 20:44:23 -0000 1.175
+++ ip_fw2.c 19 Oct 2007 12:38:16 -0000
@@ -98,6 +98,7 @@
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#ifdef INET6
+#include <netinet6/ip6_var.h>
#include <netinet6/scope6_var.h>
#endif
@@ -241,6 +242,9 @@
#define IPFW_DYN_UNLOCK() mtx_unlock(&ipfw_dyn_mtx)
#define IPFW_DYN_LOCK_ASSERT() mtx_assert(&ipfw_dyn_mtx, MA_OWNED)
+static struct mbuf *send_pkt(struct mbuf *, struct ipfw_flow_id *,
+ u_int32_t, u_int32_t, int);
+
/*
* Timeouts for various events in handing dynamic rules.
*/
@@ -671,67 +675,25 @@
}
static void
-send_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_hdr *ip6)
+send_reject6(struct ip_fw_args *args, int code, u_int hlen,
+ struct ip6_hdr *ip6)
{
struct mbuf *m;
m = args->m;
if (code == ICMP6_UNREACH_RST && args->f_id.proto == IPPROTO_TCP) {
struct tcphdr *tcp;
- tcp_seq ack, seq;
- int flags;
- struct {
- struct ip6_hdr ip6;
- struct tcphdr th;
- } ti;
tcp = (struct tcphdr *)((char *)ip6 + hlen);
- if ((tcp->th_flags & TH_RST) != 0) {
- m_freem(m);
- args->m = NULL;
- return;
- }
-
- ti.ip6 = *ip6;
- ti.th = *tcp;
- ti.th.th_seq = ntohl(ti.th.th_seq);
- ti.th.th_ack = ntohl(ti.th.th_ack);
- ti.ip6.ip6_nxt = IPPROTO_TCP;
-
- if (ti.th.th_flags & TH_ACK) {
- ack = 0;
- seq = ti.th.th_ack;
- flags = TH_RST;
- } else {
- ack = ti.th.th_seq;
- if ((m->m_flags & M_PKTHDR) != 0) {
- /*
- * total new data to ACK is:
- * total packet length,
- * minus the header length,
- * minus the tcp header length.
- */
- ack += m->m_pkthdr.len - hlen
- - (ti.th.th_off << 2);
- } else if (ip6->ip6_plen) {
- ack += ntohs(ip6->ip6_plen) + sizeof(*ip6) -
- hlen - (ti.th.th_off << 2);
- } else {
- m_freem(m);
- return;
- }
- if (tcp->th_flags & TH_SYN)
- ack++;
- seq = 0;
- flags = TH_RST|TH_ACK;
+ if ((tcp->th_flags & TH_RST) == 0) {
+ struct mbuf *m0;
+ m0 = send_pkt(args->m, &(args->f_id),
+ ntohl(tcp->th_seq), ntohl(tcp->th_ack),
+ tcp->th_flags | TH_RST);
+ if (m0 != NULL)
+ ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
}
- bcopy(&ti, ip6, sizeof(ti));
- /*
- * m is only used to recycle the mbuf
- * The data in it is never read so we don't need
- * to correct the offsets or anything
- */
- tcp_respond(NULL, ip6, tcp, m, ack, seq, flags);
+ m_freem(m);
} else if (code != ICMP6_UNREACH_RST) { /* Send an ICMPv6 unreach. */
#if 0
/*
@@ -1609,13 +1571,16 @@
u_int32_t ack, int flags)
{
struct mbuf *m;
- struct ip *ip;
- struct tcphdr *tcp;
+ int len, dir;
+ struct ip *h = NULL; /* stupid compiler */
+#ifdef INET6
+ struct ip6_hdr *h6 = NULL;
+#endif
+ struct tcphdr *th = NULL;
MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == 0)
+ if (m == NULL)
return (NULL);
- m->m_pkthdr.rcvif = (struct ifnet *)0;
#ifdef MAC
if (replyto != NULL)
@@ -1626,67 +1591,118 @@
(void)replyto; /* don't warn about unused arg */
#endif
- m->m_pkthdr.len = m->m_len = sizeof(struct ip) + sizeof(struct tcphdr);
+ switch (id->addr_type) {
+ case 4:
+ len = sizeof(struct ip) + sizeof(struct tcphdr);
+ break;
+#ifdef INET6
+ case 6:
+ len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
+ break;
+#endif
+ default:
+ /* XXX: log me?!? */
+ m_freem(m);
+ return (NULL);
+ }
+ dir = ((flags & (TH_SYN | TH_RST)) == TH_SYN);
+
m->m_data += max_linkhdr;
+ m->m_flags |= M_SKIP_FIREWALL;
+ m->m_pkthdr.len = m->m_len = len;
+ m->m_pkthdr.rcvif = NULL;
+ bzero(m->m_data, len);
+
+ switch (id->addr_type) {
+ case 4:
+ h = mtod(m, struct ip *);
+
+ /* prepare for checksum */
+ h->ip_p = IPPROTO_TCP;
+ h->ip_len = htons(sizeof(struct tcphdr));
+ if (dir) {
+ h->ip_src.s_addr = htonl(id->src_ip);
+ h->ip_dst.s_addr = htonl(id->dst_ip);
+ } else {
+ h->ip_src.s_addr = htonl(id->dst_ip);
+ h->ip_dst.s_addr = htonl(id->src_ip);
+ }
- ip = mtod(m, struct ip *);
- bzero(ip, m->m_len);
- tcp = (struct tcphdr *)(ip + 1); /* no IP options */
- ip->ip_p = IPPROTO_TCP;
- tcp->th_off = 5;
- /*
- * Assume we are sending a RST (or a keepalive in the reverse
- * direction), swap src and destination addresses and ports.
- */
- ip->ip_src.s_addr = htonl(id->dst_ip);
- ip->ip_dst.s_addr = htonl(id->src_ip);
- tcp->th_sport = htons(id->dst_port);
- tcp->th_dport = htons(id->src_port);
- if (flags & TH_RST) { /* we are sending a RST */
+ th = (struct tcphdr *)(h + 1);
+ break;
+#ifdef INET6
+ case 6:
+ h6 = mtod(m, struct ip6_hdr *);
+
+ /* prepare for checksum */
+ h6->ip6_nxt = IPPROTO_TCP;
+ h6->ip6_plen = htons(sizeof(struct tcphdr));
+ if (dir) {
+ h6->ip6_src = id->src_ip6;
+ h6->ip6_dst = id->dst_ip6;
+ } else {
+ h6->ip6_src = id->dst_ip6;
+ h6->ip6_dst = id->src_ip6;
+ }
+
+ th = (struct tcphdr *)(h6 + 1);
+ break;
+#endif
+ }
+
+ if (dir) {
+ th->th_sport = id->src_port;
+ th->th_dport = id->dst_port;
+ } else {
+ th->th_sport = id->dst_port;
+ th->th_dport = id->src_port;
+ }
+ th->th_off = sizeof(struct tcphdr) >> 2;
+
+ if (flags & TH_RST) {
if (flags & TH_ACK) {
- tcp->th_seq = htonl(ack);
- tcp->th_ack = htonl(0);
- tcp->th_flags = TH_RST;
+ th->th_seq = htonl(ack);
+ th->th_flags = TH_RST;
} else {
if (flags & TH_SYN)
seq++;
- tcp->th_seq = htonl(0);
- tcp->th_ack = htonl(seq);
- tcp->th_flags = TH_RST | TH_ACK;
+ th->th_ack = htonl(seq);
+ th->th_flags = TH_RST | TH_ACK;
}
} else {
/*
- * We are sending a keepalive. flags & TH_SYN determines
- * the direction, forward if set, reverse if clear.
- * NOTE: seq and ack are always assumed to be correct
- * as set by the caller. This may be confusing...
+ * Keepalive - use caller provided sequence numbers
*/
- if (flags & TH_SYN) {
- /*
- * we have to rewrite the correct addresses!
- */
- ip->ip_dst.s_addr = htonl(id->dst_ip);
- ip->ip_src.s_addr = htonl(id->src_ip);
- tcp->th_dport = htons(id->dst_port);
- tcp->th_sport = htons(id->src_port);
- }
- tcp->th_seq = htonl(seq);
- tcp->th_ack = htonl(ack);
- tcp->th_flags = TH_ACK;
+ th->th_seq = htonl(seq);
+ th->th_ack = htonl(ack);
+ th->th_flags = TH_ACK;
+ }
+
+ switch (id->addr_type) {
+ case 4:
+ th->th_sum = in_cksum(m, len);
+
+ /* finish the ip header */
+ h->ip_v = 4;
+ h->ip_hl = sizeof(*h) >> 2;
+ h->ip_tos = IPTOS_LOWDELAY;
+ h->ip_off = 0;
+ h->ip_len = len;
+ h->ip_ttl = ip_defttl;
+ h->ip_sum = 0;
+ break;
+#ifdef INET6
+ case 6:
+ th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(*h6),
+ sizeof(struct tcphdr));
+
+ /* finish the ip6 header */
+ h6->ip6_vfc |= IPV6_VERSION;
+ h6->ip6_hlim = IPV6_DEFHLIM;
+ break;
+#endif
}
- /*
- * set ip_len to the payload size so we can compute
- * the tcp checksum on the pseudoheader
- * XXX check this, could save a couple of words ?
- */
- ip->ip_len = htons(sizeof(struct tcphdr));
- tcp->th_sum = in_cksum(m, m->m_pkthdr.len);
- /*
- * now fill fields left out earlier
- */
- ip->ip_ttl = ip_defttl;
- ip->ip_len = m->m_pkthdr.len;
- m->m_flags |= M_SKIP_FIREWALL;
+
return (m);
}
@@ -4860,6 +4876,9 @@
ipfw_tick(void * __unused unused)
{
struct mbuf *m0, *m, *mnext, **mtailp;
+#ifdef INET6
+ struct mbuf *m6, **m6_tailp;
+#endif
int i;
ipfw_dyn_rule *q;
@@ -4874,6 +4893,10 @@
*/
m0 = NULL;
mtailp = &m0;
+#ifdef INET6
+ m6 = NULL;
+ m6_tailp = &m6;
+#endif
IPFW_DYN_LOCK();
for (i = 0 ; i < curr_dyn_buckets ; i++) {
for (q = ipfw_dyn_v[i] ; q ; q = q->next ) {
@@ -4889,14 +4912,37 @@
if (TIME_LEQ(q->expire, time_uptime))
continue; /* too late, rule expired */
- *mtailp = send_pkt(NULL, &(q->id), q->ack_rev - 1,
+ m = send_pkt(NULL, &(q->id), q->ack_rev - 1,
q->ack_fwd, TH_SYN);
- if (*mtailp != NULL)
- mtailp = &(*mtailp)->m_nextpkt;
- *mtailp = send_pkt(NULL, &(q->id), q->ack_fwd - 1,
+ mnext = send_pkt(NULL, &(q->id), q->ack_fwd - 1,
q->ack_rev, 0);
- if (*mtailp != NULL)
- mtailp = &(*mtailp)->m_nextpkt;
+
+ switch (q->id.addr_type) {
+ case 4:
+ if (m != NULL) {
+ *mtailp = m;
+ mtailp = &(*mtailp)->m_nextpkt;
+ }
+ if (mnext != NULL) {
+ *mtailp = mnext;
+ mtailp = &(*mtailp)->m_nextpkt;
+ }
+ break;
+#ifdef INET6
+ case 6:
+ if (m != NULL) {
+ *m6_tailp = m;
+ m6_tailp = &(*m6_tailp)->m_nextpkt;
+ }
+ if (mnext != NULL) {
+ *m6_tailp = mnext;
+ m6_tailp = &(*m6_tailp)->m_nextpkt;
+ }
+ break;
+#endif
+ }
+
+ m = mnext = NULL;
}
}
IPFW_DYN_UNLOCK();
@@ -4905,6 +4951,13 @@
m->m_nextpkt = NULL;
ip_output(m, NULL, NULL, 0, NULL, NULL);
}
+#ifdef INET6
+ for (m = mnext = m6; m != NULL; m = mnext) {
+ mnext = m->m_nextpkt;
+ m->m_nextpkt = NULL;
+ ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+ }
+#endif
done:
callout_reset(&ipfw_timeout, dyn_keepalive_period*hz, ipfw_tick, NULL);
}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?471DE826.2050309>
