summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_fw2.c
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2007-01-02 19:57:31 +0000
committerjulian <julian@FreeBSD.org>2007-01-02 19:57:31 +0000
commitfa85787a847721ae7f307f82717f81991dfed9a0 (patch)
tree8aee4ac4ea0ad4e31c6605703de13669b2871690 /sys/netinet/ip_fw2.c
parentbdddbb74e0dffee9c71c534a8654ff1d248a85d1 (diff)
downloadFreeBSD-src-fa85787a847721ae7f307f82717f81991dfed9a0.zip
FreeBSD-src-fa85787a847721ae7f307f82717f81991dfed9a0.tar.gz
Remove a bunch of dependencies in the IP header being the first thing in the
mbuf. First moves toward being able to cope better with having layer 2 (or other encapsulation data) before the IP header in the packet being examined. More commits to come to round out this functionality. This commit should have no practical effect but clears the way for what is coming. Revirewed by: luigi, yar MFC After: 2 weeks
Diffstat (limited to 'sys/netinet/ip_fw2.c')
-rw-r--r--sys/netinet/ip_fw2.c151
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 */
OpenPOWER on IntegriCloud