From owner-freebsd-ipfw@FreeBSD.ORG Mon Dec 20 11:02:40 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 9990D16A4CE for ; Mon, 20 Dec 2004 11:02:40 +0000 (GMT) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 851B843D31 for ; Mon, 20 Dec 2004 11:02:40 +0000 (GMT) (envelope-from owner-bugmaster@freebsd.org) Received: from freefall.freebsd.org (peter@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.1/8.13.1) with ESMTP id iBKB2eMu047550 for ; Mon, 20 Dec 2004 11:02:40 GMT (envelope-from owner-bugmaster@freebsd.org) Received: (from peter@localhost) by freefall.freebsd.org (8.13.1/8.13.1/Submit) id iBKB2dh2047544 for ipfw@freebsd.org; Mon, 20 Dec 2004 11:02:39 GMT (envelope-from owner-bugmaster@freebsd.org) Date: Mon, 20 Dec 2004 11:02:39 GMT Message-Id: <200412201102.iBKB2dh2047544@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: peter set sender to owner-bugmaster@freebsd.org using -f From: FreeBSD bugmaster To: ipfw@FreeBSD.org Subject: Current problem reports assigned to you X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Dec 2004 11:02:40 -0000 Current FreeBSD problem reports Critical problems Serious problems S Submitted Tracker Resp. Description ------------------------------------------------------------------------------- o [2003/04/22] kern/51274 ipfw ipfw2 create dynamic rules with parent nu f [2003/04/24] kern/51341 ipfw ipfw rule 'deny icmp from any to any icmp o [2003/12/11] kern/60154 ipfw ipfw core (crash) o [2004/03/03] kern/63724 ipfw IPFW2 Queues dont t work f [2004/03/25] kern/64694 ipfw [ipfw] UID/GID matching in ipfw non-funct o [2004/11/13] kern/73910 ipfw [ipfw] serious bug on forwarding of packe o [2004/11/19] kern/74104 ipfw ipfw2/1 conflict not detected or reported 7 problems total. Non-critical problems S Submitted Tracker Resp. Description ------------------------------------------------------------------------------- a [2001/04/13] kern/26534 ipfw Add an option to ipfw to log gid/uid of w o [2002/12/10] kern/46159 ipfw ipfw dynamic rules lifetime feature o [2003/02/11] kern/48172 ipfw ipfw does not log size and flags o [2003/03/10] kern/49086 ipfw [patch] Make ipfw2 log to different syslo o [2003/04/09] bin/50749 ipfw ipfw2 incorrectly parses ports and port r o [2003/08/26] kern/55984 ipfw [patch] time based firewalling support fo o [2003/12/30] kern/60719 ipfw ipfw: Headerless fragments generate cryp o [2004/08/03] kern/69963 ipfw ipfw: install_state warning about already o [2004/09/04] kern/71366 ipfw "ipfw fwd" sometimes rewrites destination 9 problems total. From owner-freebsd-ipfw@FreeBSD.ORG Mon Dec 20 18:33:38 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 9219B16A4CE for ; Mon, 20 Dec 2004 18:33:38 +0000 (GMT) Received: from msmisps01.bonddesk.com (msmisps01.bonddesk.com [12.47.70.99]) by mx1.FreeBSD.org (Postfix) with ESMTP id E6B3E43D41 for ; Mon, 20 Dec 2004 18:33:37 +0000 (GMT) (envelope-from csmith@bonddesk.com) Received: from 10.133.16.21 ([10.133.16.21]) by mimail.bdg.local ([10.132.16.100]) with Microsoft Exchange Server HTTP-DAV ; Mon, 20 Dec 2004 18:33:36 +0000 Received: from csmith-dt.bdg.local by mimail.bdg.local; 20 Dec 2004 13:33:36 -0500 From: Corey Smith To: Darcy Buskermolen In-Reply-To: <200412171431.12983.darcy@wavefire.com> References: <1103315143.35576.127.camel@localhost> <200412171431.12983.darcy@wavefire.com> Content-Type: text/plain Content-Transfer-Encoding: 7bit Date: Mon, 20 Dec 2004 13:33:36 -0500 Message-Id: <1103567616.35576.143.camel@localhost> Mime-Version: 1.0 X-Mailer: Evolution 2.0.2 FreeBSD GNOME Team Port cc: freebsd-ipfw@freebsd.org Subject: Re: Per flow load balancing X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: csmith@bonddesk.com List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Dec 2004 18:33:38 -0000 On Fri, 2004-12-17 at 14:31 -0800, Darcy Buskermolen wrote: > Yes you can do this through the use of keep-state/check-state > I'm trying a rule base like: 00005 check-state 00006 allow udp from any to any 00007 allow icmp from any to any 00010 reject tcp from any to any established 00015 prob 0.5 fwd tun1peerip tcp from any to any \ recv bge0 xmit tun0 setup keep-state 00020 allow tcp from any to any setup keep-state 65535 allow ip from any to any Unfortunately no connections ever match rule 15. Any way you can show me an example of using keep-state/check-state for per flow load balancing? -Corey Smith From owner-freebsd-ipfw@FreeBSD.ORG Mon Dec 20 21:33:36 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id ACF6D16A4CE; Mon, 20 Dec 2004 21:33:36 +0000 (GMT) Received: from odin.ac.hmc.edu (Odin.AC.HMC.Edu [134.173.32.75]) by mx1.FreeBSD.org (Postfix) with ESMTP id 3F41A43D5F; Mon, 20 Dec 2004 21:33:36 +0000 (GMT) (envelope-from brdavis@odin.ac.hmc.edu) Received: from odin.ac.hmc.edu (localhost.localdomain [127.0.0.1]) by odin.ac.hmc.edu (8.13.0/8.13.0) with ESMTP id iBKLXsTt029463; Mon, 20 Dec 2004 13:33:54 -0800 Received: (from brdavis@localhost) by odin.ac.hmc.edu (8.13.0/8.13.0/Submit) id iBKLXswE029462; Mon, 20 Dec 2004 13:33:54 -0800 Date: Mon, 20 Dec 2004 13:33:54 -0800 From: Brooks Davis To: Brooks Davis Message-ID: <20041220213354.GA29263@odin.ac.hmc.edu> References: <20040903215137.GA26762@odin.ac.hmc.edu> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="FCuugMFkClbJLl1L" Content-Disposition: inline In-Reply-To: <20040903215137.GA26762@odin.ac.hmc.edu> User-Agent: Mutt/1.4.1i X-Virus-Scanned: by amavisd-new X-Spam-Status: No, hits=0.0 required=8.0 tests=none autolearn=no version=2.63 X-Spam-Checker-Version: SpamAssassin 2.63 (2004-01-11) on odin.ac.hmc.edu cc: freebsd-ipfw@freebsd.org cc: andre@freebsd.org cc: csjp@freebsd.org Subject: Re: ipfw2 for IPV6 X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Dec 2004 21:33:36 -0000 --FCuugMFkClbJLl1L Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Fri, Sep 03, 2004 at 02:51:37PM -0700, Brooks Davis wrote: > I'm working on updating the IPFW2 for IPv6 patch Luigi posted back in > April. I've got it partially working with pfil, but I've run into some > issues with linklocal addresses and dummynet6. Inbound rules work fine, > but output rules do not because the route struct is not carried in to > the pfil hook and thus the output interface is lost. >=20 > I'm looking for comments on the best way to solve this problem. I don't > know IPv6 all that well, so I'm not sure what to propose. >=20 > The work is being done in perforce at: >=20 > //depot/user/brooks/dummynet6 >=20 > I've included a patch against current below. Be aware that you must > run with debug.mpsafenet=3D0 if you want to try IPv6 output rules. The > current code doesn't handle the case where the firewall changes the > destination, but modulo bugs, we are probably at feature parity with > ip6fw. Here's an updated version of the patch. I think it's getting close to the point where it can be committed. This one even has some documentation. -- Brooks *** diffs for ipfw6 changes *** *** Cleanup diffs *** --- ../freebsd/sbin/ipfw/ipfw2.c Mon Nov 29 11:36:53 2004 +++ ../cleanup/sbin/ipfw/ipfw2.c Mon Nov 29 11:45:53 2004 @@ -2522,17 +2522,17 @@ a =3D (a =3D=3D 32) ? ~0 : (1 << a) - 1; } else a =3D strtoul(av[0], &end, 0); - if (p32 !=3D NULL) + if (p32 !=3D NULL) { *p32 =3D a; - else if (p16 !=3D NULL) { - if (a > 65535) + } else if (p16 !=3D NULL) { + if (a > 0xffff) errx(EX_DATAERR, - "mask: must be 16 bit"); + "port mask must be 16 bit"); *p16 =3D (uint16_t)a; } else { - if (a > 255) + if (a > 0xff) errx(EX_DATAERR, - "mask: must be 8 bit"); + "proto mask must be 8 bit"); p.fs.flow_mask.proto =3D (uint8_t)a; } if (a !=3D 0) --- ../freebsd/sys/netinet/ip_dummynet.c Thu Aug 26 20:59:36 2004 +++ ../cleanup/sys/netinet/ip_dummynet.c Mon Nov 22 12:52:14 2004 @@ -1065,7 +1065,7 @@ { #if IPFW2 struct dn_flow_set *fs; - ipfw_insn *cmd =3D rule->cmd + rule->act_ofs; + ipfw_insn *cmd =3D ACTION_PTR(rule); =20 if (cmd->opcode =3D=3D O_LOG) cmd +=3D F_LEN(cmd); @@ -1132,7 +1132,7 @@ struct dn_flow_queue *q =3D NULL ; int is_pipe; #if IPFW2 - ipfw_insn *cmd =3D fwa->rule->cmd + fwa->rule->act_ofs; + ipfw_insn *cmd =3D ACTION_PTR(fwa->rule); #endif =20 KASSERT(m->m_nextpkt =3D=3D NULL, @@ -1372,7 +1372,7 @@ * remove references from all ipfw rules to all pipes. */ static void -dummynet_flush() +dummynet_flush(void) { struct dn_pipe *curr_p, *p ; struct dn_flow_set *fs, *curr_fs; --- ../freebsd/sys/netinet/ip_fw2.c Mon Dec 13 12:52:04 2004 +++ ../cleanup/sys/netinet/ip_fw2.c Mon Dec 13 22:07:04 2004 @@ -314,14 +314,18 @@ =20 =20 /* - * This macro maps an ip pointer into a layer3 header pointer of type T + * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T + * Other macros just cast void * into the appropriate type */ -#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) +#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) +#define TCP(p) ((struct tcphdr *)(p)) +#define UDP(p) ((struct udphdr *)(p)) +#define ICMP(p) ((struct icmp *)(p)) =20 static __inline int -icmptype_match(struct ip *ip, ipfw_insn_u32 *cmd) +icmptype_match(struct icmp *icmp, ipfw_insn_u32 *cmd) { - int type =3D L3HDR(struct icmp,ip)->icmp_type; + int type =3D icmp->icmp_type; =20 return (type <=3D ICMP_MAXTYPE && (cmd->d[0] & (1<icmp_type; + int type =3D icmp->icmp_type; + return (type <=3D ICMP_MAXTYPE && (TT & (1<th_off << 2) - sizeof(struct tcphdr); =20 @@ -1800,97 +1804,112 @@ struct in_addr src_ip, dst_ip; /* NOTE: network format */ u_int16_t ip_len=3D0; int pktlen; - int dyn_dir =3D MATCH_UNKNOWN; - ipfw_dyn_rule *q =3D NULL; - struct ip_fw_chain *chain =3D &layer3_chain; - struct m_tag *mtag; =20 - if (m->m_flags & M_SKIP_FIREWALL) - return 0; /* accept */ /* * dyn_dir =3D MATCH_UNKNOWN when rules unchecked, * MATCH_NONE when checked and not matched (q =3D NULL), * MATCH_FORWARD or MATCH_REVERSE otherwise (q !=3D NULL) */ - - pktlen =3D m->m_pkthdr.len; - if (args->eh =3D=3D NULL || /* layer 3 packet */ - ( m->m_pkthdr.len >=3D sizeof(struct ip) && - ntohs(args->eh->ether_type) =3D=3D ETHERTYPE_IP)) - hlen =3D ip->ip_hl << 2; + int dyn_dir =3D MATCH_UNKNOWN; + ipfw_dyn_rule *q =3D NULL; + struct ip_fw_chain *chain =3D &layer3_chain; + struct m_tag *mtag; =20 /* - * Collect parameters into local variables for faster matching. + * We store in ulp a pointer to the upper layer protocol header. + * In the ipv4 case this is easy to determine from the header, + * but for ipv6 we might have some additional headers in the middle. + * ulp is NULL if not found. */ - if (hlen =3D=3D 0) { /* do not grab addresses for non-ip pkts */ - proto =3D args->f_id.proto =3D 0; /* mark f_id invalid */ - goto after_ip_checks; - } + void *ulp =3D NULL; /* upper layer protocol pointer. */ =20 - proto =3D args->f_id.proto =3D ip->ip_p; - src_ip =3D ip->ip_src; - dst_ip =3D ip->ip_dst; - if (args->eh !=3D NULL) { /* layer 2 packets are as on the wire */ - offset =3D ntohs(ip->ip_off) & IP_OFFMASK; - ip_len =3D ntohs(ip->ip_len); - } else { - offset =3D ip->ip_off & IP_OFFMASK; - ip_len =3D ip->ip_len; - } - pktlen =3D ip_len < pktlen ? ip_len : pktlen; + if (m->m_flags & M_SKIP_FIREWALL) + return 0; /* accept */ =20 -#define PULLUP_TO(len) \ - do { \ - if ((m)->m_len < (len)) { \ - args->m =3D m =3D m_pullup(m, (len)); \ - if (m =3D=3D 0) \ - goto pullup_failed; \ - ip =3D mtod(m, struct ip *); \ - } \ - } while (0) + pktlen =3D m->m_pkthdr.len; + proto =3D args->f_id.proto =3D 0; /* mark f_id invalid */ =20 - if (offset =3D=3D 0) { - switch (proto) { - case IPPROTO_TCP: - { - struct tcphdr *tcp; +/* + * PULLUP_TO(len, p, T) makes sure that len + sizeof(T) is contiguous, + * then it sets p to point at the offset "len" in the mbuf. WARNING: the + * pointer might become stale after other pullups (but we never use it + * this way). + */ +#define PULLUP_TO(len, p, T) \ +do { \ + int x =3D (len) + sizeof(T); \ + if ((m)->m_len < x) { \ + args->m =3D m =3D m_pullup(m, x); \ + if (m =3D=3D NULL) \ + goto pullup_failed; \ + } \ + p =3D (mtod(m, char *) + (len)); \ +} while (0) + + /* Identify IP packets and fill up veriables. */ + if (pktlen >=3D sizeof(struct ip) && + (args->eh =3D=3D NULL || ntohs(args->eh->ether_type) =3D=3D ETHERTYPE= _IP) && + mtod(m, struct ip *)->ip_v =3D=3D 4) { + ip =3D mtod(m, struct ip *); + hlen =3D ip->ip_hl << 2; +#ifdef NOTYET + args->f_id.addr_type =3D 4; +#endif =20 - PULLUP_TO(hlen + sizeof(struct tcphdr)); - tcp =3D L3HDR(struct tcphdr, ip); - dst_port =3D tcp->th_dport; - src_port =3D tcp->th_sport; - args->f_id.flags =3D tcp->th_flags; - } - break; + /* + * Collect parameters into local variables for faster matching. + */ + proto =3D ip->ip_p; + src_ip =3D ip->ip_src; + dst_ip =3D ip->ip_dst; + if (args->eh !=3D NULL) { /* layer 2 packets are as on the wire */ + offset =3D ntohs(ip->ip_off) & IP_OFFMASK; + ip_len =3D ntohs(ip->ip_len); + } else { + offset =3D ip->ip_off & IP_OFFMASK; + ip_len =3D ip->ip_len; + } + pktlen =3D ip_len < pktlen ? ip_len : pktlen; =20 - case IPPROTO_UDP: - { - struct udphdr *udp; + if (offset =3D=3D 0) { + switch (proto) { + case IPPROTO_TCP: + PULLUP_TO(hlen, ulp, struct tcphdr); + dst_port =3D TCP(ulp)->th_dport; + src_port =3D TCP(ulp)->th_sport; + args->f_id.flags =3D TCP(ulp)->th_flags; + break; =20 - PULLUP_TO(hlen + sizeof(struct udphdr)); - udp =3D L3HDR(struct udphdr, ip); - dst_port =3D udp->uh_dport; - src_port =3D udp->uh_sport; - } - break; + case IPPROTO_UDP: + PULLUP_TO(hlen, ulp, struct udphdr); + dst_port =3D UDP(ulp)->uh_dport; + src_port =3D UDP(ulp)->uh_sport; + break; =20 - case IPPROTO_ICMP: - PULLUP_TO(hlen + 4); /* type, code and checksum. */ - args->f_id.flags =3D L3HDR(struct icmp, ip)->icmp_type; - break; + case IPPROTO_ICMP: + /* + * we only care for 4 bytes: type, code, + * checksum + */ + PULLUP_TO(hlen, ulp, struct icmp); + args->f_id.flags =3D ICMP(ulp)->icmp_type; + break; =20 - default: - break; + default: + break; + } } + + args->f_id.src_ip =3D ntohl(src_ip.s_addr); + args->f_id.dst_ip =3D ntohl(dst_ip.s_addr); + } #undef PULLUP_TO + if (proto) { /* we may have port numbers, store them */ + args->f_id.proto =3D proto; + args->f_id.src_port =3D src_port =3D ntohs(src_port); + args->f_id.dst_port =3D dst_port =3D ntohs(dst_port); } =20 - args->f_id.src_ip =3D ntohl(src_ip.s_addr); - args->f_id.dst_ip =3D ntohl(dst_ip.s_addr); - args->f_id.src_port =3D src_port =3D ntohs(src_port); - args->f_id.dst_port =3D dst_port =3D ntohs(dst_port); - -after_ip_checks: IPFW_RLOCK(chain); mtag =3D m_tag_find(m, PACKET_TAG_DIVERT, NULL); if (args->rule) { @@ -2187,7 +2206,7 @@ =20 case O_ICMPTYPE: match =3D (offset =3D=3D 0 && proto=3D=3DIPPROTO_ICMP && - icmptype_match(ip, (ipfw_insn_u32 *)cmd) ); + icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) ); break; =20 case O_IPOPT: @@ -2241,7 +2260,7 @@ uint16_t *p; int i; =20 - tcp =3D L3HDR(struct tcphdr,ip); + tcp =3D TCP(ulp); x =3D ip_len - ((ip->ip_hl + tcp->th_off) << 2); if (cmdlen =3D=3D 1) { @@ -2258,38 +2277,36 @@ =20 case O_TCPFLAGS: match =3D (proto =3D=3D IPPROTO_TCP && offset =3D=3D 0 && - flags_match(cmd, - L3HDR(struct tcphdr,ip)->th_flags)); + flags_match(cmd, TCP(ulp)->th_flags)); break; =20 case O_TCPOPTS: match =3D (proto =3D=3D IPPROTO_TCP && offset =3D=3D 0 && - tcpopts_match(ip, cmd)); + tcpopts_match(TCP(ulp), cmd)); break; =20 case O_TCPSEQ: match =3D (proto =3D=3D IPPROTO_TCP && offset =3D=3D 0 && ((ipfw_insn_u32 *)cmd)->d[0] =3D=3D - L3HDR(struct tcphdr,ip)->th_seq); + TCP(ulp)->th_seq); break; =20 case O_TCPACK: match =3D (proto =3D=3D IPPROTO_TCP && offset =3D=3D 0 && ((ipfw_insn_u32 *)cmd)->d[0] =3D=3D - L3HDR(struct tcphdr,ip)->th_ack); + TCP(ulp)->th_ack); break; =20 case O_TCPWIN: match =3D (proto =3D=3D IPPROTO_TCP && offset =3D=3D 0 && - cmd->arg1 =3D=3D - L3HDR(struct tcphdr,ip)->th_win); + cmd->arg1 =3D=3D TCP(ulp)->th_win); break; =20 case O_ESTAB: /* reject packets which have SYN only */ /* XXX should i also check for TH_ACK ? */ match =3D (proto =3D=3D IPPROTO_TCP && offset =3D=3D 0 && - (L3HDR(struct tcphdr,ip)->th_flags & + (TCP(ulp)->th_flags & (TH_RST | TH_ACK | TH_SYN)) !=3D TH_SYN); break; =20 @@ -2428,7 +2445,7 @@ if (dyn_dir =3D=3D MATCH_UNKNOWN && (q =3D lookup_dyn_rule(&args->f_id, &dyn_dir, proto =3D=3D IPPROTO_TCP ? - L3HDR(struct tcphdr, ip) : NULL)) + TCP(ulp) : NULL)) !=3D NULL) { /* * Found dynamic entry, update stats @@ -2509,7 +2526,7 @@ */ if (hlen > 0 && (proto !=3D IPPROTO_ICMP || - is_icmp_query(ip)) && + is_icmp_query(ICMP(ulp))) && !(m->m_flags & (M_BCAST|M_MCAST)) && !IN_MULTICAST(ntohl(dst_ip.s_addr))) { send_reject(args, cmd->arg1, --- ../freebsd/sys/netinet6/ip6_output.c Thu Oct 7 11:18:35 2004 +++ ../cleanup/sys/netinet6/ip6_output.c Wed Oct 6 18:30:54 2004 @@ -220,6 +220,7 @@ /* Destination options header(2nd part) */ MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2); } +#undef MAKE_EXTHDR =20 #ifdef IPSEC /* get a security policy for this packet */ @@ -389,18 +390,18 @@ ip6->ip6_nxt =3D IPPROTO_DSTOPTS; } =20 -#define MAKE_CHAIN(m, mp, p, i)\ - do {\ - if (m) {\ - if (!hdrsplit) \ - panic("assumption failed: hdr not split"); \ - *mtod((m), u_char *) =3D *(p);\ - *(p) =3D (i);\ - p =3D mtod((m), u_char *);\ - (m)->m_next =3D (mp)->m_next;\ - (mp)->m_next =3D (m);\ - (mp) =3D (m);\ - }\ +#define MAKE_CHAIN(m, mp, p, i) \ + do { \ + if (m) { \ + if (!hdrsplit) \ + panic("assumption failed: hdr not split"); \ + *mtod((m), u_char *) =3D *(p); \ + *(p) =3D (i); \ + p =3D mtod((m), u_char *); \ + (m)->m_next =3D (mp)->m_next; \ + (mp)->m_next =3D (m); \ + (mp) =3D (m); \ + } \ } while (/*CONSTCOND*/ 0) /* * result: IPv6 hbh dest1 rthdr dest2 payload @@ -412,6 +413,7 @@ IPPROTO_DSTOPTS); MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp, IPPROTO_ROUTING); +#undef MAKE_CHAIN =20 #if defined(IPSEC) || defined(FAST_IPSEC) if (!needipsec) @@ -465,7 +467,7 @@ rh->ip6r_segleft =3D segleft_org; } } -skip_ipsec2:; +skip_ipsec2: #endif } =20 @@ -475,8 +477,7 @@ */ if (exthdrs.ip6e_rthdr) { struct ip6_rthdr *rh =3D - (struct ip6_rthdr *)(mtod(exthdrs.ip6e_rthdr, - struct ip6_rthdr *)); + mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *); struct ip6_rthdr0 *rh0; struct in6_addr *addrs; =20 @@ -535,7 +536,7 @@ RTFREE(ro->ro_rt); ro->ro_rt =3D (struct rtentry *)0; } - if (ro->ro_rt =3D=3D 0) { + if (ro->ro_rt =3D=3D NULL) { bzero(dst, sizeof(*dst)); dst->sin6_family =3D AF_INET6; dst->sin6_len =3D sizeof(struct sockaddr_in6); Changed files: sbin/ipfw/ipfw2.c sys/netinet/ip_dummynet.c sys/netinet/ip_fw2.c sys/netinet6/ip6_output.c *** Functional diffs *** --- ../cleanup/sbin/ipfw/ipfw2.c Mon Nov 29 11:45:53 2004 +++ sbin/ipfw/ipfw2.c Mon Dec 20 13:16:12 2004 @@ -49,10 +49,12 @@ =20 #include #include +#include /* def. of struct route */ #include #include #include #include +#include #include #include #include @@ -264,6 +266,13 @@ TOK_DROPTAIL, TOK_PROTO, TOK_WEIGHT, + + TOK_IPV6, + TOK_FLOWID, + TOK_ICMP6TYPES, + TOK_EXT6HDR, + TOK_DSTIP6, + TOK_SRCIP6, }; =20 struct _s_x dummynet_params[] =3D { @@ -286,6 +295,11 @@ { "delay", TOK_DELAY }, { "pipe", TOK_PIPE }, { "queue", TOK_QUEUE }, + { "flow-id", TOK_FLOWID}, + { "dst-ipv6", TOK_DSTIP6}, + { "dst-ip6", TOK_DSTIP6}, + { "src-ipv6", TOK_SRCIP6}, + { "src-ip6", TOK_SRCIP6}, { "dummynet-params", TOK_NULL }, { NULL, 0 } /* terminator */ }; @@ -371,6 +385,16 @@ { "versrcreach", TOK_VERSRCREACH }, { "antispoof", TOK_ANTISPOOF }, { "ipsec", TOK_IPSEC }, + { "icmp6type", TOK_ICMP6TYPES }, + { "icmp6types", TOK_ICMP6TYPES }, + { "ext6hdr", TOK_EXT6HDR}, + { "flow-id", TOK_FLOWID}, + { "ipv6", TOK_IPV6}, + { "ip6", TOK_IPV6}, + { "dst-ipv6", TOK_DSTIP6}, + { "dst-ip6", TOK_DSTIP6}, + { "src-ipv6", TOK_SRCIP6}, + { "src-ip6", TOK_SRCIP6}, { "//", TOK_COMMENT }, =20 { "not", TOK_NOT }, /* pseudo option */ @@ -971,6 +995,199 @@ } } =20 +/*=20 + * Print the ip address contained in a command. + */ +static void +print_ip6(ipfw_insn_ip6 *cmd, char const *s) +{ + struct hostent *he =3D NULL; + int len =3D F_LEN((ipfw_insn *) cmd) - 1; + struct in6_addr *a =3D &(cmd->addr6); + char trad[255]; + + printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); + + if (cmd->o.opcode =3D=3D O_IP6_SRC_ME || cmd->o.opcode =3D=3D O_IP6= _DST_ME) { + printf("me6"); + return; + } + if (cmd->o.opcode =3D=3D O_IP6) { + printf(" ipv6"); + return; + } + + /* + * len =3D=3D 4 indicates a single IP, whereas lists of 1 or more + * addr/mask pairs have len =3D (2n+1). We convert len to n so we + * use that to count the number of entries. + */ + + for (len =3D len / 4; len > 0; len -=3D 2, a +=3D 2) { + int mb =3D /* mask length */ + (cmd->o.opcode =3D=3D O_IP6_SRC || cmd->o.opcode =3D=3D O_I= P6_DST) ? + 128 : contigmask((uint8_t *)&(a[1]), 128); + + if (mb =3D=3D 128 && do_resolv) + he =3D gethostbyaddr((char *)a, sizeof(*a), AF_INET6); + if (he !=3D NULL) /* resolved to name */ + printf("%s", he->h_name); + else if (mb =3D=3D 0) /* any */ + printf("any"); + else { /* numeric IP followed by some kind of mask */ + if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) =3D=3D N= ULL) + printf("Error ntop in print_ip6\n"); + printf("%s", trad ); + if (mb < 0) /* XXX not really legal... */ + printf(":%s", + inet_ntop(AF_INET6, &a[1], trad, sizeof(trad))); + else if (mb < 128) + printf("/%d", mb); + } + if (len > 2) + printf(","); + } +} + +static void +fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av) +{ + uint8_t type; + + cmd->d[0] =3D 0; + while (*av) { + if (*av =3D=3D ',') + av++; + type =3D strtoul(av, &av, 0); + if (*av !=3D ',' && *av !=3D '\0') + errx(EX_DATAERR, "invalid ICMP6 type"); + /* + * XXX: shouldn't this be 0xFF? I can't see any reason why + * we shouldn't be able to filter all possiable values + * regardless of the ability of the rest of the kernel to do + * anything useful with them. + */ + if (type > ICMP6_MAXTYPE) + errx(EX_DATAERR, "ICMP6 type out of range"); + cmd->d[type / 32] |=3D ( 1 << (type % 32)); + } + cmd->o.opcode =3D O_ICMP6TYPE; + cmd->o.len |=3D F_INSN_SIZE(ipfw_insn_icmp6); +} + + +static void +print_icmp6types(ipfw_insn_u32 *cmd) +{ + int i, j; + char sep=3D ' '; + + printf(" ipv6 icmp6types"); + for (i =3D 0; i < 7; i++) + for (j=3D0; j < 32; ++j) { + if ( (cmd->d[i] & (1 << (j))) =3D=3D 0) + continue; + printf("%c%d", sep, (i*32 + j)); + sep =3D ','; + } +} + +static void +print_flow6id( ipfw_insn_u32 *cmd) +{ + uint16_t i, limit =3D cmd->o.arg1; + char sep =3D ','; + + printf(" flow-id "); + for( i=3D0; i < limit; ++i) { + if (i =3D=3D limit - 1) + sep =3D ' '; + printf("%d%c", cmd->d[i], sep); + } +} + +/* structure and define for the extension header in ipv6 */ +static struct _s_x ext6hdrcodes[] =3D { + { "frag", EXT_FRAGMENT }, + { "hopopt", EXT_HOPOPTS }, + { "route", EXT_ROUTING }, + { "ah", EXT_AH }, + { "esp", EXT_ESP }, + { NULL, 0 } +}; + +/* fills command for the extension header filtering */ +int +fill_ext6hdr( ipfw_insn *cmd, char *av) +{ + int tok; + char *s =3D av; + + cmd->arg1 =3D 0; + + while(s) { + av =3D strsep( &s, ",") ; + tok =3D match_token(ext6hdrcodes, av); + switch (tok) { + case EXT_FRAGMENT: + cmd->arg1 |=3D EXT_FRAGMENT; + break; + + case EXT_HOPOPTS: + cmd->arg1 |=3D EXT_HOPOPTS; + break; + + case EXT_ROUTING: + cmd->arg1 |=3D EXT_ROUTING; + break; + + case EXT_AH: + cmd->arg1 |=3D EXT_AH; + break; + + case EXT_ESP: + cmd->arg1 |=3D EXT_ESP; + break; + + default: + errx( EX_DATAERR, "invalid option for ipv6 exten header" ); + break; + } + } + if (cmd->arg1 =3D=3D 0 ) + return 0; + cmd->opcode =3D O_EXT_HDR; + cmd->len |=3D F_INSN_SIZE( ipfw_insn ); + return 1; +} + +void +print_ext6hdr( ipfw_insn *cmd ) +{ + char sep =3D ' '; + + printf(" extension header:"); + if (cmd->arg1 & EXT_FRAGMENT ) { + printf("%cfragmentation", sep); + sep =3D ','; + } + if (cmd->arg1 & EXT_HOPOPTS ) { + printf("%chop options", sep); + sep =3D ','; + } + if (cmd->arg1 & EXT_ROUTING ) { + printf("%crouting options", sep); + sep =3D ','; + } + if (cmd->arg1 & EXT_AH ) { + printf("%cauthentication header", sep); + sep =3D ','; + } + if (cmd->arg1 & EXT_ESP ) { + printf("%cencapsulated security payload", sep); + } +} + /* * show_ipfw() prints the body of an ipfw rule. * Because the standard rule has at least proto src_ip dst_ip, we use @@ -989,6 +1206,7 @@ #define HAVE_DSTIP 0x0004 #define HAVE_MAC 0x0008 #define HAVE_MACTYPE 0x0010 +#define HAVE_PROTO6 0x0080 #define HAVE_OPTIONS 0x8000 =20 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) @@ -1011,6 +1229,9 @@ return; } if ( !(*flags & HAVE_OPTIONS)) { + /* XXX BED: !(*flags & HAVE_PROTO) in patch */ + if ( !(*flags & HAVE_PROTO6) && (want & HAVE_PROTO6)) + printf(" ipv6"); if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) printf(" ip"); if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) @@ -1267,6 +1488,37 @@ flags |=3D HAVE_DSTIP; break; =20 + case O_IP6_SRC: + case O_IP6_SRC_MASK: + case O_IP6_SRC_ME: + show_prerequisites(&flags, HAVE_PROTO6, 0); + if (!(flags & HAVE_SRCIP)) + printf(" from"); + if ((cmd->len & F_OR) && !or_block) + printf(" {"); + print_ip6((ipfw_insn_ip6 *)cmd, + (flags & HAVE_OPTIONS) ? " src-ip6" : ""); + flags |=3D HAVE_SRCIP | HAVE_PROTO; + break; + + case O_IP6_DST: + case O_IP6_DST_MASK: + case O_IP6_DST_ME: + show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); + if (!(flags & HAVE_DSTIP)) + printf(" to"); + if ((cmd->len & F_OR) && !or_block) + printf(" {"); + print_ip6((ipfw_insn_ip6 *)cmd, + (flags & HAVE_OPTIONS) ? " dst-ip6" : ""); + flags |=3D HAVE_DSTIP; + break; + + case O_FLOW6ID: + print_flow6id( (ipfw_insn_u32 *) cmd ); + flags |=3D HAVE_OPTIONS; + break; + case O_IP_DSTPORT: show_prerequisites(&flags, HAVE_IP, 0); case O_IP_SRCPORT: @@ -1278,14 +1530,15 @@ break; =20 case O_PROTO: { - struct protoent *pe; + struct protoent *pe =3D NULL; =20 if ((cmd->len & F_OR) && !or_block) printf(" {"); if (cmd->len & F_NOT) printf(" not"); proto =3D cmd->arg1; - pe =3D getprotobynumber(cmd->arg1); + if (proto !=3D 41) /* XXX: IPv6 is special */ + pe =3D getprotobynumber(cmd->arg1); if (flags & HAVE_OPTIONS) printf(" proto"); if (pe) @@ -1494,6 +1747,18 @@ } break; =20 + case O_IP6: =20 + printf(" ipv6"); + break; + + case O_ICMP6TYPE: + print_icmp6types((ipfw_insn_u32 *)cmd); + break; + + case O_EXT_HDR: + print_ext6hdr( (ipfw_insn *) cmd ); + break; + default: printf(" [opcode %d len %d]", cmd->opcode, cmd->len); @@ -1591,29 +1856,48 @@ list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) { int l; + int index_printed, indexes =3D 0; + char buff[255]; + struct protoent *pe; =20 - printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", - fs->flow_mask.proto, - fs->flow_mask.src_ip, fs->flow_mask.src_port, - fs->flow_mask.dst_ip, fs->flow_mask.dst_port); if (fs->rq_elements =3D=3D 0) return; =20 - printf("BKT Prot ___Source IP/port____ " - "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); if (do_sort !=3D 0) heapsort(q, fs->rq_elements, sizeof *q, sort_q); + + /* Print IPv4 flows */ + index_printed =3D 0; for (l =3D 0; l < fs->rq_elements; l++) { struct in_addr ina; - struct protoent *pe; =20 - ina.s_addr =3D htonl(q[l].id.src_ip); + /* XXX: Should check for IPv4 flows */ + if (IS_IP6_FLOW_ID(&(q[l].id))) + continue; + + if (!index_printed) { + index_printed =3D 1; + if (indexes > 0) /* currently a no-op */ + printf("\n"); + indexes++; + printf(" " + "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", + fs->flow_mask.proto, + fs->flow_mask.src_ip, fs->flow_mask.src_port, + fs->flow_mask.dst_ip, fs->flow_mask.dst_port); + + printf("BKT Prot ___Source IP/port____ " + "____Dest. IP/port____ " + "Tot_pkt/bytes Pkt/Byte Drp\n"); + } + printf("%3d ", q[l].hash_slot); pe =3D getprotobynumber(q[l].id.proto); if (pe) printf("%-4s ", pe->p_name); else printf("%4u ", q[l].id.proto); + ina.s_addr =3D htonl(q[l].id.src_ip); printf("%15s/%-5d ", inet_ntoa(ina), q[l].id.src_port); ina.s_addr =3D htonl(q[l].id.dst_ip); @@ -1626,6 +1910,50 @@ printf(" S %20qd F %20qd\n", q[l].S, q[l].F); } + + /* Print IPv6 flows */ + index_printed =3D 0; + for (l =3D 0; l < fs->rq_elements; l++) { + if (!IS_IP6_FLOW_ID(&(q[l].id))) + continue; + + if (!index_printed) { + index_printed =3D 1; + if (indexes > 0) + printf("\n"); + indexes++; + printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ", + fs->flow_mask.proto, fs->flow_mask.flow_id6); + inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6), + buff, sizeof(buff)); + printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port); + inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6), + buff, sizeof(buff) ); + printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port); + + printf("BKT ___Prot___ _flow-id_ " + "______________Source IPv6/port_______________ " + "_______________Dest. IPv6/port_______________ " + "Tot_pkt/bytes Pkt/Byte Drp\n"); + } + printf("%3d ", q[l].hash_slot); + pe =3D getprotobynumber(q[l].id.proto); + if (pe !=3D NULL) + printf("%9s ", pe->p_name); + else + printf("%9u ", q[l].id.proto); + printf("%7d %39s/%-5d ", q[l].id.flow_id6, + inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)), + q[l].id.src_port); + printf(" %39s/%-5d ", + inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)), + q[l].id.dst_port); + printf(" %4qu %8qu %2u %4u %3u\n", + q[l].tot_pkts, q[l].tot_bytes, + q[l].len, q[l].len_bytes, q[l].drops); + if (verbose) + printf(" S %20qd F %20qd\n", q[l].S, q[l].F); + } } =20 static void @@ -2018,7 +2346,7 @@ if (do_dynamic && ndyn) { printf("## Dynamic rules:\n"); for (lac =3D ac, lav =3D av; lac !=3D 0; lac--) { - rnum =3D strtoul(*lav++, &endptr, 10); + last =3D rnum =3D strtoul(*lav++, &endptr, 10); if (*endptr =3D=3D '-') last =3D strtoul(endptr+1, &endptr, 10); if (*endptr) @@ -2068,19 +2396,24 @@ "table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n" "\n" "RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n" -"ACTION: check-state | allow | count | deny | reject | skipto N |\n" +"ACTION: check-state | allow | count | deny | unreach CODE | skipto N |\n" " {divert|tee} PORT | forward ADDR | pipe N | queue N\n" "PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n" "ADDR: [ MAC dst src ether_type ] \n" -" [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" +" [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" +" [ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n" "IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n" +"IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n" +"IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n" "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" "OPTION_LIST: OPTION [OPTION_LIST]\n" "OPTION: bridged | diverted | diverted-loopback | diverted-output |\n" -" {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n" +" {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n" +" {dst-port|src-port} LIST |\n" " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" +" icmp6types LIST | ext6hdr LIST | flow-id N[,N] |\n" " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" " tcpdatalen LIST | verrevpath | versrcreach | antispoof\n" @@ -2106,7 +2439,6 @@ * fills the addr and mask fields in the instruction as appropriate from a= v. * Update length as appropriate. * The following formats are allowed: - * any matches any IP. Actually returns an empty instruction. * me returns O_IP_*_ME * 1.2.3.4 single IP address * 1.2.3.4:5.6.7.8 address:mask @@ -2293,6 +2625,231 @@ } =20 =20 +/* Try to find ipv6 address by hostname */ +static int +lookup_host6 (char *host, struct in6_addr *ip6addr) +{ + struct hostent *he; + + if (!inet_pton(AF_INET6, host, ip6addr)) { + if ((he =3D gethostbyname2(host, AF_INET6)) =3D=3D NULL) + return(-1); + memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr)); + } + return(0); +} + + +/* n2mask sets n bits of the mask */ +static void +n2mask(struct in6_addr *mask, int n) +{ + static int minimask[9] =3D + { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + u_char *p; + + memset(mask, 0, sizeof(struct in6_addr)); + p =3D (u_char *) mask; + for (; n > 0; p++, n -=3D 8) { + if (n >=3D 8) + *p =3D 0xff; + else + *p =3D minimask[n]; + } + return; +} +=20 + +/* + * fill the addr and mask fields in the instruction as appropriate from av. + * Update length as appropriate. + * The following formats are allowed: + * any matches any IP6. Actually returns an empty instruction. + * me returns O_IP6_*_ME + * + * 03f1::234:123:0342 single IP6 addres + * 03f1::234:123:0342/24 address/mask + * 03f1::234:123:0342/24,03f1::234:123:0343/ List of add= ress + * + * Set of address (as in ipv6) not supported because ipv6 address + * are typically random past the initial prefix. + * Return 1 on success, 0 on failure. + */ +static int +fill_ip6(ipfw_insn_ip6 *cmd, char *av) +{ + int len =3D 0; + struct in6_addr *d =3D &(cmd->addr6); + /* + * Needed for multiple address. + * Note d[1] points to struct in6_add r mask6 of cmd + */ + + cmd->o.len &=3D ~F_LEN_MASK; /* zero len */ + + if (strcmp(av, "any") =3D=3D 0) + return (1); + + + if (strcmp(av, "me") =3D=3D 0) { /* Set the data for "me" opt*/ + cmd->o.len |=3D F_INSN_SIZE(ipfw_insn); + return (1); + } + + if (strcmp(av, "me6") =3D=3D 0) { /* Set the data for "me" opt*/ + cmd->o.len |=3D F_INSN_SIZE(ipfw_insn); + return (1); + } + + av =3D strdup(av); + while (av) { + /* + * After the address we can have '/' indicating a mask, + * or ',' indicating another address follows. + */ + + char *p; + int masklen; + char md =3D '\0'; + + if ((p =3D strpbrk(av, "/,")) ) { + md =3D *p; /* save the separator */ + *p =3D '\0'; /* terminate address string */ + p++; /* and skip past it */ + } + /* now p points to NULL, mask or next entry */ + + /* lookup stores address in *d as a side effect */ + if (lookup_host6(av, d) !=3D 0) { + /* XXX: failed. Free memory and go */ + errx(EX_DATAERR, "bad address \"%s\"", av); + } + /* next, look at the mask, if any */ + masklen =3D (md =3D=3D '/') ? atoi(p) : 128; + if (masklen > 128 || masklen < 0) + errx(EX_DATAERR, "bad width \"%s\''", p); + else + n2mask(&d[1], masklen); + + APPLY_MASK(d, &d[1]) /* mask base address with mask */ + + /* find next separator */ + + if (md =3D=3D '/') { /* find separator past the mask */ + p =3D strpbrk(p, ","); + if (p !=3D NULL) + p++; + } + av =3D p; + + /* Check this entry */ + if (masklen =3D=3D 0) { + /* + * 'any' turns the entire list into a NOP. + * 'not any' never matches, so it is removed from the + * list unless it is the only item, in which case we + * report an error. + */ + if (cmd->o.len & F_NOT && av =3D=3D NULL && len =3D=3D 0) + errx(EX_DATAERR, "not any never matches"); + continue; + } + + /* + * A single IP can be stored alone + */ + if (masklen =3D=3D 128 && av =3D=3D NULL && len =3D=3D 0) { + len =3D F_INSN_SIZE(struct in6_addr); + break; + } + + /* Update length and pointer to arguments */ + len +=3D F_INSN_SIZE(struct in6_addr)*2; + d +=3D 2; + } /* end while */ + + /* + * Total length of the command, remember that 1 is the size of + * the base command. + */ + cmd->o.len |=3D len+1; + free(av); + return (1); +} + +/* + * fills command for ipv6 flow-id filtering + * note that the 20 bit flow number is stored in a array of u_int32_t + * it's supported lists of flow-id, so in the o.arg1 we store how many + * additional flow-id we want to filter, the basic is 1 + */ +void +fill_flow6( ipfw_insn_u32 *cmd, char *av ) +{ + u_int32_t type; /* Current flow number */ + u_int16_t nflow =3D 0; /* Current flow index */ + char *s =3D av; + cmd->d[0] =3D 0; /* Initializing the base number*/ + + while (s) { + av =3D strsep( &s, ",") ; + type =3D strtoul(av, &av, 0); + if (*av !=3D ',' && *av !=3D '\0') + errx(EX_DATAERR, "invalid ipv6 flow number %s", av); + if (type > 0xfffff) + errx(EX_DATAERR, "flow number out of range %s", av); + cmd->d[nflow] |=3D type; + nflow++; + } + if( nflow > 0 ) { + cmd->o.opcode =3D O_FLOW6ID; + cmd->o.len |=3D F_INSN_SIZE(ipfw_insn_u32) + nflow; + cmd->o.arg1 =3D nflow; + } + else { + errx(EX_DATAERR, "invalid ipv6 flow number %s", av); + } +} + +static ipfw_insn * +add_srcip6(ipfw_insn *cmd, char *av) +{ + + fill_ip6((ipfw_insn_ip6 *)cmd, av); + if (F_LEN(cmd) =3D=3D 0) /* any */ + ; + if (F_LEN(cmd) =3D=3D F_INSN_SIZE(ipfw_insn)) { /* "me" */ + cmd->opcode =3D O_IP6_SRC_ME; + } else if (F_LEN(cmd) =3D=3D + (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { + /* single IP, no mask*/ + cmd->opcode =3D O_IP6_SRC; + } else { /* addr/mask opt */ + cmd->opcode =3D O_IP6_SRC_MASK; + } + return cmd; +} + +static ipfw_insn * +add_dstip6(ipfw_insn *cmd, char *av) +{ + + fill_ip6((ipfw_insn_ip6 *)cmd, av); + if (F_LEN(cmd) =3D=3D 0) /* any */ + ; + if (F_LEN(cmd) =3D=3D F_INSN_SIZE(ipfw_insn)) { /* "me" */ + cmd->opcode =3D O_IP6_DST_ME; + } else if (F_LEN(cmd) =3D=3D + (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { + /* single IP, no mask*/ + cmd->opcode =3D O_IP6_DST; + } else { /* addr/mask opt */ + cmd->opcode =3D O_IP6_DST_MASK; + } + return cmd; +} + + /* * helper function to process a set of flags and set bits in the * appropriate masks. @@ -2404,7 +2961,6 @@ struct dn_pipe p; int i; char *end; - uint32_t a; void *par =3D NULL; =20 memset(&p, 0, sizeof p); @@ -2466,16 +3022,15 @@ */ par =3D NULL; =20 - p.fs.flow_mask.dst_ip =3D 0; - p.fs.flow_mask.src_ip =3D 0; - p.fs.flow_mask.dst_port =3D 0; - p.fs.flow_mask.src_port =3D 0; - p.fs.flow_mask.proto =3D 0; + bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask)); end =3D NULL; =20 while (ac >=3D 1) { uint32_t *p32 =3D NULL; uint16_t *p16 =3D NULL; + uint32_t *p20 =3D NULL; + struct in6_addr *pa6 =3D NULL; + uint32_t a; =20 tok =3D match_token(dummynet_params, *av); ac--; av++; @@ -2489,6 +3044,9 @@ p.fs.flow_mask.dst_port =3D ~0; p.fs.flow_mask.src_port =3D ~0; p.fs.flow_mask.proto =3D ~0; + n2mask(&(p.fs.flow_mask.dst_ip6), 128); + n2mask(&(p.fs.flow_mask.src_ip6), 128); + p.fs.flow_mask.flow_id6 =3D ~0; p.fs.flags_fs |=3D DN_HAVE_FLOW_MASK; goto end_mask; =20 @@ -2500,6 +3058,18 @@ p32 =3D &p.fs.flow_mask.src_ip; break; =20 + case TOK_DSTIP6: + pa6 =3D &(p.fs.flow_mask.dst_ip6); + break; + =20 + case TOK_SRCIP6: + pa6 =3D &(p.fs.flow_mask.src_ip6); + break; + + case TOK_FLOWID: + p20 =3D &p.fs.flow_mask.flow_id6; + break; + case TOK_DSTPORT: p16 =3D &p.fs.flow_mask.dst_port; break; @@ -2519,7 +3089,8 @@ errx(EX_USAGE, "mask: value missing"); if (*av[0] =3D=3D '/') { a =3D strtoul(av[0]+1, &end, 0); - a =3D (a =3D=3D 32) ? ~0 : (1 << a) - 1; + if (pa6 =3D=3D NULL) + a =3D (a =3D=3D 32) ? ~0 : (1 << a) - 1; } else a =3D strtoul(av[0], &end, 0); if (p32 !=3D NULL) { @@ -2529,6 +3100,17 @@ errx(EX_DATAERR, "port mask must be 16 bit"); *p16 =3D (uint16_t)a; + } else if (p20 !=3D NULL) { + if (a > 0xfffff) + errx(EX_DATAERR, + "flow_id mask must be 20 bit"); + *p20 =3D (uint32_t)a; + } else if (pa6 !=3D NULL) { + if (a < 0 || a > 128) + errx(EX_DATAERR, + "in6addr invalid mask len"); + else + n2mask(pa6, a); } else { if (a > 0xff) errx(EX_DATAERR, @@ -2852,21 +3434,25 @@ } =20 static ipfw_insn * -add_proto(ipfw_insn *cmd, char *av) +add_proto(ipfw_insn *cmd, char *av, u_char *proto) { struct protoent *pe; - u_char proto =3D 0; + + *proto =3D IPPROTO_IP; =20 if (!strncmp(av, "all", strlen(av))) ; /* same as "ip" */ - else if ((proto =3D atoi(av)) > 0) + else if ((*proto =3D atoi(av)) > 0) ; /* all done! */ else if ((pe =3D getprotobyname(av)) !=3D NULL) - proto =3D pe->p_proto; + *proto =3D pe->p_proto; + else if (strcmp(av, "ipv6") =3D=3D 0 || strcmp(av, "ip6")) + *proto =3D IPPROTO_IPV6; else return NULL; - if (proto !=3D IPPROTO_IP) - fill_cmd(cmd, O_PROTO, 0, proto); + if (*proto !=3D IPPROTO_IP && *proto !=3D IPPROTO_IPV6) + fill_cmd(cmd, O_PROTO, 0, *proto); + return cmd; } =20 @@ -2917,6 +3503,42 @@ return NULL; } =20 +static ipfw_insn * +add_src(ipfw_insn *cmd, char *av, u_char proto) +{ + struct in6_addr a; + + if (proto =3D=3D IPPROTO_IPV6 || strcmp(av, "me6") =3D=3D 0 || + inet_pton(AF_INET6, av, &a)) + return add_srcip6(cmd, av); + /* XXX: should check for IPv4, not !IPv6 */ + if (proto =3D=3D IPPROTO_IP || strcmp(av, "me") =3D=3D 0 || + !inet_pton(AF_INET6, av, &a)) + return add_srcip(cmd, av); + if (strcmp(av, "any") !=3D 0) + return cmd; + + return NULL; +} + +static ipfw_insn * +add_dst(ipfw_insn *cmd, char *av, u_char proto) +{ + struct in6_addr a; + + if (proto =3D=3D IPPROTO_IPV6 || strcmp(av, "me6") =3D=3D 0 || + inet_pton(AF_INET6, av, &a)) + return add_dstip6(cmd, av); + /* XXX: should check for IPv4, not !IPv6 */ + if (proto =3D=3D IPPROTO_IP || strcmp(av, "me") =3D=3D 0 || + !inet_pton(AF_INET6, av, &a)) + return add_dstip(cmd, av); + if (strcmp(av, "any") !=3D 0) + return cmd; + + return NULL; +} + /* * Parse arguments and assemble the microinstructions which make up a rule. * Rules are added into the 'rulebuf' and then copied in the correct order @@ -3251,7 +3873,7 @@ OR_START(get_proto); NOT_BLOCK; NEED1("missing protocol"); - if (add_proto(cmd, *av)) { + if (add_proto(cmd, *av, &proto)) { av++; ac--; if (F_LEN(cmd) =3D=3D 0) /* plain IP */ proto =3D 0; @@ -3279,13 +3901,14 @@ OR_START(source_ip); NOT_BLOCK; /* optional "not" */ NEED1("missing source address"); - if (add_srcip(cmd, *av)) { + if (add_src(cmd, *av, proto)) { ac--; av++; if (F_LEN(cmd) !=3D 0) { /* ! any */ prev =3D cmd; cmd =3D next_cmd(cmd); } - } + } else + errx(EX_USAGE, "bad source address %s", *av); OR_BLOCK(source_ip); =20 /* @@ -3314,13 +3937,14 @@ OR_START(dest_ip); NOT_BLOCK; /* optional "not" */ NEED1("missing dst address"); - if (add_dstip(cmd, *av)) { + if (add_dst(cmd, *av, proto)) { ac--; av++; if (F_LEN(cmd) !=3D 0) { /* ! any */ prev =3D cmd; cmd =3D next_cmd(cmd); } - } + } else + errx( EX_USAGE, "bad destination address %s", *av); OR_BLOCK(dest_ip); =20 /* @@ -3437,6 +4061,12 @@ fill_icmptypes((ipfw_insn_u32 *)cmd, *av); av++; ac--; break; + =09 + case TOK_ICMP6TYPES: + NEED1("icmptypes requires list of types"); + fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); + av++; ac--; + break; =20 case TOK_IPTTL: NEED1("ipttl requires TTL"); @@ -3641,8 +4271,9 @@ =20 case TOK_PROTO: NEED1("missing protocol"); - if (add_proto(cmd, *av)) { - proto =3D cmd->arg1; + if (add_proto(cmd, *av, &proto)) { + if (proto =3D=3D IPPROTO_IPV6) + fill_cmd(cmd, O_IP6, 0, 0); ac--; av++; } else errx(EX_DATAERR, "invalid protocol ``%s''", @@ -3663,6 +4294,20 @@ } break; =20 + case TOK_SRCIP6: + NEED1("missing source IP6"); + if (add_srcip6(cmd, *av)) { + ac--; av++; + } + break; + =09 + case TOK_DSTIP6: + NEED1("missing destination IP6"); + if (add_dstip6(cmd, *av)) { + ac--; av++; + } + break; + case TOK_SRCPORT: NEED1("missing source port"); if (!strncmp(*av, "any", strlen(*av)) || @@ -3709,6 +4354,24 @@ =20 case TOK_IPSEC: fill_cmd(cmd, O_IPSEC, 0, 0); + break; + + case TOK_IPV6: + fill_cmd(cmd, O_IP6, 0, 0); + ac--; av++; + break; + + case TOK_EXT6HDR: + fill_ext6hdr( cmd, *av ); + ac--; av++; + break; + + case TOK_FLOWID: + if (proto !=3D IPPROTO_IPV6 ) + errx( EX_USAGE, "flow-id filter is active " + "only for ipv6 protocol\n"); + fill_flow6( (ipfw_insn_u32 *) cmd, *av ); + ac--; av++; break; =20 case TOK_COMMENT: --- ../cleanup/sbin/ipfw/ipfw.8 Mon Dec 13 22:06:52 2004 +++ sbin/ipfw/ipfw.8 Mon Dec 20 13:28:03 2004 @@ -346,18 +346,18 @@ These places and variables are shown below, and it is important to have this picture in mind in order to design a correct ruleset. .Bd -literal -offset indent - ^ to upper layers V - | | - +----------->-----------+ - ^ V - [ip_input] [ip_output] net.inet.ip.fw.enable=3D1 - | | - ^ V -[ether_demux] [ether_output_frame] net.link.ether.ipfw=3D1 - | | - +-->--[bdg_forward]-->--+ net.link.ether.bridge_ipfw=3D1 - ^ V - | to devices | + ^ to upper layers V + | | + +----------->-----------+ + ^ V + [ip(6)_input] [ip(6)_output] net.inet.ip.fw.enable=3D1 + | | + ^ V + [ether_demux] [ether_output_frame] net.link.ether.ipfw=3D1 + | | + +-->--[bdg_forward]-->--+ net.link.ether.bridge_ipfw=3D1 + ^ V + | to devices | .Ed .Pp As can be noted from the above picture, the number of @@ -375,13 +375,17 @@ but the same packets will have the MAC header stripped off when .Nm is invoked from -.Cm ip_input() . +.Cm ip_input()=20 +or +.Cm ip6_input() . .Pp Also note that each packet is always checked against the complete ruleset, irrespective of the place where the check occurs, or the source of the pac= ket. If a rule contains some match patterns or actions which are not valid for the place of invocation (e.g.\& trying to match a MAC header within .Cm ip_input() +or +.Cm ip6_input() ), the match pattern will not match, but a .Cm not operator in front of such patterns @@ -448,7 +452,7 @@ .Bl -tag -width "Source and dest. addresses and ports" -offset XXX -compact .It Layer-2 header fields When available -.It IPv4 Protocol +.It IPv4 and IPv6 Protocol TCP, UDP, ICMP, etc. .It Source and dest. addresses and ports .It Direction @@ -461,6 +465,10 @@ fragment flag (non-zero IP offset), Time To Live .It IP options +.It IPv6 Extension headers +Fragmentation, Hop-by-Hop options, +source routing, IPSec options. +.It IPv6 Flow-ID .It Misc. TCP header fields TCP flags (SYN, FIN, ACK, RST, etc.), sequence number, acknowledgment number, @@ -468,6 +476,8 @@ .It TCP options .It ICMP types for ICMP packets +.It ICMP6 types +for ICMP6 packets .It User/group ID When the packet can be associated with a local socket. .It Divert status @@ -774,7 +784,7 @@ .Nm ipfw1 . In .Nm ipfw2 -any match pattern (including MAC headers, IPv4 protocols, +any match pattern (including MAC headers, IP protocols, addresses and ports) can be specified in the .Ar options section. @@ -783,11 +793,13 @@ .Bl -tag -width indent .It Ar proto : protocol | Cm { Ar protocol Cm or ... } .It Ar protocol : Oo Cm not Oc Ar protocol-name | protocol-number -An IPv4 protocol specified by number or name +An IP protocol specified by number or name (for a complete list see .Pa /etc/protocols ) . The -.Cm ip +.Cm ip , +.Cm ip6 , +.Cm ipv6 , or .Cm all keywords mean any protocol will match. @@ -808,7 +820,7 @@ with multiple addresses) is provided for convenience only and its use is discouraged. .It Ar addr : Oo Cm not Oc Bro -.Cm any | me | +.Cm any | me | me6 .Cm table Ns Pq Ar number Ns Op , Ns Ar value .Ar | addr-list | addr-set .Brc @@ -816,10 +828,12 @@ matches any IP address. .It Cm me matches any IP address configured on an interface in the system. +.It Cm me6 +matches any IPv6 address configured on an interface in the system. The address list is evaluated at the time the packet is analysed. .It Cm table Ns Pq Ar number Ns Op , Ns Ar value -Matches any IP address for which an entry exists in the lookup table +Matches any IPv4 address for which an entry exists in the lookup table .Ar number . If an optional 32-bit unsigned .Ar value @@ -886,6 +900,30 @@ will match the following IP addresses: .br 1.2.3.128, 1.2.3.35 to 1.2.3.55, 1.2.3.89 . +.It Ar addr6-list : ip6-addr Ns Op Ns , Ns Ar addr6-list +.It Ar ip6-addr : +A host or subnet specified one of the following ways: +.Pp +.Bl -tag -width indent +.It Ar numeric-ip | hostname +Matches a single IPv6 address as allowed by +.Xr inet_pton 3 +or a hostname. +Hostnames are resolved at the time the rule is added to the firewall +list. +.It Ar addr Ns / Ns Ar masklen +Matches all IPv6 addresses with base +.Ar addr +(specified as allowed by +.Xr inet_pton +or a hostname) +and mask width of +.Cm masklen +bits. +.El +.Pp +No support for sets of IPv6 addresses is provided because IPv6 addresses +are typically random past the initial prefix. .It Ar ports : Bro Ar port | port Ns \&- Ns Ar port Ns Brc Ns Op , Ns Ar p= orts For protocols which support port numbers (such as TCP and UDP), optional .Cm ports @@ -954,13 +992,36 @@ Matches only packets going from a divert socket back outward to the IP stack output for delivery. .It Cm dst-ip Ar ip-address -Matches IP packets whose destination IP is one of the address(es) +Matches IPv4 packets whose destination IP is one of the address(es) +specified as argument. +.It Bro Cm dst-ip6 | dst-ipv6 Brc Ar ip6-address +Matches IPv6 packets whose destination IP is one of the address(es) specified as argument. .It Cm dst-port Ar ports Matches IP packets whose destination port is one of the port(s) specified as argument. .It Cm established Matches TCP packets that have the RST or ACK bits set. +.It Cm ext6hdr Ar header +Matches IPv6 packets containing the extended header given by +.Ar header . +Supported headers are: +.Pp +Fragment, +.Pq Cm frag , +Hop-to-hop options +.Pq Cm hopopt , +Source routing +.Pq Cm route , +IPSec authentication headers +.Pq Cm ah , +and IPSec encapsulated security payload headers +.Pq Cm esp . +.It Cm flow-id Ar labels +Matches IPv6 packets containing any of the flow labels given in +.Ar labels . +.Ar labels +is a comma seperate list of numeric flow labels. .It Cm frag Matches packets that are fragments and not the first fragment of an IP datagram. @@ -1015,6 +1076,12 @@ .Pq Cm 17 and address mask reply .Pq Cm 18 . +.It Cm icmp6types Ar types +Matches ICMP6 packets whose ICMP6 type is in the list of +.Ar types . +The list may be specified as any combination of +individual types (numeric) separated by commas. +.Em Ranges are not allowed. .It Cm in | out Matches incoming or outgoing packets, respectively. .Cm in @@ -1025,7 +1092,7 @@ is implemented as .Cm not in Ns No ). .It Cm ipid Ar id-list -Matches IP packets whose +Matches IPv4 packets whose .Cm ip_id field has value included in .Ar id-list , @@ -1040,7 +1107,7 @@ specified in the same way as .Ar ports . .It Cm ipoptions Ar spec -Matches packets whose IP header contains the comma separated list of +Matches packets whose IPv4 header contains the comma separated list of options specified in .Ar spec . The supported IP options are: @@ -1057,7 +1124,7 @@ with a .Ql \&! . .It Cm ipprecedence Ar precedence -Matches IP packets whose precedence field is equal to +Matches IPv4 packets whose precedence field is equal to .Ar precedence . .It Cm ipsec Matches packets that have IPSEC history associated with them @@ -1079,7 +1146,7 @@ .Cm ipsec flag. .It Cm iptos Ar spec -Matches IP packets whose +Matches IPv4 packets whose .Cm tos field contains the comma separated list of service types specified in @@ -1100,7 +1167,7 @@ with a .Ql \&! . .It Cm ipttl Ar ttl-list -Matches IP packets whose time to live is included in +Matches IPv4 packets whose time to live is included in .Ar ttl-list , which is either a single value or a list of values or ranges specified in the same way as @@ -1128,6 +1195,8 @@ One or more of source and destination addresses and ports can be specified. +Currently, +only IPv4 flows are supported. .It Cm { MAC | mac } Ar dst-mac src-mac Match packets with a given .Ar dst-mac @@ -1180,7 +1249,7 @@ .Cm -N option is used, in which case symbolic resolution will be attempted). .It Cm proto Ar protocol -Matches packets with the corresponding IPv4 protocol. +Matches packets with the corresponding IP protocol. .It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar ipno | Ar any Matches packets received, transmitted or going through, respectively, the interface specified by exact name @@ -1228,8 +1297,11 @@ This is the short form of .Dq Li tcpflags\ syn,!ack . .It Cm src-ip Ar ip-address -Matches IP packets whose source IP is one of the address(es) -specified as argument. +Matches IPv4 packets whose source IP is one of the address(es) +specified as an argument. +.It Cm src-ip6 Ar ip6-address +Matches IPv6 packets whose source IP is one of the address(es) +specified as an argument. .It Cm src-port Ar ports Matches IP packets whose source port is one of the port(s) specified as argument. @@ -1356,7 +1428,7 @@ .Sh LOOKUP TABLES Lookup tables are useful to handle large sparse address sets, typically from a hundred to several thousands of entries. -There could be 128 different lookup tables, numbered 0 to 127. +There may be up to 128 different lookup tables, numbered 0 to 127. .Pp Each entry is represented by an .Ar addr Ns Op / Ns Ar masklen @@ -1390,6 +1462,8 @@ Internally, each table is stored in a Radix tree, the same way as the routing table (see .Xr route 4 ) . +.Pp +Lookup tables currently support IPv4 addresses only. .Sh SETS OF RULES Each rule belongs to one of 32 different .Em sets @@ -1662,9 +1736,12 @@ Available mask specifiers are a combination of one or more of the followin= g: .Pp .Cm dst-ip Ar mask , +.Cm dst-ip6 Ar mask , .Cm src-ip Ar mask , +.Cm src-ip6 Ar mask , .Cm dst-port Ar mask , .Cm src-port Ar mask , +.Cm flow-id Ar mask , .Cm proto Ar mask or .Cm all , @@ -1735,6 +1812,14 @@ thresholds are in bytes (defaults to 1500, must be greater than zero). .El .El +.Pp +When used with IPv6 data, dummynet currently has several limitations. +First, debug.mpsafenet=3D0 must be set. +Second, the information necessicary to route link-local packets to an +interface is not avalable after processing by dummynet so those packets +are dropped in the output path. +Care should be taken to insure that link-local packets are not passed to +dummynet. .Sh CHECKLIST Here are some important points to consider when designing your rules: @@ -2060,6 +2145,9 @@ .Nm dummynet pipes/queues is not supported: .Cm noerror . +.It IPv6 Support +There was no IPv6 support in +.Nm ipfw1 . .El .Sh EXAMPLES There are far too many possible uses of @@ -2336,6 +2424,8 @@ .Xr sysctl 8 , .Xr syslogd 8 .Sh BUGS +Use of dummynet with IPv6 requires that debug.mpsafenet be set to 0. +.Pp The syntax has grown over the years and sometimes it might be confusing. Unfortunately, backward compatibility prevents cleaning up mistakes made in the definition of the syntax. @@ -2364,6 +2454,8 @@ applied, making the order of .Cm divert rules in the rule sequence very important. +.Pp +Dummynet drops all packets with IPv6 link-local addresses. .Sh AUTHORS .An Ugen J. S. Antsilevich , .An Poul-Henning Kamp , --- ../cleanup/sys/netinet/ip_dummynet.c Mon Nov 22 12:52:14 2004 +++ sys/netinet/ip_dummynet.c Mon Nov 22 14:18:40 2004 @@ -77,6 +77,9 @@ #include /* for struct arpcom */ #include =20 +#include /* for ip6_input, ip6_output prototypes */ +#include + /* * We keep a private variable for the simulation time, but we could * probably use an existing one ("softticks" in sys/kern/kern_timeout.c) @@ -461,6 +464,14 @@ ip_input(m) ; break ; =20 + case DN_TO_IP6_IN: + ip6_input(m) ; + break ; + + case DN_TO_IP6_OUT: + (void)ip6_output(m, NULL, NULL, pkt->flags, NULL, NULL, NULL); + break ; + case DN_TO_BDG_FWD : /* * The bridge requires/assumes the Ethernet header is @@ -898,37 +909,80 @@ { int i =3D 0 ; /* we need i and q for new allocations */ struct dn_flow_queue *q, *prev; + int is_v6 =3D IS_IP6_FLOW_ID(id); =20 if ( !(fs->flags_fs & DN_HAVE_FLOW_MASK) ) q =3D fs->rq[0] ; else { - /* first, do the masking */ - id->dst_ip &=3D fs->flow_mask.dst_ip ; - id->src_ip &=3D fs->flow_mask.src_ip ; + /* first, do the masking, then hash */ id->dst_port &=3D fs->flow_mask.dst_port ; id->src_port &=3D fs->flow_mask.src_port ; id->proto &=3D fs->flow_mask.proto ; id->flags =3D 0 ; /* we don't care about this one */ - /* then, hash function */ - i =3D ( (id->dst_ip) & 0xffff ) ^ - ( (id->dst_ip >> 15) & 0xffff ) ^ - ( (id->src_ip << 1) & 0xffff ) ^ - ( (id->src_ip >> 16 ) & 0xffff ) ^ - (id->dst_port << 1) ^ (id->src_port) ^ - (id->proto ); + if (is_v6) { + APPLY_MASK(&id->dst_ip6, &fs->flow_mask.dst_ip6); + APPLY_MASK(&id->src_ip6, &fs->flow_mask.src_ip6); + id->flow_id6 &=3D fs->flow_mask.flow_id6; + + i =3D ((id->dst_ip6.__u6_addr.__u6_addr32[0]) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[1]) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[2]) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[3]) & 0xffff)^ + + ((id->dst_ip6.__u6_addr.__u6_addr32[0] >> 15) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[1] >> 15) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[2] >> 15) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[3] >> 15) & 0xffff)^ + + ((id->src_ip6.__u6_addr.__u6_addr32[0] << 1) & 0xfffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[1] << 1) & 0xfffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[2] << 1) & 0xfffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[3] << 1) & 0xfffff)^ + + ((id->src_ip6.__u6_addr.__u6_addr32[0] << 16) & 0xffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[1] << 16) & 0xffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[2] << 16) & 0xffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[3] << 16) & 0xffff)^ + + (id->dst_port << 1) ^ (id->src_port) ^ + (id->proto ) ^ + (id->flow_id6); + } else { + id->dst_ip &=3D fs->flow_mask.dst_ip ; + id->src_ip &=3D fs->flow_mask.src_ip ; + + i =3D ( (id->dst_ip) & 0xffff ) ^ + ( (id->dst_ip >> 15) & 0xffff ) ^ + ( (id->src_ip << 1) & 0xffff ) ^ + ( (id->src_ip >> 16 ) & 0xffff ) ^ + (id->dst_port << 1) ^ (id->src_port) ^ + (id->proto ); + } i =3D i % fs->rq_size ; /* finally, scan the current list for a match */ searches++ ; for (prev=3DNULL, q =3D fs->rq[i] ; q ; ) { search_steps++; - if (id->dst_ip =3D=3D q->id.dst_ip && + if (is_v6 && + IN6_ARE_ADDR_EQUAL(&id->dst_ip6,&q->id.dst_ip6) && =20 + IN6_ARE_ADDR_EQUAL(&id->src_ip6,&q->id.src_ip6) && =20 + id->dst_port =3D=3D q->id.dst_port && + id->src_port =3D=3D q->id.src_port && + id->proto =3D=3D q->id.proto && + id->flags =3D=3D q->id.flags && + id->flow_id6 =3D=3D q->id.flow_id6) + break ; /* found */ + + if (!is_v6 && id->dst_ip =3D=3D q->id.dst_ip && id->src_ip =3D=3D q->id.src_ip && id->dst_port =3D=3D q->id.dst_port && id->src_port =3D=3D q->id.src_port && id->proto =3D=3D q->id.proto && id->flags =3D=3D q->id.flags) break ; /* found */ - else if (pipe_expire && q->head =3D=3D NULL && q->S =3D=3D q->F+1 ) { + + /* No match. Check if we can expire the entry */ + if (pipe_expire && q->head =3D=3D NULL && q->S =3D=3D q->F+1 ) { /* entry is idle and not in any heap, expire it */ struct dn_flow_queue *old_q =3D q ; =20 @@ -1202,8 +1256,9 @@ pkt->dn_dir =3D dir ; =20 pkt->ifp =3D fwa->oif; - if (dir =3D=3D DN_TO_IP_OUT) + if (dir =3D=3D DN_TO_IP_OUT || dir =3D=3D DN_TO_IP6_OUT) pkt->flags =3D fwa->flags; + if (q->head =3D=3D NULL) q->head =3D m; else @@ -2017,7 +2072,7 @@ ip_dn_init(void) { if (bootverbose) - printf("DUMMYNET initialized (011031)\n"); + printf("DUMMYNET with IPv6 initialized (040826)\n"); =20 DUMMYNET_LOCK_INIT(); =20 --- ../cleanup/sys/netinet/ip_dummynet.h Thu Aug 26 18:01:22 2004 +++ sys/netinet/ip_dummynet.h Thu Sep 16 22:03:45 2004 @@ -124,10 +124,13 @@ #define DN_TO_BDG_FWD 3 #define DN_TO_ETH_DEMUX 4 #define DN_TO_ETH_OUT 5 +#define DN_TO_IP6_IN 6 +#define DN_TO_IP6_OUT 7 =20 dn_key output_time; /* when the pkt is due for delivery */ struct ifnet *ifp; /* interface, for ip_output */ int flags ; /* flags, for ip_output (IPv6 ?) */ + struct _ip6dn_args ip6opt; /* XXX ipv6 options */ }; #endif /* _KERNEL */ =20 --- ../cleanup/sys/netinet/ip_fw.h Wed Oct 6 18:30:46 2004 +++ sys/netinet/ip_fw.h Sat Oct 23 17:44:48 2004 @@ -137,11 +137,31 @@ O_ALTQ, /* u32 =3D altq classif. qid */ O_DIVERTED, /* arg1=3Dbitmap (1:loop, 2:out) */ O_TCPDATALEN, /* arg1 =3D tcp data len */ + O_IP6_SRC, /* address without mask */ + O_IP6_SRC_ME, /* my addresses */ + O_IP6_SRC_MASK, /* address with the mask */ + O_IP6_DST, + O_IP6_DST_ME, + O_IP6_DST_MASK, + O_FLOW6ID, /* for flow id tag in the ipv6 pkt */ + O_ICMP6TYPE, /* icmp6 packet type filtering */ + O_EXT_HDR, /* filtering for ipv6 extension header */ + O_IP6, =20 O_LAST_OPCODE /* not an opcode! */ }; =20 /* + * The extension header are filtered only for presence using a bit + * vector with a flag for each header. + */ +#define EXT_FRAGMENT 0x1 +#define EXT_HOPOPTS 0x2 +#define EXT_ROUTING 0x4 +#define EXT_AH 0x8 +#define EXT_ESP 0x10 + +/* * Template for instructions. * * ipfw_insn is used for all instructions which require no operands, @@ -285,6 +305,30 @@ u_int32_t log_left; /* how many left to log */ } ipfw_insn_log; =20 +/* Apply ipv6 mask on ipv6 addr */ +#define APPLY_MASK(addr,mask) \ + (addr)->__u6_addr.__u6_addr32[0] &=3D (mask)->__u6_addr.__u6_addr32[0]= ; \ + (addr)->__u6_addr.__u6_addr32[1] &=3D (mask)->__u6_addr.__u6_addr32[1]= ; \ + (addr)->__u6_addr.__u6_addr32[2] &=3D (mask)->__u6_addr.__u6_addr32[2]= ; \ + (addr)->__u6_addr.__u6_addr32[3] &=3D (mask)->__u6_addr.__u6_addr32[3]; + +/* Structure for ipv6 */ +typedef struct _ipfw_insn_ip6 { + ipfw_insn o; + struct in6_addr addr6; + struct in6_addr mask6; +} ipfw_insn_ip6; + +/* Used to support icmp6 types */ +typedef struct _ipfw_insn_icmp6 { + ipfw_insn o; + uint32_t d[7]; /* XXX This number si related to the netinet/icmp6.h + * define ICMP6_MAXTYPE + * as follows: n =3D ICMP6_MAXTYPE/32 + 1 + * Actually is 203=20 + */ +} ipfw_insn_icmp6; + /* * Here we have the structure representing an ipfw rule. * @@ -348,8 +392,14 @@ u_int16_t src_port; u_int8_t proto; u_int8_t flags; /* protocol-specific flags */ + uint8_t addr_type; /* 4 =3D ipv4, 6 =3D ipv6, 1=3Dether ? */ + struct in6_addr dst_ip6; /* could also store MAC addr! */ + struct in6_addr src_ip6; + u_int32_t flow_id6; }; =20 +#define IS_IP6_FLOW_ID(id) ((id)->addr_type =3D=3D 6) + /* * Dynamic ipfw rule. */ @@ -424,6 +474,21 @@ #define IP_FW_DIVERT_OUTPUT_FLAG 0x00100000 =20 /* + * Structure for collecting parameters to dummynet for ip6_output forwardi= ng + */ +struct _ip6dn_args { + struct ip6_pktopts *opt_or; + struct route_in6 ro_or; + int flags_or; + struct ip6_moptions *im6o_or; + struct ifnet *origifp_or; + struct ifnet *ifp_or; + struct sockaddr_in6 dst_or; + u_long mtu_or; + struct route_in6 ro_pmtu_or; +}; + +/* * Arguments for calling ipfw_chk() and dummynet_io(). We put them * all into a structure because this way it is easier and more * efficient to pass variables around and extend the interface. @@ -440,6 +505,8 @@ struct ipfw_flow_id f_id; /* grabbed from IP header */ u_int32_t retval; struct inpcb *inp; + + struct _ip6dn_args dummypar; /* dummynet->ip6_output */ }; =20 /* --- ../cleanup/sys/netinet/ip_fw2.c Mon Dec 13 22:07:04 2004 +++ sys/netinet/ip_fw2.c Mon Dec 20 13:28:11 2004 @@ -83,6 +83,9 @@ #include #endif =20 +#include +#include + #include /* XXX for ETHERTYPE_IP */ =20 #include /* XXX for in_cksum */ @@ -321,6 +324,7 @@ #define TCP(p) ((struct tcphdr *)(p)) #define UDP(p) ((struct udphdr *)(p)) #define ICMP(p) ((struct icmp *)(p)) +#define ICMP6(p) ((struct icmp6_hdr *)(p)) =20 static __inline int icmptype_match(struct icmp *icmp, ipfw_insn_u32 *cmd) @@ -551,6 +555,83 @@ return 1; } =20 +/* + * ipv6 specific rules here... + */ +static __inline int +icmp6type_match (int type, ipfw_insn_u32 *cmd) +{ + return (type <=3D ICMP6_MAXTYPE && (cmd->d[type/32] & (1<<(type%32)= ) ) ); +} + +static int +flow6id_match( int curr_flow, ipfw_insn_u32 *cmd ) +{ + int i; + for (i=3D0; i <=3D cmd->o.arg1; ++i ) + if (curr_flow =3D=3D cmd->d[i] ) + return 1; + return 0; +} + +/* support for IP6_*_ME opcodes */ +static int +search_ip6_addr_net (struct in6_addr * ip6_addr) +{ + struct ifnet *mdc; + struct ifaddr *mdc2; + struct in6_ifaddr *fdm; + struct in6_addr copia; + + TAILQ_FOREACH(mdc, &ifnet, if_link) + for (mdc2 =3D mdc->if_addrlist.tqh_first; mdc2; + mdc2 =3D mdc2->ifa_list.tqe_next) { + if (!mdc2->ifa_addr) + continue; + if (mdc2->ifa_addr->sa_family =3D=3D AF_INET6) { + fdm =3D (struct in6_ifaddr *)mdc2; + copia =3D fdm->ia_addr.sin6_addr; + /* need for leaving scope_id in the sock_ad= dr */ + in6_clearscope(&copia); + if (IN6_ARE_ADDR_EQUAL(ip6_addr, &copia)) + return 1; + } + } + return 0; +} + +static int +verify_rev_path6(struct in6_addr *src, struct ifnet *ifp) +{ + static struct route_in6 ro; + struct sockaddr_in6 *dst; + + dst =3D (struct sockaddr_in6 * )&(ro.ro_dst); + + if ( !(IN6_ARE_ADDR_EQUAL (src, &dst->sin6_addr) )) { + bzero(dst, sizeof(*dst)); + dst->sin6_family =3D AF_INET6; + dst->sin6_len =3D sizeof(*dst); + dst->sin6_addr =3D *src; + rtalloc_ign((struct route *)&ro, RTF_CLONING); + } + if ((ro.ro_rt =3D=3D NULL) || (ifp =3D=3D NULL) || + (ro.ro_rt->rt_ifp->if_index !=3D ifp->if_index)) + return 0; + return 1; +} +static __inline int +hash_packet6(struct ipfw_flow_id *id) +{ + u_int32_t i; + i=3D (id->dst_ip6.__u6_addr.__u6_addr32[0]) ^ + (id->dst_ip6.__u6_addr.__u6_addr32[1]) ^ + (id->dst_ip6.__u6_addr.__u6_addr32[2]) ^ + (id->dst_ip6.__u6_addr.__u6_addr32[3]) ^ + (id->dst_port) ^ (id->src_port) ^ (id->flow_id6); + return i; +} +/* end of ipv6 opcodes */ =20 static u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */ =20 @@ -761,7 +842,8 @@ { u_int32_t i; =20 - i =3D (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port); + i =3D IS_IP6_FLOW_ID(id) ? hash_packet6(id): + (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port); i &=3D (curr_dyn_buckets - 1); return i; } @@ -900,19 +982,40 @@ } if (pkt->proto =3D=3D q->id.proto && q->dyn_type !=3D O_LIMIT_PARENT) { - if (pkt->src_ip =3D=3D q->id.src_ip && - pkt->dst_ip =3D=3D q->id.dst_ip && + if (IS_IP6_FLOW_ID(pkt)) { + if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6), + &(q->id.src_ip6)) && + IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6), + &(q->id.dst_ip6)) && pkt->src_port =3D=3D q->id.src_port && pkt->dst_port =3D=3D q->id.dst_port ) { dir =3D MATCH_FORWARD; break; - } - if (pkt->src_ip =3D=3D q->id.dst_ip && - pkt->dst_ip =3D=3D q->id.src_ip && - pkt->src_port =3D=3D q->id.dst_port && - pkt->dst_port =3D=3D q->id.src_port ) { - dir =3D MATCH_REVERSE; - break; + } + if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6), + &(q->id.dst_ip6)) && + IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6), + &(q->id.src_ip6)) && + pkt->src_port =3D=3D q->id.dst_port && + pkt->dst_port =3D=3D q->id.src_port ) { + dir =3D MATCH_REVERSE; + break; + } + } else { + if (pkt->src_ip =3D=3D q->id.src_ip && + pkt->dst_ip =3D=3D q->id.dst_ip && + pkt->src_port =3D=3D q->id.src_port && + pkt->dst_port =3D=3D q->id.dst_port ) { + dir =3D MATCH_FORWARD; + break; + } + if (pkt->src_ip =3D=3D q->id.dst_ip && + pkt->dst_ip =3D=3D q->id.src_ip && + pkt->src_port =3D=3D q->id.dst_port && + pkt->dst_port =3D=3D q->id.src_port ) { + dir =3D MATCH_REVERSE; + break; + } } } next: @@ -1110,15 +1213,25 @@ IPFW_DYN_LOCK_ASSERT(); =20 if (ipfw_dyn_v) { + int is_v6 =3D IS_IP6_FLOW_ID(pkt); i =3D hash_packet( pkt ); for (q =3D ipfw_dyn_v[i] ; q !=3D NULL ; q=3Dq->next) if (q->dyn_type =3D=3D O_LIMIT_PARENT && rule=3D=3D q->rule && pkt->proto =3D=3D q->id.proto && - pkt->src_ip =3D=3D q->id.src_ip && - pkt->dst_ip =3D=3D q->id.dst_ip && pkt->src_port =3D=3D q->id.src_port && - pkt->dst_port =3D=3D q->id.dst_port) { + pkt->dst_port =3D=3D q->id.dst_port && + ( + (is_v6 && + IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6), + &(q->id.src_ip6)) && + IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6), + &(q->id.dst_ip6))) || + (!is_v6 && + pkt->src_ip =3D=3D q->id.src_ip && + pkt->dst_ip =3D=3D q->id.dst_ip) + ) + ) { q->expire =3D time_second + dyn_short_lifetime; DEB(printf("ipfw: lookup_dyn_parent found 0x%p\n",q);) return q; @@ -1192,10 +1305,17 @@ id.dst_port =3D id.src_port =3D 0; id.proto =3D args->f_id.proto; =20 - if (limit_mask & DYN_SRC_ADDR) - id.src_ip =3D args->f_id.src_ip; - if (limit_mask & DYN_DST_ADDR) - id.dst_ip =3D args->f_id.dst_ip; + if (IS_IP6_FLOW_ID (&(args->f_id))) { + if (limit_mask & DYN_SRC_ADDR) + id.src_ip6 =3D args->f_id.src_ip6; + if (limit_mask & DYN_DST_ADDR) + id.dst_ip6 =3D args->f_id.dst_ip6; + } else { + if (limit_mask & DYN_SRC_ADDR) + id.src_ip =3D args->f_id.src_ip; + if (limit_mask & DYN_DST_ADDR) + id.dst_ip =3D args->f_id.dst_ip; + } if (limit_mask & DYN_SRC_PORT) id.src_port =3D args->f_id.src_port; if (limit_mask & DYN_DST_PORT) @@ -1822,6 +1942,10 @@ * ulp is NULL if not found. */ void *ulp =3D NULL; /* upper layer protocol pointer. */ + /* XXX ipv6 variables */ + int is_ipv6 =3D 0; + u_int16_t ext_hd =3D 0; /* bits vector for extension header filtering */ + /* end of ipv6 variables */ =20 if (m->m_flags & M_SKIP_FIREWALL) return 0; /* accept */ @@ -1846,15 +1970,95 @@ p =3D (mtod(m, char *) + (len)); \ } while (0) =20 - /* Identify IP packets and fill up veriables. */ - if (pktlen >=3D sizeof(struct ip) && + /* Identify IP packets and fill up variables. */ + if (pktlen >=3D sizeof(struct ip6_hdr) && + (args->eh =3D=3D NULL || ntohs(args->eh->ether_type)=3D=3DETHERTYPE_I= PV6) && + mtod(m, struct ip *)->ip_v =3D=3D 6) { + is_ipv6 =3D 1; + args->f_id.addr_type =3D 6; + hlen =3D sizeof(struct ip6_hdr); + proto =3D mtod(m, struct ip6_hdr *)->ip6_nxt; + + /* Search extension headers to find upper layer protocols */ + while (ulp =3D=3D NULL) { + switch (proto) { + case IPPROTO_ICMPV6: + PULLUP_TO(hlen, ulp, struct icmp6_hdr); + args->f_id.flags =3D ICMP6(ulp)->icmp6_type; + break; + + case IPPROTO_TCP: + PULLUP_TO(hlen, ulp, struct tcphdr); + dst_port =3D TCP(ulp)->th_dport; + src_port =3D TCP(ulp)->th_sport; + args->f_id.flags =3D TCP(ulp)->th_flags; + break; + + case IPPROTO_UDP: + PULLUP_TO(hlen, ulp, struct udphdr); + dst_port =3D UDP(ulp)->uh_dport; + src_port =3D UDP(ulp)->uh_sport; + break; + + case IPPROTO_HOPOPTS: + PULLUP_TO(hlen, ulp, struct ip6_hbh); + ext_hd |=3D EXT_HOPOPTS; + hlen +=3D sizeof(struct ip6_hbh); + proto =3D ((struct ip6_hbh *)ulp)->ip6h_nxt; + ulp =3D NULL; + break; + + case IPPROTO_ROUTING: + PULLUP_TO(hlen, ulp, struct ip6_rthdr); + ext_hd |=3D EXT_ROUTING; + hlen +=3D sizeof(struct ip6_rthdr); + proto =3D ((struct ip6_rthdr *)ulp)->ip6r_nxt; + ulp =3D NULL; + break; + + case IPPROTO_FRAGMENT: + PULLUP_TO(hlen, ulp, struct ip6_frag); + ext_hd |=3D EXT_FRAGMENT; + hlen +=3D sizeof (struct ip6_frag); + proto =3D ((struct ip6_frag *)ulp)->ip6f_nxt; + offset =3D 1; + ulp =3D NULL; /* XXX is it correct ? */ + break; + + case IPPROTO_AH: + case IPPROTO_NONE: + case IPPROTO_ESP: + PULLUP_TO(hlen, ulp, struct ip6_ext); + if (proto =3D=3D IPPROTO_AH) + ext_hd |=3D EXT_AH; + else if (proto =3D=3D IPPROTO_ESP) + ext_hd |=3D EXT_ESP; + hlen +=3D ((struct ip6_ext *)ulp)->ip6e_len + + sizeof (struct ip6_ext); + proto =3D ((struct ip6_ext *)ulp)->ip6e_nxt; + ulp =3D NULL; + break; + + default: + printf( "IPFW2: IPV6 - Unknown Extension Header (%d)\n", + proto); + return 0; /* deny */ + break; + } /*switch */ + } + args->f_id.src_ip6 =3D mtod(m,struct ip6_hdr *)->ip6_src; + args->f_id.dst_ip6 =3D mtod(m,struct ip6_hdr *)->ip6_dst; + args->f_id.src_ip =3D 0; + args->f_id.dst_ip =3D 0; + args->f_id.flow_id6 =3D ntohs(mtod(m, struct ip6_hdr *)->ip6_flow); + /* hlen !=3D 0 is used to detect ipv4 packets, so clear it now */ + hlen =3D 0; + } else if (pktlen >=3D sizeof(struct ip) && (args->eh =3D=3D NULL || ntohs(args->eh->ether_type) =3D=3D ETHERTYPE= _IP) && mtod(m, struct ip *)->ip_v =3D=3D 4) { ip =3D mtod(m, struct ip *); hlen =3D ip->ip_hl << 2; -#ifdef NOTYET args->f_id.addr_type =3D 4; -#endif =20 /* * Collect parameters into local variables for faster matching. @@ -2018,11 +2222,13 @@ case O_JAIL: /* * We only check offset =3D=3D 0 && proto !=3D 0, - * as this ensures that we have an IPv4 + * as this ensures that we have a * packet with the ports info. */ if (offset!=3D0) break; + if (is_ipv6) /* XXX to be fixed later */ + break; if (proto =3D=3D IPPROTO_TCP || proto =3D=3D IPPROTO_UDP) match =3D check_uidgid( @@ -2077,7 +2283,7 @@ break; =20 case O_FRAG: - match =3D (hlen > 0 && offset !=3D 0); + match =3D (offset !=3D 0); break; =20 case O_IN: /* "out" is "not in" */ @@ -2186,7 +2392,7 @@ case O_IP_DSTPORT: /* * offset =3D=3D 0 && proto !=3D 0 is enough - * to guarantee that we have an IPv4 + * to guarantee that we have a * packet with port info. */ if ((proto=3D=3DIPPROTO_UDP || proto=3D=3DIPPROTO_TCP) @@ -2209,12 +2415,22 @@ icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) ); break; =20 + case O_ICMP6TYPE: + match =3D is_ipv6 && offset =3D=3D 0 && + proto=3D=3DIPPROTO_ICMPV6 && + icmp6type_match( + ICMP6(ulp)->icmp6_type, + (ipfw_insn_u32 *)cmd); + break; + case O_IPOPT: - match =3D (hlen > 0 && ipopts_match(ip, cmd) ); + match =3D (hlen > 0 && + ipopts_match(mtod(m, struct ip *), cmd) ); break; =20 case O_IPVER: - match =3D (hlen > 0 && cmd->arg1 =3D=3D ip->ip_v); + match =3D (hlen > 0 && + cmd->arg1 =3D=3D mtod(m, struct ip *)->ip_v); break; =20 case O_IPID: @@ -2228,9 +2444,9 @@ if (cmd->opcode =3D=3D O_IPLEN) x =3D ip_len; else if (cmd->opcode =3D=3D O_IPTTL) - x =3D ip->ip_ttl; + x =3D mtod(m, struct ip *)->ip_ttl; else /* must be IPID */ - x =3D ntohs(ip->ip_id); + x =3D ntohs(mtod(m, struct ip *)->ip_id); if (cmdlen =3D=3D 1) { match =3D (cmd->arg1 =3D=3D x); break; @@ -2245,12 +2461,12 @@ =20 case O_IPPRECEDENCE: match =3D (hlen > 0 && - (cmd->arg1 =3D=3D (ip->ip_tos & 0xe0)) ); + (cmd->arg1 =3D=3D (mtod(m, struct ip *)->ip_tos & 0xe0)) ); break; =20 case O_IPTOS: match =3D (hlen > 0 && - flags_match(cmd, ip->ip_tos)); + flags_match(cmd, mtod(m, struct ip *)->ip_tos)); break; =20 case O_TCPDATALEN: @@ -2348,8 +2564,12 @@ =20 case O_VERREVPATH: /* Outgoing packets automatically pass/match */ - match =3D (hlen > 0 && ((oif !=3D NULL) || + /* XXX BED: verify_path was verify_rev_path in the diff... */ + match =3D ((oif !=3D NULL) || (m->m_pkthdr.rcvif =3D=3D NULL) || + (is_ipv6 ? + verify_rev_path6(&(args->f_id.src_ip6), + m->m_pkthdr.rcvif) : verify_path(src_ip, m->m_pkthdr.rcvif))); break; =20 @@ -2380,6 +2600,60 @@ /* otherwise no match */ break; =20 + case O_IP6_SRC: + match =3D is_ipv6 && + IN6_ARE_ADDR_EQUAL(&args->f_id.src_ip6, + &((ipfw_insn_ip6 *)cmd)->addr6); + break; + + case O_IP6_DST: + match =3D is_ipv6 && + IN6_ARE_ADDR_EQUAL(&args->f_id.dst_ip6, + &((ipfw_insn_ip6 *)cmd)->addr6); + break; + case O_IP6_SRC_MASK: + if (is_ipv6) { + ipfw_insn_ip6 *te =3D (ipfw_insn_ip6 *)cmd; + struct in6_addr p =3D args->f_id.src_ip6; + + APPLY_MASK(&p, &te->mask6); + match =3D IN6_ARE_ADDR_EQUAL(&te->addr6, &p); + } + break; + + case O_IP6_DST_MASK: + if (is_ipv6) { + ipfw_insn_ip6 *te =3D (ipfw_insn_ip6 *)cmd; + struct in6_addr p =3D args->f_id.dst_ip6; + + APPLY_MASK(&p, &te->mask6); + match =3D IN6_ARE_ADDR_EQUAL(&te->addr6, &p); + } + break; + + case O_IP6_SRC_ME: + match=3D is_ipv6 && search_ip6_addr_net(&args->f_id.src_ip6); + break; + + case O_IP6_DST_ME: + match=3D is_ipv6 && search_ip6_addr_net(&args->f_id.dst_ip6); + break; + + case O_FLOW6ID: + match =3D is_ipv6 && + flow6id_match(args->f_id.flow_id6, + (ipfw_insn_u32 *) cmd); + break; + + case O_EXT_HDR: + match =3D is_ipv6 && + (ext_hd & ((ipfw_insn *) cmd)->arg1); + break; + + case O_IP6: + match =3D is_ipv6; + break; + /* * The second set of opcodes represents 'actions', * i.e. the terminal part of a rule once the packet @@ -3013,6 +3287,10 @@ case O_VERSRCREACH: case O_ANTISPOOF: case O_IPSEC: + case O_IP6_SRC_ME: + case O_IP6_DST_ME: + case O_EXT_HDR: + case O_IP6: if (cmdlen !=3D F_INSN_SIZE(ipfw_insn)) goto bad_size; break; @@ -3151,6 +3429,29 @@ return EINVAL; } break; + case O_IP6_SRC: + case O_IP6_DST: + if (cmdlen !=3D F_INSN_SIZE(struct in6_addr) + + F_INSN_SIZE(ipfw_insn)) + goto bad_size; + break; + + case O_FLOW6ID: + if (cmdlen !=3D F_INSN_SIZE(ipfw_insn_u32) + + ((ipfw_insn_u32 *)cmd)->o.arg1) + goto bad_size; + break; + + case O_IP6_SRC_MASK: + case O_IP6_DST_MASK: + if ( !(cmdlen & 1) || cmdlen > 127) + goto bad_size; + break; + case O_ICMP6TYPE: + if( cmdlen !=3D F_INSN_SIZE( ipfw_insn_icmp6 ) ) + goto bad_size; + break; + default: printf("ipfw: opcode %d, unknown opcode\n", cmd->opcode); @@ -3548,7 +3849,7 @@ } =20 ip_fw_default_rule =3D layer3_chain.rules; - printf("ipfw2 initialized, divert %s, " + printf("ipfw2 (+ipv6) initialized, divert %s, " "rule-based forwarding " #ifdef IPFIREWALL_FORWARD "enabled, " --- ../cleanup/sys/netinet/ip_fw_pfil.c Mon Dec 13 22:07:04 2004 +++ sys/netinet/ip_fw_pfil.c Mon Dec 20 13:28:12 2004 @@ -30,6 +30,7 @@ #include "opt_ipfw.h" #include "opt_ipdn.h" #include "opt_inet.h" +#include "opt_inet6.h" #ifndef INET #error IPFIREWALL requires INET. #endif /* INET */ @@ -116,7 +117,10 @@ goto pass; =20 if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) !=3D 0) { - ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_IN, &args); + if (mtod(*m0, struct ip *)->ip_v =3D=3D 4) + ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_IN, &args); + else if (mtod(*m0, struct ip *)->ip_v =3D=3D 6) + ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP6_IN, &args); *m0 =3D NULL; return 0; /* packet consumed */ } @@ -202,7 +206,10 @@ goto pass; =20 if (DUMMYNET_LOADED && (ipfw & IP_FW_PORT_DYNT_FLAG) !=3D 0) { - ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_OUT, &args); + if (mtod(*m0, struct ip *)->ip_v =3D=3D 4) + ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP_OUT, &args); + else if (mtod(*m0, struct ip *)->ip_v =3D=3D 6) + ip_dn_io_ptr(*m0, ipfw & 0xffff, DN_TO_IP6_OUT, &args); *m0 =3D NULL; return 0; /* packet consumed */ } @@ -337,6 +344,9 @@ ipfw_hook(void) { struct pfil_head *pfh_inet; +#ifdef INET6 + struct pfil_head *pfh_inet6; +#endif =20 if (ipfw_pfil_hooked) return EEXIST; @@ -344,9 +354,18 @@ pfh_inet =3D pfil_head_get(PFIL_TYPE_AF, AF_INET); if (pfh_inet =3D=3D NULL) return ENOENT; +#ifdef INET6 + pfh_inet6 =3D pfil_head_get(PFIL_TYPE_AF, AF_INET6); + if (pfh_inet6 =3D=3D NULL) + return ENOENT; +#endif =20 pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); +#ifdef INET6 + pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); + pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); +#endif =20 return 0; } @@ -355,6 +374,9 @@ ipfw_unhook(void) { struct pfil_head *pfh_inet; +#ifdef INET6 + struct pfil_head *pfh_inet6; +#endif =20 if (!ipfw_pfil_hooked) return ENOENT; @@ -362,9 +384,18 @@ pfh_inet =3D pfil_head_get(PFIL_TYPE_AF, AF_INET); if (pfh_inet =3D=3D NULL) return ENOENT; +#ifdef INET6 + pfh_inet6 =3D pfil_head_get(PFIL_TYPE_AF, AF_INET6); + if (pfh_inet6 =3D=3D NULL) + return ENOENT; +#endif =20 pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); +#ifdef INET6 + pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); + pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); +#endif =20 return 0; } --- ../cleanup/sys/netinet6/ip6_output.c Wed Oct 6 18:30:54 2004 +++ sys/netinet6/ip6_output.c Sat Oct 23 17:45:02 2004 @@ -78,6 +78,7 @@ #include =20 #include +#include #include #include =20 @@ -167,6 +168,7 @@ int hlen, tlen, len, off; struct route_in6 ip6route; struct sockaddr_in6 *dst; + struct in6_addr odst; int error =3D 0; struct in6_ifaddr *ia =3D NULL; u_long mtu; @@ -525,6 +527,7 @@ ro =3D &opt->ip6po_route; dst =3D (struct sockaddr_in6 *)&ro->ro_dst; =20 +again: /* * If there is a cached route, * check that it is to the same destination @@ -938,11 +941,34 @@ if (inet6_pfil_hook.ph_busy_count =3D=3D -1) goto passout; =20 + odst =3D ip6->ip6_dst; /* Run through list of hooks for output packets. */ error =3D pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT, inp); if (error !=3D 0 || m =3D=3D NULL) goto done; ip6 =3D mtod(m, struct ip6_hdr *); + + /* See if destination IP address was changed by packet filter. */ + if (!IN6_ARE_ADDR_EQUAL(&odst, &ip6->ip6_dst)) { + m->m_flags |=3D M_SKIP_FIREWALL; + /* If destination is now ourself drop to ip6_input(). */ + if (in6_localaddr(&ip6->ip6_dst)) { + if (m->m_pkthdr.rcvif =3D=3D NULL) + m->m_pkthdr.rcvif =3D loif; + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + m->m_pkthdr.csum_flags |=3D + CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data =3D 0xffff; + } + m->m_pkthdr.csum_flags |=3D + CSUM_IP_CHECKED | CSUM_IP_VALID; + error =3D netisr_queue(NETISR_IPV6, m); + goto done; + } else + goto again; /* Redo the routing table lookup. */ + } + + /* XXX: IPFIREWALL_FORWARD */ =20 passout: /* Changed files: sbin/ipfw/ipfw2.c sbin/ipfw/ipfw.8 sys/netinet/ip_dummynet.c sys/netinet/ip_dummynet.h sys/netinet/ip_fw.h sys/netinet/ip_fw2.c sys/netinet/ip_fw_pfil.c sys/netinet6/ip6_output.c --FCuugMFkClbJLl1L Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.1 (GNU/Linux) iD8DBQFBx0VBXY6L6fI4GtQRAsibAKDiRvnrR4TtTk5LbJTYho+GB1SQQACeOAnh TCxUM10e5Zi32beePzfRjE8= =JTjD -----END PGP SIGNATURE----- --FCuugMFkClbJLl1L-- From owner-freebsd-ipfw@FreeBSD.ORG Tue Dec 21 10:36:55 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id AD54616A4CF for ; Tue, 21 Dec 2004 10:36:55 +0000 (GMT) Received: from otaku.Xtrmntr.org (sauna.silcnet.org [147.175.66.205]) by mx1.FreeBSD.org (Postfix) with ESMTP id 8DD8843D1F for ; Tue, 21 Dec 2004 10:36:53 +0000 (GMT) (envelope-from techie@Xtrmntr.org) Received: by otaku.Xtrmntr.org (Postfix, from userid 213) id 351E11D19F; Tue, 21 Dec 2004 11:36:50 +0100 (CET) Date: Tue, 21 Dec 2004 11:36:50 +0100 From: Vladimir Kotal To: freebsd-ipfw@freebsd.org Message-ID: <20041221103650.GC25908@otaku.xtrmntr.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="7ZAtKRhVyVSsbBD2" Content-Disposition: inline User-Agent: Mutt/1.4.2.1i Accept-Languages: cz, sk, en X-Content-Filtered-By: Mailman/MimeDel 2.1.1 Subject: Re: ipfw2 for IPV6 X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: vlada@devnull.cz List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Dec 2004 10:36:55 -0000 --7ZAtKRhVyVSsbBD2 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Sep 03, 2004 at 02:51:37PM -0700, Brooks Davis wrote: > > I've included a patch against current below. Be aware that you must > run with debug.mpsafenet=0 if you want to try IPv6 output rules. The > current code doesn't handle the case where the firewall changes the > destination, but modulo bugs, we are probably at feature parity with > ip6fw. Hello, I'm attaching another variation of Luigi's/Mariano's patch. This is patch against 4.10-RELEASE and has following features/problems: - packet matching works in both directions in the right constellation - I've added logging code from ip6_fw.c - sbin/ipfw2.c parsing code can cause incorrect functionality, even segfault in some cases (see included regress script) v. --7ZAtKRhVyVSsbBD2 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="ipfw2-ipv6-dummynet.patch" diff -uNr --exclude=compile src.orig/sbin/ipfw/ipfw2.c src/sbin/ipfw/ipfw2.c --- src.orig/sbin/ipfw/ipfw2.c Sat Jan 31 20:16:46 2004 +++ src/sbin/ipfw/ipfw2.c Tue Dec 21 11:18:27 2004 @@ -53,6 +53,7 @@ #include #include #include +#include int do_resolv, /* Would try to resolve all */ @@ -244,6 +245,13 @@ TOK_DROPTAIL, TOK_PROTO, TOK_WEIGHT, + + TOK_IPV6, + TOK_FLOWID, + TOK_ICMP6TYPES, + TOK_EXT6HDR, + TOK_DSTIP6, + TOK_SRCIP6, }; struct _s_x dummynet_params[] = { @@ -266,6 +274,13 @@ { "delay", TOK_DELAY }, { "pipe", TOK_PIPE }, { "queue", TOK_QUEUE }, + + { "flow-id", TOK_FLOWID}, + { "dst-ipv6", TOK_DSTIP6}, + { "dst-ip6", TOK_DSTIP6}, + { "src-ipv6", TOK_SRCIP6}, + { "src-ip6", TOK_SRCIP6}, + { "dummynet-params", TOK_NULL }, { NULL, 0 } /* terminator */ }; @@ -340,6 +355,16 @@ { "ipsec", TOK_IPSEC }, { "//", TOK_COMMENT }, + { "icmp6type", TOK_ICMP6TYPES }, + { "icmp6types", TOK_ICMP6TYPES }, + { "ext6hdr", TOK_EXT6HDR}, + { "flow-id", TOK_FLOWID}, + { "ipv6", TOK_IPV6}, + { "dst-ipv6", TOK_DSTIP6}, + { "dst-ip6", TOK_DSTIP6}, + { "src-ipv6", TOK_SRCIP6}, + { "src-ip6", TOK_SRCIP6}, + { "not", TOK_NOT }, /* pseudo option */ { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ { "or", TOK_OR }, /* pseudo option */ @@ -827,6 +852,197 @@ } } +/* XXX ipv6 stuff */ +/* + * Print the ip address contained in a command. + */ +static void +print_ip6(ipfw_insn_ip6 *cmd, char const *s) +{ + struct hostent *he = NULL; + int len = F_LEN((ipfw_insn *) cmd) - 1; + struct in6_addr *a = &(cmd->addr6); + char trad[255]; + + printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); + + if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) { + printf("me6"); + return; + } + if (cmd->o.opcode == O_IP6) { + printf(" ipv6"); + return; + } + + /* + * len == 4 indicates a single IP, whereas lists of 1 or more + * addr/mask pairs have len = (2n+1). We convert len to n so we + * use that to count the number of entries. + */ + + for (len = len / 4; len > 0; len -= 2, a += 2) { + int mb = /* mask length */ + (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ? + 128 : contigmask((uint8_t *)&(a[1]), 128); + + if (mb == 128 && do_resolv) + he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6); + if (he != NULL) /* resolved to name */ + printf("%s", he->h_name); + else if (mb == 0) /* any */ + printf("any"); + else { /* numeric IP followed by some kind of mask */ + if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL) + printf("Error ntop in print_ip6\n"); + printf("%s", trad ); + if (mb < 0) /* XXX not really legal... */ + printf(":%s", + inet_ntop(AF_INET6, &a[1], trad, sizeof(trad))); + else if (mb < 128) + printf("/%d", mb); + } + if (len > 2) + printf(","); + } +} + +static void +fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av) +{ + uint8_t type; + + cmd->d[0] = 0; + while (*av) { + if (*av == ',') + av++; + type = strtoul(av, &av, 0); + if (*av != ',' && *av != '\0') + errx(EX_DATAERR, "invalid ICMP6 type"); + if (type > ICMP6_MAXTYPE) + errx(EX_DATAERR, "ICMP6 type out of range"); + cmd->d[type / 32] |= ( 1 << (type % 32)); + } + cmd->o.opcode = O_ICMP6TYPE; + cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); +} + + +static void +print_icmp6types(ipfw_insn_u32 *cmd) +{ + int i, j; + char sep= ' '; + + printf(" ipv6 icmp6types"); + for (i = 0; i < IPFW2_ICMP6_MAXV; i++) + for (j=0; j < 32; ++j) { + if ( (cmd->d[i] & (1 << (j))) == 0) + continue; + printf("%c%d", sep, (i*32 + j)); + sep = ','; + } +} + +static void +print_flow6id( ipfw_insn_u32 *cmd) +{ + uint16_t i, limit = cmd->o.arg1; + char sep = ','; + + printf(" flow-id "); + for( i=0; i < limit; ++i) { + if (i == limit - 1) + sep = ' '; + printf("%d%c", cmd->d[i], sep); + } +} + +/* structure and define for the extension header in ipv6 */ +static struct _s_x ext6hdrcodes[] = { + { "frag", EXT_FRAGMENT }, + { "hopopt", EXT_HOPOPTS }, + { "route", EXT_ROUTING }, + { "ah", EXT_AH }, + { "esp", EXT_ESP }, + { NULL, 0 } +}; + +/* fills command for the extension header filtering */ +int +fill_ext6hdr( ipfw_insn *cmd, char *av) +{ + int tok; + char *s = av; + + cmd->arg1 = 0; + + while(s) { + av = strsep( &s, ",") ; + tok = match_token(ext6hdrcodes, av); + switch (tok) { + case EXT_FRAGMENT: + cmd->arg1 |= EXT_FRAGMENT; + break; + + case EXT_HOPOPTS: + cmd->arg1 |= EXT_HOPOPTS; + break; + + case EXT_ROUTING: + cmd->arg1 |= EXT_ROUTING; + break; + + case EXT_AH: + cmd->arg1 |= EXT_AH; + break; + + case EXT_ESP: + cmd->arg1 |= EXT_ESP; + break; + + default: + errx( EX_DATAERR, "invalid option for ipv6 exten + headear" ); + break; + } + } + if (cmd->arg1 == 0 ) + return 0; + cmd->opcode = O_EXT_HDR; + cmd->len |= F_INSN_SIZE( ipfw_insn ); + return 1; +} + +void +print_ext6hdr( ipfw_insn *cmd ) +{ + char sep = ' '; + + printf(" extension header:"); + if (cmd->arg1 & EXT_FRAGMENT ) { + printf("%cfragmentation", sep); + sep = ','; + } + if (cmd->arg1 & EXT_HOPOPTS ) { + printf("%chop options", sep); + sep = ','; + } + if (cmd->arg1 & EXT_ROUTING ) { + printf("%crouting options", sep); + sep = ','; + } + if (cmd->arg1 & EXT_AH ) { + printf("%cauthentication header", sep); + sep = ','; + } + if (cmd->arg1 & EXT_ESP ) { + printf("%cencapsulated security payload", sep); + } +} + +/* XXX end of ipv6 stuff */ + /* * show_ipfw() prints the body of an ipfw rule. * Because the standard rule has at least proto src_ip dst_ip, we use @@ -845,6 +1061,7 @@ #define HAVE_DSTIP 0x0004 #define HAVE_MAC 0x0008 #define HAVE_MACTYPE 0x0010 +#define HAVE_PROTO6 0x0080 #define HAVE_OPTIONS 0x8000 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) @@ -865,6 +1082,8 @@ return; } if ( !(*flags & HAVE_OPTIONS)) { + if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO6)) + printf(" ipv6"); if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) printf(" ip"); if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) @@ -1095,6 +1314,40 @@ flags |= HAVE_DSTIP; break; + case O_IP6_SRC: + case O_IP6_SRC_MASK: + case O_IP6_SRC_ME: + show_prerequisites(&flags, HAVE_PROTO6, 0); + if (!(flags & HAVE_SRCIP)) + printf(" from"); + if ((cmd->len & F_OR) && !or_block) + printf(" {"); + print_ip6((ipfw_insn_ip6 *)cmd, + (flags & HAVE_OPTIONS) ? " src-ip6" : ""); + flags |= HAVE_SRCIP | HAVE_PROTO; + break; + + case O_IP6_DST: + case O_IP6_DST_MASK: + case O_IP6_DST_ME: +#if 0 + show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); +#endif + show_prerequisites(&flags, HAVE_PROTO6|HAVE_SRCIP, 0); + if (!(flags & HAVE_DSTIP)) + printf(" to"); + if ((cmd->len & F_OR) && !or_block) + printf(" {"); + print_ip6((ipfw_insn_ip6 *)cmd, + (flags & HAVE_OPTIONS) ? " dst-ip6" : ""); + flags |= HAVE_DSTIP | HAVE_PROTO; + break; + + case O_FLOW6ID: + print_flow6id( (ipfw_insn_u32 *) cmd ); + flags |= HAVE_OPTIONS; + break; + case O_IP_DSTPORT: show_prerequisites(&flags, HAVE_IP, 0); case O_IP_SRCPORT: @@ -1106,13 +1359,14 @@ break; case O_PROTO: { - struct protoent *pe; + struct protoent *pe = NULL; if ((cmd->len & F_OR) && !or_block) printf(" {"); if (cmd->len & F_NOT) printf(" not"); proto = cmd->arg1; + if (proto != 41) /* XXX ipv6 is special */ pe = getprotobynumber(cmd->arg1); if (flags & HAVE_OPTIONS) printf(" proto"); @@ -1289,6 +1543,18 @@ } break; + case O_IP6: + printf(" ipv6"); + break; + + case O_ICMP6TYPE: + print_icmp6types((ipfw_insn_u32 *)cmd); + break; + + case O_EXT_HDR: + print_ext6hdr( (ipfw_insn *) cmd ); + break; + default: printf(" [opcode %d len %d]", cmd->opcode, cmd->len); @@ -1342,11 +1608,20 @@ else printf(" proto %u", d->id.proto); + if (!IS_IP6_FLOW_ID(&(d->id))) { a.s_addr = htonl(d->id.src_ip); printf(" %s %d", inet_ntoa(a), d->id.src_port); - a.s_addr = htonl(d->id.dst_ip); printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); + } else { + char buff[255]; + inet_ntop(AF_INET6, &(d->id.src_ip6), + buff, sizeof(buff) ); + printf(" %s %d", buff, d->id.src_port); + inet_ntop(AF_INET6, &(d->id.dst_ip6), + buff, sizeof(buff) ); + printf(" <-> %s %d", buff, d->id.dst_port); + } printf("\n"); } @@ -1385,30 +1660,41 @@ static void list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) { - int l; + int l, index_print = 0; + char buff[255]; - printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", - fs->flow_mask.proto, - fs->flow_mask.src_ip, fs->flow_mask.src_port, - fs->flow_mask.dst_ip, fs->flow_mask.dst_port); if (fs->rq_elements == 0) return; - printf("BKT Prot ___Source IP/port____ " - "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); if (do_sort != 0) heapsort(q, fs->rq_elements, sizeof *q, sort_q); - for (l = 0; l < fs->rq_elements; l++) { + + /* + * Do IPv4 stuff + */ + + for (l = 0; l < fs->rq_elements; l++) + if (!IS_IP6_FLOW_ID(&(q[l].id))) { struct in_addr ina; struct protoent *pe; - ina.s_addr = htonl(q[l].id.src_ip); - printf("%3d ", q[l].hash_slot); + if (!index_print) { + index_print = 1; + printf("\n mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", + fs->flow_mask.proto, + fs->flow_mask.src_ip, fs->flow_mask.src_port, + fs->flow_mask.dst_ip, fs->flow_mask.dst_port); + + printf(" BKT Prot ___Source IP/port____ " + "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); + } + printf(" %3d ", q[l].hash_slot); pe = getprotobynumber(q[l].id.proto); if (pe) printf("%-4s ", pe->p_name); else printf("%4u ", q[l].id.proto); + ina.s_addr = htonl(q[l].id.src_ip); printf("%15s/%-5d ", inet_ntoa(ina), q[l].id.src_port); ina.s_addr = htonl(q[l].id.dst_ip); @@ -1421,6 +1707,54 @@ printf(" S %20qd F %20qd\n", q[l].S, q[l].F); } + + /* + * Do IPv6 stuff + */ + + index_print = 0; + for (l = 0; l < fs->rq_elements; l++) + if (IS_IP6_FLOW_ID(&(q[l].id))) { + struct protoent *pe; + + if (!index_print) { + index_print = 1; + printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ", + fs->flow_mask.proto, fs->flow_mask.flow_id6 ); + inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6), + buff, sizeof(buff) ); + printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port); + inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6), + buff, sizeof(buff) ); + printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port); + + printf(" BKT ___Prot___ _flow-id_ " + "______________Source IPv6/port_______________ " + "_______________Dest. IPv6/port_______________ " + "Tot_pkt/bytes Pkt/Byte Drp\n"); + } + printf(" %3d ", q[l].hash_slot); + pe = getprotobynumber(q[l].id.proto); + if (pe) + printf("%9s ", pe->p_name); + else + printf("%9u ", q[l].id.proto); + printf("%7d %39s/%-5d ", q[l].id.flow_id6, + inet_ntop(AF_INET6, &(q[l].id.src_ip6), + buff, sizeof(buff)), + q[l].id.src_port); + printf(" %39s/%-5d ", + inet_ntop(AF_INET6, &(q[l].id.dst_ip6), + buff, sizeof(buff)), + q[l].id.dst_port); + printf(" %4qu %8qu %2u %4u %3u\n", + q[l].tot_pkts, q[l].tot_bytes, + q[l].len, q[l].len_bytes, q[l].drops); + if (verbose) + printf(" S %20qd F %20qd\n", + q[l].S, q[l].F); + } + printf("\n"); } static void @@ -1803,7 +2137,7 @@ if (do_dynamic && ndyn) { printf("## Dynamic rules:\n"); for (lac = ac, lav = av; lac != 0; lac--) { - rnum = strtoul(*lav++, &endptr, 10); + last = rnum = strtoul(*lav++, &endptr, 10); if (*endptr == '-') last = strtoul(endptr+1, &endptr, 10); if (*endptr) @@ -1855,17 +2189,22 @@ "ACTION: check-state | allow | count | deny | reject | skipto N |\n" " {divert|tee} PORT | forward ADDR | pipe N | queue N\n" "ADDR: [ MAC dst src ether_type ] \n" -" [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" +" [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" +" [ ipv6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n" "IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n" "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" +"IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n" +"IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n" "OPTION_LIST: OPTION [OPTION_LIST]\n" -"OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n" +"OPTION: bridged | {dst-ip|src-ip} IPADDR | {dst-port|src-port} LIST |\n" " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" -" verrevpath\n" +" verrevpath | icmp6types LIST | ext6hdr LIST |\n" +" {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n" +" flow-id N[,N]\n" ); exit(0); } @@ -2059,6 +2398,226 @@ cmd->o.len |= len+1; } +/* XXX more ipv6 stuff */ +/* Try to find ipv6 address by hostname */ +static int +lookup_host6 (char *host, struct in6_addr *ip6addr) +{ + struct hostent *he; + + if (!inet_pton(AF_INET6, host, ip6addr)) { + if ((he = gethostbyname2(host, AF_INET6)) == NULL) + return(-1); + memcpy( ip6addr, he->h_addr_list[0], sizeof( struct in6_addr)); + } + return(0); +} + +/* n2mask sets n bits of the mask */ + +static void +n2mask(struct in6_addr *mask, int n) +{ + static int minimask[9] = { + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff + }; + u_char *p; + int i; + + memset(mask, 0, sizeof(struct in6_addr)); + p = (u_char *) mask; + for (i = 0; i < 16; i++, p++, n -= 8) { + if (n >= 8) { + *p = 0xff; + continue; + } + *p = minimask[n]; + break; + } + return; +} + +/* + * fills the addr and mask fields in the instruction as appropriate from av. + * Update length as appropriate. + * The following formats are allowed: + * any matches any IP6. Actually returns an empty instruction. + * me returns O_IP6_*_ME + * + * 03f1::234:123:0342 single IP6 addres + * 03f1::234:123:0342/24 address/mask + * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address + * + * Set of address (as in ipv6) not supported because ipv6 address + * are typically random past the initial prefix. + * Return 1 on success, 0 on failure. + */ + +static int +fill_ip6(ipfw_insn_ip6 *cmd, char *av) +{ + int len = 0; + struct in6_addr *d = &(cmd->addr6); + /* Needed for multiple address. + * Note d[1] points to struct in6_add r mask6 of cmd + */ + + cmd->o.len &= ~F_LEN_MASK; /* zero len */ + + if (!strncmp(av, "any", strlen(av))) + return 1; + + if (!strncmp(av, "me", strlen(av))) { /* Set the data for "me" opt*/ + cmd->o.len |= F_INSN_SIZE(ipfw_insn); + return 1; + } + if (!strncmp(av, "me6", strlen(av))) { /* Set the data for "me" opt*/ + cmd->o.len |= F_INSN_SIZE(ipfw_insn); + return 1; + } + + av = strdup(av); + while (av) { + /* + * After the address we can have '/' indicating a mask, + * or ',' indicating another address follows. + */ + + char *p; + int masklen; + char md = '\0'; + + if ((p = strpbrk( av, "/,")) ) { + md = *p; /* save the separator */ + *p = '\0'; /* terminate address string */ + p++; /* and skip past it */ + } + /* now p points to NULL, mask or next entry */ + + /* lookup stores address in *d as a side effect */ + if (lookup_host6(av, d) != 0) { + /* failed. Free memory and go */ + errx(EX_DATAERR, "bad address \"%s\"", av); + } + /* next, look at the mask, if any */ + masklen = (md == '/') ? atoi(p) : 128; + if (masklen > 128 || masklen < 0) + errx(EX_DATAERR, "bad width \"%s\''", p); + else + n2mask( &d[1], masklen); + + APPLY_MASK( d, &d[1]) /* mask base address with mask */ + + /* find next separator */ + + if (md == '/') { /* find separator past the mask */ + p = strpbrk(p, ","); + if (p) + p++; + } + av = p; + + /* Check this entry */ + if (masklen == 0) { + /* + * 'any' turns the entire list into a NOP. + * 'not any' never matches, so it is removed from the + * list unless it is the only item, in which case we + * report an error. + */ + if (cmd->o.len & F_NOT) { /* "not any" never matches */ + if (av == NULL && len == 0) /* only this entry */ + errx(EX_DATAERR, "not any never matches"); + } + /* else do nothing and skip this entry */ + /*continue; */ + } + + /* + * A single IP can be stored alone + */ + if (masklen == 128 && av == NULL && len == 0) { + len = F_INSN_SIZE(struct in6_addr); + break; + } + + /* Update length and pointer to arguments */ + len += F_INSN_SIZE(struct in6_addr)*2; + d += 2; + } /* end while */ + + /* Total lenght of the command, remember that 1 is the size of the base command */ + cmd->o.len |= len+1; + free(av); + return 1; +} + +/* + * fills command for ipv6 flow-id filtering + * note that the 20 bit flow number is stored in a array of u_int32_t + * it's supported lists of flow-id, so in the o.arg1 we store how many + * additional flow-id we want to filter, the basic is 1 + */ +void +fill_flow6( ipfw_insn_u32 *cmd, char *av ) +{ + u_int32_t type; /* Current flow number */ + u_int16_t nflow = 0; /* Current flow index */ + char *s = av; + cmd->d[0] = 0; /* Initializing the base number*/ + + while (s) { + av = strsep( &s, ",") ; + type = strtoul(av, &av, 0); + if (*av != ',' && *av != '\0') + errx(EX_DATAERR, "invalid ipv6 flow number %s", av); + if (type > 0xfffff) + errx(EX_DATAERR, "flow number out of range %s", av); + cmd->d[nflow] |= type; + nflow++; + } + if( nflow > 0 ) { + cmd->o.opcode = O_FLOW6ID; + cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow; + cmd->o.arg1 = nflow; + } + else { + errx(EX_DATAERR, "invalid ipv6 flow number %s", av); + } +} + +static ipfw_insn * +add_srcip6(ipfw_insn *cmd, char *av) +{ + fill_ip6( (ipfw_insn_ip6 *) cmd, av); + if (F_LEN(cmd) == 0) /* any */ + ; + else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* "me" */ + cmd->opcode = O_IP6_SRC_ME; + else if (F_LEN(cmd) == (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) + /* single IP, no mask*/ + cmd->opcode = O_IP6_SRC; + else /* addr/mask opt */ + cmd->opcode = O_IP6_SRC_MASK; + return cmd; +} + +static ipfw_insn * +add_dstip6(ipfw_insn *cmd, char *av) +{ + fill_ip6((ipfw_insn_ip6 *)cmd, av); + if (F_LEN(cmd) == 0) /* any */ + ; + else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* "me" */ + cmd->opcode = O_IP6_DST_ME; + else if (F_LEN(cmd) == (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) + /* single IP, no mask*/ + cmd->opcode = O_IP6_DST; + else /* addr/mask opt */ + cmd->opcode = O_IP6_DST_MASK; + return cmd; +} +/* end ipv6 stuff */ /* * helper function to process a set of flags and set bits in the @@ -2182,7 +2741,6 @@ struct dn_pipe p; int i; char *end; - uint32_t a; void *par = NULL; memset(&p, 0, sizeof p); @@ -2244,16 +2802,15 @@ */ par = NULL; - p.fs.flow_mask.dst_ip = 0; - p.fs.flow_mask.src_ip = 0; - p.fs.flow_mask.dst_port = 0; - p.fs.flow_mask.src_port = 0; - p.fs.flow_mask.proto = 0; + bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask)); end = NULL; while (ac >= 1) { uint32_t *p32 = NULL; uint16_t *p16 = NULL; + uint32_t *p20 = NULL; + struct in6_addr *pa6 = NULL; + uint32_t a; /* the mask */ tok = match_token(dummynet_params, *av); ac--; av++; @@ -2267,6 +2824,9 @@ p.fs.flow_mask.dst_port = ~0; p.fs.flow_mask.src_port = ~0; p.fs.flow_mask.proto = ~0; + n2mask( &(p.fs.flow_mask.dst_ip6), 128); + n2mask( &(p.fs.flow_mask.src_ip6), 128); + p.fs.flow_mask.flow_id6 = ~0; p.fs.flags_fs |= DN_HAVE_FLOW_MASK; goto end_mask; @@ -2278,6 +2838,18 @@ p32 = &p.fs.flow_mask.src_ip; break; + case TOK_DSTIP6: + pa6 = &(p.fs.flow_mask.dst_ip6); + break; + + case TOK_SRCIP6: + pa6 = &(p.fs.flow_mask.src_ip6); + break; + + case TOK_FLOWID: + p20 = &p.fs.flow_mask.flow_id6; + break; + case TOK_DSTPORT: p16 = &p.fs.flow_mask.dst_port; break; @@ -2295,22 +2867,35 @@ } if (ac < 1) errx(EX_USAGE, "mask: value missing"); - if (*av[0] == '/') { + if (*av[0] == '/') { /* mask len */ a = strtoul(av[0]+1, &end, 0); + /* convert to a mask for non IPv6 */ + if (pa6 == NULL) a = (a == 32) ? ~0 : (1 << a) - 1; - } else + } else /* explicit mask (non IPv6) */ a = strtoul(av[0], &end, 0); if (p32 != NULL) *p32 = a; else if (p16 != NULL) { - if (a > 65535) + if (a > 0xffff) errx(EX_DATAERR, - "mask: must be 16 bit"); + "port mask must be 16 bit"); *p16 = (uint16_t)a; + } else if (p20 != NULL) { + if (a > 0xfffff) + errx(EX_DATAERR, + "flow_id mask must be 20 bit"); + *p20 = (uint32_t)a; + } else if (pa6 != NULL) { + if (a < 0 || a > 128) + errx(EX_DATAERR, + "in6addr invalid mask len" ); + else + n2mask(pa6, a); } else { - if (a > 255) + if (a > 0xff) errx(EX_DATAERR, - "mask: must be 8 bit"); + "proto mask must be 8 bit"); p.fs.flow_mask.proto = (uint8_t)a; } if (a != 0) @@ -2630,21 +3215,27 @@ } static ipfw_insn * -add_proto(ipfw_insn *cmd, char *av) +add_proto(ipfw_insn *cmd, char *av, u_char *proto) { struct protoent *pe; - u_char proto = 0; + *proto = IPPROTO_IP; if (!strncmp(av, "all", strlen(av))) ; /* same as "ip" */ - else if ((proto = atoi(av)) > 0) + else if ((*proto = atoi(av)) > 0) ; /* all done! */ else if ((pe = getprotobyname(av)) != NULL) - proto = pe->p_proto; + *proto = pe->p_proto; + else if(!strncmp(av, "ipv6", strlen(av)) || + !strncmp(av, "ip6", strlen(av)) ) + { + *proto = IPPROTO_IPV6; + return cmd; /* special case for ipv6 */ + } else return NULL; - if (proto != IPPROTO_IP) - fill_cmd(cmd, O_PROTO, 0, proto); + if (*proto != IPPROTO_IP && *proto != IPPROTO_IPV6) + fill_cmd(cmd, O_PROTO, 0, *proto); return cmd; } @@ -2691,6 +3282,36 @@ return NULL; } +static ipfw_insn * +add_src(ipfw_insn *cmd, char *av, u_char proto) +{ + if( proto == IPPROTO_IPV6 || strcmp( av, "me6") == 0 || (inet_addr( av ) == INADDR_NONE)) + return add_srcip6(cmd, av); + + if (proto == IPPROTO_IP || strcmp( av, "me") == 0 || (inet_addr(av) != INADDR_NONE) ) + return add_srcip(cmd, av); + + if( !strcmp( av, "any") ) + return cmd; + + return NULL; /* bad address */ +} + +static ipfw_insn * +add_dst(ipfw_insn *cmd, char *av, u_char proto) +{ + if( proto == IPPROTO_IPV6 || strcmp( av, "me6") == 0 || (inet_addr(av) == INADDR_NONE) ) + return add_dstip6(cmd, av); + + if (proto == IPPROTO_IP || strcmp( av, "me") == 0 || (inet_addr(av) != INADDR_NONE) ) + return add_dstip(cmd, av); + + if( !strcmp( av, "any") ) + return cmd; + + return NULL; /* bad address */ +} + /* * Parse arguments and assemble the microinstructions which make up a rule. * Rules are added into the 'rulebuf' and then copied in the correct order @@ -2714,7 +3335,7 @@ */ static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; - ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; + ipfw_insn *src, *dst, *cmd, *action, *prev=NULL, *retval=NULL; ipfw_insn *first_cmd; /* first match pattern */ struct ip_fw *rule; @@ -2986,11 +3607,14 @@ OR_START(get_proto); NOT_BLOCK; NEED1("missing protocol"); - if (add_proto(cmd, *av)) { + if ( add_proto(cmd, *av, &proto) ) { +#if 0 + if ( proto == IPPROTO_IPV6 ) + fill_cmd(cmd, O_IP6, 0, 0); +#endif av++; ac--; - if (F_LEN(cmd) == 0) /* plain IP */ - proto = 0; - else { + if (F_LEN(cmd) != 0) /* plain IP */ + { proto = cmd->arg1; prev = cmd; cmd = next_cmd(cmd); @@ -3014,13 +3638,17 @@ OR_START(source_ip); NOT_BLOCK; /* optional "not" */ NEED1("missing source address"); - if (add_srcip(cmd, *av)) { + retval = add_src( cmd, *av, proto ); + + if( retval ){ ac--; av++; if (F_LEN(cmd) != 0) { /* ! any */ prev = cmd; cmd = next_cmd(cmd); } - } + } else + errx(EX_USAGE, "bad source address %s", *av); + OR_BLOCK(source_ip); /* @@ -3049,13 +3677,17 @@ OR_START(dest_ip); NOT_BLOCK; /* optional "not" */ NEED1("missing dst address"); - if (add_dstip(cmd, *av)) { + retval = NULL; + retval = add_dst(cmd, *av, proto); + + if( retval ){ ac--; av++; if (F_LEN(cmd) != 0) { /* ! any */ prev = cmd; cmd = next_cmd(cmd); } - } + } else + errx( EX_USAGE, "bad destination address %s", *av); OR_BLOCK(dest_ip); /* @@ -3161,6 +3793,12 @@ av++; ac--; break; + case TOK_ICMP6TYPES: + NEED1("icmptypes requires list of types"); + fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); + av++; ac--; + break; + case TOK_IPTTL: NEED1("ipttl requires TTL"); if (strpbrk(*av, "-,")) { @@ -3337,8 +3975,9 @@ case TOK_PROTO: NEED1("missing protocol"); - if (add_proto(cmd, *av)) { - proto = cmd->arg1; + if ( add_proto(cmd, *av, &proto)) { + if ( proto == IPPROTO_IPV6 ) + fill_cmd(cmd, O_IP6, 0, 0); ac--; av++; } else errx(EX_DATAERR, "invalid protocol ``%s''", @@ -3359,6 +3998,20 @@ } break; + case TOK_SRCIP6: + NEED1("missing source IP6"); + if (add_srcip6(cmd, *av)) { + ac--; av++; + } + break; + + case TOK_DSTIP6: + NEED1("missing destination IP6"); + if (add_dstip6(cmd, *av)) { + ac--; av++; + } + break; + case TOK_SRCPORT: NEED1("missing source port"); if (!strncmp(*av, "any", strlen(*av)) || @@ -3405,6 +4058,24 @@ fill_comment(cmd, ac, av); av += ac; ac = 0; + break; + + case TOK_IPV6: + fill_cmd(cmd, O_IP6, 0, 0); + /* XXX causes segfault */ + ac--; av++; + break; + + case TOK_EXT6HDR: + fill_ext6hdr( cmd, *av ); + ac--; av++; + break; + + case TOK_FLOWID: + if (proto != IPPROTO_IPV6 ) + errx( EX_USAGE, "flow-id filter is active only for ipv6 protocol\n"); + fill_flow6( (ipfw_insn_u32 *) cmd, *av ); + ac--;av++; break; default: diff -uNr --exclude=compile src.orig/sys/net/if_ethersubr.c src/sys/net/if_ethersubr.c --- src.orig/sys/net/if_ethersubr.c Wed Mar 3 13:35:16 2004 +++ src/sys/net/if_ethersubr.c Wed Dec 15 10:28:33 2004 @@ -40,6 +40,7 @@ #include "opt_ipx.h" #include "opt_bdg.h" #include "opt_netgraph.h" +#include "opt_ipfw.h" #include #include diff -uNr --exclude=compile src.orig/sys/netinet/ip_dummynet.c src/sys/netinet/ip_dummynet.c --- src.orig/sys/netinet/ip_dummynet.c Tue Dec 30 13:28:09 2003 +++ src/sys/netinet/ip_dummynet.c Wed Dec 15 10:04:37 2004 @@ -85,6 +85,9 @@ #include /* for struct arpcom */ #include +#include /* for ip6_input, ip6_output prototypes */ +#include + /* * We keep a private variable for the simulation time, but we could * probably use an existing one ("softticks" in sys/kern/kern_timeout.c) @@ -435,6 +438,16 @@ ip_input((struct mbuf *)pkt) ; break ; + case DN_TO_IP6_IN: + ip6_input((struct mbuf *)pkt) ; + break ; + + case DN_TO_IP6_OUT: + (void)ip6_output((struct mbuf *)pkt, NULL, NULL, 0, + NULL, NULL, NULL); + rt_unref (pkt->ip6opt.ro_or.ro_rt) ; + break ; + case DN_TO_BDG_FWD : if (!BDG_LOADED) { /* somebody unloaded the bridge module. Drop pkt */ @@ -863,37 +876,80 @@ { int i = 0 ; /* we need i and q for new allocations */ struct dn_flow_queue *q, *prev; + int is_v6 = IS_IP6_FLOW_ID(id); if ( !(fs->flags_fs & DN_HAVE_FLOW_MASK) ) q = fs->rq[0] ; else { - /* first, do the masking */ - id->dst_ip &= fs->flow_mask.dst_ip ; - id->src_ip &= fs->flow_mask.src_ip ; + /* first, do the masking, then hash */ id->dst_port &= fs->flow_mask.dst_port ; id->src_port &= fs->flow_mask.src_port ; id->proto &= fs->flow_mask.proto ; id->flags = 0 ; /* we don't care about this one */ - /* then, hash function */ + if (is_v6) { + APPLY_MASK(&id->dst_ip6, &fs->flow_mask.dst_ip6); + APPLY_MASK(&id->src_ip6, &fs->flow_mask.src_ip6); + id->flow_id6 &= fs->flow_mask.flow_id6; + + i = ((id->dst_ip6.__u6_addr.__u6_addr32[0]) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[1]) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[2]) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[3]) & 0xffff)^ + + ((id->dst_ip6.__u6_addr.__u6_addr32[0] >> 15) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[1] >> 15) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[2] >> 15) & 0xffff)^ + ((id->dst_ip6.__u6_addr.__u6_addr32[3] >> 15) & 0xffff)^ + + ((id->src_ip6.__u6_addr.__u6_addr32[0] << 1) & 0xfffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[1] << 1) & 0xfffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[2] << 1) & 0xfffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[3] << 1) & 0xfffff)^ + + ((id->src_ip6.__u6_addr.__u6_addr32[0] << 16) & 0xffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[1] << 16) & 0xffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[2] << 16) & 0xffff)^ + ((id->src_ip6.__u6_addr.__u6_addr32[3] << 16) & 0xffff)^ + + (id->dst_port << 1) ^ (id->src_port) ^ + (id->proto ) ^ + (id->flow_id6); + } else { + id->dst_ip &= fs->flow_mask.dst_ip ; + id->src_ip &= fs->flow_mask.src_ip ; + i = ( (id->dst_ip) & 0xffff ) ^ ( (id->dst_ip >> 15) & 0xffff ) ^ ( (id->src_ip << 1) & 0xffff ) ^ ( (id->src_ip >> 16 ) & 0xffff ) ^ (id->dst_port << 1) ^ (id->src_port) ^ (id->proto ); + } i = i % fs->rq_size ; /* finally, scan the current list for a match */ searches++ ; for (prev=NULL, q = fs->rq[i] ; q ; ) { search_steps++; - if (id->dst_ip == q->id.dst_ip && + if (is_v6 && + IN6_ARE_ADDR_EQUAL(&id->dst_ip6,&q->id.dst_ip6) && + IN6_ARE_ADDR_EQUAL(&id->src_ip6,&q->id.src_ip6) && + id->dst_port == q->id.dst_port && + id->src_port == q->id.src_port && + id->proto == q->id.proto && + id->flags == q->id.flags && + id->flow_id6 == q->id.flow_id6) + break ; /* found */ + + if (!is_v6 && id->dst_ip == q->id.dst_ip && id->src_ip == q->id.src_ip && id->dst_port == q->id.dst_port && id->src_port == q->id.src_port && id->proto == q->id.proto && id->flags == q->id.flags) break ; /* found */ - else if (pipe_expire && q->head == NULL && q->S == q->F+1 ) { + + /* No match. Check if we can expire the entry */ + if (pipe_expire && q->head == NULL && q->S == q->F+1 ) { /* entry is idle and not in any heap, expire it */ struct dn_flow_queue *old_q = q ; @@ -1030,7 +1086,7 @@ { #if IPFW2 struct dn_flow_set *fs; - ipfw_insn *cmd = rule->cmd + rule->act_ofs; + ipfw_insn *cmd = ACTION_PTR(rule); if (cmd->opcode == O_LOG) cmd += F_LEN(cmd); @@ -1099,7 +1155,7 @@ int s = splimp(); int is_pipe; #if IPFW2 - ipfw_insn *cmd = fwa->rule->cmd + fwa->rule->act_ofs; + ipfw_insn *cmd = ACTION_PTR(fwa->rule); if (cmd->opcode == O_LOG) cmd += F_LEN(cmd); @@ -1177,6 +1233,15 @@ pkt->dn_dst = fwa->dst; pkt->flags = fwa->flags; + } else if (dir == DN_TO_IP6_OUT) { + pkt->ip6opt.ro_or = fwa->dummypar.ro_or; + pkt->ip6opt.flags_or = fwa->dummypar.flags_or; + pkt->ip6opt.origifp_or = fwa->dummypar.origifp_or; + pkt->ip6opt.ifp_or = fwa->dummypar.ifp_or; + pkt->ip6opt.dst_or = fwa->dummypar.dst_or; + if (fwa->dummypar.ro_or.ro_rt) + fwa->dummypar.ro_or.ro_rt->rt_refcnt++; + pkt->flags = fwa->flags; } if (q->head == NULL) q->head = pkt; @@ -1275,6 +1340,7 @@ */ #define DN_FREE_PKT(pkt) { \ struct dn_pkt *n = pkt ; \ + rt_unref ( n->ip6opt.ro_or.ro_rt ); /* XXX */ \ rt_unref ( n->ro.ro_rt ) ; \ m_freem(n->dn_m); \ pkt = DN_NEXT(n) ; \ @@ -1937,7 +2003,7 @@ static void ip_dn_init(void) { - printf("DUMMYNET initialized (011031)\n"); + printf("DUMMYNET with IPv6 initialized (040114)\n"); all_pipes = NULL ; all_flow_sets = NULL ; ready_heap.size = ready_heap.elements = 0 ; diff -uNr --exclude=compile src.orig/sys/netinet/ip_dummynet.h src/sys/netinet/ip_dummynet.h --- src.orig/sys/netinet/ip_dummynet.h Tue May 13 11:31:06 2003 +++ src/sys/netinet/ip_dummynet.h Wed Dec 15 10:04:37 2004 @@ -109,6 +109,7 @@ struct dn_heap_entry *p ; /* really an array of "size" entries */ } ; +#ifdef _KERNEL /* * struct dn_pkt identifies a packet in the dummynet queue, but * is also used to tag packets passed back to the various destinations @@ -135,13 +136,17 @@ #define DN_TO_BDG_FWD 3 #define DN_TO_ETH_DEMUX 4 #define DN_TO_ETH_OUT 5 +#define DN_TO_IP6_IN 6 +#define DN_TO_IP6_OUT 7 dn_key output_time; /* when the pkt is due for delivery */ struct ifnet *ifp; /* interface, for ip_output */ struct sockaddr_in *dn_dst ; struct route ro; /* route, for ip_output. MUST COPY */ int flags ; /* flags, for ip_output (IPv6 ?) */ + struct _ip6dn_args ip6opt; /* XXX ipv6 options */ }; +#endif /* _KERNEL */ /* * Overall structure of dummynet (with WF2Q+): diff -uNr --exclude=compile src.orig/sys/netinet/ip_fw2.c src/sys/netinet/ip_fw2.c --- src.orig/sys/netinet/ip_fw2.c Fri Apr 2 19:15:44 2004 +++ src/sys/netinet/ip_fw2.c Mon Dec 20 15:53:16 2004 @@ -77,6 +77,9 @@ #include #endif +#include +#include + #include /* XXX for ETHERTYPE_IP */ #include /* XXX for in_cksum */ @@ -235,14 +238,19 @@ ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL; /* hook into dummynet */ /* - * This macro maps an ip pointer into a layer3 header pointer of type T + * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T + * Other macros just cast void * into the appropriate type */ #define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) +#define TCP(p) ((struct tcphdr *)(p)) +#define UDP(p) ((struct udphdr *)(p)) +#define ICMP(p) ((struct icmp *)(p)) +#define ICMP6(p) ((struct icmp6_hdr *)(p)) static __inline int -icmptype_match(struct ip *ip, ipfw_insn_u32 *cmd) +icmptype_match(struct icmp *icmp, ipfw_insn_u32 *cmd) { - int type = L3HDR(struct icmp,ip)->icmp_type; + int type = icmp->icmp_type; return (type <= ICMP_MAXTYPE && (cmd->d[0] & (1<icmp_type; + int type = icmp->icmp_type; + return (type <= ICMP_MAXTYPE && (TT & (1<th_off << 2) - sizeof(struct tcphdr); @@ -447,6 +455,83 @@ return 1; } +/* + * ipv6 specific rules here... + */ +static __inline int +icmp6type_match (int type, ipfw_insn_u32 *cmd) +{ + return (type <= ICMP6_MAXTYPE && (cmd->d[type/32] & (1<<(type%32)) ) ); +} + +static int +flow6id_match( int curr_flow, ipfw_insn_u32 *cmd ) +{ + int i; + for (i=0; i <= cmd->o.arg1; ++i ) + if (curr_flow == cmd->d[i] ) + return 1; + return 0; +} + +/* support for IP6_*_ME opcodes */ +static int +search_ip6_addr_net (struct in6_addr * ip6_addr) +{ + struct ifnet *mdc; + struct ifaddr *mdc2; + struct in6_ifaddr *fdm; + struct in6_addr copia; + + TAILQ_FOREACH(mdc, &ifnet, if_link) + for (mdc2 = mdc->if_addrlist.tqh_first; mdc2; + mdc2 = mdc2->ifa_list.tqe_next) { + if (!mdc2->ifa_addr) + continue; + if (mdc2->ifa_addr->sa_family == AF_INET6) { + fdm = (struct in6_ifaddr *)mdc2; + copia = fdm->ia_addr.sin6_addr; + /* need for leaving scope_id in the sock_addr */ + in6_clearscope(&copia); + if (IN6_ARE_ADDR_EQUAL(ip6_addr, &copia)) + return 1; + } + } + return 0; +} + +static int +verify_rev_path6(struct in6_addr *src, struct ifnet *ifp) +{ + static struct route_in6 ro; + struct sockaddr_in6 *dst; + + dst = (struct sockaddr_in6 * )&(ro.ro_dst); + + if ( !(IN6_ARE_ADDR_EQUAL (src, &dst->sin6_addr) )) { + bzero(dst, sizeof(*dst)); + dst->sin6_family = AF_INET6; + dst->sin6_len = sizeof(*dst); + dst->sin6_addr = *src; + rtalloc_ign((struct route *)&ro, RTF_CLONING | RTF_PRCLONING); + } + if ((ro.ro_rt == NULL) || (ifp == NULL) || + (ro.ro_rt->rt_ifp->if_index != ifp->if_index)) + return 0; + return 1; +} +static __inline int +hash_packet6(struct ipfw_flow_id *id) +{ + u_int32_t i; + i= (id->dst_ip6.__u6_addr.__u6_addr32[0]) ^ + (id->dst_ip6.__u6_addr.__u6_addr32[1]) ^ + (id->dst_ip6.__u6_addr.__u6_addr32[2]) ^ + (id->dst_ip6.__u6_addr.__u6_addr32[3]) ^ + (id->dst_port) ^ (id->src_port) ^ (id->flow_id6); + return i; +} +/* end of ipv6 opcodes */ static u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */ @@ -463,7 +548,7 @@ { char *action; int limit_reached = 0; - char action2[40], proto[48], fragment[28]; + char action2[40], proto[102], fragment[28]; fragment[0] = '\0'; proto[0] = '\0'; @@ -547,9 +632,70 @@ } } - if (hlen == 0) { /* non-ip */ - snprintf(SNPARGS(proto, 0), "MAC"); + /* preserve hlen == 0 semantics */ + if ((hlen == 0) && + mtod(m, struct ip *)->ip_v == 6) { /* IPv6 packet */ + int len; + struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); + u_int8_t protonum = mtod(m, struct ip6_hdr *)->ip6_nxt; + int off = sizeof(struct ip6_hdr); + struct tcphdr *const tcp6 = (struct tcphdr *) ((caddr_t) ip6+ off); + struct udphdr *const udp = (struct udphdr *) ((caddr_t) ip6+ off); + struct icmp6_hdr *const icmp6 = (struct icmp6_hdr *) ((caddr_t) ip6+ off); + +#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0 + + switch (protonum) { + case IPPROTO_TCP: + len = snprintf(SNPARGS(proto, 0), "TCP [%s]", + ip6_sprintf(&ip6->ip6_src)); + if (off > 0) + len += snprintf(SNPARGS(proto, len), ":%d ", + ntohs(tcp6->th_sport)); + else + len += snprintf(SNPARGS(proto, len), " "); + len += snprintf(SNPARGS(proto, len), "[%s]", + ip6_sprintf(&ip6->ip6_dst)); + if (off > 0) + snprintf(SNPARGS(proto, len), ":%d", + ntohs(tcp6->th_dport)); + break; + case IPPROTO_UDP: + len = snprintf(SNPARGS(proto, 0), "UDP [%s]", + ip6_sprintf(&ip6->ip6_src)); + if (off > 0) + len += snprintf(SNPARGS(proto, len), ":%d ", + ntohs(udp->uh_sport)); + else + len += snprintf(SNPARGS(proto, len), " "); + len += snprintf(SNPARGS(proto, len), "[%s]", + ip6_sprintf(&ip6->ip6_dst)); + if (off > 0) + snprintf(SNPARGS(proto, len), ":%d", + ntohs(udp->uh_dport)); + break; + case IPPROTO_ICMPV6: + if (off > 0) + len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP:%u.%u ", + icmp6->icmp6_type, icmp6->icmp6_code); + else + len = snprintf(SNPARGS(proto, 0), "IPV6-ICMP "); + len += snprintf(SNPARGS(proto, len), "[%s]", + ip6_sprintf(&ip6->ip6_src)); + snprintf(SNPARGS(proto, len), " [%s]", + ip6_sprintf(&ip6->ip6_dst)); + break; + default: + len = snprintf(SNPARGS(proto, 0), "P:%d [%s]", protonum, + ip6_sprintf(&ip6->ip6_src)); + snprintf(SNPARGS(proto, len), " [%s]", + ip6_sprintf(&ip6->ip6_dst)); + break; + } } else { + if (hlen == 0) + snprintf(SNPARGS(proto, 0), "MAC"); + else { struct ip *ip = mtod(m, struct ip *); /* these three are all aliases to the same thing */ struct icmp *const icmp = L3HDR(struct icmp, ip); @@ -621,6 +767,7 @@ ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2), offset << 3, (ip_off & IP_MF) ? "+" : ""); + } } if (oif || m->m_pkthdr.rcvif) log(LOG_SECURITY | LOG_INFO, @@ -651,7 +798,9 @@ { u_int32_t i; - i = (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port); + i = IS_IP6_FLOW_ID(id) ? hash_packet6(id): + (id->dst_ip) ^ (id->src_ip) ^ (id->dst_port) ^ (id->src_port); + i &= (curr_dyn_buckets - 1); return i; } @@ -776,7 +925,7 @@ if (ipfw_dyn_v == NULL) goto done; /* not found */ - i = hash_packet( pkt ); + i = hash_packet(pkt); for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) { if (q->dyn_type == O_LIMIT_PARENT && q->count) goto next; @@ -786,6 +935,27 @@ } if (pkt->proto == q->id.proto && q->dyn_type != O_LIMIT_PARENT) { + if (IS_IP6_FLOW_ID(pkt)) { + if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6), + &(q->id.src_ip6)) && + IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6), + &(q->id.dst_ip6)) && + pkt->src_port == q->id.src_port && + pkt->dst_port == q->id.dst_port ) { + dir = MATCH_FORWARD; + break; + } + if (IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6), + &(q->id.dst_ip6)) && + IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6), + &(q->id.src_ip6)) && + pkt->src_port == q->id.dst_port && + pkt->dst_port == q->id.src_port ) { + dir = MATCH_REVERSE; + break; + } + + } else { if (pkt->src_ip == q->id.src_ip && pkt->dst_ip == q->id.dst_ip && pkt->src_port == q->id.src_port && @@ -801,6 +971,7 @@ break; } } + } next: prev = q; q = q->next; @@ -976,15 +1147,25 @@ int i; if (ipfw_dyn_v) { - i = hash_packet( pkt ); + int is_v6 = IS_IP6_FLOW_ID(pkt); + i = hash_packet(pkt); for (q = ipfw_dyn_v[i] ; q != NULL ; q=q->next) if (q->dyn_type == O_LIMIT_PARENT && rule== q->rule && pkt->proto == q->id.proto && - pkt->src_ip == q->id.src_ip && - pkt->dst_ip == q->id.dst_ip && pkt->src_port == q->id.src_port && - pkt->dst_port == q->id.dst_port) { + pkt->dst_port == q->id.dst_port && + ( + (is_v6 && + IN6_ARE_ADDR_EQUAL(&(pkt->src_ip6), + &(q->id.src_ip6)) && + IN6_ARE_ADDR_EQUAL(&(pkt->dst_ip6), + &(q->id.dst_ip6))) || + (!is_v6 && + pkt->src_ip == q->id.src_ip && + pkt->dst_ip == q->id.dst_ip) + ) + ) { q->expire = time_second + dyn_short_lifetime; DEB(printf("ipfw: lookup_dyn_parent found 0x%p\n",q);) return q; @@ -1050,14 +1231,21 @@ DEB(printf("ipfw: installing dyn-limit rule %d\n", cmd->conn_limit);) - id.dst_ip = id.src_ip = 0; - id.dst_port = id.src_port = 0; + bzero (&id, sizeof(id)); + id.proto = args->f_id.proto; + if (IS_IP6_FLOW_ID (&(args->f_id))) { + if (limit_mask & DYN_SRC_ADDR) + id.src_ip6 = args->f_id.src_ip6; + if (limit_mask & DYN_DST_ADDR) + id.dst_ip6 = args->f_id.dst_ip6; + } else { if (limit_mask & DYN_SRC_ADDR) id.src_ip = args->f_id.src_ip; if (limit_mask & DYN_DST_ADDR) id.dst_ip = args->f_id.dst_ip; + } if (limit_mask & DYN_SRC_PORT) id.src_port = args->f_id.src_port; if (limit_mask & DYN_DST_PORT) @@ -1297,12 +1485,8 @@ * consumes the packet because it calls send_reject(). * XXX This has to change, so that ipfw_chk() never modifies * or consumes the buffer. - * ip is simply an alias of the value of m, and it is kept - * in sync with it (the packet is supposed to start with - * the ip header). */ struct mbuf *m = args->m; - struct ip *ip = mtod(m, struct ip *); /* * oif | args->oif If NULL, ipfw_chk has been called on the @@ -1319,12 +1503,12 @@ * hlen The length of the IPv4 header. * hlen >0 means we have an IPv4 packet. */ - u_int hlen = 0; /* hlen >0 means we have an IP pkt */ + u_int hlen = 0; /* * offset The offset of a fragment. offset != 0 means that - * we have a fragment at this offset of an IPv4 packet. - * offset == 0 means that (if this is an IPv4 packet) + * we have a fragmented ip packet. + * offset == 0 means that (if this is an IP packet) * this is the first or only fragment. */ u_short offset = 0; @@ -1348,32 +1532,151 @@ struct in_addr src_ip, dst_ip; /* NOTE: network format */ u_int16_t ip_len=0; int pktlen; - int dyn_dir = MATCH_UNKNOWN; - ipfw_dyn_rule *q = NULL; - if (m->m_flags & M_SKIP_FIREWALL) - return 0; /* accept */ /* * dyn_dir = MATCH_UNKNOWN when rules unchecked, * MATCH_NONE when checked and not matched (q = NULL), * MATCH_FORWARD or MATCH_REVERSE otherwise (q != NULL) */ + int dyn_dir = MATCH_UNKNOWN; + ipfw_dyn_rule *q = NULL; + + /* + * We store in ulp a pointer to the upper layer protocol header. + * In the ipv4 case this is easy to determine from the header, + * but for ipv6 we might have some additional headers in the middle. + * ulp is NULL if not found. + */ + void *ulp = NULL; /* upper layer protocol pointer. */ + /* XXX ipv6 variables */ + int is_ipv6 = 0; + u_int16_t ext_hd = 0; /* bits vector for extension header filtering */ + /* end of ipv6 variables */ + + if (m->m_flags & M_SKIP_FIREWALL) + return 0; /* accept */ pktlen = m->m_pkthdr.len; - if (args->eh == NULL || /* layer 3 packet */ - ( m->m_pkthdr.len >= sizeof(struct ip) && - ntohs(args->eh->ether_type) == ETHERTYPE_IP)) - hlen = ip->ip_hl << 2; + proto = args->f_id.proto = 0; /* mark f_id invalid */ + + /* Identify ipv6 packets and fill up variables. */ + if (pktlen >= sizeof(struct ip6_hdr) && + (!args->eh || ntohs(args->eh->ether_type)==ETHERTYPE_IPV6) && + mtod(m, struct ip *)->ip_v == 6) { + + is_ipv6 = 1; + args->f_id.addr_type = 6; + hlen = sizeof(struct ip6_hdr); + proto = mtod(m, struct ip6_hdr *)->ip6_nxt; + args->f_id.src_ip6 = (mtod(m, struct ip6_hdr *))->ip6_src; + args->f_id.dst_ip6 = (mtod(m, struct ip6_hdr *))->ip6_dst; + args->f_id.src_ip = 0; + args->f_id.dst_ip = 0; + args->f_id.flow_id6 = ntohs(mtod(m, struct ip6_hdr *)->ip6_flow); + + /* XXX where do we find ip_len ??? how do we set pktlen ? */ + + /* + * PULLUP6(len, p, T) makes sure that len + sizeof(T) is + * contiguous, then it sets p to point at the offset "len" in + * the mbuf. WARNING: the pointer might become stale after + * other pullups (but we never use it this way). + */ +#define PULLUP6(len, p, T) \ + do { \ + int x = (len) + sizeof(T); \ + if ((m)->m_len < x) { \ + args->m = m = m_pullup(m, x); \ + if (m == 0) \ + goto pullup_failed; \ + } \ + p = (mtod(m, char *) + (len)); \ + } while (0) + + /* Search extension headers to find upper layer protocols */ + while (ulp == NULL) { + switch (proto) { + case IPPROTO_ICMPV6: + PULLUP6(hlen, ulp, struct icmp6_hdr); + args->f_id.flags = ICMP6(ulp)->icmp6_type; + break; + + case IPPROTO_TCP: + PULLUP6(hlen, ulp, struct tcphdr); + dst_port = TCP(ulp)->th_dport; + src_port = TCP(ulp)->th_sport; + args->f_id.flags = TCP(ulp)->th_flags; + break; + + case IPPROTO_UDP: + PULLUP6(hlen, ulp, struct udphdr); + dst_port = UDP(ulp)->uh_dport; + src_port = UDP(ulp)->uh_sport; + break; + + case IPPROTO_HOPOPTS: + PULLUP6(hlen, ulp, struct ip6_hbh); + ext_hd |= EXT_HOPOPTS; + hlen += sizeof(struct ip6_hbh); + proto = ((struct ip6_hbh *)ulp)->ip6h_nxt; + ulp = NULL; + break; + + case IPPROTO_ROUTING: + PULLUP6(hlen, ulp, struct ip6_rthdr); + ext_hd |= EXT_ROUTING; + hlen += sizeof(struct ip6_rthdr); + proto = ((struct ip6_rthdr *)ulp)->ip6r_nxt; + ulp = NULL; + break; + + case IPPROTO_FRAGMENT: + PULLUP6(hlen, ulp, struct ip6_frag); + ext_hd |= EXT_FRAGMENT; + hlen += sizeof (struct ip6_frag); + proto = ((struct ip6_frag *)ulp)->ip6f_nxt; + offset = 1; + ulp = NULL; /* XXX is it correct ? */ + break; + + case IPPROTO_AH: + case IPPROTO_NONE: + case IPPROTO_ESP: + PULLUP6(hlen, ulp, struct ip6_ext); + if (proto == IPPROTO_AH) + ext_hd |= EXT_AH; + else if (proto == IPPROTO_ESP) + ext_hd |= EXT_ESP; + hlen += ((struct ip6_ext *)ulp)->ip6e_len + + sizeof (struct ip6_ext); + proto = ((struct ip6_ext *)ulp)->ip6e_nxt; + ulp = NULL; + break; + + default: + printf("IPFW2: IPV6 - Unknown Extension Header (%d)\n", + proto); + return 0; /* deny */ + break; + } /*switch */ + } + + /* hlen != 0 is used to detect ipv4 packets, so clear it now */ + hlen = 0; /* XXX why? we have args->f_id.addr_type ... */ + + } else if (pktlen >= sizeof(struct ip) && + (!args->eh || ntohs(args->eh->ether_type) == ETHERTYPE_IP) && + mtod(m, struct ip *)->ip_v == 4) { + struct ip *ip = mtod(m, struct ip *); + + hlen = ip->ip_hl << 2; + args->f_id.addr_type = 4; /* * Collect parameters into local variables for faster matching. */ - if (hlen == 0) { /* do not grab addresses for non-ip pkts */ - proto = args->f_id.proto = 0; /* mark f_id invalid */ - goto after_ip_checks; - } - proto = args->f_id.proto = ip->ip_p; + proto = ip->ip_p; src_ip = ip->ip_src; dst_ip = ip->ip_dst; if (args->eh != NULL) { /* layer 2 packets are as on the wire */ @@ -1385,58 +1688,41 @@ } pktlen = ip_len < pktlen ? ip_len : pktlen; -#define PULLUP_TO(len) \ - do { \ - if ((m)->m_len < (len)) { \ - args->m = m = m_pullup(m, (len)); \ - if (m == 0) \ - goto pullup_failed; \ - ip = mtod(m, struct ip *); \ - } \ - } while (0) - if (offset == 0) { switch (proto) { case IPPROTO_TCP: - { - struct tcphdr *tcp; - - PULLUP_TO(hlen + sizeof(struct tcphdr)); - tcp = L3HDR(struct tcphdr, ip); - dst_port = tcp->th_dport; - src_port = tcp->th_sport; - args->f_id.flags = tcp->th_flags; - } + PULLUP6(hlen, ulp, struct tcphdr); + dst_port = TCP(ulp)->th_dport; + src_port = TCP(ulp)->th_sport; + args->f_id.flags = TCP(ulp)->th_flags; break; case IPPROTO_UDP: - { - struct udphdr *udp; - - PULLUP_TO(hlen + sizeof(struct udphdr)); - udp = L3HDR(struct udphdr, ip); - dst_port = udp->uh_dport; - src_port = udp->uh_sport; - } + PULLUP6(hlen, ulp, struct udphdr); + dst_port = UDP(ulp)->uh_dport; + src_port = UDP(ulp)->uh_sport; break; case IPPROTO_ICMP: - PULLUP_TO(hlen + 4); /* type, code and checksum. */ - args->f_id.flags = L3HDR(struct icmp, ip)->icmp_type; + /* we only care for 4 bytes: type, code, checksum */ + PULLUP6(hlen, ulp, struct icmp); + args->f_id.flags = ICMP(ulp)->icmp_type; break; default: break; } -#undef PULLUP_TO } args->f_id.src_ip = ntohl(src_ip.s_addr); args->f_id.dst_ip = ntohl(dst_ip.s_addr); + } + if (proto) { /* we may have port numbers, store them */ + args->f_id.proto = proto; args->f_id.src_port = src_port = ntohs(src_port); args->f_id.dst_port = dst_port = ntohs(dst_port); + } -after_ip_checks: if (args->rule) { /* * Packet has already been tagged. Look for the next rule @@ -1529,13 +1815,11 @@ case O_GID: case O_UID: - /* - * We only check offset == 0 && proto != 0, - * as this ensures that we have an IPv4 - * packet with the ports info. - */ - if (offset!=0) + if (offset != 0) /* no port info available */ break; + if (is_ipv6) /* XXX to be fixed later */ + break; + /* the check for proto is below */ { struct inpcbinfo *pi; int wildcard; @@ -1621,7 +1905,7 @@ break; case O_FRAG: - match = (hlen > 0 && offset != 0); + match = offset != 0; break; case O_IN: /* "out" is "not in" */ @@ -1706,7 +1990,7 @@ case O_IP_DSTPORT: /* * offset == 0 && proto != 0 is enough - * to guarantee that we have an IPv4 + * to guarantee that we have a * packet with port info. */ if ((proto==IPPROTO_UDP || proto==IPPROTO_TCP) @@ -1726,15 +2010,25 @@ case O_ICMPTYPE: match = (offset == 0 && proto==IPPROTO_ICMP && - icmptype_match(ip, (ipfw_insn_u32 *)cmd) ); + icmptype_match(ICMP(ulp), (ipfw_insn_u32 *)cmd) ); + break; + + case O_ICMP6TYPE: + match = is_ipv6 && offset == 0 && + proto==IPPROTO_ICMPV6 && + icmp6type_match( + ((struct icmp6_hdr *)ulp)->icmp6_type, + (ipfw_insn_u32 *)cmd); break; case O_IPOPT: - match = (hlen > 0 && ipopts_match(ip, cmd) ); + match = (hlen > 0 && + ipopts_match(mtod(m, struct ip *), cmd) ); break; case O_IPVER: - match = (hlen > 0 && cmd->arg1 == ip->ip_v); + match = (hlen > 0 && + cmd->arg1 == mtod(m, struct ip *)->ip_v); break; case O_IPID: @@ -1748,9 +2042,9 @@ if (cmd->opcode == O_IPLEN) x = ip_len; else if (cmd->opcode == O_IPTTL) - x = ip->ip_ttl; + x = mtod(m, struct ip *)->ip_ttl; else /* must be IPID */ - x = ntohs(ip->ip_id); + x = ntohs(mtod(m, struct ip *)->ip_id); if (cmdlen == 1) { match = (cmd->arg1 == x); break; @@ -1765,49 +2059,47 @@ case O_IPPRECEDENCE: match = (hlen > 0 && - (cmd->arg1 == (ip->ip_tos & 0xe0)) ); + (cmd->arg1 == (mtod(m, struct ip *)->ip_tos & 0xe0)) ); break; case O_IPTOS: match = (hlen > 0 && - flags_match(cmd, ip->ip_tos)); + flags_match(cmd, mtod(m, struct ip *)->ip_tos)); break; case O_TCPFLAGS: - match = (proto == IPPROTO_TCP && offset == 0 && - flags_match(cmd, - L3HDR(struct tcphdr,ip)->th_flags)); + match = proto == IPPROTO_TCP && offset == 0 && + flags_match(cmd, TCP(ulp)->th_flags); break; case O_TCPOPTS: - match = (proto == IPPROTO_TCP && offset == 0 && - tcpopts_match(ip, cmd)); + match = proto == IPPROTO_TCP && offset == 0 && + tcpopts_match(TCP(ulp), cmd); break; case O_TCPSEQ: - match = (proto == IPPROTO_TCP && offset == 0 && + match = proto == IPPROTO_TCP && offset == 0 && ((ipfw_insn_u32 *)cmd)->d[0] == - L3HDR(struct tcphdr,ip)->th_seq); + TCP(ulp)->th_seq; break; case O_TCPACK: - match = (proto == IPPROTO_TCP && offset == 0 && + match = proto == IPPROTO_TCP && offset == 0 && ((ipfw_insn_u32 *)cmd)->d[0] == - L3HDR(struct tcphdr,ip)->th_ack); + TCP(ulp)->th_ack; break; case O_TCPWIN: - match = (proto == IPPROTO_TCP && offset == 0 && - cmd->arg1 == - L3HDR(struct tcphdr,ip)->th_win); + match = proto == IPPROTO_TCP && offset == 0 && + cmd->arg1 == TCP(ulp)->th_win; break; case O_ESTAB: /* reject packets which have SYN only */ /* XXX should i also check for TH_ACK ? */ - match = (proto == IPPROTO_TCP && offset == 0 && - (L3HDR(struct tcphdr,ip)->th_flags & - (TH_RST | TH_ACK | TH_SYN)) != TH_SYN); + match = proto == IPPROTO_TCP && offset == 0 && + ( TCP(ulp)->th_flags & + (TH_RST | TH_ACK | TH_SYN)) != TH_SYN; break; case O_LOG: @@ -1822,8 +2114,11 @@ case O_VERREVPATH: /* Outgoing packets automatically pass/match */ - match = ((oif != NULL) || + match = (oif != NULL) || (m->m_pkthdr.rcvif == NULL) || + (is_ipv6 ? + verify_rev_path6(&(args->f_id.src_ip6), + m->m_pkthdr.rcvif) : verify_rev_path(src_ip, m->m_pkthdr.rcvif)); break; @@ -1838,6 +2133,62 @@ /* otherwise no match */ break; + case O_IP6_SRC: + + match = is_ipv6 && + IN6_ARE_ADDR_EQUAL(&args->f_id.src_ip6, + &((ipfw_insn_ip6 *)cmd)->addr6); + break; + + case O_IP6_DST: + match = is_ipv6 && + IN6_ARE_ADDR_EQUAL(&args->f_id.dst_ip6, + &((ipfw_insn_ip6 *)cmd)->addr6); + break; + + case O_IP6_SRC_MASK: + if (is_ipv6) { + ipfw_insn_ip6 *te = (ipfw_insn_ip6 *)cmd; + struct in6_addr p = args->f_id.src_ip6; + + APPLY_MASK(&p, &te->mask6); + match = IN6_ARE_ADDR_EQUAL(&te->addr6, &p); + } + break; + + case O_IP6_DST_MASK: + if (is_ipv6) { + ipfw_insn_ip6 *te = (ipfw_insn_ip6 *)cmd; + struct in6_addr p = args->f_id.dst_ip6; + + APPLY_MASK(&p, &te->mask6); + match = IN6_ARE_ADDR_EQUAL(&te->addr6, &p); + } + break; + + case O_IP6_SRC_ME: + match= is_ipv6 && search_ip6_addr_net(&args->f_id.src_ip6); + break; + + case O_IP6_DST_ME: + match= is_ipv6 && search_ip6_addr_net(&args->f_id.dst_ip6); + break; + + case O_FLOW6ID: + match = is_ipv6 && + flow6id_match(args->f_id.flow_id6, + (ipfw_insn_u32 *) cmd); + break; + + case O_EXT_HDR: + match = is_ipv6 && + (ext_hd & ((ipfw_insn *) cmd)->arg1); + break; + + case O_IP6: + match = is_ipv6; + break; + /* * The second set of opcodes represents 'actions', * i.e. the terminal part of a rule once the packet @@ -1900,7 +2251,7 @@ if (dyn_dir == MATCH_UNKNOWN && (q = lookup_dyn_rule(&args->f_id, &dyn_dir, proto == IPPROTO_TCP ? - L3HDR(struct tcphdr, ip) : NULL)) + TCP(ulp) : NULL)) != NULL) { /* * Found dynamic entry, update stats @@ -1965,7 +2316,7 @@ */ if (hlen > 0 && (proto != IPPROTO_ICMP || - is_icmp_query(ip)) && + is_icmp_query(ICMP(ulp))) && !(m->m_flags & (M_BCAST|M_MCAST)) && !IN_MULTICAST(ntohl(dst_ip.s_addr))) { send_reject(args, cmd->arg1, @@ -2412,6 +2763,10 @@ case O_ESTAB: case O_VERREVPATH: case O_IPSEC: + case O_IP6_SRC_ME: + case O_IP6_DST_ME: + case O_EXT_HDR: + case O_IP6: if (cmdlen != F_INSN_SIZE(ipfw_insn)) goto bad_size; break; @@ -2525,6 +2880,29 @@ return EINVAL; } break; + + case O_IP6_SRC: + case O_IP6_DST: + if (cmdlen != F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn)) + goto bad_size; + break; + + case O_FLOW6ID: + if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + + ((ipfw_insn_u32 *)cmd)->o.arg1) + goto bad_size; + break; + + case O_IP6_SRC_MASK: + case O_IP6_DST_MASK: + if ( !(cmdlen & 1) || cmdlen > 127) + goto bad_size; + break; + case O_ICMP6TYPE: + if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) ) + goto bad_size; + break; + default: printf("ipfw: opcode %d, unknown opcode\n", cmd->opcode); @@ -2794,7 +3172,7 @@ add_rule(&layer3_chain, &default_rule); ip_fw_default_rule = layer3_chain; - printf("ipfw2 initialized, divert %s, " + printf("ipfw2 (+ipv6) initialized, divert %s, " "rule-based forwarding enabled, default to %s, logging ", #ifdef IPDIVERT "enabled", diff -uNr --exclude=compile src.orig/sys/netinet/ip_fw2.h src/sys/netinet/ip_fw2.h --- src.orig/sys/netinet/ip_fw2.h Thu Jul 17 08:03:39 2003 +++ src/sys/netinet/ip_fw2.h Wed Dec 15 10:05:00 2004 @@ -126,10 +126,32 @@ */ O_IPSEC, /* has ipsec history */ + O_IP6_SRC, /* address without mask */ + O_IP6_SRC_ME, /* my addresses */ + O_IP6_SRC_MASK, /* address with the mask */ + O_IP6_DST, + O_IP6_DST_ME, + O_IP6_DST_MASK, + O_FLOW6ID, /* for flow id tag in the ipv6 pkt */ + O_ICMP6TYPE, /* icmp6 packet type filtering */ + O_EXT_HDR, /* filtering for ipv6 extension header */ + O_IP6, /* Ipv6 protocol presence */ + O_LAST_OPCODE /* not an opcode! */ }; /* + * The extension header are filtered only for presence using a bit vector + * with a flag for each header. + */ + +#define EXT_FRAGMENT 0x1 +#define EXT_HOPOPTS 0x2 +#define EXT_ROUTING 0x4 +#define EXT_AH 0x8 +#define EXT_ESP 0x10 + +/* * Template for instructions. * * ipfw_insn is used for all instructions which require no operands, @@ -265,6 +287,31 @@ u_int32_t log_left; /* how many left to log */ } ipfw_insn_log; +/* Apply ipv6 mask on ipv6 addr */ +#define APPLY_MASK(addr,mask) \ + (addr)->__u6_addr.__u6_addr32[0] &= (mask)->__u6_addr.__u6_addr32[0]; \ + (addr)->__u6_addr.__u6_addr32[1] &= (mask)->__u6_addr.__u6_addr32[1]; \ + (addr)->__u6_addr.__u6_addr32[2] &= (mask)->__u6_addr.__u6_addr32[2]; \ + (addr)->__u6_addr.__u6_addr32[3] &= (mask)->__u6_addr.__u6_addr32[3]; + +/* Structure for ipv6 */ +typedef struct _ipfw_insn_ip6 { + ipfw_insn o; + struct in6_addr addr6; + struct in6_addr mask6; +} ipfw_insn_ip6; + +/* Used to support icmp6 types */ +#define IPFW2_ICMP6_MAXV 7 /* XXX This number is related to the netinet/icmp6.h + * define ICMP6_MAXTYPE + * as follws: n = ICMP6_MAXTYPE/32 + 1 + * Actually the define is 203 + */ +typedef struct _ipfw_insn_icmp6 { + ipfw_insn o; + uint32_t d[IPFW2_ICMP6_MAXV]; +} ipfw_insn_icmp6; + /* * Here we have the structure representing an ipfw rule. * @@ -327,8 +374,15 @@ u_int16_t src_port; u_int8_t proto; u_int8_t flags; /* protocol-specific flags */ + uint8_t addr_type; /* 4 = ipv4, 6 = ipv6, 1=ether ? */ + uint8_t _pad; + struct in6_addr dst_ip6; /* could also store MAC addr! */ + struct in6_addr src_ip6; + u_int32_t flow_id6; }; +#define IS_IP6_FLOW_ID(id) ((id)->addr_type == 6) + /* * Dynamic ipfw rule. */ @@ -384,6 +438,17 @@ #define IP_FW_PORT_DENY_FLAG 0x40000 /* + * Structure for collecting parameters to dummynet for ip6_output forwarding + */ +struct _ip6dn_args { + struct route_in6 ro_or; + int flags_or; + struct ifnet *origifp_or; + struct ifnet *ifp_or; + struct sockaddr_in6 dst_or; +}; + +/* * Arguments for calling ipfw_chk() and dummynet_io(). We put them * all into a structure because this way it is easier and more * efficient to pass variables around and extend the interface. @@ -402,6 +467,8 @@ struct ipfw_flow_id f_id; /* grabbed from IP header */ u_int16_t divert_rule; /* divert cookie */ u_int32_t retval; + + struct _ip6dn_args dummypar; /* dummynet->ip6_output */ }; /* diff -uNr --exclude=compile src.orig/sys/netinet/ip_fw2.h.orig src/sys/netinet/ip_fw2.h.orig --- src.orig/sys/netinet/ip_fw2.h.orig Thu Jan 1 01:00:00 1970 +++ src/sys/netinet/ip_fw2.h.orig Thu Jul 17 08:03:39 2003 @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/netinet/ip_fw2.h,v 1.1.2.4 2003/07/17 06:03:39 luigi Exp $ + */ + +#ifndef _IPFW2_H +#define _IPFW2_H + +/* + * The kernel representation of ipfw rules is made of a list of + * 'instructions' (for all practical purposes equivalent to BPF + * instructions), which specify which fields of the packet + * (or its metadata) should be analysed. + * + * Each instruction is stored in a structure which begins with + * "ipfw_insn", and can contain extra fields depending on the + * instruction type (listed below). + * Note that the code is written so that individual instructions + * have a size which is a multiple of 32 bits. This means that, if + * such structures contain pointers or other 64-bit entities, + * (there is just one instance now) they may end up unaligned on + * 64-bit architectures, so the must be handled with care. + * + * "enum ipfw_opcodes" are the opcodes supported. We can have up + * to 256 different opcodes. + */ + +enum ipfw_opcodes { /* arguments (4 byte each) */ + O_NOP, + + O_IP_SRC, /* u32 = IP */ + O_IP_SRC_MASK, /* ip = IP/mask */ + O_IP_SRC_ME, /* none */ + O_IP_SRC_SET, /* u32=base, arg1=len, bitmap */ + + O_IP_DST, /* u32 = IP */ + O_IP_DST_MASK, /* ip = IP/mask */ + O_IP_DST_ME, /* none */ + O_IP_DST_SET, /* u32=base, arg1=len, bitmap */ + + O_IP_SRCPORT, /* (n)port list:mask 4 byte ea */ + O_IP_DSTPORT, /* (n)port list:mask 4 byte ea */ + O_PROTO, /* arg1=protocol */ + + O_MACADDR2, /* 2 mac addr:mask */ + O_MAC_TYPE, /* same as srcport */ + + O_LAYER2, /* none */ + O_IN, /* none */ + O_FRAG, /* none */ + + O_RECV, /* none */ + O_XMIT, /* none */ + O_VIA, /* none */ + + O_IPOPT, /* arg1 = 2*u8 bitmap */ + O_IPLEN, /* arg1 = len */ + O_IPID, /* arg1 = id */ + + O_IPTOS, /* arg1 = id */ + O_IPPRECEDENCE, /* arg1 = precedence << 5 */ + O_IPTTL, /* arg1 = TTL */ + + O_IPVER, /* arg1 = version */ + O_UID, /* u32 = id */ + O_GID, /* u32 = id */ + O_ESTAB, /* none (tcp established) */ + O_TCPFLAGS, /* arg1 = 2*u8 bitmap */ + O_TCPWIN, /* arg1 = desired win */ + O_TCPSEQ, /* u32 = desired seq. */ + O_TCPACK, /* u32 = desired seq. */ + O_ICMPTYPE, /* u32 = icmp bitmap */ + O_TCPOPTS, /* arg1 = 2*u8 bitmap */ + + O_VERREVPATH, /* none */ + + O_PROBE_STATE, /* none */ + O_KEEP_STATE, /* none */ + O_LIMIT, /* ipfw_insn_limit */ + O_LIMIT_PARENT, /* dyn_type, not an opcode. */ + + /* + * These are really 'actions'. + */ + + O_LOG, /* ipfw_insn_log */ + O_PROB, /* u32 = match probability */ + + O_CHECK_STATE, /* none */ + O_ACCEPT, /* none */ + O_DENY, /* none */ + O_REJECT, /* arg1=icmp arg (same as deny) */ + O_COUNT, /* none */ + O_SKIPTO, /* arg1=next rule number */ + O_PIPE, /* arg1=pipe number */ + O_QUEUE, /* arg1=queue number */ + O_DIVERT, /* arg1=port number */ + O_TEE, /* arg1=port number */ + O_FORWARD_IP, /* fwd sockaddr */ + O_FORWARD_MAC, /* fwd mac */ + + /* + * More opcodes. + */ + O_IPSEC, /* has ipsec history */ + + O_LAST_OPCODE /* not an opcode! */ +}; + +/* + * Template for instructions. + * + * ipfw_insn is used for all instructions which require no operands, + * a single 16-bit value (arg1), or a couple of 8-bit values. + * + * For other instructions which require different/larger arguments + * we have derived structures, ipfw_insn_*. + * + * The size of the instruction (in 32-bit words) is in the low + * 6 bits of "len". The 2 remaining bits are used to implement + * NOT and OR on individual instructions. Given a type, you can + * compute the length to be put in "len" using F_INSN_SIZE(t) + * + * F_NOT negates the match result of the instruction. + * + * F_OR is used to build or blocks. By default, instructions + * are evaluated as part of a logical AND. An "or" block + * { X or Y or Z } contains F_OR set in all but the last + * instruction of the block. A match will cause the code + * to skip past the last instruction of the block. + * + * NOTA BENE: in a couple of places we assume that + * sizeof(ipfw_insn) == sizeof(u_int32_t) + * this needs to be fixed. + * + */ +typedef struct _ipfw_insn { /* template for instructions */ + enum ipfw_opcodes opcode:8; + u_int8_t len; /* numer of 32-byte words */ +#define F_NOT 0x80 +#define F_OR 0x40 +#define F_LEN_MASK 0x3f +#define F_LEN(cmd) ((cmd)->len & F_LEN_MASK) + + u_int16_t arg1; +} ipfw_insn; + +/* + * The F_INSN_SIZE(type) computes the size, in 4-byte words, of + * a given type. + */ +#define F_INSN_SIZE(t) ((sizeof (t))/sizeof(u_int32_t)) + +/* + * This is used to store an array of 16-bit entries (ports etc.) + */ +typedef struct _ipfw_insn_u16 { + ipfw_insn o; + u_int16_t ports[2]; /* there may be more */ +} ipfw_insn_u16; + +/* + * This is used to store an array of 32-bit entries + * (uid, single IPv4 addresses etc.) + */ +typedef struct _ipfw_insn_u32 { + ipfw_insn o; + u_int32_t d[1]; /* one or more */ +} ipfw_insn_u32; + +/* + * This is used to store IP addr-mask pairs. + */ +typedef struct _ipfw_insn_ip { + ipfw_insn o; + struct in_addr addr; + struct in_addr mask; +} ipfw_insn_ip; + +/* + * This is used to forward to a given address (ip). + */ +typedef struct _ipfw_insn_sa { + ipfw_insn o; + struct sockaddr_in sa; +} ipfw_insn_sa; + +/* + * This is used for MAC addr-mask pairs. + */ +typedef struct _ipfw_insn_mac { + ipfw_insn o; + u_char addr[12]; /* dst[6] + src[6] */ + u_char mask[12]; /* dst[6] + src[6] */ +} ipfw_insn_mac; + +/* + * This is used for interface match rules (recv xx, xmit xx). + */ +typedef struct _ipfw_insn_if { + ipfw_insn o; + union { + struct in_addr ip; + int32_t unit; + } p; + char name[IFNAMSIZ]; +} ipfw_insn_if; + +/* + * This is used for pipe and queue actions, which need to store + * a single pointer (which can have different size on different + * architectures. + * Note that, because of previous instructions, pipe_ptr might + * be unaligned in the overall structure, so it needs to be + * manipulated with care. + */ +typedef struct _ipfw_insn_pipe { + ipfw_insn o; + void *pipe_ptr; /* XXX */ +} ipfw_insn_pipe; + +/* + * This is used for limit rules. + */ +typedef struct _ipfw_insn_limit { + ipfw_insn o; + u_int8_t _pad; + u_int8_t limit_mask; /* combination of DYN_* below */ +#define DYN_SRC_ADDR 0x1 +#define DYN_SRC_PORT 0x2 +#define DYN_DST_ADDR 0x4 +#define DYN_DST_PORT 0x8 + + u_int16_t conn_limit; +} ipfw_insn_limit; + +/* + * This is used for log instructions. + */ +typedef struct _ipfw_insn_log { + ipfw_insn o; + u_int32_t max_log; /* how many do we log -- 0 = all */ + u_int32_t log_left; /* how many left to log */ +} ipfw_insn_log; + +/* + * Here we have the structure representing an ipfw rule. + * + * It starts with a general area (with link fields and counters) + * followed by an array of one or more instructions, which the code + * accesses as an array of 32-bit values. + * + * Given a rule pointer r: + * + * r->cmd is the start of the first instruction. + * ACTION_PTR(r) is the start of the first action (things to do + * once a rule matched). + * + * When assembling instruction, remember the following: + * + * + if a rule has a "keep-state" (or "limit") option, then the + * first instruction (at r->cmd) MUST BE an O_PROBE_STATE + * + if a rule has a "log" option, then the first action + * (at ACTION_PTR(r)) MUST be O_LOG + * + * NOTE: we use a simple linked list of rules because we never need + * to delete a rule without scanning the list. We do not use + * queue(3) macros for portability and readability. + */ + +struct ip_fw { + struct ip_fw *next; /* linked list of rules */ + struct ip_fw *next_rule; /* ptr to next [skipto] rule */ + /* 'next_rule' is used to pass up 'set_disable' status */ + + u_int16_t act_ofs; /* offset of action in 32-bit units */ + u_int16_t cmd_len; /* # of 32-bit words in cmd */ + u_int16_t rulenum; /* rule number */ + u_int8_t set; /* rule set (0..31) */ +#define RESVD_SET 31 /* set for default and persistent rules */ + u_int8_t _pad; /* padding */ + + /* These fields are present in all rules. */ + u_int64_t pcnt; /* Packet counter */ + u_int64_t bcnt; /* Byte counter */ + u_int32_t timestamp; /* tv_sec of last match */ + + ipfw_insn cmd[1]; /* storage for commands */ +}; + +#define ACTION_PTR(rule) \ + (ipfw_insn *)( (u_int32_t *)((rule)->cmd) + ((rule)->act_ofs) ) + +#define RULESIZE(rule) (sizeof(struct ip_fw) + \ + ((struct ip_fw *)(rule))->cmd_len * 4 - 4) + +/* + * This structure is used as a flow mask and a flow id for various + * parts of the code. + */ +struct ipfw_flow_id { + u_int32_t dst_ip; + u_int32_t src_ip; + u_int16_t dst_port; + u_int16_t src_port; + u_int8_t proto; + u_int8_t flags; /* protocol-specific flags */ +}; + +/* + * Dynamic ipfw rule. + */ +typedef struct _ipfw_dyn_rule ipfw_dyn_rule; + +struct _ipfw_dyn_rule { + ipfw_dyn_rule *next; /* linked list of rules. */ + struct ip_fw *rule; /* pointer to rule */ + /* 'rule' is used to pass up the rule number (from the parent) */ + + ipfw_dyn_rule *parent; /* pointer to parent rule */ + u_int64_t pcnt; /* packet match counter */ + u_int64_t bcnt; /* byte match counter */ + struct ipfw_flow_id id; /* (masked) flow id */ + u_int32_t expire; /* expire time */ + u_int32_t bucket; /* which bucket in hash table */ + u_int32_t state; /* state of this rule (typically a + * combination of TCP flags) + */ + u_int32_t ack_fwd; /* most recent ACKs in forward */ + u_int32_t ack_rev; /* and reverse directions (used */ + /* to generate keepalives) */ + u_int16_t dyn_type; /* rule type */ + u_int16_t count; /* refcount */ +}; + +/* + * Definitions for IP option names. + */ +#define IP_FW_IPOPT_LSRR 0x01 +#define IP_FW_IPOPT_SSRR 0x02 +#define IP_FW_IPOPT_RR 0x04 +#define IP_FW_IPOPT_TS 0x08 + +/* + * Definitions for TCP option names. + */ +#define IP_FW_TCPOPT_MSS 0x01 +#define IP_FW_TCPOPT_WINDOW 0x02 +#define IP_FW_TCPOPT_SACK 0x04 +#define IP_FW_TCPOPT_TS 0x08 +#define IP_FW_TCPOPT_CC 0x10 + +#define ICMP_REJECT_RST 0x100 /* fake ICMP code (send a TCP RST) */ + +/* + * Main firewall chains definitions and global var's definitions. + */ +#ifdef _KERNEL + +#define IP_FW_PORT_DYNT_FLAG 0x10000 +#define IP_FW_PORT_TEE_FLAG 0x20000 +#define IP_FW_PORT_DENY_FLAG 0x40000 + +/* + * Arguments for calling ipfw_chk() and dummynet_io(). We put them + * all into a structure because this way it is easier and more + * efficient to pass variables around and extend the interface. + */ +struct ip_fw_args { + struct mbuf *m; /* the mbuf chain */ + struct ifnet *oif; /* output interface */ + struct sockaddr_in *next_hop; /* forward address */ + struct ip_fw *rule; /* matching rule */ + struct ether_header *eh; /* for bridged packets */ + + struct route *ro; /* for dummynet */ + struct sockaddr_in *dst; /* for dummynet */ + int flags; /* for dummynet */ + + struct ipfw_flow_id f_id; /* grabbed from IP header */ + u_int16_t divert_rule; /* divert cookie */ + u_int32_t retval; +}; + +/* + * Function definitions. + */ + +/* Firewall hooks */ +struct sockopt; +struct dn_flow_set; + +void flush_pipe_ptrs(struct dn_flow_set *match); /* used by dummynet */ + +typedef int ip_fw_chk_t (struct ip_fw_args *args); +typedef int ip_fw_ctl_t (struct sockopt *); +extern ip_fw_chk_t *ip_fw_chk_ptr; +extern ip_fw_ctl_t *ip_fw_ctl_ptr; +extern int fw_one_pass; +extern int fw_enable; +#define IPFW_LOADED (ip_fw_chk_ptr != NULL) +#endif /* _KERNEL */ + +#endif /* _IPFW2_H */ diff -uNr --exclude=compile src.orig/sys/netinet/raw_ip.c src/sys/netinet/raw_ip.c --- src.orig/sys/netinet/raw_ip.c Tue Sep 16 07:43:56 2003 +++ src/sys/netinet/raw_ip.c Wed Dec 15 10:29:39 2004 @@ -37,6 +37,7 @@ #include "opt_inet6.h" #include "opt_ipsec.h" #include "opt_random_ip_id.h" +#include "opt_ipfw.h" #include #include diff -uNr --exclude=compile src.orig/sys/netinet6/ip6_forward.c src/sys/netinet6/ip6_forward.c --- src.orig/sys/netinet6/ip6_forward.c Fri Jan 24 06:11:35 2003 +++ src/sys/netinet6/ip6_forward.c Wed Dec 15 10:42:20 2004 @@ -34,6 +34,7 @@ #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" +#include "opt_ipfw.h" #include #include @@ -457,6 +458,7 @@ /* * Check with the firewall... */ +#ifndef IPFW2 if (ip6_fw_enable && ip6_fw_chk_ptr) { u_short port = 0; /* If ipfw says divert, we have to just drop packet */ @@ -467,6 +469,7 @@ if (!m) goto freecopy; } +#endif /* * Fake scoped addresses. Note that even link-local source or diff -uNr --exclude=compile src.orig/sys/netinet6/ip6_input.c src/sys/netinet6/ip6_input.c --- src.orig/sys/netinet6/ip6_input.c Fri Jan 24 06:11:35 2003 +++ src/sys/netinet6/ip6_input.c Wed Dec 15 10:05:00 2004 @@ -65,7 +65,7 @@ * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 */ -#include "opt_ip6fw.h" +#include "opt_ipfw.h" #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" @@ -119,7 +119,12 @@ #define IPSEC #endif /* FAST_IPSEC */ +#ifdef IPFW2 +#include +#include +#else #include +#endif #include @@ -148,9 +153,11 @@ /* firewall hooks */ +#ifndef IPFW2 ip6_fw_chk_t *ip6_fw_chk_ptr; ip6_fw_ctl_t *ip6_fw_ctl_ptr; int ip6_fw_enable = 1; +#endif /* !IPFW2 */ struct ip6stat ip6stat; @@ -263,6 +270,53 @@ int nxt, ours = 0; struct ifnet *deliverifp = NULL; +#ifdef IPFW2 + int i, hlen; +#ifdef IPDIVERT + u_int32_t divert_info = 0; /* packet divert/tee info */ +#endif + struct ip_fw_args args; + args.eh = NULL; + args.oif = NULL; + args.rule = NULL; + args.divert_rule = 0; /* divert cookie */ + args.next_hop = NULL; + + /* Grab info from MT_TAG mbufs prepended to the chain. */ + for (; m && m->m_type == MT_TAG; m = m->m_next) { + switch(m->_m_tag_id) { + default: + printf("ip6_input: unrecognised MT_TAG tag %d\n", + m->_m_tag_id); + break; + + case PACKET_TAG_DUMMYNET: + args.rule = ((struct dn_pkt *)m)->rule; + break; + + case PACKET_TAG_DIVERT: + args.divert_rule = (int)m->m_hdr.mh_data & 0xffff; + break; + +#if 0 + /* The ipfw2 forwarding is not yet implemented in ipv6 */ + case PACKET_TAG_IPFORWARD: + args.next_hop = (struct sockaddr_in *)m->m_hdr.mh_data; + break; +#endif + } + } + + KASSERT(m != NULL && (m->m_flags & M_PKTHDR) != 0, + ("ip6_input: no HDR")); + + if (args.rule) { /* dummynet already filtered us */ + ip6 = mtod(m, struct ip6_hdr *); + hlen = sizeof (struct ip6_hdr); + goto iphack; + } +#endif /* IPFW2 */ + #ifdef IPSEC /* * should the inner packet be considered authentic? @@ -354,6 +408,7 @@ goto bad; } +iphack: /* * Check if we want to allow this packet to be processed. * Consider it to be bad if not. @@ -375,6 +430,50 @@ /* * Check with the firewall... */ +#ifdef IPFW2 + if (fw_enable && IPFW_LOADED) { + /* + * If we've been forwarded from the output side, then + * skip the firewall a second time + */ + + if (args.next_hop) + ours=1; /* XXX check if this is correct */ + + args.m = m; + i = ip_fw_chk_ptr(&args); + m = args.m; + + if ( (i & IP_FW_PORT_DENY_FLAG) || m == NULL) { /* drop */ + if (m) + m_freem(m); + return; + } + ip6 = mtod(m, struct ip6_hdr *); /* just in case m changed */ + if (i == 0 && args.next_hop == NULL) /* common case */ + goto pass; + if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG) != 0) { + /* Send packet to the appropriate pipe */ + ip_dn_io_ptr(m, i & 0xffff, DN_TO_IP6_IN, &args); + return; + } +#ifdef IPDIVERT + if (i != 0 && (i & IP_FW_PORT_DYNT_FLAG) == 0) { + /* Divert or tee packet */ + divert_info = i; + ours=1; + } +#endif + if (i == 0 && args.next_hop != NULL) + goto pass; + /* + * if we get here, the packet must be dropped + */ + m_freem(m); + return; + } +pass: +#else /* !IPFW2, use the old firewall */ if (ip6_fw_enable && ip6_fw_chk_ptr) { u_short port = 0; /* If ipfw says divert, we have to just drop packet */ @@ -386,6 +485,7 @@ if (!m) return; } +#endif /* !IPFW2 */ /* * Check against address spoofing/corruption. diff -uNr --exclude=compile src.orig/sys/netinet6/ip6_output.c src/sys/netinet6/ip6_output.c --- src.orig/sys/netinet6/ip6_output.c Sun Mar 28 17:11:57 2004 +++ src/sys/netinet6/ip6_output.c Wed Dec 15 10:05:00 2004 @@ -65,7 +65,7 @@ * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 */ -#include "opt_ip6fw.h" +#include "opt_ipfw.h" #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" @@ -108,7 +108,13 @@ #include #endif /* FAST_IPSEC */ +#ifdef IPFW2 +#include +#include +#include +#else /* use old ip6fw */ #include +#endif #include @@ -173,6 +179,9 @@ struct route_in6 *ro_pmtu = NULL; int hdrsplit = 0; int needipsec = 0; +#ifdef IPFW2 + struct ip_fw_args args; +#endif #ifdef IPSEC int needipsectun = 0; struct secpolicy *sp = NULL; @@ -187,6 +196,66 @@ ip6 = mtod(m, struct ip6_hdr *); #endif /* FAST_IPSEC */ +#ifdef IPFW2 + args.eh = NULL; + args.rule = NULL; + args.next_hop = NULL; + args.divert_rule = 0; /* divert cookie */ + + /* Grab info from MT_TAG mbufs prepended to the chain. */ + for (; m0 && m0->m_type == MT_TAG; m0 = m0->m_next) { + switch(m0->_m_tag_id) { + default: + printf("ip6_output: unrecognised MT_TAG tag %d\n", + m0->_m_tag_id); + break; + + case PACKET_TAG_DUMMYNET: + /* + * the packet was already tagged, so part of the + * processing was already done, and we need to go down. + * Get parameters from the header. + */ + opt = NULL; + ro = &((struct dn_pkt *)m0)->ip6opt.ro_or; + flags = ((struct dn_pkt *)m0)->ip6opt.flags_or; + im6o = NULL; + origifp = ((struct dn_pkt *)m0)->ip6opt.origifp_or; + ifp = ((struct dn_pkt *)m0)->ip6opt.ifp_or; + dst = &((struct dn_pkt *)m0)->ip6opt.dst_or; + args.rule=((struct dn_pkt *)m0)->rule; + break; + + case PACKET_TAG_DIVERT: + args.divert_rule = (int)m0->m_data & 0xffff; + break; + +#if 0 + /* ipfw2 Forwarding is not yet supported in ipv6 */ + case PACKET_TAG_IPFORWARD: + args.next_hop = (struct sockaddr_in *)m0->m_data; + break; +#endif + } + } + m = m0; + + KASSERT(!m || (m->m_flags & M_PKTHDR) != 0, ("ip6_output: no HDR")); +#ifndef FAST_IPSEC + KASSERT(ro != NULL, ("ip6_output: no route\n")); +#endif + + if (args.rule ) { /* dummynet already saw us */ + ip6 = mtod(m, struct ip6_hdr *); + hlen = sizeof (struct ip6_hdr) ; + if (ro->ro_rt) + ia = ifatoia6(ro->ro_rt->rt_ifa); + bzero(&exthdrs, sizeof(exthdrs)); + ro_pmtu = ro; + goto send_after_dummynet; + } +#endif /* IPFW2 */ + #define MAKE_EXTHDR(hp, mp) \ do { \ if (hp) { \ @@ -765,6 +834,7 @@ } } +send_after_dummynet: /* * Fill the outgoing inteface to tell the upper layer * to increment per-interface statistics. @@ -836,6 +906,68 @@ /* * Check with the firewall... */ +#ifdef IPFW2 + if (fw_enable && IPFW_LOADED && !args.next_hop) { + /* + * Check with the firewall IPFW2... + * but not if we are already being fwd'd from a firewall. + */ + + struct sockaddr_in6 *old = dst; + args.m = m; + args.next_hop = (struct sockaddr_in *) dst; + args.oif = ifp; + off = ip_fw_chk_ptr(&args); + m = args.m; + dst = (struct sockaddr_in6 *) args.next_hop; + + /* + * On return we must do the following: + * m == NULL -> drop the pkt (old interface, deprecated) + * (off & IP_FW_PORT_DENY_FLAG) -> drop the pkt (new interface) + * 1<=off<= 0xffff -> DIVERT + * (off & IP_FW_PORT_DYNT_FLAG) -> send to a DUMMYNET pipe + * (off & IP_FW_PORT_TEE_FLAG) -> TEE the packet + * dst != old -> IPFIREWALL_FORWARD + * off==0, dst==old -> accept + * If some of the above modules are not compiled in, then + * we should't have to check the corresponding condition + * (because the ipfw control socket should not accept + * unsupported rules), but better play safe and drop + * packets in case of doubt. + */ + if ( (off & IP_FW_PORT_DENY_FLAG) || m == NULL) { + if (m) + m_freem(m); + error = EACCES; + goto done; + } + ip6 = mtod(m, struct ip6_hdr *); /* XXX check if necessary */ + if (off == 0 && dst == old) /* common case */ + goto pass6; + if (DUMMYNET_LOADED && (off & IP_FW_PORT_DYNT_FLAG) != 0) { + /* + * pass the pkt to dummynet. Need to include + * pipe number, m, ifp, ro, dst because these are + * not recomputed in the next pass. + * All other parameters have been already used and + * so they are not needed anymore. + * XXX note: if the ifp or ro entry are deleted + * while a pkt is in dummynet, we are in trouble! + */ + args.dummypar.ro_or = *ro; + args.dummypar.flags_or = flags; + args.dummypar.ifp_or = ifp; + args.dummypar.origifp_or = origifp; + args.dummypar.dst_or = *dst; + args.flags = flags; + error = ip_dn_io_ptr(m, off & 0xffff, DN_TO_IP6_OUT, + &args); + goto done; + } + } +pass6: +#else /* !IPFW2 */ if (ip6_fw_enable && ip6_fw_chk_ptr) { u_short port = 0; m->m_pkthdr.rcvif = NULL; /* XXX */ @@ -849,7 +981,7 @@ goto done; } } - +#endif /* !IPFW2 */ /* * If the outgoing packet contains a hop-by-hop options header, * it must be examined and processed even by the source node. @@ -1637,6 +1769,7 @@ break; #endif /* KAME IPSEC */ +#ifndef IPFW2 case IPV6_FW_ADD: case IPV6_FW_DEL: case IPV6_FW_FLUSH: @@ -1657,7 +1790,7 @@ m = *mp; } break; - +#endif /* !IPFW2 */ default: error = ENOPROTOOPT; break; @@ -1797,6 +1930,7 @@ } #endif /* KAME IPSEC */ +#ifndef IPFW2 case IPV6_FW_GET: { struct mbuf *m; @@ -1813,6 +1947,7 @@ m_freem(m); } break; +#endif /* !IPFW2 */ default: error = ENOPROTOOPT; @@ -2241,8 +2376,8 @@ * If an interface address was specified, get a pointer * to its ifnet structure. */ - if (mreq->ipv6mr_interface < 0 - || if_index < mreq->ipv6mr_interface) { + if (mreq->ipv6mr_interface < 0 || + if_index < mreq->ipv6mr_interface) { error = ENXIO; /* XXX EINVAL? */ break; } @@ -2253,7 +2388,7 @@ */ if (IN6_IS_ADDR_MC_LINKLOCAL(&mreq->ipv6mr_multiaddr)) { mreq->ipv6mr_multiaddr.s6_addr16[1] - = htons(mreq->ipv6mr_interface); + = htons(ifp->if_index); } /* * Find the membership in the membership list. --7ZAtKRhVyVSsbBD2-- From owner-freebsd-ipfw@FreeBSD.ORG Tue Dec 21 10:40:22 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 93F9516A4CE for ; Tue, 21 Dec 2004 10:40:22 +0000 (GMT) Received: from otaku.Xtrmntr.org (sauna.silcnet.org [147.175.66.205]) by mx1.FreeBSD.org (Postfix) with ESMTP id DAC1D43D5D for ; Tue, 21 Dec 2004 10:40:21 +0000 (GMT) (envelope-from techie@Xtrmntr.org) Received: by otaku.Xtrmntr.org (Postfix, from userid 213) id 3D6DB1D102; Tue, 21 Dec 2004 11:40:21 +0100 (CET) Date: Tue, 21 Dec 2004 11:40:21 +0100 From: Vladimir Kotal To: freebsd-ipfw@freebsd.org Message-ID: <20041221104021.GA26902@otaku.xtrmntr.org> References: <20041221103650.GC25908@otaku.xtrmntr.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20041221103650.GC25908@otaku.xtrmntr.org> User-Agent: Mutt/1.4.2.1i Accept-Languages: cz, sk, en Subject: Re: ipfw2 for IPV6 X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: vlada@devnull.cz List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Dec 2004 10:40:22 -0000 On Tue, Dec 21, 2004 at 11:36:50AM +0100, Vladimir Kotal wrote: > > - sbin/ipfw2.c parsing code can cause incorrect functionality, even > segfault in some cases (see included regress script) Hmm, the regress script did not get thru, here it is: #!/bin/sh # presume net.inet.ip.fw.one_pass = 0 ipfw=/sbin/ipfw $ipfw -f flush $ipfw -f pipe flush ipv6addr="fec0:2::2/128" ## outgoing queue $ipfw pipe 2400 config bw 64Kbit/s queue 16KBytes ## incoming queue $ipfw pipe 2401 config bw 64Kbit/s queue 16KBytes # following rules load but do not function correctly # - packets are not matched against these rules $ipfw add 01500 pipe 2400 ipv6 from any to $ipv6addr out $ipfw add 01500 allow ipv6 from any to $ipv6addr out $ipfw add 01501 pipe 2401 ipv6 from $ipv6addr to any in $ipfw add 01501 allow ipv6 from $ipv6addr to any in # following commands omit 'in/out' tokens from parsing $ipfw add 01600 pipe 2400 ipv6 from any to $ipv6addr ipv6 out $ipfw add 01600 allow ipv6 from any to $ipv6addr ipv6 out $ipfw add 01601 pipe 2401 ipv6 from $ipv6addr to any ipv6 in $ipfw add 01601 allow ipv6 from $ipv6addr to any ipv6 in # following commands cause segfault $ipfw add 01700 pipe 2400 ipv6 from any to $ipv6addr out ipv6 $ipfw add 01700 allow ipv6 from any to $ipv6addr out ipv6 $ipfw add 01701 pipe 2401 ipv6 from $ipv6addr to any in ipv6 $ipfw add 01701 allow ipv6 from $ipv6addr to any in ipv6 # default deny $ipfw add 65420 deny log all from any to any via fxp1 From owner-freebsd-ipfw@FreeBSD.ORG Tue Dec 21 16:25:48 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id BC49716A4CE for ; Tue, 21 Dec 2004 16:25:48 +0000 (GMT) Received: from mail2.dbitech.ca (radius.wavefire.com [64.141.13.252]) by mx1.FreeBSD.org (Postfix) with SMTP id 393EC43D58 for ; Tue, 21 Dec 2004 16:25:48 +0000 (GMT) (envelope-from darcy@wavefire.com) Received: (qmail 13382 invoked from network); 21 Dec 2004 17:35:45 -0000 Received: from dbitech.wavefire.com (HELO ?64.141.15.253?) (darcy@64.141.15.253) by radius.wavefire.com with SMTP; 21 Dec 2004 17:35:45 -0000 From: Darcy Buskermolen Organization: Wavefire Technologies Corp. To: freebsd-ipfw@freebsd.org, csmith@bonddesk.com Date: Tue, 21 Dec 2004 08:25:43 -0800 User-Agent: KMail/1.6.2 References: <1103315143.35576.127.camel@localhost> <200412171431.12983.darcy@wavefire.com> <1103567616.35576.143.camel@localhost> In-Reply-To: <1103567616.35576.143.camel@localhost> MIME-Version: 1.0 Content-Disposition: inline Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Message-Id: <200412210825.44270.darcy@wavefire.com> Subject: Re: Per flow load balancing X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Dec 2004 16:25:48 -0000 On December 20, 2004 10:33 am, Corey Smith wrote: > On Fri, 2004-12-17 at 14:31 -0800, Darcy Buskermolen wrote: > > Yes you can do this through the use of keep-state/check-state > > I'm trying a rule base like: > > 00005 check-state > 00006 allow udp from any to any > 00007 allow icmp from any to any > 00010 reject tcp from any to any established > 00015 prob 0.5 fwd tun1peerip tcp from any to any \ > recv bge0 xmit tun0 setup keep-state > 00020 allow tcp from any to any setup keep-state > 65535 allow ip from any to any > > Unfortunately no connections ever match rule 15. Any way you can show > me an example of using keep-state/check-state for per flow load > balancing? Here is a cut down set I use in one of my setups that does perflow load ballancing add 1 skipto 50000 tcp from any 1023-65535 to me 22 via xl1 #interactive traffic like ssh or telnet is best suited to the DSL 1000 skipto 1012 tcp from 192.168.0.0/16 to 1.2.3.0/24 22,23 #skip vpn traffic 1010 divert 8668 tcp from 192.168.0.0/16 to not 192.168.0.0/16 22 #xl0 1011 divert 8668 tcp from 192.168.0.0/16 to not 192.168.0.0/16 23 #xl0 #5000 -> 5999 default divert rules 5000 divert 8668 ip from any to me in via xl0 5001 divert 8669 ip from any to me in via fxp0 add 5010 check-state #push 45% of the traffic down the DSL 5100 prob 0.4 skipto 5500 ip from 192.168.0.0/16 to not 192.168.0.0/16 out keep-state 5101 skipto 5550 tcp from 192.168.0.0/16 to not 192.168.0.0/16 dst-port 20,2 1 out keep-state #the rest down cable 5110 skipto 5550 ip from 192.168.0.0/16 to not 192.168.0.0/16 out keep-state 5500 divert 8668 ip from 192.168.0.0/16 to not 192.168.0.0/16 550 divert 8669 ip from 192.168.0.0/16 to not 192.168.0.0/16 10000 skipto 50000 ip from 192.162.0.0/16 to me in via xl1 10020 skipto 50000 tcp from any to any established 11010 skipto 50000 icmp from me to any 60000 fwd dslgateway ip from mydslip to not 192.168.0.0/16 60001 fwd cablegateway ip from mycableip to not 192.168.0.0/16 65534 allow ip from any to any > > -Corey Smith > _______________________________________________ > freebsd-ipfw@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-ipfw > To unsubscribe, send any mail to "freebsd-ipfw-unsubscribe@freebsd.org" -- Darcy Buskermolen Wavefire Technologies Corp. ph: 250.717.0200 fx: 250.763.1759 http://www.wavefire.com From owner-freebsd-ipfw@FreeBSD.ORG Wed Dec 22 16:47:34 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id DBBF016A4CE for ; Wed, 22 Dec 2004 16:47:34 +0000 (GMT) Received: from wproxy.gmail.com (wproxy.gmail.com [64.233.184.203]) by mx1.FreeBSD.org (Postfix) with ESMTP id 8BA7543D41 for ; Wed, 22 Dec 2004 16:47:29 +0000 (GMT) (envelope-from surricani@gmail.com) Received: by wproxy.gmail.com with SMTP id 55so140wri for ; Wed, 22 Dec 2004 08:46:45 -0800 (PST) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:reply-to:to:subject:mime-version:content-type:content-transfer-encoding; b=MXUrhYAGVAoHC2iJ5wgfBq91ymDQ5pgFZVJGRrJWFxWgaYgy+04ooz7ArVQhyZjYfets6HOdQPFG8BS39YAtvK1BSR3AZZSk9F42wp941/a52NLPGErL6Yl5aq41KHPieEZyn6+r/hnyEhwpKcleiMf4fxzRVk/XXz+vtLO/oDo= Received: by 10.54.42.56 with SMTP id p56mr34393wrp; Wed, 22 Dec 2004 08:46:45 -0800 (PST) Received: by 10.54.2.66 with HTTP; Wed, 22 Dec 2004 08:46:45 -0800 (PST) Message-ID: <4591fd910412220846d2c92cd@mail.gmail.com> Date: Wed, 22 Dec 2004 17:46:45 +0100 From: "Dott. Surricani" To: freebsd-ipfw@freebsd.org Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Subject: problem with IPFILTER X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: "Dott. Surricani" List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 22 Dec 2004 16:47:35 -0000 Hello everybody. I've succesfully set up an Inclusive Firewall for my small Lan, how explained in Chapter 24 of the Handbook, with IPFILTER and ipnat (Either with kld modules). I've included in rc.conf the lines neeeded and i've written custom ipf.rules and ipnat.rules... It's super, and work great, but I've got a problem/question: each time I restart the server the rules are cleared and It leave all packets enter and exit an I have to type in the shell ipf -Fa -f /etc/ipf.rules and ipnat -CF -f /etc/ipnat.rules It's very boring.... What I can do to automate this task? Thanks all very much!!!! From owner-freebsd-ipfw@FreeBSD.ORG Wed Dec 22 19:16:07 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id C6D0D16A4D8 for ; Wed, 22 Dec 2004 19:16:07 +0000 (GMT) Received: from odin.ac.hmc.edu (Odin.AC.HMC.Edu [134.173.32.75]) by mx1.FreeBSD.org (Postfix) with ESMTP id 9D81743D1D for ; Wed, 22 Dec 2004 19:16:07 +0000 (GMT) (envelope-from brdavis@odin.ac.hmc.edu) Received: from odin.ac.hmc.edu (localhost.localdomain [127.0.0.1]) by odin.ac.hmc.edu (8.13.0/8.13.0) with ESMTP id iBMJGSRF020582; Wed, 22 Dec 2004 11:16:28 -0800 Received: (from brdavis@localhost) by odin.ac.hmc.edu (8.13.0/8.13.0/Submit) id iBMJGSMx020581; Wed, 22 Dec 2004 11:16:28 -0800 Date: Wed, 22 Dec 2004 11:16:28 -0800 From: Brooks Davis To: "Dott. Surricani" Message-ID: <20041222191628.GA15881@odin.ac.hmc.edu> References: <4591fd910412220846d2c92cd@mail.gmail.com> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="XsQoSWH+UP9D9v3l" Content-Disposition: inline In-Reply-To: <4591fd910412220846d2c92cd@mail.gmail.com> User-Agent: Mutt/1.4.1i X-Virus-Scanned: by amavisd-new X-Spam-Status: No, hits=0.0 required=8.0 tests=none autolearn=no version=2.63 X-Spam-Checker-Version: SpamAssassin 2.63 (2004-01-11) on odin.ac.hmc.edu cc: freebsd-ipfw@freebsd.org Subject: Re: problem with IPFILTER X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 22 Dec 2004 19:16:07 -0000 --XsQoSWH+UP9D9v3l Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Wed, Dec 22, 2004 at 05:46:45PM +0100, Dott. Surricani wrote: > Hello everybody. >=20 > I've succesfully set up an Inclusive Firewall for my small Lan, how > explained in Chapter 24 of the Handbook, > with IPFILTER and ipnat (Either with kld modules). > I've included in rc.conf the lines neeeded and i've written custom > ipf.rules and ipnat.rules... >=20 > It's super, and work great, but I've got a problem/question: >=20 > each time I restart the server the rules are cleared and It leave all > packets enter and exit > an I have to type in the shell >=20 > ipf -Fa -f /etc/ipf.rules and > ipnat -CF -f /etc/ipnat.rules >=20 > It's very boring.... >=20 > What I can do to automate this task? Search for ipfilter and ipnat in /etc/defaults/rc.conf to find the appropriate variables to set in your /etc/rc.conf. -- Brooks --=20 Any statement of the form "X is the one, true Y" is FALSE. PGP fingerprint 655D 519C 26A7 82E7 2529 9BF0 5D8E 8BE9 F238 1AD4 --XsQoSWH+UP9D9v3l Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.1 (GNU/Linux) iD8DBQFBycgLXY6L6fI4GtQRAiSpAJ0V6EVG6J8ak369KTI/9TkvVN5jVACgnqAI W1C61Cw/3ZNVPIhE2Y+vT6s= =6Y7p -----END PGP SIGNATURE----- --XsQoSWH+UP9D9v3l-- From owner-freebsd-ipfw@FreeBSD.ORG Thu Dec 23 15:30:13 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 2BDC316A4CE for ; Thu, 23 Dec 2004 15:30:13 +0000 (GMT) Received: from citadel.icyb.net.ua (citadel.icyb.net.ua [212.40.38.140]) by mx1.FreeBSD.org (Postfix) with ESMTP id C4BEB43D3F for ; Thu, 23 Dec 2004 15:30:07 +0000 (GMT) (envelope-from avg@icyb.net.ua) Received: from oddity (oddity.topspin.kiev.ua [212.40.38.87]) by citadel.icyb.net.ua (8.8.8p3/ICyb-2.3exp) with ESMTP id RAA10063 for ; Thu, 23 Dec 2004 17:30:04 +0200 (EET) (envelope-from avg@icyb.net.ua) Message-ID: <41C9BAF6.4020507@icyb.net.ua> Date: Wed, 22 Dec 2004 13:20:38 -0500 From: Andriy Gapon User-Agent: Mozilla Thunderbird 1.0RC1 (Windows/20041201) X-Accept-Language: en-us, en MIME-Version: 1.0 To: freebsd-ipfw@freebsd.org Content-Type: text/plain; charset=KOI8-U; format=flowed Content-Transfer-Encoding: 7bit Status: RO X-UID: 3726 X-Keywords: ReSent-Date: Thu, 23 Dec 2004 17:29:50 +0200 (EET) Resent-From: Andriy Gapon Resent-To: freebsd-ipfw@freebsd.org ReSent-Subject: packet dumping for ipfw ReSent-Message-ID: <20041223172950.V7281@oddity.topspin.kiev.ua> Subject: packet dumping for ipfw X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 23 Dec 2004 15:30:13 -0000 I remeber reading proposals for including full packet dump capability into ipfw. Recently I have stumbled upon this utility: http://cns.utoronto.ca/~pkern/stuff/ipfwpcap/ And it is quite a useful small program. I think it is worthy of including into our ports collection, or maybe even into the base system support for ipfw (no additional dependcies). -- Andriy Gapon From owner-freebsd-ipfw@FreeBSD.ORG Sat Dec 25 08:42:56 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 62AF316A4CE for ; Sat, 25 Dec 2004 08:42:56 +0000 (GMT) Received: from web21326.mail.yahoo.com (web21326.mail.yahoo.com [216.136.175.215]) by mx1.FreeBSD.org (Postfix) with SMTP id 3A47343D54 for ; Sat, 25 Dec 2004 08:42:56 +0000 (GMT) (envelope-from asal20002001@yahoo.com) Received: (qmail 49091 invoked by uid 60001); 25 Dec 2004 08:42:56 -0000 Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.com; b=xT73QvAg+K63X1E4QvjycFdHgoae4oH5szJ0RRj+vNLJvAKdKKkgRJY78tqVYehybpux8sVVNZ3CNSWMWp2KwB/mKPgPDHtKm38sZ/zEAq9iIdOn9O7gr2hwU/4As7utJXrwHqEStIWQo4DRdlmw4Fsi6vpE2x6FyoP6Z+9TcAk= ; Message-ID: <20041225084255.49089.qmail@web21326.mail.yahoo.com> Received: from [152.118.24.3] by web21326.mail.yahoo.com via HTTP; Sat, 25 Dec 2004 00:42:55 PST Date: Sat, 25 Dec 2004 00:42:55 -0800 (PST) From: Yudi To: freebsd-ipfw@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Content-Filtered-By: Mailman/MimeDel 2.1.1 Subject: bandwitdh is not limited X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Dec 2004 08:42:56 -0000 I'm student who's doing final project about QoS in ipv6, Finally, I can use dummynet by changing FREEBSDv4.9 to FREEBSDv5.3 for limiting my local bandwitdh. But, i'm confused that the bandwitdh is not limited. I know that by using ethereal and some streaming video. the sintag is oke , here it is : # ipfw add pipe 1 ipv6 from any to any # ipfw pipe 1 config bw 10kbit/s # ipfw show 00100 0 0 pipe 1 ipv6 from any to any 65535 0 0 allow ip from any to any Can anyone figure it out ??? Thanks before --------------------------------- Do you Yahoo!? Yahoo! Mail - 250MB free storage. Do more. Manage less. From owner-freebsd-ipfw@FreeBSD.ORG Sat Dec 25 10:39:59 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 8336616A4CE for ; Sat, 25 Dec 2004 10:39:59 +0000 (GMT) Received: from web21321.mail.yahoo.com (web21321.mail.yahoo.com [216.136.175.207]) by mx1.FreeBSD.org (Postfix) with SMTP id 2835943D48 for ; Sat, 25 Dec 2004 10:39:59 +0000 (GMT) (envelope-from asal20002001@yahoo.com) Received: (qmail 45802 invoked by uid 60001); 25 Dec 2004 10:39:59 -0000 Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.com; b=EJXJJNoJC9+fu0LdhV19w7b/jd9mOq40zj3eC/G4PxD9hg4+VFvhU92U3sHrpbkFxRSnhLoO/Cs6895yZ4OvyH8nzDu9o0/IhKKBQGMj+6K5sRVvVjF6A4WTCxj3XOywa6YKeIZ/6OBmaClSZRGB8Oh2J3KPTMrFnav7bLssA6U= ; Message-ID: <20041225103959.45800.qmail@web21321.mail.yahoo.com> Received: from [152.118.24.3] by web21321.mail.yahoo.com via HTTP; Sat, 25 Dec 2004 02:39:58 PST Date: Sat, 25 Dec 2004 02:39:58 -0800 (PST) From: Yudi To: freebsd-ipfw@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Content-Filtered-By: Mailman/MimeDel 2.1.1 Subject: dummynet for ipv6 X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Dec 2004 10:39:59 -0000 I'm sorry, this is the addition of the previous email. I wonder, did ipfw/dummynet support ipv6 ??? nb: I'm using FreeBSDv5.3 --------------------------------- Do you Yahoo!? The all-new My Yahoo! – What will yours do? From owner-freebsd-ipfw@FreeBSD.ORG Sat Dec 25 21:48:54 2004 Return-Path: Delivered-To: freebsd-ipfw@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 0AC1C16A4CE for ; Sat, 25 Dec 2004 21:48:54 +0000 (GMT) Received: from r2d2.bromirski.net (r2d2.bromirski.net [217.153.57.194]) by mx1.FreeBSD.org (Postfix) with ESMTP id 8F68943D1D for ; Sat, 25 Dec 2004 21:48:53 +0000 (GMT) (envelope-from lukasz@bromirski.net) Received: from [127.0.0.1] (szopen.jjs.pl [62.111.150.246]) by r2d2.bromirski.net (Postfix) with ESMTP id 23E76108AFA for ; Sat, 25 Dec 2004 22:48:52 +0100 (CET) Message-ID: <41CDE046.1090706@bromirski.net> Date: Sat, 25 Dec 2004 22:48:54 +0100 From: =?ISO-8859-2?Q?=A3ukasz_Bromirski?= User-Agent: Mozilla Thunderbird 1.0 (Windows/20041205) X-Accept-Language: en-us, en MIME-Version: 1.0 To: freebsd-ipfw@freebsd.org Content-Type: text/plain; charset=ISO-8859-2; format=flowed Content-Transfer-Encoding: 8bit X-Scan-Module: SMTP[mks_vir 2004.12.24 (2004.10.07)] Subject: IP rule to log also source MAC X-BeenThere: freebsd-ipfw@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: IPFW Technical Discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 25 Dec 2004 21:48:54 -0000 Hi, I wonder if the `log' keyword for ipfw could be extended to also log MAC-address of packet originator. Something like `log-input' on Cisco boxes, where You get also MAC of sender. It would be useful in scenarios, where You have spoofed traffic incoming on Ethernet interface, and IP source addresses are faked, spoofed etc. ..ie, when You have: deny log ip from any to any not verrevpath in via xl0 something like: deny log-input ip from any to any not verrevpath in via xl0 ...to get also source MAC-address. -- this space was intentionally left blank | Łukasz Bromirski you can insert your favourite quote here | lukasz:bromirski,net