diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 5cf462ea00a7..ac0865f7f87d 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -116,7 +116,6 @@ static struct _s_x f_ipopts[] = { { NULL, 0 } }; -#if 0 /* XXX not used yet */ static struct _s_x f_iptos[] = { { "lowdelay", IPTOS_LOWDELAY}, { "throughput", IPTOS_THROUGHPUT}, @@ -127,7 +126,6 @@ static struct _s_x f_iptos[] = { { "ip tos option", 0}, { NULL, 0 } }; -#endif static struct _s_x limit_masks[] = { {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, @@ -254,6 +252,7 @@ struct _s_x dummynet_params[] = { { "bw", TOK_BW }, { "bandwidth", TOK_BW }, { "delay", TOK_DELAY }, + { "pipe", TOK_PIPE }, { "queue", TOK_QUEUE }, { "dummynet-params", TOK_NULL }, { NULL, 0 } @@ -276,6 +275,7 @@ struct _s_x rule_actions[] = { { "drop", TOK_DENY }, { "reject", TOK_REJECT }, { "reset", TOK_RESET }, + { "unreach", TOK_UNREACH }, { "check-state", TOK_CHECKSTATE }, { NULL, TOK_NULL }, { NULL, 0 } @@ -496,7 +496,6 @@ fill_newports(ipfw_insn_u16 *cmd, char *av, int proto) return i; } -#if 0 /* XXX not used yet */ static struct _s_x icmpcodes[] = { { "net", ICMP_UNREACH_NET }, { "host", ICMP_UNREACH_HOST }, @@ -533,16 +532,15 @@ fill_reject_code(u_short *codep, char *str) } static void -print_reject_code(u_int32_t code) +print_reject_code(u_int16_t code) { char *s = match_value(icmpcodes, code); if (s != NULL) - printf("%s", s); + printf("unreach %s", s); else - printf("%u", code); + printf("unreach %u", code); } -#endif /* XXX not used yet */ /* * Returns the number of bits set (from left) in a contiguous bitmask, @@ -678,6 +676,44 @@ print_mac(u_char *addr, u_char *mask) } } +static void +fill_icmptypes(ipfw_insn_u32 *cmd, char *av) +{ + u_int8_t type; + + cmd->d[0] = 0; + while (*av) { + if (*av == ',') + av++; + + type = strtoul(av, &av, 0); + + if (*av != ',' && *av != '\0') + errx(EX_DATAERR, "invalid ICMP type"); + + if (type > 31) + errx(EX_DATAERR, "ICMP type out of range"); + + cmd->d[0] |= 1 << type; + } + cmd->o.opcode = O_ICMPTYPE; + cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); +} + +static void +print_icmptypes(ipfw_insn_u32 *cmd) +{ + int i; + char sep= ' '; + + printf(" icmptypes"); + for (i = 0; i < 32; i++) { + if ( (cmd->d[0] & (1 << (i))) == 0) + continue; + printf("%c%d", sep, i); + sep = ','; + } +} /* * show_ipfw() prints the body of an ipfw rule. @@ -763,6 +799,15 @@ show_ipfw(struct ip_fw *rule) printf("deny"); break; + case O_REJECT: + if (cmd->arg1 == ICMP_REJECT_RST) + printf("reset"); + else if (cmd->arg1 == ICMP_UNREACH_HOST) + printf("reject"); + else + print_reject_code(cmd->arg1); + break; + case O_SKIPTO: printf("skipto %u", cmd->arg1); break; @@ -813,7 +858,8 @@ show_ipfw(struct ip_fw *rule) */ for (l = rule->act_ofs, cmd = rule->cmd ; l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { - ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; /* useful alias */ + /* useful alias */ + ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; switch(cmd->opcode) { case O_PROBE_STATE: @@ -918,11 +964,13 @@ show_ipfw(struct ip_fw *rule) else if (cmd->opcode == O_VIA) s = "via"; if (cmdif->name[0] == '\0') - printf(" %s %s", s, inet_ntoa(cmdif->p.ip)); + printf(" %s %s", s, + inet_ntoa(cmdif->p.ip)); else if (cmdif->p.unit == -1) printf(" %s %s*", s, cmdif->name); else - printf(" %s %s%d", s, cmdif->name, cmdif->p.unit); + printf(" %s %s%d", s, cmdif->name, + cmdif->p.unit); } break; @@ -938,6 +986,10 @@ show_ipfw(struct ip_fw *rule) printf(" ipver %u", cmd->arg1 ); break; + case O_IPPRECEDENCE: + printf(" ipprecedence %u", (cmd->arg1) >> 5 ); + break; + case O_IPLEN: printf(" iplen %u", cmd->arg1 ); break; @@ -946,6 +998,14 @@ show_ipfw(struct ip_fw *rule) print_flags("ipoptions", cmd, f_ipopts); break; + case O_IPTOS: + print_flags("iptos", cmd, f_iptos); + break; + + case O_ICMPTYPE: + print_icmptypes((ipfw_insn_u32 *)cmd); + break; + case O_ESTAB: printf(" established"); break; @@ -1029,45 +1089,6 @@ show_ipfw(struct ip_fw *rule) } show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP|HAVE_DSTIP); -#if 0 /* old stuff */ - switch (chain->fw_flg & IP_FW_F_COMMAND) { - case IP_FW_F_REJECT: - if (chain->fw_reject_code == IP_FW_REJECT_RST) - printf("reset"); - else { - printf("unreach "); - print_reject_code(chain->fw_reject_code); - } - break; - } - -do_options: - if (chain->fw_ipflg & IP_FW_IF_IPOPT) - print_flags("ipopt", chain->fw_ipopt, chain->fw_ipnopt, - f_ipopts); - - if (chain->fw_ipflg & IP_FW_IF_IPPRE) - printf(" ipprecedence %u", (chain->fw_iptos & 0xe0) >> 5); - - if (chain->fw_ipflg & IP_FW_IF_IPTOS) - print_flags("iptos", chain->fw_iptos, chain->fw_ipntos, - f_iptos); - - if (chain->fw_flg & IP_FW_F_ICMPBIT) { - int i, first = 1; - unsigned j; - - printf(" icmptype"); - - for (i = 0; i < IP_FW_ICMPTYPES_DIM; ++i) - for (j = 0; j < sizeof(unsigned) * 8; ++j) - if (chain->fw_uar.fw_icmptypes[i] & (1 << j)) { - printf("%c%d", first ? ' ' : ',', - i * sizeof(unsigned) * 8 + j); - first = 0; - } - } -#endif /* XXX old stuff */ printf("\n"); } @@ -1620,31 +1641,6 @@ fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); } -#if 0 /* XXX todo */ -static void -fill_icmptypes(unsigned *types, char **vp, u_int *fw_flg) -{ - unsigned long icmptype; - char *c = *vp; - - while (*c) { - if (*c == ',') - ++c; - - icmptype = strtoul(c, &c, 0); - - if (*c != ',' && *c != '\0') - errx(EX_DATAERR, "invalid ICMP type"); - - if (icmptype >= IP_FW_ICMPTYPES_DIM * sizeof(unsigned) * 8) - errx(EX_DATAERR, "ICMP type out of range"); - - types[icmptype / (sizeof(unsigned) * 8)] |= - 1 << (icmptype % (sizeof(unsigned) * 8)); - *fw_flg |= IP_FW_F_ICMPBIT; - } -} -#endif /* XXX todo */ static void delete(int ac, char *av[]) @@ -1745,7 +1741,7 @@ config_pipe(int ac, char **av) else pipe.fs.fs_nr = i; } - while (ac > 1) { + while (ac > 0) { double d; int tok = match_token(dummynet_params, *av); ac--; av++; @@ -2231,6 +2227,24 @@ add(int ac, char *av[]) case TOK_DENY: action->opcode = O_DENY; + action->arg1 = 0; + break; + + case TOK_REJECT: + action->opcode = O_REJECT; + action->arg1 = ICMP_UNREACH_HOST; + break; + + case TOK_RESET: + action->opcode = O_REJECT; + action->arg1 = ICMP_REJECT_RST; + break; + + case TOK_UNREACH: + action->opcode = O_REJECT; + NEED1("missing reject code"); + fill_reject_code(&action->arg1, *av); + ac--; av++; break; case TOK_COUNT: @@ -2305,19 +2319,6 @@ add(int ac, char *av[]) } action = next_cmd(action); -#if 0 - } else if (!strncmp(*av, "reject", strlen(*av))) { - rule.fw_flg |= IP_FW_F_REJECT; av++; ac--; - rule.fw_reject_code = ICMP_UNREACH_HOST; - } else if (!strncmp(*av, "reset", strlen(*av))) { - rule.fw_flg |= IP_FW_F_REJECT; av++; ac--; - rule.fw_reject_code = ICMP_REJECT_RST; /* check TCP later */ - } else if (!strncmp(*av, "unreach", strlen(*av))) { - rule.fw_flg |= IP_FW_F_REJECT; av++; ac--; - fill_reject_code(&rule.fw_reject_code, *av); av++; ac--; - } -#endif /* XXX other actions */ - /* * [log [logamount N]] -- log, optional * @@ -2568,6 +2569,12 @@ add(int ac, char *av[]) cmd->opcode = O_VIA; break; + case TOK_ICMPTYPES: + NEED1("icmptypes requires list of types"); + fill_icmptypes((ipfw_insn_u32 *)cmd, *av); + av++; ac--; + break; + case TOK_IPTTL: NEED1("ipttl requires TTL"); fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); @@ -2592,12 +2599,25 @@ add(int ac, char *av[]) ac--; av++; break; + case TOK_IPPRECEDENCE: + NEED1("ipprecedence requires value"); + fill_cmd(cmd, O_IPPRECEDENCE, 0, + (strtoul(*av, NULL, 0) & 7) << 5); + ac--; av++; + break; + case TOK_IPOPTS: NEED1("missing argument for ipoptions"); fill_flags(cmd, O_IPOPTS, f_ipopts, *av); ac--; av++; break; + case TOK_IPTOS: + NEED1("missing argument for iptos"); + fill_flags(cmd, O_IPOPTS, f_iptos, *av); + ac--; av++; + break; + case TOK_UID: NEED1("uid requires argument"); { @@ -2714,43 +2734,7 @@ add(int ac, char *av[]) cmd = next_cmd(cmd); } } -#if 0 /* XXX todo */ -do_options: - while (ac) { - } else if (!strncmp(*av, "ipprecedence", strlen(*av))) { - u_long ippre; - char *c; - av++; ac--; - NEED1("missing argument for ``ipprecedence''"); - ippre = strtoul(*av, &c, 0); - if (*c != '\0') - errx(EX_DATAERR, "argument to ipprecedence" - " must be numeric"); - if (ippre > 7) - errx(EX_DATAERR, "argument to ipprecedence" - " out of range"); - rule.fw_ipflg |= IP_FW_IF_IPPRE; - rule.fw_iptos |= (u_short)(ippre << 5); - av++; ac--; - } else if (!strncmp(*av, "iptos", strlen(*av))) { - av++; ac--; - NEED1("missing argument for ``iptos''"); - rule.fw_ipflg |= IP_FW_IF_IPTOS; - fill_flags(&rule.fw_iptos, &rule.fw_ipntos, - f_iptos, av); - av++; ac--; - } else if (rule.fw_prot == IPPROTO_ICMP) { - if (!strncmp(*av, "icmptypes", strlen(*av))) { - av++; ac--; - NEED1("missing argument for ``icmptypes''"); - fill_icmptypes(rule.fw_uar.fw_icmptypes, - av, &rule.fw_flg); - av++; ac--; - } - } - } -#endif /* XXX todo */ done: /* * Now copy stuff into the rule. diff --git a/sys/netinet/ip_fw.h b/sys/netinet/ip_fw.h index 508cc767b43b..f26c6ea7d0c2 100644 --- a/sys/netinet/ip_fw.h +++ b/sys/netinet/ip_fw.h @@ -76,6 +76,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */ O_IPPRE, /* arg1 = id */ O_IPTOS, /* arg1 = id */ + O_IPPRECEDENCE, /* arg1 = precedence << 5 */ O_IPTTL, /* arg1 = TTL */ O_IPVER, /* arg1 = version */ diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 6998cbdc357f..e27a171990e3 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -73,6 +73,8 @@ #include /* XXX for ETHERTYPE_IP */ +#include /* XXX for in_cksum */ + static int fw_verbose = 0; static int verbose_limit = 0; @@ -345,16 +347,13 @@ tcpopts_match(struct ip *ip, ipfw_insn *cmd) return (flags_match(cmd, bits)); } -/* - * XXX done - */ static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd) { if (ifp == NULL) /* no iface with this packet, match fails */ return 0; /* Check by name or by IP address */ - if (cmd->name[0] != '\0') { /* XXX by name */ + if (cmd->name[0] != '\0') { /* match by name */ /* Check unit number (-1 is wildcard) */ if (cmd->p.unit != -1 && cmd->p.unit != ifp->if_unit) return(0); @@ -419,10 +418,17 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh, case O_DENY: action = "Deny"; break; + case O_REJECT: - action = (cmd->arg1==ICMP_REJECT_RST) ? - "Reset" : "Unreach"; + if (cmd->arg1==ICMP_REJECT_RST) + action = "Reset"; + else if (cmd->arg1==ICMP_UNREACH_HOST) + action = "Reject"; + else + snprintf(SNPARGS(action2, 0), "Unreach %d", + cmd->arg1); break; + case O_ACCEPT: action = "Accept"; break; @@ -568,7 +574,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh, /* * IMPORTANT: the hash function for dynamic rules must be commutative - * in * source and destination (ip,port), because rules are bidirectional + * in source and destination (ip,port), because rules are bidirectional * and we want to find both in the same bucket. */ static __inline int @@ -979,23 +985,94 @@ install_state(struct ip_fw *rule, ipfw_insn_limit *cmd, return 0; } +#if 0 +static void +send_pkt(struct ip_fw_args *args, u_int32_t seq, u_int32_t ack, int flags) +{ + struct mbuf *m; + struct ip *ip = mtod(args->m, struct ip *); + struct tcphdr *tcp; + struct route sro; /* fake route */ + + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (m == 0) + return; + m->m_pkthdr.rcvif = (struct ifnet *)0; + m->m_pkthdr.len = m->m_len = sizeof(struct ip) + sizeof(struct tcphdr); + m->m_data += max_linkhdr; + + ip->ip_v = 4; + ip->ip_hl = 5; + ip->ip_tos = 0; + ip->ip_len = 0; /* set later */ +#ifdef RANDOM_IP_ID + ip->ip_id = ip_randomid(); +#else + ip->ip_id = htons(ip_id++); +#endif + ip->ip_off = 0; + ip->ip_ttl = 0; /* set later */ + ip->ip_p = IPPROTO_TCP; + ip->ip_sum = 0; + ip->ip_src.s_addr = args->f_id.dst_ip; + ip->ip_dst.s_addr = args->f_id.src_ip; + + tcp = L3HDR(struct tcphdr, ip); + tcp->th_sport = htons(args->f_id.dst_port); /* swap ports */ + tcp->th_dport = htons(args->f_id.src_port); + tcp->th_off = 4; + tcp->th_x2 = 0; + tcp->th_win = 0; + tcp->th_sum = 0; + tcp->th_urp = 0; + if (flags & TH_ACK) { + tcp->th_seq = htonl(ack); + tcp->th_ack = htonl(0); + tcp->th_flags = TH_RST; + } else { + if (flags & TH_SYN) + seq++; + tcp->th_seq = htonl(0); + tcp->th_ack = htonl(seq); + tcp->th_flags = TH_RST | TH_ACK; + } + /* compute TCP checksum... */ + tcp->th_sum = in_cksum(m, m->m_pkthdr.len); + ip->ip_ttl = ip_defttl; + ip->ip_len = m->m_pkthdr.len; + bzero (&sro, sizeof (sro)); + ip_rtaddr(ip->ip_dst, &sro); + ip_output(m, NULL, &sro, 0, NULL); + if (sro.ro_rt) + RTFREE(sro.ro_rt); +} +#endif + /* * sends a reject message, consuming the mbuf passed as an argument. */ static void -send_reject(struct mbuf *m, int code, int offset, int ip_len) +send_reject(struct ip_fw_args *args, int code, int offset, int ip_len) { if (code != ICMP_REJECT_RST) /* Send an ICMP unreach */ - icmp_error(m, ICMP_UNREACH, code, 0L, 0); - else { + icmp_error(args->m, ICMP_UNREACH, code, 0L, 0); + else if (offset == 0 && args->f_id.proto == IPPROTO_TCP) { +#if 0 + struct tcphdr *const tcp = + L3HDR(struct tcphdr, mtod(args->m, struct ip *)); + if ( (tcp->th_flags & TH_RST) == 0) + send_pkt(args, tcp->th_seq, tcp->th_ack, tcp->th_flags); + m_freem(args->m); +#else /* XXX warning, this code writes into the mbuf */ - struct ip *ip = mtod(m, struct ip *); + struct ip *ip = mtod(args->m, struct ip *); struct tcphdr *const tcp = L3HDR(struct tcphdr, ip); struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip; int hlen = ip->ip_hl << 2; - if (offset != 0 || (tcp->th_flags & TH_RST)) { - m_freem(m); /* free the mbuf */ + if (tcp->th_flags & TH_RST) { + m_freem(args->m); /* free the mbuf */ + args->m = NULL; return; } ti.ti_i = *((struct ipovly *) ip); @@ -1005,15 +1082,18 @@ send_reject(struct mbuf *m, int code, int offset, int ip_len) tip->ti_ack = ntohl(tip->ti_ack); tip->ti_len = ip_len - hlen - (tip->ti_off << 2); if (tcp->th_flags & TH_ACK) { - tcp_respond(NULL, (void *)ip, tcp, m, + tcp_respond(NULL, (void *)ip, tcp, args->m, 0, tcp->th_ack, TH_RST); } else { if (tcp->th_flags & TH_SYN) tip->ti_len++; - tcp_respond(NULL, (void *)ip, tcp, m, + tcp_respond(NULL, (void *)ip, tcp, args->m, tip->ti_seq + tip->ti_len, 0, TH_RST|TH_ACK); } - } +#endif + } else + m_freem(args->m); + args->m = NULL; } /** @@ -1579,6 +1659,12 @@ ipfw_chk(struct ip_fw_args *args) goto cmd_fail; goto cmd_match; + case O_IPPRECEDENCE: + if (hlen == 0 || + (cmd->arg1 != (ip->ip_tos & 0xe0)) ) + goto cmd_fail; + goto cmd_match; + case O_IPTOS: if (hlen == 0 || !flags_match(cmd, ip->ip_tos)) @@ -1635,7 +1721,7 @@ ipfw_chk(struct ip_fw_args *args) ipfw_log(f, hlen, args->eh, m, oif); goto cmd_match; - case O_PROB: /* XXX check */ + case O_PROB: if (random() < ((ipfw_insn_u32 *)cmd)->d[0] ) goto cmd_match; goto cmd_fail; @@ -1717,11 +1803,12 @@ ipfw_chk(struct ip_fw_args *args) */ if (hlen > 0 && (proto != IPPROTO_ICMP || - is_icmp_query(ip)) && + is_icmp_query(ip)) && !(m->m_flags & (M_BCAST|M_MCAST)) && !IN_MULTICAST(dst_ip.s_addr)) { - send_reject(m,cmd->arg1,offset,ip_len); - args->m = m = NULL; + send_reject(args, cmd->arg1, + offset,ip_len); + m = args->m; } goto deny; @@ -1796,20 +1883,6 @@ next_rule:; /* try next rule */ return(IP_FW_PORT_DENY_FLAG); } -#if 0 /* XXX old instructions not implemented yet XXX */ -bogusfrag: - if (fw_verbose) { - if (*m != NULL) - ipfw_report(NULL, ip, ip_off, ip_len, (*m)->m_pkthdr.rcvif, oif); - } - return(IP_FW_PORT_DENY_FLAG); - - if (f->fw_ipflg & IP_FW_IF_IPPRE && - (f->fw_iptos & 0xe0) != (ip->ip_tos & 0xe0)) - continue; - -#endif /* XXX old instructions not implemented yet */ - /* * When a rule is added/deleted, clear the next_rule pointers in all rules. * These will be reconstructed on the fly as packets are matched. @@ -2119,6 +2192,7 @@ check_ipfw_struct(struct ip_fw *rule, int size) case O_IPID: case O_IPPRE: case O_IPTOS: + case O_IPPRECEDENCE: case O_IPTTL: case O_IPVER: case O_TCPWIN: @@ -2203,12 +2277,12 @@ check_ipfw_struct(struct ip_fw *rule, int size) goto bad_size; goto check_action; - case O_FORWARD_IP: /* XXX no! */ + case O_FORWARD_IP: if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) goto bad_size; goto check_action; - case O_FORWARD_MAC: /* XXX no! */ + case O_FORWARD_MAC: /* XXX not implemented yet */ case O_CHECK_STATE: case O_COUNT: case O_ACCEPT: