* Add dynamic sysctl for net.inet6.ip6.fw.
* Correct handling of IPv6 Extension Headers. * Add unreach6 code. * Add logging for IPv6. Submitted by: sysctl handling derived from patch from ume needed for ip6fw Obtained from: is_icmp6_query and send_reject6 derived from similar functions of netinet6,ip6fw Reviewed by: ume, gnn; silence on ipfw@ Test setup provided by: CK Software GmbH MFC after: 6 days
This commit is contained in:
parent
b37630e3a6
commit
9066356ba1
@ -1,7 +1,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd June 30, 2005
|
||||
.Dd August 13, 2005
|
||||
.Dt IPFW 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -710,6 +710,10 @@ Synonym for
|
||||
Discard packets that match this rule, and if the
|
||||
packet is a TCP packet, try to send a TCP reset (RST) notice.
|
||||
The search terminates.
|
||||
.It Cm reset6
|
||||
Discard packets that match this rule, and if the
|
||||
packet is a TCP packet, try to send a TCP reset (RST) notice.
|
||||
The search terminates.
|
||||
.It Cm skipto Ar number
|
||||
Skip all subsequent rules numbered less than
|
||||
.Ar number .
|
||||
@ -736,6 +740,17 @@ is a number from 0 to 255, or one of these aliases:
|
||||
or
|
||||
.Cm precedence-cutoff .
|
||||
The search terminates.
|
||||
.It Cm unreach6 Ar code
|
||||
Discard packets that match this rule, and try to send an ICMPv6
|
||||
unreachable notice with code
|
||||
.Ar code ,
|
||||
where
|
||||
.Ar code
|
||||
is a number from 0, 1, 3 or 4, or one of these aliases:
|
||||
.Cm no-route, admin-prohib, address
|
||||
or
|
||||
.Cm port .
|
||||
The search terminates.
|
||||
.It Cm netgraph Ar cookie
|
||||
Divert packet into netgraph with given
|
||||
.Ar cookie .
|
||||
@ -1036,6 +1051,8 @@ Hop-to-hop options
|
||||
.Pq Cm hopopt ,
|
||||
Source routing
|
||||
.Pq Cm route ,
|
||||
Destination options
|
||||
.Pq Cm dstopt ,
|
||||
IPSec authentication headers
|
||||
.Pq Cm ah ,
|
||||
and IPSec encapsulated security payload headers
|
||||
@ -2018,6 +2035,8 @@ reinjected into the firewall at the next rule.
|
||||
Enables verbose messages.
|
||||
.It Em net.inet.ip.fw.verbose_limit : No 0
|
||||
Limits the number of messages produced by a verbose firewall.
|
||||
.It Em net.inet6.ip6.fw.deny_unknown_exthdrs : No 1
|
||||
If enabled packets with unknown IPv6 Extension Headers will be denied.
|
||||
.It Em net.link.ether.ipfw : No 0
|
||||
Controls whether layer-2 packets are passed to
|
||||
.Nm .
|
||||
|
@ -277,6 +277,8 @@ enum tokens {
|
||||
TOK_SRCIP6,
|
||||
|
||||
TOK_IPV4,
|
||||
TOK_UNREACH6,
|
||||
TOK_RESET6,
|
||||
};
|
||||
|
||||
struct _s_x dummynet_params[] = {
|
||||
@ -326,7 +328,9 @@ struct _s_x rule_actions[] = {
|
||||
{ "deny", TOK_DENY },
|
||||
{ "drop", TOK_DENY },
|
||||
{ "reject", TOK_REJECT },
|
||||
{ "reset6", TOK_RESET6 },
|
||||
{ "reset", TOK_RESET },
|
||||
{ "unreach6", TOK_UNREACH6 },
|
||||
{ "unreach", TOK_UNREACH },
|
||||
{ "check-state", TOK_CHECKSTATE },
|
||||
{ "//", TOK_COMMENT },
|
||||
@ -851,6 +855,40 @@ print_reject_code(uint16_t code)
|
||||
printf("unreach %u", code);
|
||||
}
|
||||
|
||||
static struct _s_x icmp6codes[] = {
|
||||
{ "no-route", ICMP6_DST_UNREACH_NOROUTE },
|
||||
{ "admin-prohib", ICMP6_DST_UNREACH_ADMIN },
|
||||
{ "address", ICMP6_DST_UNREACH_ADDR },
|
||||
{ "port", ICMP6_DST_UNREACH_NOPORT },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static void
|
||||
fill_unreach6_code(u_short *codep, char *str)
|
||||
{
|
||||
int val;
|
||||
char *s;
|
||||
|
||||
val = strtoul(str, &s, 0);
|
||||
if (s == str || *s != '\0' || val >= 0x100)
|
||||
val = match_token(icmp6codes, str);
|
||||
if (val < 0)
|
||||
errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str);
|
||||
*codep = val;
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
print_unreach6_code(uint16_t code)
|
||||
{
|
||||
char const *s = match_value(icmp6codes, code);
|
||||
|
||||
if (s != NULL)
|
||||
printf("unreach6 %s", s);
|
||||
else
|
||||
printf("unreach6 %u", code);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of bits set (from left) in a contiguous bitmask,
|
||||
* or -1 if the mask is not contiguous.
|
||||
@ -1169,6 +1207,7 @@ static struct _s_x ext6hdrcodes[] = {
|
||||
{ "frag", EXT_FRAGMENT },
|
||||
{ "hopopt", EXT_HOPOPTS },
|
||||
{ "route", EXT_ROUTING },
|
||||
{ "dstopt", EXT_DSTOPTS },
|
||||
{ "ah", EXT_AH },
|
||||
{ "esp", EXT_ESP },
|
||||
{ NULL, 0 }
|
||||
@ -1199,6 +1238,10 @@ fill_ext6hdr( ipfw_insn *cmd, char *av)
|
||||
cmd->arg1 |= EXT_ROUTING;
|
||||
break;
|
||||
|
||||
case EXT_DSTOPTS:
|
||||
cmd->arg1 |= EXT_DSTOPTS;
|
||||
break;
|
||||
|
||||
case EXT_AH:
|
||||
cmd->arg1 |= EXT_AH;
|
||||
break;
|
||||
@ -1237,6 +1280,10 @@ print_ext6hdr( ipfw_insn *cmd )
|
||||
printf("%crouting options", sep);
|
||||
sep = ',';
|
||||
}
|
||||
if (cmd->arg1 & EXT_DSTOPTS ) {
|
||||
printf("%cdestination options", sep);
|
||||
sep = ',';
|
||||
}
|
||||
if (cmd->arg1 & EXT_AH ) {
|
||||
printf("%cauthentication header", sep);
|
||||
sep = ',';
|
||||
@ -1406,6 +1453,13 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
|
||||
print_reject_code(cmd->arg1);
|
||||
break;
|
||||
|
||||
case O_UNREACH6:
|
||||
if (cmd->arg1 == ICMP6_UNREACH_RST)
|
||||
printf("reset6");
|
||||
else
|
||||
print_unreach6_code(cmd->arg1);
|
||||
break;
|
||||
|
||||
case O_SKIPTO:
|
||||
printf("skipto %u", cmd->arg1);
|
||||
break;
|
||||
@ -2495,8 +2549,9 @@ help(void)
|
||||
"table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n"
|
||||
"\n"
|
||||
"RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n"
|
||||
"ACTION: check-state | allow | count | deny | unreach CODE | skipto N |\n"
|
||||
" {divert|tee} PORT | forward ADDR | pipe N | queue N\n"
|
||||
"ACTION: check-state | allow | count | deny | unreach{,6} CODE |\n"
|
||||
" skipto N | {divert|tee} PORT | forward ADDR |\n"
|
||||
" pipe N | queue N\n"
|
||||
"PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
|
||||
"ADDR: [ MAC dst src ether_type ] \n"
|
||||
" [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
|
||||
@ -3754,6 +3809,11 @@ add(int ac, char *av[])
|
||||
action->arg1 = ICMP_REJECT_RST;
|
||||
break;
|
||||
|
||||
case TOK_RESET6:
|
||||
action->opcode = O_UNREACH6;
|
||||
action->arg1 = ICMP6_UNREACH_RST;
|
||||
break;
|
||||
|
||||
case TOK_UNREACH:
|
||||
action->opcode = O_REJECT;
|
||||
NEED1("missing reject code");
|
||||
@ -3761,6 +3821,13 @@ add(int ac, char *av[])
|
||||
ac--; av++;
|
||||
break;
|
||||
|
||||
case TOK_UNREACH6:
|
||||
action->opcode = O_UNREACH6;
|
||||
NEED1("missing unreach code");
|
||||
fill_unreach6_code(&action->arg1, *av);
|
||||
ac--; av++;
|
||||
break;
|
||||
|
||||
case TOK_COUNT:
|
||||
action->opcode = O_COUNT;
|
||||
break;
|
||||
|
@ -155,6 +155,8 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
|
||||
|
||||
O_IP4,
|
||||
|
||||
O_UNREACH6, /* arg1=icmpv6 code arg (deny) */
|
||||
|
||||
O_LAST_OPCODE /* not an opcode! */
|
||||
};
|
||||
|
||||
@ -167,6 +169,7 @@ enum ipfw_opcodes { /* arguments (4 byte each) */
|
||||
#define EXT_ROUTING 0x4
|
||||
#define EXT_AH 0x8
|
||||
#define EXT_ESP 0x10
|
||||
#define EXT_DSTOPTS 0x20
|
||||
|
||||
/*
|
||||
* Template for instructions.
|
||||
@ -403,6 +406,7 @@ struct ipfw_flow_id {
|
||||
struct in6_addr dst_ip6; /* could also store MAC addr! */
|
||||
struct in6_addr src_ip6;
|
||||
u_int32_t flow_id6;
|
||||
u_int32_t frag_id6;
|
||||
};
|
||||
|
||||
#define IS_IP6_FLOW_ID(id) ((id)->addr_type == 6)
|
||||
@ -451,6 +455,7 @@ struct _ipfw_dyn_rule {
|
||||
#define IP_FW_TCPOPT_CC 0x10
|
||||
|
||||
#define ICMP_REJECT_RST 0x100 /* fake ICMP code (send a TCP RST) */
|
||||
#define ICMP6_UNREACH_RST 0x100 /* fake ICMPv6 code (send a TCP RST) */
|
||||
|
||||
/*
|
||||
* These are used for lookup tables.
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#if !defined(KLD_MODULE)
|
||||
#include "opt_ipfw.h"
|
||||
#include "opt_ip6fw.h"
|
||||
#include "opt_ipdn.h"
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
@ -322,6 +323,15 @@ SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_short_lifetime, CTLFLAG_RW,
|
||||
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive, CTLFLAG_RW,
|
||||
&dyn_keepalive, 0, "Enable keepalives for dyn. rules");
|
||||
|
||||
/*
|
||||
* IPv6 specific variables
|
||||
*/
|
||||
SYSCTL_DECL(_net_inet6_ip6);
|
||||
|
||||
static struct sysctl_ctx_list ip6_fw_sysctl_ctx;
|
||||
static struct sysctl_oid *ip6_fw_sysctl_tree;
|
||||
|
||||
static int fw_deny_unknown_exthdrs = 1;
|
||||
#endif /* SYSCTL_NODE */
|
||||
|
||||
|
||||
@ -662,7 +672,88 @@ hash_packet6(struct ipfw_flow_id *id)
|
||||
(id->dst_port) ^ (id->src_port) ^ (id->flow_id6);
|
||||
return i;
|
||||
}
|
||||
/* end of ipv6 opcodes */
|
||||
|
||||
static int
|
||||
is_icmp6_query(int icmp6_type)
|
||||
{
|
||||
if ((icmp6_type <= ICMP6_MAXTYPE) &&
|
||||
(icmp6_type == ICMP6_ECHO_REQUEST ||
|
||||
icmp6_type == ICMP6_MEMBERSHIP_QUERY ||
|
||||
icmp6_type == ICMP6_WRUREQUEST ||
|
||||
icmp6_type == ICMP6_FQDN_QUERY ||
|
||||
icmp6_type == ICMP6_NI_QUERY))
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
send_reject6(struct ip_fw_args *args, int code, u_short offset, u_int hlen)
|
||||
{
|
||||
if (code == ICMP6_UNREACH_RST && offset == 0 &&
|
||||
args->f_id.proto == IPPROTO_TCP) {
|
||||
struct ip6_hdr *ip6;
|
||||
struct tcphdr *tcp;
|
||||
tcp_seq ack, seq;
|
||||
int flags;
|
||||
struct {
|
||||
struct ip6_hdr ip6;
|
||||
struct tcphdr th;
|
||||
} ti;
|
||||
|
||||
if (args->m->m_len < (hlen+sizeof(struct tcphdr))) {
|
||||
args->m = m_pullup(args->m, hlen+sizeof(struct tcphdr));
|
||||
if (args->m == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
ip6 = mtod(args->m, struct ip6_hdr *);
|
||||
tcp = (struct tcphdr *)(mtod(args->m, char *) + hlen);
|
||||
|
||||
if ((tcp->th_flags & TH_RST) != 0) {
|
||||
m_freem(args->m);
|
||||
return;
|
||||
}
|
||||
|
||||
ti.ip6 = *ip6;
|
||||
ti.th = *tcp;
|
||||
ti.th.th_seq = ntohl(ti.th.th_seq);
|
||||
ti.th.th_ack = ntohl(ti.th.th_ack);
|
||||
ti.ip6.ip6_nxt = IPPROTO_TCP;
|
||||
|
||||
if (ti.th.th_flags & TH_ACK) {
|
||||
ack = 0;
|
||||
seq = ti.th.th_ack;
|
||||
flags = TH_RST;
|
||||
} else {
|
||||
ack = ti.th.th_seq;
|
||||
if (((args->m)->m_flags & M_PKTHDR) != 0) {
|
||||
ack += (args->m)->m_pkthdr.len - hlen
|
||||
- (ti.th.th_off << 2);
|
||||
} else if (ip6->ip6_plen) {
|
||||
ack += ntohs(ip6->ip6_plen) + sizeof(*ip6)
|
||||
- hlen - (ti.th.th_off << 2);
|
||||
} else {
|
||||
m_freem(args->m);
|
||||
return;
|
||||
}
|
||||
if (tcp->th_flags & TH_SYN)
|
||||
ack++;
|
||||
seq = 0;
|
||||
flags = TH_RST|TH_ACK;
|
||||
}
|
||||
bcopy(&ti, ip6, sizeof(ti));
|
||||
tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),
|
||||
args->m, ack, seq, flags);
|
||||
|
||||
} else if (code != ICMP6_UNREACH_RST) { /* Send an ICMPv6 unreach. */
|
||||
icmp6_error(args->m, ICMP6_DST_UNREACH, code, 0);
|
||||
|
||||
} else
|
||||
m_freem(args->m);
|
||||
|
||||
args->m = NULL;
|
||||
}
|
||||
|
||||
#endif /* INET6 */
|
||||
|
||||
@ -676,12 +767,13 @@ static u_int64_t norule_counter; /* counter for ipfw_log(NULL...) */
|
||||
* XXX this function alone takes about 2Kbytes of code!
|
||||
*/
|
||||
static void
|
||||
ipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh,
|
||||
struct mbuf *m, struct ifnet *oif)
|
||||
ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args,
|
||||
struct mbuf *m, struct ifnet *oif, u_short offset)
|
||||
{
|
||||
struct ether_header *eh = args->eh;
|
||||
char *action;
|
||||
int limit_reached = 0;
|
||||
char action2[40], proto[48], fragment[28];
|
||||
char action2[40], proto[128], fragment[32];
|
||||
|
||||
fragment[0] = '\0';
|
||||
proto[0] = '\0';
|
||||
@ -729,6 +821,14 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh,
|
||||
cmd->arg1);
|
||||
break;
|
||||
|
||||
case O_UNREACH6:
|
||||
if (cmd->arg1==ICMP6_UNREACH_RST)
|
||||
action = "Reset";
|
||||
else
|
||||
snprintf(SNPARGS(action2, 0), "Unreach %d",
|
||||
cmd->arg1);
|
||||
break;
|
||||
|
||||
case O_ACCEPT:
|
||||
action = "Accept";
|
||||
break;
|
||||
@ -782,78 +882,123 @@ ipfw_log(struct ip_fw *f, u_int hlen, struct ether_header *eh,
|
||||
|
||||
if (hlen == 0) { /* non-ip */
|
||||
snprintf(SNPARGS(proto, 0), "MAC");
|
||||
|
||||
} else {
|
||||
struct ip *ip = mtod(m, struct ip *);
|
||||
/* these three are all aliases to the same thing */
|
||||
struct icmphdr *const icmp = L3HDR(struct icmphdr, ip);
|
||||
struct tcphdr *const tcp = (struct tcphdr *)icmp;
|
||||
struct udphdr *const udp = (struct udphdr *)icmp;
|
||||
|
||||
int ip_off, offset, ip_len;
|
||||
|
||||
int len;
|
||||
char src[48], dst[48];
|
||||
struct icmphdr *icmp;
|
||||
struct tcphdr *tcp;
|
||||
struct udphdr *udp;
|
||||
/* Initialize to make compiler happy. */
|
||||
struct ip *ip = NULL;
|
||||
#ifdef INET6
|
||||
struct ip6_hdr *ip6 = NULL;
|
||||
struct icmp6_hdr *icmp6;
|
||||
#endif
|
||||
src[0] = '\0';
|
||||
dst[0] = '\0';
|
||||
#ifdef INET6
|
||||
if (args->f_id.addr_type == 6) {
|
||||
snprintf(src, sizeof(src), "[%s]",
|
||||
ip6_sprintf(&args->f_id.src_ip6));
|
||||
snprintf(dst, sizeof(dst), "[%s]",
|
||||
ip6_sprintf(&args->f_id.dst_ip6));
|
||||
|
||||
if (eh != NULL) { /* layer 2 packets are as on the wire */
|
||||
ip_off = ntohs(ip->ip_off);
|
||||
ip_len = ntohs(ip->ip_len);
|
||||
} else {
|
||||
ip_off = ip->ip_off;
|
||||
ip_len = ip->ip_len;
|
||||
ip6 = (struct ip6_hdr *)mtod(m, struct ip6_hdr *);
|
||||
tcp = (struct tcphdr *)(mtod(args->m, char *) + hlen);
|
||||
udp = (struct udphdr *)(mtod(args->m, char *) + hlen);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ip = mtod(m, struct ip *);
|
||||
tcp = L3HDR(struct tcphdr, ip);
|
||||
udp = L3HDR(struct udphdr, ip);
|
||||
|
||||
inet_ntoa_r(ip->ip_src, src);
|
||||
inet_ntoa_r(ip->ip_dst, dst);
|
||||
}
|
||||
offset = ip_off & IP_OFFMASK;
|
||||
switch (ip->ip_p) {
|
||||
|
||||
switch (args->f_id.proto) {
|
||||
case IPPROTO_TCP:
|
||||
len = snprintf(SNPARGS(proto, 0), "TCP %s",
|
||||
inet_ntoa(ip->ip_src));
|
||||
len = snprintf(SNPARGS(proto, 0), "TCP %s", src);
|
||||
if (offset == 0)
|
||||
snprintf(SNPARGS(proto, len), ":%d %s:%d",
|
||||
ntohs(tcp->th_sport),
|
||||
inet_ntoa(ip->ip_dst),
|
||||
dst,
|
||||
ntohs(tcp->th_dport));
|
||||
else
|
||||
snprintf(SNPARGS(proto, len), " %s",
|
||||
inet_ntoa(ip->ip_dst));
|
||||
snprintf(SNPARGS(proto, len), " %s", dst);
|
||||
break;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
len = snprintf(SNPARGS(proto, 0), "UDP %s",
|
||||
inet_ntoa(ip->ip_src));
|
||||
len = snprintf(SNPARGS(proto, 0), "UDP %s", src);
|
||||
if (offset == 0)
|
||||
snprintf(SNPARGS(proto, len), ":%d %s:%d",
|
||||
ntohs(udp->uh_sport),
|
||||
inet_ntoa(ip->ip_dst),
|
||||
dst,
|
||||
ntohs(udp->uh_dport));
|
||||
else
|
||||
snprintf(SNPARGS(proto, len), " %s",
|
||||
inet_ntoa(ip->ip_dst));
|
||||
snprintf(SNPARGS(proto, len), " %s", dst);
|
||||
break;
|
||||
|
||||
case IPPROTO_ICMP:
|
||||
icmp = L3HDR(struct icmphdr, ip);
|
||||
if (offset == 0)
|
||||
len = snprintf(SNPARGS(proto, 0),
|
||||
"ICMP:%u.%u ",
|
||||
icmp->icmp_type, icmp->icmp_code);
|
||||
else
|
||||
len = snprintf(SNPARGS(proto, 0), "ICMP ");
|
||||
len += snprintf(SNPARGS(proto, len), "%s",
|
||||
inet_ntoa(ip->ip_src));
|
||||
snprintf(SNPARGS(proto, len), " %s",
|
||||
inet_ntoa(ip->ip_dst));
|
||||
len += snprintf(SNPARGS(proto, len), "%s", src);
|
||||
snprintf(SNPARGS(proto, len), " %s", dst);
|
||||
break;
|
||||
|
||||
#ifdef INET6
|
||||
case IPPROTO_ICMPV6:
|
||||
icmp6 = (struct icmp6_hdr *)(mtod(args->m, char *) + hlen);
|
||||
if (offset == 0)
|
||||
len = snprintf(SNPARGS(proto, 0),
|
||||
"ICMPv6:%u.%u ",
|
||||
icmp6->icmp6_type, icmp6->icmp6_code);
|
||||
else
|
||||
len = snprintf(SNPARGS(proto, 0), "ICMPv6 ");
|
||||
len += snprintf(SNPARGS(proto, len), "%s", src);
|
||||
snprintf(SNPARGS(proto, len), " %s", dst);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
len = snprintf(SNPARGS(proto, 0), "P:%d %s", ip->ip_p,
|
||||
inet_ntoa(ip->ip_src));
|
||||
snprintf(SNPARGS(proto, len), " %s",
|
||||
inet_ntoa(ip->ip_dst));
|
||||
len = snprintf(SNPARGS(proto, 0), "P:%d %s",
|
||||
args->f_id.proto, src);
|
||||
snprintf(SNPARGS(proto, len), " %s", dst);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ip_off & (IP_MF | IP_OFFMASK))
|
||||
snprintf(SNPARGS(fragment, 0), " (frag %d:%d@%d%s)",
|
||||
ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2),
|
||||
offset << 3,
|
||||
(ip_off & IP_MF) ? "+" : "");
|
||||
#ifdef INET6
|
||||
if (args->f_id.addr_type == 6) {
|
||||
if (offset & (IP6F_OFF_MASK | IP6F_MORE_FRAG))
|
||||
snprintf(SNPARGS(fragment, 0),
|
||||
" (frag %08x:%d@%d%s)",
|
||||
args->f_id.frag_id6,
|
||||
ntohs(ip6->ip6_plen) - hlen,
|
||||
ntohs(offset & IP6F_OFF_MASK) << 3,
|
||||
(offset & IP6F_MORE_FRAG) ? "+" : "");
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
int ip_off, ip_len;
|
||||
if (eh != NULL) { /* layer 2 packets are as on the wire */
|
||||
ip_off = ntohs(ip->ip_off);
|
||||
ip_len = ntohs(ip->ip_len);
|
||||
} else {
|
||||
ip_off = ip->ip_off;
|
||||
ip_len = ip->ip_len;
|
||||
}
|
||||
if (ip_off & (IP_MF | IP_OFFMASK))
|
||||
snprintf(SNPARGS(fragment, 0),
|
||||
" (frag %d:%d@%d%s)",
|
||||
ntohs(ip->ip_id), ip_len - (ip->ip_hl << 2),
|
||||
offset << 3,
|
||||
(ip_off & IP_MF) ? "+" : "");
|
||||
}
|
||||
}
|
||||
if (oif || m->m_pkthdr.rcvif)
|
||||
log(LOG_SECURITY | LOG_INFO,
|
||||
@ -1483,7 +1628,7 @@ send_pkt(struct ipfw_flow_id *id, u_int32_t seq, u_int32_t ack, int flags)
|
||||
* sends a reject message, consuming the mbuf passed as an argument.
|
||||
*/
|
||||
static void
|
||||
send_reject(struct ip_fw_args *args, int code, int offset, int ip_len)
|
||||
send_reject(struct ip_fw_args *args, int code, u_short offset, int ip_len)
|
||||
{
|
||||
|
||||
if (code != ICMP_REJECT_RST) { /* Send an ICMP unreach */
|
||||
@ -1947,6 +2092,11 @@ ipfw_chk(struct ip_fw_args *args)
|
||||
* we have a fragment at this offset of an IPv4 packet.
|
||||
* offset == 0 means that (if this is an IPv4 packet)
|
||||
* this is the first or only fragment.
|
||||
* For IPv6 offset == 0 means there is no Fragment Header.
|
||||
* If offset != 0 for IPv6 always use correct mask to
|
||||
* get the correct offset because we add IP6F_MORE_FRAG
|
||||
* to be able to dectect the first fragment which would
|
||||
* otherwise have offset = 0.
|
||||
*/
|
||||
u_short offset = 0;
|
||||
|
||||
@ -1998,6 +2148,7 @@ ipfw_chk(struct ip_fw_args *args)
|
||||
|
||||
pktlen = m->m_pkthdr.len;
|
||||
proto = args->f_id.proto = 0; /* mark f_id invalid */
|
||||
/* XXX 0 is a valid proto: IP/IPv6 Hop-by-Hop Option */
|
||||
|
||||
/*
|
||||
* PULLUP_TO(len, p, T) makes sure that len + sizeof(T) is contiguous,
|
||||
@ -2046,54 +2197,92 @@ do { \
|
||||
src_port = UDP(ulp)->uh_sport;
|
||||
break;
|
||||
|
||||
case IPPROTO_HOPOPTS:
|
||||
case IPPROTO_HOPOPTS: /* RFC 2460 */
|
||||
PULLUP_TO(hlen, ulp, struct ip6_hbh);
|
||||
ext_hd |= EXT_HOPOPTS;
|
||||
hlen += sizeof(struct ip6_hbh);
|
||||
hlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3;
|
||||
proto = ((struct ip6_hbh *)ulp)->ip6h_nxt;
|
||||
ulp = NULL;
|
||||
break;
|
||||
|
||||
case IPPROTO_ROUTING:
|
||||
case IPPROTO_ROUTING: /* RFC 2460 */
|
||||
PULLUP_TO(hlen, ulp, struct ip6_rthdr);
|
||||
if (((struct ip6_rthdr *)ulp)->ip6r_type != 0) {
|
||||
printf("IPFW2: IPV6 - Unknown Routing "
|
||||
"Header type(%d)\n",
|
||||
((struct ip6_rthdr *)ulp)->ip6r_type);
|
||||
if (fw_deny_unknown_exthdrs)
|
||||
return (IP_FW_DENY);
|
||||
break;
|
||||
}
|
||||
ext_hd |= EXT_ROUTING;
|
||||
hlen += sizeof(struct ip6_rthdr);
|
||||
hlen += (((struct ip6_rthdr *)ulp)->ip6r_len + 1) << 3;
|
||||
proto = ((struct ip6_rthdr *)ulp)->ip6r_nxt;
|
||||
ulp = NULL;
|
||||
break;
|
||||
|
||||
case IPPROTO_FRAGMENT:
|
||||
case IPPROTO_FRAGMENT: /* RFC 2460 */
|
||||
PULLUP_TO(hlen, ulp, struct ip6_frag);
|
||||
ext_hd |= EXT_FRAGMENT;
|
||||
hlen += sizeof (struct ip6_frag);
|
||||
proto = ((struct ip6_frag *)ulp)->ip6f_nxt;
|
||||
offset = 1;
|
||||
ulp = NULL; /* XXX is it correct ? */
|
||||
offset = ((struct ip6_frag *)ulp)->ip6f_offlg &
|
||||
IP6F_OFF_MASK;
|
||||
/* Add IP6F_MORE_FRAG for offset of first
|
||||
* fragment to be != 0. */
|
||||
offset |= ((struct ip6_frag *)ulp)->ip6f_offlg &
|
||||
IP6F_MORE_FRAG;
|
||||
if (offset == 0) {
|
||||
printf("IPFW2: IPV6 - Invalid Fragment "
|
||||
"Header\n");
|
||||
if (fw_deny_unknown_exthdrs)
|
||||
return (IP_FW_DENY);
|
||||
break;
|
||||
}
|
||||
args->f_id.frag_id6 =
|
||||
ntohl(((struct ip6_frag *)ulp)->ip6f_ident);
|
||||
ulp = NULL;
|
||||
break;
|
||||
|
||||
case IPPROTO_AH:
|
||||
case IPPROTO_NONE:
|
||||
case IPPROTO_ESP:
|
||||
case IPPROTO_DSTOPTS: /* RFC 2460 */
|
||||
PULLUP_TO(hlen, ulp, struct ip6_hbh);
|
||||
ext_hd |= EXT_DSTOPTS;
|
||||
hlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3;
|
||||
proto = ((struct ip6_hbh *)ulp)->ip6h_nxt;
|
||||
ulp = NULL;
|
||||
break;
|
||||
|
||||
case IPPROTO_AH: /* RFC 2402 */
|
||||
PULLUP_TO(hlen, ulp, struct ip6_ext);
|
||||
if (proto == IPPROTO_AH)
|
||||
ext_hd |= EXT_AH;
|
||||
else if (proto == IPPROTO_ESP)
|
||||
ext_hd |= EXT_ESP;
|
||||
hlen += ((struct ip6_ext *)ulp)->ip6e_len +
|
||||
sizeof (struct ip6_ext);
|
||||
hlen += (((struct ip6_ext *)ulp)->ip6e_len + 2) << 2;
|
||||
proto = ((struct ip6_ext *)ulp)->ip6e_nxt;
|
||||
ulp = NULL;
|
||||
break;
|
||||
|
||||
case IPPROTO_ESP: /* RFC 2406 */
|
||||
PULLUP_TO(hlen, ulp, uint32_t); /* SPI, Seq# */
|
||||
/* Anything past Seq# is variable length and
|
||||
* data past this ext. header is encrypted. */
|
||||
ext_hd |= EXT_ESP;
|
||||
break;
|
||||
|
||||
case IPPROTO_NONE: /* RFC 2460 */
|
||||
PULLUP_TO(hlen, ulp, struct ip6_ext);
|
||||
/* Packet ends here. if ip6e_len!=0 octets
|
||||
* must be ignored. */
|
||||
break;
|
||||
|
||||
case IPPROTO_OSPFIGP:
|
||||
/* XXX OSPF header check? */
|
||||
PULLUP_TO(hlen, ulp, struct ip6_ext);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf( "IPFW2: IPV6 - Unknown Extension Header (%d)\n",
|
||||
proto);
|
||||
return 0; /* deny */
|
||||
printf("IPFW2: IPV6 - Unknown Extension "
|
||||
"Header(%d), ext_hd=%x\n", proto, ext_hd);
|
||||
if (fw_deny_unknown_exthdrs)
|
||||
return (IP_FW_DENY);
|
||||
break;
|
||||
} /*switch */
|
||||
}
|
||||
@ -2101,7 +2290,7 @@ do { \
|
||||
args->f_id.dst_ip6 = mtod(m,struct ip6_hdr *)->ip6_dst;
|
||||
args->f_id.src_ip = 0;
|
||||
args->f_id.dst_ip = 0;
|
||||
args->f_id.flow_id6 = ntohs(mtod(m, struct ip6_hdr *)->ip6_flow);
|
||||
args->f_id.flow_id6 = ntohl(mtod(m, struct ip6_hdr *)->ip6_flow);
|
||||
} else if (pktlen >= sizeof(struct ip) &&
|
||||
(args->eh == NULL || ntohs(args->eh->ether_type) == ETHERTYPE_IP) &&
|
||||
mtod(m, struct ip *)->ip_v == 4) {
|
||||
@ -2604,8 +2793,8 @@ do { \
|
||||
}
|
||||
|
||||
case O_LOG:
|
||||
if (fw_verbose && !is_ipv6)
|
||||
ipfw_log(f, hlen, args->eh, m, oif);
|
||||
if (fw_verbose)
|
||||
ipfw_log(f, hlen, args, m, oif, offset);
|
||||
match = 1;
|
||||
break;
|
||||
|
||||
@ -2873,7 +3062,6 @@ do { \
|
||||
* if the packet is not ICMP (or is an ICMP
|
||||
* query), and it is not multicast/broadcast.
|
||||
*/
|
||||
/* XXX: IPv6 missing!?! */
|
||||
if (hlen > 0 && is_ipv4 &&
|
||||
(proto != IPPROTO_ICMP ||
|
||||
is_icmp_query(ICMP(ulp))) &&
|
||||
@ -2884,6 +3072,19 @@ do { \
|
||||
m = args->m;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
#ifdef INET6
|
||||
case O_UNREACH6:
|
||||
if (hlen > 0 && is_ipv6 &&
|
||||
(proto != IPPROTO_ICMPV6 ||
|
||||
(is_icmp6_query(args->f_id.flags) == 1)) &&
|
||||
!(m->m_flags & (M_BCAST|M_MCAST)) &&
|
||||
!IN6_IS_ADDR_MULTICAST(&args->f_id.dst_ip6)) {
|
||||
send_reject6(args, cmd->arg1,
|
||||
offset, hlen);
|
||||
m = args->m;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
#endif
|
||||
case O_DENY:
|
||||
retval = IP_FW_DENY;
|
||||
goto done;
|
||||
@ -3504,6 +3705,7 @@ check_ipfw_struct(struct ip_fw *rule, int size)
|
||||
case O_ACCEPT:
|
||||
case O_DENY:
|
||||
case O_REJECT:
|
||||
case O_UNREACH6:
|
||||
case O_SKIPTO:
|
||||
check_size:
|
||||
if (cmdlen != F_INSN_SIZE(ipfw_insn))
|
||||
@ -3931,6 +4133,16 @@ ipfw_init(void)
|
||||
struct ip_fw default_rule;
|
||||
int error;
|
||||
|
||||
/* Setup IPv6 fw sysctl tree. */
|
||||
sysctl_ctx_init(&ip6_fw_sysctl_ctx);
|
||||
ip6_fw_sysctl_tree = SYSCTL_ADD_NODE(&ip6_fw_sysctl_ctx,
|
||||
SYSCTL_STATIC_CHILDREN(_net_inet6_ip6), OID_AUTO, "fw",
|
||||
CTLFLAG_RW | CTLFLAG_SECURE, 0, "Firewall");
|
||||
SYSCTL_ADD_INT(&ip6_fw_sysctl_ctx, SYSCTL_CHILDREN(ip6_fw_sysctl_tree),
|
||||
OID_AUTO, "deny_unknown_exthdrs", CTLFLAG_RW | CTLFLAG_SECURE,
|
||||
&fw_deny_unknown_exthdrs, 0,
|
||||
"Deny packets with unknown IPv6 Extension Headers");
|
||||
|
||||
layer3_chain.rules = NULL;
|
||||
layer3_chain.want_write = 0;
|
||||
layer3_chain.busy_count = 0;
|
||||
@ -4022,5 +4234,9 @@ ipfw_destroy(void)
|
||||
IPFW_DYN_LOCK_DESTROY();
|
||||
uma_zdestroy(ipfw_dyn_rule_zone);
|
||||
IPFW_LOCK_DESTROY(&layer3_chain);
|
||||
|
||||
/* Free IPv6 fw sysctl tree. */
|
||||
sysctl_ctx_free(&ip6_fw_sysctl_ctx);
|
||||
|
||||
printf("IP firewall unloaded\n");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user