Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Oct 2007 14:50:49 +0200
From:      Max Laier <max@love2party.net>
To:        freebsd-ipfw@freebsd.org
Cc:        john.w.court@nokia.com
Subject:   Re: Send_pkt()  does it support IPV6 ?
Message-ID:  <200710191450.56014.max@love2party.net>
In-Reply-To: <200710160916.05510.max@love2party.net>
References:  <DBA4167E9E1EB44D8476A6F928BE52450EDDC9@siebe101.NOE.Nokia.com> <200710160916.05510.max@love2party.net>

next in thread | previous in thread | raw e-mail | index | archive | help
--nextPart1730097.U4u31Cs6Nl
Content-Type: multipart/mixed;
  boundary="Boundary-01=_qgKGHg+rBYy2qDj"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

--Boundary-01=_qgKGHg+rBYy2qDj
Content-Type: text/plain;
  charset="iso-8859-6"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

On Tuesday 16 October 2007, I wrote:
> On Tuesday 16 October 2007, john.w.court@nokia.com wrote:
> > Hi,
> >
> > Sorry if I have missed something blindingly obvious, but I can't see
> > how the send_pkt() routine in ip_fw2.c would create a valid ipv6
> > source and destination address.  This is relevent due to its use in
> > ipfw_tick(). Basically in an ipv6 configuration when ipfw_tick() goes
> > off to send a keep-alive, I think send_pkt() would produce an
> > erroneous IPV4 style packet due to its use of id->dst_ip and
> > id->src_ip rather than  dst_ip6 and src_ip6 ?   Further, ipfw_tick()
> > then calls ip_output() rather than any ip6_output() routine.
> >
> > I am just checking before I make any modifications that I am not
> > missing something fundamental that invalidates my analysis.
>
> I don't think you are missing something.  IPv6 support in ipfw is still
> a second class citizen (as is stateful filtering).  I remember seeing a
> mail with similar topic just recently, but can't recall on which list
> or from whom.
>
> I don't see a PR for this - could you please create one so it's not
> forgotten about?

Here is a patch - completely untested as of yet.  I just finished typing=20
and have to run out for a bit, if anyone would like to give it a spin or=20
review in the meantime, please let me know of your findings.

BTW, the PR is kern/117234.  I'll add this patch to the trail as soon as I=
=20
had a chance to give it a try.

=2D-=20
/"\  Best regards,                      | mlaier@freebsd.org
\ /  Max Laier                          | ICQ #67774661
 X   http://pf4freebsd.love2party.net/  | mlaier@EFnet
/ \  ASCII Ribbon Campaign              | Against HTML Mail and News

--Boundary-01=_qgKGHg+rBYy2qDj
Content-Type: text/x-diff;
  charset="iso-8859-6";
  name="ipfw_v6send.diff"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="ipfw_v6send.diff"

Index: ip_fw2.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /home/ncvs/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.175
diff -u -r1.175 ip_fw2.c
=2D-- 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
=20
@@ -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)
=20
+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 @@
 }
=20
 static void
