From f2254cf7022e4e6909272699c8e1f774b7e4e3f1 Mon Sep 17 00:00:00 2001 From: mlaier Date: Fri, 3 Jun 2005 01:10:28 +0000 Subject: Add support for IPv4 only rules to IPFW2 now that it supports IPv6 as well. This is the last requirement before we can retire ip6fw. Reviewed by: dwhite, brooks(earlier version) Submitted by: dwhite (manpage) Silence from: -ipfw --- sbin/ipfw/ipfw.8 | 28 +++++++++++---------- sbin/ipfw/ipfw2.c | 69 ++++++++++++++++++++++++++++++++++++++++++---------- sys/netinet/ip_fw.h | 2 ++ sys/netinet/ip_fw2.c | 7 ++++++ 4 files changed, 80 insertions(+), 26 deletions(-) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index b0ad0ac..55f8b77 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -623,7 +623,7 @@ The search terminates. .It Cm fwd | forward Ar ipaddr Ns Op , Ns Ar port Change the next-hop on matching packets to .Ar ipaddr , -which can be an IP address in dotted quad format or a host name. +which can be an IP address or a host name. The search terminates if this rule matches. .Pp If @@ -805,14 +805,16 @@ Rule fields have the following meaning: .It Ar protocol : Oo Cm not Oc Ar protocol-name | protocol-number An IP protocol specified by number or name (for a complete list see -.Pa /etc/protocols ) . -The -.Cm ip , -.Cm ip6 , -.Cm ipv6 , -or -.Cm all -keywords mean any protocol will match. +.Pa /etc/protocols ) , +or one of the following keywords: +.Bl -tag -width indent +.It Cm ip4 | ipv4 +Matches IPv4 packets. +.It Cm ip6 | ipv6 +Matches IPv6 packets. +.It Cm ip | all +Matches any packet. +.El .Pp The .Cm { Ar protocol Cm or ... } @@ -861,7 +863,7 @@ Hostnames are resolved at the time the rule is added to the firewall list. .It Ar addr Ns / Ns Ar masklen Matches all addresses with base .Ar addr -(specified as a dotted quad or a hostname) +(specified as an IP address or a hostname) and mask width of .Cm masklen bits. @@ -870,7 +872,7 @@ all IP numbers from 1.2.3.0 to 1.2.3.127 . .It Ar addr Ns : Ns Ar mask Matches all addresses with base .Ar addr -(specified as a dotted quad or a hostname) +(specified as an IP address or a hostname) and the mask of .Ar mask , specified as a dotted quad. @@ -887,7 +889,7 @@ error-prone. .It Ar list : Bro Ar num | num-num Brc Ns Op Ns , Ns Ar list Matches all addresses with base address .Ar addr -(specified as a dotted quad or a hostname) +(specified as an IP address or a hostname) and whose last byte is in the list between braces { } . Note that there must be no spaces between braces and numbers (spaces after commas are allowed). @@ -1444,7 +1446,7 @@ Each entry is represented by an .Ar addr Ns Op / Ns Ar masklen and will match all addresses with base .Ar addr -(specified as a dotted quad or a hostname) +(specified as an IP address or a hostname) and mask width of .Ar masklen bits. diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 4e3ce34..c645e0b 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -275,6 +275,8 @@ enum tokens { TOK_EXT6HDR, TOK_DSTIP6, TOK_SRCIP6, + + TOK_IPV4, }; struct _s_x dummynet_params[] = { @@ -395,6 +397,8 @@ struct _s_x rule_options[] = { { "flow-id", TOK_FLOWID}, { "ipv6", TOK_IPV6}, { "ip6", TOK_IPV6}, + { "ipv4", TOK_IPV4}, + { "ip4", TOK_IPV4}, { "dst-ipv6", TOK_DSTIP6}, { "dst-ip6", TOK_DSTIP6}, { "src-ipv6", TOK_SRCIP6}, @@ -1260,6 +1264,7 @@ print_ext6hdr( ipfw_insn *cmd ) #define HAVE_DSTIP 0x0004 #define HAVE_MAC 0x0008 #define HAVE_MACTYPE 0x0010 +#define HAVE_PROTO4 0x0040 #define HAVE_PROTO6 0x0080 #define HAVE_OPTIONS 0x8000 @@ -1283,11 +1288,14 @@ show_prerequisites(int *flags, int want, int cmd) return; } if ( !(*flags & HAVE_OPTIONS)) { - /* XXX BED: !(*flags & HAVE_PROTO) in patch */ - if ( !(*flags & HAVE_PROTO6) && (want & HAVE_PROTO6)) - printf(" ipv6"); if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) - printf(" ip"); + if ( (*flags & HAVE_PROTO4)) + printf(" ip4"); + else if ( (*flags & HAVE_PROTO6)) + printf(" ip6"); + else + printf(" ip"); + if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) printf(" from any"); if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) @@ -1468,9 +1476,23 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) /* * then print the body. */ + for (l = rule->act_ofs, cmd = rule->cmd ; + l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { + if ((cmd->len & F_OR) || (cmd->len & F_NOT)) + continue; + if (cmd->opcode == O_IP4) { + flags |= HAVE_PROTO4; + break; + } else if (cmd->opcode == O_IP6) { + flags |= HAVE_PROTO6; + break; + } + } if (rule->_pad & 1) { /* empty rules before options */ - if (!do_compact) - printf(" ip from any to any"); + if (!do_compact) { + show_prerequisites(&flags, HAVE_PROTO, 0); + printf(" from any to any"); + } flags |= HAVE_IP | HAVE_OPTIONS; } @@ -1600,6 +1622,10 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) printf(" not"); proto = cmd->arg1; pe = getprotobynumber(cmd->arg1); + if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) && + !(flags & HAVE_PROTO)) + show_prerequisites(&flags, + HAVE_IP | HAVE_OPTIONS, 0); if (flags & HAVE_OPTIONS) printf(" proto"); if (pe) @@ -1611,6 +1637,12 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) break; default: /*options ... */ + if (!(cmd->len & (F_OR|F_NOT))) + if (((cmd->opcode == O_IP6) && + (flags & HAVE_PROTO6)) || + ((cmd->opcode == O_IP4) && + (flags & HAVE_PROTO4))) + break; show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); if ((cmd->len & F_OR) && !or_block) printf(" {"); @@ -1810,10 +1842,14 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) } break; - case O_IP6: + case O_IP6: printf(" ipv6"); break; + case O_IP4: + printf(" ipv4"); + break; + case O_ICMP6TYPE: print_icmp6types((ipfw_insn_u32 *)cmd); break; @@ -3506,13 +3542,18 @@ add_proto(ipfw_insn *cmd, char *av, u_char *proto) *proto = IPPROTO_IP; if (_substrcmp(av, "all") == 0) - ; /* same as "ip" */ - else if ((*proto = atoi(av)) > 0) + ; /* do not set O_IP4 nor O_IP6 */ + else if (strcmp(av, "ipv4") == 0 || strcmp(av, "ip4") == 0) + /* explicit "just IPv4" rule */ + fill_cmd(cmd, O_IP4, 0, 0); + else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6") == 0) { + /* explicit "just IPv6" rule */ + *proto = IPPROTO_IPV6; + fill_cmd(cmd, O_IP6, 0, 0); + } else if ((*proto = atoi(av)) > 0) ; /* all done! */ else if ((pe = getprotobyname(av)) != NULL) *proto = pe->p_proto; - else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6") == 0) - *proto = IPPROTO_IPV6; else return NULL; if (*proto != IPPROTO_IP && *proto != IPPROTO_IPV6) @@ -4347,8 +4388,6 @@ read_options: case TOK_PROTO: NEED1("missing protocol"); if (add_proto(cmd, *av, &proto)) { - if (proto == IPPROTO_IPV6) - fill_cmd(cmd, O_IP6, 0, 0); ac--; av++; } else errx(EX_DATAERR, "invalid protocol ``%s''", @@ -4435,6 +4474,10 @@ read_options: fill_cmd(cmd, O_IP6, 0, 0); break; + case TOK_IPV4: + fill_cmd(cmd, O_IP4, 0, 0); + break; + case TOK_EXT6HDR: fill_ext6hdr( cmd, *av ); ac--; av++; diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 01d91f1..5c5fd6e 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -153,6 +153,8 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_NETGRAPH, /* send to ng_ipfw */ O_NGTEE, /* copy to ng_ipfw */ + O_IP4, + O_LAST_OPCODE /* not an opcode! */ }; diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 0c1d2a2..8211977 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -1961,6 +1961,7 @@ ipfw_chk(struct ip_fw_args *args) int is_ipv6 = 0; u_int16_t ext_hd = 0; /* bits vector for extension header filtering */ /* end of ipv6 variables */ + int is_ipv4 = 0; if (m->m_flags & M_SKIP_FIREWALL) return (IP_FW_PASS); /* accept */ @@ -2076,6 +2077,7 @@ do { \ } else if (pktlen >= sizeof(struct ip) && (args->eh == NULL || ntohs(args->eh->ether_type) == ETHERTYPE_IP) && mtod(m, struct ip *)->ip_v == 4) { + is_ipv4 = 1; ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; args->f_id.addr_type = 4; @@ -2677,6 +2679,10 @@ check_body: break; #endif + case O_IP4: + match = is_ipv4; + break; + /* * The second set of opcodes represents 'actions', * i.e. the terminal part of a rule once the packet @@ -3322,6 +3328,7 @@ check_ipfw_struct(struct ip_fw *rule, int size) case O_IP6_DST_ME: case O_EXT_HDR: case O_IP6: + case O_IP4: if (cmdlen != F_INSN_SIZE(ipfw_insn)) goto bad_size; break; -- cgit v1.1