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>