diff options
-rw-r--r-- | sys/netinet/ip_fw2.c | 151 |
1 files changed, 94 insertions, 57 deletions
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 070de18..8278eaf 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -672,10 +672,12 @@ is_icmp6_query(int icmp6_type) } static void -send_reject6(struct ip_fw_args *args, int code, u_int hlen) +send_reject6(struct ip_fw_args *args, int code, u_int hlen, struct ip6_hdr *ip6) { + struct mbuf *m; + + m = args->m; if (code == ICMP6_UNREACH_RST && args->f_id.proto == IPPROTO_TCP) { - struct ip6_hdr *ip6; struct tcphdr *tcp; tcp_seq ack, seq; int flags; @@ -683,18 +685,11 @@ send_reject6(struct ip_fw_args *args, int code, u_int hlen) struct ip6_hdr ip6; struct tcphdr th; } ti; - - if (args->m->m_len < (hlen+sizeof(struct tcphdr))) { - args->m = m_pullup(args->m, hlen+sizeof(struct tcphdr)); - if (args->m == NULL) - return; - } - - ip6 = mtod(args->m, struct ip6_hdr *); - tcp = (struct tcphdr *)(mtod(args->m, char *) + hlen); + tcp = (struct tcphdr *)((char *)ip6 + hlen); if ((tcp->th_flags & TH_RST) != 0) { - m_freem(args->m); + m_freem(m); + args->m = NULL; return; } @@ -710,14 +705,20 @@ send_reject6(struct ip_fw_args *args, int code, u_int hlen) flags = TH_RST; } else { ack = ti.th.th_seq; - if (((args->m)->m_flags & M_PKTHDR) != 0) { - ack += (args->m)->m_pkthdr.len - hlen + if ((m->m_flags & M_PKTHDR) != 0) { + /* + * total new data to ACK is: + * total packet length, + * minus the header length, + * minus the tcp header length. + */ + ack += m->m_pkthdr.len - hlen - (ti.th.th_off << 2); } else if (ip6->ip6_plen) { - ack += ntohs(ip6->ip6_plen) + sizeof(*ip6) - - hlen - (ti.th.th_off << 2); + ack += ntohs(ip6->ip6_plen) + sizeof(*ip6) - + hlen - (ti.th.th_off << 2); } else { - m_freem(args->m); + m_freem(m); return; } if (tcp->th_flags & TH_SYN) @@ -726,14 +727,28 @@ send_reject6(struct ip_fw_args *args, int code, u_int hlen) flags = TH_RST|TH_ACK; } bcopy(&ti, ip6, sizeof(ti)); - tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1), - args->m, ack, seq, flags); - + /* + * m is only used to recycle the mbuf + * The data in it is never read so we don't need + * to correct the offsets or anything + */ + tcp_respond(NULL, ip6, tcp, m, ack, seq, flags); } else if (code != ICMP6_UNREACH_RST) { /* Send an ICMPv6 unreach. */ - icmp6_error(args->m, ICMP6_DST_UNREACH, code, 0); - +#if 0 + /* + * Unlike above, the mbufs need to line up with the ip6 hdr, + * as the contents are read. We need to m_adj() the + * needed amount. + * The mbuf will however be thrown away so we can adjust it. + * Remember we did an m_pullup on it already so we + * can make some assumptions about contiguousness. + */ + if (args->L3offset) + m_adj(m, args->L3offset); +#endif + icmp6_error(m, ICMP6_DST_UNREACH, code, 0); } else - m_freem(args->m); + m_freem(m); args->m = NULL; } @@ -751,7 +766,8 @@ static u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */ */ static void ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, - struct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg) + struct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg, + struct ip *ip) { struct ether_header *eh = args->eh; char *action; @@ -900,13 +916,12 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, snprintf(dst, sizeof(dst), "[%s]", ip6_sprintf(ip6buf, &args->f_id.dst_ip6)); - ip6 = (struct ip6_hdr *)mtod(m, struct ip6_hdr *); - tcp = (struct tcphdr *)(mtod(args->m, char *) + hlen); - udp = (struct udphdr *)(mtod(args->m, char *) + hlen); + ip6 = (struct ip6_hdr *)ip; + tcp = (struct tcphdr *)(((char *)ip) + hlen); + udp = (struct udphdr *)(((char *)ip) + hlen); } else #endif { - ip = mtod(m, struct ip *); tcp = L3HDR(struct tcphdr, ip); udp = L3HDR(struct udphdr, ip); @@ -950,7 +965,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, break; #ifdef INET6 case IPPROTO_ICMPV6: - icmp6 = (struct icmp6_hdr *)(mtod(args->m, char *) + hlen); + icmp6 = (struct icmp6_hdr *)(((char *)ip) + hlen); if (offset == 0) len = snprintf(SNPARGS(proto, 0), "ICMPv6:%u.%u ", @@ -1681,13 +1696,22 @@ send_pkt(struct mbuf *replyto, struct ipfw_flow_id *id, u_int32_t seq, * sends a reject message, consuming the mbuf passed as an argument. */ static void -send_reject(struct ip_fw_args *args, int code, int ip_len) +send_reject(struct ip_fw_args *args, int code, int ip_len, struct ip *ip) { +#if 0 + /* XXX When ip is not guaranteed to be at mtod() we will + * need to account for this */ + * The mbuf will however be thrown away so we can adjust it. + * Remember we did an m_pullup on it already so we + * can make some assumptions about contiguousness. + */ + if (args->L3offset) + m_adj(m, args->L3offset); +#endif if (code != ICMP_REJECT_RST) { /* Send an ICMP unreach */ /* We need the IP header in host order for icmp_error(). */ if (args->eh != NULL) { - struct ip *ip = mtod(args->m, struct ip *); ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); } @@ -2219,6 +2243,8 @@ bad: * args->m (in/out) The packet; we set to NULL when/if we nuke it. * Starts with the IP header. * args->eh (in) Mac header if present, or NULL for layer3 packet. + * args->L3offset Number of bytes bypassed if we came from L2. + * e.g. often sizeof(eh) ** NOTYET ** * args->oif Outgoing interface, or NULL if packet is incoming. * The incoming interface is in the mbuf. (in) * args->divert_rule (in/out) @@ -2240,12 +2266,11 @@ bad: * IP_FW_NETGRAPH into netgraph, cookie args->cookie * */ - int ipfw_chk(struct ip_fw_args *args) { /* - * Local variables hold state during the processing of a packet. + * Local variables holding state during the processing of a packet: * * IMPORTANT NOTE: to speed up the processing of rules, there * are some assumption on the values of the variables, which @@ -2255,15 +2280,18 @@ ipfw_chk(struct ip_fw_args *args) * * args->eh The MAC header. It is non-null for a layer2 * packet, it is NULL for a layer-3 packet. + * **notyet** + * args->L3offset Offset in the packet to the L3 (IP or equiv.) header. * * m | args->m Pointer to the mbuf, as received from the caller. * It may change if ipfw_chk() does an m_pullup, or if it * 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). + * ip is the beginning of the ip(4 or 6) header. + * Calculated by adding the L3offset to the start of data. + * (Until we start using L3offset, the packet is + * supposed to start with the ip header). */ struct mbuf *m = args->m; struct ip *ip = mtod(m, struct ip *); @@ -2334,6 +2362,7 @@ ipfw_chk(struct ip_fw_args *args) struct in_addr src_ip, dst_ip; /* NOTE: network format */ u_int16_t ip_len=0; int pktlen; + u_int16_t etype = 0; /* Host order stored ether type */ /* * dyn_dir = MATCH_UNKNOWN when rules unchecked, @@ -2382,14 +2411,20 @@ do { \ p = (mtod(m, char *) + (len)); \ } while (0) + /* + * if we have an ether header, + */ + if (args->eh) + etype = ntohs(args->eh->ether_type); + /* Identify IP packets and fill up variables. */ if (pktlen >= sizeof(struct ip6_hdr) && - (args->eh == NULL || ntohs(args->eh->ether_type)==ETHERTYPE_IPV6) && - mtod(m, struct ip *)->ip_v == 6) { + (args->eh == NULL || etype == ETHERTYPE_IPV6) && ip->ip_v == 6) { + struct ip6_hdr *ip6 = (struct ip6_hdr *)ip; is_ipv6 = 1; args->f_id.addr_type = 6; hlen = sizeof(struct ip6_hdr); - proto = mtod(m, struct ip6_hdr *)->ip6_nxt; + proto = ip6->ip6_nxt; /* Search extension headers to find upper layer protocols */ while (ulp == NULL) { @@ -2534,16 +2569,16 @@ do { \ break; } /*switch */ } - args->f_id.src_ip6 = mtod(m,struct ip6_hdr *)->ip6_src; - args->f_id.dst_ip6 = mtod(m,struct ip6_hdr *)->ip6_dst; + ip = mtod(m, struct ip *); + ip6 = (struct ip6_hdr *)ip; + args->f_id.src_ip6 = ip6->ip6_src; + args->f_id.dst_ip6 = ip6->ip6_dst; args->f_id.src_ip = 0; args->f_id.dst_ip = 0; - args->f_id.flow_id6 = ntohl(mtod(m, struct ip6_hdr *)->ip6_flow); + args->f_id.flow_id6 = ntohl(ip6->ip6_flow); } else if (pktlen >= sizeof(struct ip) && - (args->eh == NULL || ntohs(args->eh->ether_type) == ETHERTYPE_IP) && - mtod(m, struct ip *)->ip_v == 4) { + (args->eh == NULL || etype == ETHERTYPE_IP) && ip->ip_v == 4) { is_ipv4 = 1; - ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; args->f_id.addr_type = 4; @@ -2587,6 +2622,7 @@ do { \ } } + ip = mtod(m, struct ip *); args->f_id.src_ip = ntohl(src_ip.s_addr); args->f_id.dst_ip = ntohl(dst_ip.s_addr); } @@ -2753,15 +2789,14 @@ check_body: case O_MAC_TYPE: if (args->eh != NULL) { - u_int16_t t = - ntohs(args->eh->ether_type); u_int16_t *p = ((ipfw_insn_u16 *)cmd)->ports; int i; for (i = cmdlen - 1; !match && i>0; i--, p += 2) - match = (t>=p[0] && t<=p[1]); + match = (etype >= p[0] && + etype <= p[1]); } break; @@ -2913,12 +2948,12 @@ check_body: case O_IPOPT: match = (is_ipv4 && - ipopts_match(mtod(m, struct ip *), cmd) ); + ipopts_match(ip, cmd) ); break; case O_IPVER: match = (is_ipv4 && - cmd->arg1 == mtod(m, struct ip *)->ip_v); + cmd->arg1 == ip->ip_v); break; case O_IPID: @@ -2932,9 +2967,9 @@ check_body: if (cmd->opcode == O_IPLEN) x = ip_len; else if (cmd->opcode == O_IPTTL) - x = mtod(m, struct ip *)->ip_ttl; + x = ip->ip_ttl; else /* must be IPID */ - x = ntohs(mtod(m, struct ip *)->ip_id); + x = ntohs(ip->ip_id); if (cmdlen == 1) { match = (cmd->arg1 == x); break; @@ -2949,12 +2984,12 @@ check_body: case O_IPPRECEDENCE: match = (is_ipv4 && - (cmd->arg1 == (mtod(m, struct ip *)->ip_tos & 0xe0)) ); + (cmd->arg1 == (ip->ip_tos & 0xe0)) ); break; case O_IPTOS: match = (is_ipv4 && - flags_match(cmd, mtod(m, struct ip *)->ip_tos)); + flags_match(cmd, ip->ip_tos)); break; case O_TCPDATALEN: @@ -3046,7 +3081,7 @@ check_body: case O_LOG: if (fw_verbose) ipfw_log(f, hlen, args, m, - oif, offset, tablearg); + oif, offset, tablearg, ip); match = 1; break; @@ -3384,7 +3419,7 @@ check_body: is_icmp_query(ICMP(ulp))) && !(m->m_flags & (M_BCAST|M_MCAST)) && !IN_MULTICAST(ntohl(dst_ip.s_addr))) { - send_reject(args, cmd->arg1, ip_len); + send_reject(args, cmd->arg1, ip_len, ip); m = args->m; } /* FALLTHROUGH */ @@ -3396,7 +3431,9 @@ check_body: (is_icmp6_query(args->f_id.flags) == 1)) && !(m->m_flags & (M_BCAST|M_MCAST)) && !IN6_IS_ADDR_MULTICAST(&args->f_id.dst_ip6)) { - send_reject6(args, cmd->arg1, hlen); + send_reject6( + args, cmd->arg1, hlen, + (struct ip6_hdr *)ip); m = args->m; } /* FALLTHROUGH */ |