提交 749f621e 编写于 作者: D David S. Miller
......@@ -114,15 +114,17 @@ struct nf_sockopt_ops {
int set_optmin;
int set_optmax;
int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len);
#ifdef CONFIG_COMPAT
int (*compat_set)(struct sock *sk, int optval,
void __user *user, unsigned int len);
#endif
int get_optmin;
int get_optmax;
int (*get)(struct sock *sk, int optval, void __user *user, int *len);
#ifdef CONFIG_COMPAT
int (*compat_get)(struct sock *sk, int optval,
void __user *user, int *len);
#endif
/* Use the module struct to lock set/get code in place */
struct module *owner;
};
......@@ -161,11 +163,8 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *), int thresh,
int cond)
int (*okfn)(struct sk_buff *), int thresh)
{
if (!cond)
return 1;
#ifndef CONFIG_NETFILTER_DEBUG
if (list_empty(&nf_hooks[pf][hook]))
return 1;
......@@ -177,7 +176,7 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct sk_buff *))
{
return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN, 1);
return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN);
}
/* Activate hook; either okfn or kfree_skb called, unless a hook
......@@ -197,36 +196,48 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
coders :)
*/
/* This is gross, but inline doesn't cut it for avoiding the function
call in fast path: gcc doesn't inline (needs value tracking?). --RR */
/* HX: It's slightly less gross now. */
#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \
({int __ret; \
if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh, 1)) == 1)\
__ret = (okfn)(skb); \
__ret;})
static inline int
NF_HOOK_THRESH(uint8_t pf, unsigned int hook, struct sk_buff *skb,
struct net_device *in, struct net_device *out,
int (*okfn)(struct sk_buff *), int thresh)
{
int ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, thresh);
if (ret == 1)
ret = okfn(skb);
return ret;
}
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \
({int __ret; \
if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, INT_MIN, cond)) == 1)\
__ret = (okfn)(skb); \
__ret;})
static inline int
NF_HOOK_COND(uint8_t pf, unsigned int hook, struct sk_buff *skb,
struct net_device *in, struct net_device *out,
int (*okfn)(struct sk_buff *), bool cond)
{
int ret = 1;
if (cond ||
(ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, INT_MIN) == 1))
ret = okfn(skb);
return ret;
}
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN)
static inline int
NF_HOOK(uint8_t pf, unsigned int hook, struct sk_buff *skb,
struct net_device *in, struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return NF_HOOK_THRESH(pf, hook, skb, in, out, okfn, INT_MIN);
}
/* Call setsockopt() */
int nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt,
unsigned int len);
int nf_getsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt,
int *len);
#ifdef CONFIG_COMPAT
int compat_nf_setsockopt(struct sock *sk, u_int8_t pf, int optval,
char __user *opt, unsigned int len);
int compat_nf_getsockopt(struct sock *sk, u_int8_t pf, int optval,
char __user *opt, int *len);
#endif
/* Call this before modifying an existing packet: ensures it is
modifiable and linear to the point you care about (writable_len).
......@@ -325,8 +336,7 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
int (*okfn)(struct sk_buff *), int thresh,
int cond)
int (*okfn)(struct sk_buff *), int thresh)
{
return okfn(skb);
}
......
......@@ -6,6 +6,7 @@ header-y += nfnetlink_queue.h
header-y += xt_CLASSIFY.h
header-y += xt_CONNMARK.h
header-y += xt_CONNSECMARK.h
header-y += xt_CT.h
header-y += xt_DSCP.h
header-y += xt_LED.h
header-y += xt_MARK.h
......
......@@ -72,6 +72,28 @@ enum ip_conntrack_status {
/* Connection has fixed timeout. */
IPS_FIXED_TIMEOUT_BIT = 10,
IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
/* Conntrack is a template */
IPS_TEMPLATE_BIT = 11,
IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
};
/* Connection tracking event types */
enum ip_conntrack_events {
IPCT_NEW, /* new conntrack */
IPCT_RELATED, /* related conntrack */
IPCT_DESTROY, /* destroyed conntrack */
IPCT_REPLY, /* connection has seen two-way traffic */
IPCT_ASSURED, /* connection status has changed to assured */
IPCT_PROTOINFO, /* protocol information has changed */
IPCT_HELPER, /* new helper has been set */
IPCT_MARK, /* new mark has been set */
IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */
IPCT_SECMARK, /* new security mark has been set */
};
enum ip_conntrack_expect_events {
IPEXP_NEW, /* new expectation */
};
#ifdef __KERNEL__
......
......@@ -14,6 +14,7 @@ enum sip_expectation_classes {
SIP_EXPECT_SIGNALLING,
SIP_EXPECT_AUDIO,
SIP_EXPECT_VIDEO,
SIP_EXPECT_IMAGE,
__SIP_EXPECT_MAX
};
#define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1)
......@@ -34,10 +35,10 @@ struct sdp_media_type {
struct sip_handler {
const char *method;
unsigned int len;
int (*request)(struct sk_buff *skb,
int (*request)(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int cseq);
int (*response)(struct sk_buff *skb,
int (*response)(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int cseq, unsigned int code);
};
......@@ -84,7 +85,8 @@ enum sip_header_types {
SIP_HDR_FROM,
SIP_HDR_TO,
SIP_HDR_CONTACT,
SIP_HDR_VIA,
SIP_HDR_VIA_UDP,
SIP_HDR_VIA_TCP,
SIP_HDR_EXPIRES,
SIP_HDR_CONTENT_LENGTH,
};
......@@ -100,33 +102,40 @@ enum sdp_header_types {
};
extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen);
extern void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, s16 off);
extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
struct nf_conntrack_expect *exp,
unsigned int matchoff,
unsigned int matchlen);
extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
unsigned int sdpoff,
enum sdp_header_types type,
enum sdp_header_types term,
const union nf_inet_addr *addr);
extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
unsigned int matchoff,
unsigned int matchlen,
u_int16_t port);
extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
unsigned int sdpoff,
const union nf_inet_addr *addr);
extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
struct nf_conntrack_expect *rtp_exp,
......
......@@ -73,11 +73,11 @@ struct nfnetlink_subsystem {
extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n);
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,
extern int nfnetlink_has_listeners(struct net *net, unsigned int group);
extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group,
int echo, gfp_t flags);
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 nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error);
extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags);
extern void nfnl_lock(void);
extern void nfnl_unlock(void);
......
......@@ -40,6 +40,7 @@ enum ctattr_type {
CTA_NAT_SEQ_ADJ_ORIG,
CTA_NAT_SEQ_ADJ_REPLY,
CTA_SECMARK,
CTA_ZONE,
__CTA_MAX
};
#define CTA_MAX (__CTA_MAX - 1)
......@@ -159,6 +160,7 @@ enum ctattr_expect {
CTA_EXPECT_TIMEOUT,
CTA_EXPECT_ID,
CTA_EXPECT_HELP_NAME,
CTA_EXPECT_ZONE,
__CTA_EXPECT_MAX
};
#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1)
......
......@@ -93,8 +93,7 @@ struct _xt_align {
__u64 u64;
};
#define XT_ALIGN(s) (((s) + (__alignof__(struct _xt_align)-1)) \
& ~(__alignof__(struct _xt_align)-1))
#define XT_ALIGN(s) ALIGN((s), __alignof__(struct _xt_align))
/* Standard return verdict, or do jump. */
#define XT_STANDARD_TARGET ""
......@@ -205,6 +204,7 @@ struct xt_match_param {
* @hook_mask: via which hooks the new rule is reachable
*/
struct xt_mtchk_param {
struct net *net;
const char *table;
const void *entryinfo;
const struct xt_match *match;
......@@ -215,6 +215,7 @@ struct xt_mtchk_param {
/* Match destructor parameters */
struct xt_mtdtor_param {
struct net *net;
const struct xt_match *match;
void *matchinfo;
u_int8_t family;
......@@ -247,6 +248,7 @@ struct xt_target_param {
* Other fields see above.
*/
struct xt_tgchk_param {
struct net *net;
const char *table;
const void *entryinfo;
const struct xt_target *target;
......@@ -257,6 +259,7 @@ struct xt_tgchk_param {
/* Target destructor parameters */
struct xt_tgdtor_param {
struct net *net;
const struct xt_target *target;
void *targinfo;
u_int8_t family;
......@@ -281,11 +284,11 @@ struct xt_match {
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_mtdtor_param *);
#ifdef CONFIG_COMPAT
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, void *src);
int (*compat_to_user)(void __user *dst, void *src);
void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src);
#endif
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
......@@ -294,7 +297,9 @@ struct xt_match {
const char *table;
unsigned int matchsize;
#ifdef CONFIG_COMPAT
unsigned int compatsize;
#endif
unsigned int hooks;
unsigned short proto;
......@@ -321,17 +326,19 @@ struct xt_target {
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_tgdtor_param *);
#ifdef CONFIG_COMPAT
/* Called when userspace align differs from kernel space one */
void (*compat_from_user)(void *dst, void *src);
int (*compat_to_user)(void __user *dst, void *src);
void (*compat_from_user)(void *dst, const void *src);
int (*compat_to_user)(void __user *dst, const void *src);
#endif
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
const char *table;
unsigned int targetsize;
#ifdef CONFIG_COMPAT
unsigned int compatsize;
#endif
unsigned int hooks;
unsigned short proto;
......@@ -353,6 +360,7 @@ struct xt_table {
struct module *me;
u_int8_t af; /* address/protocol family */
int priority; /* hook order */
/* A unique name... */
const char name[XT_TABLE_MAXNAMELEN];
......@@ -514,6 +522,9 @@ static inline unsigned long ifname_compare_aligned(const char *_a,
return ret;
}
extern struct nf_hook_ops *xt_hook_link(const struct xt_table *, nf_hookfn *);
extern void xt_hook_unlink(const struct xt_table *, struct nf_hook_ops *);
#ifdef CONFIG_COMPAT
#include <net/compat.h>
......@@ -554,11 +565,7 @@ struct compat_xt_entry_target {
* current task alignment */
struct compat_xt_counters {
#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
u_int32_t cnt[4];
#else
u_int64_t cnt[2];
#endif
compat_u64 pcnt, bcnt; /* Packet and byte counters */
};
struct compat_xt_counters_info {
......@@ -567,26 +574,32 @@ struct compat_xt_counters_info {
struct compat_xt_counters counters[0];
};
#define COMPAT_XT_ALIGN(s) (((s) + (__alignof__(struct compat_xt_counters)-1)) \
& ~(__alignof__(struct compat_xt_counters)-1))
struct _compat_xt_align {
__u8 u8;
__u16 u16;
__u32 u32;
compat_u64 u64;
};
#define COMPAT_XT_ALIGN(s) ALIGN((s), __alignof__(struct _compat_xt_align))
extern void xt_compat_lock(u_int8_t af);
extern void xt_compat_unlock(u_int8_t af);
extern int xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta);
extern void xt_compat_flush_offsets(u_int8_t af);
extern short xt_compat_calc_jump(u_int8_t af, unsigned int offset);
extern int xt_compat_calc_jump(u_int8_t af, unsigned int offset);
extern int xt_compat_match_offset(const struct xt_match *match);
extern int xt_compat_match_from_user(struct xt_entry_match *m,
void **dstptr, unsigned int *size);
extern int xt_compat_match_to_user(struct xt_entry_match *m,
extern int xt_compat_match_to_user(const struct xt_entry_match *m,
void __user **dstptr, unsigned int *size);
extern int xt_compat_target_offset(const struct xt_target *target);
extern void xt_compat_target_from_user(struct xt_entry_target *t,
void **dstptr, unsigned int *size);
extern int xt_compat_target_to_user(struct xt_entry_target *t,
extern int xt_compat_target_to_user(const struct xt_entry_target *t,
void __user **dstptr, unsigned int *size);
#endif /* CONFIG_COMPAT */
......
#ifndef _XT_CT_H
#define _XT_CT_H
#define XT_CT_NOTRACK 0x1
struct xt_ct_target_info {
u_int16_t flags;
u_int16_t zone;
u_int32_t ct_events;
u_int32_t exp_events;
char helper[16];
/* Used internally by the kernel */
struct nf_conn *ct __attribute__((aligned(8)));
};
#endif /* _XT_CT_H */
......@@ -258,6 +258,7 @@ struct arpt_error {
.target.errorname = "ERROR", \
}
extern void *arpt_alloc_initial_table(const struct xt_table *);
extern struct xt_table *arpt_register_table(struct net *net,
const struct xt_table *table,
const struct arpt_replace *repl);
......
......@@ -289,7 +289,7 @@ struct ebt_table {
~(__alignof__(struct ebt_replace)-1))
extern struct ebt_table *ebt_register_table(struct net *net,
const struct ebt_table *table);
extern void ebt_unregister_table(struct ebt_table *table);
extern void ebt_unregister_table(struct net *net, struct ebt_table *table);
extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
struct ebt_table *table);
......
......@@ -242,7 +242,7 @@ extern void ipt_init(void) __init;
extern struct xt_table *ipt_register_table(struct net *net,
const struct xt_table *table,
const struct ipt_replace *repl);
extern void ipt_unregister_table(struct xt_table *table);
extern void ipt_unregister_table(struct net *net, struct xt_table *table);
/* Standard entry. */
struct ipt_standard {
......@@ -282,6 +282,7 @@ struct ipt_error {
.target.errorname = "ERROR", \
}
extern void *ipt_alloc_initial_table(const struct xt_table *);
extern unsigned int ipt_do_table(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
......
......@@ -297,10 +297,11 @@ ip6t_get_target(struct ip6t_entry *e)
#include <linux/init.h>
extern void ip6t_init(void) __init;
extern void *ip6t_alloc_initial_table(const struct xt_table *);
extern struct xt_table *ip6t_register_table(struct net *net,
const struct xt_table *table,
const struct ip6t_replace *repl);
extern void ip6t_unregister_table(struct xt_table *table);
extern void ip6t_unregister_table(struct net *net, struct xt_table *table);
extern unsigned int ip6t_do_table(struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
......
......@@ -352,8 +352,11 @@ enum ip_defrag_users {
IP_DEFRAG_LOCAL_DELIVER,
IP_DEFRAG_CALL_RA_CHAIN,
IP_DEFRAG_CONNTRACK_IN,
__IP_DEFRAG_CONNTRACK_IN_END = IP_DEFRAG_CONNTRACK_IN + USHORT_MAX,
IP_DEFRAG_CONNTRACK_OUT,
__IP_DEFRAG_CONNTRACK_OUT_END = IP_DEFRAG_CONNTRACK_OUT + USHORT_MAX,
IP_DEFRAG_CONNTRACK_BRIDGE_IN,
__IP_DEFRAG_CONNTRACK_BRIDGE_IN = IP_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX,
IP_DEFRAG_VS_IN,
IP_DEFRAG_VS_OUT,
IP_DEFRAG_VS_FWD
......
......@@ -26,6 +26,11 @@
#include <linux/ipv6.h> /* for struct ipv6hdr */
#include <net/ipv6.h> /* for ipv6_addr_copy */
/* Connections' size value needed by ip_vs_ctl.c */
extern int ip_vs_conn_tab_size;
struct ip_vs_iphdr {
int len;
__u8 protocol;
......@@ -592,17 +597,6 @@ extern void ip_vs_init_hash_table(struct list_head *table, int rows);
* (from ip_vs_conn.c)
*/
/*
* IPVS connection entry hash table
*/
#ifndef CONFIG_IP_VS_TAB_BITS
#define CONFIG_IP_VS_TAB_BITS 12
#endif
#define IP_VS_CONN_TAB_BITS CONFIG_IP_VS_TAB_BITS
#define IP_VS_CONN_TAB_SIZE (1 << IP_VS_CONN_TAB_BITS)
#define IP_VS_CONN_TAB_MASK (IP_VS_CONN_TAB_SIZE - 1)
enum {
IP_VS_DIR_INPUT = 0,
IP_VS_DIR_OUTPUT,
......
......@@ -246,6 +246,8 @@ extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb);
int ip6_frag_nqueues(struct net *net);
int ip6_frag_mem(struct net *net);
#define IPV6_FRAG_HIGH_THRESH 262144 /* == 256*1024 */
#define IPV6_FRAG_LOW_THRESH 196608 /* == 192*1024 */
#define IPV6_FRAG_TIMEOUT (60*HZ) /* 60 seconds */
extern int __ipv6_addr_type(const struct in6_addr *addr);
......@@ -353,8 +355,11 @@ struct inet_frag_queue;
enum ip6_defrag_users {
IP6_DEFRAG_LOCAL_DELIVER,
IP6_DEFRAG_CONNTRACK_IN,
__IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHORT_MAX,
IP6_DEFRAG_CONNTRACK_OUT,
__IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHORT_MAX,
IP6_DEFRAG_CONNTRACK_BRIDGE_IN,
__IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX,
};
struct ip6_create_arg {
......
......@@ -81,6 +81,8 @@ struct net {
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct;
#endif
struct sock *nfnl;
struct sock *nfnl_stash;
#endif
#ifdef CONFIG_XFRM
struct netns_xfrm xfrm;
......
......@@ -70,7 +70,7 @@ union nf_conntrack_help {
struct nf_conntrack_helper;
/* Must be kept in sync with the classes defined by helpers */
#define NF_CT_MAX_EXPECT_CLASSES 3
#define NF_CT_MAX_EXPECT_CLASSES 4
/* nf_conn feature for connections that have a helper */
struct nf_conn_help {
......@@ -198,7 +198,8 @@ extern void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int null
extern void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size);
extern struct nf_conntrack_tuple_hash *
__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple);
__nf_conntrack_find(struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple);
extern void nf_conntrack_hash_insert(struct nf_conn *ct);
extern void nf_ct_delete_from_lists(struct nf_conn *ct);
......@@ -267,11 +268,16 @@ extern void
nf_ct_iterate_cleanup(struct net *net, int (*iter)(struct nf_conn *i, void *data), void *data);
extern void nf_conntrack_free(struct nf_conn *ct);
extern struct nf_conn *
nf_conntrack_alloc(struct net *net,
nf_conntrack_alloc(struct net *net, u16 zone,
const struct nf_conntrack_tuple *orig,
const struct nf_conntrack_tuple *repl,
gfp_t gfp);
static inline int nf_ct_is_template(const struct nf_conn *ct)
{
return test_bit(IPS_TEMPLATE_BIT, &ct->status);
}
/* It's confirmed if it is, or has been in the hash table. */
static inline int nf_ct_is_confirmed(struct nf_conn *ct)
{
......
......@@ -49,7 +49,8 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
/* Find a connection corresponding to a tuple. */
extern struct nf_conntrack_tuple_hash *
nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple);
nf_conntrack_find_get(struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple);
extern int __nf_conntrack_confirm(struct sk_buff *skb);
......
......@@ -12,27 +12,12 @@
#include <linux/netfilter/nf_conntrack_tuple_common.h>
#include <net/netfilter/nf_conntrack_extend.h>
/* Connection tracking event types */
enum ip_conntrack_events {
IPCT_NEW = 0, /* new conntrack */
IPCT_RELATED = 1, /* related conntrack */
IPCT_DESTROY = 2, /* destroyed conntrack */
IPCT_STATUS = 3, /* status has changed */
IPCT_PROTOINFO = 4, /* protocol information has changed */
IPCT_HELPER = 5, /* new helper has been set */
IPCT_MARK = 6, /* new mark has been set */
IPCT_NATSEQADJ = 7, /* NAT is doing sequence adjustment */
IPCT_SECMARK = 8, /* new security mark has been set */
};
enum ip_conntrack_expect_events {
IPEXP_NEW = 0, /* new expectation */
};
struct nf_conntrack_ecache {
unsigned long cache; /* bitops want long */
unsigned long missed; /* missed events */
u32 pid; /* netlink pid of destroyer */
unsigned long cache; /* bitops want long */
unsigned long missed; /* missed events */
u16 ctmask; /* bitmask of ct events to be delivered */
u16 expmask; /* bitmask of expect events to be delivered */
u32 pid; /* netlink pid of destroyer */
};
static inline struct nf_conntrack_ecache *
......@@ -42,14 +27,24 @@ nf_ct_ecache_find(const struct nf_conn *ct)
}
static inline struct nf_conntrack_ecache *
nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp)
nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp)
{
struct net *net = nf_ct_net(ct);
struct nf_conntrack_ecache *e;
if (!net->ct.sysctl_events)
if (!ctmask && !expmask && net->ct.sysctl_events) {
ctmask = ~0;
expmask = ~0;
}
if (!ctmask && !expmask)
return NULL;
return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
if (e) {
e->ctmask = ctmask;
e->expmask = expmask;
}
return e;
};
#ifdef CONFIG_NF_CONNTRACK_EVENTS
......@@ -82,6 +77,9 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
if (e == NULL)
return;
if (!(e->ctmask & (1 << event)))
return;
set_bit(event, &e->cache);
}
......@@ -92,7 +90,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
int report)
{
int ret = 0;
struct net *net = nf_ct_net(ct);
struct nf_ct_event_notifier *notify;
struct nf_conntrack_ecache *e;
......@@ -101,9 +98,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
if (notify == NULL)
goto out_unlock;
if (!net->ct.sysctl_events)
goto out_unlock;
e = nf_ct_ecache_find(ct);
if (e == NULL)
goto out_unlock;
......@@ -117,6 +111,9 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
/* This is a resent of a destroy event? If so, skip missed */
unsigned long missed = e->pid ? 0 : e->missed;
if (!((eventmask | missed) & e->ctmask))
goto out_unlock;
ret = notify->fcn(eventmask | missed, &item);
if (unlikely(ret < 0 || missed)) {
spin_lock_bh(&ct->lock);
......@@ -172,18 +169,19 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
u32 pid,
int report)
{
struct net *net = nf_ct_exp_net(exp);
struct nf_exp_event_notifier *notify;
struct nf_conntrack_ecache *e;
rcu_read_lock();
notify = rcu_dereference(nf_expect_event_cb);
if (notify == NULL)
goto out_unlock;
if (!net->ct.sysctl_events)
e = nf_ct_ecache_find(exp->master);
if (e == NULL)
goto out_unlock;
{
if (e->expmask & (1 << event)) {
struct nf_exp_event item = {
.exp = exp,
.pid = pid,
......
......@@ -56,16 +56,13 @@ struct nf_conntrack_expect {
static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp)
{
#ifdef CONFIG_NET_NS
return exp->master->ct_net; /* by definition */
#else
return &init_net;
#endif
return nf_ct_net(exp->master);
}
struct nf_conntrack_expect_policy {
unsigned int max_expected;
unsigned int timeout;
const char *name;
};
#define NF_CT_EXPECT_CLASS_DEFAULT 0
......@@ -77,13 +74,16 @@ int nf_conntrack_expect_init(struct net *net);
void nf_conntrack_expect_fini(struct net *net);
struct nf_conntrack_expect *
__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple);
__nf_ct_expect_find(struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple);
struct nf_conntrack_expect *
nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple);
nf_ct_expect_find_get(struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple);
struct nf_conntrack_expect *
nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple);
nf_ct_find_expectation(struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple);
void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
void nf_ct_remove_expectations(struct nf_conn *ct);
......
......@@ -8,6 +8,7 @@ enum nf_ct_ext_id {
NF_CT_EXT_NAT,
NF_CT_EXT_ACCT,
NF_CT_EXT_ECACHE,
NF_CT_EXT_ZONE,
NF_CT_EXT_NUM,
};
......@@ -15,6 +16,7 @@ enum nf_ct_ext_id {
#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat
#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter
#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache
#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
/* Extensions: optional stuff which isn't permanently in struct. */
struct nf_ct_ext {
......
......@@ -40,14 +40,18 @@ struct nf_conntrack_helper {
};
extern struct nf_conntrack_helper *
__nf_conntrack_helper_find_byname(const char *name);
__nf_conntrack_helper_find(const char *name, u16 l3num, u8 protonum);
extern struct nf_conntrack_helper *
nf_conntrack_helper_try_module_get(const char *name, u16 l3num, u8 protonum);
extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp);
extern int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags);
extern int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
gfp_t flags);
extern void nf_ct_helper_destroy(struct nf_conn *ct);
......
......@@ -49,8 +49,8 @@ struct nf_conntrack_l4proto {
/* Called when a conntrack entry is destroyed */
void (*destroy)(struct nf_conn *ct);
int (*error)(struct net *net, struct sk_buff *skb, unsigned int dataoff,
enum ip_conntrack_info *ctinfo,
int (*error)(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
unsigned int dataoff, enum ip_conntrack_info *ctinfo,
u_int8_t pf, unsigned int hooknum);
/* Print out the per-protocol part of the tuple. Return like seq_* */
......
#ifndef _NF_CONNTRACK_ZONES_H
#define _NF_CONNTRACK_ZONES_H
#include <net/netfilter/nf_conntrack_extend.h>
#define NF_CT_DEFAULT_ZONE 0
struct nf_conntrack_zone {
u16 id;
};
static inline u16 nf_ct_zone(const struct nf_conn *ct)
{
#ifdef CONFIG_NF_CONNTRACK_ZONES
struct nf_conntrack_zone *nf_ct_zone;
nf_ct_zone = nf_ct_ext_find(ct, NF_CT_EXT_ZONE);
if (nf_ct_zone)
return nf_ct_zone->id;
#endif
return NF_CT_DEFAULT_ZONE;
}
#endif /* _NF_CONNTRACK_ZONES_H */
......@@ -7,13 +7,27 @@
struct sk_buff;
/* These return true or false. */
extern int nf_nat_mangle_tcp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len);
extern int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len, bool adjust);
static inline int nf_nat_mangle_tcp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len)
{
return __nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
match_offset, match_len,
rep_buffer, rep_len, true);
}
extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
......@@ -21,6 +35,10 @@ extern int nf_nat_mangle_udp_packet(struct sk_buff *skb,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len);
extern void nf_nat_set_seq_adjust(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
__be32 seq, s16 off);
extern int nf_nat_seq_adjust(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo);
......
......@@ -37,7 +37,9 @@ struct netns_ipv4 {
struct xt_table *iptable_mangle;
struct xt_table *iptable_raw;
struct xt_table *arptable_filter;
#ifdef CONFIG_SECURITY
struct xt_table *iptable_security;
#endif
struct xt_table *nat_table;
struct hlist_head *nat_bysource;
unsigned int nat_htable_size;
......
......@@ -36,7 +36,9 @@ struct netns_ipv6 {
struct xt_table *ip6table_filter;
struct xt_table *ip6table_mangle;
struct xt_table *ip6table_raw;
#ifdef CONFIG_SECURITY
struct xt_table *ip6table_security;
#endif
#endif
struct rt6_info *ip6_null_entry;
struct rt6_statistics *rt6_stats;
......
......@@ -52,7 +52,7 @@ static struct xt_match ebt_802_3_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_802_3_mt,
.checkentry = ebt_802_3_mt_check,
.matchsize = XT_ALIGN(sizeof(struct ebt_802_3_info)),
.matchsize = sizeof(struct ebt_802_3_info),
.me = THIS_MODULE,
};
......
......@@ -120,7 +120,7 @@ static struct xt_match ebt_arp_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_arp_mt,
.checkentry = ebt_arp_mt_check,
.matchsize = XT_ALIGN(sizeof(struct ebt_arp_info)),
.matchsize = sizeof(struct ebt_arp_info),
.me = THIS_MODULE,
};
......
......@@ -78,7 +78,7 @@ static struct xt_target ebt_arpreply_tg_reg __read_mostly = {
.hooks = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_PRE_ROUTING),
.target = ebt_arpreply_tg,
.checkentry = ebt_arpreply_tg_check,
.targetsize = XT_ALIGN(sizeof(struct ebt_arpreply_info)),
.targetsize = sizeof(struct ebt_arpreply_info),
.me = THIS_MODULE,
};
......
......@@ -54,7 +54,7 @@ static struct xt_target ebt_dnat_tg_reg __read_mostly = {
(1 << NF_BR_LOCAL_OUT) | (1 << NF_BR_BROUTING),
.target = ebt_dnat_tg,
.checkentry = ebt_dnat_tg_check,
.targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)),
.targetsize = sizeof(struct ebt_nat_info),
.me = THIS_MODULE,
};
......
......@@ -110,7 +110,7 @@ static struct xt_match ebt_ip_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_ip_mt,
.checkentry = ebt_ip_mt_check,
.matchsize = XT_ALIGN(sizeof(struct ebt_ip_info)),
.matchsize = sizeof(struct ebt_ip_info),
.me = THIS_MODULE,
};
......
......@@ -122,7 +122,7 @@ static struct xt_match ebt_ip6_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_ip6_mt,
.checkentry = ebt_ip6_mt_check,
.matchsize = XT_ALIGN(sizeof(struct ebt_ip6_info)),
.matchsize = sizeof(struct ebt_ip6_info),
.me = THIS_MODULE,
};
......
......@@ -90,7 +90,7 @@ static struct xt_match ebt_limit_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_limit_mt,
.checkentry = ebt_limit_mt_check,
.matchsize = XT_ALIGN(sizeof(struct ebt_limit_info)),
.matchsize = sizeof(struct ebt_limit_info),
.me = THIS_MODULE,
};
......
......@@ -195,7 +195,7 @@ static struct xt_target ebt_log_tg_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.target = ebt_log_tg,
.checkentry = ebt_log_tg_check,
.targetsize = XT_ALIGN(sizeof(struct ebt_log_info)),
.targetsize = sizeof(struct ebt_log_info),
.me = THIS_MODULE,
};
......
......@@ -59,7 +59,7 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.target = ebt_mark_tg,
.checkentry = ebt_mark_tg_check,
.targetsize = XT_ALIGN(sizeof(struct ebt_mark_t_info)),
.targetsize = sizeof(struct ebt_mark_t_info),
.me = THIS_MODULE,
};
......
......@@ -41,7 +41,7 @@ static struct xt_match ebt_mark_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_mark_mt,
.checkentry = ebt_mark_mt_check,
.matchsize = XT_ALIGN(sizeof(struct ebt_mark_m_info)),
.matchsize = sizeof(struct ebt_mark_m_info),
.me = THIS_MODULE,
};
......
......@@ -51,7 +51,7 @@ static struct xt_target ebt_nflog_tg_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.target = ebt_nflog_tg,
.checkentry = ebt_nflog_tg_check,
.targetsize = XT_ALIGN(sizeof(struct ebt_nflog_info)),
.targetsize = sizeof(struct ebt_nflog_info),
.me = THIS_MODULE,
};
......
......@@ -36,7 +36,7 @@ static struct xt_match ebt_pkttype_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_pkttype_mt,
.checkentry = ebt_pkttype_mt_check,
.matchsize = XT_ALIGN(sizeof(struct ebt_pkttype_info)),
.matchsize = sizeof(struct ebt_pkttype_info),
.me = THIS_MODULE,
};
......
......@@ -59,7 +59,7 @@ static struct xt_target ebt_redirect_tg_reg __read_mostly = {
(1 << NF_BR_BROUTING),
.target = ebt_redirect_tg,
.checkentry = ebt_redirect_tg_check,
.targetsize = XT_ALIGN(sizeof(struct ebt_redirect_info)),
.targetsize = sizeof(struct ebt_redirect_info),
.me = THIS_MODULE,
};
......
......@@ -67,7 +67,7 @@ static struct xt_target ebt_snat_tg_reg __read_mostly = {
.hooks = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_POST_ROUTING),
.target = ebt_snat_tg,
.checkentry = ebt_snat_tg_check,
.targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)),
.targetsize = sizeof(struct ebt_nat_info),
.me = THIS_MODULE,
};
......
......@@ -177,7 +177,7 @@ static struct xt_match ebt_stp_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_stp_mt,
.checkentry = ebt_stp_mt_check,
.matchsize = XT_ALIGN(sizeof(struct ebt_stp_info)),
.matchsize = sizeof(struct ebt_stp_info),
.me = THIS_MODULE,
};
......
......@@ -275,7 +275,7 @@ static struct xt_target ebt_ulog_tg_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.target = ebt_ulog_tg,
.checkentry = ebt_ulog_tg_check,
.targetsize = XT_ALIGN(sizeof(struct ebt_ulog_info)),
.targetsize = sizeof(struct ebt_ulog_info),
.me = THIS_MODULE,
};
......
......@@ -163,7 +163,7 @@ static struct xt_match ebt_vlan_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_vlan_mt,
.checkentry = ebt_vlan_mt_check,
.matchsize = XT_ALIGN(sizeof(struct ebt_vlan_info)),
.matchsize = sizeof(struct ebt_vlan_info),
.me = THIS_MODULE,
};
......
......@@ -71,7 +71,7 @@ static int __net_init broute_net_init(struct net *net)
static void __net_exit broute_net_exit(struct net *net)
{
ebt_unregister_table(net->xt.broute_table);
ebt_unregister_table(net, net->xt.broute_table);
}
static struct pernet_operations broute_net_ops = {
......
......@@ -107,7 +107,7 @@ static int __net_init frame_filter_net_init(struct net *net)
static void __net_exit frame_filter_net_exit(struct net *net)
{
ebt_unregister_table(net->xt.frame_filter);
ebt_unregister_table(net, net->xt.frame_filter);
}
static struct pernet_operations frame_filter_net_ops = {
......
......@@ -107,7 +107,7 @@ static int __net_init frame_nat_net_init(struct net *net)
static void __net_exit frame_nat_net_exit(struct net *net)
{
ebt_unregister_table(net->xt.frame_nat);
ebt_unregister_table(net, net->xt.frame_nat);
}
static struct pernet_operations frame_nat_net_ops = {
......
......@@ -82,7 +82,8 @@ static inline int ebt_do_match (struct ebt_entry_match *m,
return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH;
}
static inline int ebt_dev_check(char *entry, const struct net_device *device)
static inline int
ebt_dev_check(const char *entry, const struct net_device *device)
{
int i = 0;
const char *devname;
......@@ -100,8 +101,9 @@ static inline int ebt_dev_check(char *entry, const struct net_device *device)
#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
/* process standard matches */
static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
const struct net_device *in, const struct net_device *out)
static inline int
ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
const struct net_device *in, const struct net_device *out)
{
int verdict, i;
......@@ -156,12 +158,12 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
int i, nentries;
struct ebt_entry *point;
struct ebt_counter *counter_base, *cb_base;
struct ebt_entry_target *t;
const struct ebt_entry_target *t;
int verdict, sp = 0;
struct ebt_chainstack *cs;
struct ebt_entries *chaininfo;
char *base;
struct ebt_table_info *private;
const char *base;
const struct ebt_table_info *private;
bool hotdrop = false;
struct xt_match_param mtpar;
struct xt_target_param tgpar;
......@@ -395,7 +397,7 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
return 0;
}
static int ebt_verify_pointers(struct ebt_replace *repl,
static int ebt_verify_pointers(const struct ebt_replace *repl,
struct ebt_table_info *newinfo)
{
unsigned int limit = repl->entries_size;
......@@ -442,6 +444,8 @@ static int ebt_verify_pointers(struct ebt_replace *repl,
break;
if (left < e->next_offset)
break;
if (e->next_offset < sizeof(struct ebt_entry))
return -EINVAL;
offset += e->next_offset;
}
}
......@@ -466,8 +470,8 @@ static int ebt_verify_pointers(struct ebt_replace *repl,
* to parse the userspace data
*/
static inline int
ebt_check_entry_size_and_hooks(struct ebt_entry *e,
struct ebt_table_info *newinfo,
ebt_check_entry_size_and_hooks(const struct ebt_entry *e,
const struct ebt_table_info *newinfo,
unsigned int *n, unsigned int *cnt,
unsigned int *totalcnt, unsigned int *udc_cnt)
{
......@@ -561,13 +565,14 @@ ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
}
static inline int
ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
ebt_cleanup_match(struct ebt_entry_match *m, struct net *net, unsigned int *i)
{
struct xt_mtdtor_param par;
if (i && (*i)-- == 0)
return 1;
par.net = net;
par.match = m->u.match;
par.matchinfo = m->data;
par.family = NFPROTO_BRIDGE;
......@@ -578,13 +583,14 @@ ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
}
static inline int
ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
ebt_cleanup_watcher(struct ebt_entry_watcher *w, struct net *net, unsigned int *i)
{
struct xt_tgdtor_param par;
if (i && (*i)-- == 0)
return 1;
par.net = net;
par.target = w->u.watcher;
par.targinfo = w->data;
par.family = NFPROTO_BRIDGE;
......@@ -595,7 +601,7 @@ ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
}
static inline int
ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
{
struct xt_tgdtor_param par;
struct ebt_entry_target *t;
......@@ -605,10 +611,11 @@ ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
/* we're done */
if (cnt && (*cnt)-- == 0)
return 1;
EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, NULL);
EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, NULL);
t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
par.net = net;
par.target = t->u.target;
par.targinfo = t->data;
par.family = NFPROTO_BRIDGE;
......@@ -619,7 +626,8 @@ ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
}
static inline int
ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
ebt_check_entry(struct ebt_entry *e, struct net *net,
const struct ebt_table_info *newinfo,
const char *name, unsigned int *cnt,
struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
{
......@@ -671,6 +679,7 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
}
i = 0;
mtpar.net = tgpar.net = net;
mtpar.table = tgpar.table = name;
mtpar.entryinfo = tgpar.entryinfo = e;
mtpar.hook_mask = tgpar.hook_mask = hookmask;
......@@ -726,9 +735,9 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
(*cnt)++;
return 0;
cleanup_watchers:
EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, net, &j);
cleanup_matches:
EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
EBT_MATCH_ITERATE(e, ebt_cleanup_match, net, &i);
return ret;
}
......@@ -737,12 +746,12 @@ ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
* the hook mask for udc tells us from which base chains the udc can be
* accessed. This mask is a parameter to the check() functions of the extensions
*/
static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
static int check_chainloops(const struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
unsigned int udc_cnt, unsigned int hooknr, char *base)
{
int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
struct ebt_entry *e = (struct ebt_entry *)chain->data;
struct ebt_entry_target *t;
const struct ebt_entry *e = (struct ebt_entry *)chain->data;
const struct ebt_entry_target *t;
while (pos < nentries || chain_nr != -1) {
/* end of udc, go back one 'recursion' step */
......@@ -808,7 +817,8 @@ static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s
}
/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
static int translate_table(char *name, struct ebt_table_info *newinfo)
static int translate_table(struct net *net, const char *name,
struct ebt_table_info *newinfo)
{
unsigned int i, j, k, udc_cnt;
int ret;
......@@ -917,17 +927,17 @@ static int translate_table(char *name, struct ebt_table_info *newinfo)
/* used to know what we need to clean up if something goes wrong */
i = 0;
ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
ebt_check_entry, newinfo, name, &i, cl_s, udc_cnt);
ebt_check_entry, net, newinfo, name, &i, cl_s, udc_cnt);
if (ret != 0) {
EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
ebt_cleanup_entry, &i);
ebt_cleanup_entry, net, &i);
}
vfree(cl_s);
return ret;
}
/* called under write_lock */
static void get_counters(struct ebt_counter *oldcounters,
static void get_counters(const struct ebt_counter *oldcounters,
struct ebt_counter *counters, unsigned int nentries)
{
int i, cpu;
......@@ -950,7 +960,8 @@ static void get_counters(struct ebt_counter *oldcounters,
}
/* replace the table */
static int do_replace(struct net *net, void __user *user, unsigned int len)
static int do_replace(struct net *net, const void __user *user,
unsigned int len)
{
int ret, i, countersize;
struct ebt_table_info *newinfo;
......@@ -1017,7 +1028,7 @@ static int do_replace(struct net *net, void __user *user, unsigned int len)
if (ret != 0)
goto free_counterstmp;
ret = translate_table(tmp.name, newinfo);
ret = translate_table(net, tmp.name, newinfo);
if (ret != 0)
goto free_counterstmp;
......@@ -1070,7 +1081,7 @@ static int do_replace(struct net *net, void __user *user, unsigned int len)
/* decrease module count and free resources */
EBT_ENTRY_ITERATE(table->entries, table->entries_size,
ebt_cleanup_entry, NULL);
ebt_cleanup_entry, net, NULL);
vfree(table->entries);
if (table->chainstack) {
......@@ -1087,7 +1098,7 @@ static int do_replace(struct net *net, void __user *user, unsigned int len)
mutex_unlock(&ebt_mutex);
free_iterate:
EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
ebt_cleanup_entry, NULL);
ebt_cleanup_entry, net, NULL);
free_counterstmp:
vfree(counterstmp);
/* can be initialized in translate_table() */
......@@ -1154,7 +1165,7 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table)
newinfo->hook_entry[i] = p +
((char *)repl->hook_entry[i] - repl->entries);
}
ret = translate_table(repl->name, newinfo);
ret = translate_table(net, repl->name, newinfo);
if (ret != 0) {
BUGPRINT("Translate_table failed\n");
goto free_chainstack;
......@@ -1204,7 +1215,7 @@ ebt_register_table(struct net *net, const struct ebt_table *input_table)
return ERR_PTR(ret);
}
void ebt_unregister_table(struct ebt_table *table)
void ebt_unregister_table(struct net *net, struct ebt_table *table)
{
int i;
......@@ -1216,7 +1227,7 @@ void ebt_unregister_table(struct ebt_table *table)
list_del(&table->list);
mutex_unlock(&ebt_mutex);
EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
ebt_cleanup_entry, NULL);
ebt_cleanup_entry, net, NULL);
if (table->private->nentries)
module_put(table->me);
vfree(table->private->entries);
......@@ -1230,7 +1241,8 @@ void ebt_unregister_table(struct ebt_table *table)
}
/* userspace just supplied us with counters */
static int update_counters(struct net *net, void __user *user, unsigned int len)
static int update_counters(struct net *net, const void __user *user,
unsigned int len)
{
int i, ret;
struct ebt_counter *tmp;
......@@ -1285,8 +1297,8 @@ static int update_counters(struct net *net, void __user *user, unsigned int len)
return ret;
}
static inline int ebt_make_matchname(struct ebt_entry_match *m,
char *base, char __user *ubase)
static inline int ebt_make_matchname(const struct ebt_entry_match *m,
const char *base, char __user *ubase)
{
char __user *hlp = ubase + ((char *)m - base);
if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
......@@ -1294,8 +1306,8 @@ static inline int ebt_make_matchname(struct ebt_entry_match *m,
return 0;
}
static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
char *base, char __user *ubase)
static inline int ebt_make_watchername(const struct ebt_entry_watcher *w,
const char *base, char __user *ubase)
{
char __user *hlp = ubase + ((char *)w - base);
if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
......@@ -1303,11 +1315,12 @@ static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
return 0;
}
static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
static inline int
ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
{
int ret;
char __user *hlp;
struct ebt_entry_target *t;
const struct ebt_entry_target *t;
if (e->bitmask == 0)
return 0;
......@@ -1328,10 +1341,11 @@ static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *u
/* called with ebt_mutex locked */
static int copy_everything_to_user(struct ebt_table *t, void __user *user,
int *len, int cmd)
const int *len, int cmd)
{
struct ebt_replace tmp;
struct ebt_counter *counterstmp, *oldcounters;
struct ebt_counter *counterstmp;
const struct ebt_counter *oldcounters;
unsigned int entries_size, nentries;
char *entries;
......
......@@ -27,6 +27,7 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_arp/arp_tables.h>
#include "../../netfilter/xt_repldata.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
......@@ -58,6 +59,12 @@ do { \
#define ARP_NF_ASSERT(x)
#endif
void *arpt_alloc_initial_table(const struct xt_table *info)
{
return xt_alloc_initial_table(arpt, ARPT);
}
EXPORT_SYMBOL_GPL(arpt_alloc_initial_table);
static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
const char *hdr_addr, int len)
{
......@@ -226,7 +233,14 @@ arpt_error(struct sk_buff *skb, const struct xt_target_param *par)
return NF_DROP;
}
static inline struct arpt_entry *get_entry(void *base, unsigned int offset)
static inline const struct arpt_entry_target *
arpt_get_target_c(const struct arpt_entry *e)
{
return arpt_get_target((struct arpt_entry *)e);
}
static inline struct arpt_entry *
get_entry(const void *base, unsigned int offset)
{
return (struct arpt_entry *)(base + offset);
}
......@@ -273,7 +287,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
arp = arp_hdr(skb);
do {
struct arpt_entry_target *t;
const struct arpt_entry_target *t;
int hdr_len;
if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
......@@ -285,7 +299,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
(2 * skb->dev->addr_len);
ADD_COUNTER(e->counters, hdr_len, 1);
t = arpt_get_target(e);
t = arpt_get_target_c(e);
/* Standard target? */
if (!t->u.kernel.target->target) {
......@@ -351,7 +365,7 @@ static inline bool unconditional(const struct arpt_arp *arp)
/* Figures out from what hook each rule can be called: returns 0 if
* there are loops. Puts hook bitmask in comefrom.
*/
static int mark_source_chains(struct xt_table_info *newinfo,
static int mark_source_chains(const struct xt_table_info *newinfo,
unsigned int valid_hooks, void *entry0)
{
unsigned int hook;
......@@ -372,7 +386,7 @@ static int mark_source_chains(struct xt_table_info *newinfo,
for (;;) {
const struct arpt_standard_target *t
= (void *)arpt_get_target(e);
= (void *)arpt_get_target_c(e);
int visited = e->comefrom & (1 << hook);
if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) {
......@@ -456,7 +470,7 @@ static int mark_source_chains(struct xt_table_info *newinfo,
return 1;
}
static inline int check_entry(struct arpt_entry *e, const char *name)
static inline int check_entry(const struct arpt_entry *e, const char *name)
{
const struct arpt_entry_target *t;
......@@ -468,7 +482,7 @@ static inline int check_entry(struct arpt_entry *e, const char *name)
if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset)
return -EINVAL;
t = arpt_get_target(e);
t = arpt_get_target_c(e);
if (e->target_offset + t->u.target_size > e->next_offset)
return -EINVAL;
......@@ -533,14 +547,14 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size,
return ret;
}
static bool check_underflow(struct arpt_entry *e)
static bool check_underflow(const struct arpt_entry *e)
{
const struct arpt_entry_target *t;
unsigned int verdict;
if (!unconditional(&e->arp))
return false;
t = arpt_get_target(e);
t = arpt_get_target_c(e);
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
return false;
verdict = ((struct arpt_standard_target *)t)->verdict;
......@@ -550,8 +564,8 @@ static bool check_underflow(struct arpt_entry *e)
static inline int check_entry_size_and_hooks(struct arpt_entry *e,
struct xt_table_info *newinfo,
unsigned char *base,
unsigned char *limit,
const unsigned char *base,
const unsigned char *limit,
const unsigned int *hook_entries,
const unsigned int *underflows,
unsigned int valid_hooks,
......@@ -761,11 +775,11 @@ static void get_counters(const struct xt_table_info *t,
local_bh_enable();
}
static struct xt_counters *alloc_counters(struct xt_table *table)
static struct xt_counters *alloc_counters(const struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
struct xt_table_info *private = table->private;
const struct xt_table_info *private = table->private;
/* We need atomic snapshot of counters: rest doesn't change
* (other than comefrom, which userspace doesn't care
......@@ -783,11 +797,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
}
static int copy_entries_to_user(unsigned int total_size,
struct xt_table *table,
const struct xt_table *table,
void __user *userptr)
{
unsigned int off, num;
struct arpt_entry *e;
const struct arpt_entry *e;
struct xt_counters *counters;
struct xt_table_info *private = table->private;
int ret = 0;
......@@ -807,7 +821,7 @@ static int copy_entries_to_user(unsigned int total_size,
/* FIXME: use iterator macros --RR */
/* ... then go back and fix counters and names */
for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
struct arpt_entry_target *t;
const struct arpt_entry_target *t;
e = (struct arpt_entry *)(loc_cpu_entry + off);
if (copy_to_user(userptr + off
......@@ -818,7 +832,7 @@ static int copy_entries_to_user(unsigned int total_size,
goto free_counters;
}
t = arpt_get_target(e);
t = arpt_get_target_c(e);
if (copy_to_user(userptr + off + e->target_offset
+ offsetof(struct arpt_entry_target,
u.user.name),
......@@ -835,7 +849,7 @@ static int copy_entries_to_user(unsigned int total_size,
}
#ifdef CONFIG_COMPAT
static void compat_standard_from_user(void *dst, void *src)
static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
......@@ -844,7 +858,7 @@ static void compat_standard_from_user(void *dst, void *src)
memcpy(dst, &v, sizeof(v));
}
static int compat_standard_to_user(void __user *dst, void *src)
static int compat_standard_to_user(void __user *dst, const void *src)
{
compat_int_t cv = *(int *)src;
......@@ -853,18 +867,18 @@ static int compat_standard_to_user(void __user *dst, void *src)
return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
}
static int compat_calc_entry(struct arpt_entry *e,
static int compat_calc_entry(const struct arpt_entry *e,
const struct xt_table_info *info,
void *base, struct xt_table_info *newinfo)
const void *base, struct xt_table_info *newinfo)
{
struct arpt_entry_target *t;
const struct arpt_entry_target *t;
unsigned int entry_offset;
int off, i, ret;
off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
entry_offset = (void *)e - base;
t = arpt_get_target(e);
t = arpt_get_target_c(e);
off += xt_compat_target_offset(t->u.kernel.target);
newinfo->size -= off;
ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
......@@ -900,7 +914,8 @@ static int compat_table_info(const struct xt_table_info *info,
}
#endif
static int get_info(struct net *net, void __user *user, int *len, int compat)
static int get_info(struct net *net, void __user *user,
const int *len, int compat)
{
char name[ARPT_TABLE_MAXNAMELEN];
struct xt_table *t;
......@@ -959,7 +974,7 @@ static int get_info(struct net *net, void __user *user, int *len, int compat)
}
static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
int *len)
const int *len)
{
int ret;
struct arpt_get_entries get;
......@@ -1073,7 +1088,8 @@ static int __do_replace(struct net *net, const char *name,
return ret;
}
static int do_replace(struct net *net, void __user *user, unsigned int len)
static int do_replace(struct net *net, const void __user *user,
unsigned int len)
{
int ret;
struct arpt_replace tmp;
......@@ -1133,8 +1149,8 @@ add_counter_to_entry(struct arpt_entry *e,
return 0;
}
static int do_add_counters(struct net *net, void __user *user, unsigned int len,
int compat)
static int do_add_counters(struct net *net, const void __user *user,
unsigned int len, int compat)
{
unsigned int i, curcpu;
struct xt_counters_info tmp;
......@@ -1238,10 +1254,10 @@ static inline int
check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
struct xt_table_info *newinfo,
unsigned int *size,
unsigned char *base,
unsigned char *limit,
unsigned int *hook_entries,
unsigned int *underflows,
const unsigned char *base,
const unsigned char *limit,
const unsigned int *hook_entries,
const unsigned int *underflows,
unsigned int *i,
const char *name)
{
......
......@@ -6,6 +6,7 @@
*/
#include <linux/module.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_arp/arp_tables.h>
MODULE_LICENSE("GPL");
......@@ -15,93 +16,37 @@ MODULE_DESCRIPTION("arptables filter table");
#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \
(1 << NF_ARP_FORWARD))
static const struct
{
struct arpt_replace repl;
struct arpt_standard entries[3];
struct arpt_error term;
} initial_table __net_initdata = {
.repl = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error),
.hook_entry = {
[NF_ARP_IN] = 0,
[NF_ARP_OUT] = sizeof(struct arpt_standard),
[NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
},
.underflow = {
[NF_ARP_IN] = 0,
[NF_ARP_OUT] = sizeof(struct arpt_standard),
[NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
},
},
.entries = {
ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_IN */
ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_OUT */
ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_FORWARD */
},
.term = ARPT_ERROR_INIT,
};
static const struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_ARP,
.priority = NF_IP_PRI_FILTER,
};
/* The work comes in here from netfilter.c */
static unsigned int arpt_in_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
static unsigned int
arptable_filter_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return arpt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.arptable_filter);
}
const struct net *net = dev_net((in != NULL) ? in : out);
static unsigned int arpt_out_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return arpt_do_table(skb, hook, in, out,
dev_net(out)->ipv4.arptable_filter);
return arpt_do_table(skb, hook, in, out, net->ipv4.arptable_filter);
}
static struct nf_hook_ops arpt_ops[] __read_mostly = {
{
.hook = arpt_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_ARP,
.hooknum = NF_ARP_IN,
.priority = NF_IP_PRI_FILTER,
},
{
.hook = arpt_out_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_ARP,
.hooknum = NF_ARP_OUT,
.priority = NF_IP_PRI_FILTER,
},
{
.hook = arpt_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_ARP,
.hooknum = NF_ARP_FORWARD,
.priority = NF_IP_PRI_FILTER,
},
};
static struct nf_hook_ops *arpfilter_ops __read_mostly;
static int __net_init arptable_filter_net_init(struct net *net)
{
/* Register table */
struct arpt_replace *repl;
repl = arpt_alloc_initial_table(&packet_filter);
if (repl == NULL)
return -ENOMEM;
net->ipv4.arptable_filter =
arpt_register_table(net, &packet_filter, &initial_table.repl);
arpt_register_table(net, &packet_filter, repl);
kfree(repl);
if (IS_ERR(net->ipv4.arptable_filter))
return PTR_ERR(net->ipv4.arptable_filter);
return 0;
......@@ -125,9 +70,11 @@ static int __init arptable_filter_init(void)
if (ret < 0)
return ret;
ret = nf_register_hooks(arpt_ops, ARRAY_SIZE(arpt_ops));
if (ret < 0)
arpfilter_ops = xt_hook_link(&packet_filter, arptable_filter_hook);
if (IS_ERR(arpfilter_ops)) {
ret = PTR_ERR(arpfilter_ops);
goto cleanup_table;
}
return ret;
cleanup_table:
......@@ -137,7 +84,7 @@ static int __init arptable_filter_init(void)
static void __exit arptable_filter_fini(void)
{
nf_unregister_hooks(arpt_ops, ARRAY_SIZE(arpt_ops));
xt_hook_unlink(&packet_filter, arpfilter_ops);
unregister_pernet_subsys(&arptable_filter_net_ops);
}
......
......@@ -28,6 +28,7 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <net/netfilter/nf_log.h>
#include "../../netfilter/xt_repldata.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
......@@ -66,6 +67,12 @@ do { \
#define inline
#endif
void *ipt_alloc_initial_table(const struct xt_table *info)
{
return xt_alloc_initial_table(ipt, IPT);
}
EXPORT_SYMBOL_GPL(ipt_alloc_initial_table);
/*
We keep a set of rules for each CPU, so we can avoid write-locking
them in the softirq when updating the counters and therefore
......@@ -169,7 +176,7 @@ ipt_error(struct sk_buff *skb, const struct xt_target_param *par)
/* Performance critical - called for every packet */
static inline bool
do_match(struct ipt_entry_match *m, const struct sk_buff *skb,
do_match(const struct ipt_entry_match *m, const struct sk_buff *skb,
struct xt_match_param *par)
{
par->match = m->u.kernel.match;
......@@ -184,7 +191,7 @@ do_match(struct ipt_entry_match *m, const struct sk_buff *skb,
/* Performance critical */
static inline struct ipt_entry *
get_entry(void *base, unsigned int offset)
get_entry(const void *base, unsigned int offset)
{
return (struct ipt_entry *)(base + offset);
}
......@@ -199,6 +206,13 @@ static inline bool unconditional(const struct ipt_ip *ip)
#undef FWINV
}
/* for const-correctness */
static inline const struct ipt_entry_target *
ipt_get_target_c(const struct ipt_entry *e)
{
return ipt_get_target((struct ipt_entry *)e);
}
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
static const char *const hooknames[] = {
......@@ -233,11 +247,11 @@ static struct nf_loginfo trace_loginfo = {
/* Mildly perf critical (only if packet tracing is on) */
static inline int
get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e,
get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
const char *hookname, const char **chainname,
const char **comment, unsigned int *rulenum)
{
struct ipt_standard_target *t = (void *)ipt_get_target(s);
const struct ipt_standard_target *t = (void *)ipt_get_target_c(s);
if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) {
/* Head of user chain: ERROR target with chainname */
......@@ -263,15 +277,15 @@ get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e,
return 0;
}
static void trace_packet(struct sk_buff *skb,
static void trace_packet(const struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
const char *tablename,
struct xt_table_info *private,
struct ipt_entry *e)
const struct xt_table_info *private,
const struct ipt_entry *e)
{
void *table_base;
const void *table_base;
const struct ipt_entry *root;
const char *hookname, *chainname, *comment;
unsigned int rulenum = 0;
......@@ -315,9 +329,9 @@ ipt_do_table(struct sk_buff *skb,
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
const char *indev, *outdev;
void *table_base;
const void *table_base;
struct ipt_entry *e, *back;
struct xt_table_info *private;
const struct xt_table_info *private;
struct xt_match_param mtpar;
struct xt_target_param tgpar;
......@@ -350,7 +364,7 @@ ipt_do_table(struct sk_buff *skb,
back = get_entry(table_base, private->underflow[hook]);
do {
struct ipt_entry_target *t;
const struct ipt_entry_target *t;
IP_NF_ASSERT(e);
IP_NF_ASSERT(back);
......@@ -443,7 +457,7 @@ ipt_do_table(struct sk_buff *skb,
/* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */
static int
mark_source_chains(struct xt_table_info *newinfo,
mark_source_chains(const struct xt_table_info *newinfo,
unsigned int valid_hooks, void *entry0)
{
unsigned int hook;
......@@ -461,8 +475,8 @@ mark_source_chains(struct xt_table_info *newinfo,
e->counters.pcnt = pos;
for (;;) {
struct ipt_standard_target *t
= (void *)ipt_get_target(e);
const struct ipt_standard_target *t
= (void *)ipt_get_target_c(e);
int visited = e->comefrom & (1 << hook);
if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
......@@ -553,13 +567,14 @@ mark_source_chains(struct xt_table_info *newinfo,
}
static int
cleanup_match(struct ipt_entry_match *m, unsigned int *i)
cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i)
{
struct xt_mtdtor_param par;
if (i && (*i)-- == 0)
return 1;
par.net = net;
par.match = m->u.kernel.match;
par.matchinfo = m->data;
par.family = NFPROTO_IPV4;
......@@ -570,9 +585,9 @@ cleanup_match(struct ipt_entry_match *m, unsigned int *i)
}
static int
check_entry(struct ipt_entry *e, const char *name)
check_entry(const struct ipt_entry *e, const char *name)
{
struct ipt_entry_target *t;
const struct ipt_entry_target *t;
if (!ip_checkentry(&e->ip)) {
duprintf("ip_tables: ip check failed %p %s.\n", e, name);
......@@ -583,7 +598,7 @@ check_entry(struct ipt_entry *e, const char *name)
e->next_offset)
return -EINVAL;
t = ipt_get_target(e);
t = ipt_get_target_c(e);
if (e->target_offset + t->u.target_size > e->next_offset)
return -EINVAL;
......@@ -637,10 +652,11 @@ find_check_match(struct ipt_entry_match *m, struct xt_mtchk_param *par,
return ret;
}
static int check_target(struct ipt_entry *e, const char *name)
static int check_target(struct ipt_entry *e, struct net *net, const char *name)
{
struct ipt_entry_target *t = ipt_get_target(e);
struct xt_tgchk_param par = {
.net = net,
.table = name,
.entryinfo = e,
.target = t->u.kernel.target,
......@@ -661,8 +677,8 @@ static int check_target(struct ipt_entry *e, const char *name)
}
static int
find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
unsigned int *i)
find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
unsigned int size, unsigned int *i)
{
struct ipt_entry_target *t;
struct xt_target *target;
......@@ -675,6 +691,7 @@ find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
return ret;
j = 0;
mtpar.net = net;
mtpar.table = name;
mtpar.entryinfo = &e->ip;
mtpar.hook_mask = e->comefrom;
......@@ -695,7 +712,7 @@ find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
}
t->u.kernel.target = target;
ret = check_target(e, name);
ret = check_target(e, net, name);
if (ret)
goto err;
......@@ -704,18 +721,18 @@ find_check_entry(struct ipt_entry *e, const char *name, unsigned int size,
err:
module_put(t->u.kernel.target->me);
cleanup_matches:
IPT_MATCH_ITERATE(e, cleanup_match, &j);
IPT_MATCH_ITERATE(e, cleanup_match, net, &j);
return ret;
}
static bool check_underflow(struct ipt_entry *e)
static bool check_underflow(const struct ipt_entry *e)
{
const struct ipt_entry_target *t;
unsigned int verdict;
if (!unconditional(&e->ip))
return false;
t = ipt_get_target(e);
t = ipt_get_target_c(e);
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
return false;
verdict = ((struct ipt_standard_target *)t)->verdict;
......@@ -726,8 +743,8 @@ static bool check_underflow(struct ipt_entry *e)
static int
check_entry_size_and_hooks(struct ipt_entry *e,
struct xt_table_info *newinfo,
unsigned char *base,
unsigned char *limit,
const unsigned char *base,
const unsigned char *limit,
const unsigned int *hook_entries,
const unsigned int *underflows,
unsigned int valid_hooks,
......@@ -774,7 +791,7 @@ check_entry_size_and_hooks(struct ipt_entry *e,
}
static int
cleanup_entry(struct ipt_entry *e, unsigned int *i)
cleanup_entry(struct ipt_entry *e, struct net *net, unsigned int *i)
{
struct xt_tgdtor_param par;
struct ipt_entry_target *t;
......@@ -783,9 +800,10 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i)
return 1;
/* Cleanup all matches */
IPT_MATCH_ITERATE(e, cleanup_match, NULL);
IPT_MATCH_ITERATE(e, cleanup_match, net, NULL);
t = ipt_get_target(e);
par.net = net;
par.target = t->u.kernel.target;
par.targinfo = t->data;
par.family = NFPROTO_IPV4;
......@@ -798,7 +816,8 @@ cleanup_entry(struct ipt_entry *e, unsigned int *i)
/* Checks and translates the user-supplied table segment (held in
newinfo) */
static int
translate_table(const char *name,
translate_table(struct net *net,
const char *name,
unsigned int valid_hooks,
struct xt_table_info *newinfo,
void *entry0,
......@@ -860,11 +879,11 @@ translate_table(const char *name,
/* Finally, each sanity check must pass */
i = 0;
ret = IPT_ENTRY_ITERATE(entry0, newinfo->size,
find_check_entry, name, size, &i);
find_check_entry, net, name, size, &i);
if (ret != 0) {
IPT_ENTRY_ITERATE(entry0, newinfo->size,
cleanup_entry, &i);
cleanup_entry, net, &i);
return ret;
}
......@@ -940,11 +959,11 @@ get_counters(const struct xt_table_info *t,
local_bh_enable();
}
static struct xt_counters * alloc_counters(struct xt_table *table)
static struct xt_counters *alloc_counters(const struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
struct xt_table_info *private = table->private;
const struct xt_table_info *private = table->private;
/* We need atomic snapshot of counters: rest doesn't change
(other than comefrom, which userspace doesn't care
......@@ -962,11 +981,11 @@ static struct xt_counters * alloc_counters(struct xt_table *table)
static int
copy_entries_to_user(unsigned int total_size,
struct xt_table *table,
const struct xt_table *table,
void __user *userptr)
{
unsigned int off, num;
struct ipt_entry *e;
const struct ipt_entry *e;
struct xt_counters *counters;
const struct xt_table_info *private = table->private;
int ret = 0;
......@@ -1018,7 +1037,7 @@ copy_entries_to_user(unsigned int total_size,
}
}
t = ipt_get_target(e);
t = ipt_get_target_c(e);
if (copy_to_user(userptr + off + e->target_offset
+ offsetof(struct ipt_entry_target,
u.user.name),
......@@ -1035,7 +1054,7 @@ copy_entries_to_user(unsigned int total_size,
}
#ifdef CONFIG_COMPAT
static void compat_standard_from_user(void *dst, void *src)
static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
......@@ -1044,7 +1063,7 @@ static void compat_standard_from_user(void *dst, void *src)
memcpy(dst, &v, sizeof(v));
}
static int compat_standard_to_user(void __user *dst, void *src)
static int compat_standard_to_user(void __user *dst, const void *src)
{
compat_int_t cv = *(int *)src;
......@@ -1054,24 +1073,24 @@ static int compat_standard_to_user(void __user *dst, void *src)
}
static inline int
compat_calc_match(struct ipt_entry_match *m, int *size)
compat_calc_match(const struct ipt_entry_match *m, int *size)
{
*size += xt_compat_match_offset(m->u.kernel.match);
return 0;
}
static int compat_calc_entry(struct ipt_entry *e,
static int compat_calc_entry(const struct ipt_entry *e,
const struct xt_table_info *info,
void *base, struct xt_table_info *newinfo)
const void *base, struct xt_table_info *newinfo)
{
struct ipt_entry_target *t;
const struct ipt_entry_target *t;
unsigned int entry_offset;
int off, i, ret;
off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
entry_offset = (void *)e - base;
IPT_MATCH_ITERATE(e, compat_calc_match, &off);
t = ipt_get_target(e);
t = ipt_get_target_c(e);
off += xt_compat_target_offset(t->u.kernel.target);
newinfo->size -= off;
ret = xt_compat_add_offset(AF_INET, entry_offset, off);
......@@ -1107,7 +1126,8 @@ static int compat_table_info(const struct xt_table_info *info,
}
#endif
static int get_info(struct net *net, void __user *user, int *len, int compat)
static int get_info(struct net *net, void __user *user,
const int *len, int compat)
{
char name[IPT_TABLE_MAXNAMELEN];
struct xt_table *t;
......@@ -1167,7 +1187,8 @@ static int get_info(struct net *net, void __user *user, int *len, int compat)
}
static int
get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len)
get_entries(struct net *net, struct ipt_get_entries __user *uptr,
const int *len)
{
int ret;
struct ipt_get_entries get;
......@@ -1258,7 +1279,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
/* Decrease module usage counts and free resource */
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
NULL);
net, NULL);
xt_free_table_info(oldinfo);
if (copy_to_user(counters_ptr, counters,
sizeof(struct xt_counters) * num_counters) != 0)
......@@ -1277,7 +1298,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
}
static int
do_replace(struct net *net, void __user *user, unsigned int len)
do_replace(struct net *net, const void __user *user, unsigned int len)
{
int ret;
struct ipt_replace tmp;
......@@ -1303,7 +1324,7 @@ do_replace(struct net *net, void __user *user, unsigned int len)
goto free_newinfo;
}
ret = translate_table(tmp.name, tmp.valid_hooks,
ret = translate_table(net, tmp.name, tmp.valid_hooks,
newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
tmp.hook_entry, tmp.underflow);
if (ret != 0)
......@@ -1318,7 +1339,7 @@ do_replace(struct net *net, void __user *user, unsigned int len)
return 0;
free_newinfo_untrans:
IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL);
free_newinfo:
xt_free_table_info(newinfo);
return ret;
......@@ -1338,7 +1359,8 @@ add_counter_to_entry(struct ipt_entry *e,
}
static int
do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
do_add_counters(struct net *net, const void __user *user,
unsigned int len, int compat)
{
unsigned int i, curcpu;
struct xt_counters_info tmp;
......@@ -1534,10 +1556,10 @@ static int
check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
struct xt_table_info *newinfo,
unsigned int *size,
unsigned char *base,
unsigned char *limit,
unsigned int *hook_entries,
unsigned int *underflows,
const unsigned char *base,
const unsigned char *limit,
const unsigned int *hook_entries,
const unsigned int *underflows,
unsigned int *i,
const char *name)
{
......@@ -1655,7 +1677,7 @@ compat_copy_entry_from_user(struct compat_ipt_entry *e, void **dstptr,
}
static int
compat_check_entry(struct ipt_entry *e, const char *name,
compat_check_entry(struct ipt_entry *e, struct net *net, const char *name,
unsigned int *i)
{
struct xt_mtchk_param mtpar;
......@@ -1663,6 +1685,7 @@ compat_check_entry(struct ipt_entry *e, const char *name,
int ret;
j = 0;
mtpar.net = net;
mtpar.table = name;
mtpar.entryinfo = &e->ip;
mtpar.hook_mask = e->comefrom;
......@@ -1671,7 +1694,7 @@ compat_check_entry(struct ipt_entry *e, const char *name,
if (ret)
goto cleanup_matches;
ret = check_target(e, name);
ret = check_target(e, net, name);
if (ret)
goto cleanup_matches;
......@@ -1679,12 +1702,13 @@ compat_check_entry(struct ipt_entry *e, const char *name,
return 0;
cleanup_matches:
IPT_MATCH_ITERATE(e, cleanup_match, &j);
IPT_MATCH_ITERATE(e, cleanup_match, net, &j);
return ret;
}
static int
translate_compat_table(const char *name,
translate_compat_table(struct net *net,
const char *name,
unsigned int valid_hooks,
struct xt_table_info **pinfo,
void **pentry0,
......@@ -1773,12 +1797,12 @@ translate_compat_table(const char *name,
i = 0;
ret = IPT_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
name, &i);
net, name, &i);
if (ret) {
j -= i;
COMPAT_IPT_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
compat_release_entry, &j);
IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
IPT_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, net, &i);
xt_free_table_info(newinfo);
return ret;
}
......@@ -1833,7 +1857,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
goto free_newinfo;
}
ret = translate_compat_table(tmp.name, tmp.valid_hooks,
ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
&newinfo, &loc_cpu_entry, tmp.size,
tmp.num_entries, tmp.hook_entry,
tmp.underflow);
......@@ -1849,7 +1873,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
return 0;
free_newinfo_untrans:
IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
IPT_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL);
free_newinfo:
xt_free_table_info(newinfo);
return ret;
......@@ -2086,7 +2110,7 @@ struct xt_table *ipt_register_table(struct net *net,
loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(table->name, table->valid_hooks,
ret = translate_table(net, table->name, table->valid_hooks,
newinfo, loc_cpu_entry, repl->size,
repl->num_entries,
repl->hook_entry,
......@@ -2108,7 +2132,7 @@ struct xt_table *ipt_register_table(struct net *net,
return ERR_PTR(ret);
}
void ipt_unregister_table(struct xt_table *table)
void ipt_unregister_table(struct net *net, struct xt_table *table)
{
struct xt_table_info *private;
void *loc_cpu_entry;
......@@ -2118,7 +2142,7 @@ void ipt_unregister_table(struct xt_table *table)
/* Decrease module usage counts and free resources */
loc_cpu_entry = private->entries[raw_smp_processor_id()];
IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
IPT_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, net, NULL);
if (private->number > private->initial_entries)
module_put(table_owner);
xt_free_table_info(private);
......
......@@ -560,8 +560,7 @@ struct clusterip_seq_position {
static void *clusterip_seq_start(struct seq_file *s, loff_t *pos)
{
const struct proc_dir_entry *pde = s->private;
struct clusterip_config *c = pde->data;
struct clusterip_config *c = s->private;
unsigned int weight;
u_int32_t local_nodes;
struct clusterip_seq_position *idx;
......@@ -632,10 +631,9 @@ static int clusterip_proc_open(struct inode *inode, struct file *file)
if (!ret) {
struct seq_file *sf = file->private_data;
struct proc_dir_entry *pde = PDE(inode);
struct clusterip_config *c = pde->data;
struct clusterip_config *c = PDE(inode)->data;
sf->private = pde;
sf->private = c;
clusterip_config_get(c);
}
......@@ -645,8 +643,7 @@ static int clusterip_proc_open(struct inode *inode, struct file *file)
static int clusterip_proc_release(struct inode *inode, struct file *file)
{
struct proc_dir_entry *pde = PDE(inode);
struct clusterip_config *c = pde->data;
struct clusterip_config *c = PDE(inode)->data;
int ret;
ret = seq_release(inode, file);
......@@ -660,10 +657,9 @@ static int clusterip_proc_release(struct inode *inode, struct file *file)
static ssize_t clusterip_proc_write(struct file *file, const char __user *input,
size_t size, loff_t *ofs)
{
struct clusterip_config *c = PDE(file->f_path.dentry->d_inode)->data;
#define PROC_WRITELEN 10
char buffer[PROC_WRITELEN+1];
const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct clusterip_config *c = pde->data;
unsigned long nodenum;
if (copy_from_user(buffer, input, PROC_WRITELEN))
......
......@@ -338,7 +338,7 @@ struct compat_ipt_ulog_info {
char prefix[ULOG_PREFIX_LEN];
};
static void ulog_tg_compat_from_user(void *dst, void *src)
static void ulog_tg_compat_from_user(void *dst, const void *src)
{
const struct compat_ipt_ulog_info *cl = src;
struct ipt_ulog_info l = {
......@@ -351,7 +351,7 @@ static void ulog_tg_compat_from_user(void *dst, void *src)
memcpy(dst, &l, sizeof(l));
}
static int ulog_tg_compat_to_user(void __user *dst, void *src)
static int ulog_tg_compat_to_user(void __user *dst, const void *src)
{
const struct ipt_ulog_info *l = src;
struct compat_ipt_ulog_info cl = {
......
......@@ -23,104 +23,32 @@ MODULE_DESCRIPTION("iptables filter table");
(1 << NF_INET_FORWARD) | \
(1 << NF_INET_LOCAL_OUT))
static struct
{
struct ipt_replace repl;
struct ipt_standard entries[3];
struct ipt_error term;
} initial_table __net_initdata = {
.repl = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
.hook_entry = {
[NF_INET_LOCAL_IN] = 0,
[NF_INET_FORWARD] = sizeof(struct ipt_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
},
.underflow = {
[NF_INET_LOCAL_IN] = 0,
[NF_INET_FORWARD] = sizeof(struct ipt_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
},
},
.entries = {
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
.term = IPT_ERROR_INIT, /* ERROR */
};
static const struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_FILTER,
};
/* The work comes in here from netfilter.c. */
static unsigned int
ipt_local_in_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.iptable_filter);
}
static unsigned int
ipt_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
iptable_filter_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.iptable_filter);
}
const struct net *net;
static unsigned int
ipt_local_out_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr))
if (hook == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)))
/* root is playing with raw sockets. */
return NF_ACCEPT;
return ipt_do_table(skb, hook, in, out,
dev_net(out)->ipv4.iptable_filter);
net = dev_net((in != NULL) ? in : out);
return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_filter);
}
static struct nf_hook_ops ipt_ops[] __read_mostly = {
{
.hook = ipt_local_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_FILTER,
},
{
.hook = ipt_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_FILTER,
},
{
.hook = ipt_local_out_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_FILTER,
},
};
static struct nf_hook_ops *filter_ops __read_mostly;
/* Default to forward because I got too much mail already. */
static int forward = NF_ACCEPT;
......@@ -128,9 +56,18 @@ module_param(forward, bool, 0000);
static int __net_init iptable_filter_net_init(struct net *net)
{
/* Register table */
struct ipt_replace *repl;
repl = ipt_alloc_initial_table(&packet_filter);
if (repl == NULL)
return -ENOMEM;
/* Entry 1 is the FORWARD hook */
((struct ipt_standard *)repl->entries)[1].target.verdict =
-forward - 1;
net->ipv4.iptable_filter =
ipt_register_table(net, &packet_filter, &initial_table.repl);
ipt_register_table(net, &packet_filter, repl);
kfree(repl);
if (IS_ERR(net->ipv4.iptable_filter))
return PTR_ERR(net->ipv4.iptable_filter);
return 0;
......@@ -138,7 +75,7 @@ static int __net_init iptable_filter_net_init(struct net *net)
static void __net_exit iptable_filter_net_exit(struct net *net)
{
ipt_unregister_table(net->ipv4.iptable_filter);
ipt_unregister_table(net, net->ipv4.iptable_filter);
}
static struct pernet_operations iptable_filter_net_ops = {
......@@ -155,17 +92,16 @@ static int __init iptable_filter_init(void)
return -EINVAL;
}
/* Entry 1 is the FORWARD hook */
initial_table.entries[1].target.verdict = -forward - 1;
ret = register_pernet_subsys(&iptable_filter_net_ops);
if (ret < 0)
return ret;
/* Register hooks */
ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
if (ret < 0)
filter_ops = xt_hook_link(&packet_filter, iptable_filter_hook);
if (IS_ERR(filter_ops)) {
ret = PTR_ERR(filter_ops);
goto cleanup_table;
}
return ret;
......@@ -176,7 +112,7 @@ static int __init iptable_filter_init(void)
static void __exit iptable_filter_fini(void)
{
nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
xt_hook_unlink(&packet_filter, filter_ops);
unregister_pernet_subsys(&iptable_filter_net_ops);
}
......
......@@ -27,101 +27,16 @@ MODULE_DESCRIPTION("iptables mangle table");
(1 << NF_INET_LOCAL_OUT) | \
(1 << NF_INET_POST_ROUTING))
/* Ouch - five different hooks? Maybe this should be a config option..... -- BC */
static const struct
{
struct ipt_replace repl;
struct ipt_standard entries[5];
struct ipt_error term;
} initial_table __net_initdata = {
.repl = {
.name = "mangle",
.valid_hooks = MANGLE_VALID_HOOKS,
.num_entries = 6,
.size = sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
.hook_entry = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_LOCAL_IN] = sizeof(struct ipt_standard),
[NF_INET_FORWARD] = sizeof(struct ipt_standard) * 2,
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 3,
[NF_INET_POST_ROUTING] = sizeof(struct ipt_standard) * 4,
},
.underflow = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_LOCAL_IN] = sizeof(struct ipt_standard),
[NF_INET_FORWARD] = sizeof(struct ipt_standard) * 2,
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 3,
[NF_INET_POST_ROUTING] = sizeof(struct ipt_standard) * 4,
},
},
.entries = {
IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
},
.term = IPT_ERROR_INIT, /* ERROR */
};
static const struct xt_table packet_mangler = {
.name = "mangle",
.valid_hooks = MANGLE_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_MANGLE,
};
/* The work comes in here from netfilter.c. */
static unsigned int
ipt_pre_routing_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.iptable_mangle);
}
static unsigned int
ipt_post_routing_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(skb, hook, in, out,
dev_net(out)->ipv4.iptable_mangle);
}
static unsigned int
ipt_local_in_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.iptable_mangle);
}
static unsigned int
ipt_forward_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.iptable_mangle);
}
static unsigned int
ipt_local_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
ipt_mangle_out(struct sk_buff *skb, const struct net_device *out)
{
unsigned int ret;
const struct iphdr *iph;
......@@ -141,7 +56,7 @@ ipt_local_hook(unsigned int hook,
daddr = iph->daddr;
tos = iph->tos;
ret = ipt_do_table(skb, hook, in, out,
ret = ipt_do_table(skb, NF_INET_LOCAL_OUT, NULL, out,
dev_net(out)->ipv4.iptable_mangle);
/* Reroute for ANY change. */
if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) {
......@@ -158,49 +73,36 @@ ipt_local_hook(unsigned int hook,
return ret;
}
static struct nf_hook_ops ipt_ops[] __read_mostly = {
{
.hook = ipt_pre_routing_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_MANGLE,
},
{
.hook = ipt_local_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_MANGLE,
},
{
.hook = ipt_forward_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_MANGLE,
},
{
.hook = ipt_local_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_MANGLE,
},
{
.hook = ipt_post_routing_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_MANGLE,
},
};
/* The work comes in here from netfilter.c. */
static unsigned int
iptable_mangle_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
if (hook == NF_INET_LOCAL_OUT)
return ipt_mangle_out(skb, out);
if (hook == NF_INET_POST_ROUTING)
return ipt_do_table(skb, hook, in, out,
dev_net(out)->ipv4.iptable_mangle);
/* PREROUTING/INPUT/FORWARD: */
return ipt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.iptable_mangle);
}
static struct nf_hook_ops *mangle_ops __read_mostly;
static int __net_init iptable_mangle_net_init(struct net *net)
{
/* Register table */
struct ipt_replace *repl;
repl = ipt_alloc_initial_table(&packet_mangler);
if (repl == NULL)
return -ENOMEM;
net->ipv4.iptable_mangle =
ipt_register_table(net, &packet_mangler, &initial_table.repl);
ipt_register_table(net, &packet_mangler, repl);
kfree(repl);
if (IS_ERR(net->ipv4.iptable_mangle))
return PTR_ERR(net->ipv4.iptable_mangle);
return 0;
......@@ -208,7 +110,7 @@ static int __net_init iptable_mangle_net_init(struct net *net)
static void __net_exit iptable_mangle_net_exit(struct net *net)
{
ipt_unregister_table(net->ipv4.iptable_mangle);
ipt_unregister_table(net, net->ipv4.iptable_mangle);
}
static struct pernet_operations iptable_mangle_net_ops = {
......@@ -225,9 +127,11 @@ static int __init iptable_mangle_init(void)
return ret;
/* Register hooks */
ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
if (ret < 0)
mangle_ops = xt_hook_link(&packet_mangler, iptable_mangle_hook);
if (IS_ERR(mangle_ops)) {
ret = PTR_ERR(mangle_ops);
goto cleanup_table;
}
return ret;
......@@ -238,7 +142,7 @@ static int __init iptable_mangle_init(void)
static void __exit iptable_mangle_fini(void)
{
nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
xt_hook_unlink(&packet_mangler, mangle_ops);
unregister_pernet_subsys(&iptable_mangle_net_ops);
}
......
......@@ -9,90 +9,44 @@
#define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))
static const struct
{
struct ipt_replace repl;
struct ipt_standard entries[2];
struct ipt_error term;
} initial_table __net_initdata = {
.repl = {
.name = "raw",
.valid_hooks = RAW_VALID_HOOKS,
.num_entries = 3,
.size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
.hook_entry = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard)
},
.underflow = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard)
},
},
.entries = {
IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
.term = IPT_ERROR_INIT, /* ERROR */
};
static const struct xt_table packet_raw = {
.name = "raw",
.valid_hooks = RAW_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_RAW,
};
/* The work comes in here from netfilter.c. */
static unsigned int
ipt_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
iptable_raw_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.iptable_raw);
}
const struct net *net;
static unsigned int
ipt_local_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr))
if (hook == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)))
/* root is playing with raw sockets. */
return NF_ACCEPT;
return ipt_do_table(skb, hook, in, out,
dev_net(out)->ipv4.iptable_raw);
net = dev_net((in != NULL) ? in : out);
return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_raw);
}
/* 'raw' is the very first table. */
static struct nf_hook_ops ipt_ops[] __read_mostly = {
{
.hook = ipt_hook,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_RAW,
.owner = THIS_MODULE,
},
{
.hook = ipt_local_hook,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_RAW,
.owner = THIS_MODULE,
},
};
static struct nf_hook_ops *rawtable_ops __read_mostly;
static int __net_init iptable_raw_net_init(struct net *net)
{
/* Register table */
struct ipt_replace *repl;
repl = ipt_alloc_initial_table(&packet_raw);
if (repl == NULL)
return -ENOMEM;
net->ipv4.iptable_raw =
ipt_register_table(net, &packet_raw, &initial_table.repl);
ipt_register_table(net, &packet_raw, repl);
kfree(repl);
if (IS_ERR(net->ipv4.iptable_raw))
return PTR_ERR(net->ipv4.iptable_raw);
return 0;
......@@ -100,7 +54,7 @@ static int __net_init iptable_raw_net_init(struct net *net)
static void __net_exit iptable_raw_net_exit(struct net *net)
{
ipt_unregister_table(net->ipv4.iptable_raw);
ipt_unregister_table(net, net->ipv4.iptable_raw);
}
static struct pernet_operations iptable_raw_net_ops = {
......@@ -117,9 +71,11 @@ static int __init iptable_raw_init(void)
return ret;
/* Register hooks */
ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
if (ret < 0)
rawtable_ops = xt_hook_link(&packet_raw, iptable_raw_hook);
if (IS_ERR(rawtable_ops)) {
ret = PTR_ERR(rawtable_ops);
goto cleanup_table;
}
return ret;
......@@ -130,7 +86,7 @@ static int __init iptable_raw_init(void)
static void __exit iptable_raw_fini(void)
{
nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
xt_hook_unlink(&packet_raw, rawtable_ops);
unregister_pernet_subsys(&iptable_raw_net_ops);
}
......
......@@ -27,109 +27,44 @@ MODULE_DESCRIPTION("iptables security table, for MAC rules");
(1 << NF_INET_FORWARD) | \
(1 << NF_INET_LOCAL_OUT)
static const struct
{
struct ipt_replace repl;
struct ipt_standard entries[3];
struct ipt_error term;
} initial_table __net_initdata = {
.repl = {
.name = "security",
.valid_hooks = SECURITY_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
.hook_entry = {
[NF_INET_LOCAL_IN] = 0,
[NF_INET_FORWARD] = sizeof(struct ipt_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
},
.underflow = {
[NF_INET_LOCAL_IN] = 0,
[NF_INET_FORWARD] = sizeof(struct ipt_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
},
},
.entries = {
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
.term = IPT_ERROR_INIT, /* ERROR */
};
static const struct xt_table security_table = {
.name = "security",
.valid_hooks = SECURITY_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV4,
.priority = NF_IP_PRI_SECURITY,
};
static unsigned int
ipt_local_in_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.iptable_security);
}
static unsigned int
ipt_forward_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
iptable_security_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ipt_do_table(skb, hook, in, out,
dev_net(in)->ipv4.iptable_security);
}
const struct net *net;
static unsigned int
ipt_local_out_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* Somebody is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr))
if (hook == NF_INET_LOCAL_OUT &&
(skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)))
/* Somebody is playing with raw sockets. */
return NF_ACCEPT;
return ipt_do_table(skb, hook, in, out,
dev_net(out)->ipv4.iptable_security);
net = dev_net((in != NULL) ? in : out);
return ipt_do_table(skb, hook, in, out, net->ipv4.iptable_security);
}
static struct nf_hook_ops ipt_ops[] __read_mostly = {
{
.hook = ipt_local_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP_PRI_SECURITY,
},
{
.hook = ipt_forward_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_SECURITY,
},
{
.hook = ipt_local_out_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_SECURITY,
},
};
static struct nf_hook_ops *sectbl_ops __read_mostly;
static int __net_init iptable_security_net_init(struct net *net)
{
net->ipv4.iptable_security =
ipt_register_table(net, &security_table, &initial_table.repl);
struct ipt_replace *repl;
repl = ipt_alloc_initial_table(&security_table);
if (repl == NULL)
return -ENOMEM;
net->ipv4.iptable_security =
ipt_register_table(net, &security_table, repl);
kfree(repl);
if (IS_ERR(net->ipv4.iptable_security))
return PTR_ERR(net->ipv4.iptable_security);
......@@ -138,7 +73,7 @@ static int __net_init iptable_security_net_init(struct net *net)
static void __net_exit iptable_security_net_exit(struct net *net)
{
ipt_unregister_table(net->ipv4.iptable_security);
ipt_unregister_table(net, net->ipv4.iptable_security);
}
static struct pernet_operations iptable_security_net_ops = {
......@@ -154,9 +89,11 @@ static int __init iptable_security_init(void)
if (ret < 0)
return ret;
ret = nf_register_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
if (ret < 0)
sectbl_ops = xt_hook_link(&security_table, iptable_security_hook);
if (IS_ERR(sectbl_ops)) {
ret = PTR_ERR(sectbl_ops);
goto cleanup_table;
}
return ret;
......@@ -167,7 +104,7 @@ static int __init iptable_security_init(void)
static void __exit iptable_security_fini(void)
{
nf_unregister_hooks(ipt_ops, ARRAY_SIZE(ipt_ops));
xt_hook_unlink(&security_table, sectbl_ops);
unregister_pernet_subsys(&iptable_security_net_ops);
}
......
......@@ -22,6 +22,7 @@
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/nf_nat_helper.h>
......@@ -266,7 +267,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
return -EINVAL;
}
h = nf_conntrack_find_get(sock_net(sk), &tuple);
h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple);
if (h) {
struct sockaddr_in sin;
struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
......
......@@ -18,6 +18,7 @@
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_log.h>
static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ;
......@@ -114,13 +115,14 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb,
/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
static int
icmp_error_message(struct net *net, struct sk_buff *skb,
icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
enum ip_conntrack_info *ctinfo,
unsigned int hooknum)
{
struct nf_conntrack_tuple innertuple, origtuple;
const struct nf_conntrack_l4proto *innerproto;
const struct nf_conntrack_tuple_hash *h;
u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
NF_CT_ASSERT(skb->nfct == NULL);
......@@ -146,7 +148,7 @@ icmp_error_message(struct net *net, struct sk_buff *skb,
*ctinfo = IP_CT_RELATED;
h = nf_conntrack_find_get(net, &innertuple);
h = nf_conntrack_find_get(net, zone, &innertuple);
if (!h) {
pr_debug("icmp_error_message: no match\n");
return -NF_ACCEPT;
......@@ -163,7 +165,8 @@ icmp_error_message(struct net *net, struct sk_buff *skb,
/* Small and modified version of icmp_rcv */
static int
icmp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
icmp_error(struct net *net, struct nf_conn *tmpl,
struct sk_buff *skb, unsigned int dataoff,
enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum)
{
const struct icmphdr *icmph;
......@@ -208,7 +211,7 @@ icmp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
icmph->type != ICMP_REDIRECT)
return NF_ACCEPT;
return icmp_error_message(net, skb, ctinfo, hooknum);
return icmp_error_message(net, tmpl, skb, ctinfo, hooknum);
}
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
......
......@@ -16,7 +16,9 @@
#include <linux/netfilter_bridge.h>
#include <linux/netfilter_ipv4.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
#include <net/netfilter/nf_conntrack.h>
/* Returns new sk_buff, or NULL */
static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
......@@ -38,15 +40,20 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum,
struct sk_buff *skb)
{
u16 zone = NF_CT_DEFAULT_ZONE;
if (skb->nfct)
zone = nf_ct_zone((struct nf_conn *)skb->nfct);
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge &&
skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
return IP_DEFRAG_CONNTRACK_BRIDGE_IN;
return IP_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
#endif
if (hooknum == NF_INET_PRE_ROUTING)
return IP_DEFRAG_CONNTRACK_IN;
return IP_DEFRAG_CONNTRACK_IN + zone;
else
return IP_DEFRAG_CONNTRACK_OUT;
return IP_DEFRAG_CONNTRACK_OUT + zone;
}
static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
......@@ -59,7 +66,7 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
#if !defined(CONFIG_NF_NAT) && !defined(CONFIG_NF_NAT_MODULE)
/* Previously seen (loopback)? Ignore. Do this before
fragment check. */
if (skb->nfct)
if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct))
return NF_ACCEPT;
#endif
#endif
......
......@@ -30,6 +30,7 @@
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_zones.h>
static DEFINE_SPINLOCK(nf_nat_lock);
......@@ -69,13 +70,14 @@ EXPORT_SYMBOL_GPL(nf_nat_proto_put);
/* We keep an extra hash for each conntrack, for fast searching. */
static inline unsigned int
hash_by_src(const struct net *net, const struct nf_conntrack_tuple *tuple)
hash_by_src(const struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple)
{
unsigned int hash;
/* Original src, to ensure we map it consistently if poss. */
hash = jhash_3words((__force u32)tuple->src.u3.ip,
(__force u32)tuple->src.u.all,
(__force u32)tuple->src.u.all ^ zone,
tuple->dst.protonum, 0);
return ((u64)hash * net->ipv4.nat_htable_size) >> 32;
}
......@@ -139,12 +141,12 @@ same_src(const struct nf_conn *ct,
/* Only called for SRC manip */
static int
find_appropriate_src(struct net *net,
find_appropriate_src(struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple,
struct nf_conntrack_tuple *result,
const struct nf_nat_range *range)
{
unsigned int h = hash_by_src(net, tuple);
unsigned int h = hash_by_src(net, zone, tuple);
const struct nf_conn_nat *nat;
const struct nf_conn *ct;
const struct hlist_node *n;
......@@ -152,7 +154,7 @@ find_appropriate_src(struct net *net,
rcu_read_lock();
hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
ct = nat->ct;
if (same_src(ct, tuple)) {
if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) {
/* Copy source part from reply tuple. */
nf_ct_invert_tuplepr(result,
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
......@@ -175,7 +177,7 @@ find_appropriate_src(struct net *net,
the ip with the lowest src-ip/dst-ip/proto usage.
*/
static void
find_best_ips_proto(struct nf_conntrack_tuple *tuple,
find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
const struct nf_conn *ct,
enum nf_nat_manip_type maniptype)
......@@ -209,7 +211,7 @@ find_best_ips_proto(struct nf_conntrack_tuple *tuple,
maxip = ntohl(range->max_ip);
j = jhash_2words((__force u32)tuple->src.u3.ip,
range->flags & IP_NAT_RANGE_PERSISTENT ?
0 : (__force u32)tuple->dst.u3.ip, 0);
0 : (__force u32)tuple->dst.u3.ip ^ zone, 0);
j = ((u64)j * (maxip - minip + 1)) >> 32;
*var_ipp = htonl(minip + j);
}
......@@ -229,6 +231,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
{
struct net *net = nf_ct_net(ct);
const struct nf_nat_protocol *proto;
u16 zone = nf_ct_zone(ct);
/* 1) If this srcip/proto/src-proto-part is currently mapped,
and that same mapping gives a unique tuple within the given
......@@ -239,7 +242,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
manips not an issue. */
if (maniptype == IP_NAT_MANIP_SRC &&
!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
if (find_appropriate_src(net, orig_tuple, tuple, range)) {
if (find_appropriate_src(net, zone, orig_tuple, tuple, range)) {
pr_debug("get_unique_tuple: Found current src map\n");
if (!nf_nat_used_tuple(tuple, ct))
return;
......@@ -249,7 +252,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
/* 2) Select the least-used IP/proto combination in the given
range. */
*tuple = *orig_tuple;
find_best_ips_proto(tuple, range, ct, maniptype);
find_best_ips_proto(zone, tuple, range, ct, maniptype);
/* 3) The per-protocol part of the manip is made to map into
the range to make a unique tuple. */
......@@ -327,7 +330,8 @@ nf_nat_setup_info(struct nf_conn *ct,
if (have_to_hash) {
unsigned int srchash;
srchash = hash_by_src(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
srchash = hash_by_src(net, nf_ct_zone(ct),
&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
spin_lock_bh(&nf_nat_lock);
/* nf_conntrack_alter_reply might re-allocate exntension aera */
nat = nfct_nat(ct);
......
......@@ -27,76 +27,29 @@ MODULE_ALIAS("ip_nat_ftp");
/* FIXME: Time out? --RR */
static int
mangle_rfc959_packet(struct sk_buff *skb,
__be32 newip,
u_int16_t port,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
static int nf_nat_ftp_fmt_cmd(enum nf_ct_ftp_type type,
char *buffer, size_t buflen,
__be32 addr, u16 port)
{
char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
sprintf(buffer, "%u,%u,%u,%u,%u,%u",
NIPQUAD(newip), port>>8, port&0xFF);
pr_debug("calling nf_nat_mangle_tcp_packet\n");
return nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
}
/* |1|132.235.1.2|6275| */
static int
mangle_eprt_packet(struct sk_buff *skb,
__be32 newip,
u_int16_t port,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
char buffer[sizeof("|1|255.255.255.255|65535|")];
sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);
pr_debug("calling nf_nat_mangle_tcp_packet\n");
return nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
}
/* |1|132.235.1.2|6275| */
static int
mangle_epsv_packet(struct sk_buff *skb,
__be32 newip,
u_int16_t port,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
char buffer[sizeof("|||65535|")];
sprintf(buffer, "|||%u|", port);
pr_debug("calling nf_nat_mangle_tcp_packet\n");
switch (type) {
case NF_CT_FTP_PORT:
case NF_CT_FTP_PASV:
return snprintf(buffer, buflen, "%u,%u,%u,%u,%u,%u",
((unsigned char *)&addr)[0],
((unsigned char *)&addr)[1],
((unsigned char *)&addr)[2],
((unsigned char *)&addr)[3],
port >> 8,
port & 0xFF);
case NF_CT_FTP_EPRT:
return snprintf(buffer, buflen, "|1|%pI4|%u|", &addr, port);
case NF_CT_FTP_EPSV:
return snprintf(buffer, buflen, "|||%u|", port);
}
return nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
return 0;
}
static int (*mangle[])(struct sk_buff *, __be32, u_int16_t,
unsigned int, unsigned int, struct nf_conn *,
enum ip_conntrack_info)
= {
[NF_CT_FTP_PORT] = mangle_rfc959_packet,
[NF_CT_FTP_PASV] = mangle_rfc959_packet,
[NF_CT_FTP_EPRT] = mangle_eprt_packet,
[NF_CT_FTP_EPSV] = mangle_epsv_packet
};
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int nf_nat_ftp(struct sk_buff *skb,
......@@ -110,6 +63,8 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
u_int16_t port;
int dir = CTINFO2DIR(ctinfo);
struct nf_conn *ct = exp->master;
char buffer[sizeof("|1|255.255.255.255|65535|")];
unsigned int buflen;
pr_debug("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);
......@@ -132,11 +87,21 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
if (port == 0)
return NF_DROP;
if (!mangle[type](skb, newip, port, matchoff, matchlen, ct, ctinfo)) {
nf_ct_unexpect_related(exp);
return NF_DROP;
}
buflen = nf_nat_ftp_fmt_cmd(type, buffer, sizeof(buffer), newip, port);
if (!buflen)
goto out;
pr_debug("calling nf_nat_mangle_tcp_packet\n");
if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
matchlen, buffer, buflen))
goto out;
return NF_ACCEPT;
out:
nf_ct_unexpect_related(exp);
return NF_DROP;
}
static void __exit nf_nat_ftp_fini(void)
......
......@@ -141,6 +141,17 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
return 1;
}
void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
__be32 seq, s16 off)
{
if (!off)
return;
set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
adjust_tcp_sequence(ntohl(seq), off, ct, ctinfo);
nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
}
EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
/* Generic function for mangling variable-length address changes inside
* NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
* command in FTP).
......@@ -149,14 +160,13 @@ static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
* skb enlargement, ...
*
* */
int
nf_nat_mangle_tcp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len)
int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len, bool adjust)
{
struct rtable *rt = skb_rtable(skb);
struct iphdr *iph;
......@@ -202,16 +212,13 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
inet_proto_csum_replace2(&tcph->check, skb,
htons(oldlen), htons(datalen), 1);
if (rep_len != match_len) {
set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
adjust_tcp_sequence(ntohl(tcph->seq),
(int)rep_len - (int)match_len,
ct, ctinfo);
nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
}
if (adjust && rep_len != match_len)
nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
(int)rep_len - (int)match_len);
return 1;
}
EXPORT_SYMBOL(nf_nat_mangle_tcp_packet);
EXPORT_SYMBOL(__nf_nat_mangle_tcp_packet);
/* Generic function for mangling variable-length address changes inside
* NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
......
......@@ -25,6 +25,7 @@
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_zones.h>
#include <linux/netfilter/nf_conntrack_proto_gre.h>
#include <linux/netfilter/nf_conntrack_pptp.h>
......@@ -74,7 +75,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
pr_debug("trying to unexpect other dir: ");
nf_ct_dump_tuple_ip(&t);
other_exp = nf_ct_expect_find_get(net, &t);
other_exp = nf_ct_expect_find_get(net, nf_ct_zone(ct), &t);
if (other_exp) {
nf_ct_unexpect_related(other_exp);
nf_ct_expect_put(other_exp);
......
......@@ -28,36 +28,6 @@
(1 << NF_INET_POST_ROUTING) | \
(1 << NF_INET_LOCAL_OUT))
static const struct
{
struct ipt_replace repl;
struct ipt_standard entries[3];
struct ipt_error term;
} nat_initial_table __net_initdata = {
.repl = {
.name = "nat",
.valid_hooks = NAT_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
.hook_entry = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_POST_ROUTING] = sizeof(struct ipt_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
},
.underflow = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_POST_ROUTING] = sizeof(struct ipt_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
},
},
.entries = {
IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
.term = IPT_ERROR_INIT, /* ERROR */
};
static const struct xt_table nat_table = {
.name = "nat",
.valid_hooks = NAT_VALID_HOOKS,
......@@ -186,8 +156,13 @@ static struct xt_target ipt_dnat_reg __read_mostly = {
static int __net_init nf_nat_rule_net_init(struct net *net)
{
net->ipv4.nat_table = ipt_register_table(net, &nat_table,
&nat_initial_table.repl);
struct ipt_replace *repl;
repl = ipt_alloc_initial_table(&nat_table);
if (repl == NULL)
return -ENOMEM;
net->ipv4.nat_table = ipt_register_table(net, &nat_table, repl);
kfree(repl);
if (IS_ERR(net->ipv4.nat_table))
return PTR_ERR(net->ipv4.nat_table);
return 0;
......@@ -195,7 +170,7 @@ static int __net_init nf_nat_rule_net_init(struct net *net)
static void __net_exit nf_nat_rule_net_exit(struct net *net)
{
ipt_unregister_table(net->ipv4.nat_table);
ipt_unregister_table(net, net->ipv4.nat_table);
}
static struct pernet_operations nf_nat_rule_net_ops = {
......
/* SIP extension for UDP NAT alteration.
/* SIP extension for NAT alteration.
*
* (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
* based on RR's ip_nat_ftp.c and other modules.
......@@ -15,6 +15,7 @@
#include <linux/ip.h>
#include <net/ip.h>
#include <linux/udp.h>
#include <linux/tcp.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_helper.h>
......@@ -29,25 +30,42 @@ MODULE_DESCRIPTION("SIP NAT helper");
MODULE_ALIAS("ip_nat_sip");
static unsigned int mangle_packet(struct sk_buff *skb,
static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int matchoff, unsigned int matchlen,
const char *buffer, unsigned int buflen)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen,
buffer, buflen))
return 0;
struct tcphdr *th;
unsigned int baseoff;
if (nf_ct_protonum(ct) == IPPROTO_TCP) {
th = (struct tcphdr *)(skb->data + ip_hdrlen(skb));
baseoff = ip_hdrlen(skb) + th->doff * 4;
matchoff += dataoff - baseoff;
if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
matchoff, matchlen,
buffer, buflen, false))
return 0;
} else {
baseoff = ip_hdrlen(skb) + sizeof(struct udphdr);
matchoff += dataoff - baseoff;
if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
matchoff, matchlen,
buffer, buflen))
return 0;
}
/* Reload data pointer and adjust datalen value */
*dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
*dptr = skb->data + dataoff;
*datalen += buflen - matchlen;
return 1;
}
static int map_addr(struct sk_buff *skb,
static int map_addr(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int matchoff, unsigned int matchlen,
union nf_inet_addr *addr, __be16 port)
......@@ -76,11 +94,11 @@ static int map_addr(struct sk_buff *skb,
buflen = sprintf(buffer, "%pI4:%u", &newaddr, ntohs(newport));
return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
buffer, buflen);
}
static int map_sip_addr(struct sk_buff *skb,
static int map_sip_addr(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
enum sip_header_types type)
{
......@@ -93,16 +111,18 @@ static int map_sip_addr(struct sk_buff *skb,
if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
&matchoff, &matchlen, &addr, &port) <= 0)
return 1;
return map_addr(skb, dptr, datalen, matchoff, matchlen, &addr, port);
return map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
&addr, port);
}
static unsigned int ip_nat_sip(struct sk_buff *skb,
static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned int dataoff, matchoff, matchlen;
unsigned int coff, matchoff, matchlen;
enum sip_header_types hdr;
union nf_inet_addr addr;
__be16 port;
int request, in_header;
......@@ -112,16 +132,21 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
if (ct_sip_parse_request(ct, *dptr, *datalen,
&matchoff, &matchlen,
&addr, &port) > 0 &&
!map_addr(skb, dptr, datalen, matchoff, matchlen,
!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
&addr, port))
return NF_DROP;
request = 1;
} else
request = 0;
if (nf_ct_protonum(ct) == IPPROTO_TCP)
hdr = SIP_HDR_VIA_TCP;
else
hdr = SIP_HDR_VIA_UDP;
/* Translate topmost Via header and parameters */
if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
SIP_HDR_VIA, NULL, &matchoff, &matchlen,
hdr, NULL, &matchoff, &matchlen,
&addr, &port) > 0) {
unsigned int matchend, poff, plen, buflen, n;
char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
......@@ -138,7 +163,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
goto next;
}
if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
&addr, port))
return NF_DROP;
......@@ -153,8 +178,8 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
buflen = sprintf(buffer, "%pI4",
&ct->tuplehash[!dir].tuple.dst.u3.ip);
if (!mangle_packet(skb, dptr, datalen, poff, plen,
buffer, buflen))
if (!mangle_packet(skb, dataoff, dptr, datalen,
poff, plen, buffer, buflen))
return NF_DROP;
}
......@@ -167,8 +192,8 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
buflen = sprintf(buffer, "%pI4",
&ct->tuplehash[!dir].tuple.src.u3.ip);
if (!mangle_packet(skb, dptr, datalen, poff, plen,
buffer, buflen))
if (!mangle_packet(skb, dataoff, dptr, datalen,
poff, plen, buffer, buflen))
return NF_DROP;
}
......@@ -181,31 +206,45 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
buflen = sprintf(buffer, "%u", ntohs(p));
if (!mangle_packet(skb, dptr, datalen, poff, plen,
buffer, buflen))
if (!mangle_packet(skb, dataoff, dptr, datalen,
poff, plen, buffer, buflen))
return NF_DROP;
}
}
next:
/* Translate Contact headers */
dataoff = 0;
coff = 0;
in_header = 0;
while (ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen,
while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen,
SIP_HDR_CONTACT, &in_header,
&matchoff, &matchlen,
&addr, &port) > 0) {
if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
&addr, port))
return NF_DROP;
}
if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) ||
!map_sip_addr(skb, dptr, datalen, SIP_HDR_TO))
if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) ||
!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO))
return NF_DROP;
return NF_ACCEPT;
}
static void ip_nat_sip_seq_adjust(struct sk_buff *skb, s16 off)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
const struct tcphdr *th;
if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0)
return;
th = (struct tcphdr *)(skb->data + ip_hdrlen(skb));
nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off);
}
/* Handles expected signalling connections and media streams */
static void ip_nat_sip_expected(struct nf_conn *ct,
struct nf_conntrack_expect *exp)
......@@ -232,7 +271,7 @@ static void ip_nat_sip_expected(struct nf_conn *ct,
}
}
static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
struct nf_conntrack_expect *exp,
unsigned int matchoff,
......@@ -279,8 +318,8 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
if (exp->tuple.dst.u3.ip != exp->saved_ip ||
exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
buflen = sprintf(buffer, "%pI4:%u", &newip, port);
if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
buffer, buflen))
if (!mangle_packet(skb, dataoff, dptr, datalen,
matchoff, matchlen, buffer, buflen))
goto err;
}
return NF_ACCEPT;
......@@ -290,7 +329,7 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
return NF_DROP;
}
static int mangle_content_len(struct sk_buff *skb,
static int mangle_content_len(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen)
{
enum ip_conntrack_info ctinfo;
......@@ -312,12 +351,13 @@ static int mangle_content_len(struct sk_buff *skb,
return 0;
buflen = sprintf(buffer, "%u", c_len);
return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
buffer, buflen);
}
static int mangle_sdp_packet(struct sk_buff *skb, const char **dptr,
unsigned int dataoff, unsigned int *datalen,
static int mangle_sdp_packet(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int sdpoff,
enum sdp_header_types type,
enum sdp_header_types term,
char *buffer, int buflen)
......@@ -326,16 +366,16 @@ static int mangle_sdp_packet(struct sk_buff *skb, const char **dptr,
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchlen, matchoff;
if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term,
if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
&matchoff, &matchlen) <= 0)
return -ENOENT;
return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
buffer, buflen) ? 0 : -EINVAL;
}
static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr,
unsigned int dataoff,
unsigned int *datalen,
static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int sdpoff,
enum sdp_header_types type,
enum sdp_header_types term,
const union nf_inet_addr *addr)
......@@ -344,16 +384,15 @@ static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr,
unsigned int buflen;
buflen = sprintf(buffer, "%pI4", &addr->ip);
if (mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term,
if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, type, term,
buffer, buflen))
return 0;
return mangle_content_len(skb, dptr, datalen);
return mangle_content_len(skb, dataoff, dptr, datalen);
}
static unsigned int ip_nat_sdp_port(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int matchoff,
unsigned int matchlen,
u_int16_t port)
......@@ -362,16 +401,16 @@ static unsigned int ip_nat_sdp_port(struct sk_buff *skb,
unsigned int buflen;
buflen = sprintf(buffer, "%u", port);
if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
if (!mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
buffer, buflen))
return 0;
return mangle_content_len(skb, dptr, datalen);
return mangle_content_len(skb, dataoff, dptr, datalen);
}
static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr,
unsigned int dataoff,
unsigned int *datalen,
static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int sdpoff,
const union nf_inet_addr *addr)
{
char buffer[sizeof("nnn.nnn.nnn.nnn")];
......@@ -379,12 +418,12 @@ static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr,
/* Mangle session description owner and contact addresses */
buflen = sprintf(buffer, "%pI4", &addr->ip);
if (mangle_sdp_packet(skb, dptr, dataoff, datalen,
if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA,
buffer, buflen))
return 0;
switch (mangle_sdp_packet(skb, dptr, dataoff, datalen,
switch (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA,
buffer, buflen)) {
case 0:
......@@ -401,14 +440,13 @@ static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr,
return 0;
}
return mangle_content_len(skb, dptr, datalen);
return mangle_content_len(skb, dataoff, dptr, datalen);
}
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_sdp_media(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp,
unsigned int mediaoff,
......@@ -456,7 +494,8 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb,
/* Update media port. */
if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
!ip_nat_sdp_port(skb, dptr, datalen, mediaoff, medialen, port))
!ip_nat_sdp_port(skb, dataoff, dptr, datalen,
mediaoff, medialen, port))
goto err2;
return NF_ACCEPT;
......@@ -471,6 +510,7 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb,
static void __exit nf_nat_sip_fini(void)
{
rcu_assign_pointer(nf_nat_sip_hook, NULL);
rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, NULL);
rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_port_hook, NULL);
......@@ -482,12 +522,14 @@ static void __exit nf_nat_sip_fini(void)
static int __init nf_nat_sip_init(void)
{
BUG_ON(nf_nat_sip_hook != NULL);
BUG_ON(nf_nat_sip_seq_adjust_hook != NULL);
BUG_ON(nf_nat_sip_expect_hook != NULL);
BUG_ON(nf_nat_sdp_addr_hook != NULL);
BUG_ON(nf_nat_sdp_port_hook != NULL);
BUG_ON(nf_nat_sdp_session_hook != NULL);
BUG_ON(nf_nat_sdp_media_hook != NULL);
rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, ip_nat_sip_seq_adjust);
rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port);
......
......@@ -1038,7 +1038,7 @@ static int snmp_parse_mangle(unsigned char *msg,
unsigned int cls, con, tag, vers, pdutype;
struct asn1_ctx ctx;
struct asn1_octstr comm;
struct snmp_object **obj;
struct snmp_object *obj;
if (debug > 1)
hex_dump(msg, len);
......@@ -1148,43 +1148,34 @@ static int snmp_parse_mangle(unsigned char *msg,
if (cls != ASN1_UNI || con != ASN1_CON || tag != ASN1_SEQ)
return 0;
obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC);
if (obj == NULL) {
if (net_ratelimit())
printk(KERN_WARNING "OOM in bsalg(%d)\n", __LINE__);
return 0;
}
while (!asn1_eoc_decode(&ctx, eoc)) {
unsigned int i;
if (!snmp_object_decode(&ctx, obj)) {
if (*obj) {
kfree((*obj)->id);
kfree(*obj);
if (!snmp_object_decode(&ctx, &obj)) {
if (obj) {
kfree(obj->id);
kfree(obj);
}
kfree(obj);
return 0;
}
if (debug > 1) {
printk(KERN_DEBUG "bsalg: object: ");
for (i = 0; i < (*obj)->id_len; i++) {
for (i = 0; i < obj->id_len; i++) {
if (i > 0)
printk(".");
printk("%lu", (*obj)->id[i]);
printk("%lu", obj->id[i]);
}
printk(": type=%u\n", (*obj)->type);
printk(": type=%u\n", obj->type);
}
if ((*obj)->type == SNMP_IPADDR)
if (obj->type == SNMP_IPADDR)
mangle_address(ctx.begin, ctx.pointer - 4 , map, check);
kfree((*obj)->id);
kfree(*obj);
kfree(obj->id);
kfree(obj);
}
kfree(obj);
if (!asn1_eoc_decode(&ctx, eoc))
return 0;
......
......@@ -29,6 +29,7 @@
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_log.h>
#include "../../netfilter/xt_repldata.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
......@@ -67,6 +68,12 @@ do { \
#define inline
#endif
void *ip6t_alloc_initial_table(const struct xt_table *info)
{
return xt_alloc_initial_table(ip6t, IP6T);
}
EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
/*
We keep a set of rules for each CPU, so we can avoid write-locking
them in the softirq when updating the counters and therefore
......@@ -201,7 +208,7 @@ ip6t_error(struct sk_buff *skb, const struct xt_target_param *par)
/* Performance critical - called for every packet */
static inline bool
do_match(struct ip6t_entry_match *m, const struct sk_buff *skb,
do_match(const struct ip6t_entry_match *m, const struct sk_buff *skb,
struct xt_match_param *par)
{
par->match = m->u.kernel.match;
......@@ -215,7 +222,7 @@ do_match(struct ip6t_entry_match *m, const struct sk_buff *skb,
}
static inline struct ip6t_entry *
get_entry(void *base, unsigned int offset)
get_entry(const void *base, unsigned int offset)
{
return (struct ip6t_entry *)(base + offset);
}
......@@ -229,6 +236,12 @@ static inline bool unconditional(const struct ip6t_ip6 *ipv6)
return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
}
static inline const struct ip6t_entry_target *
ip6t_get_target_c(const struct ip6t_entry *e)
{
return ip6t_get_target((struct ip6t_entry *)e);
}
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
/* This cries for unification! */
......@@ -264,11 +277,11 @@ static struct nf_loginfo trace_loginfo = {
/* Mildly perf critical (only if packet tracing is on) */
static inline int
get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
const char *hookname, const char **chainname,
const char **comment, unsigned int *rulenum)
{
struct ip6t_standard_target *t = (void *)ip6t_get_target(s);
const struct ip6t_standard_target *t = (void *)ip6t_get_target_c(s);
if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
/* Head of user chain: ERROR target with chainname */
......@@ -294,15 +307,15 @@ get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
return 0;
}
static void trace_packet(struct sk_buff *skb,
static void trace_packet(const struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
const char *tablename,
struct xt_table_info *private,
struct ip6t_entry *e)
const struct xt_table_info *private,
const struct ip6t_entry *e)
{
void *table_base;
const void *table_base;
const struct ip6t_entry *root;
const char *hookname, *chainname, *comment;
unsigned int rulenum = 0;
......@@ -345,9 +358,9 @@ ip6t_do_table(struct sk_buff *skb,
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
const char *indev, *outdev;
void *table_base;
const void *table_base;
struct ip6t_entry *e, *back;
struct xt_table_info *private;
const struct xt_table_info *private;
struct xt_match_param mtpar;
struct xt_target_param tgpar;
......@@ -378,7 +391,7 @@ ip6t_do_table(struct sk_buff *skb,
back = get_entry(table_base, private->underflow[hook]);
do {
struct ip6t_entry_target *t;
const struct ip6t_entry_target *t;
IP_NF_ASSERT(e);
IP_NF_ASSERT(back);
......@@ -393,7 +406,7 @@ ip6t_do_table(struct sk_buff *skb,
ntohs(ipv6_hdr(skb)->payload_len) +
sizeof(struct ipv6hdr), 1);
t = ip6t_get_target(e);
t = ip6t_get_target_c(e);
IP_NF_ASSERT(t->u.kernel.target);
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
......@@ -475,7 +488,7 @@ ip6t_do_table(struct sk_buff *skb,
/* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */
static int
mark_source_chains(struct xt_table_info *newinfo,
mark_source_chains(const struct xt_table_info *newinfo,
unsigned int valid_hooks, void *entry0)
{
unsigned int hook;
......@@ -493,8 +506,8 @@ mark_source_chains(struct xt_table_info *newinfo,
e->counters.pcnt = pos;
for (;;) {
struct ip6t_standard_target *t
= (void *)ip6t_get_target(e);
const struct ip6t_standard_target *t
= (void *)ip6t_get_target_c(e);
int visited = e->comefrom & (1 << hook);
if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
......@@ -585,13 +598,14 @@ mark_source_chains(struct xt_table_info *newinfo,
}
static int
cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
cleanup_match(struct ip6t_entry_match *m, struct net *net, unsigned int *i)
{
struct xt_mtdtor_param par;
if (i && (*i)-- == 0)
return 1;
par.net = net;
par.match = m->u.kernel.match;
par.matchinfo = m->data;
par.family = NFPROTO_IPV6;
......@@ -602,9 +616,9 @@ cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
}
static int
check_entry(struct ip6t_entry *e, const char *name)
check_entry(const struct ip6t_entry *e, const char *name)
{
struct ip6t_entry_target *t;
const struct ip6t_entry_target *t;
if (!ip6_checkentry(&e->ipv6)) {
duprintf("ip_tables: ip check failed %p %s.\n", e, name);
......@@ -615,7 +629,7 @@ check_entry(struct ip6t_entry *e, const char *name)
e->next_offset)
return -EINVAL;
t = ip6t_get_target(e);
t = ip6t_get_target_c(e);
if (e->target_offset + t->u.target_size > e->next_offset)
return -EINVAL;
......@@ -668,10 +682,11 @@ find_check_match(struct ip6t_entry_match *m, struct xt_mtchk_param *par,
return ret;
}
static int check_target(struct ip6t_entry *e, const char *name)
static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
{
struct ip6t_entry_target *t = ip6t_get_target(e);
struct xt_tgchk_param par = {
.net = net,
.table = name,
.entryinfo = e,
.target = t->u.kernel.target,
......@@ -693,8 +708,8 @@ static int check_target(struct ip6t_entry *e, const char *name)
}
static int
find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
unsigned int *i)
find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
unsigned int size, unsigned int *i)
{
struct ip6t_entry_target *t;
struct xt_target *target;
......@@ -707,6 +722,7 @@ find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
return ret;
j = 0;
mtpar.net = net;
mtpar.table = name;
mtpar.entryinfo = &e->ipv6;
mtpar.hook_mask = e->comefrom;
......@@ -727,7 +743,7 @@ find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
}
t->u.kernel.target = target;
ret = check_target(e, name);
ret = check_target(e, net, name);
if (ret)
goto err;
......@@ -736,18 +752,18 @@ find_check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
err:
module_put(t->u.kernel.target->me);
cleanup_matches:
IP6T_MATCH_ITERATE(e, cleanup_match, &j);
IP6T_MATCH_ITERATE(e, cleanup_match, net, &j);
return ret;
}
static bool check_underflow(struct ip6t_entry *e)
static bool check_underflow(const struct ip6t_entry *e)
{
const struct ip6t_entry_target *t;
unsigned int verdict;
if (!unconditional(&e->ipv6))
return false;
t = ip6t_get_target(e);
t = ip6t_get_target_c(e);
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
return false;
verdict = ((struct ip6t_standard_target *)t)->verdict;
......@@ -758,8 +774,8 @@ static bool check_underflow(struct ip6t_entry *e)
static int
check_entry_size_and_hooks(struct ip6t_entry *e,
struct xt_table_info *newinfo,
unsigned char *base,
unsigned char *limit,
const unsigned char *base,
const unsigned char *limit,
const unsigned int *hook_entries,
const unsigned int *underflows,
unsigned int valid_hooks,
......@@ -806,7 +822,7 @@ check_entry_size_and_hooks(struct ip6t_entry *e,
}
static int
cleanup_entry(struct ip6t_entry *e, unsigned int *i)
cleanup_entry(struct ip6t_entry *e, struct net *net, unsigned int *i)
{
struct xt_tgdtor_param par;
struct ip6t_entry_target *t;
......@@ -815,9 +831,10 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i)
return 1;
/* Cleanup all matches */
IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
IP6T_MATCH_ITERATE(e, cleanup_match, net, NULL);
t = ip6t_get_target(e);
par.net = net;
par.target = t->u.kernel.target;
par.targinfo = t->data;
par.family = NFPROTO_IPV6;
......@@ -830,7 +847,8 @@ cleanup_entry(struct ip6t_entry *e, unsigned int *i)
/* Checks and translates the user-supplied table segment (held in
newinfo) */
static int
translate_table(const char *name,
translate_table(struct net *net,
const char *name,
unsigned int valid_hooks,
struct xt_table_info *newinfo,
void *entry0,
......@@ -892,11 +910,11 @@ translate_table(const char *name,
/* Finally, each sanity check must pass */
i = 0;
ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
find_check_entry, name, size, &i);
find_check_entry, net, name, size, &i);
if (ret != 0) {
IP6T_ENTRY_ITERATE(entry0, newinfo->size,
cleanup_entry, &i);
cleanup_entry, net, &i);
return ret;
}
......@@ -972,11 +990,11 @@ get_counters(const struct xt_table_info *t,
local_bh_enable();
}
static struct xt_counters *alloc_counters(struct xt_table *table)
static struct xt_counters *alloc_counters(const struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
struct xt_table_info *private = table->private;
const struct xt_table_info *private = table->private;
/* We need atomic snapshot of counters: rest doesn't change
(other than comefrom, which userspace doesn't care
......@@ -994,11 +1012,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
static int
copy_entries_to_user(unsigned int total_size,
struct xt_table *table,
const struct xt_table *table,
void __user *userptr)
{
unsigned int off, num;
struct ip6t_entry *e;
const struct ip6t_entry *e;
struct xt_counters *counters;
const struct xt_table_info *private = table->private;
int ret = 0;
......@@ -1050,7 +1068,7 @@ copy_entries_to_user(unsigned int total_size,
}
}
t = ip6t_get_target(e);
t = ip6t_get_target_c(e);
if (copy_to_user(userptr + off + e->target_offset
+ offsetof(struct ip6t_entry_target,
u.user.name),
......@@ -1067,7 +1085,7 @@ copy_entries_to_user(unsigned int total_size,
}
#ifdef CONFIG_COMPAT
static void compat_standard_from_user(void *dst, void *src)
static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
......@@ -1076,7 +1094,7 @@ static void compat_standard_from_user(void *dst, void *src)
memcpy(dst, &v, sizeof(v));
}
static int compat_standard_to_user(void __user *dst, void *src)
static int compat_standard_to_user(void __user *dst, const void *src)
{
compat_int_t cv = *(int *)src;
......@@ -1086,24 +1104,24 @@ static int compat_standard_to_user(void __user *dst, void *src)
}
static inline int
compat_calc_match(struct ip6t_entry_match *m, int *size)
compat_calc_match(const struct ip6t_entry_match *m, int *size)
{
*size += xt_compat_match_offset(m->u.kernel.match);
return 0;
}
static int compat_calc_entry(struct ip6t_entry *e,
static int compat_calc_entry(const struct ip6t_entry *e,
const struct xt_table_info *info,
void *base, struct xt_table_info *newinfo)
const void *base, struct xt_table_info *newinfo)
{
struct ip6t_entry_target *t;
const struct ip6t_entry_target *t;
unsigned int entry_offset;
int off, i, ret;
off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
entry_offset = (void *)e - base;
IP6T_MATCH_ITERATE(e, compat_calc_match, &off);
t = ip6t_get_target(e);
t = ip6t_get_target_c(e);
off += xt_compat_target_offset(t->u.kernel.target);
newinfo->size -= off;
ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
......@@ -1139,7 +1157,8 @@ static int compat_table_info(const struct xt_table_info *info,
}
#endif
static int get_info(struct net *net, void __user *user, int *len, int compat)
static int get_info(struct net *net, void __user *user,
const int *len, int compat)
{
char name[IP6T_TABLE_MAXNAMELEN];
struct xt_table *t;
......@@ -1199,7 +1218,8 @@ static int get_info(struct net *net, void __user *user, int *len, int compat)
}
static int
get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
const int *len)
{
int ret;
struct ip6t_get_entries get;
......@@ -1291,7 +1311,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
/* Decrease module usage counts and free resource */
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
NULL);
net, NULL);
xt_free_table_info(oldinfo);
if (copy_to_user(counters_ptr, counters,
sizeof(struct xt_counters) * num_counters) != 0)
......@@ -1310,7 +1330,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
}
static int
do_replace(struct net *net, void __user *user, unsigned int len)
do_replace(struct net *net, const void __user *user, unsigned int len)
{
int ret;
struct ip6t_replace tmp;
......@@ -1336,7 +1356,7 @@ do_replace(struct net *net, void __user *user, unsigned int len)
goto free_newinfo;
}
ret = translate_table(tmp.name, tmp.valid_hooks,
ret = translate_table(net, tmp.name, tmp.valid_hooks,
newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
tmp.hook_entry, tmp.underflow);
if (ret != 0)
......@@ -1351,7 +1371,7 @@ do_replace(struct net *net, void __user *user, unsigned int len)
return 0;
free_newinfo_untrans:
IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL);
free_newinfo:
xt_free_table_info(newinfo);
return ret;
......@@ -1371,7 +1391,7 @@ add_counter_to_entry(struct ip6t_entry *e,
}
static int
do_add_counters(struct net *net, void __user *user, unsigned int len,
do_add_counters(struct net *net, const void __user *user, unsigned int len,
int compat)
{
unsigned int i, curcpu;
......@@ -1570,10 +1590,10 @@ static int
check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
struct xt_table_info *newinfo,
unsigned int *size,
unsigned char *base,
unsigned char *limit,
unsigned int *hook_entries,
unsigned int *underflows,
const unsigned char *base,
const unsigned char *limit,
const unsigned int *hook_entries,
const unsigned int *underflows,
unsigned int *i,
const char *name)
{
......@@ -1690,14 +1710,15 @@ compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
return ret;
}
static int compat_check_entry(struct ip6t_entry *e, const char *name,
unsigned int *i)
static int compat_check_entry(struct ip6t_entry *e, struct net *net,
const char *name, unsigned int *i)
{
unsigned int j;
int ret;
struct xt_mtchk_param mtpar;
j = 0;
mtpar.net = net;
mtpar.table = name;
mtpar.entryinfo = &e->ipv6;
mtpar.hook_mask = e->comefrom;
......@@ -1706,7 +1727,7 @@ static int compat_check_entry(struct ip6t_entry *e, const char *name,
if (ret)
goto cleanup_matches;
ret = check_target(e, name);
ret = check_target(e, net, name);
if (ret)
goto cleanup_matches;
......@@ -1714,12 +1735,13 @@ static int compat_check_entry(struct ip6t_entry *e, const char *name,
return 0;
cleanup_matches:
IP6T_MATCH_ITERATE(e, cleanup_match, &j);
IP6T_MATCH_ITERATE(e, cleanup_match, net, &j);
return ret;
}
static int
translate_compat_table(const char *name,
translate_compat_table(struct net *net,
const char *name,
unsigned int valid_hooks,
struct xt_table_info **pinfo,
void **pentry0,
......@@ -1808,12 +1830,12 @@ translate_compat_table(const char *name,
i = 0;
ret = IP6T_ENTRY_ITERATE(entry1, newinfo->size, compat_check_entry,
name, &i);
net, name, &i);
if (ret) {
j -= i;
COMPAT_IP6T_ENTRY_ITERATE_CONTINUE(entry0, newinfo->size, i,
compat_release_entry, &j);
IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, &i);
IP6T_ENTRY_ITERATE(entry1, newinfo->size, cleanup_entry, net, &i);
xt_free_table_info(newinfo);
return ret;
}
......@@ -1868,7 +1890,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
goto free_newinfo;
}
ret = translate_compat_table(tmp.name, tmp.valid_hooks,
ret = translate_compat_table(net, tmp.name, tmp.valid_hooks,
&newinfo, &loc_cpu_entry, tmp.size,
tmp.num_entries, tmp.hook_entry,
tmp.underflow);
......@@ -1884,7 +1906,7 @@ compat_do_replace(struct net *net, void __user *user, unsigned int len)
return 0;
free_newinfo_untrans:
IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, NULL);
IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry, net, NULL);
free_newinfo:
xt_free_table_info(newinfo);
return ret;
......@@ -2121,7 +2143,7 @@ struct xt_table *ip6t_register_table(struct net *net,
loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(table->name, table->valid_hooks,
ret = translate_table(net, table->name, table->valid_hooks,
newinfo, loc_cpu_entry, repl->size,
repl->num_entries,
repl->hook_entry,
......@@ -2142,7 +2164,7 @@ struct xt_table *ip6t_register_table(struct net *net,
return ERR_PTR(ret);
}
void ip6t_unregister_table(struct xt_table *table)
void ip6t_unregister_table(struct net *net, struct xt_table *table)
{
struct xt_table_info *private;
void *loc_cpu_entry;
......@@ -2152,7 +2174,7 @@ void ip6t_unregister_table(struct xt_table *table)
/* Decrease module usage counts and free resources */
loc_cpu_entry = private->entries[raw_smp_processor_id()];
IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, NULL);
IP6T_ENTRY_ITERATE(loc_cpu_entry, private->size, cleanup_entry, net, NULL);
if (private->number > private->initial_entries)
module_put(table_owner);
xt_free_table_info(private);
......
......@@ -21,99 +21,26 @@ MODULE_DESCRIPTION("ip6tables filter table");
(1 << NF_INET_FORWARD) | \
(1 << NF_INET_LOCAL_OUT))
static struct
{
struct ip6t_replace repl;
struct ip6t_standard entries[3];
struct ip6t_error term;
} initial_table __net_initdata = {
.repl = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
.hook_entry = {
[NF_INET_LOCAL_IN] = 0,
[NF_INET_FORWARD] = sizeof(struct ip6t_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
},
.underflow = {
[NF_INET_LOCAL_IN] = 0,
[NF_INET_FORWARD] = sizeof(struct ip6t_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
},
},
.entries = {
IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
.term = IP6T_ERROR_INIT, /* ERROR */
};
static const struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.priority = NF_IP6_PRI_FILTER,
};
/* The work comes in here from netfilter.c. */
static unsigned int
ip6t_in_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ip6t_do_table(skb, hook, in, out,
dev_net(in)->ipv6.ip6table_filter);
}
static unsigned int
ip6t_local_out_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
ip6table_filter_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
#if 0
/* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) ||
ip_hdrlen(skb) < sizeof(struct iphdr)) {
if (net_ratelimit())
printk("ip6t_hook: happy cracking.\n");
return NF_ACCEPT;
}
#endif
const struct net *net = dev_net((in != NULL) ? in : out);
return ip6t_do_table(skb, hook, in, out,
dev_net(out)->ipv6.ip6table_filter);
return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_filter);
}
static struct nf_hook_ops ip6t_ops[] __read_mostly = {
{
.hook = ip6t_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP6_PRI_FILTER,
},
{
.hook = ip6t_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP6_PRI_FILTER,
},
{
.hook = ip6t_local_out_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP6_PRI_FILTER,
},
};
static struct nf_hook_ops *filter_ops __read_mostly;
/* Default to forward because I got too much mail already. */
static int forward = NF_ACCEPT;
......@@ -121,9 +48,18 @@ module_param(forward, bool, 0000);
static int __net_init ip6table_filter_net_init(struct net *net)
{
/* Register table */
struct ip6t_replace *repl;
repl = ip6t_alloc_initial_table(&packet_filter);
if (repl == NULL)
return -ENOMEM;
/* Entry 1 is the FORWARD hook */
((struct ip6t_standard *)repl->entries)[1].target.verdict =
-forward - 1;
net->ipv6.ip6table_filter =
ip6t_register_table(net, &packet_filter, &initial_table.repl);
ip6t_register_table(net, &packet_filter, repl);
kfree(repl);
if (IS_ERR(net->ipv6.ip6table_filter))
return PTR_ERR(net->ipv6.ip6table_filter);
return 0;
......@@ -131,7 +67,7 @@ static int __net_init ip6table_filter_net_init(struct net *net)
static void __net_exit ip6table_filter_net_exit(struct net *net)
{
ip6t_unregister_table(net->ipv6.ip6table_filter);
ip6t_unregister_table(net, net->ipv6.ip6table_filter);
}
static struct pernet_operations ip6table_filter_net_ops = {
......@@ -148,17 +84,16 @@ static int __init ip6table_filter_init(void)
return -EINVAL;
}
/* Entry 1 is the FORWARD hook */
initial_table.entries[1].target.verdict = -forward - 1;
ret = register_pernet_subsys(&ip6table_filter_net_ops);
if (ret < 0)
return ret;
/* Register hooks */
ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
if (ret < 0)
filter_ops = xt_hook_link(&packet_filter, ip6table_filter_hook);
if (IS_ERR(filter_ops)) {
ret = PTR_ERR(filter_ops);
goto cleanup_table;
}
return ret;
......@@ -169,7 +104,7 @@ static int __init ip6table_filter_init(void)
static void __exit ip6table_filter_fini(void)
{
nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
xt_hook_unlink(&packet_filter, filter_ops);
unregister_pernet_subsys(&ip6table_filter_net_ops);
}
......
......@@ -21,80 +21,17 @@ MODULE_DESCRIPTION("ip6tables mangle table");
(1 << NF_INET_LOCAL_OUT) | \
(1 << NF_INET_POST_ROUTING))
static const struct
{
struct ip6t_replace repl;
struct ip6t_standard entries[5];
struct ip6t_error term;
} initial_table __net_initdata = {
.repl = {
.name = "mangle",
.valid_hooks = MANGLE_VALID_HOOKS,
.num_entries = 6,
.size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
.hook_entry = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_LOCAL_IN] = sizeof(struct ip6t_standard),
[NF_INET_FORWARD] = sizeof(struct ip6t_standard) * 2,
[NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3,
[NF_INET_POST_ROUTING] = sizeof(struct ip6t_standard) * 4,
},
.underflow = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_LOCAL_IN] = sizeof(struct ip6t_standard),
[NF_INET_FORWARD] = sizeof(struct ip6t_standard) * 2,
[NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3,
[NF_INET_POST_ROUTING] = sizeof(struct ip6t_standard) * 4,
},
},
.entries = {
IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
IP6T_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
},
.term = IP6T_ERROR_INIT, /* ERROR */
};
static const struct xt_table packet_mangler = {
.name = "mangle",
.valid_hooks = MANGLE_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.priority = NF_IP6_PRI_MANGLE,
};
/* The work comes in here from netfilter.c. */
static unsigned int
ip6t_in_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ip6t_do_table(skb, hook, in, out,
dev_net(in)->ipv6.ip6table_mangle);
}
static unsigned int
ip6t_post_routing_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ip6t_do_table(skb, hook, in, out,
dev_net(out)->ipv6.ip6table_mangle);
}
static unsigned int
ip6t_local_out_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
{
unsigned int ret;
struct in6_addr saddr, daddr;
u_int8_t hop_limit;
......@@ -119,7 +56,7 @@ ip6t_local_out_hook(unsigned int hook,
/* flowlabel and prio (includes version, which shouldn't change either */
flowlabel = *((u_int32_t *)ipv6_hdr(skb));
ret = ip6t_do_table(skb, hook, in, out,
ret = ip6t_do_table(skb, NF_INET_LOCAL_OUT, NULL, out,
dev_net(out)->ipv6.ip6table_mangle);
if (ret != NF_DROP && ret != NF_STOLEN &&
......@@ -132,49 +69,33 @@ ip6t_local_out_hook(unsigned int hook,
return ret;
}
static struct nf_hook_ops ip6t_ops[] __read_mostly = {
{
.hook = ip6t_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP6_PRI_MANGLE,
},
{
.hook = ip6t_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP6_PRI_MANGLE,
},
{
.hook = ip6t_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP6_PRI_MANGLE,
},
{
.hook = ip6t_local_out_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP6_PRI_MANGLE,
},
{
.hook = ip6t_post_routing_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP6_PRI_MANGLE,
},
};
/* The work comes in here from netfilter.c. */
static unsigned int
ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
if (hook == NF_INET_LOCAL_OUT)
return ip6t_mangle_out(skb, out);
if (hook == NF_INET_POST_ROUTING)
return ip6t_do_table(skb, hook, in, out,
dev_net(out)->ipv6.ip6table_mangle);
/* INPUT/FORWARD */
return ip6t_do_table(skb, hook, in, out,
dev_net(in)->ipv6.ip6table_mangle);
}
static struct nf_hook_ops *mangle_ops __read_mostly;
static int __net_init ip6table_mangle_net_init(struct net *net)
{
/* Register table */
struct ip6t_replace *repl;
repl = ip6t_alloc_initial_table(&packet_mangler);
if (repl == NULL)
return -ENOMEM;
net->ipv6.ip6table_mangle =
ip6t_register_table(net, &packet_mangler, &initial_table.repl);
ip6t_register_table(net, &packet_mangler, repl);
kfree(repl);
if (IS_ERR(net->ipv6.ip6table_mangle))
return PTR_ERR(net->ipv6.ip6table_mangle);
return 0;
......@@ -182,7 +103,7 @@ static int __net_init ip6table_mangle_net_init(struct net *net)
static void __net_exit ip6table_mangle_net_exit(struct net *net)
{
ip6t_unregister_table(net->ipv6.ip6table_mangle);
ip6t_unregister_table(net, net->ipv6.ip6table_mangle);
}
static struct pernet_operations ip6table_mangle_net_ops = {
......@@ -199,9 +120,11 @@ static int __init ip6table_mangle_init(void)
return ret;
/* Register hooks */
ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
if (ret < 0)
mangle_ops = xt_hook_link(&packet_mangler, ip6table_mangle_hook);
if (IS_ERR(mangle_ops)) {
ret = PTR_ERR(mangle_ops);
goto cleanup_table;
}
return ret;
......@@ -212,7 +135,7 @@ static int __init ip6table_mangle_init(void)
static void __exit ip6table_mangle_fini(void)
{
nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
xt_hook_unlink(&packet_mangler, mangle_ops);
unregister_pernet_subsys(&ip6table_mangle_net_ops);
}
......
......@@ -8,85 +8,37 @@
#define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))
static const struct
{
struct ip6t_replace repl;
struct ip6t_standard entries[2];
struct ip6t_error term;
} initial_table __net_initdata = {
.repl = {
.name = "raw",
.valid_hooks = RAW_VALID_HOOKS,
.num_entries = 3,
.size = sizeof(struct ip6t_standard) * 2 + sizeof(struct ip6t_error),
.hook_entry = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard)
},
.underflow = {
[NF_INET_PRE_ROUTING] = 0,
[NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard)
},
},
.entries = {
IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
.term = IP6T_ERROR_INIT, /* ERROR */
};
static const struct xt_table packet_raw = {
.name = "raw",
.valid_hooks = RAW_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.priority = NF_IP6_PRI_FIRST,
};
/* The work comes in here from netfilter.c. */
static unsigned int
ip6t_pre_routing_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
ip6table_raw_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ip6t_do_table(skb, hook, in, out,
dev_net(in)->ipv6.ip6table_raw);
}
const struct net *net = dev_net((in != NULL) ? in : out);
static unsigned int
ip6t_local_out_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ip6t_do_table(skb, hook, in, out,
dev_net(out)->ipv6.ip6table_raw);
return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_raw);
}
static struct nf_hook_ops ip6t_ops[] __read_mostly = {
{
.hook = ip6t_pre_routing_hook,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP6_PRI_FIRST,
.owner = THIS_MODULE,
},
{
.hook = ip6t_local_out_hook,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP6_PRI_FIRST,
.owner = THIS_MODULE,
},
};
static struct nf_hook_ops *rawtable_ops __read_mostly;
static int __net_init ip6table_raw_net_init(struct net *net)
{
/* Register table */
struct ip6t_replace *repl;
repl = ip6t_alloc_initial_table(&packet_raw);
if (repl == NULL)
return -ENOMEM;
net->ipv6.ip6table_raw =
ip6t_register_table(net, &packet_raw, &initial_table.repl);
ip6t_register_table(net, &packet_raw, repl);
kfree(repl);
if (IS_ERR(net->ipv6.ip6table_raw))
return PTR_ERR(net->ipv6.ip6table_raw);
return 0;
......@@ -94,7 +46,7 @@ static int __net_init ip6table_raw_net_init(struct net *net)
static void __net_exit ip6table_raw_net_exit(struct net *net)
{
ip6t_unregister_table(net->ipv6.ip6table_raw);
ip6t_unregister_table(net, net->ipv6.ip6table_raw);
}
static struct pernet_operations ip6table_raw_net_ops = {
......@@ -111,9 +63,11 @@ static int __init ip6table_raw_init(void)
return ret;
/* Register hooks */
ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
if (ret < 0)
rawtable_ops = xt_hook_link(&packet_raw, ip6table_raw_hook);
if (IS_ERR(rawtable_ops)) {
ret = PTR_ERR(rawtable_ops);
goto cleanup_table;
}
return ret;
......@@ -124,7 +78,7 @@ static int __init ip6table_raw_init(void)
static void __exit ip6table_raw_fini(void)
{
nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
xt_hook_unlink(&packet_raw, rawtable_ops);
unregister_pernet_subsys(&ip6table_raw_net_ops);
}
......
......@@ -26,106 +26,37 @@ MODULE_DESCRIPTION("ip6tables security table, for MAC rules");
(1 << NF_INET_FORWARD) | \
(1 << NF_INET_LOCAL_OUT)
static const struct
{
struct ip6t_replace repl;
struct ip6t_standard entries[3];
struct ip6t_error term;
} initial_table __net_initdata = {
.repl = {
.name = "security",
.valid_hooks = SECURITY_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
.hook_entry = {
[NF_INET_LOCAL_IN] = 0,
[NF_INET_FORWARD] = sizeof(struct ip6t_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2,
},
.underflow = {
[NF_INET_LOCAL_IN] = 0,
[NF_INET_FORWARD] = sizeof(struct ip6t_standard),
[NF_INET_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2,
},
},
.entries = {
IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
.term = IP6T_ERROR_INIT, /* ERROR */
};
static const struct xt_table security_table = {
.name = "security",
.valid_hooks = SECURITY_VALID_HOOKS,
.me = THIS_MODULE,
.af = NFPROTO_IPV6,
.priority = NF_IP6_PRI_SECURITY,
};
static unsigned int
ip6t_local_in_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ip6t_do_table(skb, hook, in, out,
dev_net(in)->ipv6.ip6table_security);
}
static unsigned int
ip6t_forward_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
ip6table_security_hook(unsigned int hook, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return ip6t_do_table(skb, hook, in, out,
dev_net(in)->ipv6.ip6table_security);
}
const struct net *net = dev_net((in != NULL) ? in : out);
static unsigned int
ip6t_local_out_hook(unsigned int hook,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
/* TBD: handle short packets via raw socket */
return ip6t_do_table(skb, hook, in, out,
dev_net(out)->ipv6.ip6table_security);
return ip6t_do_table(skb, hook, in, out, net->ipv6.ip6table_security);
}
static struct nf_hook_ops ip6t_ops[] __read_mostly = {
{
.hook = ip6t_local_in_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_IN,
.priority = NF_IP6_PRI_SECURITY,
},
{
.hook = ip6t_forward_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP6_PRI_SECURITY,
},
{
.hook = ip6t_local_out_hook,
.owner = THIS_MODULE,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP6_PRI_SECURITY,
},
};
static struct nf_hook_ops *sectbl_ops __read_mostly;
static int __net_init ip6table_security_net_init(struct net *net)
{
net->ipv6.ip6table_security =
ip6t_register_table(net, &security_table, &initial_table.repl);
struct ip6t_replace *repl;
repl = ip6t_alloc_initial_table(&security_table);
if (repl == NULL)
return -ENOMEM;
net->ipv6.ip6table_security =
ip6t_register_table(net, &security_table, repl);
kfree(repl);
if (IS_ERR(net->ipv6.ip6table_security))
return PTR_ERR(net->ipv6.ip6table_security);
......@@ -134,7 +65,7 @@ static int __net_init ip6table_security_net_init(struct net *net)
static void __net_exit ip6table_security_net_exit(struct net *net)
{
ip6t_unregister_table(net->ipv6.ip6table_security);
ip6t_unregister_table(net, net->ipv6.ip6table_security);
}
static struct pernet_operations ip6table_security_net_ops = {
......@@ -150,9 +81,11 @@ static int __init ip6table_security_init(void)
if (ret < 0)
return ret;
ret = nf_register_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
if (ret < 0)
sectbl_ops = xt_hook_link(&security_table, ip6table_security_hook);
if (IS_ERR(sectbl_ops)) {
ret = PTR_ERR(sectbl_ops);
goto cleanup_table;
}
return ret;
......@@ -163,7 +96,7 @@ static int __init ip6table_security_init(void)
static void __exit ip6table_security_fini(void)
{
nf_unregister_hooks(ip6t_ops, ARRAY_SIZE(ip6t_ops));
xt_hook_unlink(&security_table, sectbl_ops);
unregister_pernet_subsys(&ip6table_security_net_ops);
}
......
......@@ -27,6 +27,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/nf_conntrack_zones.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
#include <net/netfilter/nf_log.h>
......@@ -191,15 +192,20 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
struct sk_buff *skb)
{
u16 zone = NF_CT_DEFAULT_ZONE;
if (skb->nfct)
zone = nf_ct_zone((struct nf_conn *)skb->nfct);
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge &&
skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
return IP6_DEFRAG_CONNTRACK_BRIDGE_IN;
return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
#endif
if (hooknum == NF_INET_PRE_ROUTING)
return IP6_DEFRAG_CONNTRACK_IN;
return IP6_DEFRAG_CONNTRACK_IN + zone;
else
return IP6_DEFRAG_CONNTRACK_OUT;
return IP6_DEFRAG_CONNTRACK_OUT + zone;
}
......@@ -212,7 +218,7 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
struct sk_buff *reasm;
/* Previously seen (loopback)? */
if (skb->nfct)
if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct))
return NF_ACCEPT;
reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb));
......
......@@ -742,8 +742,8 @@ static inline void ip6_frags_sysctl_unregister(void)
static int __net_init ipv6_frags_init_net(struct net *net)
{
net->ipv6.frags.high_thresh = 256 * 1024;
net->ipv6.frags.low_thresh = 192 * 1024;
net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT;
inet_frags_init_net(&net->ipv6.frags);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册