From owner-svn-src-user@FreeBSD.ORG Mon Jan 4 16:03:26 2010 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id C40D310656A9; Mon, 4 Jan 2010 16:03:26 +0000 (UTC) (envelope-from luigi@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id B0DB88FC22; Mon, 4 Jan 2010 16:03:26 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o04G3QtP011502; Mon, 4 Jan 2010 16:03:26 GMT (envelope-from luigi@svn.freebsd.org) Received: (from luigi@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o04G3QFE011495; Mon, 4 Jan 2010 16:03:26 GMT (envelope-from luigi@svn.freebsd.org) Message-Id: <201001041603.o04G3QFE011495@svn.freebsd.org> From: Luigi Rizzo Date: Mon, 4 Jan 2010 16:03:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r201516 - in user/luigi/ipfw3-head/sys/netinet: . ipfw X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Jan 2010 16:03:26 -0000 Author: luigi Date: Mon Jan 4 16:03:26 2010 New Revision: 201516 URL: http://svn.freebsd.org/changeset/base/201516 Log: The main purpose of this commit is to fix 'divert', 'diverted' and operation with one_pass=0 which was not completed in the previous commits (in this branch). In detail: === ip_fw_private.h === + introduce enum constants to define the input and output info in struct ipfw_rule_ref, so the same format can be used by different clients. + remember to rename the file, as it exports kernel APIs, not private stuff; === ip_fw_pfil.c === + put the conversion of ip+len and ip_off in the right place (was not correct for reinjected packets); + optimize the path for net.inet.ip.fw.onepass=1 === ip_fw2.c === + complete the implementation of 'diverted' + localize a variable; === ip_divert.c === + use MTAG_IPFW_RULE tags for divert; + extract the rule and divert port directly from the tag; + store the return info in the 'info' field; Modified: user/luigi/ipfw3-head/sys/netinet/ip_divert.c user/luigi/ipfw3-head/sys/netinet/ip_divert.h user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw2.c user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_pfil.c user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_private.h Modified: user/luigi/ipfw3-head/sys/netinet/ip_divert.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ip_divert.c Mon Jan 4 15:58:36 2010 (r201515) +++ user/luigi/ipfw3-head/sys/netinet/ip_divert.c Mon Jan 4 16:03:26 2010 (r201516) @@ -218,7 +218,7 @@ divert_packet(struct mbuf *m, int incomi struct sockaddr_in divsrc; struct m_tag *mtag; - mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL); + mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL); if (mtag == NULL) { m_freem(m); return; @@ -244,14 +244,15 @@ divert_packet(struct mbuf *m, int incomi ip->ip_len = htons(ip->ip_len); } #endif + bzero(&divsrc, sizeof(divsrc)); + divsrc.sin_len = sizeof(divsrc); + divsrc.sin_family = AF_INET; + /* record matching rule, in host format */ + divsrc.sin_port = ((struct ipfw_rule_ref *)(mtag+1))->rulenum; /* * Record receive interface address, if any. * But only for incoming packets. */ - bzero(&divsrc, sizeof(divsrc)); - divsrc.sin_len = sizeof(divsrc); - divsrc.sin_family = AF_INET; - divsrc.sin_port = divert_cookie(mtag); /* record matching rule */ if (incoming) { struct ifaddr *ifa; struct ifnet *ifp; @@ -299,7 +300,7 @@ divert_packet(struct mbuf *m, int incomi /* Put packet on socket queue, if any */ sa = NULL; - nport = htons((u_int16_t)divert_info(mtag)); + nport = htons((u_int16_t)(((struct ipfw_rule_ref *)(mtag+1))->info)); INP_INFO_RLOCK(&V_divcbinfo); LIST_FOREACH(inp, &V_divcb, inp_list) { /* XXX why does only one socket match? */ @@ -395,7 +396,7 @@ div_output(struct socket *so, struct mbu struct ip *const ip = mtod(m, struct ip *); struct inpcb *inp; - dt->info |= IP_FW_DIVERT_OUTPUT_FLAG; + dt->info |= IPFW_IS_DIVERT | IPFW_INFO_OUT; INP_INFO_WLOCK(&V_divcbinfo); inp = sotoinpcb(so); INP_RLOCK(inp); @@ -461,7 +462,7 @@ div_output(struct socket *so, struct mbu m_freem(options); } } else { - dt->info |= IP_FW_DIVERT_LOOPBACK_FLAG; + dt->info |= IPFW_IS_DIVERT | IPFW_INFO_IN; if (m->m_pkthdr.rcvif == NULL) { /* * No luck with the name, check by IP address. Modified: user/luigi/ipfw3-head/sys/netinet/ip_divert.h ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ip_divert.h Mon Jan 4 15:58:36 2010 (r201515) +++ user/luigi/ipfw3-head/sys/netinet/ip_divert.h Mon Jan 4 16:03:26 2010 (r201516) @@ -55,15 +55,6 @@ divert_cookie(struct m_tag *mtag) return ((struct ipfw_rule_ref *)(mtag+1))->rulenum; } -/* - * Return the divert info associated with the mbuf; if any. - */ -static __inline u_int32_t -divert_info(struct m_tag *mtag) -{ - return ((struct ipfw_rule_ref *)(mtag+1))->info; -} - typedef void ip_divert_packet_t(struct mbuf *m, int incoming); extern ip_divert_packet_t *ip_divert_ptr; Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Mon Jan 4 15:58:36 2010 (r201515) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_dummynet.c Mon Jan 4 16:03:26 2010 (r201516) @@ -1370,7 +1370,7 @@ dummynet_io(struct mbuf **m0, int dir, s struct dn_pipe *pipe; uint64_t len = m->m_pkthdr.len; struct dn_flow_queue *q = NULL; - int is_pipe = fwa->rule.info & 0x8000000 ? 0 : 1; + int is_pipe = fwa->rule.info & IPFW_IS_PIPE; KASSERT(m->m_nextpkt == NULL, ("dummynet_io: mbuf queue passed to dummynet")); @@ -1379,16 +1379,13 @@ dummynet_io(struct mbuf **m0, int dir, s io_pkt++; /* * This is a dummynet rule, so we expect an O_PIPE or O_QUEUE rule. - * - * XXXGL: probably the pipe->fs and fs->pipe logic here - * below can be simplified. */ if (is_pipe) { - pipe = locate_pipe(fwa->rule.info & 0xffff); + pipe = locate_pipe(fwa->rule.info & IPFW_INFO_MASK); if (pipe != NULL) fs = &(pipe->fs); } else - fs = locate_flowset(fwa->rule.info & 0xffff); + fs = locate_flowset(fwa->rule.info & IPFW_INFO_MASK); if (fs == NULL) goto dropit; /* This queue/pipe does not exist! */ @@ -1435,6 +1432,7 @@ dummynet_io(struct mbuf **m0, int dir, s * Build and enqueue packet + parameters. */ pkt->rule = fwa->rule; + pkt->rule.info &= IPFW_ONEPASS; /* only keep this info */ pkt->dn_dir = dir; pkt->ifp = fwa->oif; Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw2.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw2.c Mon Jan 4 15:58:36 2010 (r201515) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw2.c Mon Jan 4 16:03:26 2010 (r201516) @@ -799,14 +799,6 @@ ipfw_chk(struct ip_fw_args *args) int ucred_lookup = 0; /* - * divinput_flags If non-zero, set to the IP_FW_DIVERT_*_FLAG - * associated with a packet input on a divert socket. This - * will allow to distinguish traffic and its direction when - * it originates from a divert socket. - */ - u_int divinput_flags = 0; - - /* * oif | args->oif If NULL, ipfw_chk has been called on the * inbound path (ether_input, ip_input). * If non-NULL, ipfw_chk has been called on the outbound path @@ -864,7 +856,6 @@ ipfw_chk(struct ip_fw_args *args) int dyn_dir = MATCH_UNKNOWN; ipfw_dyn_rule *q = NULL; struct ip_fw_chain *chain = &V_layer3_chain; - struct m_tag *mtag; /* * We store in ulp a pointer to the upper layer protocol header. @@ -1152,10 +1143,6 @@ do { \ } else { f_pos = 0; } -#if 0 // XXX to be fixed - divinput_flags = divert_info(mtag) & - (IP_FW_DIVERT_OUTPUT_FLAG | IP_FW_DIVERT_LOOPBACK_FLAG); -#endif /* * Now scan the rules, and parse microinstructions for each rule. @@ -1306,10 +1293,15 @@ do { \ break; case O_DIVERTED: - match = (cmd->arg1 & 1 && divinput_flags & - IP_FW_DIVERT_LOOPBACK_FLAG) || - (cmd->arg1 & 2 && divinput_flags & - IP_FW_DIVERT_OUTPUT_FLAG); + { + /* For diverted packets, args->rule.info + * contains the divert port (in host format) + * reason and direction. + */ + uint32_t i = args->rule.info; + match = (i&IPFW_IS_MASK) == IPFW_IS_DIVERT && + cmd->arg1 & ((i & IPFW_INFO_IN) ? 1 : 2); + } break; case O_PROTO: @@ -1729,6 +1721,7 @@ do { \ break; case O_TAG: { + struct m_tag *mtag; uint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ? tablearg : cmd->arg1; @@ -1761,6 +1754,7 @@ do { \ break; case O_TAGGED: { + struct m_tag *mtag; uint32_t tag = (cmd->arg1 == IP_FW_TABLEARG) ? tablearg : cmd->arg1; @@ -1903,8 +1897,10 @@ do { \ set_match(args, f_pos, chain); args->rule.info = (cmd->arg1 == IP_FW_TABLEARG) ? tablearg : cmd->arg1; - if (cmd->opcode == O_QUEUE) - args->rule.info |= 0x80000000; + if (cmd->opcode == O_PIPE) + args->rule.info |= IPFW_IS_PIPE; + if (V_fw_one_pass) + args->rule.info |= IPFW_ONEPASS; retval = IP_FW_DUMMYNET; l = 0; /* exit inner loop */ done = 1; /* exit outer loop */ @@ -1917,6 +1913,8 @@ do { \ /* otherwise this is terminal */ l = 0; /* exit inner loop */ done = 1; /* exit outer loop */ + retval = (cmd->opcode == O_DIVERT) ? + IP_FW_DIVERT : IP_FW_TEE; set_match(args, f_pos, chain); args->rule.info = (cmd->arg1 == IP_FW_TABLEARG) ? tablearg : cmd->arg1; Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_pfil.c ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_pfil.c Mon Jan 4 15:58:36 2010 (r201515) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_pfil.c Mon Jan 4 16:03:26 2010 (r201516) @@ -110,33 +110,35 @@ ipfw_check_hook(void *arg, struct mbuf * struct m_tag *tag; int ipfw; int ret; -#ifdef IPFIREWALL_FORWARD - struct m_tag *fwd_tag; -#endif + + /* all the processing now uses ip_len in net format */ + SET_NET_IPLEN(mtod(*m0, struct ip *)); /* convert dir to IPFW values */ dir = (dir == PFIL_IN) ? DIR_IN : DIR_OUT; bzero(&args, sizeof(args)); again: + /* + * extract and remove the tag if present. If we are left + * with onepass, optimize the outgoing path. + */ tag = m_tag_locate(*m0, MTAG_IPFW_RULE, 0, NULL); if (tag != NULL) { args.rule = *((struct ipfw_rule_ref *)(tag+1)); m_tag_delete(*m0, tag); + if (args.rule.info & IPFW_ONEPASS) { + SET_HOST_IPLEN(mtod(*m0, struct ip *)); + return 0; + } } args.m = *m0; args.oif = dir == DIR_OUT ? ifp : NULL; args.inp = inp; - /* all the processing now uses ip_len in net format */ - SET_NET_IPLEN(mtod(*m0, struct ip *)); - - if (V_fw_one_pass == 0 || args.rule.slot == 0) { - ipfw = ipfw_chk(&args); - *m0 = args.m; - } else - ipfw = IP_FW_PASS; + ipfw = ipfw_chk(&args); + *m0 = args.m; KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL", __func__)); @@ -151,6 +153,9 @@ again: #ifndef IPFIREWALL_FORWARD ret = EACCES; #else + { + struct m_tag *fwd_tag; + /* Incoming packets should not be tagged so we do not * m_tag_find. Outgoing packets may be tagged, so we * reuse the tag if present. @@ -172,6 +177,7 @@ again: if (in_localip(args.next_hop->sin_addr)) (*m0)->m_flags |= M_FASTFWD_OURS; + } #endif break; Modified: user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_private.h ============================================================================== --- user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_private.h Mon Jan 4 15:58:36 2010 (r201515) +++ user/luigi/ipfw3-head/sys/netinet/ipfw/ip_fw_private.h Mon Jan 4 16:03:26 2010 (r201516) @@ -51,10 +51,6 @@ enum { IP_FW_REASS, }; -/* flags for divert mtag */ -#define IP_FW_DIVERT_LOOPBACK_FLAG 0x00080000 -#define IP_FW_DIVERT_OUTPUT_FLAG 0x00100000 - /* * Structure for collecting parameters to dummynet for ip6_output forwarding */ @@ -75,13 +71,32 @@ struct _ip6dn_args { * A rule is identified by rulenum:rule_id which is ordered. * In version chain_id the rule can be found in slot 'slot', so * we don't need a lookup if chain_id == chain->id. + * + * On exit from the firewall this structure refers to the rule after + * the matching one (slot points to the new rule; rulenum:rule_id-1 + * is the matching rule), and additional info (e.g. info often contains + * the insn argument or tablearg in the low 16 bits, in host format). + * On entry, the structure is valid if slot>0, and refers to the starting + * rules. 'info' contains the reason for reinject, e.g. divert port, + * divert direction, and so on. */ struct ipfw_rule_ref { uint32_t slot; /* slot for matching rule */ uint32_t rulenum; /* matching rule number */ uint32_t rule_id; /* matching rule id */ uint32_t chain_id; /* ruleset id */ - uint32_t info; /* reason for reinject */ + uint32_t info; /* see below */ +}; + +enum { + IPFW_INFO_MASK = 0x0000ffff, + IPFW_INFO_OUT = 0x00000000, /* outgoing, just for convenience */ + IPFW_INFO_IN = 0x80000000, /* incoming, overloads dir */ + IPFW_ONEPASS = 0x40000000, /* One-pass, do not reinject */ + IPFW_IS_MASK = 0x30000000, /* which source ? */ + IPFW_IS_DIVERT = 0x20000000, + IPFW_IS_DUMMYNET =0x10000000, + IPFW_IS_PIPE = 0x08000000, /* pip1=1, queue = 0 */ }; /*