Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
This commit is contained in:
commit
b5bb14386e
@ -223,4 +223,7 @@ config LEDS_TRIGGER_DEFAULT_ON
|
||||
This allows LEDs to be initialised in the ON state.
|
||||
If unsure, say Y.
|
||||
|
||||
comment "iptables trigger is under Netfilter config (LED target)"
|
||||
depends on LEDS_TRIGGERS
|
||||
|
||||
endif # NEW_LEDS
|
||||
|
@ -7,16 +7,21 @@ header-y += xt_CLASSIFY.h
|
||||
header-y += xt_CONNMARK.h
|
||||
header-y += xt_CONNSECMARK.h
|
||||
header-y += xt_DSCP.h
|
||||
header-y += xt_LED.h
|
||||
header-y += xt_MARK.h
|
||||
header-y += xt_NFLOG.h
|
||||
header-y += xt_NFQUEUE.h
|
||||
header-y += xt_RATEEST.h
|
||||
header-y += xt_SECMARK.h
|
||||
header-y += xt_TCPMSS.h
|
||||
header-y += xt_TCPOPTSTRIP.h
|
||||
header-y += xt_TPROXY.h
|
||||
header-y += xt_comment.h
|
||||
header-y += xt_connbytes.h
|
||||
header-y += xt_connlimit.h
|
||||
header-y += xt_connmark.h
|
||||
header-y += xt_conntrack.h
|
||||
header-y += xt_cluster.h
|
||||
header-y += xt_dccp.h
|
||||
header-y += xt_dscp.h
|
||||
header-y += xt_esp.h
|
||||
@ -30,6 +35,7 @@ header-y += xt_mark.h
|
||||
header-y += xt_multiport.h
|
||||
header-y += xt_owner.h
|
||||
header-y += xt_pkttype.h
|
||||
header-y += xt_quota.h
|
||||
header-y += xt_rateest.h
|
||||
header-y += xt_realm.h
|
||||
header-y += xt_recent.h
|
||||
@ -39,6 +45,8 @@ header-y += xt_statistic.h
|
||||
header-y += xt_string.h
|
||||
header-y += xt_tcpmss.h
|
||||
header-y += xt_tcpudp.h
|
||||
header-y += xt_time.h
|
||||
header-y += xt_u32.h
|
||||
|
||||
unifdef-y += nf_conntrack_common.h
|
||||
unifdef-y += nf_conntrack_ftp.h
|
||||
|
@ -76,6 +76,7 @@ extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n);
|
||||
extern int nfnetlink_has_listeners(unsigned int group);
|
||||
extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group,
|
||||
int echo);
|
||||
extern void nfnetlink_set_err(u32 pid, u32 group, int error);
|
||||
extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
|
||||
|
||||
extern void nfnl_lock(void);
|
||||
|
@ -349,23 +349,22 @@ struct xt_table
|
||||
{
|
||||
struct list_head list;
|
||||
|
||||
/* A unique name... */
|
||||
const char name[XT_TABLE_MAXNAMELEN];
|
||||
|
||||
/* What hooks you will enter on */
|
||||
unsigned int valid_hooks;
|
||||
|
||||
/* Lock for the curtain */
|
||||
rwlock_t lock;
|
||||
struct mutex lock;
|
||||
|
||||
/* Man behind the curtain... */
|
||||
//struct ip6t_table_info *private;
|
||||
void *private;
|
||||
struct xt_table_info *private;
|
||||
|
||||
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
|
||||
struct module *me;
|
||||
|
||||
u_int8_t af; /* address/protocol family */
|
||||
|
||||
/* A unique name... */
|
||||
const char name[XT_TABLE_MAXNAMELEN];
|
||||
};
|
||||
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
@ -386,7 +385,7 @@ struct xt_table_info
|
||||
|
||||
/* ipt_entry tables: one per CPU */
|
||||
/* Note : this field MUST be the last one, see XT_TABLE_INFO_SZ */
|
||||
char *entries[1];
|
||||
void *entries[1];
|
||||
};
|
||||
|
||||
#define XT_TABLE_INFO_SZ (offsetof(struct xt_table_info, entries) \
|
||||
@ -433,6 +432,8 @@ extern void xt_proto_fini(struct net *net, u_int8_t af);
|
||||
|
||||
extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
|
||||
extern void xt_free_table_info(struct xt_table_info *info);
|
||||
extern void xt_table_entry_swap_rcu(struct xt_table_info *old,
|
||||
struct xt_table_info *new);
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#include <net/compat.h>
|
||||
|
13
include/linux/netfilter/xt_LED.h
Normal file
13
include/linux/netfilter/xt_LED.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef _XT_LED_H
|
||||
#define _XT_LED_H
|
||||
|
||||
struct xt_led_info {
|
||||
char id[27]; /* Unique ID for this trigger in the LED class */
|
||||
__u8 always_blink; /* Blink even if the LED is already on */
|
||||
__u32 delay; /* Delay until LED is switched off after trigger */
|
||||
|
||||
/* Kernel data used in the module */
|
||||
void *internal_data __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
#endif /* _XT_LED_H */
|
15
include/linux/netfilter/xt_cluster.h
Normal file
15
include/linux/netfilter/xt_cluster.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _XT_CLUSTER_MATCH_H
|
||||
#define _XT_CLUSTER_MATCH_H
|
||||
|
||||
enum xt_cluster_flags {
|
||||
XT_CLUSTER_F_INV = (1 << 0)
|
||||
};
|
||||
|
||||
struct xt_cluster_match_info {
|
||||
u_int32_t total_nodes;
|
||||
u_int32_t node_mask;
|
||||
u_int32_t hash_seed;
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
#endif /* _XT_CLUSTER_MATCH_H */
|
@ -4,6 +4,8 @@
|
||||
/* timings are in milliseconds. */
|
||||
#define XT_LIMIT_SCALE 10000
|
||||
|
||||
struct xt_limit_priv;
|
||||
|
||||
/* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490
|
||||
seconds, or one every 59 hours. */
|
||||
struct xt_rateinfo {
|
||||
@ -11,11 +13,10 @@ struct xt_rateinfo {
|
||||
u_int32_t burst; /* Period multiplier for upper limit. */
|
||||
|
||||
/* Used internally by the kernel */
|
||||
unsigned long prev;
|
||||
u_int32_t credit;
|
||||
unsigned long prev; /* moved to xt_limit_priv */
|
||||
u_int32_t credit; /* moved to xt_limit_priv */
|
||||
u_int32_t credit_cap, cost;
|
||||
|
||||
/* Ugly, ugly fucker. */
|
||||
struct xt_rateinfo *master;
|
||||
struct xt_limit_priv *master;
|
||||
};
|
||||
#endif /*_XT_RATE_H*/
|
||||
|
@ -6,13 +6,15 @@ enum xt_quota_flags {
|
||||
};
|
||||
#define XT_QUOTA_MASK 0x1
|
||||
|
||||
struct xt_quota_priv;
|
||||
|
||||
struct xt_quota_info {
|
||||
u_int32_t flags;
|
||||
u_int32_t pad;
|
||||
|
||||
/* Used internally by the kernel */
|
||||
aligned_u64 quota;
|
||||
struct xt_quota_info *master;
|
||||
struct xt_quota_priv *master;
|
||||
};
|
||||
|
||||
#endif /* _XT_QUOTA_H */
|
||||
|
@ -13,6 +13,8 @@ enum xt_statistic_flags {
|
||||
};
|
||||
#define XT_STATISTIC_MASK 0x1
|
||||
|
||||
struct xt_statistic_priv;
|
||||
|
||||
struct xt_statistic_info {
|
||||
u_int16_t mode;
|
||||
u_int16_t flags;
|
||||
@ -23,11 +25,10 @@ struct xt_statistic_info {
|
||||
struct {
|
||||
u_int32_t every;
|
||||
u_int32_t packet;
|
||||
/* Used internally by the kernel */
|
||||
u_int32_t count;
|
||||
u_int32_t count; /* unused */
|
||||
} nth;
|
||||
} u;
|
||||
struct xt_statistic_info *master __attribute__((aligned(8)));
|
||||
struct xt_statistic_priv *master __attribute__((aligned(8)));
|
||||
};
|
||||
|
||||
#endif /* _XT_STATISTIC_H */
|
||||
|
@ -11,6 +11,7 @@ header-y += ip6t_length.h
|
||||
header-y += ip6t_limit.h
|
||||
header-y += ip6t_mac.h
|
||||
header-y += ip6t_mark.h
|
||||
header-y += ip6t_mh.h
|
||||
header-y += ip6t_multiport.h
|
||||
header-y += ip6t_opts.h
|
||||
header-y += ip6t_owner.h
|
||||
|
@ -287,7 +287,7 @@ static inline int nf_ct_is_untracked(const struct sk_buff *skb)
|
||||
|
||||
extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp);
|
||||
extern unsigned int nf_conntrack_htable_size;
|
||||
extern int nf_conntrack_max;
|
||||
extern unsigned int nf_conntrack_max;
|
||||
|
||||
#define NF_CT_STAT_INC(net, count) \
|
||||
(per_cpu_ptr((net)->ct.stat, raw_smp_processor_id())->count++)
|
||||
|
@ -90,10 +90,7 @@ struct nf_conntrack_l4proto
|
||||
struct module *me;
|
||||
};
|
||||
|
||||
/* Existing built-in protocols */
|
||||
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6;
|
||||
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4;
|
||||
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6;
|
||||
/* Existing built-in generic protocol */
|
||||
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic;
|
||||
|
||||
#define MAX_NF_CT_PROTO 256
|
||||
@ -101,11 +98,6 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic;
|
||||
extern struct nf_conntrack_l4proto *
|
||||
__nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto);
|
||||
|
||||
extern struct nf_conntrack_l4proto *
|
||||
nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t protocol);
|
||||
|
||||
extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p);
|
||||
|
||||
/* Protocol registration. */
|
||||
extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto);
|
||||
extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto);
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef _NF_LOG_H
|
||||
#define _NF_LOG_H
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
|
||||
/* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will
|
||||
* disappear once iptables is replaced with pkttables. Please DO NOT use them
|
||||
* for any new code! */
|
||||
@ -40,12 +42,15 @@ struct nf_logger {
|
||||
struct module *me;
|
||||
nf_logfn *logfn;
|
||||
char *name;
|
||||
struct list_head list[NFPROTO_NUMPROTO];
|
||||
};
|
||||
|
||||
/* Function to register/unregister log function. */
|
||||
int nf_log_register(u_int8_t pf, const struct nf_logger *logger);
|
||||
void nf_log_unregister(const struct nf_logger *logger);
|
||||
void nf_log_unregister_pf(u_int8_t pf);
|
||||
int nf_log_register(u_int8_t pf, struct nf_logger *logger);
|
||||
void nf_log_unregister(struct nf_logger *logger);
|
||||
|
||||
int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger);
|
||||
void nf_log_unbind_pf(u_int8_t pf);
|
||||
|
||||
/* Calls the registered backend logging function */
|
||||
void nf_log_packet(u_int8_t pf,
|
||||
|
@ -46,7 +46,6 @@ static struct ebt_table broute_table =
|
||||
.name = "broute",
|
||||
.table = &initial_table,
|
||||
.valid_hooks = 1 << NF_BR_BROUTING,
|
||||
.lock = __RW_LOCK_UNLOCKED(broute_table.lock),
|
||||
.check = check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@ -55,7 +55,6 @@ static struct ebt_table frame_filter =
|
||||
.name = "filter",
|
||||
.table = &initial_table,
|
||||
.valid_hooks = FILTER_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(frame_filter.lock),
|
||||
.check = check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@ -55,7 +55,6 @@ static struct ebt_table frame_nat =
|
||||
.name = "nat",
|
||||
.table = &initial_table,
|
||||
.valid_hooks = NAT_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(frame_nat.lock),
|
||||
.check = check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@ -31,7 +31,7 @@ config NF_CONNTRACK_PROC_COMPAT
|
||||
default y
|
||||
help
|
||||
This option enables /proc and sysctl compatibility with the old
|
||||
layer 3 dependant connection tracking. This is needed to keep
|
||||
layer 3 dependent connection tracking. This is needed to keep
|
||||
old programs that have not been adapted to the new names working.
|
||||
|
||||
If unsure, say Y.
|
||||
@ -95,11 +95,11 @@ config IP_NF_MATCH_ECN
|
||||
config IP_NF_MATCH_TTL
|
||||
tristate '"ttl" match support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
help
|
||||
This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user
|
||||
to match packets by their TTL value.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
select NETFILTER_XT_MATCH_HL
|
||||
---help---
|
||||
This is a backwards-compat option for the user's convenience
|
||||
(e.g. when running oldconfig). It selects
|
||||
CONFIG_NETFILTER_XT_MATCH_HL.
|
||||
|
||||
# `filter', generic and specific targets
|
||||
config IP_NF_FILTER
|
||||
@ -323,19 +323,13 @@ config IP_NF_TARGET_ECN
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP_NF_TARGET_TTL
|
||||
tristate 'TTL target support'
|
||||
depends on IP_NF_MANGLE
|
||||
tristate '"TTL" target support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
help
|
||||
This option adds a `TTL' target, which enables the user to modify
|
||||
the TTL value of the IP header.
|
||||
|
||||
While it is safe to decrement/lower the TTL, this target also enables
|
||||
functionality to increment and set the TTL value of the IP header to
|
||||
arbitrary values. This is EXTREMELY DANGEROUS since you can easily
|
||||
create immortal packets that loop forever on the network.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
select NETFILTER_XT_TARGET_HL
|
||||
---help---
|
||||
This is a backwards-compat option for the user's convenience
|
||||
(e.g. when running oldconfig). It selects
|
||||
CONFIG_NETFILTER_XT_TARGET_HL.
|
||||
|
||||
# raw + specific targets
|
||||
config IP_NF_RAW
|
||||
|
@ -51,7 +51,6 @@ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
|
||||
obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
|
||||
obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
|
||||
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
|
||||
obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
|
||||
|
||||
# targets
|
||||
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
|
||||
@ -61,7 +60,6 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
|
||||
|
||||
# generic ARP tables
|
||||
|
@ -73,6 +73,36 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
|
||||
return (ret != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunatly, _b and _mask are not aligned to an int (or long int)
|
||||
* Some arches dont care, unrolling the loop is a win on them.
|
||||
*/
|
||||
static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
|
||||
{
|
||||
#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||
const unsigned long *a = (const unsigned long *)_a;
|
||||
const unsigned long *b = (const unsigned long *)_b;
|
||||
const unsigned long *mask = (const unsigned long *)_mask;
|
||||
unsigned long ret;
|
||||
|
||||
ret = (a[0] ^ b[0]) & mask[0];
|
||||
if (IFNAMSIZ > sizeof(unsigned long))
|
||||
ret |= (a[1] ^ b[1]) & mask[1];
|
||||
if (IFNAMSIZ > 2 * sizeof(unsigned long))
|
||||
ret |= (a[2] ^ b[2]) & mask[2];
|
||||
if (IFNAMSIZ > 3 * sizeof(unsigned long))
|
||||
ret |= (a[3] ^ b[3]) & mask[3];
|
||||
BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
|
||||
#else
|
||||
unsigned long ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IFNAMSIZ; i++)
|
||||
ret |= (_a[i] ^ _b[i]) & _mask[i];
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns whether packet matches rule or not. */
|
||||
static inline int arp_packet_match(const struct arphdr *arphdr,
|
||||
struct net_device *dev,
|
||||
@ -83,7 +113,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
|
||||
const char *arpptr = (char *)(arphdr + 1);
|
||||
const char *src_devaddr, *tgt_devaddr;
|
||||
__be32 src_ipaddr, tgt_ipaddr;
|
||||
int i, ret;
|
||||
long ret;
|
||||
|
||||
#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg)))
|
||||
|
||||
@ -156,10 +186,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
|
||||
}
|
||||
|
||||
/* Look for ifname matches. */
|
||||
for (i = 0, ret = 0; i < IFNAMSIZ; i++) {
|
||||
ret |= (indev[i] ^ arpinfo->iniface[i])
|
||||
& arpinfo->iniface_mask[i];
|
||||
}
|
||||
ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);
|
||||
|
||||
if (FWINV(ret != 0, ARPT_INV_VIA_IN)) {
|
||||
dprintf("VIA in mismatch (%s vs %s).%s\n",
|
||||
@ -168,10 +195,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0, ret = 0; i < IFNAMSIZ; i++) {
|
||||
ret |= (outdev[i] ^ arpinfo->outiface[i])
|
||||
& arpinfo->outiface_mask[i];
|
||||
}
|
||||
ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);
|
||||
|
||||
if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) {
|
||||
dprintf("VIA out mismatch (%s vs %s).%s\n",
|
||||
@ -221,7 +245,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
||||
const struct net_device *out,
|
||||
struct xt_table *table)
|
||||
{
|
||||
static const char nulldevname[IFNAMSIZ];
|
||||
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
|
||||
unsigned int verdict = NF_DROP;
|
||||
const struct arphdr *arp;
|
||||
bool hotdrop = false;
|
||||
@ -237,9 +261,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
||||
indev = in ? in->name : nulldevname;
|
||||
outdev = out ? out->name : nulldevname;
|
||||
|
||||
read_lock_bh(&table->lock);
|
||||
private = table->private;
|
||||
table_base = (void *)private->entries[smp_processor_id()];
|
||||
rcu_read_lock();
|
||||
private = rcu_dereference(table->private);
|
||||
table_base = rcu_dereference(private->entries[smp_processor_id()]);
|
||||
|
||||
e = get_entry(table_base, private->hook_entry[hook]);
|
||||
back = get_entry(table_base, private->underflow[hook]);
|
||||
|
||||
@ -311,7 +336,8 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
||||
e = (void *)e + e->next_offset;
|
||||
}
|
||||
} while (!hotdrop);
|
||||
read_unlock_bh(&table->lock);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (hotdrop)
|
||||
return NF_DROP;
|
||||
@ -714,11 +740,65 @@ static void get_counters(const struct xt_table_info *t,
|
||||
}
|
||||
}
|
||||
|
||||
static inline struct xt_counters *alloc_counters(struct xt_table *table)
|
||||
|
||||
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
||||
* and everything is OK. */
|
||||
static int
|
||||
add_counter_to_entry(struct arpt_entry *e,
|
||||
const struct xt_counters addme[],
|
||||
unsigned int *i)
|
||||
{
|
||||
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
||||
|
||||
(*i)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Take values from counters and add them back onto the current cpu */
|
||||
static void put_counters(struct xt_table_info *t,
|
||||
const struct xt_counters counters[])
|
||||
{
|
||||
unsigned int i, cpu;
|
||||
|
||||
local_bh_disable();
|
||||
cpu = smp_processor_id();
|
||||
i = 0;
|
||||
ARPT_ENTRY_ITERATE(t->entries[cpu],
|
||||
t->size,
|
||||
add_counter_to_entry,
|
||||
counters,
|
||||
&i);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
static inline int
|
||||
zero_entry_counter(struct arpt_entry *e, void *arg)
|
||||
{
|
||||
e->counters.bcnt = 0;
|
||||
e->counters.pcnt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
|
||||
{
|
||||
unsigned int cpu;
|
||||
const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
|
||||
|
||||
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
|
||||
for_each_possible_cpu(cpu) {
|
||||
memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
|
||||
ARPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
|
||||
zero_entry_counter, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static struct xt_counters *alloc_counters(struct xt_table *table)
|
||||
{
|
||||
unsigned int countersize;
|
||||
struct xt_counters *counters;
|
||||
const struct xt_table_info *private = table->private;
|
||||
struct xt_table_info *private = table->private;
|
||||
struct xt_table_info *info;
|
||||
|
||||
/* We need atomic snapshot of counters: rest doesn't change
|
||||
* (other than comefrom, which userspace doesn't care
|
||||
@ -728,14 +808,30 @@ static inline struct xt_counters *alloc_counters(struct xt_table *table)
|
||||
counters = vmalloc_node(countersize, numa_node_id());
|
||||
|
||||
if (counters == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
goto nomem;
|
||||
|
||||
/* First, sum counters... */
|
||||
write_lock_bh(&table->lock);
|
||||
get_counters(private, counters);
|
||||
write_unlock_bh(&table->lock);
|
||||
info = xt_alloc_table_info(private->size);
|
||||
if (!info)
|
||||
goto free_counters;
|
||||
|
||||
clone_counters(info, private);
|
||||
|
||||
mutex_lock(&table->lock);
|
||||
xt_table_entry_swap_rcu(private, info);
|
||||
synchronize_net(); /* Wait until smoke has cleared */
|
||||
|
||||
get_counters(info, counters);
|
||||
put_counters(private, counters);
|
||||
mutex_unlock(&table->lock);
|
||||
|
||||
xt_free_table_info(info);
|
||||
|
||||
return counters;
|
||||
|
||||
free_counters:
|
||||
vfree(counters);
|
||||
nomem:
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
static int copy_entries_to_user(unsigned int total_size,
|
||||
@ -1075,20 +1171,6 @@ static int do_replace(struct net *net, void __user *user, unsigned int len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
||||
* and everything is OK.
|
||||
*/
|
||||
static inline int add_counter_to_entry(struct arpt_entry *e,
|
||||
const struct xt_counters addme[],
|
||||
unsigned int *i)
|
||||
{
|
||||
|
||||
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
||||
|
||||
(*i)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||
int compat)
|
||||
{
|
||||
@ -1148,13 +1230,14 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||
goto free;
|
||||
}
|
||||
|
||||
write_lock_bh(&t->lock);
|
||||
mutex_lock(&t->lock);
|
||||
private = t->private;
|
||||
if (private->number != num_counters) {
|
||||
ret = -EINVAL;
|
||||
goto unlock_up_free;
|
||||
}
|
||||
|
||||
preempt_disable();
|
||||
i = 0;
|
||||
/* Choose the copy that is on our node */
|
||||
loc_cpu_entry = private->entries[smp_processor_id()];
|
||||
@ -1163,8 +1246,10 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||
add_counter_to_entry,
|
||||
paddc,
|
||||
&i);
|
||||
preempt_enable();
|
||||
unlock_up_free:
|
||||
write_unlock_bh(&t->lock);
|
||||
mutex_unlock(&t->lock);
|
||||
|
||||
xt_table_unlock(t);
|
||||
module_put(t->me);
|
||||
free:
|
||||
|
@ -48,8 +48,6 @@ static struct
|
||||
static struct xt_table packet_filter = {
|
||||
.name = "filter",
|
||||
.valid_hooks = FILTER_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(packet_filter.lock),
|
||||
.private = NULL,
|
||||
.me = THIS_MODULE,
|
||||
.af = NFPROTO_ARP,
|
||||
};
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/sock.h>
|
||||
@ -640,6 +641,7 @@ static void __exit ip_queue_fini(void)
|
||||
MODULE_DESCRIPTION("IPv4 packet queue handler");
|
||||
MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_FIREWALL);
|
||||
|
||||
module_init(ip_queue_init);
|
||||
module_exit(ip_queue_fini);
|
||||
|
@ -74,6 +74,25 @@ do { \
|
||||
|
||||
Hence the start of any table is given by get_table() below. */
|
||||
|
||||
static unsigned long ifname_compare(const char *_a, const char *_b,
|
||||
const unsigned char *_mask)
|
||||
{
|
||||
const unsigned long *a = (const unsigned long *)_a;
|
||||
const unsigned long *b = (const unsigned long *)_b;
|
||||
const unsigned long *mask = (const unsigned long *)_mask;
|
||||
unsigned long ret;
|
||||
|
||||
ret = (a[0] ^ b[0]) & mask[0];
|
||||
if (IFNAMSIZ > sizeof(unsigned long))
|
||||
ret |= (a[1] ^ b[1]) & mask[1];
|
||||
if (IFNAMSIZ > 2 * sizeof(unsigned long))
|
||||
ret |= (a[2] ^ b[2]) & mask[2];
|
||||
if (IFNAMSIZ > 3 * sizeof(unsigned long))
|
||||
ret |= (a[3] ^ b[3]) & mask[3];
|
||||
BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns whether matches rule or not. */
|
||||
/* Performance critical - called for every packet */
|
||||
static inline bool
|
||||
@ -83,7 +102,6 @@ ip_packet_match(const struct iphdr *ip,
|
||||
const struct ipt_ip *ipinfo,
|
||||
int isfrag)
|
||||
{
|
||||
size_t i;
|
||||
unsigned long ret;
|
||||
|
||||
#define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg)))
|
||||
@ -103,12 +121,7 @@ ip_packet_match(const struct iphdr *ip,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Look for ifname matches; this should unroll nicely. */
|
||||
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
|
||||
ret |= (((const unsigned long *)indev)[i]
|
||||
^ ((const unsigned long *)ipinfo->iniface)[i])
|
||||
& ((const unsigned long *)ipinfo->iniface_mask)[i];
|
||||
}
|
||||
ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask);
|
||||
|
||||
if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
|
||||
dprintf("VIA in mismatch (%s vs %s).%s\n",
|
||||
@ -117,11 +130,7 @@ ip_packet_match(const struct iphdr *ip,
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
|
||||
ret |= (((const unsigned long *)outdev)[i]
|
||||
^ ((const unsigned long *)ipinfo->outiface)[i])
|
||||
& ((const unsigned long *)ipinfo->outiface_mask)[i];
|
||||
}
|
||||
ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask);
|
||||
|
||||
if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
|
||||
dprintf("VIA out mismatch (%s vs %s).%s\n",
|
||||
@ -347,10 +356,12 @@ ipt_do_table(struct sk_buff *skb,
|
||||
mtpar.family = tgpar.family = NFPROTO_IPV4;
|
||||
tgpar.hooknum = hook;
|
||||
|
||||
read_lock_bh(&table->lock);
|
||||
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
|
||||
private = table->private;
|
||||
table_base = (void *)private->entries[smp_processor_id()];
|
||||
|
||||
rcu_read_lock();
|
||||
private = rcu_dereference(table->private);
|
||||
table_base = rcu_dereference(private->entries[smp_processor_id()]);
|
||||
|
||||
e = get_entry(table_base, private->hook_entry[hook]);
|
||||
|
||||
/* For return from builtin chain */
|
||||
@ -445,7 +456,7 @@ ipt_do_table(struct sk_buff *skb,
|
||||
}
|
||||
} while (!hotdrop);
|
||||
|
||||
read_unlock_bh(&table->lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
#ifdef DEBUG_ALLOW_ALL
|
||||
return NF_ACCEPT;
|
||||
@ -924,13 +935,68 @@ get_counters(const struct xt_table_info *t,
|
||||
counters,
|
||||
&i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
||||
* and everything is OK. */
|
||||
static int
|
||||
add_counter_to_entry(struct ipt_entry *e,
|
||||
const struct xt_counters addme[],
|
||||
unsigned int *i)
|
||||
{
|
||||
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
||||
|
||||
(*i)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Take values from counters and add them back onto the current cpu */
|
||||
static void put_counters(struct xt_table_info *t,
|
||||
const struct xt_counters counters[])
|
||||
{
|
||||
unsigned int i, cpu;
|
||||
|
||||
local_bh_disable();
|
||||
cpu = smp_processor_id();
|
||||
i = 0;
|
||||
IPT_ENTRY_ITERATE(t->entries[cpu],
|
||||
t->size,
|
||||
add_counter_to_entry,
|
||||
counters,
|
||||
&i);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
zero_entry_counter(struct ipt_entry *e, void *arg)
|
||||
{
|
||||
e->counters.bcnt = 0;
|
||||
e->counters.pcnt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
|
||||
{
|
||||
unsigned int cpu;
|
||||
const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
|
||||
|
||||
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
|
||||
for_each_possible_cpu(cpu) {
|
||||
memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
|
||||
IPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
|
||||
zero_entry_counter, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static struct xt_counters * alloc_counters(struct xt_table *table)
|
||||
{
|
||||
unsigned int countersize;
|
||||
struct xt_counters *counters;
|
||||
const struct xt_table_info *private = table->private;
|
||||
struct xt_table_info *private = table->private;
|
||||
struct xt_table_info *info;
|
||||
|
||||
/* We need atomic snapshot of counters: rest doesn't change
|
||||
(other than comefrom, which userspace doesn't care
|
||||
@ -939,14 +1005,30 @@ static struct xt_counters * alloc_counters(struct xt_table *table)
|
||||
counters = vmalloc_node(countersize, numa_node_id());
|
||||
|
||||
if (counters == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
goto nomem;
|
||||
|
||||
/* First, sum counters... */
|
||||
write_lock_bh(&table->lock);
|
||||
get_counters(private, counters);
|
||||
write_unlock_bh(&table->lock);
|
||||
info = xt_alloc_table_info(private->size);
|
||||
if (!info)
|
||||
goto free_counters;
|
||||
|
||||
clone_counters(info, private);
|
||||
|
||||
mutex_lock(&table->lock);
|
||||
xt_table_entry_swap_rcu(private, info);
|
||||
synchronize_net(); /* Wait until smoke has cleared */
|
||||
|
||||
get_counters(info, counters);
|
||||
put_counters(private, counters);
|
||||
mutex_unlock(&table->lock);
|
||||
|
||||
xt_free_table_info(info);
|
||||
|
||||
return counters;
|
||||
|
||||
free_counters:
|
||||
vfree(counters);
|
||||
nomem:
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1312,27 +1394,6 @@ do_replace(struct net *net, void __user *user, unsigned int len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
||||
* and everything is OK. */
|
||||
static int
|
||||
add_counter_to_entry(struct ipt_entry *e,
|
||||
const struct xt_counters addme[],
|
||||
unsigned int *i)
|
||||
{
|
||||
#if 0
|
||||
duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
|
||||
*i,
|
||||
(long unsigned int)e->counters.pcnt,
|
||||
(long unsigned int)e->counters.bcnt,
|
||||
(long unsigned int)addme[*i].pcnt,
|
||||
(long unsigned int)addme[*i].bcnt);
|
||||
#endif
|
||||
|
||||
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
||||
|
||||
(*i)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
|
||||
@ -1393,13 +1454,14 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat
|
||||
goto free;
|
||||
}
|
||||
|
||||
write_lock_bh(&t->lock);
|
||||
mutex_lock(&t->lock);
|
||||
private = t->private;
|
||||
if (private->number != num_counters) {
|
||||
ret = -EINVAL;
|
||||
goto unlock_up_free;
|
||||
}
|
||||
|
||||
preempt_disable();
|
||||
i = 0;
|
||||
/* Choose the copy that is on our node */
|
||||
loc_cpu_entry = private->entries[raw_smp_processor_id()];
|
||||
@ -1408,8 +1470,9 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat
|
||||
add_counter_to_entry,
|
||||
paddc,
|
||||
&i);
|
||||
preempt_enable();
|
||||
unlock_up_free:
|
||||
write_unlock_bh(&t->lock);
|
||||
mutex_unlock(&t->lock);
|
||||
xt_table_unlock(t);
|
||||
module_put(t->me);
|
||||
free:
|
||||
|
@ -464,7 +464,7 @@ static struct xt_target log_tg_reg __read_mostly = {
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct nf_logger ipt_log_logger ={
|
||||
static struct nf_logger ipt_log_logger __read_mostly = {
|
||||
.name = "ipt_LOG",
|
||||
.logfn = &ipt_log_packet,
|
||||
.me = THIS_MODULE,
|
||||
|
@ -1,97 +0,0 @@
|
||||
/* TTL modification target for IP tables
|
||||
* (C) 2000,2005 by Harald Welte <laforge@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/checksum.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv4/ipt_TTL.h>
|
||||
|
||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||
MODULE_DESCRIPTION("Xtables: IPv4 TTL field modification target");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int
|
||||
ttl_tg(struct sk_buff *skb, const struct xt_target_param *par)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
const struct ipt_TTL_info *info = par->targinfo;
|
||||
int new_ttl;
|
||||
|
||||
if (!skb_make_writable(skb, skb->len))
|
||||
return NF_DROP;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
|
||||
switch (info->mode) {
|
||||
case IPT_TTL_SET:
|
||||
new_ttl = info->ttl;
|
||||
break;
|
||||
case IPT_TTL_INC:
|
||||
new_ttl = iph->ttl + info->ttl;
|
||||
if (new_ttl > 255)
|
||||
new_ttl = 255;
|
||||
break;
|
||||
case IPT_TTL_DEC:
|
||||
new_ttl = iph->ttl - info->ttl;
|
||||
if (new_ttl < 0)
|
||||
new_ttl = 0;
|
||||
break;
|
||||
default:
|
||||
new_ttl = iph->ttl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_ttl != iph->ttl) {
|
||||
csum_replace2(&iph->check, htons(iph->ttl << 8),
|
||||
htons(new_ttl << 8));
|
||||
iph->ttl = new_ttl;
|
||||
}
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static bool ttl_tg_check(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct ipt_TTL_info *info = par->targinfo;
|
||||
|
||||
if (info->mode > IPT_TTL_MAXMODE) {
|
||||
printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
|
||||
info->mode);
|
||||
return false;
|
||||
}
|
||||
if (info->mode != IPT_TTL_SET && info->ttl == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct xt_target ttl_tg_reg __read_mostly = {
|
||||
.name = "TTL",
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = ttl_tg,
|
||||
.targetsize = sizeof(struct ipt_TTL_info),
|
||||
.table = "mangle",
|
||||
.checkentry = ttl_tg_check,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init ttl_tg_init(void)
|
||||
{
|
||||
return xt_register_target(&ttl_tg_reg);
|
||||
}
|
||||
|
||||
static void __exit ttl_tg_exit(void)
|
||||
{
|
||||
xt_unregister_target(&ttl_tg_reg);
|
||||
}
|
||||
|
||||
module_init(ttl_tg_init);
|
||||
module_exit(ttl_tg_exit);
|
@ -379,7 +379,7 @@ static struct xt_target ulog_tg_reg __read_mostly = {
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct nf_logger ipt_ulog_logger = {
|
||||
static struct nf_logger ipt_ulog_logger __read_mostly = {
|
||||
.name = "ipt_ULOG",
|
||||
.logfn = ipt_logfn,
|
||||
.me = THIS_MODULE,
|
||||
|
@ -1,63 +0,0 @@
|
||||
/* IP tables module for matching the value of the TTL
|
||||
*
|
||||
* (C) 2000,2001 by Harald Welte <laforge@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/ip.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ipt_ttl.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||
MODULE_DESCRIPTION("Xtables: IPv4 TTL field match");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
const struct ipt_ttl_info *info = par->matchinfo;
|
||||
const u8 ttl = ip_hdr(skb)->ttl;
|
||||
|
||||
switch (info->mode) {
|
||||
case IPT_TTL_EQ:
|
||||
return ttl == info->ttl;
|
||||
case IPT_TTL_NE:
|
||||
return ttl != info->ttl;
|
||||
case IPT_TTL_LT:
|
||||
return ttl < info->ttl;
|
||||
case IPT_TTL_GT:
|
||||
return ttl > info->ttl;
|
||||
default:
|
||||
printk(KERN_WARNING "ipt_ttl: unknown mode %d\n",
|
||||
info->mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct xt_match ttl_mt_reg __read_mostly = {
|
||||
.name = "ttl",
|
||||
.family = NFPROTO_IPV4,
|
||||
.match = ttl_mt,
|
||||
.matchsize = sizeof(struct ipt_ttl_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init ttl_mt_init(void)
|
||||
{
|
||||
return xt_register_match(&ttl_mt_reg);
|
||||
}
|
||||
|
||||
static void __exit ttl_mt_exit(void)
|
||||
{
|
||||
xt_unregister_match(&ttl_mt_reg);
|
||||
}
|
||||
|
||||
module_init(ttl_mt_init);
|
||||
module_exit(ttl_mt_exit);
|
@ -56,7 +56,6 @@ static struct
|
||||
static struct xt_table packet_filter = {
|
||||
.name = "filter",
|
||||
.valid_hooks = FILTER_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(packet_filter.lock),
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET,
|
||||
};
|
||||
|
@ -67,7 +67,6 @@ static struct
|
||||
static struct xt_table packet_mangler = {
|
||||
.name = "mangle",
|
||||
.valid_hooks = MANGLE_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(packet_mangler.lock),
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET,
|
||||
};
|
||||
|
@ -39,7 +39,6 @@ static struct
|
||||
static struct xt_table packet_raw = {
|
||||
.name = "raw",
|
||||
.valid_hooks = RAW_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(packet_raw.lock),
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET,
|
||||
};
|
||||
|
@ -60,7 +60,6 @@ static struct
|
||||
static struct xt_table security_table = {
|
||||
.name = "security",
|
||||
.valid_hooks = SECURITY_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(security_table.lock),
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET,
|
||||
};
|
||||
|
@ -120,8 +120,10 @@ static unsigned int ipv4_confirm(unsigned int hooknum,
|
||||
typeof(nf_nat_seq_adjust_hook) seq_adjust;
|
||||
|
||||
seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook);
|
||||
if (!seq_adjust || !seq_adjust(skb, ct, ctinfo))
|
||||
if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) {
|
||||
NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
|
||||
return NF_DROP;
|
||||
}
|
||||
}
|
||||
out:
|
||||
/* We've seen it coming out the other side: confirm it */
|
||||
|
@ -61,7 +61,6 @@ static struct
|
||||
static struct xt_table nat_table = {
|
||||
.name = "nat",
|
||||
.valid_hooks = NAT_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(nat_table.lock),
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET,
|
||||
};
|
||||
|
@ -95,13 +95,13 @@ config IP6_NF_MATCH_OPTS
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP6_NF_MATCH_HL
|
||||
tristate '"hl" match support'
|
||||
tristate '"hl" hoplimit match support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
help
|
||||
HL matching allows you to match packets based on the hop
|
||||
limit of the packet.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
select NETFILTER_XT_MATCH_HL
|
||||
---help---
|
||||
This is a backwards-compat option for the user's convenience
|
||||
(e.g. when running oldconfig). It selects
|
||||
COFNIG_NETFILTER_XT_MATCH_HL.
|
||||
|
||||
config IP6_NF_MATCH_IPV6HEADER
|
||||
tristate '"ipv6header" IPv6 Extension Headers Match'
|
||||
@ -130,6 +130,15 @@ config IP6_NF_MATCH_RT
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
# The targets
|
||||
config IP6_NF_TARGET_HL
|
||||
tristate '"HL" hoplimit target support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
select NETFILTER_XT_TARGET_HL
|
||||
---help---
|
||||
This is a backwards-compat option for the user's convenience
|
||||
(e.g. when running oldconfig). It selects
|
||||
COFNIG_NETFILTER_XT_TARGET_HL.
|
||||
|
||||
config IP6_NF_TARGET_LOG
|
||||
tristate "LOG target support"
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
@ -170,23 +179,6 @@ config IP6_NF_MANGLE
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP6_NF_TARGET_HL
|
||||
tristate 'HL (hoplimit) target support'
|
||||
depends on IP6_NF_MANGLE
|
||||
depends on NETFILTER_ADVANCED
|
||||
help
|
||||
This option adds a `HL' target, which enables the user to decrement
|
||||
the hoplimit value of the IPv6 header or set it to a given (lower)
|
||||
value.
|
||||
|
||||
While it is safe to decrement the hoplimit value, this option also
|
||||
enables functionality to increment and set the hoplimit value of the
|
||||
IPv6 header to arbitrary values. This is EXTREMELY DANGEROUS since
|
||||
you can easily create immortal packets that loop forever on the
|
||||
network.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP6_NF_RAW
|
||||
tristate 'raw table support (required for TRACE)'
|
||||
depends on NETFILTER_ADVANCED
|
||||
|
@ -20,13 +20,11 @@ obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
|
||||
obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
|
||||
|
||||
# targets
|
||||
obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o
|
||||
obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
|
||||
obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
|
||||
|
@ -643,6 +643,7 @@ static void __exit ip6_queue_fini(void)
|
||||
|
||||
MODULE_DESCRIPTION("IPv6 packet queue handler");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_IP6_FW);
|
||||
|
||||
module_init(ip6_queue_init);
|
||||
module_exit(ip6_queue_fini);
|
||||
|
@ -89,6 +89,25 @@ ip6t_ext_hdr(u8 nexthdr)
|
||||
(nexthdr == IPPROTO_DSTOPTS) );
|
||||
}
|
||||
|
||||
static unsigned long ifname_compare(const char *_a, const char *_b,
|
||||
const unsigned char *_mask)
|
||||
{
|
||||
const unsigned long *a = (const unsigned long *)_a;
|
||||
const unsigned long *b = (const unsigned long *)_b;
|
||||
const unsigned long *mask = (const unsigned long *)_mask;
|
||||
unsigned long ret;
|
||||
|
||||
ret = (a[0] ^ b[0]) & mask[0];
|
||||
if (IFNAMSIZ > sizeof(unsigned long))
|
||||
ret |= (a[1] ^ b[1]) & mask[1];
|
||||
if (IFNAMSIZ > 2 * sizeof(unsigned long))
|
||||
ret |= (a[2] ^ b[2]) & mask[2];
|
||||
if (IFNAMSIZ > 3 * sizeof(unsigned long))
|
||||
ret |= (a[3] ^ b[3]) & mask[3];
|
||||
BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Returns whether matches rule or not. */
|
||||
/* Performance critical - called for every packet */
|
||||
static inline bool
|
||||
@ -99,7 +118,6 @@ ip6_packet_match(const struct sk_buff *skb,
|
||||
unsigned int *protoff,
|
||||
int *fragoff, bool *hotdrop)
|
||||
{
|
||||
size_t i;
|
||||
unsigned long ret;
|
||||
const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
|
||||
|
||||
@ -120,12 +138,7 @@ ip6_packet_match(const struct sk_buff *skb,
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Look for ifname matches; this should unroll nicely. */
|
||||
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
|
||||
ret |= (((const unsigned long *)indev)[i]
|
||||
^ ((const unsigned long *)ip6info->iniface)[i])
|
||||
& ((const unsigned long *)ip6info->iniface_mask)[i];
|
||||
}
|
||||
ret = ifname_compare(indev, ip6info->iniface, ip6info->iniface_mask);
|
||||
|
||||
if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
|
||||
dprintf("VIA in mismatch (%s vs %s).%s\n",
|
||||
@ -134,11 +147,7 @@ ip6_packet_match(const struct sk_buff *skb,
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
|
||||
ret |= (((const unsigned long *)outdev)[i]
|
||||
^ ((const unsigned long *)ip6info->outiface)[i])
|
||||
& ((const unsigned long *)ip6info->outiface_mask)[i];
|
||||
}
|
||||
ret = ifname_compare(outdev, ip6info->outiface, ip6info->outiface_mask);
|
||||
|
||||
if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
|
||||
dprintf("VIA out mismatch (%s vs %s).%s\n",
|
||||
@ -373,10 +382,12 @@ ip6t_do_table(struct sk_buff *skb,
|
||||
mtpar.family = tgpar.family = NFPROTO_IPV6;
|
||||
tgpar.hooknum = hook;
|
||||
|
||||
read_lock_bh(&table->lock);
|
||||
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
|
||||
private = table->private;
|
||||
table_base = (void *)private->entries[smp_processor_id()];
|
||||
|
||||
rcu_read_lock();
|
||||
private = rcu_dereference(table->private);
|
||||
table_base = rcu_dereference(private->entries[smp_processor_id()]);
|
||||
|
||||
e = get_entry(table_base, private->hook_entry[hook]);
|
||||
|
||||
/* For return from builtin chain */
|
||||
@ -474,7 +485,7 @@ ip6t_do_table(struct sk_buff *skb,
|
||||
#ifdef CONFIG_NETFILTER_DEBUG
|
||||
((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
|
||||
#endif
|
||||
read_unlock_bh(&table->lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
#ifdef DEBUG_ALLOW_ALL
|
||||
return NF_ACCEPT;
|
||||
@ -955,11 +966,64 @@ get_counters(const struct xt_table_info *t,
|
||||
}
|
||||
}
|
||||
|
||||
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
||||
* and everything is OK. */
|
||||
static int
|
||||
add_counter_to_entry(struct ip6t_entry *e,
|
||||
const struct xt_counters addme[],
|
||||
unsigned int *i)
|
||||
{
|
||||
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
||||
|
||||
(*i)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Take values from counters and add them back onto the current cpu */
|
||||
static void put_counters(struct xt_table_info *t,
|
||||
const struct xt_counters counters[])
|
||||
{
|
||||
unsigned int i, cpu;
|
||||
|
||||
local_bh_disable();
|
||||
cpu = smp_processor_id();
|
||||
i = 0;
|
||||
IP6T_ENTRY_ITERATE(t->entries[cpu],
|
||||
t->size,
|
||||
add_counter_to_entry,
|
||||
counters,
|
||||
&i);
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
static inline int
|
||||
zero_entry_counter(struct ip6t_entry *e, void *arg)
|
||||
{
|
||||
e->counters.bcnt = 0;
|
||||
e->counters.pcnt = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
|
||||
{
|
||||
unsigned int cpu;
|
||||
const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
|
||||
|
||||
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
|
||||
for_each_possible_cpu(cpu) {
|
||||
memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
|
||||
IP6T_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
|
||||
zero_entry_counter, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static struct xt_counters *alloc_counters(struct xt_table *table)
|
||||
{
|
||||
unsigned int countersize;
|
||||
struct xt_counters *counters;
|
||||
const struct xt_table_info *private = table->private;
|
||||
struct xt_table_info *private = table->private;
|
||||
struct xt_table_info *info;
|
||||
|
||||
/* We need atomic snapshot of counters: rest doesn't change
|
||||
(other than comefrom, which userspace doesn't care
|
||||
@ -968,14 +1032,28 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
|
||||
counters = vmalloc_node(countersize, numa_node_id());
|
||||
|
||||
if (counters == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
goto nomem;
|
||||
|
||||
/* First, sum counters... */
|
||||
write_lock_bh(&table->lock);
|
||||
get_counters(private, counters);
|
||||
write_unlock_bh(&table->lock);
|
||||
info = xt_alloc_table_info(private->size);
|
||||
if (!info)
|
||||
goto free_counters;
|
||||
|
||||
return counters;
|
||||
clone_counters(info, private);
|
||||
|
||||
mutex_lock(&table->lock);
|
||||
xt_table_entry_swap_rcu(private, info);
|
||||
synchronize_net(); /* Wait until smoke has cleared */
|
||||
|
||||
get_counters(info, counters);
|
||||
put_counters(private, counters);
|
||||
mutex_unlock(&table->lock);
|
||||
|
||||
xt_free_table_info(info);
|
||||
|
||||
free_counters:
|
||||
vfree(counters);
|
||||
nomem:
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1342,28 +1420,6 @@ do_replace(struct net *net, void __user *user, unsigned int len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
||||
* and everything is OK. */
|
||||
static inline int
|
||||
add_counter_to_entry(struct ip6t_entry *e,
|
||||
const struct xt_counters addme[],
|
||||
unsigned int *i)
|
||||
{
|
||||
#if 0
|
||||
duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
|
||||
*i,
|
||||
(long unsigned int)e->counters.pcnt,
|
||||
(long unsigned int)e->counters.bcnt,
|
||||
(long unsigned int)addme[*i].pcnt,
|
||||
(long unsigned int)addme[*i].bcnt);
|
||||
#endif
|
||||
|
||||
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
||||
|
||||
(*i)++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||
int compat)
|
||||
@ -1424,13 +1480,14 @@ do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||
goto free;
|
||||
}
|
||||
|
||||
write_lock_bh(&t->lock);
|
||||
mutex_lock(&t->lock);
|
||||
private = t->private;
|
||||
if (private->number != num_counters) {
|
||||
ret = -EINVAL;
|
||||
goto unlock_up_free;
|
||||
}
|
||||
|
||||
preempt_disable();
|
||||
i = 0;
|
||||
/* Choose the copy that is on our node */
|
||||
loc_cpu_entry = private->entries[raw_smp_processor_id()];
|
||||
@ -1439,8 +1496,9 @@ do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||
add_counter_to_entry,
|
||||
paddc,
|
||||
&i);
|
||||
preempt_enable();
|
||||
unlock_up_free:
|
||||
write_unlock_bh(&t->lock);
|
||||
mutex_unlock(&t->lock);
|
||||
xt_table_unlock(t);
|
||||
module_put(t->me);
|
||||
free:
|
||||
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Hop Limit modification target for ip6tables
|
||||
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
|
||||
* Based on HW's TTL module
|
||||
*
|
||||
* This software is distributed under the terms of GNU GPL
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv6/ip6t_HL.h>
|
||||
|
||||
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
|
||||
MODULE_DESCRIPTION("Xtables: IPv6 Hop Limit field modification target");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int
|
||||
hl_tg6(struct sk_buff *skb, const struct xt_target_param *par)
|
||||
{
|
||||
struct ipv6hdr *ip6h;
|
||||
const struct ip6t_HL_info *info = par->targinfo;
|
||||
int new_hl;
|
||||
|
||||
if (!skb_make_writable(skb, skb->len))
|
||||
return NF_DROP;
|
||||
|
||||
ip6h = ipv6_hdr(skb);
|
||||
|
||||
switch (info->mode) {
|
||||
case IP6T_HL_SET:
|
||||
new_hl = info->hop_limit;
|
||||
break;
|
||||
case IP6T_HL_INC:
|
||||
new_hl = ip6h->hop_limit + info->hop_limit;
|
||||
if (new_hl > 255)
|
||||
new_hl = 255;
|
||||
break;
|
||||
case IP6T_HL_DEC:
|
||||
new_hl = ip6h->hop_limit - info->hop_limit;
|
||||
if (new_hl < 0)
|
||||
new_hl = 0;
|
||||
break;
|
||||
default:
|
||||
new_hl = ip6h->hop_limit;
|
||||
break;
|
||||
}
|
||||
|
||||
ip6h->hop_limit = new_hl;
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static bool hl_tg6_check(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct ip6t_HL_info *info = par->targinfo;
|
||||
|
||||
if (info->mode > IP6T_HL_MAXMODE) {
|
||||
printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n",
|
||||
info->mode);
|
||||
return false;
|
||||
}
|
||||
if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
|
||||
printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
|
||||
"make sense with value 0\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct xt_target hl_tg6_reg __read_mostly = {
|
||||
.name = "HL",
|
||||
.family = NFPROTO_IPV6,
|
||||
.target = hl_tg6,
|
||||
.targetsize = sizeof(struct ip6t_HL_info),
|
||||
.table = "mangle",
|
||||
.checkentry = hl_tg6_check,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
static int __init hl_tg6_init(void)
|
||||
{
|
||||
return xt_register_target(&hl_tg6_reg);
|
||||
}
|
||||
|
||||
static void __exit hl_tg6_exit(void)
|
||||
{
|
||||
xt_unregister_target(&hl_tg6_reg);
|
||||
}
|
||||
|
||||
module_init(hl_tg6_init);
|
||||
module_exit(hl_tg6_exit);
|
@ -477,7 +477,7 @@ static struct xt_target log_tg6_reg __read_mostly = {
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct nf_logger ip6t_logger = {
|
||||
static struct nf_logger ip6t_logger __read_mostly = {
|
||||
.name = "ip6t_LOG",
|
||||
.logfn = &ip6t_log_packet,
|
||||
.me = THIS_MODULE,
|
||||
|
@ -1,68 +0,0 @@
|
||||
/* Hop Limit matching module */
|
||||
|
||||
/* (C) 2001-2002 Maciej Soltysiak <solt@dns.toxicfilms.tv>
|
||||
* Based on HW's ttl module
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/netfilter_ipv6/ip6t_hl.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
|
||||
MODULE_DESCRIPTION("Xtables: IPv6 Hop Limit field match");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
const struct ip6t_hl_info *info = par->matchinfo;
|
||||
const struct ipv6hdr *ip6h = ipv6_hdr(skb);
|
||||
|
||||
switch (info->mode) {
|
||||
case IP6T_HL_EQ:
|
||||
return ip6h->hop_limit == info->hop_limit;
|
||||
break;
|
||||
case IP6T_HL_NE:
|
||||
return ip6h->hop_limit != info->hop_limit;
|
||||
break;
|
||||
case IP6T_HL_LT:
|
||||
return ip6h->hop_limit < info->hop_limit;
|
||||
break;
|
||||
case IP6T_HL_GT:
|
||||
return ip6h->hop_limit > info->hop_limit;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "ip6t_hl: unknown mode %d\n",
|
||||
info->mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct xt_match hl_mt6_reg __read_mostly = {
|
||||
.name = "hl",
|
||||
.family = NFPROTO_IPV6,
|
||||
.match = hl_mt6,
|
||||
.matchsize = sizeof(struct ip6t_hl_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init hl_mt6_init(void)
|
||||
{
|
||||
return xt_register_match(&hl_mt6_reg);
|
||||
}
|
||||
|
||||
static void __exit hl_mt6_exit(void)
|
||||
{
|
||||
xt_unregister_match(&hl_mt6_reg);
|
||||
}
|
||||
|
||||
module_init(hl_mt6_init);
|
||||
module_exit(hl_mt6_exit);
|
@ -54,7 +54,6 @@ static struct
|
||||
static struct xt_table packet_filter = {
|
||||
.name = "filter",
|
||||
.valid_hooks = FILTER_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(packet_filter.lock),
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET6,
|
||||
};
|
||||
|
@ -60,7 +60,6 @@ static struct
|
||||
static struct xt_table packet_mangler = {
|
||||
.name = "mangle",
|
||||
.valid_hooks = MANGLE_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(packet_mangler.lock),
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET6,
|
||||
};
|
||||
|
@ -38,7 +38,6 @@ static struct
|
||||
static struct xt_table packet_raw = {
|
||||
.name = "raw",
|
||||
.valid_hooks = RAW_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(packet_raw.lock),
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET6,
|
||||
};
|
||||
|
@ -59,7 +59,6 @@ static struct
|
||||
static struct xt_table security_table = {
|
||||
.name = "security",
|
||||
.valid_hooks = SECURITY_VALID_HOOKS,
|
||||
.lock = __RW_LOCK_UNLOCKED(security_table.lock),
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET6,
|
||||
};
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <net/netfilter/nf_conntrack_l4proto.h>
|
||||
#include <net/netfilter/nf_conntrack_l3proto.h>
|
||||
#include <net/netfilter/nf_conntrack_core.h>
|
||||
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
|
||||
|
||||
static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
|
||||
struct nf_conntrack_tuple *tuple)
|
||||
|
@ -126,6 +126,10 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb,
|
||||
pr_debug("icmpv6: can't create new conn with type %u\n",
|
||||
type + 128);
|
||||
nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple);
|
||||
if (LOG_INVALID(nf_ct_net(ct), IPPROTO_ICMPV6))
|
||||
nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
|
||||
"nf_ct_icmpv6: invalid new with type %d ",
|
||||
type + 128);
|
||||
return false;
|
||||
}
|
||||
atomic_set(&ct->proto.icmp.count, 0);
|
||||
|
@ -357,6 +357,45 @@ config NETFILTER_XT_TARGET_DSCP
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NETFILTER_XT_TARGET_HL
|
||||
tristate '"HL" hoplimit target support'
|
||||
depends on IP_NF_MANGLE || IP6_NF_MANGLE
|
||||
depends on NETFILTER_ADVANCED
|
||||
---help---
|
||||
This option adds the "HL" (for IPv6) and "TTL" (for IPv4)
|
||||
targets, which enable the user to change the
|
||||
hoplimit/time-to-live value of the IP header.
|
||||
|
||||
While it is safe to decrement the hoplimit/TTL value, the
|
||||
modules also allow to increment and set the hoplimit value of
|
||||
the header to arbitrary values. This is EXTREMELY DANGEROUS
|
||||
since you can easily create immortal packets that loop
|
||||
forever on the network.
|
||||
|
||||
config NETFILTER_XT_TARGET_LED
|
||||
tristate '"LED" target support'
|
||||
depends on LEDS_CLASS
|
||||
depends on NETFILTER_ADVANCED
|
||||
help
|
||||
This option adds a `LED' target, which allows you to blink LEDs in
|
||||
response to particular packets passing through your machine.
|
||||
|
||||
This can be used to turn a spare LED into a network activity LED,
|
||||
which only flashes in response to FTP transfers, for example. Or
|
||||
you could have an LED which lights up for a minute or two every time
|
||||
somebody connects to your machine via SSH.
|
||||
|
||||
You will need support for the "led" class to make this work.
|
||||
|
||||
To create an LED trigger for incoming SSH traffic:
|
||||
iptables -A INPUT -p tcp --dport 22 -j LED --led-trigger-id ssh --led-delay 1000
|
||||
|
||||
Then attach the new trigger to an LED on your system:
|
||||
echo netfilter-ssh > /sys/class/leds/<ledname>/trigger
|
||||
|
||||
For more information on the LEDs available on your system, see
|
||||
Documentation/leds-class.txt
|
||||
|
||||
config NETFILTER_XT_TARGET_MARK
|
||||
tristate '"MARK" target support'
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
@ -488,6 +527,22 @@ config NETFILTER_XT_TARGET_TCPOPTSTRIP
|
||||
This option adds a "TCPOPTSTRIP" target, which allows you to strip
|
||||
TCP options from TCP packets.
|
||||
|
||||
config NETFILTER_XT_MATCH_CLUSTER
|
||||
tristate '"cluster" match support'
|
||||
depends on NF_CONNTRACK
|
||||
depends on NETFILTER_ADVANCED
|
||||
---help---
|
||||
This option allows you to build work-load-sharing clusters of
|
||||
network servers/stateful firewalls without having a dedicated
|
||||
load-balancing router/server/switch. Basically, this match returns
|
||||
true when the packet must be handled by this cluster node. Thus,
|
||||
all nodes see all packets and this match decides which node handles
|
||||
what packets. The work-load sharing algorithm is based on source
|
||||
address hashing.
|
||||
|
||||
If you say Y or M here, try `iptables -m cluster --help` for
|
||||
more information.
|
||||
|
||||
config NETFILTER_XT_MATCH_COMMENT
|
||||
tristate '"comment" match support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
@ -605,6 +660,14 @@ config NETFILTER_XT_MATCH_HELPER
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say Y.
|
||||
|
||||
config NETFILTER_XT_MATCH_HL
|
||||
tristate '"hl" hoplimit/TTL match support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
---help---
|
||||
HL matching allows you to match packets based on the hoplimit
|
||||
in the IPv6 header, or the time-to-live field in the IPv4
|
||||
header of the packet.
|
||||
|
||||
config NETFILTER_XT_MATCH_IPRANGE
|
||||
tristate '"iprange" address range match support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
|
@ -45,6 +45,8 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
|
||||
@ -57,6 +59,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
|
||||
|
||||
# matches
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
|
||||
@ -67,6 +70,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
|
||||
obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
|
||||
|
@ -174,7 +174,6 @@ next_hook:
|
||||
outdev, &elem, okfn, hook_thresh);
|
||||
if (verdict == NF_ACCEPT || verdict == NF_STOP) {
|
||||
ret = 1;
|
||||
goto unlock;
|
||||
} else if (verdict == NF_DROP) {
|
||||
kfree_skb(skb);
|
||||
ret = -EPERM;
|
||||
@ -183,7 +182,6 @@ next_hook:
|
||||
verdict >> NF_VERDICT_BITS))
|
||||
goto next_hook;
|
||||
}
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_lock);
|
||||
unsigned int nf_conntrack_htable_size __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
|
||||
|
||||
int nf_conntrack_max __read_mostly;
|
||||
unsigned int nf_conntrack_max __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_max);
|
||||
|
||||
struct nf_conn nf_conntrack_untracked __read_mostly;
|
||||
@ -472,7 +472,8 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
|
||||
struct nf_conn *ct;
|
||||
|
||||
if (unlikely(!nf_conntrack_hash_rnd_initted)) {
|
||||
get_random_bytes(&nf_conntrack_hash_rnd, 4);
|
||||
get_random_bytes(&nf_conntrack_hash_rnd,
|
||||
sizeof(nf_conntrack_hash_rnd));
|
||||
nf_conntrack_hash_rnd_initted = 1;
|
||||
}
|
||||
|
||||
@ -516,16 +517,17 @@ EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
|
||||
static void nf_conntrack_free_rcu(struct rcu_head *head)
|
||||
{
|
||||
struct nf_conn *ct = container_of(head, struct nf_conn, rcu);
|
||||
struct net *net = nf_ct_net(ct);
|
||||
|
||||
nf_ct_ext_free(ct);
|
||||
kmem_cache_free(nf_conntrack_cachep, ct);
|
||||
atomic_dec(&net->ct.count);
|
||||
}
|
||||
|
||||
void nf_conntrack_free(struct nf_conn *ct)
|
||||
{
|
||||
struct net *net = nf_ct_net(ct);
|
||||
|
||||
nf_ct_ext_destroy(ct);
|
||||
atomic_dec(&net->ct.count);
|
||||
call_rcu(&ct->rcu, nf_conntrack_free_rcu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_free);
|
||||
@ -733,6 +735,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
|
||||
nf_conntrack_put(skb->nfct);
|
||||
skb->nfct = NULL;
|
||||
NF_CT_STAT_INC_ATOMIC(net, invalid);
|
||||
if (ret == -NF_DROP)
|
||||
NF_CT_STAT_INC_ATOMIC(net, drop);
|
||||
return -ret;
|
||||
}
|
||||
|
||||
@ -1103,7 +1107,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
|
||||
|
||||
/* We have to rehahs for the new table anyway, so we also can
|
||||
* use a newrandom seed */
|
||||
get_random_bytes(&rnd, 4);
|
||||
get_random_bytes(&rnd, sizeof(rnd));
|
||||
|
||||
/* Lookups in the old hash might happen in parallel, which means we
|
||||
* might get false negatives during connection lookup. New connections
|
||||
|
@ -72,7 +72,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple
|
||||
unsigned int hash;
|
||||
|
||||
if (unlikely(!nf_ct_expect_hash_rnd_initted)) {
|
||||
get_random_bytes(&nf_ct_expect_hash_rnd, 4);
|
||||
get_random_bytes(&nf_ct_expect_hash_rnd,
|
||||
sizeof(nf_ct_expect_hash_rnd));
|
||||
nf_ct_expect_hash_rnd_initted = 1;
|
||||
}
|
||||
|
||||
|
@ -518,6 +518,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
|
||||
nla_put_failure:
|
||||
rcu_read_unlock();
|
||||
nlmsg_failure:
|
||||
nfnetlink_set_err(0, group, -ENOBUFS);
|
||||
kfree_skb(skb);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
@ -599,7 +600,8 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple)
|
||||
|
||||
nla_parse_nested(tb, CTA_IP_MAX, attr, NULL);
|
||||
|
||||
l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
|
||||
rcu_read_lock();
|
||||
l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
|
||||
|
||||
if (likely(l3proto->nlattr_to_tuple)) {
|
||||
ret = nla_validate_nested(attr, CTA_IP_MAX,
|
||||
@ -608,7 +610,7 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple)
|
||||
ret = l3proto->nlattr_to_tuple(tb, tuple);
|
||||
}
|
||||
|
||||
nf_ct_l3proto_put(l3proto);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -633,7 +635,8 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
|
||||
return -EINVAL;
|
||||
tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]);
|
||||
|
||||
l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);
|
||||
rcu_read_lock();
|
||||
l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
|
||||
|
||||
if (likely(l4proto->nlattr_to_tuple)) {
|
||||
ret = nla_validate_nested(attr, CTA_PROTO_MAX,
|
||||
@ -642,7 +645,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
|
||||
ret = l4proto->nlattr_to_tuple(tb, tuple);
|
||||
}
|
||||
|
||||
nf_ct_l4proto_put(l4proto);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -989,10 +992,11 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[])
|
||||
|
||||
nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL);
|
||||
|
||||
l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct));
|
||||
rcu_read_lock();
|
||||
l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
|
||||
if (l4proto->from_nlattr)
|
||||
err = l4proto->from_nlattr(tb, ct);
|
||||
nf_ct_l4proto_put(l4proto);
|
||||
rcu_read_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -1062,6 +1066,10 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[])
|
||||
{
|
||||
int err;
|
||||
|
||||
/* only allow NAT changes and master assignation for new conntracks */
|
||||
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST] || cda[CTA_TUPLE_MASTER])
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (cda[CTA_HELP]) {
|
||||
err = ctnetlink_change_helper(ct, cda);
|
||||
if (err < 0)
|
||||
@ -1124,13 +1132,11 @@ ctnetlink_event_report(struct nf_conn *ct, u32 pid, int report)
|
||||
report);
|
||||
}
|
||||
|
||||
static int
|
||||
static struct nf_conn *
|
||||
ctnetlink_create_conntrack(struct nlattr *cda[],
|
||||
struct nf_conntrack_tuple *otuple,
|
||||
struct nf_conntrack_tuple *rtuple,
|
||||
struct nf_conn *master_ct,
|
||||
u32 pid,
|
||||
int report)
|
||||
u8 u3)
|
||||
{
|
||||
struct nf_conn *ct;
|
||||
int err = -EINVAL;
|
||||
@ -1138,10 +1144,10 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
|
||||
|
||||
ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC);
|
||||
if (IS_ERR(ct))
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (!cda[CTA_TIMEOUT])
|
||||
goto err;
|
||||
goto err1;
|
||||
ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT]));
|
||||
|
||||
ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
|
||||
@ -1152,10 +1158,8 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
|
||||
char *helpname;
|
||||
|
||||
err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
|
||||
if (err < 0) {
|
||||
rcu_read_unlock();
|
||||
goto err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
|
||||
helper = __nf_conntrack_helper_find_byname(helpname);
|
||||
if (helper == NULL) {
|
||||
@ -1163,28 +1167,26 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
|
||||
#ifdef CONFIG_MODULES
|
||||
if (request_module("nfct-helper-%s", helpname) < 0) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto err;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
helper = __nf_conntrack_helper_find_byname(helpname);
|
||||
if (helper) {
|
||||
rcu_read_unlock();
|
||||
err = -EAGAIN;
|
||||
goto err;
|
||||
goto err2;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
#endif
|
||||
err = -EOPNOTSUPP;
|
||||
goto err;
|
||||
goto err1;
|
||||
} else {
|
||||
struct nf_conn_help *help;
|
||||
|
||||
help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
|
||||
if (help == NULL) {
|
||||
rcu_read_unlock();
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
/* not in hash table yet so not strictly necessary */
|
||||
@ -1193,44 +1195,34 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
|
||||
} else {
|
||||
/* try an implicit helper assignation */
|
||||
err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
|
||||
if (err < 0) {
|
||||
rcu_read_unlock();
|
||||
goto err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (cda[CTA_STATUS]) {
|
||||
err = ctnetlink_change_status(ct, cda);
|
||||
if (err < 0) {
|
||||
rcu_read_unlock();
|
||||
goto err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
|
||||
err = ctnetlink_change_nat(ct, cda);
|
||||
if (err < 0) {
|
||||
rcu_read_unlock();
|
||||
goto err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) {
|
||||
err = ctnetlink_change_nat_seq_adj(ct, cda);
|
||||
if (err < 0) {
|
||||
rcu_read_unlock();
|
||||
goto err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cda[CTA_PROTOINFO]) {
|
||||
err = ctnetlink_change_protoinfo(ct, cda);
|
||||
if (err < 0) {
|
||||
rcu_read_unlock();
|
||||
goto err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
}
|
||||
|
||||
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
|
||||
@ -1241,23 +1233,37 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
|
||||
#endif
|
||||
|
||||
/* setup master conntrack: this is a confirmed expectation */
|
||||
if (master_ct) {
|
||||
if (cda[CTA_TUPLE_MASTER]) {
|
||||
struct nf_conntrack_tuple master;
|
||||
struct nf_conntrack_tuple_hash *master_h;
|
||||
struct nf_conn *master_ct;
|
||||
|
||||
err = ctnetlink_parse_tuple(cda, &master, CTA_TUPLE_MASTER, u3);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
|
||||
master_h = __nf_conntrack_find(&init_net, &master);
|
||||
if (master_h == NULL) {
|
||||
err = -ENOENT;
|
||||
goto err2;
|
||||
}
|
||||
master_ct = nf_ct_tuplehash_to_ctrack(master_h);
|
||||
nf_conntrack_get(&master_ct->ct_general);
|
||||
__set_bit(IPS_EXPECTED_BIT, &ct->status);
|
||||
ct->master = master_ct;
|
||||
}
|
||||
|
||||
nf_conntrack_get(&ct->ct_general);
|
||||
add_timer(&ct->timeout);
|
||||
nf_conntrack_hash_insert(ct);
|
||||
rcu_read_unlock();
|
||||
ctnetlink_event_report(ct, pid, report);
|
||||
nf_ct_put(ct);
|
||||
|
||||
return 0;
|
||||
return ct;
|
||||
|
||||
err:
|
||||
err2:
|
||||
rcu_read_unlock();
|
||||
err1:
|
||||
nf_conntrack_free(ct);
|
||||
return err;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1289,38 +1295,25 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
||||
h = __nf_conntrack_find(&init_net, &rtuple);
|
||||
|
||||
if (h == NULL) {
|
||||
struct nf_conntrack_tuple master;
|
||||
struct nf_conntrack_tuple_hash *master_h = NULL;
|
||||
struct nf_conn *master_ct = NULL;
|
||||
err = -ENOENT;
|
||||
if (nlh->nlmsg_flags & NLM_F_CREATE) {
|
||||
struct nf_conn *ct;
|
||||
|
||||
if (cda[CTA_TUPLE_MASTER]) {
|
||||
err = ctnetlink_parse_tuple(cda,
|
||||
&master,
|
||||
CTA_TUPLE_MASTER,
|
||||
u3);
|
||||
if (err < 0)
|
||||
goto out_unlock;
|
||||
|
||||
master_h = __nf_conntrack_find(&init_net, &master);
|
||||
if (master_h == NULL) {
|
||||
err = -ENOENT;
|
||||
ct = ctnetlink_create_conntrack(cda, &otuple,
|
||||
&rtuple, u3);
|
||||
if (IS_ERR(ct)) {
|
||||
err = PTR_ERR(ct);
|
||||
goto out_unlock;
|
||||
}
|
||||
master_ct = nf_ct_tuplehash_to_ctrack(master_h);
|
||||
nf_conntrack_get(&master_ct->ct_general);
|
||||
}
|
||||
|
||||
err = -ENOENT;
|
||||
if (nlh->nlmsg_flags & NLM_F_CREATE)
|
||||
err = ctnetlink_create_conntrack(cda,
|
||||
&otuple,
|
||||
&rtuple,
|
||||
master_ct,
|
||||
NETLINK_CB(skb).pid,
|
||||
nlmsg_report(nlh));
|
||||
spin_unlock_bh(&nf_conntrack_lock);
|
||||
if (err < 0 && master_ct)
|
||||
nf_ct_put(master_ct);
|
||||
err = 0;
|
||||
nf_conntrack_get(&ct->ct_general);
|
||||
spin_unlock_bh(&nf_conntrack_lock);
|
||||
ctnetlink_event_report(ct,
|
||||
NETLINK_CB(skb).pid,
|
||||
nlmsg_report(nlh));
|
||||
nf_ct_put(ct);
|
||||
} else
|
||||
spin_unlock_bh(&nf_conntrack_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -1332,17 +1325,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
|
||||
if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
|
||||
struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
|
||||
|
||||
/* we only allow nat config for new conntracks */
|
||||
if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_unlock;
|
||||
}
|
||||
/* can't link an existing conntrack to a master */
|
||||
if (cda[CTA_TUPLE_MASTER]) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
err = ctnetlink_change_conntrack(ct, cda);
|
||||
if (err == 0) {
|
||||
nf_conntrack_get(&ct->ct_general);
|
||||
@ -1533,6 +1515,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
|
||||
nla_put_failure:
|
||||
rcu_read_unlock();
|
||||
nlmsg_failure:
|
||||
nfnetlink_set_err(0, 0, -ENOBUFS);
|
||||
kfree_skb(skb);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
@ -74,27 +74,6 @@ EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find);
|
||||
|
||||
/* this is guaranteed to always return a valid protocol helper, since
|
||||
* it falls back to generic_protocol */
|
||||
struct nf_conntrack_l4proto *
|
||||
nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto)
|
||||
{
|
||||
struct nf_conntrack_l4proto *p;
|
||||
|
||||
rcu_read_lock();
|
||||
p = __nf_ct_l4proto_find(l3proto, l4proto);
|
||||
if (!try_module_get(p->me))
|
||||
p = &nf_conntrack_l4proto_generic;
|
||||
rcu_read_unlock();
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get);
|
||||
|
||||
void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p)
|
||||
{
|
||||
module_put(p->me);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_l4proto_put);
|
||||
|
||||
struct nf_conntrack_l3proto *
|
||||
nf_ct_l3proto_find_get(u_int16_t l3proto)
|
||||
{
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/dccp.h>
|
||||
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
|
||||
#include <linux/netfilter/nfnetlink_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack_l4proto.h>
|
||||
@ -23,8 +26,6 @@
|
||||
|
||||
static DEFINE_RWLOCK(dccp_lock);
|
||||
|
||||
static int nf_ct_dccp_loose __read_mostly = 1;
|
||||
|
||||
/* Timeouts are based on values from RFC4340:
|
||||
*
|
||||
* - REQUEST:
|
||||
@ -72,16 +73,6 @@ static int nf_ct_dccp_loose __read_mostly = 1;
|
||||
|
||||
#define DCCP_MSL (2 * 60 * HZ)
|
||||
|
||||
static unsigned int dccp_timeout[CT_DCCP_MAX + 1] __read_mostly = {
|
||||
[CT_DCCP_REQUEST] = 2 * DCCP_MSL,
|
||||
[CT_DCCP_RESPOND] = 4 * DCCP_MSL,
|
||||
[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL,
|
||||
[CT_DCCP_OPEN] = 12 * 3600 * HZ,
|
||||
[CT_DCCP_CLOSEREQ] = 64 * HZ,
|
||||
[CT_DCCP_CLOSING] = 64 * HZ,
|
||||
[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL,
|
||||
};
|
||||
|
||||
static const char * const dccp_state_names[] = {
|
||||
[CT_DCCP_NONE] = "NONE",
|
||||
[CT_DCCP_REQUEST] = "REQUEST",
|
||||
@ -393,6 +384,22 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
|
||||
},
|
||||
};
|
||||
|
||||
/* this module per-net specifics */
|
||||
static int dccp_net_id;
|
||||
struct dccp_net {
|
||||
int dccp_loose;
|
||||
unsigned int dccp_timeout[CT_DCCP_MAX + 1];
|
||||
#ifdef CONFIG_SYSCTL
|
||||
struct ctl_table_header *sysctl_header;
|
||||
struct ctl_table *sysctl_table;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline struct dccp_net *dccp_pernet(struct net *net)
|
||||
{
|
||||
return net_generic(net, dccp_net_id);
|
||||
}
|
||||
|
||||
static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
|
||||
struct nf_conntrack_tuple *tuple)
|
||||
{
|
||||
@ -419,6 +426,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
|
||||
unsigned int dataoff)
|
||||
{
|
||||
struct net *net = nf_ct_net(ct);
|
||||
struct dccp_net *dn;
|
||||
struct dccp_hdr _dh, *dh;
|
||||
const char *msg;
|
||||
u_int8_t state;
|
||||
@ -429,7 +437,8 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
|
||||
state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
|
||||
switch (state) {
|
||||
default:
|
||||
if (nf_ct_dccp_loose == 0) {
|
||||
dn = dccp_pernet(net);
|
||||
if (dn->dccp_loose == 0) {
|
||||
msg = "nf_ct_dccp: not picking up existing connection ";
|
||||
goto out_invalid;
|
||||
}
|
||||
@ -465,6 +474,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
|
||||
u_int8_t pf, unsigned int hooknum)
|
||||
{
|
||||
struct net *net = nf_ct_net(ct);
|
||||
struct dccp_net *dn;
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
struct dccp_hdr _dh, *dh;
|
||||
u_int8_t type, old_state, new_state;
|
||||
@ -542,7 +552,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
|
||||
ct->proto.dccp.last_pkt = type;
|
||||
ct->proto.dccp.state = new_state;
|
||||
write_unlock_bh(&dccp_lock);
|
||||
nf_ct_refresh_acct(ct, ctinfo, skb, dccp_timeout[new_state]);
|
||||
|
||||
dn = dccp_pernet(net);
|
||||
nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]);
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
@ -660,13 +672,11 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
static unsigned int dccp_sysctl_table_users;
|
||||
static struct ctl_table_header *dccp_sysctl_header;
|
||||
static ctl_table dccp_sysctl_table[] = {
|
||||
/* template, data assigned later */
|
||||
static struct ctl_table dccp_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nf_conntrack_dccp_timeout_request",
|
||||
.data = &dccp_timeout[CT_DCCP_REQUEST],
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
@ -674,7 +684,6 @@ static ctl_table dccp_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nf_conntrack_dccp_timeout_respond",
|
||||
.data = &dccp_timeout[CT_DCCP_RESPOND],
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
@ -682,7 +691,6 @@ static ctl_table dccp_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nf_conntrack_dccp_timeout_partopen",
|
||||
.data = &dccp_timeout[CT_DCCP_PARTOPEN],
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
@ -690,7 +698,6 @@ static ctl_table dccp_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nf_conntrack_dccp_timeout_open",
|
||||
.data = &dccp_timeout[CT_DCCP_OPEN],
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
@ -698,7 +705,6 @@ static ctl_table dccp_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nf_conntrack_dccp_timeout_closereq",
|
||||
.data = &dccp_timeout[CT_DCCP_CLOSEREQ],
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
@ -706,7 +712,6 @@ static ctl_table dccp_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nf_conntrack_dccp_timeout_closing",
|
||||
.data = &dccp_timeout[CT_DCCP_CLOSING],
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
@ -714,7 +719,6 @@ static ctl_table dccp_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nf_conntrack_dccp_timeout_timewait",
|
||||
.data = &dccp_timeout[CT_DCCP_TIMEWAIT],
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
@ -722,8 +726,7 @@ static ctl_table dccp_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_UNNUMBERED,
|
||||
.procname = "nf_conntrack_dccp_loose",
|
||||
.data = &nf_ct_dccp_loose,
|
||||
.maxlen = sizeof(nf_ct_dccp_loose),
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
@ -751,11 +754,6 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
|
||||
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
|
||||
.nla_policy = nf_ct_port_nla_policy,
|
||||
#endif
|
||||
#ifdef CONFIG_SYSCTL
|
||||
.ctl_table_users = &dccp_sysctl_table_users,
|
||||
.ctl_table_header = &dccp_sysctl_header,
|
||||
.ctl_table = dccp_sysctl_table,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
|
||||
@ -776,34 +774,107 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
|
||||
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
|
||||
.nla_policy = nf_ct_port_nla_policy,
|
||||
#endif
|
||||
};
|
||||
|
||||
static __net_init int dccp_net_init(struct net *net)
|
||||
{
|
||||
struct dccp_net *dn;
|
||||
int err;
|
||||
|
||||
dn = kmalloc(sizeof(*dn), GFP_KERNEL);
|
||||
if (!dn)
|
||||
return -ENOMEM;
|
||||
|
||||
/* default values */
|
||||
dn->dccp_loose = 1;
|
||||
dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL;
|
||||
dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL;
|
||||
dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL;
|
||||
dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ;
|
||||
dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ;
|
||||
dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ;
|
||||
dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL;
|
||||
|
||||
err = net_assign_generic(net, dccp_net_id, dn);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
.ctl_table_users = &dccp_sysctl_table_users,
|
||||
.ctl_table_header = &dccp_sysctl_header,
|
||||
.ctl_table = dccp_sysctl_table,
|
||||
err = -ENOMEM;
|
||||
dn->sysctl_table = kmemdup(dccp_sysctl_table,
|
||||
sizeof(dccp_sysctl_table), GFP_KERNEL);
|
||||
if (!dn->sysctl_table)
|
||||
goto out;
|
||||
|
||||
dn->sysctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
|
||||
dn->sysctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
|
||||
dn->sysctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
|
||||
dn->sysctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
|
||||
dn->sysctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
|
||||
dn->sysctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
|
||||
dn->sysctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
|
||||
dn->sysctl_table[7].data = &dn->dccp_loose;
|
||||
|
||||
dn->sysctl_header = register_net_sysctl_table(net,
|
||||
nf_net_netfilter_sysctl_path, dn->sysctl_table);
|
||||
if (!dn->sysctl_header) {
|
||||
kfree(dn->sysctl_table);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
kfree(dn);
|
||||
return err;
|
||||
}
|
||||
|
||||
static __net_exit void dccp_net_exit(struct net *net)
|
||||
{
|
||||
struct dccp_net *dn = dccp_pernet(net);
|
||||
#ifdef CONFIG_SYSCTL
|
||||
unregister_net_sysctl_table(dn->sysctl_header);
|
||||
kfree(dn->sysctl_table);
|
||||
#endif
|
||||
kfree(dn);
|
||||
|
||||
net_assign_generic(net, dccp_net_id, NULL);
|
||||
}
|
||||
|
||||
static struct pernet_operations dccp_net_ops = {
|
||||
.init = dccp_net_init,
|
||||
.exit = dccp_net_exit,
|
||||
};
|
||||
|
||||
static int __init nf_conntrack_proto_dccp_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = nf_conntrack_l4proto_register(&dccp_proto4);
|
||||
err = register_pernet_gen_subsys(&dccp_net_id, &dccp_net_ops);
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
|
||||
err = nf_conntrack_l4proto_register(&dccp_proto6);
|
||||
err = nf_conntrack_l4proto_register(&dccp_proto4);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
|
||||
err = nf_conntrack_l4proto_register(&dccp_proto6);
|
||||
if (err < 0)
|
||||
goto err3;
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
err3:
|
||||
nf_conntrack_l4proto_unregister(&dccp_proto4);
|
||||
err2:
|
||||
unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops);
|
||||
err1:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit nf_conntrack_proto_dccp_fini(void)
|
||||
{
|
||||
unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops);
|
||||
nf_conntrack_l4proto_unregister(&dccp_proto6);
|
||||
nf_conntrack_l4proto_unregister(&dccp_proto4);
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ static struct ctl_table generic_compat_sysctl_table[] = {
|
||||
struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
|
||||
{
|
||||
.l3proto = PF_UNSPEC,
|
||||
.l4proto = 0,
|
||||
.l4proto = 255,
|
||||
.name = "unknown",
|
||||
.pkt_to_tuple = generic_pkt_to_tuple,
|
||||
.invert_tuple = generic_invert_tuple,
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include <net/netfilter/nf_conntrack_l4proto.h>
|
||||
#include <net/netfilter/nf_conntrack_ecache.h>
|
||||
#include <net/netfilter/nf_log.h>
|
||||
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
|
||||
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
|
||||
|
||||
/* Protects ct->proto.tcp */
|
||||
static DEFINE_RWLOCK(tcp_lock);
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include <net/netfilter/nf_conntrack_l4proto.h>
|
||||
#include <net/netfilter/nf_conntrack_ecache.h>
|
||||
#include <net/netfilter/nf_log.h>
|
||||
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
|
||||
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
|
||||
|
||||
static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ;
|
||||
static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ;
|
||||
|
@ -14,58 +14,63 @@
|
||||
LOG target modules */
|
||||
|
||||
#define NF_LOG_PREFIXLEN 128
|
||||
#define NFLOGGER_NAME_LEN 64
|
||||
|
||||
static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly;
|
||||
static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly;
|
||||
static DEFINE_MUTEX(nf_log_mutex);
|
||||
|
||||
/* return EBUSY if somebody else is registered, EEXIST if the same logger
|
||||
* is registred, 0 on success. */
|
||||
int nf_log_register(u_int8_t pf, const struct nf_logger *logger)
|
||||
static struct nf_logger *__find_logger(int pf, const char *str_logger)
|
||||
{
|
||||
int ret;
|
||||
struct nf_logger *t;
|
||||
|
||||
list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) {
|
||||
if (!strnicmp(str_logger, t->name, strlen(t->name)))
|
||||
return t;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* return EEXIST if the same logger is registred, 0 on success. */
|
||||
int nf_log_register(u_int8_t pf, struct nf_logger *logger)
|
||||
{
|
||||
const struct nf_logger *llog;
|
||||
|
||||
if (pf >= ARRAY_SIZE(nf_loggers))
|
||||
return -EINVAL;
|
||||
|
||||
/* Any setup of logging members must be done before
|
||||
* substituting pointer. */
|
||||
ret = mutex_lock_interruptible(&nf_log_mutex);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
mutex_lock(&nf_log_mutex);
|
||||
|
||||
if (!nf_loggers[pf])
|
||||
rcu_assign_pointer(nf_loggers[pf], logger);
|
||||
else if (nf_loggers[pf] == logger)
|
||||
ret = -EEXIST;
|
||||
else
|
||||
ret = -EBUSY;
|
||||
if (pf == NFPROTO_UNSPEC) {
|
||||
int i;
|
||||
for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
|
||||
list_add_tail(&(logger->list[i]), &(nf_loggers_l[i]));
|
||||
} else {
|
||||
/* register at end of list to honor first register win */
|
||||
list_add_tail(&logger->list[pf], &nf_loggers_l[pf]);
|
||||
llog = rcu_dereference(nf_loggers[pf]);
|
||||
if (llog == NULL)
|
||||
rcu_assign_pointer(nf_loggers[pf], logger);
|
||||
}
|
||||
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(nf_log_register);
|
||||
|
||||
void nf_log_unregister_pf(u_int8_t pf)
|
||||
{
|
||||
if (pf >= ARRAY_SIZE(nf_loggers))
|
||||
return;
|
||||
mutex_lock(&nf_log_mutex);
|
||||
rcu_assign_pointer(nf_loggers[pf], NULL);
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
|
||||
/* Give time to concurrent readers. */
|
||||
synchronize_rcu();
|
||||
}
|
||||
EXPORT_SYMBOL(nf_log_unregister_pf);
|
||||
|
||||
void nf_log_unregister(const struct nf_logger *logger)
|
||||
void nf_log_unregister(struct nf_logger *logger)
|
||||
{
|
||||
const struct nf_logger *c_logger;
|
||||
int i;
|
||||
|
||||
mutex_lock(&nf_log_mutex);
|
||||
for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) {
|
||||
if (nf_loggers[i] == logger)
|
||||
c_logger = rcu_dereference(nf_loggers[i]);
|
||||
if (c_logger == logger)
|
||||
rcu_assign_pointer(nf_loggers[i], NULL);
|
||||
list_del(&logger->list[i]);
|
||||
}
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
|
||||
@ -73,6 +78,27 @@ void nf_log_unregister(const struct nf_logger *logger)
|
||||
}
|
||||
EXPORT_SYMBOL(nf_log_unregister);
|
||||
|
||||
int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
|
||||
{
|
||||
mutex_lock(&nf_log_mutex);
|
||||
if (__find_logger(pf, logger->name) == NULL) {
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
return -ENOENT;
|
||||
}
|
||||
rcu_assign_pointer(nf_loggers[pf], logger);
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(nf_log_bind_pf);
|
||||
|
||||
void nf_log_unbind_pf(u_int8_t pf)
|
||||
{
|
||||
mutex_lock(&nf_log_mutex);
|
||||
rcu_assign_pointer(nf_loggers[pf], NULL);
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(nf_log_unbind_pf);
|
||||
|
||||
void nf_log_packet(u_int8_t pf,
|
||||
unsigned int hooknum,
|
||||
const struct sk_buff *skb,
|
||||
@ -129,13 +155,37 @@ static int seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
loff_t *pos = v;
|
||||
const struct nf_logger *logger;
|
||||
struct nf_logger *t;
|
||||
int ret;
|
||||
|
||||
logger = rcu_dereference(nf_loggers[*pos]);
|
||||
|
||||
if (!logger)
|
||||
return seq_printf(s, "%2lld NONE\n", *pos);
|
||||
ret = seq_printf(s, "%2lld NONE (", *pos);
|
||||
else
|
||||
ret = seq_printf(s, "%2lld %s (", *pos, logger->name);
|
||||
|
||||
return seq_printf(s, "%2lld %s\n", *pos, logger->name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&nf_log_mutex);
|
||||
list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) {
|
||||
ret = seq_printf(s, "%s", t->name);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
return ret;
|
||||
}
|
||||
if (&t->list[*pos] != nf_loggers_l[*pos].prev) {
|
||||
ret = seq_printf(s, ",");
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
|
||||
return seq_printf(s, ")\n");
|
||||
}
|
||||
|
||||
static const struct seq_operations nflog_seq_ops = {
|
||||
@ -158,15 +208,102 @@ static const struct file_operations nflog_file_ops = {
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
|
||||
#endif /* PROC_FS */
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
struct ctl_path nf_log_sysctl_path[] = {
|
||||
{ .procname = "net", .ctl_name = CTL_NET, },
|
||||
{ .procname = "netfilter", .ctl_name = NET_NETFILTER, },
|
||||
{ .procname = "nf_log", .ctl_name = CTL_UNNUMBERED, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
|
||||
static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
|
||||
static struct ctl_table_header *nf_log_dir_header;
|
||||
|
||||
static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp,
|
||||
void *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
const struct nf_logger *logger;
|
||||
int r = 0;
|
||||
int tindex = (unsigned long)table->extra1;
|
||||
|
||||
if (write) {
|
||||
if (!strcmp(buffer, "NONE")) {
|
||||
nf_log_unbind_pf(tindex);
|
||||
return 0;
|
||||
}
|
||||
mutex_lock(&nf_log_mutex);
|
||||
logger = __find_logger(tindex, buffer);
|
||||
if (logger == NULL) {
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
return -ENOENT;
|
||||
}
|
||||
rcu_assign_pointer(nf_loggers[tindex], logger);
|
||||
mutex_unlock(&nf_log_mutex);
|
||||
} else {
|
||||
rcu_read_lock();
|
||||
logger = rcu_dereference(nf_loggers[tindex]);
|
||||
if (!logger)
|
||||
table->data = "NONE";
|
||||
else
|
||||
table->data = logger->name;
|
||||
r = proc_dostring(table, write, filp, buffer, lenp, ppos);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static __init int netfilter_log_sysctl_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
|
||||
snprintf(nf_log_sysctl_fnames[i-NFPROTO_UNSPEC], 3, "%d", i);
|
||||
nf_log_sysctl_table[i].ctl_name = CTL_UNNUMBERED;
|
||||
nf_log_sysctl_table[i].procname =
|
||||
nf_log_sysctl_fnames[i-NFPROTO_UNSPEC];
|
||||
nf_log_sysctl_table[i].data = NULL;
|
||||
nf_log_sysctl_table[i].maxlen =
|
||||
NFLOGGER_NAME_LEN * sizeof(char);
|
||||
nf_log_sysctl_table[i].mode = 0644;
|
||||
nf_log_sysctl_table[i].proc_handler = nf_log_proc_dostring;
|
||||
nf_log_sysctl_table[i].extra1 = (void *)(unsigned long) i;
|
||||
}
|
||||
|
||||
nf_log_dir_header = register_sysctl_paths(nf_log_sysctl_path,
|
||||
nf_log_sysctl_table);
|
||||
if (!nf_log_dir_header)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static __init int netfilter_log_sysctl_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_SYSCTL */
|
||||
|
||||
int __init netfilter_log_init(void)
|
||||
{
|
||||
int i, r;
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (!proc_create("nf_log", S_IRUGO,
|
||||
proc_net_netfilter, &nflog_file_ops))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
/* Errors will trigger panic, unroll on error is unnecessary. */
|
||||
r = netfilter_log_sysctl_init();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
|
||||
INIT_LIST_HEAD(&(nf_loggers_l[i]));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -113,6 +113,12 @@ int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfnetlink_send);
|
||||
|
||||
void nfnetlink_set_err(u32 pid, u32 group, int error)
|
||||
{
|
||||
netlink_set_err(nfnl, pid, group, error);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfnetlink_set_err);
|
||||
|
||||
int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags)
|
||||
{
|
||||
return netlink_unicast(nfnl, skb, pid, flags);
|
||||
|
@ -693,7 +693,7 @@ nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static const struct nf_logger nfulnl_logger = {
|
||||
static struct nf_logger nfulnl_logger __read_mostly = {
|
||||
.name = "nfnetlink_log",
|
||||
.logfn = &nfulnl_log_packet,
|
||||
.me = THIS_MODULE,
|
||||
@ -725,9 +725,9 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
|
||||
/* Commands without queue context */
|
||||
switch (cmd->command) {
|
||||
case NFULNL_CFG_CMD_PF_BIND:
|
||||
return nf_log_register(pf, &nfulnl_logger);
|
||||
return nf_log_bind_pf(pf, &nfulnl_logger);
|
||||
case NFULNL_CFG_CMD_PF_UNBIND:
|
||||
nf_log_unregister_pf(pf);
|
||||
nf_log_unbind_pf(pf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -952,17 +952,25 @@ static int __init nfnetlink_log_init(void)
|
||||
goto cleanup_netlink_notifier;
|
||||
}
|
||||
|
||||
status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger);
|
||||
if (status < 0) {
|
||||
printk(KERN_ERR "log: failed to register logger\n");
|
||||
goto cleanup_subsys;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
if (!proc_create("nfnetlink_log", 0440,
|
||||
proc_net_netfilter, &nful_file_ops))
|
||||
goto cleanup_subsys;
|
||||
goto cleanup_logger;
|
||||
#endif
|
||||
return status;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
cleanup_logger:
|
||||
nf_log_unregister(&nfulnl_logger);
|
||||
#endif
|
||||
cleanup_subsys:
|
||||
nfnetlink_subsys_unregister(&nfulnl_subsys);
|
||||
#endif
|
||||
cleanup_netlink_notifier:
|
||||
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
|
||||
return status;
|
||||
|
@ -625,6 +625,20 @@ void xt_free_table_info(struct xt_table_info *info)
|
||||
}
|
||||
EXPORT_SYMBOL(xt_free_table_info);
|
||||
|
||||
void xt_table_entry_swap_rcu(struct xt_table_info *oldinfo,
|
||||
struct xt_table_info *newinfo)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
void *p = oldinfo->entries[cpu];
|
||||
rcu_assign_pointer(oldinfo->entries[cpu], newinfo->entries[cpu]);
|
||||
newinfo->entries[cpu] = p;
|
||||
}
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_table_entry_swap_rcu);
|
||||
|
||||
/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
|
||||
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
|
||||
const char *name)
|
||||
@ -671,21 +685,22 @@ xt_replace_table(struct xt_table *table,
|
||||
struct xt_table_info *oldinfo, *private;
|
||||
|
||||
/* Do the substitution. */
|
||||
write_lock_bh(&table->lock);
|
||||
mutex_lock(&table->lock);
|
||||
private = table->private;
|
||||
/* Check inside lock: is the old number correct? */
|
||||
if (num_counters != private->number) {
|
||||
duprintf("num_counters != table->private->number (%u/%u)\n",
|
||||
num_counters, private->number);
|
||||
write_unlock_bh(&table->lock);
|
||||
mutex_unlock(&table->lock);
|
||||
*error = -EAGAIN;
|
||||
return NULL;
|
||||
}
|
||||
oldinfo = private;
|
||||
table->private = newinfo;
|
||||
rcu_assign_pointer(table->private, newinfo);
|
||||
newinfo->initial_entries = oldinfo->initial_entries;
|
||||
write_unlock_bh(&table->lock);
|
||||
mutex_unlock(&table->lock);
|
||||
|
||||
synchronize_net();
|
||||
return oldinfo;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xt_replace_table);
|
||||
@ -719,7 +734,8 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table *table,
|
||||
|
||||
/* Simplifies replace_table code. */
|
||||
table->private = bootstrap;
|
||||
rwlock_init(&table->lock);
|
||||
mutex_init(&table->lock);
|
||||
|
||||
if (!xt_replace_table(table, 0, newinfo, &ret))
|
||||
goto unlock;
|
||||
|
||||
|
171
net/netfilter/xt_HL.c
Normal file
171
net/netfilter/xt_HL.c
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* TTL modification target for IP tables
|
||||
* (C) 2000,2005 by Harald Welte <laforge@netfilter.org>
|
||||
*
|
||||
* Hop Limit modification target for ip6tables
|
||||
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/checksum.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv4/ipt_TTL.h>
|
||||
#include <linux/netfilter_ipv6/ip6t_HL.h>
|
||||
|
||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
|
||||
MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int
|
||||
ttl_tg(struct sk_buff *skb, const struct xt_target_param *par)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
const struct ipt_TTL_info *info = par->targinfo;
|
||||
int new_ttl;
|
||||
|
||||
if (!skb_make_writable(skb, skb->len))
|
||||
return NF_DROP;
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
|
||||
switch (info->mode) {
|
||||
case IPT_TTL_SET:
|
||||
new_ttl = info->ttl;
|
||||
break;
|
||||
case IPT_TTL_INC:
|
||||
new_ttl = iph->ttl + info->ttl;
|
||||
if (new_ttl > 255)
|
||||
new_ttl = 255;
|
||||
break;
|
||||
case IPT_TTL_DEC:
|
||||
new_ttl = iph->ttl - info->ttl;
|
||||
if (new_ttl < 0)
|
||||
new_ttl = 0;
|
||||
break;
|
||||
default:
|
||||
new_ttl = iph->ttl;
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_ttl != iph->ttl) {
|
||||
csum_replace2(&iph->check, htons(iph->ttl << 8),
|
||||
htons(new_ttl << 8));
|
||||
iph->ttl = new_ttl;
|
||||
}
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hl_tg6(struct sk_buff *skb, const struct xt_target_param *par)
|
||||
{
|
||||
struct ipv6hdr *ip6h;
|
||||
const struct ip6t_HL_info *info = par->targinfo;
|
||||
int new_hl;
|
||||
|
||||
if (!skb_make_writable(skb, skb->len))
|
||||
return NF_DROP;
|
||||
|
||||
ip6h = ipv6_hdr(skb);
|
||||
|
||||
switch (info->mode) {
|
||||
case IP6T_HL_SET:
|
||||
new_hl = info->hop_limit;
|
||||
break;
|
||||
case IP6T_HL_INC:
|
||||
new_hl = ip6h->hop_limit + info->hop_limit;
|
||||
if (new_hl > 255)
|
||||
new_hl = 255;
|
||||
break;
|
||||
case IP6T_HL_DEC:
|
||||
new_hl = ip6h->hop_limit - info->hop_limit;
|
||||
if (new_hl < 0)
|
||||
new_hl = 0;
|
||||
break;
|
||||
default:
|
||||
new_hl = ip6h->hop_limit;
|
||||
break;
|
||||
}
|
||||
|
||||
ip6h->hop_limit = new_hl;
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static bool ttl_tg_check(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct ipt_TTL_info *info = par->targinfo;
|
||||
|
||||
if (info->mode > IPT_TTL_MAXMODE) {
|
||||
printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
|
||||
info->mode);
|
||||
return false;
|
||||
}
|
||||
if (info->mode != IPT_TTL_SET && info->ttl == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hl_tg6_check(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct ip6t_HL_info *info = par->targinfo;
|
||||
|
||||
if (info->mode > IP6T_HL_MAXMODE) {
|
||||
printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n",
|
||||
info->mode);
|
||||
return false;
|
||||
}
|
||||
if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
|
||||
printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
|
||||
"make sense with value 0\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct xt_target hl_tg_reg[] __read_mostly = {
|
||||
{
|
||||
.name = "TTL",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = ttl_tg,
|
||||
.targetsize = sizeof(struct ipt_TTL_info),
|
||||
.table = "mangle",
|
||||
.checkentry = ttl_tg_check,
|
||||
.me = THIS_MODULE,
|
||||
},
|
||||
{
|
||||
.name = "HL",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV6,
|
||||
.target = hl_tg6,
|
||||
.targetsize = sizeof(struct ip6t_HL_info),
|
||||
.table = "mangle",
|
||||
.checkentry = hl_tg6_check,
|
||||
.me = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init hl_tg_init(void)
|
||||
{
|
||||
return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
|
||||
}
|
||||
|
||||
static void __exit hl_tg_exit(void)
|
||||
{
|
||||
xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
|
||||
}
|
||||
|
||||
module_init(hl_tg_init);
|
||||
module_exit(hl_tg_exit);
|
||||
MODULE_ALIAS("ipt_TTL");
|
||||
MODULE_ALIAS("ip6t_HL");
|
161
net/netfilter/xt_LED.c
Normal file
161
net/netfilter/xt_LED.c
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* xt_LED.c - netfilter target to make LEDs blink upon packet matches
|
||||
*
|
||||
* Copyright (C) 2008 Adam Nielsen <a.nielsen@shikadi.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/netfilter/xt_LED.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>");
|
||||
MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match");
|
||||
|
||||
/*
|
||||
* This is declared in here (the kernel module) only, to avoid having these
|
||||
* dependencies in userspace code. This is what xt_led_info.internal_data
|
||||
* points to.
|
||||
*/
|
||||
struct xt_led_info_internal {
|
||||
struct led_trigger netfilter_led_trigger;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
led_tg(struct sk_buff *skb, const struct xt_target_param *par)
|
||||
{
|
||||
const struct xt_led_info *ledinfo = par->targinfo;
|
||||
struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
|
||||
|
||||
/*
|
||||
* If "always blink" is enabled, and there's still some time until the
|
||||
* LED will switch off, briefly switch it off now.
|
||||
*/
|
||||
if ((ledinfo->delay > 0) && ledinfo->always_blink &&
|
||||
timer_pending(&ledinternal->timer))
|
||||
led_trigger_event(&ledinternal->netfilter_led_trigger,LED_OFF);
|
||||
|
||||
led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL);
|
||||
|
||||
/* If there's a positive delay, start/update the timer */
|
||||
if (ledinfo->delay > 0) {
|
||||
mod_timer(&ledinternal->timer,
|
||||
jiffies + msecs_to_jiffies(ledinfo->delay));
|
||||
|
||||
/* Otherwise if there was no delay given, blink as fast as possible */
|
||||
} else if (ledinfo->delay == 0) {
|
||||
led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
|
||||
}
|
||||
|
||||
/* else the delay is negative, which means switch on and stay on */
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static void led_timeout_callback(unsigned long data)
|
||||
{
|
||||
struct xt_led_info *ledinfo = (struct xt_led_info *)data;
|
||||
struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
|
||||
|
||||
led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
|
||||
}
|
||||
|
||||
static bool led_tg_check(const struct xt_tgchk_param *par)
|
||||
{
|
||||
struct xt_led_info *ledinfo = par->targinfo;
|
||||
struct xt_led_info_internal *ledinternal;
|
||||
int err;
|
||||
|
||||
if (ledinfo->id[0] == '\0') {
|
||||
printk(KERN_ERR KBUILD_MODNAME ": No 'id' parameter given.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL);
|
||||
if (!ledinternal) {
|
||||
printk(KERN_CRIT KBUILD_MODNAME ": out of memory\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
ledinternal->netfilter_led_trigger.name = ledinfo->id;
|
||||
|
||||
err = led_trigger_register(&ledinternal->netfilter_led_trigger);
|
||||
if (err) {
|
||||
printk(KERN_CRIT KBUILD_MODNAME
|
||||
": led_trigger_register() failed\n");
|
||||
if (err == -EEXIST)
|
||||
printk(KERN_ERR KBUILD_MODNAME
|
||||
": Trigger name is already in use.\n");
|
||||
goto exit_alloc;
|
||||
}
|
||||
|
||||
/* See if we need to set up a timer */
|
||||
if (ledinfo->delay > 0)
|
||||
setup_timer(&ledinternal->timer, led_timeout_callback,
|
||||
(unsigned long)ledinfo);
|
||||
|
||||
ledinfo->internal_data = ledinternal;
|
||||
|
||||
return true;
|
||||
|
||||
exit_alloc:
|
||||
kfree(ledinternal);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void led_tg_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
const struct xt_led_info *ledinfo = par->targinfo;
|
||||
struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
|
||||
|
||||
if (ledinfo->delay > 0)
|
||||
del_timer_sync(&ledinternal->timer);
|
||||
|
||||
led_trigger_unregister(&ledinternal->netfilter_led_trigger);
|
||||
kfree(ledinternal);
|
||||
}
|
||||
|
||||
static struct xt_target led_tg_reg __read_mostly = {
|
||||
.name = "LED",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.target = led_tg,
|
||||
.targetsize = XT_ALIGN(sizeof(struct xt_led_info)),
|
||||
.checkentry = led_tg_check,
|
||||
.destroy = led_tg_destroy,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init led_tg_init(void)
|
||||
{
|
||||
return xt_register_target(&led_tg_reg);
|
||||
}
|
||||
|
||||
static void __exit led_tg_exit(void)
|
||||
{
|
||||
xt_unregister_target(&led_tg_reg);
|
||||
}
|
||||
|
||||
module_init(led_tg_init);
|
||||
module_exit(led_tg_exit);
|
164
net/netfilter/xt_cluster.c
Normal file
164
net/netfilter/xt_cluster.c
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* (C) 2008-2009 Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <linux/netfilter/xt_cluster.h>
|
||||
|
||||
static inline u_int32_t nf_ct_orig_ipv4_src(const struct nf_conn *ct)
|
||||
{
|
||||
return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
|
||||
}
|
||||
|
||||
static inline const void *nf_ct_orig_ipv6_src(const struct nf_conn *ct)
|
||||
{
|
||||
return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6;
|
||||
}
|
||||
|
||||
static inline u_int32_t
|
||||
xt_cluster_hash_ipv4(u_int32_t ip, const struct xt_cluster_match_info *info)
|
||||
{
|
||||
return jhash_1word(ip, info->hash_seed);
|
||||
}
|
||||
|
||||
static inline u_int32_t
|
||||
xt_cluster_hash_ipv6(const void *ip, const struct xt_cluster_match_info *info)
|
||||
{
|
||||
return jhash2(ip, NF_CT_TUPLE_L3SIZE / sizeof(__u32), info->hash_seed);
|
||||
}
|
||||
|
||||
static inline u_int32_t
|
||||
xt_cluster_hash(const struct nf_conn *ct,
|
||||
const struct xt_cluster_match_info *info)
|
||||
{
|
||||
u_int32_t hash = 0;
|
||||
|
||||
switch(nf_ct_l3num(ct)) {
|
||||
case AF_INET:
|
||||
hash = xt_cluster_hash_ipv4(nf_ct_orig_ipv4_src(ct), info);
|
||||
break;
|
||||
case AF_INET6:
|
||||
hash = xt_cluster_hash_ipv6(nf_ct_orig_ipv6_src(ct), info);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
return (((u64)hash * info->total_nodes) >> 32);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family)
|
||||
{
|
||||
bool is_multicast = false;
|
||||
|
||||
switch(family) {
|
||||
case NFPROTO_IPV4:
|
||||
is_multicast = ipv4_is_multicast(ip_hdr(skb)->daddr);
|
||||
break;
|
||||
case NFPROTO_IPV6:
|
||||
is_multicast = ipv6_addr_type(&ipv6_hdr(skb)->daddr) &
|
||||
IPV6_ADDR_MULTICAST;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
return is_multicast;
|
||||
}
|
||||
|
||||
static bool
|
||||
xt_cluster_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
struct sk_buff *pskb = (struct sk_buff *)skb;
|
||||
const struct xt_cluster_match_info *info = par->matchinfo;
|
||||
const struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
unsigned long hash;
|
||||
|
||||
/* This match assumes that all nodes see the same packets. This can be
|
||||
* achieved if the switch that connects the cluster nodes support some
|
||||
* sort of 'port mirroring'. However, if your switch does not support
|
||||
* this, your cluster nodes can reply ARP request using a multicast MAC
|
||||
* address. Thus, your switch will flood the same packets to the
|
||||
* cluster nodes with the same multicast MAC address. Using a multicast
|
||||
* link address is a RFC 1812 (section 3.3.2) violation, but this works
|
||||
* fine in practise.
|
||||
*
|
||||
* Unfortunately, if you use the multicast MAC address, the link layer
|
||||
* sets skbuff's pkt_type to PACKET_MULTICAST, which is not accepted
|
||||
* by TCP and others for packets coming to this node. For that reason,
|
||||
* this match mangles skbuff's pkt_type if it detects a packet
|
||||
* addressed to a unicast address but using PACKET_MULTICAST. Yes, I
|
||||
* know, matches should not alter packets, but we are doing this here
|
||||
* because we would need to add a PKTTYPE target for this sole purpose.
|
||||
*/
|
||||
if (!xt_cluster_is_multicast_addr(skb, par->family) &&
|
||||
skb->pkt_type == PACKET_MULTICAST) {
|
||||
pskb->pkt_type = PACKET_HOST;
|
||||
}
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (ct == NULL)
|
||||
return false;
|
||||
|
||||
if (ct == &nf_conntrack_untracked)
|
||||
return false;
|
||||
|
||||
if (ct->master)
|
||||
hash = xt_cluster_hash(ct->master, info);
|
||||
else
|
||||
hash = xt_cluster_hash(ct, info);
|
||||
|
||||
return !!((1 << hash) & info->node_mask) ^
|
||||
!!(info->flags & XT_CLUSTER_F_INV);
|
||||
}
|
||||
|
||||
static bool xt_cluster_mt_checkentry(const struct xt_mtchk_param *par)
|
||||
{
|
||||
struct xt_cluster_match_info *info = par->matchinfo;
|
||||
|
||||
if (info->node_mask >= (1 << info->total_nodes)) {
|
||||
printk(KERN_ERR "xt_cluster: this node mask cannot be "
|
||||
"higher than the total number of nodes\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct xt_match xt_cluster_match __read_mostly = {
|
||||
.name = "cluster",
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.match = xt_cluster_mt,
|
||||
.checkentry = xt_cluster_mt_checkentry,
|
||||
.matchsize = sizeof(struct xt_cluster_match_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init xt_cluster_mt_init(void)
|
||||
{
|
||||
return xt_register_match(&xt_cluster_match);
|
||||
}
|
||||
|
||||
static void __exit xt_cluster_mt_fini(void)
|
||||
{
|
||||
xt_unregister_match(&xt_cluster_match);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Xtables: hash-based cluster match");
|
||||
MODULE_ALIAS("ipt_cluster");
|
||||
MODULE_ALIAS("ip6t_cluster");
|
||||
module_init(xt_cluster_mt_init);
|
||||
module_exit(xt_cluster_mt_fini);
|
@ -149,7 +149,7 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht,
|
||||
/* initialize hash with random val at the time we allocate
|
||||
* the first hashtable entry */
|
||||
if (!ht->rnd_initialized) {
|
||||
get_random_bytes(&ht->rnd, 4);
|
||||
get_random_bytes(&ht->rnd, sizeof(ht->rnd));
|
||||
ht->rnd_initialized = 1;
|
||||
}
|
||||
|
||||
@ -565,8 +565,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
|
||||
static bool
|
||||
hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
const struct xt_hashlimit_info *r =
|
||||
((const struct xt_hashlimit_info *)par->matchinfo)->u.master;
|
||||
const struct xt_hashlimit_info *r = par->matchinfo;
|
||||
struct xt_hashlimit_htable *hinfo = r->hinfo;
|
||||
unsigned long now = jiffies;
|
||||
struct dsthash_ent *dh;
|
||||
@ -702,8 +701,6 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
|
||||
}
|
||||
mutex_unlock(&hlimit_mutex);
|
||||
|
||||
/* Ugly hack: For SMP, we only want to use one set */
|
||||
r->u.master = r;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
108
net/netfilter/xt_hl.c
Normal file
108
net/netfilter/xt_hl.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* IP tables module for matching the value of the TTL
|
||||
* (C) 2000,2001 by Harald Welte <laforge@netfilter.org>
|
||||
*
|
||||
* Hop Limit matching module
|
||||
* (C) 2001-2002 Maciej Soltysiak <solt@dns.toxicfilms.tv>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv4/ipt_ttl.h>
|
||||
#include <linux/netfilter_ipv6/ip6t_hl.h>
|
||||
|
||||
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
|
||||
MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_ttl");
|
||||
MODULE_ALIAS("ip6t_hl");
|
||||
|
||||
static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
const struct ipt_ttl_info *info = par->matchinfo;
|
||||
const u8 ttl = ip_hdr(skb)->ttl;
|
||||
|
||||
switch (info->mode) {
|
||||
case IPT_TTL_EQ:
|
||||
return ttl == info->ttl;
|
||||
case IPT_TTL_NE:
|
||||
return ttl != info->ttl;
|
||||
case IPT_TTL_LT:
|
||||
return ttl < info->ttl;
|
||||
case IPT_TTL_GT:
|
||||
return ttl > info->ttl;
|
||||
default:
|
||||
printk(KERN_WARNING "ipt_ttl: unknown mode %d\n",
|
||||
info->mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
const struct ip6t_hl_info *info = par->matchinfo;
|
||||
const struct ipv6hdr *ip6h = ipv6_hdr(skb);
|
||||
|
||||
switch (info->mode) {
|
||||
case IP6T_HL_EQ:
|
||||
return ip6h->hop_limit == info->hop_limit;
|
||||
break;
|
||||
case IP6T_HL_NE:
|
||||
return ip6h->hop_limit != info->hop_limit;
|
||||
break;
|
||||
case IP6T_HL_LT:
|
||||
return ip6h->hop_limit < info->hop_limit;
|
||||
break;
|
||||
case IP6T_HL_GT:
|
||||
return ip6h->hop_limit > info->hop_limit;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "ip6t_hl: unknown mode %d\n",
|
||||
info->mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct xt_match hl_mt_reg[] __read_mostly = {
|
||||
{
|
||||
.name = "ttl",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.match = ttl_mt,
|
||||
.matchsize = sizeof(struct ipt_ttl_info),
|
||||
.me = THIS_MODULE,
|
||||
},
|
||||
{
|
||||
.name = "hl",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV6,
|
||||
.match = hl_mt6,
|
||||
.matchsize = sizeof(struct ip6t_hl_info),
|
||||
.me = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init hl_mt_init(void)
|
||||
{
|
||||
return xt_register_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg));
|
||||
}
|
||||
|
||||
static void __exit hl_mt_exit(void)
|
||||
{
|
||||
xt_unregister_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg));
|
||||
}
|
||||
|
||||
module_init(hl_mt_init);
|
||||
module_exit(hl_mt_exit);
|
@ -14,6 +14,11 @@
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_limit.h>
|
||||
|
||||
struct xt_limit_priv {
|
||||
unsigned long prev;
|
||||
uint32_t credit;
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
|
||||
MODULE_DESCRIPTION("Xtables: rate-limit match");
|
||||
@ -60,18 +65,18 @@ static DEFINE_SPINLOCK(limit_lock);
|
||||
static bool
|
||||
limit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
struct xt_rateinfo *r =
|
||||
((const struct xt_rateinfo *)par->matchinfo)->master;
|
||||
const struct xt_rateinfo *r = par->matchinfo;
|
||||
struct xt_limit_priv *priv = r->master;
|
||||
unsigned long now = jiffies;
|
||||
|
||||
spin_lock_bh(&limit_lock);
|
||||
r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY;
|
||||
if (r->credit > r->credit_cap)
|
||||
r->credit = r->credit_cap;
|
||||
priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
|
||||
if (priv->credit > r->credit_cap)
|
||||
priv->credit = r->credit_cap;
|
||||
|
||||
if (r->credit >= r->cost) {
|
||||
if (priv->credit >= r->cost) {
|
||||
/* We're not limited. */
|
||||
r->credit -= r->cost;
|
||||
priv->credit -= r->cost;
|
||||
spin_unlock_bh(&limit_lock);
|
||||
return true;
|
||||
}
|
||||
@ -95,6 +100,7 @@ user2credits(u_int32_t user)
|
||||
static bool limit_mt_check(const struct xt_mtchk_param *par)
|
||||
{
|
||||
struct xt_rateinfo *r = par->matchinfo;
|
||||
struct xt_limit_priv *priv;
|
||||
|
||||
/* Check for overflow. */
|
||||
if (r->burst == 0
|
||||
@ -104,19 +110,30 @@ static bool limit_mt_check(const struct xt_mtchk_param *par)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* For SMP, we only want to use one set of counters. */
|
||||
r->master = r;
|
||||
priv = kmalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* For SMP, we only want to use one set of state. */
|
||||
r->master = priv;
|
||||
if (r->cost == 0) {
|
||||
/* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
|
||||
128. */
|
||||
r->prev = jiffies;
|
||||
r->credit = user2credits(r->avg * r->burst); /* Credits full. */
|
||||
priv->prev = jiffies;
|
||||
priv->credit = user2credits(r->avg * r->burst); /* Credits full. */
|
||||
r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
|
||||
r->cost = user2credits(r->avg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void limit_mt_destroy(const struct xt_mtdtor_param *par)
|
||||
{
|
||||
const struct xt_rateinfo *info = par->matchinfo;
|
||||
|
||||
kfree(info->master);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_xt_rateinfo {
|
||||
u_int32_t avg;
|
||||
@ -167,6 +184,7 @@ static struct xt_match limit_mt_reg __read_mostly = {
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.match = limit_mt,
|
||||
.checkentry = limit_mt_check,
|
||||
.destroy = limit_mt_destroy,
|
||||
.matchsize = sizeof(struct xt_rateinfo),
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compatsize = sizeof(struct compat_xt_rateinfo),
|
||||
|
@ -20,13 +20,30 @@ MODULE_DESCRIPTION("Xtables: Bridge physical device match");
|
||||
MODULE_ALIAS("ipt_physdev");
|
||||
MODULE_ALIAS("ip6t_physdev");
|
||||
|
||||
static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
|
||||
{
|
||||
const unsigned long *a = (const unsigned long *)_a;
|
||||
const unsigned long *b = (const unsigned long *)_b;
|
||||
const unsigned long *mask = (const unsigned long *)_mask;
|
||||
unsigned long ret;
|
||||
|
||||
ret = (a[0] ^ b[0]) & mask[0];
|
||||
if (IFNAMSIZ > sizeof(unsigned long))
|
||||
ret |= (a[1] ^ b[1]) & mask[1];
|
||||
if (IFNAMSIZ > 2 * sizeof(unsigned long))
|
||||
ret |= (a[2] ^ b[2]) & mask[2];
|
||||
if (IFNAMSIZ > 3 * sizeof(unsigned long))
|
||||
ret |= (a[3] ^ b[3]) & mask[3];
|
||||
BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
int i;
|
||||
static const char nulldevname[IFNAMSIZ];
|
||||
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
|
||||
const struct xt_physdev_info *info = par->matchinfo;
|
||||
bool ret;
|
||||
unsigned long ret;
|
||||
const char *indev, *outdev;
|
||||
const struct nf_bridge_info *nf_bridge;
|
||||
|
||||
@ -68,11 +85,7 @@ physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
if (!(info->bitmask & XT_PHYSDEV_OP_IN))
|
||||
goto match_outdev;
|
||||
indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
|
||||
for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) {
|
||||
ret |= (((const unsigned int *)indev)[i]
|
||||
^ ((const unsigned int *)info->physindev)[i])
|
||||
& ((const unsigned int *)info->in_mask)[i];
|
||||
}
|
||||
ret = ifname_compare(indev, info->physindev, info->in_mask);
|
||||
|
||||
if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN))
|
||||
return false;
|
||||
@ -82,13 +95,9 @@ match_outdev:
|
||||
return true;
|
||||
outdev = nf_bridge->physoutdev ?
|
||||
nf_bridge->physoutdev->name : nulldevname;
|
||||
for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) {
|
||||
ret |= (((const unsigned int *)outdev)[i]
|
||||
^ ((const unsigned int *)info->physoutdev)[i])
|
||||
& ((const unsigned int *)info->out_mask)[i];
|
||||
}
|
||||
ret = ifname_compare(outdev, info->physoutdev, info->out_mask);
|
||||
|
||||
return ret ^ !(info->invert & XT_PHYSDEV_OP_OUT);
|
||||
return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT));
|
||||
}
|
||||
|
||||
static bool physdev_mt_check(const struct xt_mtchk_param *par)
|
||||
|
@ -9,6 +9,10 @@
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_quota.h>
|
||||
|
||||
struct xt_quota_priv {
|
||||
uint64_t quota;
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
|
||||
MODULE_DESCRIPTION("Xtables: countdown quota match");
|
||||
@ -20,18 +24,20 @@ static DEFINE_SPINLOCK(quota_lock);
|
||||
static bool
|
||||
quota_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
struct xt_quota_info *q =
|
||||
((const struct xt_quota_info *)par->matchinfo)->master;
|
||||
struct xt_quota_info *q = (void *)par->matchinfo;
|
||||
struct xt_quota_priv *priv = q->master;
|
||||
bool ret = q->flags & XT_QUOTA_INVERT;
|
||||
|
||||
spin_lock_bh("a_lock);
|
||||
if (q->quota >= skb->len) {
|
||||
q->quota -= skb->len;
|
||||
if (priv->quota >= skb->len) {
|
||||
priv->quota -= skb->len;
|
||||
ret = !ret;
|
||||
} else {
|
||||
/* we do not allow even small packets from now on */
|
||||
q->quota = 0;
|
||||
priv->quota = 0;
|
||||
}
|
||||
/* Copy quota back to matchinfo so that iptables can display it */
|
||||
q->quota = priv->quota;
|
||||
spin_unlock_bh("a_lock);
|
||||
|
||||
return ret;
|
||||
@ -43,17 +49,28 @@ static bool quota_mt_check(const struct xt_mtchk_param *par)
|
||||
|
||||
if (q->flags & ~XT_QUOTA_MASK)
|
||||
return false;
|
||||
/* For SMP, we only want to use one set of counters. */
|
||||
q->master = q;
|
||||
|
||||
q->master = kmalloc(sizeof(*q->master), GFP_KERNEL);
|
||||
if (q->master == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void quota_mt_destroy(const struct xt_mtdtor_param *par)
|
||||
{
|
||||
const struct xt_quota_info *q = par->matchinfo;
|
||||
|
||||
kfree(q->master);
|
||||
}
|
||||
|
||||
static struct xt_match quota_mt_reg __read_mostly = {
|
||||
.name = "quota",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.match = quota_mt,
|
||||
.checkentry = quota_mt_check,
|
||||
.destroy = quota_mt_destroy,
|
||||
.matchsize = sizeof(struct xt_quota_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@ -16,6 +16,10 @@
|
||||
#include <linux/netfilter/xt_statistic.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
struct xt_statistic_priv {
|
||||
uint32_t count;
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)");
|
||||
@ -27,7 +31,7 @@ static DEFINE_SPINLOCK(nth_lock);
|
||||
static bool
|
||||
statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
{
|
||||
struct xt_statistic_info *info = (void *)par->matchinfo;
|
||||
const struct xt_statistic_info *info = par->matchinfo;
|
||||
bool ret = info->flags & XT_STATISTIC_INVERT;
|
||||
|
||||
switch (info->mode) {
|
||||
@ -36,10 +40,9 @@ statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
ret = !ret;
|
||||
break;
|
||||
case XT_STATISTIC_MODE_NTH:
|
||||
info = info->master;
|
||||
spin_lock_bh(&nth_lock);
|
||||
if (info->u.nth.count++ == info->u.nth.every) {
|
||||
info->u.nth.count = 0;
|
||||
if (info->master->count++ == info->u.nth.every) {
|
||||
info->master->count = 0;
|
||||
ret = !ret;
|
||||
}
|
||||
spin_unlock_bh(&nth_lock);
|
||||
@ -56,16 +59,31 @@ static bool statistic_mt_check(const struct xt_mtchk_param *par)
|
||||
if (info->mode > XT_STATISTIC_MODE_MAX ||
|
||||
info->flags & ~XT_STATISTIC_MASK)
|
||||
return false;
|
||||
info->master = info;
|
||||
|
||||
info->master = kzalloc(sizeof(*info->master), GFP_KERNEL);
|
||||
if (info->master == NULL) {
|
||||
printk(KERN_ERR KBUILD_MODNAME ": Out of memory\n");
|
||||
return false;
|
||||
}
|
||||
info->master->count = info->u.nth.count;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void statistic_mt_destroy(const struct xt_mtdtor_param *par)
|
||||
{
|
||||
const struct xt_statistic_info *info = par->matchinfo;
|
||||
|
||||
kfree(info->master);
|
||||
}
|
||||
|
||||
static struct xt_match xt_statistic_mt_reg __read_mostly = {
|
||||
.name = "statistic",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.match = statistic_mt,
|
||||
.checkentry = statistic_mt_check,
|
||||
.destroy = statistic_mt_destroy,
|
||||
.matchsize = sizeof(struct xt_statistic_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@ -1117,6 +1117,7 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
|
||||
|
||||
read_unlock(&nl_table_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(netlink_set_err);
|
||||
|
||||
/* must be called with netlink table grabbed */
|
||||
static void netlink_update_socket_mc(struct netlink_sock *nlk,
|
||||
|
@ -61,7 +61,7 @@ static struct ctl_table_root net_sysctl_root = {
|
||||
static int net_ctl_ro_header_perms(struct ctl_table_root *root,
|
||||
struct nsproxy *namespaces, struct ctl_table *table)
|
||||
{
|
||||
if (namespaces->net_ns == &init_net)
|
||||
if (net_eq(namespaces->net_ns, &init_net))
|
||||
return table->mode;
|
||||
else
|
||||
return table->mode & ~0222;
|
||||
|
Loading…
Reference in New Issue
Block a user