From owner-freebsd-ipfw Tue Sep 26 20: 9:44 2000 Delivered-To: freebsd-ipfw@freebsd.org Received: from jade.chc-chimes.com (jade.chc-chimes.com [216.28.46.6]) by hub.freebsd.org (Postfix) with ESMTP id 495DF37B424; Tue, 26 Sep 2000 20:08:47 -0700 (PDT) Received: by jade.chc-chimes.com (Postfix, from userid 1001) id 9B13D1C41; Tue, 26 Sep 2000 23:08:46 -0400 (EDT) Date: Tue, 26 Sep 2000 23:08:46 -0400 From: Bill Fumerola To: freebsd-ipfw@freebsd.org Cc: luigi@freebsd.org Subject: REVIEW REQUEST - new ipfw options Message-ID: <20000926230846.H34501@jade.chc-chimes.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Mailer: Mutt 1.0i X-Operating-System: FreeBSD 3.3-STABLE i386 Sender: owner-freebsd-ipfw@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG [ sent to net@ and ipfw@, discussion in ipfw@ ] Please review the following patch for ipfw, adding more fields to provide the firewall administrator with a higher level of granularity. This patch also introduces a new flags member to struct ip_fw as I ran out of space in that, and I feel that splitting up things that change the operation of ipfw internally and things that define where we poke around belong in different locations. Its possible that more things now belong in the new flag member. Everything should be pretty straightforward. One thing notably absent is the diff to ipfw.8 in this patch. That's not due to incompetence with cvs, that's due to incompetence with mdoc. It should be very easy for someone with any mdoc clue to add these options in ipfw.8, and I'd ask that someone do that. Thanks, -- Bill Fumerola - Network Architect, BOFH / Chimes, Inc. billf@chimesnet.com / billf@FreeBSD.org ----- Forwarded message from Bill Fumerola ----- Index: ipfw.c =================================================================== RCS file: /home/ncvs/src/sbin/ipfw/ipfw.c,v retrieving revision 1.89 diff -u -r1.89 ipfw.c --- ipfw.c 2000/08/16 07:36:29 1.89 +++ ipfw.c 2000/09/27 02:38:43 @@ -412,7 +412,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;} @@ -428,12 +428,39 @@ if (chain->fw_ipnopt & IP_FW_IPOPT_TS) 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 0x%04x", 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_tcpf & IP_FW_TCPF_ESTAB) 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_TCPOPT) { int _flg_printed = 0; #define PRINTFLG(x) {if (_flg_printed) printf(",");\ printf(x); _flg_printed = 1;} @@ -452,7 +479,7 @@ if (chain->fw_tcpf & IP_FW_TCPF_URG) PRINTFLG("urg"); 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;} @@ -470,6 +497,13 @@ if (chain->fw_tcpnopt & IP_FW_TCPOPT_CC) 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; @@ -837,7 +871,15 @@ " {established|setup}\n" " tcpflags [!]{syn|fin|rst|ack|psh|urg},...\n" " ipoptions [!]{ssrr|lsrr|rr|ts},...\n" +" iplen {length}\n" +" ipid {identification number (in hex)}\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" " pipeconfig:\n" " {bw|bandwidth} {bit/s|Kbit/s|Mbit/s|Bytes/s|KBytes/s|MBytes/s}\n" @@ -1148,6 +1190,40 @@ } 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; +#if 0 /* conflicting! */ + if (!strncmp(p,"ecntransport",strlen(p))) + *d |= IPTOS_ECT; +#endif + p = q; + } +} + +static void fill_icmptypes(types, vp, fw_flg) u_long *types; char **vp; @@ -1878,22 +1954,78 @@ rule.fw_flg |= IP_FW_F_FRAG; av++; ac--; continue; } - if (!strncmp(*av,"ipoptions",strlen(*av))) { + if (!strncmp(*av,"ipoptions",strlen(*av)) || + !strncmp(*av,"ipopts",strlen(*av))) { av++; ac--; if (!ac) show_usage("missing argument" " for ``ipoptions''"); + rule.fw_ipflg |= IP_FW_IF_IPOPT; fill_ipopt(&rule.fw_ipopt, &rule.fw_ipnopt, av); av++; ac--; continue; } + if (!strncmp(*av,"iplen",strlen(*av))) { + av++; ac--; + if (!ac) + show_usage("missing arguement" + " for ``iplen''"); + rule.fw_ipflg |= IP_FW_IF_IPLEN; + rule.fw_iplen = (u_short)strtoul(*av, NULL, 0); + av++; ac--; continue; + } + if (!strncmp(*av,"ipid",strlen(*av))) { + av++; ac--; + if (!ac) + show_usage("missing arguement" + " for ``ipid''"); + rule.fw_ipflg |= IP_FW_IF_IPID; + if (strlen(*av) != 6 || (*av)[0] != '0' || (*av)[1] != 'x' || + isxdigit((*av)[2]) == 0 || + isxdigit((*av)[3]) == 0 || + isxdigit((*av)[4]) == 0 || + isxdigit((*av)[5]) == 0) + show_usage("arguement to ipid must be in hex"); + rule.fw_ipid = (u_short)strtoul(*av, NULL, 0); + av++; ac--; continue; + } + if (!strncmp(*av,"iptos",strlen(*av))) { + av++; ac--; + if (!ac) + show_usage("missing arguement" + " for ``iptos''"); + rule.fw_ipflg |= IP_FW_IF_IPTOS; + fill_iptos(&rule.fw_iptos, &rule.fw_ipntos, av); + av++; ac--; continue; + } + if (!strncmp(*av,"ipttl",strlen(*av))) { + av++; ac--; + if (!ac) + show_usage("missing arguement" + " for ``ipttl''"); + rule.fw_ipflg |= IP_FW_IF_IPTTL; + rule.fw_ipttl = (u_short)strtoul(*av, NULL, 0); + av++; ac--; continue; + } + if (!strncmp(*av,"ipversion",strlen(*av)) || + !strncmp(*av,"ipver",strlen(*av))) { + av++; ac--; + if (!ac) + show_usage("missing arguement" + " for ``ipversion''"); + rule.fw_ipflg |= IP_FW_IF_IPVER; + rule.fw_ipver = (u_short)strtoul(*av, NULL, 0); + av++; ac--; continue; + } if (rule.fw_prot == IPPROTO_TCP) { if (!strncmp(*av,"established",strlen(*av))) { rule.fw_tcpf |= IP_FW_TCPF_ESTAB; + rule.fw_ipflg |= IP_FW_IF_TCPFLG; av++; ac--; continue; } 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--; continue; } if (!strncmp(*av,"tcpflags",strlen(*av)) || !strncmp(*av,"tcpflgs",strlen(*av))) { @@ -1901,6 +2033,7 @@ if (!ac) show_usage("missing argument" " for ``tcpflags''"); + rule.fw_ipflg |= IP_FW_IF_TCPFLG; fill_tcpflag(&rule.fw_tcpf, &rule.fw_tcpnf, av); av++; ac--; continue; } @@ -1909,9 +2042,37 @@ if (!ac) show_usage("missing argument" " for ``tcpoptions''"); + rule.fw_ipflg |= IP_FW_IF_TCPOPT; fill_tcpopts(&rule.fw_tcpopt, &rule.fw_tcpnopt, av); av++; ac--; continue; } + if (!strncmp(*av,"tcpseq",strlen(*av))) { + av++; ac--; + if (!ac) + show_usage("missing arguement" + " for ``tcpseq''"); + rule.fw_ipflg |= IP_FW_IF_TCPSEQ; + rule.fw_tcpseq = htonl((u_int32_t)strtoul(*av, NULL, 0)); + av++; ac--; continue; + } + if (!strncmp(*av,"tcpack",strlen(*av))) { + av++; ac--; + if (!ac) + show_usage("missing arguement" + " for ``tcpack''"); + rule.fw_ipflg |= IP_FW_IF_TCPACK; + rule.fw_tcpack = htonl((u_int32_t)strtoul(*av, NULL, 0)); + av++; ac--; continue; + } + if (!strncmp(*av,"tcpwin",strlen(*av))) { + av++; ac--; + if (!ac) + show_usage("missing arguement" + " for ``tcpwin''"); + rule.fw_ipflg |= IP_FW_IF_TCPWIN; + rule.fw_tcpwin = htons((u_short)strtoul(*av, NULL, 0)); + av++; ac--; continue; + } } if (rule.fw_prot == IPPROTO_ICMP) { if (!strncmp(*av,"icmptypes",strlen(*av))) { Index: /sys/netinet/ip_fw.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_fw.c,v retrieving revision 1.140 diff -u -r1.140 ip_fw.c --- /sys/netinet/ip_fw.c 2000/09/12 02:38:05 1.140 +++ /sys/netinet/ip_fw.c 2000/09/26 07:14:14 @@ -193,6 +193,7 @@ iface_match __P((struct ifnet *ifp, union ip_fw_if *ifu, int byname)); static int ipopts_match __P((struct ip *ip, struct ip_fw *f)); +static int iptos_match __P((struct ip *ip, struct ip_fw *f)); static __inline int port_match __P((u_short *portptr, int nports, u_short port, int range_flag, int mask)); @@ -354,6 +355,33 @@ } 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; @@ -1108,9 +1136,19 @@ 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 != 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 */ if (f->fw_prot == IPPROTO_IP) { @@ -1211,9 +1249,15 @@ } 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_TCPFLG && !tcpflg_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_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f)) + if (f->fw_ipflg & IP_FW_IF_TCPWIN && tcp->th_win != f->fw_tcpwin) continue; goto check_ports; } Index: /sys/netinet/ip_fw.h =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_fw.h,v retrieving revision 1.52 diff -u -r1.52 ip_fw.h --- /sys/netinet/ip_fw.h 2000/08/22 00:32:52 1.52 +++ /sys/netinet/ip_fw.h 2000/09/26 07:14:42 @@ -54,7 +54,7 @@ struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ u_short fw_number; /* Rule number */ - u_int fw_flg; /* Flags word */ + u_int fw_flg; /* Operational Flags word */ #define IP_FW_MAX_PORTS 10 /* A reasonable maximum */ union { u_short fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */ @@ -62,9 +62,16 @@ #define IP_FW_ICMPTYPES_DIM (IP_FW_ICMPTYPES_MAX / (sizeof(unsigned) * 8)) unsigned fw_icmptypes[IP_FW_ICMPTYPES_DIM]; /* ICMP types bitmap */ } fw_uar; + u_int fw_ipflg; /* IP flags word */ u_char fw_ipopt,fw_ipnopt; /* IP options set/unset */ + u_short fw_iplen, fw_ipid; /* IP length, identification */ + u_char fw_iptos, fw_ipntos; /* IP type of service set/unset */ + u_char fw_ipttl; /* IP time to live */ + u_int fw_ipver:4; /* IP version */ u_char fw_tcpopt,fw_tcpnopt; /* TCP options set/unset */ u_char fw_tcpf,fw_tcpnf; /* TCP flags set/unset */ + u_int32_t fw_tcpseq, fw_tcpack; /* TCP sequence and acknowledgement */ + u_short fw_tcpwin; /* TCP window size */ long timestamp; /* timestamp (tv_sec) of last match */ union ip_fw_if fw_in_if, fw_out_if; /* Incoming and outgoing interfaces */ union { @@ -206,6 +213,26 @@ #define IP_FW_F_CHECK_S 0x10000000 /* check state */ #define IP_FW_F_MASK 0x1FFFFFFF /* All possible flag bits mask */ + +/* + * Flags for the 'fw_ipflg' field, for comparing values of ip and its protocols. + */ +#define IP_FW_IF_TCPOPT 0x00000001 /* tcp options */ +#define IP_FW_IF_TCPFLG 0x00000002 /* tcp flags */ +#define IP_FW_IF_TCPSEQ 0x00000004 /* tcp sequence number */ +#define IP_FW_IF_TCPACK 0x00000008 /* tcp acknowledgement number */ +#define IP_FW_IF_TCPWIN 0x00000010 /* tcp window size */ +#define IP_FW_IF_TCPMSK 0x0000001f /* mask of all tcp values */ + +#define IP_FW_IF_IPOPT 0x00000100 /* ip options */ +#define IP_FW_IF_IPLEN 0x00000200 /* ip length */ +#define IP_FW_IF_IPID 0x00000400 /* ip identification */ +#define IP_FW_IF_IPTOS 0x00000800 /* ip type of service */ +#define IP_FW_IF_IPTTL 0x00001000 /* ip time to live */ +#define IP_FW_IF_IPVER 0x00002000 /* ip version */ +#define IP_FW_IF_IPMSK 0x00003f00 /* mask of all ip values */ + +#define IP_FW_IF_MSK 0x0000ffff /* All possible bits mask */ /* * For backwards compatibility with rules specifying "via iface" but ----- End forwarded message ----- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ipfw" in the body of the message