diff options
author | brooks <brooks@FreeBSD.org> | 2005-04-15 00:47:44 +0000 |
---|---|---|
committer | brooks <brooks@FreeBSD.org> | 2005-04-15 00:47:44 +0000 |
commit | def26873da79e9312c3cc02cd67700d2f2301f90 (patch) | |
tree | 73e1b3416723fb8aac4cc76c524e66547a50955f /sys/netinet/ip_fw2.c | |
parent | 81de31b8550822562334b600c4b906847db35008 (diff) | |
download | FreeBSD-src-def26873da79e9312c3cc02cd67700d2f2301f90.zip FreeBSD-src-def26873da79e9312c3cc02cd67700d2f2301f90.tar.gz |
Centralized finding the protocol header in IP packets in preperation for
IPv6 support. The header in IPv6 is more complex then in IPv4 so we
want to handle skipping over it in one location.
Submitted by: Mariano Tortoriello and Raffaele De Lorenzo (via luigi)
Diffstat (limited to 'sys/netinet/ip_fw2.c')
-rw-r--r-- | sys/netinet/ip_fw2.c | 201 |
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, |