=2Dsend_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_h=
dr *ip6)
+send_reject6(struct ip_fw_args *args, int code, u_int hlen,
+    struct ip6_hdr *ip6)
 {
 	struct mbuf *m;
=20
 	m =3D args->m;
 	if (code =3D=3D ICMP6_UNREACH_RST && args->f_id.proto =3D=3D IPPROTO_TCP)=
 {
 		struct tcphdr *tcp;
=2D		tcp_seq ack, seq;
=2D		int flags;
=2D		struct {
=2D			struct ip6_hdr ip6;
=2D			struct tcphdr th;
=2D		} ti;
 		tcp =3D (struct tcphdr *)((char *)ip6 + hlen);
=20
=2D		if ((tcp->th_flags & TH_RST) !=3D 0) {
=2D			m_freem(m);
=2D			args->m =3D NULL;
=2D			return;
=2D		}
=2D
=2D		ti.ip6 =3D *ip6;
=2D		ti.th =3D *tcp;
=2D		ti.th.th_seq =3D ntohl(ti.th.th_seq);
=2D		ti.th.th_ack =3D ntohl(ti.th.th_ack);
=2D		ti.ip6.ip6_nxt =3D IPPROTO_TCP;
=2D
=2D		if (ti.th.th_flags & TH_ACK) {
=2D			ack =3D 0;
=2D			seq =3D ti.th.th_ack;
=2D			flags =3D TH_RST;
=2D		} else {
=2D			ack =3D ti.th.th_seq;
=2D			if ((m->m_flags & M_PKTHDR) !=3D 0) {
=2D				/*
=2D				 * total new data to ACK is:
=2D				 * total packet length,
=2D				 * minus the header length,
=2D				 * minus the tcp header length.
=2D				 */
=2D				ack +=3D m->m_pkthdr.len - hlen
=2D					- (ti.th.th_off << 2);
=2D			} else if (ip6->ip6_plen) {
=2D				ack +=3D ntohs(ip6->ip6_plen) + sizeof(*ip6) -
=2D				    hlen - (ti.th.th_off << 2);
=2D			} else {
=2D				m_freem(m);
=2D				return;
=2D			}
=2D			if (tcp->th_flags & TH_SYN)
=2D				ack++;
=2D			seq =3D 0;
=2D			flags =3D TH_RST|TH_ACK;
+		if ((tcp->th_flags & TH_RST) =3D=3D 0) {
+			struct mbuf *m0;
+			m0 =3D send_pkt(args->m, &(args->f_id),
+				ntohl(tcp->th_seq), ntohl(tcp->th_ack),
+				tcp->th_flags | TH_RST);
+			if (m0 !=3D NULL)
+				ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
 		}
=2D		bcopy(&ti, ip6, sizeof(ti));
=2D		/*
=2D		 * m is only used to recycle the mbuf
=2D		 * The data in it is never read so we don't need
=2D		 * to correct the offsets or anything
=2D		 */
=2D		tcp_respond(NULL, ip6, tcp, m, ack, seq, flags);
+		m_freem(m);
 	} else if (code !=3D ICMP6_UNREACH_RST) { /* Send an ICMPv6 unreach. */
 #if 0
 		/*
@@ -1609,13 +1571,16 @@
     u_int32_t ack, int flags)
 {
 	struct mbuf *m;
=2D	struct ip *ip;
=2D	struct tcphdr *tcp;
+	int len, dir;
+	struct ip *h =3D NULL;		/* stupid compiler */
+#ifdef INET6
+	struct ip6_hdr *h6 =3D NULL;
+#endif
+	struct tcphdr *th =3D NULL;
=20
 	MGETHDR(m, M_DONTWAIT, MT_DATA);
=2D	if (m =3D=3D 0)
+	if (m =3D=3D NULL)
 		return (NULL);
=2D	m->m_pkthdr.rcvif =3D (struct ifnet *)0;
=20
 #ifdef MAC
 	if (replyto !=3D NULL)
@@ -1626,67 +1591,118 @@
 	(void)replyto;		/* don't warn about unused arg */
 #endif
=20
=2D	m->m_pkthdr.len =3D m->m_len =3D sizeof(struct ip) + sizeof(struct tcph=
dr);
+	switch (id->addr_type) {
+	case 4:
+		len =3D sizeof(struct ip) + sizeof(struct tcphdr);
+		break;
+#ifdef INET6
+	case 6:
+		len =3D sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
+		break;
+#endif
+	default:
+		/* XXX: log me?!? */
+		m_freem(m);
+		return (NULL);
+	}
+	dir =3D ((flags & (TH_SYN | TH_RST)) =3D=3D TH_SYN);
+
 	m->m_data +=3D max_linkhdr;
+	m->m_flags |=3D M_SKIP_FIREWALL;
+	m->m_pkthdr.len =3D m->m_len =3D len;
+	m->m_pkthdr.rcvif =3D NULL;
+	bzero(m->m_data, len);
+
+	switch (id->addr_type) {
+	case 4:
+		h =3D mtod(m, struct ip *);
+
+		/* prepare for checksum */
+		h->ip_p =3D IPPROTO_TCP;
+		h->ip_len =3D htons(sizeof(struct tcphdr));
+		if (dir) {
+			h->ip_src.s_addr =3D htonl(id->src_ip);
+			h->ip_dst.s_addr =3D htonl(id->dst_ip);
+		} else {
+			h->ip_src.s_addr =3D htonl(id->dst_ip);
+			h->ip_dst.s_addr =3D htonl(id->src_ip);
+		}
=20
=2D	ip =3D mtod(m, struct ip *);
=2D	bzero(ip, m->m_len);
=2D	tcp =3D (struct tcphdr *)(ip + 1); /* no IP options */
=2D	ip->ip_p =3D IPPROTO_TCP;
=2D	tcp->th_off =3D 5;
=2D	/*
=2D	 * Assume we are sending a RST (or a keepalive in the reverse
=2D	 * direction), swap src and destination addresses and ports.
=2D	 */
=2D	ip->ip_src.s_addr =3D htonl(id->dst_ip);
=2D	ip->ip_dst.s_addr =3D htonl(id->src_ip);
=2D	tcp->th_sport =3D htons(id->dst_port);
=2D	tcp->th_dport =3D htons(id->src_port);
=2D	if (flags & TH_RST) {	/* we are sending a RST */
+		th =3D (struct tcphdr *)(h + 1);
+		break;
+#ifdef INET6
+	case 6:
+		h6 =3D mtod(m, struct ip6_hdr *);
+
+		/* prepare for checksum */
+		h6->ip6_nxt =3D IPPROTO_TCP;
+		h6->ip6_plen =3D htons(sizeof(struct tcphdr));
+		if (dir) {
+			h6->ip6_src =3D id->src_ip6;
+			h6->ip6_dst =3D id->dst_ip6;
+		} else {
+			h6->ip6_src =3D id->dst_ip6;
+			h6->ip6_dst =3D id->src_ip6;
+		}
+
+		th =3D (struct tcphdr *)(h6 + 1);
+		break;
+#endif
+	}
+
+	if (dir) {
+		th->th_sport =3D id->src_port;
+		th->th_dport =3D id->dst_port;
+	} else {
+		th->th_sport =3D id->dst_port;
+		th->th_dport =3D id->src_port;
+	}
+	th->th_off =3D sizeof(struct tcphdr) >> 2;
+
+	if (flags & TH_RST) {
 		if (flags & TH_ACK) {
=2D			tcp->th_seq =3D htonl(ack);
=2D			tcp->th_ack =3D htonl(0);
=2D			tcp->th_flags =3D TH_RST;
+			th->th_seq =3D htonl(ack);
+			th->th_flags =3D TH_RST;
 		} else {
 			if (flags & TH_SYN)
 				seq++;
=2D			tcp->th_seq =3D htonl(0);
=2D			tcp->th_ack =3D htonl(seq);
=2D			tcp->th_flags =3D TH_RST | TH_ACK;
+			th->th_ack =3D htonl(seq);
+			th->th_flags =3D TH_RST | TH_ACK;
 		}
 	} else {
 		/*
=2D		 * We are sending a keepalive. flags & TH_SYN determines
=2D		 * the direction, forward if set, reverse if clear.
=2D		 * NOTE: seq and ack are always assumed to be correct
=2D		 * as set by the caller. This may be confusing...
+		 * Keepalive - use caller provided sequence numbers
 		 */
=2D		if (flags & TH_SYN) {
=2D			/*
=2D			 * we have to rewrite the correct addresses!
=2D			 */
=2D			ip->ip_dst.s_addr =3D htonl(id->dst_ip);
=2D			ip->ip_src.s_addr =3D htonl(id->src_ip);
=2D			tcp->th_dport =3D htons(id->dst_port);
=2D			tcp->th_sport =3D htons(id->src_port);
=2D		}
=2D		tcp->th_seq =3D htonl(seq);
=2D		tcp->th_ack =3D htonl(ack);
=2D		tcp->th_flags =3D TH_ACK;
+		th->th_seq =3D htonl(seq);
+		th->th_ack =3D htonl(ack);
+		th->th_flags =3D TH_ACK;
+	}
+
+	switch (id->addr_type) {
+	case 4:
+		th->th_sum =3D in_cksum(m, len);
+
+		/* finish the ip header */
+		h->ip_v =3D 4;
+		h->ip_hl =3D sizeof(*h) >> 2;
+		h->ip_tos =3D IPTOS_LOWDELAY;
+		h->ip_off =3D 0;
+		h->ip_len =3D len;
+		h->ip_ttl =3D ip_defttl;
+		h->ip_sum =3D 0;
+		break;
+#ifdef INET6
+	case 6:
+		th->th_sum =3D in6_cksum(m, IPPROTO_TCP, sizeof(*h6),
+		    sizeof(struct tcphdr));
+
+		/* finish the ip6 header */
+		h6->ip6_vfc |=3D IPV6_VERSION;
+		h6->ip6_hlim =3D IPV6_DEFHLIM;
+		break;
+#endif
 	}
=2D	/*
=2D	 * set ip_len to the payload size so we can compute
=2D	 * the tcp checksum on the pseudoheader
=2D	 * XXX check this, could save a couple of words ?
=2D	 */
=2D	ip->ip_len =3D htons(sizeof(struct tcphdr));
=2D	tcp->th_sum =3D in_cksum(m, m->m_pkthdr.len);
=2D	/*
=2D	 * now fill fields left out earlier
=2D	 */
=2D	ip->ip_ttl =3D ip_defttl;
=2D	ip->ip_len =3D m->m_pkthdr.len;
=2D	m->m_flags |=3D M_SKIP_FIREWALL;
+
 	return (m);
 }
=20
@@ -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;
=20
@@ -4874,6 +4893,10 @@
 	 */
 	m0 =3D NULL;
 	mtailp =3D &m0;
+#ifdef INET6
+	m6 =3D NULL;
+	m6_tailp =3D &m6;
+#endif
 	IPFW_DYN_LOCK();
 	for (i =3D 0 ; i < curr_dyn_buckets ; i++) {
 		for (q =3D ipfw_dyn_v[i] ; q ; q =3D q->next ) {
@@ -4889,14 +4912,37 @@
 			if (TIME_LEQ(q->expire, time_uptime))
 				continue;	/* too late, rule expired */
=20
=2D			*mtailp =3D send_pkt(NULL, &(q->id), q->ack_rev - 1,
+			m =3D send_pkt(NULL, &(q->id), q->ack_rev - 1,
 				q->ack_fwd, TH_SYN);
=2D			if (*mtailp !=3D NULL)
=2D				mtailp =3D &(*mtailp)->m_nextpkt;
=2D			*mtailp =3D send_pkt(NULL, &(q->id), q->ack_fwd - 1,
+			mnext =3D send_pkt(NULL, &(q->id), q->ack_fwd - 1,
 				q->ack_rev, 0);
=2D			if (*mtailp !=3D NULL)
=2D				mtailp =3D &(*mtailp)->m_nextpkt;
+
+			switch (q->id.addr_type) {
+			case 4:
+				if (m !=3D NULL) {
+					*mtailp =3D m;
+					mtailp =3D &(*mtailp)->m_nextpkt;
+				}
+				if (mnext !=3D NULL) {
+					*mtailp =3D mnext;
+					mtailp =3D &(*mtailp)->m_nextpkt;
+				}
+				break;
+#ifdef INET6
+			case 6:
+				if (m !=3D NULL) {
+					*m6_tailp =3D m;
+					m6_tailp =3D &(*m6_tailp)->m_nextpkt;
+				}
+				if (mnext !=3D NULL) {
+					*m6_tailp =3D mnext;
+					m6_tailp =3D &(*m6_tailp)->m_nextpkt;
+				}
+				break;
+#endif
+			}
+
+			m =3D mnext =3D NULL;
 		}
 	}
 	IPFW_DYN_UNLOCK();
@@ -4905,6 +4951,13 @@
 		m->m_nextpkt =3D NULL;
 		ip_output(m, NULL, NULL, 0, NULL, NULL);
 	}
+#ifdef INET6
+	for (m =3D mnext =3D m6; m !=3D NULL; m =3D mnext) {
+		mnext =3D m->m_nextpkt;
+		m->m_nextpkt =3D NULL;
+		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+	}
+#endif
 done:
 	callout_reset(&ipfw_timeout, dyn_keepalive_period*hz, ipfw_tick, NULL);
 }

--Boundary-01=_qgKGHg+rBYy2qDj--

--nextPart1730097.U4u31Cs6Nl
Content-Type: application/pgp-signature; name=signature.asc 
Content-Description: This is a digitally signed message part.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4 (FreeBSD)

iD8DBQBHGKgvXyyEoT62BG0RAqkAAJ9n2TO+LpayNJ1DHDIZ6kqssV0LAgCeMUT3
nXk/2aLyPGbZu/y7re5qNJY=
=fXDh
-----END PGP SIGNATURE-----

--nextPart1730097.U4u31Cs6Nl--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200710191450.56014.max>