[was] addition to ipfw (read vlans from bridge)..
Yar Tikhiy
yar at comp.chem.msu.su
Sat Dec 30 09:31:11 PST 2006
On Tue, Dec 26, 2006 at 02:31:47PM -0800, Julian Elischer wrote:
> Ok, so, here is a patch for general review by ipfw types.
> This is the first of two related changes.
>
> It is MOSTLY a cleanup of ip_fw2.c, removing a bunch of mtod()
> operations and replacing them with a cached value of the address of the
> IP header.
>
> It also has a couple of (commented out) references to
> args->L3offset which is the next commit. This explains
> WHY we are mainignsome of the cleanups.
> Basically, this commit removes the assumption that
> mtod(m, struct ip *) returns the address of the IP header,
> as there may be other stuff before it in the packet.
> e.g. vlan headers and ethernet headers.
>
> The next commit would actually implement that by modifying
> the callers to no longer strip such heaers off but instead,
> to set the offset correctly. (and uncomment those bits in
> this diff)
>
> The AIM of this code is to make it easier to do layer 2 based
> IP filtering when there may be a variety of L2 headers on the
> front of the packet. The idea is to make the changes in a way
> that ipfw (a layer 3 animal) does not need to know any of the
> details of the layer 2 encapsulation, of to know how to interpret
> L2 headers on the ffront of the packet. it needs to only know
> how much to skip over.
>
>
> Comments welcome.
>
Frankly, I am not too familiar with the details of the ip_fw2
implementation, but in general the change looks all right to me,
especially if you omit style changes from it.
However, I have one question regarding "etype", please see below.
> Index: netinet/ip_fw2.c
> ===================================================================
> RCS file: /usr/local/cvsroot/freebsd/src/sys/netinet/ip_fw2.c,v
> retrieving revision 1.155
> diff -u -r1.155 ip_fw2.c
> --- netinet/ip_fw2.c 12 Dec 2006 12:17:56 -0000 1.155
> +++ netinet/ip_fw2.c 26 Dec 2006 22:14:16 -0000
> @@ -667,10 +667,12 @@
> }
>
> 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;
> @@ -678,18 +680,11 @@
> 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;
> }
>
> @@ -705,14 +700,20 @@
> 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)
> @@ -721,14 +722,28 @@
> 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;
> }
> @@ -746,7 +761,8 @@
> */
> 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;
> @@ -892,13 +908,12 @@
> 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);
>
> @@ -942,7 +957,7 @@
> 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 ",
> @@ -1673,13 +1688,22 @@
> * 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);
> }
> @@ -2039,6 +2063,8 @@
> * 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)
> @@ -2060,12 +2086,11 @@
> * 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
> @@ -2075,15 +2100,18 @@
> *
> * 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 *);
> @@ -2154,6 +2182,7 @@
> 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 */
Here we suppose that etype will contain an ethertype value, don't we?
> /*
> * dyn_dir = MATCH_UNKNOWN when rules unchecked,
> @@ -2202,14 +2231,20 @@
> p = (mtod(m, char *) + (len)); \
> } while (0)
>
> + /*
> + * if we have an ether header,
> + */
> + if (args->eh)
> + etype = (ntohs(args->eh->ether_type)) == ETHERTYPE_VLAN;
And here we assign a boolean value to etype. Is it intended?
Looks like a error to me. Apparently it should read:
etype = ntohs(args->eh->ether_type);
But some processing of the (etype == ETHERTYPE_VLAN) case may be
missing here.
> +
> /* 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) {
> @@ -2354,16 +2389,16 @@
> 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;
>
> @@ -2407,6 +2442,7 @@
> }
> }
>
> + 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);
> }
> @@ -2573,15 +2609,14 @@
>
> 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;
>
> @@ -2733,12 +2768,12 @@
>
> 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:
> @@ -2752,9 +2787,9 @@
> 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;
> @@ -2769,12 +2804,12 @@
>
> 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:
> @@ -2866,7 +2901,7 @@
> case O_LOG:
> if (fw_verbose)
> ipfw_log(f, hlen, args, m,
> - oif, offset, tablearg);
> + oif, offset, tablearg, ip);
> match = 1;
> break;
>
> @@ -3204,7 +3239,7 @@
> 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 */
> @@ -3216,7 +3251,9 @@
> (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 */
--
Yar
More information about the freebsd-net
mailing list