summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/ip_fw2.c201
1 files changed, 109 insertions, 92 deletions
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c
index a72a630..563ac52 100644
--- a/sys/netinet/ip_fw2.c
+++ b/sys/netinet/ip_fw2.c
@@ -318,14 +318,18 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive, CTLFLAG_RW,
/*
- * 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))
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<<type)) );
}
@@ -334,9 +338,10 @@ icmptype_match(struct ip *ip, ipfw_insn_u32 *cmd)
(1 << ICMP_TSTAMP) | (1 << ICMP_IREQ) | (1 << ICMP_MASKREQ) )
static int
-is_icmp_query(struct ip *ip)
+is_icmp_query(struct icmp *icmp)
{
- int type = L3HDR(struct icmp, ip)->icmp_type;
+ int type = icmp->icmp_type;
+
return (type <= ICMP_MAXTYPE && (TT & (1<<type)) );
}
#undef TT
@@ -412,10 +417,9 @@ ipopts_match(struct ip *ip, ipfw_insn *cmd)
}
static int
-tcpopts_match(struct ip *ip, ipfw_insn *cmd)
+tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
{
int optlen, bits = 0;
- struct tcphdr *tcp = L3HDR(struct tcphdr,ip);
u_char *cp = (u_char *)(tcp + 1);
int x = (tcp->th_off << 2) - sizeof(struct tcphdr);
@@ -1809,97 +1813,112 @@ 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;
+
+ /*
+ * 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;
struct ip_fw_chain *chain = &layer3_chain;
struct m_tag *mtag;
- if (m->m_flags & M_SKIP_FIREWALL)
- return (IP_FW_PASS); /* 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)
+ * 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. */
+
+ if (m->m_flags & M_SKIP_FIREWALL)
+ return (IP_FW_PASS); /* 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 */
- /*
- * 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;
- }
+/*
+ * 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 = (len) + sizeof(T); \
+ if ((m)->m_len < x) { \
+ args->m = m = m_pullup(m, x); \
+ if (m == NULL) \
+ goto pullup_failed; \
+ } \
+ p = (mtod(m, char *) + (len)); \
+} while (0)
- proto = args->f_id.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 */
- offset = ntohs(ip->ip_off) & IP_OFFMASK;
- ip_len = ntohs(ip->ip_len);
- } else {
- offset = ip->ip_off & IP_OFFMASK;
- ip_len = ip->ip_len;
- }
- 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;
- }
- break;
+ /* Identify IP packets and fill up veriables. */
+ if (pktlen >= sizeof(struct ip) &&
+ (args->eh == NULL || ntohs(args->eh->ether_type) == ETHERTYPE_IP) &&
+ mtod(m, struct ip *)->ip_v == 4) {
+ ip = mtod(m, struct ip *);
+ hlen = ip->ip_hl << 2;
+#ifdef NOTYET
+ args->f_id.addr_type = 4;
+#endif
- case IPPROTO_UDP:
- {
- struct udphdr *udp;
+ /*
+ * Collect parameters into local variables for faster matching.
+ */
+ 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 */
+ offset = ntohs(ip->ip_off) & IP_OFFMASK;
+ ip_len = ntohs(ip->ip_len);
+ } else {
+ offset = ip->ip_off & IP_OFFMASK;
+ ip_len = ip->ip_len;
+ }
+ pktlen = ip_len < pktlen ? ip_len : pktlen;
+
+ if (offset == 0) {
+ switch (proto) {
+ case IPPROTO_TCP:
+ PULLUP_TO(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;
- PULLUP_TO(hlen + sizeof(struct udphdr));
- udp = L3HDR(struct udphdr, ip);
- dst_port = udp->uh_dport;
- src_port = udp->uh_sport;
- }
- break;
+ case IPPROTO_UDP:
+ PULLUP_TO(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;
- break;
+ case IPPROTO_ICMP:
+ /*
+ * we only care for 4 bytes: type, code,
+ * checksum
+ */
+ PULLUP_TO(hlen, ulp, struct icmp);
+ args->f_id.flags = ICMP(ulp)->icmp_type;
+ break;
- default:
- break;
+ default:
+ break;
+ }
}
+
+ args->f_id.src_ip = ntohl(src_ip.s_addr);
+ args->f_id.dst_ip = ntohl(dst_ip.s_addr);
+ }
#undef PULLUP_TO
+ 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);
}
- args->f_id.src_ip = ntohl(src_ip.s_addr);
- args->f_id.dst_ip = ntohl(dst_ip.s_addr);
- args->f_id.src_port = src_port = ntohs(src_port);
- args->f_id.dst_port = dst_port = ntohs(dst_port);
-
-after_ip_checks:
IPFW_RLOCK(chain);
mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
if (args->rule) {
@@ -2196,7 +2215,7 @@ check_body:
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_IPOPT:
@@ -2250,7 +2269,7 @@ check_body:
uint16_t *p;
int i;
- tcp = L3HDR(struct tcphdr,ip);
+ tcp = TCP(ulp);
x = ip_len -
((ip->ip_hl + tcp->th_off) << 2);
if (cmdlen == 1) {
@@ -2267,38 +2286,36 @@ check_body:
case O_TCPFLAGS:
match = (proto == IPPROTO_TCP && offset == 0 &&
- flags_match(cmd,
- L3HDR(struct tcphdr,ip)->th_flags));
+ flags_match(cmd, TCP(ulp)->th_flags));
break;
case O_TCPOPTS:
match = (proto == IPPROTO_TCP && offset == 0 &&
- tcpopts_match(ip, cmd));
+ tcpopts_match(TCP(ulp), cmd));
break;
case O_TCPSEQ:
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 &&
((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);
+ 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 &
+ (TCP(ulp)->th_flags &
(TH_RST | TH_ACK | TH_SYN)) != TH_SYN);
break;
@@ -2437,7 +2454,7 @@ check_body:
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
@@ -2518,7 +2535,7 @@ check_body:
*/
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,
OpenPOWER on IntegriCloud