Change 14861 by fumerola@scurvy on 2003/10/15 22:36:01 MFC: ipfw1 support for more fields in the ip and tcp headers. Affected files ... ... //depot/yahoo/ybsd_4/src/sbin/ipfw/ipfw.c#13 integrate ... //depot/yahoo/ybsd_4/src/sys/netinet/ip_fw.c#16 integrate ... //depot/yahoo/ybsd_4/src/sys/netinet/ip_fw.h#4 integrate Differences ... ==== //depot/yahoo/ybsd_4/src/sbin/ipfw/ipfw.c#13 (text+ko) ==== @@ -435,7 +435,7 @@ if (chain->fw_flg & IP_FW_F_FRAG) printf(" frag"); - if (chain->fw_ipopt || chain->fw_ipnopt) { + if (chain->fw_ipflg & IP_FW_IF_IPOPT) { int _opt_printed = 0; #define PRINTOPT(x) {if (_opt_printed) printf(",");\ printf(x); _opt_printed = 1;} @@ -459,12 +459,49 @@ PRINTOPT("!ts"); } + if (chain->fw_ipflg & IP_FW_IF_IPLEN) + printf(" iplen %u", chain->fw_iplen); + if (chain->fw_ipflg & IP_FW_IF_IPID) + printf(" ipid %#x", chain->fw_ipid); + + if (chain->fw_ipflg & IP_FW_IF_IPTOS) { + int _opt_printed = 0; + + printf(" iptos "); + if (chain->fw_iptos & IPTOS_LOWDELAY) + PRINTOPT("lowdelay"); + if (chain->fw_ipntos & IPTOS_LOWDELAY) + PRINTOPT("!lowdelay"); + if (chain->fw_iptos & IPTOS_THROUGHPUT) + PRINTOPT("throughput"); + if (chain->fw_ipntos & IPTOS_THROUGHPUT) + PRINTOPT("!throughput"); + if (chain->fw_iptos & IPTOS_RELIABILITY) + PRINTOPT("reliability"); + if (chain->fw_ipntos & IPTOS_RELIABILITY) + PRINTOPT("!reliability"); + if (chain->fw_iptos & IPTOS_MINCOST) + PRINTOPT("mincost"); + if (chain->fw_ipntos & IPTOS_MINCOST) + PRINTOPT("!mincost"); + if (chain->fw_iptos & IPTOS_CE) + PRINTOPT("congestion"); + if (chain->fw_ipntos & IPTOS_CE) + PRINTOPT("!congestion"); + } + + if (chain->fw_ipflg & IP_FW_IF_IPTTL) + printf(" ipttl %u", chain->fw_ipttl); + + if (chain->fw_ipflg & IP_FW_IF_IPVER) + printf(" ipversion %u", chain->fw_ipver); + if (chain->fw_ipflg & IP_FW_IF_TCPEST) printf(" established"); else if (chain->fw_tcpf == IP_FW_TCPF_SYN && chain->fw_tcpnf == IP_FW_TCPF_ACK) printf(" setup"); - else if (chain->fw_tcpf || chain->fw_tcpnf) { + else if (chain->fw_ipflg & IP_FW_IF_TCPFLG) { int _flg_printed = 0; #define PRINTFLG(x) {if (_flg_printed) printf(",");\ printf(x); _flg_printed = 1;} @@ -495,7 +532,7 @@ if (chain->fw_tcpnf & IP_FW_TCPF_URG) PRINTFLG("!urg"); } - if (chain->fw_tcpopt || chain->fw_tcpnopt) { + if (chain->fw_ipflg & IP_FW_IF_TCPOPT) { int _opt_printed = 0; #define PRINTTOPT(x) {if (_opt_printed) printf(",");\ printf(x); _opt_printed = 1;} @@ -523,6 +560,13 @@ PRINTTOPT("!cc"); } + if (chain->fw_ipflg & IP_FW_IF_TCPSEQ) + printf(" tcpseq %lu", ntohl(chain->fw_tcpseq)); + if (chain->fw_ipflg & IP_FW_IF_TCPACK) + printf(" tcpack %lu", ntohl(chain->fw_tcpack)); + if (chain->fw_ipflg & IP_FW_IF_TCPWIN) + printf(" tcpwin %hu", ntohs(chain->fw_tcpwin)); + if (chain->fw_flg & IP_FW_F_ICMPBIT) { int type_index; int first = 1; @@ -918,7 +962,15 @@ " {established|setup}\n" " tcpflags [!]{syn|fin|rst|ack|psh|urg}, ...\n" " ipoptions [!]{ssrr|lsrr|rr|ts}, ...\n" +" iplen {length}\n" +" ipid {identification number}\n" +" iptos [!]{lowdelay|throughput|reliability|mincost|congestion}\n" +" ipttl {time to live}\n" +" ipversion {version number}\n" " tcpoptions [!]{mss|window|sack|ts|cc}, ...\n" +" tcpseq {sequence number}\n" +" tcpack {acknowledgement number}\n" +" tcpwin {window size}\n" " icmptypes {type[, type]}...\n" " keep-state [method]\n" " pipeconfig:\n" @@ -1236,6 +1288,36 @@ } static void +fill_iptos(u_char *set, u_char *reset, char **vp) +{ + char *p = *vp,*q; + u_char *d; + + while (p && *p) { + if (*p == '!') { + p++; + d = reset; + } else { + d = set; + } + q = strchr(p, ','); + if (q) + *q++ = '\0'; + if (!strncmp(p,"lowdelay",strlen(p))) + *d |= IPTOS_LOWDELAY; + if (!strncmp(p,"throughput",strlen(p))) + *d |= IPTOS_THROUGHPUT; + if (!strncmp(p,"reliability",strlen(p))) + *d |= IPTOS_RELIABILITY; + if (!strncmp(p,"mincost",strlen(p))) + *d |= IPTOS_MINCOST; + if (!strncmp(p,"congestion",strlen(p))) + *d |= IPTOS_CE; + p = q; + } +} + +static void fill_icmptypes(unsigned *types, char **vp, u_int *fw_flg) { unsigned long icmptype; @@ -2048,15 +2130,67 @@ if (!ac) errx(EX_USAGE, "missing argument" " for ``ipoptions''"); + rule.fw_ipflg |= IP_FW_IF_IPOPT; fill_ipopt(&rule.fw_ipopt, &rule.fw_ipnopt, av); av++; ac--; + } else if (!strncmp(*av,"iplen",strlen(*av))) { + av++; ac--; + if (!ac) + errx(EX_USAGE, "missing argument" + " for ``iplen''"); + rule.fw_ipflg |= IP_FW_IF_IPLEN; + rule.fw_iplen = (u_short)strtoul(*av, NULL, 0); + av++; ac--; + } else if (!strncmp(*av,"ipid",strlen(*av))) { + unsigned long ipid; + char *c; + + av++; ac--; + if (!ac) + errx(EX_USAGE, "missing argument" + " for ``ipid''"); + rule.fw_ipflg |= IP_FW_IF_IPID; + ipid = strtoul(*av, &c, 0); + if (*c != '\0') + errx(EX_USAGE, "ipid must be numeric"); + if (ipid > 65535) + errx(EX_USAGE," ipid out of range"); + rule.fw_ipid = (u_short)ipid; + av++; ac--; + } else if (!strncmp(*av,"iptos",strlen(*av))) { + av++; ac--; + if (!ac) + errx(EX_USAGE, "missing argument" + " for ``iptos''"); + rule.fw_ipflg |= IP_FW_IF_IPTOS; + fill_iptos(&rule.fw_iptos, &rule.fw_ipntos, av); + av++; ac--; + } else if (!strncmp(*av,"ipttl",strlen(*av))) { + av++; ac--; + if (!ac) + errx(EX_USAGE, "missing argument" + " for ``ipttl''"); + rule.fw_ipflg |= IP_FW_IF_IPTTL; + rule.fw_ipttl = (u_short)strtoul(*av, NULL, 0); + av++; ac--; + } else if (!strncmp(*av,"ipversion",strlen(*av)) || + !strncmp(*av,"ipver",strlen(*av))) { + av++; ac--; + if (!ac) + errx(EX_USAGE, "missing argument" + " for ``ipversion''"); + rule.fw_ipflg |= IP_FW_IF_IPVER; + rule.fw_ipver = (u_short)strtoul(*av, NULL, 0); + av++; ac--; } else if (rule.fw_prot == IPPROTO_TCP) { if (!strncmp(*av, "established", strlen(*av))) { rule.fw_ipflg |= IP_FW_IF_TCPEST; + rule.fw_ipflg |= IP_FW_IF_TCPFLG; av++; ac--; } else if (!strncmp(*av, "setup", strlen(*av))) { rule.fw_tcpf |= IP_FW_TCPF_SYN; rule.fw_tcpnf |= IP_FW_TCPF_ACK; + rule.fw_ipflg |= IP_FW_IF_TCPFLG; av++; ac--; } else if (!strncmp(*av, "tcpflags", strlen(*av)) || !strncmp(*av, "tcpflgs", strlen(*av))) { @@ -2064,6 +2198,7 @@ if (!ac) errx(EX_USAGE, "missing argument" " for ``tcpflags''"); + rule.fw_ipflg |= IP_FW_IF_TCPFLG; fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av); av++; ac--; @@ -2073,9 +2208,34 @@ if (!ac) errx(EX_USAGE, "missing argument" " for ``tcpoptions''"); + rule.fw_ipflg |= IP_FW_IF_TCPOPT; fill_tcpopts(&rule.fw_tcpopt, &rule.fw_tcpnopt, av); av++; ac--; + } else if (!strncmp(*av,"tcpseq",strlen(*av))) { + av++; ac--; + if (!ac) + errx(EX_USAGE, "missing argument" + " for ``tcpseq''"); + rule.fw_ipflg |= IP_FW_IF_TCPSEQ; + rule.fw_tcpseq = htonl((u_int32_t)strtoul(*av, NULL, 0)); + av++; ac--; + } else if (!strncmp(*av,"tcpack",strlen(*av))) { + av++; ac--; + if (!ac) + errx(EX_USAGE, "missing argument" + " for ``tcpack''"); + rule.fw_ipflg |= IP_FW_IF_TCPACK; + rule.fw_tcpack = htonl((u_int32_t)strtoul(*av, NULL, 0)); + av++; ac--; + } else if (!strncmp(*av,"tcpwin",strlen(*av))) { + av++; ac--; + if (!ac) + errx(EX_USAGE, "missing argument" + " for ``tcpwin''"); + rule.fw_ipflg |= IP_FW_IF_TCPWIN; + rule.fw_tcpwin = htons((u_short)strtoul(*av, NULL, 0)); + av++; ac--; } else { errx(EX_USAGE, "unknown or out of order" " argument ``%s''", *av); ==== //depot/yahoo/ybsd_4/src/sys/netinet/ip_fw.c#16 (text+ko) ==== @@ -377,6 +377,31 @@ } static int +iptos_match(struct ip *ip, struct ip_fw *f) +{ + + u_int flags = (ip->ip_tos & 0x1f); + u_char opts, nopts, nopts_sve; + + opts = f->fw_iptos; + nopts = nopts_sve = f->fw_ipntos; + + while (flags != 0) { + u_int flag; + + flag = 1 << (ffs(flags) -1); + opts &= ~flag; + nopts &= ~flag; + flags &= ~flag; + } + + if (opts == 0 && nopts == nopts_sve) + return 1; + else + return 0; +} + +static int tcpopts_match(struct tcphdr *tcp, struct ip_fw *f) { register u_char *cp; @@ -1291,8 +1316,18 @@ continue; } - /* Check IP options */ - if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f)) + /* Check IP header values */ + if (f->fw_ipflg & IP_FW_IF_IPOPT && !ipopts_match(ip, f)) + continue; + if (f->fw_ipflg & IP_FW_IF_IPLEN && f->fw_iplen != ip->ip_len) + continue; + if (f->fw_ipflg & IP_FW_IF_IPID && f->fw_ipid != ntohs(ip->ip_id)) + continue; + if (f->fw_ipflg & IP_FW_IF_IPTOS && !iptos_match(ip, f)) + continue; + if (f->fw_ipflg & IP_FW_IF_IPTTL && f->fw_ipttl != ip->ip_ttl) + continue; + if (f->fw_ipflg & IP_FW_IF_IPVER && f->fw_ipver != ip->ip_v) continue; /* Check protocol; if wildcard, and no [ug]id, match */ @@ -1387,17 +1422,22 @@ * we consider the rule a non-match. */ if (IP_FW_HAVEPORTS(f) != 0 || - f->fw_tcpopt != f->fw_tcpnopt || - f->fw_tcpf != f->fw_tcpnf) + f->fw_ipflg & IP_FW_IF_TCPMSK) continue; break; } tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl); - if (f->fw_tcpopt != f->fw_tcpnopt && !tcpopts_match(tcp, f)) + if (f->fw_ipflg & IP_FW_IF_TCPOPT && !tcpopts_match(tcp, f)) + continue; + if (f->fw_ipflg & IP_FW_IF_TCPSEQ && tcp->th_seq != f->fw_tcpseq) + continue; + if (f->fw_ipflg & IP_FW_IF_TCPACK && tcp->th_ack != f->fw_tcpack) + continue; + if (f->fw_ipflg & IP_FW_IF_TCPWIN && tcp->th_win != f->fw_tcpwin) continue; - if (((f->fw_tcpf != f->fw_tcpnf) || + if (((f->fw_ipflg & IP_FW_IF_TCPFLG) || (f->fw_ipflg & IP_FW_IF_TCPEST)) && !tcpflg_match(tcp, f)) continue; ==== //depot/yahoo/ybsd_4/src/sys/netinet/ip_fw.h#4 (text+ko) ==== @@ -96,25 +96,25 @@ } fw_uar; u_int fw_ipflg; /* IP flags word */ - u_short fw_iplen; /* IP length XXX */ - u_short fw_ipid; /* Identification XXX */ + u_short fw_iplen; /* IP length */ + u_short fw_ipid; /* Identification */ u_char fw_ipopt; /* IP options set */ u_char fw_ipnopt; /* IP options unset */ - u_char fw_iptos; /* IP type of service set XXX */ - u_char fw_ipntos; /* IP type of service unset XXX */ + u_char fw_iptos; /* IP type of service set */ + u_char fw_ipntos; /* IP type of service unset */ - u_char fw_ipttl; /* IP time to live XXX */ - u_char fw_ipver:4; /* IP version XXX */ + u_char fw_ipttl; /* IP time to live */ + u_char fw_ipver:4; /* IP version */ u_char fw_tcpopt; /* TCP options set */ u_char fw_tcpnopt; /* TCP options unset */ u_char fw_tcpf; /* TCP flags set/unset */ u_char fw_tcpnf; /* TCP flags set/unset */ - u_short fw_tcpwin; /* TCP window size XXX */ + u_short fw_tcpwin; /* TCP window size */ - u_int32_t fw_tcpseq; /* TCP sequence XXX */ - u_int32_t fw_tcpack; /* TCP acknowledgement XXX */ + u_int32_t fw_tcpseq; /* TCP sequence */ + u_int32_t fw_tcpack; /* TCP acknowledgement */ long timestamp; /* timestamp (tv_sec) of last match */ union ip_fw_if fw_in_if; /* Incoming interfaces */