Add IPv6 support for NPF.

This commit is contained in:
zoltan 2011-11-04 01:00:27 +00:00
parent 766dd565c7
commit 5a5d868dc5
21 changed files with 605 additions and 284 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf.c,v 1.2 2011/02/02 15:17:37 rmind Exp $ */
/* $NetBSD: npf.c,v 1.3 2011/11/04 01:00:28 zoltan Exp $ */
/*-
* Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.2 2011/02/02 15:17:37 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.3 2011/11/04 01:00:28 zoltan Exp $");
#include <sys/types.h>
#include <netinet/in_systm.h>
@ -429,18 +429,21 @@ npf_table_create(int id, int type)
}
int
npf_table_add_entry(nl_table_t *tl, in_addr_t addr, in_addr_t mask)
npf_table_add_entry(nl_table_t *tl, npf_addr_t *addr, npf_netmask_t mask)
{
prop_dictionary_t tldict = tl->ntl_dict, entdict;
prop_array_t tblents;
prop_data_t addrdata;
/* Create the table entry. */
entdict = prop_dictionary_create();
if (entdict) {
return ENOMEM;
}
prop_dictionary_set_uint32(entdict, "addr", addr);
prop_dictionary_set_uint32(entdict, "mask", mask);
addrdata = prop_data_create_data(addr, sizeof(npf_addr_t));
prop_dictionary_set(entdict, "addr", addrdata);
prop_dictionary_set_uint8(entdict, "mask", mask);
prop_object_release(addrdata);
/* Insert the entry. */
tblents = prop_dictionary_get(tldict, "entries");

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf.h,v 1.1 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npf.h,v 1.2 2011/11/04 01:00:28 zoltan Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@ -84,7 +84,7 @@ nl_nat_t * npf_nat_create(int, int, u_int, npf_addr_t *, int, in_port_t);
int npf_nat_insert(nl_config_t *, nl_nat_t *, pri_t);
nl_table_t * npf_table_create(int, int);
int npf_table_add_entry(nl_table_t *, in_addr_t, in_addr_t);
int npf_table_add_entry(nl_table_t *, npf_addr_t *, npf_netmask_t);
bool npf_table_exists_p(nl_config_t *, u_int);
int npf_table_insert(nl_config_t *, nl_table_t *);
void npf_table_destroy(nl_table_t *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf.h,v 1.8 2011/02/02 23:01:34 rmind Exp $ */
/* $NetBSD: npf.h,v 1.9 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@ -55,8 +55,11 @@
* Public declarations and definitions.
*/
/* Storage of address (both for IPv4 and IPv6). */
/* Storage of address (both for IPv4 and IPv6) and netmask */
typedef struct in6_addr npf_addr_t;
typedef uint_fast8_t npf_netmask_t;
#define NPF_NO_NETMASK (npf_netmask_t)~0
#if defined(_KERNEL) || defined(_NPF_TESTING)
@ -80,7 +83,7 @@ typedef struct npf_hook npf_hook_t;
#define NPC_IP4 0x01 /* Indicates fetched IPv4 header. */
#define NPC_IP6 0x02 /* Indicates IPv6 header. */
#define NPC_IPFRAG 0x04 /* IPv4 fragment. */
#define NPC_IPFRAG 0x04 /* IPv4/IPv6 fragment. */
#define NPC_LAYER4 0x08 /* Layer 4 has been fetched. */
#define NPC_TCP 0x10 /* TCP header. */
@ -98,6 +101,8 @@ typedef struct {
npf_addr_t * npc_dstip;
/* Size (v4 or v6) of IP addresses. */
int npc_ipsz;
size_t npc_hlen;
int npc_next_proto;
/* IPv4, IPv6. */
union {
struct ip v4;
@ -111,6 +116,71 @@ typedef struct {
} npc_l4;
} npf_cache_t;
/* Max length is 32 for IPv4 and 128 for IPv6 */
static inline void
npf_generate_mask(npf_addr_t *dst, const npf_netmask_t omask)
{
uint_fast8_t length = omask;
KASSERT(length <= 128);
memset(dst, 0, sizeof(npf_addr_t));
for (int i = 0; i < 4; i++) {
if (length >= 32) {
dst->s6_addr32[i] = htonl(0xffffffff);
length -= 32;
} else {
dst->s6_addr32[i] = htonl(0xffffffff << (32 - length));
length = 0;
}
}
}
static inline void
npf_calculate_masked_addr(npf_addr_t *dst, const npf_addr_t *src, const npf_netmask_t omask)
{
npf_addr_t mask;
npf_generate_mask(&mask, omask);
for (int i = 0; i < 4; i++) {
dst->s6_addr32[i] =
src->s6_addr32[i] & mask.s6_addr32[i];
}
}
/*
* compare two addresses, either v4 or v6
* if the mask is NULL, ignore it
*/
static inline int
npf_compare_cidr(const npf_addr_t *addr1, const npf_netmask_t mask1,
const npf_addr_t *addr2, const npf_netmask_t mask2)
{
npf_addr_t realmask1, realmask2;
if (mask1 != NPF_NO_NETMASK) {
npf_generate_mask(&realmask1, mask1);
}
if (mask2 != NPF_NO_NETMASK) {
npf_generate_mask(&realmask2, mask2);
}
for (int i = 0; i < 4; i++) {
const uint32_t x = mask1 != NPF_NO_NETMASK ?
addr1->s6_addr32[i] & realmask1.s6_addr32[i] :
addr1->s6_addr32[i];
const uint32_t y = mask2 != NPF_NO_NETMASK ?
addr2->s6_addr32[i] & realmask2.s6_addr32[i] :
addr2->s6_addr32[i];
if (x < y) {
return -1;
}
if (x > y) {
return 1;
}
}
return 0;
}
static inline bool
npf_iscached(const npf_cache_t *npc, const int inf)
{
@ -121,10 +191,15 @@ npf_iscached(const npf_cache_t *npc, const int inf)
static inline int
npf_cache_ipproto(const npf_cache_t *npc)
{
const struct ip *ip = &npc->npc_ip.v4;
KASSERT(npf_iscached(npc, NPC_IP46));
return ip->ip_p;
return npc->npc_next_proto;
}
static inline int
npf_cache_hlen(const npf_cache_t *npc, nbuf_t *nbuf)
{
KASSERT(npf_iscached(npc, NPC_IP46));
return npc->npc_hlen;
}
/* Network buffer interface. */
@ -190,8 +265,8 @@ void npf_hook_unregister(npf_rule_t *, npf_hook_t *);
typedef struct npf_ioctl_table {
int nct_action;
u_int nct_tid;
in_addr_t nct_addr;
in_addr_t nct_mask;
npf_addr_t nct_addr;
npf_netmask_t nct_mask;
int _reserved;
} npf_ioctl_table_t;

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_alg_icmp.c,v 1.6 2011/01/18 20:33:45 rmind Exp $ */
/* $NetBSD: npf_alg_icmp.c,v 1.7 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.6 2011/01/18 20:33:45 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_alg_icmp.c,v 1.7 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -119,7 +119,8 @@ npfa_icmp_match(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
struct ip *ip = &npc->npc_ip.v4;
in_port_t dport;
KASSERT(npf_iscached(npc, NPC_IP46 | NPC_LAYER4));
KASSERT(npf_iscached(npc, NPC_IP46));
KASSERT(npf_iscached(npc, NPC_LAYER4));
/* Check for low TTL. */
if (ip->ip_ttl > TR_MAX_TTL) {
@ -247,10 +248,10 @@ npfa_icmp_session(npf_cache_t *npc, nbuf_t *nbuf, void *keyptr)
KASSERT(npf_iscached(npc, NPC_ICMP));
/* Advance to ICMP header. */
struct ip *ip = &npc->npc_ip.v4;
void *n_ptr = nbuf_dataptr(nbuf);
const size_t hlen = npf_cache_hlen(npc, nbuf);
if ((n_ptr = nbuf_advance(&nbuf, n_ptr, ip->ip_hl << 2)) == NULL) {
if ((n_ptr = nbuf_advance(&nbuf, n_ptr, hlen)) == NULL) {
return false;
}
@ -297,7 +298,8 @@ npfa_icmp_natin(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
return false;
}
/* XXX: Restore inversion (inefficient). */
KASSERT(npf_iscached(&enpc, NPC_IP46 | NPC_LAYER4));
KASSERT(npf_iscached(&enpc, NPC_IP46));
KASSERT(npf_iscached(&enpc, NPC_LAYER4));
npfa_srcdst_invert(&enpc);
/*
@ -306,7 +308,7 @@ npfa_icmp_natin(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
* embedded packet changes, while data is not rewritten in the cache.
*/
const int proto = npf_cache_ipproto(&enpc);
const struct ip * const ip = &npc->npc_ip.v4, *eip = &enpc.npc_ip.v4;
const struct ip *eip = &enpc.npc_ip.v4;
const struct icmp * const ic = &npc->npc_l4.icmp;
uint16_t cksum = ic->icmp_cksum, ecksum = eip->ip_sum, l4cksum;
npf_nat_t *nt = ntptr;
@ -331,7 +333,7 @@ npfa_icmp_natin(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
* to the embedded IP header after ICMP header.
*/
void *n_ptr = nbuf_dataptr(nbuf), *cnbuf = nbuf, *cnptr = n_ptr;
u_int offby = (ip->ip_hl << 2) + offsetof(struct icmp, icmp_ip);
u_int offby = npf_cache_hlen(npc, nbuf) + offsetof(struct icmp, icmp_ip);
if ((n_ptr = nbuf_advance(&nbuf, n_ptr, offby)) == NULL) {
return false;
@ -365,7 +367,7 @@ npfa_icmp_natin(npf_cache_t *npc, nbuf_t *nbuf, void *ntptr)
}
cksum = npf_fixup16_cksum(cksum, ecksum, eip->ip_sum);
offby = (ip->ip_hl << 2) + offsetof(struct icmp, icmp_cksum);
offby = npf_cache_hlen(npc, nbuf) + offsetof(struct icmp, icmp_cksum);
if (nbuf_advstore(&cnbuf, &cnptr, offby, sizeof(uint16_t), &cksum)) {
return false;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_ctl.c,v 1.6 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npf_ctl.c,v 1.7 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.6 2011/02/02 02:20:25 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.7 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@ -120,12 +120,13 @@ npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables)
}
eit = prop_array_iterator(entries);
while ((ent = prop_object_iterator_next(eit)) != NULL) {
in_addr_t addr, mask; /* XXX: IPv6 */
const npf_addr_t *addr;
npf_netmask_t mask;
/* Get address and mask. Add a table entry. */
prop_dictionary_get_uint32(ent, "addr", &addr);
prop_dictionary_get_uint32(ent, "mask", &mask);
error = npf_table_add_v4cidr(tblset, tid, addr, mask);
addr = (const npf_addr_t *)prop_data_data_nocopy(prop_dictionary_get(ent, "addr"));
prop_dictionary_get_uint8(ent, "mask", &mask);
error = npf_table_add_cidr(tblset, tid, addr, mask);
if (error)
break;
}
@ -600,16 +601,16 @@ npfctl_table(void *data)
npf_core_enter(); /* XXXSMP */
switch (nct->nct_action) {
case NPF_IOCTL_TBLENT_ADD:
error = npf_table_add_v4cidr(NULL, nct->nct_tid,
nct->nct_addr, nct->nct_mask);
error = npf_table_add_cidr(NULL, nct->nct_tid,
&nct->nct_addr, nct->nct_mask);
break;
case NPF_IOCTL_TBLENT_REM:
error = npf_table_rem_v4cidr(NULL, nct->nct_tid,
nct->nct_addr, nct->nct_mask);
error = npf_table_rem_cidr(NULL, nct->nct_tid,
&nct->nct_addr, nct->nct_mask);
break;
default:
/* XXX */
error = npf_table_match_v4addr(nct->nct_tid, nct->nct_addr);
error = npf_table_match_addr(nct->nct_tid, &nct->nct_addr);
if (error) {
error = EINVAL;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_handler.c,v 1.7 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npf_handler.c,v 1.8 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.7 2011/02/02 02:20:25 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.8 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -48,6 +48,8 @@ __KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.7 2011/02/02 02:20:25 rmind Exp $"
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip_var.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include "npf_impl.h"
@ -57,6 +59,7 @@ __KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.7 2011/02/02 02:20:25 rmind Exp $"
*/
static struct pfil_head * npf_ph_if = NULL;
static struct pfil_head * npf_ph_inet = NULL;
static struct pfil_head * npf_ph_inet6 = NULL;
static bool default_pass = true;
@ -86,7 +89,7 @@ npf_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
npf_ruleset_t *rlset;
npf_rule_t *rl;
npf_rproc_t *rp;
int retfl, error;
int retfl, error, ret;
/*
* Initialise packet information cache.
@ -96,15 +99,28 @@ npf_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
error = 0;
retfl = 0;
rp = NULL;
ret = 0;
/* Cache everything. Determine whether it is an IPv4 fragment. */
if (npf_cache_all(&npc, nbuf) && npf_iscached(&npc, NPC_IPFRAG)) {
struct ip *ip = nbuf_dataptr(*mp);
/*
* Pass to IPv4 reassembly mechanism.
*/
if (ip_reass_packet(mp, ip) != 0) {
/* Failed; invalid fragment(s) or packet. */
/* Cache IP information */
npf_cache_all(&npc, nbuf);
if (npf_iscached(&npc, NPC_IPFRAG)) {
if (npf_iscached(&npc, NPC_IP4)) {
struct ip *ip = nbuf_dataptr(*mp);
/* Pass to IPv4 reassembly mechanism. */
ret = ip_reass_packet(mp, ip);
} else if (npf_iscached(&npc, NPC_IP6)) {
/* frag6_input's offset is the start of the fragment header */
size_t hlen = npf_cache_hlen(&npc, nbuf);
/* Pass to IPv6 reassembly mechanism. */
ret = ip6_reass_packet(mp, hlen);
} else {
KASSERT(false);
}
if (ret != 0) {
error = EINVAL;
se = NULL;
goto out;
@ -115,6 +131,13 @@ npf_packet_handler(void *arg, struct mbuf **mp, ifnet_t *ifp, int di)
}
/* Reassembly is complete, we have the final packet. */
nbuf = (nbuf_t *)*mp;
/*
* Before reassembly, we can't cache anything above layer3,
* but at this point, it's reassembled - let's cache it again
*/
npc.npc_info = 0;
npf_cache_all(&npc, nbuf);
}
/* Inspect the list of sessions. */
@ -230,6 +253,7 @@ npf_register_pfil(void)
/* Capture point of any activity in interfaces and IP layer. */
npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
if (npf_ph_if == NULL || npf_ph_inet == NULL) {
npf_ph_if = NULL;
error = ENOENT;
@ -246,6 +270,9 @@ npf_register_pfil(void)
PFIL_WAITOK | PFIL_ALL, npf_ph_inet);
KASSERT(error == 0);
error = pfil_add_hook(npf_packet_handler, NULL,
PFIL_WAITOK | PFIL_ALL, npf_ph_inet6);
KASSERT(error == 0);
fail:
KERNEL_UNLOCK_ONE(NULL);
mutex_exit(softnet_lock);
@ -264,6 +291,8 @@ npf_unregister_pfil(void)
KERNEL_LOCK(1, NULL);
if (npf_ph_if) {
(void)pfil_remove_hook(npf_packet_handler, NULL,
PFIL_ALL, npf_ph_inet6);
(void)pfil_remove_hook(npf_packet_handler, NULL,
PFIL_ALL, npf_ph_inet);
(void)pfil_remove_hook(npf_ifhook, NULL,

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_impl.h,v 1.7 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npf_impl.h,v 1.8 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@ -161,7 +161,7 @@ uint16_t npf_fixup16_cksum(uint16_t, uint16_t, uint16_t);
uint16_t npf_fixup32_cksum(uint16_t, uint32_t, uint32_t);
uint16_t npf_addr_cksum(uint16_t, int, npf_addr_t *, npf_addr_t *);
uint32_t npf_addr_sum(const int, const npf_addr_t *, const npf_addr_t *);
int npf_tcpsaw(npf_cache_t *, tcp_seq *, tcp_seq *, uint32_t *);
int npf_tcpsaw(npf_cache_t *, nbuf_t *, tcp_seq *, tcp_seq *, uint32_t *);
bool npf_fetch_tcpopts(const npf_cache_t *, nbuf_t *,
uint16_t *, int *);
bool npf_normalize(npf_cache_t *, nbuf_t *, bool, bool, u_int, u_int);
@ -169,10 +169,10 @@ void npf_return_block(npf_cache_t *, nbuf_t *, const int);
/* Complex instructions. */
int npf_match_ether(nbuf_t *, int, int, uint16_t, uint32_t *);
int npf_match_ip4table(npf_cache_t *, nbuf_t *, void *,
int npf_match_table(npf_cache_t *, nbuf_t *, void *,
const int, const u_int);
int npf_match_ip4mask(npf_cache_t *, nbuf_t *, void *,
const int, in_addr_t, in_addr_t);
int npf_match_ipmask(npf_cache_t *, nbuf_t *, void *,
const int, const npf_addr_t *, const npf_netmask_t);
int npf_match_tcp_ports(npf_cache_t *, nbuf_t *, void *,
const int, const uint32_t);
int npf_match_udp_ports(npf_cache_t *, nbuf_t *, void *,
@ -197,11 +197,11 @@ void npf_table_unref(npf_table_t *);
npf_table_t * npf_table_get(npf_tableset_t *, u_int);
void npf_table_put(npf_table_t *);
int npf_table_check(npf_tableset_t *, u_int, int);
int npf_table_add_v4cidr(npf_tableset_t *, u_int,
in_addr_t, in_addr_t);
int npf_table_rem_v4cidr(npf_tableset_t *, u_int,
in_addr_t, in_addr_t);
int npf_table_match_v4addr(u_int, in_addr_t);
int npf_table_add_cidr(npf_tableset_t *, u_int,
const npf_addr_t *, const npf_netmask_t);
int npf_table_rem_cidr(npf_tableset_t *, u_int,
const npf_addr_t *, const npf_netmask_t);
int npf_table_match_addr(u_int, const npf_addr_t *);
/* Ruleset interface. */
npf_ruleset_t * npf_ruleset_create(void);

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_inet.c,v 1.6 2011/01/18 20:33:45 rmind Exp $ */
/* $NetBSD: npf_inet.c,v 1.7 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.6 2011/01/18 20:33:45 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.7 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -126,18 +126,29 @@ npf_addr_sum(const int sz, const npf_addr_t *a1, const npf_addr_t *a2)
* Returns all values in host byte-order.
*/
int
npf_tcpsaw(npf_cache_t *npc, tcp_seq *seq, tcp_seq *ack, uint32_t *win)
npf_tcpsaw(npf_cache_t *npc, nbuf_t *nbuf, tcp_seq *seq, tcp_seq *ack, uint32_t *win)
{
struct ip *ip = &npc->npc_ip.v4;
struct tcphdr *th = &npc->npc_l4.tcp;
KASSERT(npf_iscached(npc, NPC_IP46 | NPC_TCP));
KASSERT(npf_iscached(npc, NPC_TCP));
*seq = ntohl(th->th_seq);
*ack = ntohl(th->th_ack);
*win = (uint32_t)ntohs(th->th_win);
return ntohs(ip->ip_len) - (ip->ip_hl << 2) - (th->th_off << 2);
/*
* total length of packet - header length - tcp header length
*/
if (npf_iscached(npc, NPC_IP4)) {
struct ip *ip = &npc->npc_ip.v4;
return ntohs(ip->ip_len) - npf_cache_hlen(npc, nbuf) - (th->th_off << 2);
} else {
KASSERT(npf_iscached(npc, NPC_IP6));
struct ip6_hdr *ip6 = &npc->npc_ip.v6;
return ntohs(ip6->ip6_plen) - (th->th_off << 2);
}
return 0;
}
/*
@ -148,14 +159,13 @@ npf_fetch_tcpopts(const npf_cache_t *npc, nbuf_t *nbuf,
uint16_t *mss, int *wscale)
{
void *n_ptr = nbuf_dataptr(nbuf);
const struct ip *ip = &npc->npc_ip.v4;
const struct tcphdr *th = &npc->npc_l4.tcp;
int topts_len, step;
uint16_t val16;
uint8_t val;
KASSERT(npf_iscached(npc, NPC_IP46 | NPC_TCP));
KASSERT(npf_iscached(npc, NPC_IP46));
KASSERT(npf_iscached(npc, NPC_TCP));
/* Determine if there are any TCP options, get their length. */
topts_len = (th->th_off << 2) - sizeof(struct tcphdr);
if (topts_len <= 0) {
@ -165,7 +175,7 @@ npf_fetch_tcpopts(const npf_cache_t *npc, nbuf_t *nbuf,
KASSERT(topts_len <= MAX_TCPOPTLEN);
/* First step: IP and TCP header up to options. */
step = (ip->ip_hl << 2) + sizeof(struct tcphdr);
step = npf_cache_hlen(npc, nbuf) + sizeof(struct tcphdr);
next:
if (nbuf_advfetch(&nbuf, &n_ptr, step, sizeof(val), &val)) {
return false;
@ -229,6 +239,7 @@ bool
npf_fetch_ip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
{
struct ip *ip;
struct ip6_hdr *ip6;
uint8_t ver;
if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &ver)) {
@ -255,10 +266,59 @@ npf_fetch_ip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
npc->npc_srcip = (npf_addr_t *)&ip->ip_src;
npc->npc_dstip = (npf_addr_t *)&ip->ip_dst;
npc->npc_info |= NPC_IP4;
npc->npc_hlen = ip->ip_hl << 2;
npc->npc_next_proto = npc->npc_ip.v4.ip_p;
break;
case (IPV6_VERSION >> 4):
/* TODO */
ip6 = &npc->npc_ip.v6;
if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(struct ip6_hdr), ip6)) {
return false;
}
struct ip6_ext ip6e;
size_t toskip = sizeof(struct ip6_hdr);
bool processing_ends = false;
npc->npc_next_proto = ip6->ip6_nxt;
npc->npc_hlen = 0;
do {
/* advance the length of the previous known header,
and fetch the next extension header's length */
if (nbuf_advfetch(&nbuf, &n_ptr, toskip, sizeof(struct ip6_ext), &ip6e)) {
return false;
}
switch (npc->npc_next_proto) {
case IPPROTO_DSTOPTS:
case IPPROTO_ROUTING:
toskip = (ip6e.ip6e_len + 1) << 3;
break;
case IPPROTO_FRAGMENT:
npc->npc_info |= NPC_IPFRAG;
toskip = sizeof(struct ip6_frag);
break;
case IPPROTO_AH:
toskip = (ip6e.ip6e_len + 2) << 2;
break;
default:
processing_ends = true;
break;
}
npc->npc_hlen += toskip;
if (!processing_ends) {
npc->npc_next_proto = ip6e.ip6e_nxt;
}
} while (!processing_ends);
npc->npc_ipsz = sizeof(struct in6_addr);
npc->npc_srcip = (npf_addr_t *)&ip6->ip6_src;
npc->npc_dstip = (npf_addr_t *)&ip6->ip6_dst;
npc->npc_info |= NPC_IP6;
break;
default:
return false;
}
@ -268,22 +328,19 @@ npf_fetch_ip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
bool
npf_fetch_tcp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
{
struct ip *ip = &npc->npc_ip.v4;
struct tcphdr *th;
u_int hlen;
/* Must have IP header processed for its length and protocol. */
if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
return false;
}
if (ip->ip_p != IPPROTO_TCP) {
if (npf_cache_ipproto(npc) != IPPROTO_TCP) {
return false;
}
hlen = ip->ip_hl << 2;
th = &npc->npc_l4.tcp;
/* Fetch TCP header. */
if (nbuf_advfetch(&nbuf, &n_ptr, hlen, sizeof(struct tcphdr), th)) {
if (nbuf_advfetch(&nbuf, &n_ptr, npf_cache_hlen(npc, nbuf), sizeof(struct tcphdr), th)) {
return false;
}
@ -297,7 +354,7 @@ npf_fetch_udp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
{
struct ip *ip = &npc->npc_ip.v4;
struct udphdr *uh;
u_int hlen;
size_t hlen;
/* Must have IP header processed for its length and protocol. */
if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
@ -306,8 +363,8 @@ npf_fetch_udp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
if (ip->ip_p != IPPROTO_UDP) {
return false;
}
hlen = ip->ip_hl << 2;
uh = &npc->npc_l4.udp;
hlen = npf_cache_hlen(npc, nbuf);
/* Fetch ICMP header. */
if (nbuf_advfetch(&nbuf, &n_ptr, hlen, sizeof(struct udphdr), uh)) {
@ -329,7 +386,8 @@ npf_fetch_icmp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
{
struct ip *ip = &npc->npc_ip.v4;
struct icmp *ic;
u_int hlen, iclen;
u_int iclen;
size_t hlen;
/* Must have IP header processed for its length and protocol. */
if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
@ -338,8 +396,8 @@ npf_fetch_icmp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr)
if (ip->ip_p != IPPROTO_ICMP) {
return false;
}
hlen = ip->ip_hl << 2;
ic = &npc->npc_l4.icmp;
hlen = npf_cache_hlen(npc, nbuf);
/* Fetch basic ICMP header, up to the "data" point. */
iclen = offsetof(struct icmp, icmp_data);
@ -417,8 +475,7 @@ npf_rwrport(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di,
in_port_t port)
{
const int proto = npf_cache_ipproto(npc);
struct ip *ip = &npc->npc_ip.v4;
u_int offby = ip->ip_hl << 2;
u_int offby = npf_cache_hlen(npc, nbuf);
in_port_t *oport;
KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
@ -481,7 +538,7 @@ npf_rwrcksum(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di,
return false;
ip->ip_sum = ipsum;
offby = (ip->ip_hl << 2) - offby;
offby = npf_cache_hlen(npc, nbuf) - offby;
} else {
/* No checksum for IPv6. */
KASSERT(npf_iscached(npc, NPC_IP6));
@ -494,7 +551,7 @@ npf_rwrcksum(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr, const int di,
if (proto == IPPROTO_ICMP || port == 0) {
return true;
}
KASSERT(npf_iscached(npc, NPC_TCP | NPC_UDP));
KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
/* Calculate TCP/UDP checksum. */
if (proto == IPPROTO_TCP) {
@ -591,7 +648,6 @@ npf_normalize(npf_cache_t *npc, nbuf_t *nbuf,
bool no_df, bool rnd, u_int minttl, u_int maxmss)
{
void *n_ptr = nbuf_dataptr(nbuf);
struct ip *ip = &npc->npc_ip.v4;
struct tcphdr *th = &npc->npc_l4.tcp;
uint16_t cksum, mss;
int offby, wscale;
@ -631,7 +687,7 @@ npf_normalize(npf_cache_t *npc, nbuf_t *nbuf,
if (!npf_fetch_tcpopts(npc, nbuf, &mss, &wscale)) {
return false;
}
offby = (ip->ip_hl << 2) + offsetof(struct tcphdr, th_sum);
offby = npf_cache_hlen(npc, nbuf) + offsetof(struct tcphdr, th_sum);
if (nbuf_advstore(&nbuf, &n_ptr, offby, sizeof(cksum), &cksum)) {
return false;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_instr.c,v 1.5 2011/01/18 20:33:45 rmind Exp $ */
/* $NetBSD: npf_instr.c,v 1.6 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.5 2011/01/18 20:33:45 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.6 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -93,11 +93,10 @@ again:
* npf_match_ip4table: match IPv4 address against NPF table.
*/
int
npf_match_ip4table(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
npf_match_table(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
const int sd, const u_int tid)
{
struct ip *ip = &npc->npc_ip.v4;
in_addr_t ip4addr;
npf_addr_t *addr;
if (!npf_iscached(npc, NPC_IP46)) {
if (!npf_fetch_ip(npc, nbuf, n_ptr)) {
@ -105,21 +104,20 @@ npf_match_ip4table(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
}
KASSERT(npf_iscached(npc, NPC_IP46));
}
ip4addr = sd ? ip->ip_src.s_addr : ip->ip_dst.s_addr;
addr = sd ? npc->npc_srcip : npc->npc_dstip;
/* Match address against NPF table. */
return npf_table_match_v4addr(tid, ip4addr);
return npf_table_match_addr(tid, addr);
}
/*
* npf_match_ip4mask: match IPv4 address against netaddr/subnet.
* npf_match_ipmask: match an address against netaddr/mask.
*/
int
npf_match_ip4mask(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
const int sd, in_addr_t netaddr, in_addr_t subnet)
npf_match_ipmask(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
const int sd, const npf_addr_t *netaddr, npf_netmask_t omask)
{
struct ip *ip = &npc->npc_ip.v4;
in_addr_t ip4addr;
npf_addr_t *addr1, addr2;
if (!npf_iscached(npc, NPC_IP46)) {
if (!npf_fetch_ip(npc, nbuf, n_ptr)) {
@ -127,9 +125,15 @@ npf_match_ip4mask(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr,
}
KASSERT(npf_iscached(npc, NPC_IP46));
}
ip4addr = sd ? ip->ip_src.s_addr : ip->ip_dst.s_addr;
if (omask == 0)
return 0;
return (ip4addr & subnet) == netaddr ? 0 : -1;
addr1 = sd ? npc->npc_srcip : npc->npc_dstip;
npf_calculate_masked_addr(&addr2, netaddr, omask);
if (memcmp(addr1, &addr2, npc->npc_ipsz)) {
return -1;
}
return 0;
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_nat.c,v 1.6 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npf_nat.c,v 1.7 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@ -76,7 +76,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.6 2011/02/02 02:20:25 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.7 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -419,7 +419,8 @@ npf_nat_create(npf_cache_t *npc, npf_natpolicy_t *np)
const int proto = npf_cache_ipproto(npc);
npf_nat_t *nt;
KASSERT(npf_iscached(npc, NPC_IP46 | NPC_LAYER4));
KASSERT(npf_iscached(npc, NPC_IP46));
KASSERT(npf_iscached(npc, NPC_LAYER4));
/* New NAT association. */
nt = pool_cache_get(nat_cache, PR_NOWAIT);
@ -531,7 +532,7 @@ npf_nat_translate(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt,
switch (npf_cache_ipproto(npc)) {
case IPPROTO_TCP:
case IPPROTO_UDP:
KASSERT(npf_iscached(npc, NPC_TCP | NPC_UDP));
KASSERT(npf_iscached(npc, NPC_TCP) || npf_iscached(npc, NPC_UDP));
/* Rewrite source/destination port. */
if (!npf_rwrport(npc, nbuf, n_ptr, di, port)) {
return EINVAL;

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_ncode.h,v 1.4 2010/12/18 01:07:25 rmind Exp $ */
/* $NetBSD: npf_ncode.h,v 1.5 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@ -114,8 +114,9 @@ int npf_ncode_validate(const void *, size_t, int *);
#define NPF_OPCODE_ETHER 0x80
#define NPF_OPCODE_IP4MASK 0x90
#define NPF_OPCODE_IP4TABLE 0x91
#define NPF_OPCODE_TABLE 0x91
#define NPF_OPCODE_ICMP4 0x92
#define NPF_OPCODE_IP6MASK 0x93
#define NPF_OPCODE_TCP_PORTS 0xa0
#define NPF_OPCODE_UDP_PORTS 0xa1

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_processor.c,v 1.4 2010/12/18 01:07:25 rmind Exp $ */
/* $NetBSD: npf_processor.c,v 1.5 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.4 2010/12/18 01:07:25 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_processor.c,v 1.5 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -146,6 +146,8 @@ npf_ncode_process(npf_cache_t *npc, const void *ncode,
uint32_t regs[NPF_NREGS];
/* Local, state variables. */
uint32_t d, i, n;
npf_addr_t addr;
uint32_t mask;
u_int lcount;
int cmpval;
@ -284,13 +286,20 @@ cisc_like:
case NPF_OPCODE_IP4MASK:
/* Source/destination, network address, subnet mask. */
i_ptr = nc_fetch_word(i_ptr, &d);
i_ptr = nc_fetch_double(i_ptr, &n, &i);
cmpval = npf_match_ip4mask(npc, nbuf, n_ptr, d, n, i);
i_ptr = nc_fetch_double(i_ptr, &addr.s6_addr32[0], &mask);
cmpval = npf_match_ipmask(npc, nbuf, n_ptr, d, &addr, (npf_netmask_t)mask);
break;
case NPF_OPCODE_IP4TABLE:
case NPF_OPCODE_IP6MASK:
i_ptr = nc_fetch_word(i_ptr, &d);
i_ptr = nc_fetch_double(i_ptr, &addr.s6_addr32[0], &addr.s6_addr32[1]);
i_ptr = nc_fetch_double(i_ptr, &addr.s6_addr32[2], &addr.s6_addr32[3]);
i_ptr = nc_fetch_word(i_ptr, &mask);
cmpval = npf_match_ipmask(npc, nbuf, n_ptr, d, &addr, (npf_netmask_t)mask);
break;
case NPF_OPCODE_TABLE:
/* Source/destination, NPF table ID. */
i_ptr = nc_fetch_double(i_ptr, &n, &i);
cmpval = npf_match_ip4table(npc, nbuf, n_ptr, n, i);
cmpval = npf_match_table(npc, nbuf, n_ptr, n, i);
break;
case NPF_OPCODE_TCP_PORTS:
/* Source/destination, port range. */
@ -441,7 +450,10 @@ jmp_check:
case NPF_OPCODE_IP4MASK:
error = nc_ptr_check(&iptr, nc, sz, 3, NULL, 0);
break;
case NPF_OPCODE_IP4TABLE:
case NPF_OPCODE_IP6MASK:
error = nc_ptr_check(&iptr, nc, sz, 6, NULL, 0);
break;
case NPF_OPCODE_TABLE:
error = nc_ptr_check(&iptr, nc, sz, 2, NULL, 0);
break;
case NPF_OPCODE_TCP_PORTS:

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_sendpkt.c,v 1.4 2011/01/18 20:33:46 rmind Exp $ */
/* $NetBSD: npf_sendpkt.c,v 1.5 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.4 2011/01/18 20:33:46 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.5 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -45,6 +45,9 @@ __KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.4 2011/01/18 20:33:46 rmind Exp $"
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <netinet6/ip6_var.h>
#include <sys/mbuf.h>
#include "npf_impl.h"
@ -58,16 +61,17 @@ static int
npf_return_tcp(npf_cache_t *npc, nbuf_t *nbuf)
{
struct mbuf *m;
struct ip *oip, *ip;
struct ip *ip = NULL;
struct ip6_hdr *ip6 = NULL;
struct tcphdr *oth, *th;
tcp_seq seq, ack;
int tcpdlen, len;
uint32_t win;
/* Fetch relevant data. */
KASSERT(npf_iscached(npc, NPC_IP46 | NPC_LAYER4));
tcpdlen = npf_tcpsaw(npc, &seq, &ack, &win);
oip = &npc->npc_ip.v4;
KASSERT(npf_iscached(npc, NPC_IP46));
KASSERT(npf_iscached(npc, NPC_LAYER4));
tcpdlen = npf_tcpsaw(npc, nbuf, &seq, &ack, &win);
oth = &npc->npc_l4.tcp;
if (oth->th_flags & TH_RST) {
@ -75,7 +79,11 @@ npf_return_tcp(npf_cache_t *npc, nbuf_t *nbuf)
}
/* Create and setup a network buffer. */
len = sizeof(struct ip) + sizeof(struct tcphdr);
if (npc->npc_info & NPC_IP4)
len = sizeof(struct ip) + sizeof(struct tcphdr);
else
len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
m = m_gethdr(M_DONTWAIT, MT_HEADER);
if (m == NULL) {
return ENOMEM;
@ -84,20 +92,37 @@ npf_return_tcp(npf_cache_t *npc, nbuf_t *nbuf)
m->m_len = len;
m->m_pkthdr.len = len;
ip = mtod(m, struct ip *);
memset(ip, 0, len);
if (npc->npc_info & NPC_IP4) {
struct ip *oip = &npc->npc_ip.v4;
ip = mtod(m, struct ip *);
memset(ip, 0, len);
/*
* First fill of IPv4 header, for TCP checksum.
* Note: IP length contains TCP header length.
*/
ip->ip_p = IPPROTO_TCP;
ip->ip_src.s_addr = oip->ip_dst.s_addr;
ip->ip_dst.s_addr = oip->ip_src.s_addr;
ip->ip_len = htons(sizeof(struct tcphdr));
/*
* First fill of IPv4 header, for TCP checksum.
* Note: IP length contains TCP header length.
*/
ip->ip_p = IPPROTO_TCP;
ip->ip_src.s_addr = oip->ip_dst.s_addr;
ip->ip_dst.s_addr = oip->ip_src.s_addr;
ip->ip_len = htons(sizeof(struct tcphdr));
th = (struct tcphdr *)(ip + 1);
} else {
struct ip6_hdr *oip = &npc->npc_ip.v6;
ip6 = mtod(m, struct ip6_hdr *);
memset(ip6, 0, len);
ip6->ip6_nxt = IPPROTO_TCP;
ip6->ip6_hlim = IPV6_DEFHLIM;
memcpy(&ip6->ip6_src, &oip->ip6_dst, sizeof(struct in6_addr));
memcpy(&ip6->ip6_dst, &oip->ip6_src, sizeof(struct in6_addr));
ip6->ip6_plen = htons(len);
ip6->ip6_vfc = IPV6_VERSION;
th = (struct tcphdr *)(ip6 + 1);
}
/* Construct TCP header and compute the checksum. */
th = (struct tcphdr *)(ip + 1);
th->th_sport = oth->th_dport;
th->th_dport = oth->th_sport;
th->th_seq = htonl(ack);
@ -107,33 +132,48 @@ npf_return_tcp(npf_cache_t *npc, nbuf_t *nbuf)
th->th_ack = htonl(seq + tcpdlen);
th->th_off = sizeof(struct tcphdr) >> 2;
th->th_flags = TH_ACK | TH_RST;
th->th_sum = in_cksum(m, len);
/* Second fill of IPv4 header, fill correct IP length. */
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(struct ip) >> 2;
ip->ip_tos = IPTOS_LOWDELAY;
ip->ip_len = htons(len);
ip->ip_ttl = DEFAULT_IP_TTL;
if (npc->npc_info & NPC_IP4) {
th->th_sum = in_cksum(m, len);
/* Second fill of IPv4 header, fill correct IP length. */
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(struct ip) >> 2;
ip->ip_tos = IPTOS_LOWDELAY;
ip->ip_len = htons(len);
ip->ip_ttl = DEFAULT_IP_TTL;
} else {
th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr), sizeof(struct tcphdr));
}
/* Pass to IP layer. */
return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
if (npc->npc_info & NPC_IP4) {
return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
} else {
return ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL);
}
}
/*
* npf_return_icmp: return an ICMP error.
*/
static int
npf_return_icmp(nbuf_t *nbuf)
npf_return_icmp(npf_cache_t *npc, nbuf_t *nbuf)
{
struct mbuf *m = nbuf;
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_ADMIN_PROHIBIT, 0, 0);
if (npf_iscached(npc, NPC_IP4)) {
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_ADMIN_PROHIBIT, 0, 0);
} else {
KASSERT(npf_iscached(npc, NPC_IP6));
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN, 0);
}
return 0;
}
/*
* npf_return_block: return TCP reset or ICMP host unreachable packet.
* TODO: user should be able to specify exact ICMP error codes in config
*/
void
npf_return_block(npf_cache_t *npc, nbuf_t *nbuf, const int retfl)
@ -154,7 +194,7 @@ npf_return_block(npf_cache_t *npc, nbuf_t *nbuf, const int retfl)
break;
case IPPROTO_UDP:
if (retfl & NPF_RULE_RETICMP) {
(void)npf_return_icmp(nbuf);
(void)npf_return_icmp(npc, nbuf);
}
break;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_session.c,v 1.8 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npf_session.c,v 1.9 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
@ -74,7 +74,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.8 2011/02/02 02:20:25 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.9 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -506,7 +506,8 @@ npf_session_establish(const npf_cache_t *npc, nbuf_t *nbuf, const int di)
if (!sess_tracking) {
return NULL;
}
KASSERT(npf_iscached(npc, NPC_IP46 | NPC_LAYER4));
KASSERT(npf_iscached(npc, NPC_IP46));
KASSERT(npf_iscached(npc, NPC_LAYER4));
/* Allocate and initialise new state. */
se = pool_cache_get(sess_cache, PR_NOWAIT);

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_state.c,v 1.4 2011/04/25 22:16:21 yamt Exp $ */
/* $NetBSD: npf_state.c,v 1.5 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
@ -34,7 +34,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.4 2011/04/25 22:16:21 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.5 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -85,7 +85,7 @@ npf_tcp_inwindow(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst,
uint32_t win;
KASSERT(npf_iscached(npc, NPC_TCP));
tcpdlen = npf_tcpsaw(__UNCONST(npc), &seq, &ack, &win);
tcpdlen = npf_tcpsaw(__UNCONST(npc), nbuf, &seq, &ack, &win);
end = seq + tcpdlen;
if (tcpfl & TH_SYN) {
end++;
@ -326,7 +326,8 @@ npf_state_init(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst)
{
const int proto = npf_cache_ipproto(npc);
KASSERT(npf_iscached(npc, NPC_IP46 | NPC_LAYER4));
KASSERT(npf_iscached(npc, NPC_IP46));
KASSERT(npf_iscached(npc, NPC_LAYER4));
mutex_init(&nst->nst_lock, MUTEX_DEFAULT, IPL_SOFTNET);

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_tableset.c,v 1.5 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npf_tableset.c,v 1.6 2011/11/04 01:00:27 zoltan Exp $ */
/*-
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.5 2011/02/02 02:20:25 rmind Exp $");
__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.6 2011/11/04 01:00:27 zoltan Exp $");
#include <sys/param.h>
#include <sys/kernel.h>
@ -63,8 +63,8 @@ struct npf_tblent {
rb_node_t rbnode;
} te_entry;
/* IPv4 CIDR block. */
in_addr_t te_addr;
in_addr_t te_mask;
npf_addr_t te_addr;
npf_netmask_t te_mask;
};
LIST_HEAD(npf_hashl, npf_tblent);
@ -163,28 +163,18 @@ table_rbtree_cmp_nodes(void *ctx, const void *n1, const void *n2)
{
const npf_tblent_t * const te1 = n1;
const npf_tblent_t * const te2 = n2;
const in_addr_t x = te1->te_addr & te1->te_mask;
const in_addr_t y = te2->te_addr & te2->te_mask;
if (x < y)
return -1;
if (x > y)
return 1;
return 0;
return npf_compare_cidr(&te1->te_addr, te1->te_mask,
&te2->te_addr, te2->te_mask);
}
static signed int
table_rbtree_cmp_key(void *ctx, const void *n1, const void *key)
{
const npf_tblent_t * const te = n1;
const in_addr_t x = te->te_addr & te->te_mask;
const in_addr_t y = *(const in_addr_t *)key;
const npf_addr_t *t2 = key;
if (x < y)
return -1;
if (x > y)
return 1;
return 0;
return npf_compare_cidr(&te->te_addr, te->te_mask, t2, NPF_NO_NETMASK);
}
static const rb_tree_ops_t table_rbtree_ops = {
@ -199,7 +189,7 @@ static const rb_tree_ops_t table_rbtree_ops = {
*/
static inline struct npf_hashl *
table_hash_bucket(npf_table_t *t, void *buf, size_t sz)
table_hash_bucket(npf_table_t *t, const void *buf, size_t sz)
{
const uint32_t hidx = hash32_buf(buf, sz, HASH32_BUF_INIT);
@ -348,21 +338,21 @@ npf_table_check(npf_tableset_t *tset, u_int tid, int type)
}
/*
* npf_table_add_v4cidr: add an IPv4 CIDR into the table.
* npf_table_add_cidr: add an IPv4 or IPv6 CIDR into the table.
*/
int
npf_table_add_v4cidr(npf_tableset_t *tset, u_int tid,
in_addr_t addr, in_addr_t mask)
npf_table_add_cidr(npf_tableset_t *tset, u_int tid,
const npf_addr_t *addr, const npf_netmask_t mask)
{
struct npf_hashl *htbl;
npf_tblent_t *e, *it;
npf_table_t *t;
in_addr_t val;
npf_addr_t val;
int error = 0;
/* Allocate and setup entry. */
e = pool_cache_get(tblent_cache, PR_WAITOK);
e->te_addr = addr;
memcpy(&e->te_addr, addr, sizeof(npf_addr_t));
e->te_mask = mask;
/* Locks the table. */
@ -374,12 +364,19 @@ npf_table_add_v4cidr(npf_tableset_t *tset, u_int tid,
switch (t->t_type) {
case NPF_TABLE_HASH:
/* Generate hash value from: address & mask. */
val = addr & mask;
htbl = table_hash_bucket(t, &val, sizeof(in_addr_t));
npf_calculate_masked_addr(&val, addr, mask);
htbl = table_hash_bucket(t, &val, sizeof(npf_addr_t));
/* Lookup to check for duplicates. */
LIST_FOREACH(it, htbl, te_entry.hashq) {
if (it->te_addr == addr && it->te_mask == mask)
break;
if (it->te_mask == mask) {
const uint32_t *addr1 = it->te_addr.s6_addr32;
const uint32_t *addr2 = addr->s6_addr32;
const size_t len = sizeof(npf_addr_t);
if (memcmp(addr1, addr2, len) == 0) {
break;
}
}
}
/* If no duplicate - insert entry. */
if (__predict_true(it == NULL)) {
@ -409,13 +406,13 @@ npf_table_add_v4cidr(npf_tableset_t *tset, u_int tid,
* npf_table_rem_v4cidr: remove an IPv4 CIDR from the table.
*/
int
npf_table_rem_v4cidr(npf_tableset_t *tset, u_int tid,
in_addr_t addr, in_addr_t mask)
npf_table_rem_cidr(npf_tableset_t *tset, u_int tid,
const npf_addr_t *addr, const npf_netmask_t mask)
{
struct npf_hashl *htbl;
npf_tblent_t *e;
npf_table_t *t;
in_addr_t val;
npf_addr_t val;
int error;
e = NULL;
@ -429,11 +426,18 @@ npf_table_rem_v4cidr(npf_tableset_t *tset, u_int tid,
switch (t->t_type) {
case NPF_TABLE_HASH:
/* Generate hash value from: (address & mask). */
val = addr & mask;
htbl = table_hash_bucket(t, &val, sizeof(in_addr_t));
npf_calculate_masked_addr(&val, addr, mask);
htbl = table_hash_bucket(t, &val, sizeof(npf_addr_t));
LIST_FOREACH(e, htbl, te_entry.hashq) {
if (e->te_addr == addr && e->te_mask == mask)
break;
if (e->te_mask == mask) {
const uint32_t *addr1 = e->te_addr.s6_addr32;
const uint32_t *addr2 = addr->s6_addr32;
const size_t len = sizeof(npf_addr_t);
if (memcmp(addr1, addr2, len) == 0) {
break;
}
}
}
if (__predict_true(e != NULL)) {
LIST_REMOVE(e, te_entry.hashq);
@ -443,7 +447,7 @@ npf_table_rem_v4cidr(npf_tableset_t *tset, u_int tid,
break;
case NPF_TABLE_RBTREE:
/* Key: (address & mask). */
val = addr & mask;
npf_calculate_masked_addr(&val, addr, mask);
e = rb_tree_find_node(&t->t_rbtree, &val);
if (__predict_true(e != NULL)) {
rb_tree_remove_node(&t->t_rbtree, e);
@ -464,11 +468,11 @@ npf_table_rem_v4cidr(npf_tableset_t *tset, u_int tid,
}
/*
* npf_table_match_v4addr: find the table according to ID, lookup and
* npf_table_match_addr: find the table according to ID, lookup and
* match the contents with specified IPv4 address.
*/
int
npf_table_match_v4addr(u_int tid, in_addr_t ip4addr)
npf_table_match_addr(u_int tid, const npf_addr_t *addr)
{
struct npf_hashl *htbl;
npf_tblent_t *e = NULL;
@ -481,16 +485,17 @@ npf_table_match_v4addr(u_int tid, in_addr_t ip4addr)
}
switch (t->t_type) {
case NPF_TABLE_HASH:
htbl = table_hash_bucket(t, &ip4addr, sizeof(in_addr_t));
htbl = table_hash_bucket(t, addr, sizeof(npf_addr_t));
LIST_FOREACH(e, htbl, te_entry.hashq) {
if ((ip4addr & e->te_mask) == e->te_addr) {
break;
}
if (npf_compare_cidr(addr, e->te_mask, &e->te_addr, NPF_NO_NETMASK) == 0)
break;
}
break;
case NPF_TABLE_RBTREE:
e = rb_tree_find_node(&t->t_rbtree, &ip4addr);
KASSERT((ip4addr & e->te_mask) == e->te_addr);
e = rb_tree_find_node(&t->t_rbtree, addr);
if (e != NULL) {
KASSERT(npf_compare_cidr(addr, e->te_mask, &e->te_addr, NPF_NO_NETMASK) == 0);
}
break;
default:
KASSERT(false);

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_data.c,v 1.7 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npf_data.c,v 1.8 2011/11/04 01:00:28 zoltan Exp $ */
/*-
* Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: npf_data.c,v 1.7 2011/02/02 02:20:25 rmind Exp $");
__RCSID("$NetBSD: npf_data.c,v 1.8 2011/11/04 01:00:28 zoltan Exp $");
#include <sys/types.h>
#include <sys/socket.h>
@ -86,14 +86,14 @@ npfctl_ioctl_send(int fd)
*/
struct ifaddrs *
npfctl_getif(char *ifname, unsigned int *if_idx, bool reqaddr)
npfctl_getif(char *ifname, unsigned int *if_idx, bool reqaddr, sa_family_t addrtype)
{
struct ifaddrs *ifent;
struct sockaddr_in *sin;
for (ifent = ifs_list; ifent != NULL; ifent = ifent->ifa_next) {
sin = (struct sockaddr_in *)ifent->ifa_addr;
if (sin->sin_family != AF_INET && reqaddr)
if (sin->sin_family != addrtype && reqaddr)
continue;
if (strcmp(ifent->ifa_name, ifname) == 0)
break;
@ -104,27 +104,6 @@ npfctl_getif(char *ifname, unsigned int *if_idx, bool reqaddr)
return ifent;
}
bool
npfctl_parse_v4mask(char *ostr, in_addr_t *addr, in_addr_t *mask)
{
char *str = xstrdup(ostr);
char *p = strchr(str, '/');
u_int bits;
bool ret;
/* In network byte order. */
if (p) {
*p++ = '\0';
bits = (u_int)atoi(p);
*mask = bits ? htonl(0xffffffff << (32 - bits)) : 0;
} else {
*mask = 0xffffffff;
}
ret = inet_aton(str, (struct in_addr *)addr) != 0;
free(str);
return ret;
}
bool
npfctl_parse_port(char *ostr, bool *range, in_port_t *fport, in_port_t *tport)
{
@ -154,29 +133,90 @@ npfctl_parse_port(char *ostr, bool *range, in_port_t *fport, in_port_t *tport)
}
void
npfctl_parse_cidr(char *str, in_addr_t *addr, in_addr_t *mask)
npfctl_create_mask(sa_family_t family, u_int length, npf_addr_t *omask)
{
uint32_t part;
uint32_t *mask = (uint32_t*)omask;
memset(omask, 0, sizeof(npf_addr_t));
if (family == AF_INET) {
part = htonl(0xffffffff << (32 - length));
memcpy(mask, &part, 4);
} else if (family == AF_INET6) {
while (length > 32) {
part = htonl(0xffffffff);
memcpy(mask, &part, 4);
mask += 1;
length -= 32;
}
part = htonl(0xffffffff << (32 - length));
memcpy(mask, &part, 4);
}
}
sa_family_t
npfctl_get_addrfamily(const char *ostr)
{
struct addrinfo hint, *res = NULL;
int ret;
char *str = xstrdup(ostr);
char *p = strchr(str, '/');
sa_family_t family;
if (p)
*p = '\0';
memset(&hint, '\0', sizeof(hint));
hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo(str, NULL, &hint, &res);
if (ret) {
family = AF_UNSPEC;
} else {
family = res->ai_family;
}
freeaddrinfo(res);
free(str);
return family;
}
sa_family_t
npfctl_parse_cidr(char *str, sa_family_t addrfamily, npf_addr_t *addr, npf_netmask_t *mask)
{
if (strcmp(str, "any") == 0) {
*addr = 0x0;
*mask = 0x0;
memset(addr, 0, sizeof(npf_addr_t));
memset(mask, 0, sizeof(npf_netmask_t));
} else if (isalpha((unsigned char)*str)) {
/* TODO: handle multiple addresses per interface */
struct ifaddrs *ifa;
struct sockaddr_in *sin;
u_int idx;
if ((ifa = npfctl_getif(str, &idx, true)) == NULL) {
if ((ifa = npfctl_getif(str, &idx, true, AF_INET)) == NULL) {
errx(EXIT_FAILURE, "invalid interface '%s'", str);
}
/* Interface address. */
sin = (struct sockaddr_in *)ifa->ifa_addr;
*addr = sin->sin_addr.s_addr;
*mask = 0xffffffff;
} else if (!npfctl_parse_v4mask(str, addr, mask)) {
errx(EXIT_FAILURE, "invalid CIDR '%s'\n", str);
memcpy(addr, &(sin->sin_addr.s_addr), sizeof(struct in_addr));
//v4mask = 0xffffffff; - TODO!
} else {
char *p = strchr(str, '/');
if (p != NULL) {
*p++ = '\0';
*mask = atoi(p);
} else {
if (addrfamily == AF_INET)
*mask = 32;
else
*mask = 128;
}
memset(addr, 0, sizeof(npf_addr_t));
int ret = inet_pton(addrfamily, str, addr);
if (ret != 1) {
printf("TODO: error");
}
}
return addrfamily;
}
static bool
@ -228,18 +268,18 @@ npfctl_fill_table(nl_table_t *tl, char *fname)
l = 1;
buf = NULL;
while (getline(&buf, &n, fp) != -1) {
in_addr_t addr, mask;
npf_addr_t addr;
npf_netmask_t mask;
if (*buf == '\n' || *buf == '#')
continue;
/* IPv4 CIDR: a.b.c.d/mask */
if (!npfctl_parse_v4mask(buf, &addr, &mask)) {
if (!npfctl_parse_cidr(buf, npfctl_get_addrfamily(buf), &addr, &mask)) {
errx(EXIT_FAILURE, "invalid table entry at line %d", l);
}
/* Create and add table entry. */
npf_table_add_entry(tl, addr, mask);
npf_table_add_entry(tl, &addr, mask);
l++;
}
if (buf != NULL) {
@ -252,7 +292,7 @@ npfctl_fill_table(nl_table_t *tl, char *fname)
*/
static void
npfctl_rulenc_v4cidr(void **nc, int nblocks[], var_t *dat, bool sd)
npfctl_rulenc_cidr(void **nc, int nblocks[], var_t *dat, bool sd, sa_family_t addrfamily)
{
element_t *el = dat->v_elements;
int foff;
@ -267,15 +307,21 @@ npfctl_rulenc_v4cidr(void **nc, int nblocks[], var_t *dat, bool sd)
return;
}
/* Generate v4 CIDR matching blocks. */
/* Generate v4/v6 CIDR matching blocks. */
for (el = dat->v_elements; el != NULL; el = el->e_next) {
in_addr_t addr, mask;
npf_addr_t addr;
npf_netmask_t mask;
npfctl_parse_cidr(el->e_data, &addr, &mask);
nblocks[1]--;
npfctl_parse_cidr(el->e_data, addrfamily, &addr, &mask);
if (addrfamily == AF_INET)
nblocks[1]--;
else if (addrfamily == AF_INET6)
nblocks[3]--;
foff = npfctl_failure_offset(nblocks);
npfctl_gennc_v4cidr(nc, foff, addr, mask, sd);
if (addrfamily == AF_INET)
npfctl_gennc_v4cidr(nc, foff, &addr, mask, sd);
else if (addrfamily == AF_INET6)
npfctl_gennc_v6cidr(nc, foff, &addr, mask, sd);
}
}
@ -304,10 +350,10 @@ npfctl_rulenc_ports(void **nc, int nblocks[], var_t *dat, bool tcpudp,
static void
npfctl_rulenc_block(void **nc, int nblocks[], var_t *cidr, var_t *ports,
bool both, bool tcpudp, bool sd)
bool both, bool tcpudp, bool sd, sa_family_t addrfamily)
{
npfctl_rulenc_v4cidr(nc, nblocks, cidr, sd);
npfctl_rulenc_cidr(nc, nblocks, cidr, sd, addrfamily);
if (ports == NULL) {
return;
}
@ -320,9 +366,9 @@ npfctl_rulenc_block(void **nc, int nblocks[], var_t *cidr, var_t *ports,
void
npfctl_rule_ncode(nl_rule_t *rl, char *proto, char *tcpfl, int icmp_type,
int icmp_code, var_t *from, var_t *fports, var_t *to, var_t *tports)
int icmp_code, var_t *from, sa_family_t addrfamily, var_t *fports, var_t *to, var_t *tports)
{
int nblocks[3] = { 0, 0, 0 };
int nblocks[4] = { 0, 0, 0, 0 };
bool icmp, tcpudp, both;
void *ncptr, *nc;
size_t sz, foff;
@ -370,22 +416,30 @@ skip_proto:
if (from && from->v_count) {
if (from->v_type == VAR_TABLE)
nblocks[0] += 1;
else
nblocks[1] += from->v_count;
else {
if (addrfamily == AF_INET)
nblocks[1] += from->v_count;
else
nblocks[3] += from->v_count;
}
if (fports && fports->v_count)
nblocks[0] += fports->v_count * (both ? 2 : 1);
}
if (to && to->v_count) {
if (to->v_type == VAR_TABLE)
nblocks[0] += 1;
else
nblocks[1] += to->v_count;
else {
if (addrfamily == AF_INET)
nblocks[1] += to->v_count;
else
nblocks[3] += to->v_count;
}
if (tports && tports->v_count)
nblocks[0] += tports->v_count * (both ? 2 : 1);
}
/* Any n-code to generate? */
if (!icmp && (nblocks[0] + nblocks[1] + nblocks[2]) == 0) {
if (!icmp && (nblocks[0] + nblocks[1] + nblocks[2] + nblocks[3]) == 0) {
/* Done, if none. */
return;
}
@ -399,15 +453,15 @@ skip_proto:
nc = ncptr;
/*
* Generate v4 CIDR matching blocks and TCP/UDP port matching.
* Generate v4/v6 CIDR matching blocks and TCP/UDP port matching.
*/
if (from) {
npfctl_rulenc_block(&nc, nblocks, from, fports,
both, tcpudp, true);
both, tcpudp, true, addrfamily);
}
if (to) {
npfctl_rulenc_block(&nc, nblocks, to, tports,
both, tcpudp, false);
both, tcpudp, false, addrfamily);
}
if (icmp) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_ncgen.c,v 1.4 2010/12/18 01:07:26 rmind Exp $ */
/* $NetBSD: npf_ncgen.c,v 1.5 2011/11/04 01:00:28 zoltan Exp $ */
/*-
* Copyright (c) 2009-2010 The NetBSD Foundation, Inc.
@ -37,9 +37,10 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: npf_ncgen.c,v 1.4 2010/12/18 01:07:26 rmind Exp $");
__RCSID("$NetBSD: npf_ncgen.c,v 1.5 2011/11/04 01:00:28 zoltan Exp $");
#include <sys/types.h>
#include <string.h>
#include "npfctl.h"
@ -54,11 +55,13 @@ npfctl_calc_ncsize(int nblocks[])
* - 5 words each by npfctl_gennc_ports/tbl(), stored in nblocks[0].
* - 6 words each by npfctl_gennc_v4cidr(), stored in nblocks[1].
* - 4 words by npfctl_gennc_{icmp,tcpfl}(), stored in nblocks[2].
* - 9 words each by npfctl_gennc_v6cidr(), stored in nblocks[3].
* - 4 words by npfctl_gennc_complete(), single last fragment.
*/
return nblocks[0] * 5 * sizeof(uint32_t) +
nblocks[1] * 6 * sizeof(uint32_t) +
nblocks[2] * 4 * sizeof(uint32_t) +
nblocks[3] * 9 * sizeof(uint32_t) +
4 * sizeof(uint32_t);
}
@ -68,7 +71,7 @@ npfctl_calc_ncsize(int nblocks[])
size_t
npfctl_failure_offset(int nblocks[])
{
size_t tblport_blocks, v4cidr_blocks, icmp_tcpfl;
size_t tblport_blocks, v4cidr_blocks, v6cidr_blocks, icmp_tcpfl;
/*
* Take into account all blocks (plus 2 words for comparison each),
* and additional 4 words to skip the last comparison and success path.
@ -76,7 +79,8 @@ npfctl_failure_offset(int nblocks[])
tblport_blocks = (3 + 2) * nblocks[0];
v4cidr_blocks = (4 + 2) * nblocks[1];
icmp_tcpfl = (2 + 2) * nblocks[2];
return tblport_blocks + v4cidr_blocks + icmp_tcpfl + 4;
v6cidr_blocks = (7 + 2) * nblocks[3];
return tblport_blocks + v4cidr_blocks + v6cidr_blocks + icmp_tcpfl + 4;
}
#if 0
@ -115,20 +119,46 @@ npfctl_gennc_ether(void **ncptr, int foff, uint16_t ethertype)
}
#endif
void
npfctl_gennc_v6cidr(void **ncptr, int foff,
const npf_addr_t *netaddr, const npf_netmask_t mask, bool sd)
{
uint32_t *nc = *ncptr;
const uint32_t *addr = (const uint32_t *)netaddr;
/* OP, direction, netaddr/subnet (10 words) */
*nc++ = NPF_OPCODE_IP6MASK;
*nc++ = (sd ? 0x01 : 0x00);
*nc++ = addr[0];
*nc++ = addr[1];
*nc++ = addr[2];
*nc++ = addr[3];
*nc++ = mask;
/* If not equal, jump to failure block, continue otherwise (2 words). */
*nc++ = NPF_OPCODE_BNE;
*nc++ = foff;
/* + 9 words. */
*ncptr = (void *)nc;
}
/*
* npfctl_gennc_v4cidr: fragment to match IPv4 CIDR.
*/
void
npfctl_gennc_v4cidr(void **ncptr, int foff,
in_addr_t netaddr, in_addr_t subnet, bool sd)
const npf_addr_t *netaddr, const npf_netmask_t mask, bool sd)
{
uint32_t *nc = *ncptr;
const uint32_t *addr = (const uint32_t *)netaddr;
/* OP, direction, netaddr/subnet (4 words) */
*nc++ = NPF_OPCODE_IP4MASK;
*nc++ = (sd ? 0x01 : 0x00);
*nc++ = netaddr;
*nc++ = subnet;
*nc++ = addr[0];
*nc++ = mask;
/* If not equal, jump to failure block, continue otherwise (2 words). */
*nc++ = NPF_OPCODE_BNE;
@ -200,7 +230,7 @@ npfctl_gennc_tbl(void **ncptr, int foff, u_int tid, bool sd)
uint32_t *nc = *ncptr;
/* OP, direction, table ID (3 words). */
*nc++ = NPF_OPCODE_IP4TABLE;
*nc++ = NPF_OPCODE_TABLE;
*nc++ = (sd ? 0x01 : 0x00);
*nc++ = tid;

View File

@ -1,4 +1,4 @@
/* $NetBSD: npf_parser.c,v 1.6 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npf_parser.c,v 1.7 2011/11/04 01:00:28 zoltan Exp $ */
/*-
* Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: npf_parser.c,v 1.6 2011/02/02 02:20:25 rmind Exp $");
__RCSID("$NetBSD: npf_parser.c,v 1.7 2011/11/04 01:00:28 zoltan Exp $");
#include <stdio.h>
#include <stdlib.h>
@ -161,7 +161,9 @@ npfctl_val_interface(var_t *v, char *p, bool reqaddr)
char *iface = npfctl_val_single(v, p);
u_int if_idx;
if (iface == NULL || npfctl_getif(iface, &if_idx, reqaddr) == NULL) {
if (iface == NULL ||
((npfctl_getif(iface, &if_idx, reqaddr, AF_INET) == NULL) &&
(npfctl_getif(iface, &if_idx, reqaddr, AF_INET6) == NULL))) {
errx(EXIT_FAILURE, "invalid interface '%s'", iface);
}
return if_idx;
@ -269,6 +271,7 @@ npfctl_parserule(char *buf, nl_rule_t *parent)
u_int if_idx = 0;
int ret, attr = 0;
nl_rule_t *rl;
sa_family_t addrfamily = AF_UNSPEC;
DPRINTF(("rule\t|%s|\n", buf));
@ -324,10 +327,11 @@ npfctl_parserule(char *buf, nl_rule_t *parent)
PARSE_NEXT_TOKEN();
}
/* inet, inet6 (TODO) */
if (strcmp(p, "inet") == 0) {
addrfamily = AF_INET;
PARSE_NEXT_TOKEN();
} else if (strcmp(p, "inet6") == 0) {
addrfamily = AF_INET6;
PARSE_NEXT_TOKEN();
}
@ -361,6 +365,8 @@ npfctl_parserule(char *buf, nl_rule_t *parent)
/* from <addr> port <port | range> */
if (strcmp(p, "from") == 0) {
PARSE_NEXT_TOKEN();
if (addrfamily == AF_UNSPEC)
addrfamily = npfctl_get_addrfamily(p);
from_v = npfctl_parsevalue(p);
PARSE_NEXT_TOKEN_NOCHECK();
@ -375,6 +381,8 @@ npfctl_parserule(char *buf, nl_rule_t *parent)
/* to <addr> port <port | range> */
if (p && strcmp(p, "to") == 0) {
PARSE_NEXT_TOKEN();
if (addrfamily == AF_UNSPEC)
addrfamily = npfctl_get_addrfamily(p);
to_v = npfctl_parsevalue(p);
PARSE_NEXT_TOKEN_NOCHECK();
@ -454,7 +462,7 @@ last:
*/
rl = npf_rule_create(NULL, attr, if_idx);
npfctl_rule_ncode(rl, proto, tcp_flags, icmp_type, icmp_code,
from_v, fports, to_v, tports);
from_v, addrfamily, fports, to_v, tports);
if (rproc && npf_rule_setproc(npf_conf, rl, rproc) != 0) {
errx(EXIT_FAILURE, "procedure '%s' is not defined", rproc);
}
@ -574,19 +582,16 @@ npfctl_parsetable(char *buf)
return PARSE_ERR();
}
PARSE_NEXT_TOKEN_NOCHECK();
if (p == NULL || *p != '"') {
if (p == NULL) {
return PARSE_ERR();
}
if (strcmp(p, "hash")) {
if (strcmp(p, "hash") == 0) {
type = NPF_TABLE_HASH;
} else if (strcmp(p, "tree")) {
} else if (strcmp(p, "tree") == 0) {
type = NPF_TABLE_RBTREE;
} else {
errx(EXIT_FAILURE, "invalid table type '%s'", p);
}
if ((p = strchr(++p, '"')) == NULL) {
return PARSE_ERR();
}
*p = '\0';
/*
@ -631,8 +636,8 @@ npfctl_parse_nat(char *buf)
var_t *ifvar, *from_v, *to_v, *raddr_v;
var_t *tports = NULL, *rport_v = NULL;
char *p, *sptr, *raddr_s, *rport_s;
in_addr_t raddr4, _dummy;
npf_addr_t raddr;
npf_netmask_t dummy;
bool binat, rdr;
nl_nat_t *nat;
u_int if_idx;
@ -702,8 +707,7 @@ npfctl_parse_nat(char *buf)
PARSE_NEXT_TOKEN();
raddr_v = npfctl_parsevalue(p);
raddr_s = npfctl_val_single(raddr_v, p);
npfctl_parse_cidr(raddr_s, &raddr4, &_dummy);
memcpy(&raddr, &raddr4, sizeof(struct in_addr)); /* XXX IPv6 */
npfctl_parse_cidr(raddr_s, npfctl_get_addrfamily(raddr_s), &raddr, &dummy);
if (rdr) {
PARSE_NEXT_TOKEN();
@ -739,7 +743,7 @@ npfctl_parse_nat(char *buf)
nat = npf_nat_create(NPF_NATIN, NPF_NAT_PORTS,
if_idx, &raddr, AF_INET, rport);
}
npfctl_rule_ncode(nat, NULL, NULL, -1, -1, from_v, NULL, to_v, tports);
npfctl_rule_ncode(nat, NULL, NULL, -1, -1, from_v, AF_INET, NULL, to_v, tports);
(void)npf_nat_insert(npf_conf, nat, NPF_PRI_NEXT);
/*
@ -751,15 +755,13 @@ npfctl_parse_nat(char *buf)
*/
if (binat) {
char *taddr_s = npfctl_val_single(from_v, NULL);
in_addr_t taddr4;
npf_addr_t taddr;
nl_nat_t *bn;
npfctl_parse_cidr(taddr_s, &taddr4, &_dummy);
memcpy(&taddr, &taddr4, sizeof(struct in_addr)); /* XXX IPv6 */
npfctl_parse_cidr(taddr_s, npfctl_get_addrfamily(taddr_s), &taddr, &dummy);
bn = npf_nat_create(NPF_NATIN, 0, if_idx, &taddr, AF_INET, 0);
npfctl_rule_ncode(bn, NULL, NULL, -1, -1,
to_v, NULL, raddr_v, NULL);
to_v, AF_INET, NULL, raddr_v, NULL);
(void)npf_nat_insert(npf_conf, bn, NPF_PRI_NEXT);
}
return 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: npfctl.c,v 1.6 2011/08/31 13:32:38 joerg Exp $ */
/* $NetBSD: npfctl.c,v 1.7 2011/11/04 01:00:28 zoltan Exp $ */
/*-
* Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: npfctl.c,v 1.6 2011/08/31 13:32:38 joerg Exp $");
__RCSID("$NetBSD: npfctl.c,v 1.7 2011/11/04 01:00:28 zoltan Exp $");
#include <sys/ioctl.h>
#include <sys/stat.h>
@ -252,7 +252,8 @@ npfctl(int action, int argc, char **argv)
tbl.nct_action = 0;
arg = argv[3];
}
if (!npfctl_parse_v4mask(arg,
if (!npfctl_parse_cidr(arg,
npfctl_get_addrfamily(arg),
&tbl.nct_addr, &tbl.nct_mask)) {
errx(EXIT_FAILURE, "invalid CIDR '%s'", arg);
}
@ -276,7 +277,7 @@ npfctl(int action, int argc, char **argv)
}
break;
}
if (ret == -1) {
if (ret) {
err(EXIT_FAILURE, "ioctl");
}
close(fd);

View File

@ -1,4 +1,4 @@
/* $NetBSD: npfctl.h,v 1.6 2011/02/02 02:20:25 rmind Exp $ */
/* $NetBSD: npfctl.h,v 1.7 2011/11/04 01:00:28 zoltan Exp $ */
/*-
* Copyright (c) 2009-2011 The NetBSD Foundation, Inc.
@ -74,22 +74,25 @@ char * xstrdup(const char *);
void npfctl_init_data(void);
int npfctl_ioctl_send(int);
struct ifaddrs *npfctl_getif(char *, unsigned int *, bool);
bool npfctl_parse_v4mask(char *, in_addr_t *, in_addr_t *);
void npfctl_parse_cidr(char *, in_addr_t *, in_addr_t *);
struct ifaddrs *npfctl_getif(char *, unsigned int *, bool, sa_family_t);
void npfctl_create_mask(sa_family_t, u_int, npf_addr_t *);
sa_family_t npfctl_get_addrfamily(const char *);
sa_family_t npfctl_parse_cidr(char *, sa_family_t, npf_addr_t *, npf_netmask_t *);
bool npfctl_parse_port(char *, bool *, in_port_t *, in_port_t *);
void npfctl_fill_table(nl_table_t *, char *);
void npfctl_rule_ncode(nl_rule_t *, char *, char *,
int, int, var_t *, var_t *, var_t *, var_t *);
int, int, var_t *, sa_family_t, var_t *, var_t *, var_t *);
size_t npfctl_calc_ncsize(int []);
size_t npfctl_failure_offset(int []);
void npfctl_gennc_ether(void **, int, uint16_t);
void npfctl_gennc_v4cidr(void **, int,
in_addr_t, in_addr_t, bool);
const npf_addr_t *, const npf_netmask_t, bool);
void npfctl_gennc_v6cidr(void **, int,
const npf_addr_t *, const npf_netmask_t, bool);
void npfctl_gennc_icmp(void **, int, int, int);
void npfctl_gennc_tcpfl(void **, int , uint8_t, uint8_t);
void npfctl_gennc_ports(void **, int,