Commit c75a312d authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://1984.lsi.us.es/net-next

parents b4fb05ea ace30d73
...@@ -10,6 +10,7 @@ header-y += nfnetlink.h ...@@ -10,6 +10,7 @@ header-y += nfnetlink.h
header-y += nfnetlink_acct.h header-y += nfnetlink_acct.h
header-y += nfnetlink_compat.h header-y += nfnetlink_compat.h
header-y += nfnetlink_conntrack.h header-y += nfnetlink_conntrack.h
header-y += nfnetlink_cttimeout.h
header-y += nfnetlink_log.h header-y += nfnetlink_log.h
header-y += nfnetlink_queue.h header-y += nfnetlink_queue.h
header-y += x_tables.h header-y += x_tables.h
...@@ -22,6 +23,7 @@ header-y += xt_CT.h ...@@ -22,6 +23,7 @@ header-y += xt_CT.h
header-y += xt_DSCP.h header-y += xt_DSCP.h
header-y += xt_IDLETIMER.h header-y += xt_IDLETIMER.h
header-y += xt_LED.h header-y += xt_LED.h
header-y += xt_LOG.h
header-y += xt_MARK.h header-y += xt_MARK.h
header-y += xt_nfacct.h header-y += xt_nfacct.h
header-y += xt_NFLOG.h header-y += xt_NFLOG.h
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <linux/types.h>
/* The protocol version */ /* The protocol version */
#define IPSET_PROTOCOL 6 #define IPSET_PROTOCOL 6
...@@ -148,6 +150,7 @@ enum ipset_cmd_flags { ...@@ -148,6 +150,7 @@ enum ipset_cmd_flags {
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME), IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
IPSET_FLAG_BIT_LIST_HEADER = 2, IPSET_FLAG_BIT_LIST_HEADER = 2,
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER), IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
IPSET_FLAG_CMD_MAX = 15, /* Lower half */
}; };
/* Flags at CADT attribute level */ /* Flags at CADT attribute level */
...@@ -156,6 +159,9 @@ enum ipset_cadt_flags { ...@@ -156,6 +159,9 @@ enum ipset_cadt_flags {
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE), IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
IPSET_FLAG_BIT_PHYSDEV = 1, IPSET_FLAG_BIT_PHYSDEV = 1,
IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV), IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
IPSET_FLAG_BIT_NOMATCH = 2,
IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH),
IPSET_FLAG_CADT_MAX = 15, /* Upper half */
}; };
/* Commands with settype-specific attributes */ /* Commands with settype-specific attributes */
...@@ -168,19 +174,10 @@ enum ipset_adt { ...@@ -168,19 +174,10 @@ enum ipset_adt {
IPSET_CADT_MAX, IPSET_CADT_MAX,
}; };
#ifdef __KERNEL__
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/vmalloc.h>
#include <net/netlink.h>
/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t /* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
* and IPSET_INVALID_ID if you want to increase the max number of sets. * and IPSET_INVALID_ID if you want to increase the max number of sets.
*/ */
typedef u16 ip_set_id_t; typedef __u16 ip_set_id_t;
#define IPSET_INVALID_ID 65535 #define IPSET_INVALID_ID 65535
...@@ -203,6 +200,15 @@ enum ip_set_kopt { ...@@ -203,6 +200,15 @@ enum ip_set_kopt {
IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE), IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
}; };
#ifdef __KERNEL__
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/vmalloc.h>
#include <net/netlink.h>
/* Set features */ /* Set features */
enum ip_set_feature { enum ip_set_feature {
IPSET_TYPE_IP_FLAG = 0, IPSET_TYPE_IP_FLAG = 0,
...@@ -288,7 +294,10 @@ struct ip_set_type { ...@@ -288,7 +294,10 @@ struct ip_set_type {
u8 features; u8 features;
/* Set type dimension */ /* Set type dimension */
u8 dimension; u8 dimension;
/* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */ /*
* Supported family: may be NFPROTO_UNSPEC for both
* NFPROTO_IPV4/NFPROTO_IPV6.
*/
u8 family; u8 family;
/* Type revisions */ /* Type revisions */
u8 revision_min, revision_max; u8 revision_min, revision_max;
...@@ -450,6 +459,8 @@ bitmap_bytes(u32 a, u32 b) ...@@ -450,6 +459,8 @@ bitmap_bytes(u32 a, u32 b)
return 4 * ((((b - a + 8) / 8) + 3) / 4); return 4 * ((((b - a + 8) / 8) + 3) / 4);
} }
#endif /* __KERNEL__ */
/* Interface to iptables/ip6tables */ /* Interface to iptables/ip6tables */
#define SO_IP_SET 83 #define SO_IP_SET 83
...@@ -475,6 +486,4 @@ struct ip_set_req_version { ...@@ -475,6 +486,4 @@ struct ip_set_req_version {
unsigned version; unsigned version;
}; };
#endif /* __KERNEL__ */
#endif /*_IP_SET_H */ #endif /*_IP_SET_H */
...@@ -18,7 +18,10 @@ enum tcp_conntrack { ...@@ -18,7 +18,10 @@ enum tcp_conntrack {
TCP_CONNTRACK_LISTEN, /* obsolete */ TCP_CONNTRACK_LISTEN, /* obsolete */
#define TCP_CONNTRACK_SYN_SENT2 TCP_CONNTRACK_LISTEN #define TCP_CONNTRACK_SYN_SENT2 TCP_CONNTRACK_LISTEN
TCP_CONNTRACK_MAX, TCP_CONNTRACK_MAX,
TCP_CONNTRACK_IGNORE TCP_CONNTRACK_IGNORE,
TCP_CONNTRACK_RETRANS,
TCP_CONNTRACK_UNACK,
TCP_CONNTRACK_TIMEOUT_MAX
}; };
/* Window scaling is advertised by the sender */ /* Window scaling is advertised by the sender */
......
...@@ -49,7 +49,8 @@ struct nfgenmsg { ...@@ -49,7 +49,8 @@ struct nfgenmsg {
#define NFNL_SUBSYS_OSF 5 #define NFNL_SUBSYS_OSF 5
#define NFNL_SUBSYS_IPSET 6 #define NFNL_SUBSYS_IPSET 6
#define NFNL_SUBSYS_ACCT 7 #define NFNL_SUBSYS_ACCT 7
#define NFNL_SUBSYS_COUNT 8 #define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8
#define NFNL_SUBSYS_COUNT 9
#ifdef __KERNEL__ #ifdef __KERNEL__
......
...@@ -173,10 +173,21 @@ enum ctattr_expect { ...@@ -173,10 +173,21 @@ enum ctattr_expect {
CTA_EXPECT_HELP_NAME, CTA_EXPECT_HELP_NAME,
CTA_EXPECT_ZONE, CTA_EXPECT_ZONE,
CTA_EXPECT_FLAGS, CTA_EXPECT_FLAGS,
CTA_EXPECT_CLASS,
CTA_EXPECT_NAT,
CTA_EXPECT_FN,
__CTA_EXPECT_MAX __CTA_EXPECT_MAX
}; };
#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1) #define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1)
enum ctattr_expect_nat {
CTA_EXPECT_NAT_UNSPEC,
CTA_EXPECT_NAT_DIR,
CTA_EXPECT_NAT_TUPLE,
__CTA_EXPECT_NAT_MAX
};
#define CTA_EXPECT_NAT_MAX (__CTA_EXPECT_NAT_MAX - 1)
enum ctattr_help { enum ctattr_help {
CTA_HELP_UNSPEC, CTA_HELP_UNSPEC,
CTA_HELP_NAME, CTA_HELP_NAME,
......
#ifndef _CTTIMEOUT_NETLINK_H
#define _CTTIMEOUT_NETLINK_H
#include <linux/netfilter/nfnetlink.h>
enum ctnl_timeout_msg_types {
IPCTNL_MSG_TIMEOUT_NEW,
IPCTNL_MSG_TIMEOUT_GET,
IPCTNL_MSG_TIMEOUT_DELETE,
IPCTNL_MSG_TIMEOUT_MAX
};
enum ctattr_timeout {
CTA_TIMEOUT_UNSPEC,
CTA_TIMEOUT_NAME,
CTA_TIMEOUT_L3PROTO,
CTA_TIMEOUT_L4PROTO,
CTA_TIMEOUT_DATA,
CTA_TIMEOUT_USE,
__CTA_TIMEOUT_MAX
};
#define CTA_TIMEOUT_MAX (__CTA_TIMEOUT_MAX - 1)
enum ctattr_timeout_generic {
CTA_TIMEOUT_GENERIC_UNSPEC,
CTA_TIMEOUT_GENERIC_TIMEOUT,
__CTA_TIMEOUT_GENERIC_MAX
};
#define CTA_TIMEOUT_GENERIC_MAX (__CTA_TIMEOUT_GENERIC_MAX - 1)
enum ctattr_timeout_tcp {
CTA_TIMEOUT_TCP_UNSPEC,
CTA_TIMEOUT_TCP_SYN_SENT,
CTA_TIMEOUT_TCP_SYN_RECV,
CTA_TIMEOUT_TCP_ESTABLISHED,
CTA_TIMEOUT_TCP_FIN_WAIT,
CTA_TIMEOUT_TCP_CLOSE_WAIT,
CTA_TIMEOUT_TCP_LAST_ACK,
CTA_TIMEOUT_TCP_TIME_WAIT,
CTA_TIMEOUT_TCP_CLOSE,
CTA_TIMEOUT_TCP_SYN_SENT2,
CTA_TIMEOUT_TCP_RETRANS,
CTA_TIMEOUT_TCP_UNACK,
__CTA_TIMEOUT_TCP_MAX
};
#define CTA_TIMEOUT_TCP_MAX (__CTA_TIMEOUT_TCP_MAX - 1)
enum ctattr_timeout_udp {
CTA_TIMEOUT_UDP_UNSPEC,
CTA_TIMEOUT_UDP_UNREPLIED,
CTA_TIMEOUT_UDP_REPLIED,
__CTA_TIMEOUT_UDP_MAX
};
#define CTA_TIMEOUT_UDP_MAX (__CTA_TIMEOUT_UDP_MAX - 1)
enum ctattr_timeout_udplite {
CTA_TIMEOUT_UDPLITE_UNSPEC,
CTA_TIMEOUT_UDPLITE_UNREPLIED,
CTA_TIMEOUT_UDPLITE_REPLIED,
__CTA_TIMEOUT_UDPLITE_MAX
};
#define CTA_TIMEOUT_UDPLITE_MAX (__CTA_TIMEOUT_UDPLITE_MAX - 1)
enum ctattr_timeout_icmp {
CTA_TIMEOUT_ICMP_UNSPEC,
CTA_TIMEOUT_ICMP_TIMEOUT,
__CTA_TIMEOUT_ICMP_MAX
};
#define CTA_TIMEOUT_ICMP_MAX (__CTA_TIMEOUT_ICMP_MAX - 1)
enum ctattr_timeout_dccp {
CTA_TIMEOUT_DCCP_UNSPEC,
CTA_TIMEOUT_DCCP_REQUEST,
CTA_TIMEOUT_DCCP_RESPOND,
CTA_TIMEOUT_DCCP_PARTOPEN,
CTA_TIMEOUT_DCCP_OPEN,
CTA_TIMEOUT_DCCP_CLOSEREQ,
CTA_TIMEOUT_DCCP_CLOSING,
CTA_TIMEOUT_DCCP_TIMEWAIT,
__CTA_TIMEOUT_DCCP_MAX
};
#define CTA_TIMEOUT_DCCP_MAX (__CTA_TIMEOUT_DCCP_MAX - 1)
enum ctattr_timeout_sctp {
CTA_TIMEOUT_SCTP_UNSPEC,
CTA_TIMEOUT_SCTP_CLOSED,
CTA_TIMEOUT_SCTP_COOKIE_WAIT,
CTA_TIMEOUT_SCTP_COOKIE_ECHOED,
CTA_TIMEOUT_SCTP_ESTABLISHED,
CTA_TIMEOUT_SCTP_SHUTDOWN_SENT,
CTA_TIMEOUT_SCTP_SHUTDOWN_RECD,
CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT,
__CTA_TIMEOUT_SCTP_MAX
};
#define CTA_TIMEOUT_SCTP_MAX (__CTA_TIMEOUT_SCTP_MAX - 1)
enum ctattr_timeout_icmpv6 {
CTA_TIMEOUT_ICMPV6_UNSPEC,
CTA_TIMEOUT_ICMPV6_TIMEOUT,
__CTA_TIMEOUT_ICMPV6_MAX
};
#define CTA_TIMEOUT_ICMPV6_MAX (__CTA_TIMEOUT_ICMPV6_MAX - 1)
enum ctattr_timeout_gre {
CTA_TIMEOUT_GRE_UNSPEC,
CTA_TIMEOUT_GRE_UNREPLIED,
CTA_TIMEOUT_GRE_REPLIED,
__CTA_TIMEOUT_GRE_MAX
};
#define CTA_TIMEOUT_GRE_MAX (__CTA_TIMEOUT_GRE_MAX - 1)
#define CTNL_TIMEOUT_NAME_MAX 32
#endif
...@@ -16,4 +16,16 @@ struct xt_ct_target_info { ...@@ -16,4 +16,16 @@ struct xt_ct_target_info {
struct nf_conn *ct __attribute__((aligned(8))); struct nf_conn *ct __attribute__((aligned(8)));
}; };
struct xt_ct_target_info_v1 {
__u16 flags;
__u16 zone;
__u32 ct_events;
__u32 exp_events;
char helper[16];
char timeout[32];
/* Used internally by the kernel */
struct nf_conn *ct __attribute__((aligned(8)));
};
#endif /* _XT_CT_H */ #endif /* _XT_CT_H */
#ifndef _XT_LOG_H
#define _XT_LOG_H
/* make sure not to change this without changing nf_log.h:NF_LOG_* (!) */
#define XT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */
#define XT_LOG_TCPOPT 0x02 /* Log TCP options */
#define XT_LOG_IPOPT 0x04 /* Log IP options */
#define XT_LOG_UID 0x08 /* Log UID owning local socket */
#define XT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */
#define XT_LOG_MACDECODE 0x20 /* Decode MAC header */
#define XT_LOG_MASK 0x2f
struct xt_log_info {
unsigned char level;
unsigned char logflags;
char prefix[30];
};
#endif /* _XT_LOG_H */
...@@ -4,11 +4,9 @@ header-y += ipt_CLUSTERIP.h ...@@ -4,11 +4,9 @@ header-y += ipt_CLUSTERIP.h
header-y += ipt_ECN.h header-y += ipt_ECN.h
header-y += ipt_LOG.h header-y += ipt_LOG.h
header-y += ipt_REJECT.h header-y += ipt_REJECT.h
header-y += ipt_SAME.h
header-y += ipt_TTL.h header-y += ipt_TTL.h
header-y += ipt_ULOG.h header-y += ipt_ULOG.h
header-y += ipt_addrtype.h header-y += ipt_addrtype.h
header-y += ipt_ah.h header-y += ipt_ah.h
header-y += ipt_ecn.h header-y += ipt_ecn.h
header-y += ipt_realm.h
header-y += ipt_ttl.h header-y += ipt_ttl.h
#ifndef _IPT_LOG_H #ifndef _IPT_LOG_H
#define _IPT_LOG_H #define _IPT_LOG_H
#warning "Please update iptables, this file will be removed soon!"
/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
#define IPT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ #define IPT_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */
#define IPT_LOG_TCPOPT 0x02 /* Log TCP options */ #define IPT_LOG_TCPOPT 0x02 /* Log TCP options */
......
#ifndef _IPT_SAME_H
#define _IPT_SAME_H
#include <linux/types.h>
#define IPT_SAME_MAX_RANGE 10
#define IPT_SAME_NODST 0x01
struct ipt_same_info {
unsigned char info;
__u32 rangesize;
__u32 ipnum;
__u32 *iparray;
/* hangs off end. */
struct nf_nat_range range[IPT_SAME_MAX_RANGE];
};
#endif /*_IPT_SAME_H*/
#ifndef _IPT_REALM_H
#define _IPT_REALM_H
#include <linux/netfilter/xt_realm.h>
#define ipt_realm_info xt_realm_info
#endif /* _IPT_REALM_H */
#ifndef _IP6T_LOG_H #ifndef _IP6T_LOG_H
#define _IP6T_LOG_H #define _IP6T_LOG_H
#warning "Please update iptables, this file will be removed soon!"
/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */ /* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
#define IP6T_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ #define IP6T_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */
#define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */ #define IP6T_LOG_TCPOPT 0x02 /* Log TCP options */
......
...@@ -19,6 +19,9 @@ enum nf_ct_ext_id { ...@@ -19,6 +19,9 @@ enum nf_ct_ext_id {
#endif #endif
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
NF_CT_EXT_TSTAMP, NF_CT_EXT_TSTAMP,
#endif
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
NF_CT_EXT_TIMEOUT,
#endif #endif
NF_CT_EXT_NUM, NF_CT_EXT_NUM,
}; };
...@@ -29,6 +32,7 @@ enum nf_ct_ext_id { ...@@ -29,6 +32,7 @@ enum nf_ct_ext_id {
#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache #define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache
#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone #define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
#define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp #define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp
#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
/* Extensions: optional stuff which isn't permanently in struct. */ /* Extensions: optional stuff which isn't permanently in struct. */
struct nf_ct_ext { struct nf_ct_ext {
......
...@@ -69,4 +69,17 @@ extern int nf_conntrack_broadcast_help(struct sk_buff *skb, ...@@ -69,4 +69,17 @@ extern int nf_conntrack_broadcast_help(struct sk_buff *skb,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int timeout); unsigned int timeout);
struct nf_ct_helper_expectfn {
struct list_head head;
const char *name;
void (*expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
};
void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n);
void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n);
struct nf_ct_helper_expectfn *
nf_ct_helper_expectfn_find_by_name(const char *name);
struct nf_ct_helper_expectfn *
nf_ct_helper_expectfn_find_by_symbol(const void *symbol);
#endif /*_NF_CONNTRACK_HELPER_H*/ #endif /*_NF_CONNTRACK_HELPER_H*/
...@@ -39,12 +39,13 @@ struct nf_conntrack_l4proto { ...@@ -39,12 +39,13 @@ struct nf_conntrack_l4proto {
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
u_int8_t pf, u_int8_t pf,
unsigned int hooknum); unsigned int hooknum,
unsigned int *timeouts);
/* Called when a new connection for this protocol found; /* Called when a new connection for this protocol found;
* returns TRUE if it's OK. If so, packet() called next. */ * returns TRUE if it's OK. If so, packet() called next. */
bool (*new)(struct nf_conn *ct, const struct sk_buff *skb, bool (*new)(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff); unsigned int dataoff, unsigned int *timeouts);
/* Called when a conntrack entry is destroyed */ /* Called when a conntrack entry is destroyed */
void (*destroy)(struct nf_conn *ct); void (*destroy)(struct nf_conn *ct);
...@@ -60,6 +61,9 @@ struct nf_conntrack_l4proto { ...@@ -60,6 +61,9 @@ struct nf_conntrack_l4proto {
/* Print out the private part of the conntrack. */ /* Print out the private part of the conntrack. */
int (*print_conntrack)(struct seq_file *s, struct nf_conn *); int (*print_conntrack)(struct seq_file *s, struct nf_conn *);
/* Return the array of timeouts for this protocol. */
unsigned int *(*get_timeouts)(struct net *net);
/* convert protoinfo to nfnetink attributes */ /* convert protoinfo to nfnetink attributes */
int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
struct nf_conn *ct); struct nf_conn *ct);
...@@ -79,6 +83,17 @@ struct nf_conntrack_l4proto { ...@@ -79,6 +83,17 @@ struct nf_conntrack_l4proto {
size_t nla_size; size_t nla_size;
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
struct {
size_t obj_size;
int (*nlattr_to_obj)(struct nlattr *tb[], void *data);
int (*obj_to_nlattr)(struct sk_buff *skb, const void *data);
unsigned int nlattr_max;
const struct nla_policy *nla_policy;
} ctnl_timeout;
#endif
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
struct ctl_table_header **ctl_table_header; struct ctl_table_header **ctl_table_header;
struct ctl_table *ctl_table; struct ctl_table *ctl_table;
......
#ifndef _NF_CONNTRACK_TIMEOUT_H
#define _NF_CONNTRACK_TIMEOUT_H
#include <net/net_namespace.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <linux/netfilter/nf_conntrack_tuple_common.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_extend.h>
#define CTNL_TIMEOUT_NAME_MAX 32
struct ctnl_timeout {
struct list_head head;
struct rcu_head rcu_head;
atomic_t refcnt;
char name[CTNL_TIMEOUT_NAME_MAX];
__u16 l3num;
__u8 l4num;
char data[0];
};
struct nf_conn_timeout {
struct ctnl_timeout *timeout;
};
#define NF_CT_TIMEOUT_EXT_DATA(__t) (unsigned int *) &((__t)->timeout->data)
static inline
struct nf_conn_timeout *nf_ct_timeout_find(const struct nf_conn *ct)
{
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
return nf_ct_ext_find(ct, NF_CT_EXT_TIMEOUT);
#else
return NULL;
#endif
}
static inline
struct nf_conn_timeout *nf_ct_timeout_ext_add(struct nf_conn *ct,
struct ctnl_timeout *timeout,
gfp_t gfp)
{
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
struct nf_conn_timeout *timeout_ext;
timeout_ext = nf_ct_ext_add(ct, NF_CT_EXT_TIMEOUT, gfp);
if (timeout_ext == NULL)
return NULL;
timeout_ext->timeout = timeout;
return timeout_ext;
#else
return NULL;
#endif
};
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
extern int nf_conntrack_timeout_init(struct net *net);
extern void nf_conntrack_timeout_fini(struct net *net);
#else
static inline int nf_conntrack_timeout_init(struct net *net)
{
return 0;
}
static inline void nf_conntrack_timeout_fini(struct net *net)
{
return;
}
#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
extern struct ctnl_timeout *(*nf_ct_timeout_find_get_hook)(const char *name);
extern void (*nf_ct_timeout_put_hook)(struct ctnl_timeout *timeout);
#endif
#endif /* _NF_CONNTRACK_TIMEOUT_H */
...@@ -6,7 +6,7 @@ struct sbuff { ...@@ -6,7 +6,7 @@ struct sbuff {
}; };
static struct sbuff emergency, *emergency_ptr = &emergency; static struct sbuff emergency, *emergency_ptr = &emergency;
static int sb_add(struct sbuff *m, const char *f, ...) static __printf(2, 3) int sb_add(struct sbuff *m, const char *f, ...)
{ {
va_list args; va_list args;
int len; int len;
......
...@@ -123,15 +123,6 @@ config IP_NF_TARGET_REJECT ...@@ -123,15 +123,6 @@ config IP_NF_TARGET_REJECT
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
config IP_NF_TARGET_LOG
tristate "LOG target support"
default m if NETFILTER_ADVANCED=n
help
This option adds a `LOG' target, which allows you to create rules in
any iptables table which records the packet header to the syslog.
To compile it as a module, choose M here. If unsure, say N.
config IP_NF_TARGET_ULOG config IP_NF_TARGET_ULOG
tristate "ULOG target support" tristate "ULOG target support"
default m if NETFILTER_ADVANCED=n default m if NETFILTER_ADVANCED=n
......
...@@ -54,7 +54,6 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o ...@@ -54,7 +54,6 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o
# targets # targets
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
......
...@@ -75,25 +75,31 @@ static int icmp_print_tuple(struct seq_file *s, ...@@ -75,25 +75,31 @@ static int icmp_print_tuple(struct seq_file *s,
ntohs(tuple->src.u.icmp.id)); ntohs(tuple->src.u.icmp.id));
} }
static unsigned int *icmp_get_timeouts(struct net *net)
{
return &nf_ct_icmp_timeout;
}
/* Returns verdict for packet, or -1 for invalid. */ /* Returns verdict for packet, or -1 for invalid. */
static int icmp_packet(struct nf_conn *ct, static int icmp_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
u_int8_t pf, u_int8_t pf,
unsigned int hooknum) unsigned int hooknum,
unsigned int *timeout)
{ {
/* Do not immediately delete the connection after the first /* Do not immediately delete the connection after the first
successful reply to avoid excessive conntrackd traffic successful reply to avoid excessive conntrackd traffic
and also to handle correctly ICMP echo reply duplicates. */ and also to handle correctly ICMP echo reply duplicates. */
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
return NF_ACCEPT; return NF_ACCEPT;
} }
/* Called when a new connection for this protocol found. */ /* Called when a new connection for this protocol found. */
static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff) unsigned int dataoff, unsigned int *timeouts)
{ {
static const u_int8_t valid_new[] = { static const u_int8_t valid_new[] = {
[ICMP_ECHO] = 1, [ICMP_ECHO] = 1,
...@@ -263,6 +269,44 @@ static int icmp_nlattr_tuple_size(void) ...@@ -263,6 +269,44 @@ static int icmp_nlattr_tuple_size(void)
} }
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_cttimeout.h>
static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
unsigned int *timeout = data;
if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) {
*timeout =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ;
} else {
/* Set default ICMP timeout. */
*timeout = nf_ct_icmp_timeout;
}
return 0;
}
static int
icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeout = data;
NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ));
return 0;
nla_put_failure:
return -ENOSPC;
}
static const struct nla_policy
icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = {
[CTA_TIMEOUT_ICMP_TIMEOUT] = { .type = NLA_U32 },
};
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static struct ctl_table_header *icmp_sysctl_header; static struct ctl_table_header *icmp_sysctl_header;
static struct ctl_table icmp_sysctl_table[] = { static struct ctl_table icmp_sysctl_table[] = {
...@@ -298,6 +342,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = ...@@ -298,6 +342,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
.invert_tuple = icmp_invert_tuple, .invert_tuple = icmp_invert_tuple,
.print_tuple = icmp_print_tuple, .print_tuple = icmp_print_tuple,
.packet = icmp_packet, .packet = icmp_packet,
.get_timeouts = icmp_get_timeouts,
.new = icmp_new, .new = icmp_new,
.error = icmp_error, .error = icmp_error,
.destroy = NULL, .destroy = NULL,
...@@ -308,6 +353,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly = ...@@ -308,6 +353,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
.nlattr_to_tuple = icmp_nlattr_to_tuple, .nlattr_to_tuple = icmp_nlattr_to_tuple,
.nla_policy = icmp_nla_policy, .nla_policy = icmp_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = icmp_timeout_nlattr_to_obj,
.obj_to_nlattr = icmp_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_ICMP_MAX,
.obj_size = sizeof(unsigned int),
.nla_policy = icmp_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_header = &icmp_sysctl_header, .ctl_table_header = &icmp_sysctl_header,
.ctl_table = icmp_sysctl_table, .ctl_table = icmp_sysctl_table,
......
...@@ -686,6 +686,11 @@ static struct pernet_operations nf_nat_net_ops = { ...@@ -686,6 +686,11 @@ static struct pernet_operations nf_nat_net_ops = {
.exit = nf_nat_net_exit, .exit = nf_nat_net_exit,
}; };
static struct nf_ct_helper_expectfn follow_master_nat = {
.name = "nat-follow-master",
.expectfn = nf_nat_follow_master,
};
static int __init nf_nat_init(void) static int __init nf_nat_init(void)
{ {
size_t i; size_t i;
...@@ -717,6 +722,8 @@ static int __init nf_nat_init(void) ...@@ -717,6 +722,8 @@ static int __init nf_nat_init(void)
l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
nf_ct_helper_expectfn_register(&follow_master_nat);
BUG_ON(nf_nat_seq_adjust_hook != NULL); BUG_ON(nf_nat_seq_adjust_hook != NULL);
RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); RCU_INIT_POINTER(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
...@@ -736,6 +743,7 @@ static void __exit nf_nat_cleanup(void) ...@@ -736,6 +743,7 @@ static void __exit nf_nat_cleanup(void)
unregister_pernet_subsys(&nf_nat_net_ops); unregister_pernet_subsys(&nf_nat_net_ops);
nf_ct_l3proto_put(l3proto); nf_ct_l3proto_put(l3proto);
nf_ct_extend_unregister(&nat_extend); nf_ct_extend_unregister(&nat_extend);
nf_ct_helper_expectfn_unregister(&follow_master_nat);
RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL); RCU_INIT_POINTER(nf_nat_seq_adjust_hook, NULL);
RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL); RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook, NULL);
RCU_INIT_POINTER(nf_ct_nat_offset, NULL); RCU_INIT_POINTER(nf_ct_nat_offset, NULL);
......
...@@ -568,6 +568,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct, ...@@ -568,6 +568,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
return 0; return 0;
} }
static struct nf_ct_helper_expectfn q931_nat = {
.name = "Q.931",
.expectfn = ip_nat_q931_expect,
};
static struct nf_ct_helper_expectfn callforwarding_nat = {
.name = "callforwarding",
.expectfn = ip_nat_callforwarding_expect,
};
/****************************************************************************/ /****************************************************************************/
static int __init init(void) static int __init init(void)
{ {
...@@ -590,6 +600,8 @@ static int __init init(void) ...@@ -590,6 +600,8 @@ static int __init init(void)
RCU_INIT_POINTER(nat_h245_hook, nat_h245); RCU_INIT_POINTER(nat_h245_hook, nat_h245);
RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding); RCU_INIT_POINTER(nat_callforwarding_hook, nat_callforwarding);
RCU_INIT_POINTER(nat_q931_hook, nat_q931); RCU_INIT_POINTER(nat_q931_hook, nat_q931);
nf_ct_helper_expectfn_register(&q931_nat);
nf_ct_helper_expectfn_register(&callforwarding_nat);
return 0; return 0;
} }
...@@ -605,6 +617,8 @@ static void __exit fini(void) ...@@ -605,6 +617,8 @@ static void __exit fini(void)
RCU_INIT_POINTER(nat_h245_hook, NULL); RCU_INIT_POINTER(nat_h245_hook, NULL);
RCU_INIT_POINTER(nat_callforwarding_hook, NULL); RCU_INIT_POINTER(nat_callforwarding_hook, NULL);
RCU_INIT_POINTER(nat_q931_hook, NULL); RCU_INIT_POINTER(nat_q931_hook, NULL);
nf_ct_helper_expectfn_unregister(&q931_nat);
nf_ct_helper_expectfn_unregister(&callforwarding_nat);
synchronize_rcu(); synchronize_rcu();
} }
......
...@@ -526,6 +526,11 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff, ...@@ -526,6 +526,11 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
return NF_DROP; return NF_DROP;
} }
static struct nf_ct_helper_expectfn sip_nat = {
.name = "sip",
.expectfn = ip_nat_sip_expected,
};
static void __exit nf_nat_sip_fini(void) static void __exit nf_nat_sip_fini(void)
{ {
RCU_INIT_POINTER(nf_nat_sip_hook, NULL); RCU_INIT_POINTER(nf_nat_sip_hook, NULL);
...@@ -535,6 +540,7 @@ static void __exit nf_nat_sip_fini(void) ...@@ -535,6 +540,7 @@ static void __exit nf_nat_sip_fini(void)
RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL);
RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL);
RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL);
nf_ct_helper_expectfn_unregister(&sip_nat);
synchronize_rcu(); synchronize_rcu();
} }
...@@ -554,6 +560,7 @@ static int __init nf_nat_sip_init(void) ...@@ -554,6 +560,7 @@ static int __init nf_nat_sip_init(void)
RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port); RCU_INIT_POINTER(nf_nat_sdp_port_hook, ip_nat_sdp_port);
RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session); RCU_INIT_POINTER(nf_nat_sdp_session_hook, ip_nat_sdp_session);
RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media); RCU_INIT_POINTER(nf_nat_sdp_media_hook, ip_nat_sdp_media);
nf_ct_helper_expectfn_register(&sip_nat);
return 0; return 0;
} }
......
...@@ -154,15 +154,6 @@ config IP6_NF_TARGET_HL ...@@ -154,15 +154,6 @@ config IP6_NF_TARGET_HL
(e.g. when running oldconfig). It selects (e.g. when running oldconfig). It selects
CONFIG_NETFILTER_XT_TARGET_HL. CONFIG_NETFILTER_XT_TARGET_HL.
config IP6_NF_TARGET_LOG
tristate "LOG target support"
default m if NETFILTER_ADVANCED=n
help
This option adds a `LOG' target, which allows you to create rules in
any iptables table which records the packet header to the syslog.
To compile it as a module, choose M here. If unsure, say N.
config IP6_NF_FILTER config IP6_NF_FILTER
tristate "Packet filtering" tristate "Packet filtering"
default m if NETFILTER_ADVANCED=n default m if NETFILTER_ADVANCED=n
......
...@@ -31,5 +31,4 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o ...@@ -31,5 +31,4 @@ obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
# targets # targets
obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
This diff is collapsed.
...@@ -88,25 +88,31 @@ static int icmpv6_print_tuple(struct seq_file *s, ...@@ -88,25 +88,31 @@ static int icmpv6_print_tuple(struct seq_file *s,
ntohs(tuple->src.u.icmp.id)); ntohs(tuple->src.u.icmp.id));
} }
static unsigned int *icmpv6_get_timeouts(struct net *net)
{
return &nf_ct_icmpv6_timeout;
}
/* Returns verdict for packet, or -1 for invalid. */ /* Returns verdict for packet, or -1 for invalid. */
static int icmpv6_packet(struct nf_conn *ct, static int icmpv6_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
u_int8_t pf, u_int8_t pf,
unsigned int hooknum) unsigned int hooknum,
unsigned int *timeout)
{ {
/* Do not immediately delete the connection after the first /* Do not immediately delete the connection after the first
successful reply to avoid excessive conntrackd traffic successful reply to avoid excessive conntrackd traffic
and also to handle correctly ICMP echo reply duplicates. */ and also to handle correctly ICMP echo reply duplicates. */
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
return NF_ACCEPT; return NF_ACCEPT;
} }
/* Called when a new connection for this protocol found. */ /* Called when a new connection for this protocol found. */
static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff) unsigned int dataoff, unsigned int *timeouts)
{ {
static const u_int8_t valid_new[] = { static const u_int8_t valid_new[] = {
[ICMPV6_ECHO_REQUEST - 128] = 1, [ICMPV6_ECHO_REQUEST - 128] = 1,
...@@ -270,6 +276,44 @@ static int icmpv6_nlattr_tuple_size(void) ...@@ -270,6 +276,44 @@ static int icmpv6_nlattr_tuple_size(void)
} }
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_cttimeout.h>
static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
unsigned int *timeout = data;
if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) {
*timeout =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ;
} else {
/* Set default ICMPv6 timeout. */
*timeout = nf_ct_icmpv6_timeout;
}
return 0;
}
static int
icmpv6_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeout = data;
NLA_PUT_BE32(skb, CTA_TIMEOUT_ICMPV6_TIMEOUT, htonl(*timeout / HZ));
return 0;
nla_put_failure:
return -ENOSPC;
}
static const struct nla_policy
icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = {
[CTA_TIMEOUT_ICMPV6_TIMEOUT] = { .type = NLA_U32 },
};
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static struct ctl_table_header *icmpv6_sysctl_header; static struct ctl_table_header *icmpv6_sysctl_header;
static struct ctl_table icmpv6_sysctl_table[] = { static struct ctl_table icmpv6_sysctl_table[] = {
...@@ -293,6 +337,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = ...@@ -293,6 +337,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
.invert_tuple = icmpv6_invert_tuple, .invert_tuple = icmpv6_invert_tuple,
.print_tuple = icmpv6_print_tuple, .print_tuple = icmpv6_print_tuple,
.packet = icmpv6_packet, .packet = icmpv6_packet,
.get_timeouts = icmpv6_get_timeouts,
.new = icmpv6_new, .new = icmpv6_new,
.error = icmpv6_error, .error = icmpv6_error,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
...@@ -301,6 +346,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly = ...@@ -301,6 +346,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
.nlattr_to_tuple = icmpv6_nlattr_to_tuple, .nlattr_to_tuple = icmpv6_nlattr_to_tuple,
.nla_policy = icmpv6_nla_policy, .nla_policy = icmpv6_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = icmpv6_timeout_nlattr_to_obj,
.obj_to_nlattr = icmpv6_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_ICMP_MAX,
.obj_size = sizeof(unsigned int),
.nla_policy = icmpv6_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_header = &icmpv6_sysctl_header, .ctl_table_header = &icmpv6_sysctl_header,
.ctl_table = icmpv6_sysctl_table, .ctl_table = icmpv6_sysctl_table,
......
...@@ -103,6 +103,16 @@ config NF_CONNTRACK_EVENTS ...@@ -103,6 +103,16 @@ config NF_CONNTRACK_EVENTS
If unsure, say `N'. If unsure, say `N'.
config NF_CONNTRACK_TIMEOUT
bool 'Connection tracking timeout'
depends on NETFILTER_ADVANCED
help
This option enables support for connection tracking timeout
extension. This allows you to attach timeout policies to flow
via the CT target.
If unsure, say `N'.
config NF_CONNTRACK_TIMESTAMP config NF_CONNTRACK_TIMESTAMP
bool 'Connection tracking timestamping' bool 'Connection tracking timestamping'
depends on NETFILTER_ADVANCED depends on NETFILTER_ADVANCED
...@@ -314,6 +324,17 @@ config NF_CT_NETLINK ...@@ -314,6 +324,17 @@ config NF_CT_NETLINK
help help
This option enables support for a netlink-based userspace interface This option enables support for a netlink-based userspace interface
config NF_CT_NETLINK_TIMEOUT
tristate 'Connection tracking timeout tuning via Netlink'
select NETFILTER_NETLINK
depends on NETFILTER_ADVANCED
help
This option enables support for connection tracking timeout
fine-grain tuning. This allows you to attach specific timeout
policies to flows, instead of using the global timeout policy.
If unsure, say `N'.
endif # NF_CONNTRACK endif # NF_CONNTRACK
# transparent proxy support # transparent proxy support
...@@ -524,6 +545,15 @@ config NETFILTER_XT_TARGET_LED ...@@ -524,6 +545,15 @@ config NETFILTER_XT_TARGET_LED
For more information on the LEDs available on your system, see For more information on the LEDs available on your system, see
Documentation/leds/leds-class.txt Documentation/leds/leds-class.txt
config NETFILTER_XT_TARGET_LOG
tristate "LOG target support"
default m if NETFILTER_ADVANCED=n
help
This option adds a `LOG' target, which allows you to create rules in
any iptables table which records the packet header to the syslog.
To compile it as a module, choose M here. If unsure, say N.
config NETFILTER_XT_TARGET_MARK config NETFILTER_XT_TARGET_MARK
tristate '"MARK" target support' tristate '"MARK" target support'
depends on NETFILTER_ADVANCED depends on NETFILTER_ADVANCED
......
netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o nf_conntrack_acct.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
...@@ -22,6 +23,7 @@ obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o ...@@ -22,6 +23,7 @@ obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o
# netlink interface for nf_conntrack # netlink interface for nf_conntrack
obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
obj-$(CONFIG_NF_CT_NETLINK_TIMEOUT) += nfnetlink_cttimeout.o
# connection tracking helpers # connection tracking helpers
nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o nf_conntrack_h323-objs := nf_conntrack_h323_main.o nf_conntrack_h323_asn1.o
...@@ -58,6 +60,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o ...@@ -58,6 +60,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
......
...@@ -442,7 +442,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, ...@@ -442,7 +442,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
map->timeout = IPSET_NO_TIMEOUT; map->timeout = IPSET_NO_TIMEOUT;
set->data = map; set->data = map;
set->family = AF_INET; set->family = NFPROTO_IPV4;
return true; return true;
} }
...@@ -550,7 +550,7 @@ static struct ip_set_type bitmap_ip_type __read_mostly = { ...@@ -550,7 +550,7 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP, .features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_INET, .family = NFPROTO_IPV4,
.revision_min = 0, .revision_min = 0,
.revision_max = 0, .revision_max = 0,
.create = bitmap_ip_create, .create = bitmap_ip_create,
......
...@@ -543,7 +543,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, ...@@ -543,7 +543,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
map->timeout = IPSET_NO_TIMEOUT; map->timeout = IPSET_NO_TIMEOUT;
set->data = map; set->data = map;
set->family = AF_INET; set->family = NFPROTO_IPV4;
return true; return true;
} }
...@@ -623,7 +623,7 @@ static struct ip_set_type bitmap_ipmac_type = { ...@@ -623,7 +623,7 @@ static struct ip_set_type bitmap_ipmac_type = {
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC, .features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = AF_INET, .family = NFPROTO_IPV4,
.revision_min = 0, .revision_min = 0,
.revision_max = 0, .revision_max = 0,
.create = bitmap_ipmac_create, .create = bitmap_ipmac_create,
......
...@@ -422,7 +422,7 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, ...@@ -422,7 +422,7 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
map->timeout = IPSET_NO_TIMEOUT; map->timeout = IPSET_NO_TIMEOUT;
set->data = map; set->data = map;
set->family = AF_UNSPEC; set->family = NFPROTO_UNSPEC;
return true; return true;
} }
...@@ -483,7 +483,7 @@ static struct ip_set_type bitmap_port_type = { ...@@ -483,7 +483,7 @@ static struct ip_set_type bitmap_port_type = {
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_PORT, .features = IPSET_TYPE_PORT,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = 0,
.revision_max = 0, .revision_max = 0,
.create = bitmap_port_create, .create = bitmap_port_create,
......
...@@ -69,7 +69,7 @@ find_set_type(const char *name, u8 family, u8 revision) ...@@ -69,7 +69,7 @@ find_set_type(const char *name, u8 family, u8 revision)
list_for_each_entry_rcu(type, &ip_set_type_list, list) list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) && if (STREQ(type->name, name) &&
(type->family == family || type->family == AF_UNSPEC) && (type->family == family || type->family == NFPROTO_UNSPEC) &&
revision >= type->revision_min && revision >= type->revision_min &&
revision <= type->revision_max) revision <= type->revision_max)
return type; return type;
...@@ -149,7 +149,7 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max, ...@@ -149,7 +149,7 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max,
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(type, &ip_set_type_list, list) list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) && if (STREQ(type->name, name) &&
(type->family == family || type->family == AF_UNSPEC)) { (type->family == family || type->family == NFPROTO_UNSPEC)) {
found = true; found = true;
if (type->revision_min < *min) if (type->revision_min < *min)
*min = type->revision_min; *min = type->revision_min;
...@@ -164,8 +164,8 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max, ...@@ -164,8 +164,8 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max,
__find_set_type_minmax(name, family, min, max, true); __find_set_type_minmax(name, family, min, max, true);
} }
#define family_name(f) ((f) == AF_INET ? "inet" : \ #define family_name(f) ((f) == NFPROTO_IPV4 ? "inet" : \
(f) == AF_INET6 ? "inet6" : "any") (f) == NFPROTO_IPV6 ? "inet6" : "any")
/* Register a set type structure. The type is identified by /* Register a set type structure. The type is identified by
* the unique triple of name, family and revision. * the unique triple of name, family and revision.
...@@ -354,7 +354,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ...@@ -354,7 +354,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
pr_debug("set %s, index %u\n", set->name, index); pr_debug("set %s, index %u\n", set->name, index);
if (opt->dim < set->type->dimension || if (opt->dim < set->type->dimension ||
!(opt->family == set->family || set->family == AF_UNSPEC)) !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
return 0; return 0;
read_lock_bh(&set->lock); read_lock_bh(&set->lock);
...@@ -387,7 +387,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb, ...@@ -387,7 +387,7 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
pr_debug("set %s, index %u\n", set->name, index); pr_debug("set %s, index %u\n", set->name, index);
if (opt->dim < set->type->dimension || if (opt->dim < set->type->dimension ||
!(opt->family == set->family || set->family == AF_UNSPEC)) !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
return 0; return 0;
write_lock_bh(&set->lock); write_lock_bh(&set->lock);
...@@ -410,7 +410,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb, ...@@ -410,7 +410,7 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
pr_debug("set %s, index %u\n", set->name, index); pr_debug("set %s, index %u\n", set->name, index);
if (opt->dim < set->type->dimension || if (opt->dim < set->type->dimension ||
!(opt->family == set->family || set->family == AF_UNSPEC)) !(opt->family == set->family || set->family == NFPROTO_UNSPEC))
return 0; return 0;
write_lock_bh(&set->lock); write_lock_bh(&set->lock);
...@@ -575,7 +575,7 @@ start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags, ...@@ -575,7 +575,7 @@ start_msg(struct sk_buff *skb, u32 pid, u32 seq, unsigned int flags,
return NULL; return NULL;
nfmsg = nlmsg_data(nlh); nfmsg = nlmsg_data(nlh);
nfmsg->nfgen_family = AF_INET; nfmsg->nfgen_family = NFPROTO_IPV4;
nfmsg->version = NFNETLINK_V0; nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = 0; nfmsg->res_id = 0;
......
...@@ -136,10 +136,10 @@ ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port) ...@@ -136,10 +136,10 @@ ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port)
u8 proto; u8 proto;
switch (pf) { switch (pf) {
case AF_INET: case NFPROTO_IPV4:
ret = ip_set_get_ip4_port(skb, src, port, &proto); ret = ip_set_get_ip4_port(skb, src, port, &proto);
break; break;
case AF_INET6: case NFPROTO_IPV6:
ret = ip_set_get_ip6_port(skb, src, port, &proto); ret = ip_set_get_ip6_port(skb, src, port, &proto);
break; break;
default: default:
......
...@@ -366,11 +366,11 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -366,11 +366,11 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
u8 netmask, hbits; u8 netmask, hbits;
struct ip_set_hash *h; struct ip_set_hash *h;
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
netmask = set->family == AF_INET ? 32 : 128; netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
pr_debug("Create set %s with family %s\n", pr_debug("Create set %s with family %s\n",
set->name, set->family == AF_INET ? "inet" : "inet6"); set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
...@@ -389,8 +389,8 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -389,8 +389,8 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (tb[IPSET_ATTR_NETMASK]) { if (tb[IPSET_ATTR_NETMASK]) {
netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]); netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
if ((set->family == AF_INET && netmask > 32) || if ((set->family == NFPROTO_IPV4 && netmask > 32) ||
(set->family == AF_INET6 && netmask > 128) || (set->family == NFPROTO_IPV6 && netmask > 128) ||
netmask == 0) netmask == 0)
return -IPSET_ERR_INVALID_NETMASK; return -IPSET_ERR_INVALID_NETMASK;
} }
...@@ -419,15 +419,15 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -419,15 +419,15 @@ hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_ip4_tvariant : &hash_ip6_tvariant; ? &hash_ip4_tvariant : &hash_ip6_tvariant;
if (set->family == AF_INET) if (set->family == NFPROTO_IPV4)
hash_ip4_gc_init(set); hash_ip4_gc_init(set);
else else
hash_ip6_gc_init(set); hash_ip6_gc_init(set);
} else { } else {
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_ip4_variant : &hash_ip6_variant; ? &hash_ip4_variant : &hash_ip6_variant;
} }
...@@ -443,7 +443,7 @@ static struct ip_set_type hash_ip_type __read_mostly = { ...@@ -443,7 +443,7 @@ static struct ip_set_type hash_ip_type __read_mostly = {
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP, .features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = 0,
.revision_max = 0, .revision_max = 0,
.create = hash_ip_create, .create = hash_ip_create,
......
...@@ -450,7 +450,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -450,7 +450,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
...@@ -490,15 +490,15 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -490,15 +490,15 @@ hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_ipport4_tvariant : &hash_ipport6_tvariant; ? &hash_ipport4_tvariant : &hash_ipport6_tvariant;
if (set->family == AF_INET) if (set->family == NFPROTO_IPV4)
hash_ipport4_gc_init(set); hash_ipport4_gc_init(set);
else else
hash_ipport6_gc_init(set); hash_ipport6_gc_init(set);
} else { } else {
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_ipport4_variant : &hash_ipport6_variant; ? &hash_ipport4_variant : &hash_ipport6_variant;
} }
...@@ -514,7 +514,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = { ...@@ -514,7 +514,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = AF_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = 0,
.revision_max = 1, /* SCTP and UDPLITE support added */ .revision_max = 1, /* SCTP and UDPLITE support added */
.create = hash_ipport_create, .create = hash_ipport_create,
......
...@@ -468,7 +468,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -468,7 +468,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
...@@ -508,15 +508,15 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -508,15 +508,15 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant; ? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant;
if (set->family == AF_INET) if (set->family == NFPROTO_IPV4)
hash_ipportip4_gc_init(set); hash_ipportip4_gc_init(set);
else else
hash_ipportip6_gc_init(set); hash_ipportip6_gc_init(set);
} else { } else {
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_ipportip4_variant : &hash_ipportip6_variant; ? &hash_ipportip4_variant : &hash_ipportip6_variant;
} }
...@@ -532,7 +532,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { ...@@ -532,7 +532,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
.dimension = IPSET_DIM_THREE, .dimension = IPSET_DIM_THREE,
.family = AF_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = 0,
.revision_max = 1, /* SCTP and UDPLITE support added */ .revision_max = 1, /* SCTP and UDPLITE support added */
.create = hash_ipportip_create, .create = hash_ipportip_create,
......
This diff is collapsed.
...@@ -43,7 +43,7 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b); ...@@ -43,7 +43,7 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b);
struct hash_net4_elem { struct hash_net4_elem {
__be32 ip; __be32 ip;
u16 padding0; u16 padding0;
u8 padding1; u8 nomatch;
u8 cidr; u8 cidr;
}; };
...@@ -51,7 +51,7 @@ struct hash_net4_elem { ...@@ -51,7 +51,7 @@ struct hash_net4_elem {
struct hash_net4_telem { struct hash_net4_telem {
__be32 ip; __be32 ip;
u16 padding0; u16 padding0;
u8 padding1; u8 nomatch;
u8 cidr; u8 cidr;
unsigned long timeout; unsigned long timeout;
}; };
...@@ -61,7 +61,8 @@ hash_net4_data_equal(const struct hash_net4_elem *ip1, ...@@ -61,7 +61,8 @@ hash_net4_data_equal(const struct hash_net4_elem *ip1,
const struct hash_net4_elem *ip2, const struct hash_net4_elem *ip2,
u32 *multi) u32 *multi)
{ {
return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr; return ip1->ip == ip2->ip &&
ip1->cidr == ip2->cidr;
} }
static inline bool static inline bool
...@@ -76,6 +77,19 @@ hash_net4_data_copy(struct hash_net4_elem *dst, ...@@ -76,6 +77,19 @@ hash_net4_data_copy(struct hash_net4_elem *dst,
{ {
dst->ip = src->ip; dst->ip = src->ip;
dst->cidr = src->cidr; dst->cidr = src->cidr;
dst->nomatch = src->nomatch;
}
static inline void
hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags)
{
dst->nomatch = flags & IPSET_FLAG_NOMATCH;
}
static inline bool
hash_net4_data_match(const struct hash_net4_elem *elem)
{
return !elem->nomatch;
} }
static inline void static inline void
...@@ -95,8 +109,12 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem) ...@@ -95,8 +109,12 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem)
static bool static bool
hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data) hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
{ {
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
return 0; return 0;
nla_put_failure: nla_put_failure:
...@@ -108,11 +126,14 @@ hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data) ...@@ -108,11 +126,14 @@ hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
{ {
const struct hash_net4_telem *tdata = const struct hash_net4_telem *tdata =
(const struct hash_net4_telem *)data; (const struct hash_net4_telem *)data;
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout))); htonl(ip_set_timeout_get(tdata->timeout)));
if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
return 0; return 0;
...@@ -167,7 +188,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -167,7 +188,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
...@@ -179,7 +201,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -179,7 +201,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_CIDR]) { if (tb[IPSET_ATTR_CIDR]) {
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr) if (!data.cidr || data.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
} }
...@@ -189,6 +211,12 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -189,6 +211,12 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_NOMATCH)
flags |= (cadt_flags << 16);
}
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
data.ip = htonl(ip & ip_set_hostmask(data.cidr)); data.ip = htonl(ip & ip_set_hostmask(data.cidr));
ret = adtfn(set, &data, timeout, flags); ret = adtfn(set, &data, timeout, flags);
...@@ -236,14 +264,14 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b) ...@@ -236,14 +264,14 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b)
struct hash_net6_elem { struct hash_net6_elem {
union nf_inet_addr ip; union nf_inet_addr ip;
u16 padding0; u16 padding0;
u8 padding1; u8 nomatch;
u8 cidr; u8 cidr;
}; };
struct hash_net6_telem { struct hash_net6_telem {
union nf_inet_addr ip; union nf_inet_addr ip;
u16 padding0; u16 padding0;
u8 padding1; u8 nomatch;
u8 cidr; u8 cidr;
unsigned long timeout; unsigned long timeout;
}; };
...@@ -269,6 +297,19 @@ hash_net6_data_copy(struct hash_net6_elem *dst, ...@@ -269,6 +297,19 @@ hash_net6_data_copy(struct hash_net6_elem *dst,
{ {
dst->ip.in6 = src->ip.in6; dst->ip.in6 = src->ip.in6;
dst->cidr = src->cidr; dst->cidr = src->cidr;
dst->nomatch = src->nomatch;
}
static inline void
hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags)
{
dst->nomatch = flags & IPSET_FLAG_NOMATCH;
}
static inline bool
hash_net6_data_match(const struct hash_net6_elem *elem)
{
return !elem->nomatch;
} }
static inline void static inline void
...@@ -296,8 +337,12 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr) ...@@ -296,8 +337,12 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
static bool static bool
hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data) hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
{ {
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
return 0; return 0;
nla_put_failure: nla_put_failure:
...@@ -309,11 +354,14 @@ hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data) ...@@ -309,11 +354,14 @@ hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
{ {
const struct hash_net6_telem *e = const struct hash_net6_telem *e =
(const struct hash_net6_telem *)data; (const struct hash_net6_telem *)data;
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout))); htonl(ip_set_timeout_get(e->timeout)));
if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
return 0; return 0;
nla_put_failure: nla_put_failure:
...@@ -366,7 +414,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -366,7 +414,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
int ret; int ret;
if (unlikely(!tb[IPSET_ATTR_IP] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(tb[IPSET_ATTR_IP_TO])) if (unlikely(tb[IPSET_ATTR_IP_TO]))
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
...@@ -381,7 +430,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -381,7 +430,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_CIDR]) if (tb[IPSET_ATTR_CIDR])
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr) if (!data.cidr || data.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip6_netmask(&data.ip, data.cidr); ip6_netmask(&data.ip, data.cidr);
...@@ -392,6 +441,12 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -392,6 +441,12 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
} }
if (tb[IPSET_ATTR_CADT_FLAGS] && adt == IPSET_ADD) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_NOMATCH)
flags |= (cadt_flags << 16);
}
ret = adtfn(set, &data, timeout, flags); ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret; return ip_set_eexist(ret, flags) ? 0 : ret;
...@@ -406,7 +461,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -406,7 +461,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
struct ip_set_hash *h; struct ip_set_hash *h;
u8 hbits; u8 hbits;
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
...@@ -425,7 +480,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -425,7 +480,7 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
h = kzalloc(sizeof(*h) h = kzalloc(sizeof(*h)
+ sizeof(struct ip_set_hash_nets) + sizeof(struct ip_set_hash_nets)
* (set->family == AF_INET ? 32 : 128), GFP_KERNEL); * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
if (!h) if (!h)
return -ENOMEM; return -ENOMEM;
...@@ -448,15 +503,15 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -448,15 +503,15 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_net4_tvariant : &hash_net6_tvariant; ? &hash_net4_tvariant : &hash_net6_tvariant;
if (set->family == AF_INET) if (set->family == NFPROTO_IPV4)
hash_net4_gc_init(set); hash_net4_gc_init(set);
else else
hash_net6_gc_init(set); hash_net6_gc_init(set);
} else { } else {
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_net4_variant : &hash_net6_variant; ? &hash_net4_variant : &hash_net6_variant;
} }
...@@ -472,9 +527,10 @@ static struct ip_set_type hash_net_type __read_mostly = { ...@@ -472,9 +527,10 @@ static struct ip_set_type hash_net_type __read_mostly = {
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP, .features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = 0,
.revision_max = 1, /* Range as input support for IPv4 added */ /* = 1 Range as input support for IPv4 added */
.revision_max = 2, /* nomatch flag support added */
.create = hash_net_create, .create = hash_net_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
...@@ -488,6 +544,7 @@ static struct ip_set_type hash_net_type __read_mostly = { ...@@ -488,6 +544,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 }, [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
}, },
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
......
...@@ -163,7 +163,8 @@ struct hash_netiface4_elem_hashed { ...@@ -163,7 +163,8 @@ struct hash_netiface4_elem_hashed {
__be32 ip; __be32 ip;
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u16 padding; u8 nomatch;
u8 padding;
}; };
#define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed) #define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed)
...@@ -173,7 +174,8 @@ struct hash_netiface4_elem { ...@@ -173,7 +174,8 @@ struct hash_netiface4_elem {
__be32 ip; __be32 ip;
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u16 padding; u8 nomatch;
u8 padding;
const char *iface; const char *iface;
}; };
...@@ -182,7 +184,8 @@ struct hash_netiface4_telem { ...@@ -182,7 +184,8 @@ struct hash_netiface4_telem {
__be32 ip; __be32 ip;
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u16 padding; u8 nomatch;
u8 padding;
const char *iface; const char *iface;
unsigned long timeout; unsigned long timeout;
}; };
...@@ -207,11 +210,25 @@ hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem) ...@@ -207,11 +210,25 @@ hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem)
static inline void static inline void
hash_netiface4_data_copy(struct hash_netiface4_elem *dst, hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
const struct hash_netiface4_elem *src) { const struct hash_netiface4_elem *src)
{
dst->ip = src->ip; dst->ip = src->ip;
dst->cidr = src->cidr; dst->cidr = src->cidr;
dst->physdev = src->physdev; dst->physdev = src->physdev;
dst->iface = src->iface; dst->iface = src->iface;
dst->nomatch = src->nomatch;
}
static inline void
hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags)
{
dst->nomatch = flags & IPSET_FLAG_NOMATCH;
}
static inline bool
hash_netiface4_data_match(const struct hash_netiface4_elem *elem)
{
return !elem->nomatch;
} }
static inline void static inline void
...@@ -233,11 +250,13 @@ hash_netiface4_data_list(struct sk_buff *skb, ...@@ -233,11 +250,13 @@ hash_netiface4_data_list(struct sk_buff *skb,
{ {
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
if (data->nomatch)
flags |= IPSET_FLAG_NOMATCH;
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
if (flags) if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
return 0; return 0;
nla_put_failure: nla_put_failure:
...@@ -252,11 +271,13 @@ hash_netiface4_data_tlist(struct sk_buff *skb, ...@@ -252,11 +271,13 @@ hash_netiface4_data_tlist(struct sk_buff *skb,
(const struct hash_netiface4_telem *)data; (const struct hash_netiface4_telem *)data;
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
if (data->nomatch)
flags |= IPSET_FLAG_NOMATCH;
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
if (flags) if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(tdata->timeout))); htonl(ip_set_timeout_get(tdata->timeout)));
...@@ -361,7 +382,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -361,7 +382,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_CIDR]) { if (tb[IPSET_ATTR_CIDR]) {
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr) if (!data.cidr || data.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
} }
...@@ -387,6 +408,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -387,6 +408,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_PHYSDEV) if (cadt_flags & IPSET_FLAG_PHYSDEV)
data.physdev = 1; data.physdev = 1;
if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH))
flags |= (cadt_flags << 16);
} }
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
...@@ -440,7 +463,8 @@ struct hash_netiface6_elem_hashed { ...@@ -440,7 +463,8 @@ struct hash_netiface6_elem_hashed {
union nf_inet_addr ip; union nf_inet_addr ip;
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u16 padding; u8 nomatch;
u8 padding;
}; };
#define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed) #define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed)
...@@ -449,7 +473,8 @@ struct hash_netiface6_elem { ...@@ -449,7 +473,8 @@ struct hash_netiface6_elem {
union nf_inet_addr ip; union nf_inet_addr ip;
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u16 padding; u8 nomatch;
u8 padding;
const char *iface; const char *iface;
}; };
...@@ -457,7 +482,8 @@ struct hash_netiface6_telem { ...@@ -457,7 +482,8 @@ struct hash_netiface6_telem {
union nf_inet_addr ip; union nf_inet_addr ip;
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u16 padding; u8 nomatch;
u8 padding;
const char *iface; const char *iface;
unsigned long timeout; unsigned long timeout;
}; };
...@@ -487,9 +513,22 @@ hash_netiface6_data_copy(struct hash_netiface6_elem *dst, ...@@ -487,9 +513,22 @@ hash_netiface6_data_copy(struct hash_netiface6_elem *dst,
memcpy(dst, src, sizeof(*dst)); memcpy(dst, src, sizeof(*dst));
} }
static inline void
hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags)
{
dst->nomatch = flags & IPSET_FLAG_NOMATCH;
}
static inline bool
hash_netiface6_data_match(const struct hash_netiface6_elem *elem)
{
return !elem->nomatch;
}
static inline void static inline void
hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem) hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
{ {
elem->cidr = 0;
} }
static inline void static inline void
...@@ -514,11 +553,13 @@ hash_netiface6_data_list(struct sk_buff *skb, ...@@ -514,11 +553,13 @@ hash_netiface6_data_list(struct sk_buff *skb,
{ {
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
if (data->nomatch)
flags |= IPSET_FLAG_NOMATCH;
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
if (flags) if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
return 0; return 0;
nla_put_failure: nla_put_failure:
...@@ -533,11 +574,13 @@ hash_netiface6_data_tlist(struct sk_buff *skb, ...@@ -533,11 +574,13 @@ hash_netiface6_data_tlist(struct sk_buff *skb,
(const struct hash_netiface6_telem *)data; (const struct hash_netiface6_telem *)data;
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0; u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
if (data->nomatch)
flags |= IPSET_FLAG_NOMATCH;
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr); NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface); NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
if (flags) if (flags)
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags); NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags));
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(e->timeout))); htonl(ip_set_timeout_get(e->timeout)));
return 0; return 0;
...@@ -636,7 +679,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -636,7 +679,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_CIDR]) if (tb[IPSET_ATTR_CIDR])
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr) if (!data.cidr || data.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip6_netmask(&data.ip, data.cidr); ip6_netmask(&data.ip, data.cidr);
...@@ -662,6 +705,8 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -662,6 +705,8 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_PHYSDEV) if (cadt_flags & IPSET_FLAG_PHYSDEV)
data.physdev = 1; data.physdev = 1;
if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH))
flags |= (cadt_flags << 16);
} }
ret = adtfn(set, &data, timeout, flags); ret = adtfn(set, &data, timeout, flags);
...@@ -678,7 +723,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -678,7 +723,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY; return -IPSET_ERR_INVALID_FAMILY;
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
...@@ -697,7 +742,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -697,7 +742,7 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
h = kzalloc(sizeof(*h) h = kzalloc(sizeof(*h)
+ sizeof(struct ip_set_hash_nets) + sizeof(struct ip_set_hash_nets)
* (set->family == AF_INET ? 32 : 128), GFP_KERNEL); * (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
if (!h) if (!h)
return -ENOMEM; return -ENOMEM;
...@@ -722,15 +767,15 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -722,15 +767,15 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_netiface4_tvariant : &hash_netiface6_tvariant; ? &hash_netiface4_tvariant : &hash_netiface6_tvariant;
if (set->family == AF_INET) if (set->family == NFPROTO_IPV4)
hash_netiface4_gc_init(set); hash_netiface4_gc_init(set);
else else
hash_netiface6_gc_init(set); hash_netiface6_gc_init(set);
} else { } else {
set->variant = set->family == AF_INET set->variant = set->family == NFPROTO_IPV4
? &hash_netiface4_variant : &hash_netiface6_variant; ? &hash_netiface4_variant : &hash_netiface6_variant;
} }
...@@ -746,8 +791,9 @@ static struct ip_set_type hash_netiface_type __read_mostly = { ...@@ -746,8 +791,9 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP | IPSET_TYPE_IFACE, .features = IPSET_TYPE_IP | IPSET_TYPE_IFACE,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = AF_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = 0,
.revision_max = 1, /* nomatch flag support added */
.create = hash_netiface_create, .create = hash_netiface_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
This diff is collapsed.
...@@ -575,7 +575,7 @@ static struct ip_set_type list_set_type __read_mostly = { ...@@ -575,7 +575,7 @@ static struct ip_set_type list_set_type __read_mostly = {
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_NAME | IPSET_DUMP_LAST, .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = 0,
.revision_max = 0, .revision_max = 0,
.create = list_set_create, .create = list_set_create,
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <net/netfilter/nf_conntrack_ecache.h> #include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_conntrack_zones.h> #include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_timestamp.h> #include <net/netfilter/nf_conntrack_timestamp.h>
#include <net/netfilter/nf_conntrack_timeout.h>
#include <net/netfilter/nf_nat.h> #include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h> #include <net/netfilter/nf_nat_core.h>
...@@ -763,7 +764,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, ...@@ -763,7 +764,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l3proto *l3proto,
struct nf_conntrack_l4proto *l4proto, struct nf_conntrack_l4proto *l4proto,
struct sk_buff *skb, struct sk_buff *skb,
unsigned int dataoff, u32 hash) unsigned int dataoff, u32 hash,
unsigned int *timeouts)
{ {
struct nf_conn *ct; struct nf_conn *ct;
struct nf_conn_help *help; struct nf_conn_help *help;
...@@ -782,7 +784,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, ...@@ -782,7 +784,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
if (IS_ERR(ct)) if (IS_ERR(ct))
return (struct nf_conntrack_tuple_hash *)ct; return (struct nf_conntrack_tuple_hash *)ct;
if (!l4proto->new(ct, skb, dataoff)) { if (!l4proto->new(ct, skb, dataoff, timeouts)) {
nf_conntrack_free(ct); nf_conntrack_free(ct);
pr_debug("init conntrack: can't track with proto module\n"); pr_debug("init conntrack: can't track with proto module\n");
return NULL; return NULL;
...@@ -848,7 +850,8 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, ...@@ -848,7 +850,8 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_l3proto *l3proto, struct nf_conntrack_l3proto *l3proto,
struct nf_conntrack_l4proto *l4proto, struct nf_conntrack_l4proto *l4proto,
int *set_reply, int *set_reply,
enum ip_conntrack_info *ctinfo) enum ip_conntrack_info *ctinfo,
unsigned int *timeouts)
{ {
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
...@@ -868,7 +871,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl, ...@@ -868,7 +871,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
h = __nf_conntrack_find_get(net, zone, &tuple, hash); h = __nf_conntrack_find_get(net, zone, &tuple, hash);
if (!h) { if (!h) {
h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto, h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
skb, dataoff, hash); skb, dataoff, hash, timeouts);
if (!h) if (!h)
return NULL; return NULL;
if (IS_ERR(h)) if (IS_ERR(h))
...@@ -909,6 +912,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, ...@@ -909,6 +912,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l3proto *l3proto;
struct nf_conntrack_l4proto *l4proto; struct nf_conntrack_l4proto *l4proto;
struct nf_conn_timeout *timeout_ext;
unsigned int *timeouts;
unsigned int dataoff; unsigned int dataoff;
u_int8_t protonum; u_int8_t protonum;
int set_reply = 0; int set_reply = 0;
...@@ -955,8 +960,19 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, ...@@ -955,8 +960,19 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
goto out; goto out;
} }
/* Decide what timeout policy we want to apply to this flow. */
if (tmpl) {
timeout_ext = nf_ct_timeout_find(tmpl);
if (timeout_ext)
timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext);
else
timeouts = l4proto->get_timeouts(net);
} else
timeouts = l4proto->get_timeouts(net);
ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
l3proto, l4proto, &set_reply, &ctinfo); l3proto, l4proto, &set_reply, &ctinfo,
timeouts);
if (!ct) { if (!ct) {
/* Not valid part of a connection */ /* Not valid part of a connection */
NF_CT_STAT_INC_ATOMIC(net, invalid); NF_CT_STAT_INC_ATOMIC(net, invalid);
...@@ -973,7 +989,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, ...@@ -973,7 +989,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
NF_CT_ASSERT(skb->nfct); NF_CT_ASSERT(skb->nfct);
ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum); ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts);
if (ret <= 0) { if (ret <= 0) {
/* Invalid: inverse of the return code tells /* Invalid: inverse of the return code tells
* the netfilter core what to do */ * the netfilter core what to do */
...@@ -1327,6 +1343,7 @@ static void nf_conntrack_cleanup_net(struct net *net) ...@@ -1327,6 +1343,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
} }
nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
nf_conntrack_timeout_fini(net);
nf_conntrack_ecache_fini(net); nf_conntrack_ecache_fini(net);
nf_conntrack_tstamp_fini(net); nf_conntrack_tstamp_fini(net);
nf_conntrack_acct_fini(net); nf_conntrack_acct_fini(net);
...@@ -1558,9 +1575,14 @@ static int nf_conntrack_init_net(struct net *net) ...@@ -1558,9 +1575,14 @@ static int nf_conntrack_init_net(struct net *net)
ret = nf_conntrack_ecache_init(net); ret = nf_conntrack_ecache_init(net);
if (ret < 0) if (ret < 0)
goto err_ecache; goto err_ecache;
ret = nf_conntrack_timeout_init(net);
if (ret < 0)
goto err_timeout;
return 0; return 0;
err_timeout:
nf_conntrack_timeout_fini(net);
err_ecache: err_ecache:
nf_conntrack_tstamp_fini(net); nf_conntrack_tstamp_fini(net);
err_tstamp: err_tstamp:
......
...@@ -32,9 +32,11 @@ static DEFINE_MUTEX(nf_ct_ecache_mutex); ...@@ -32,9 +32,11 @@ static DEFINE_MUTEX(nf_ct_ecache_mutex);
void nf_ct_deliver_cached_events(struct nf_conn *ct) void nf_ct_deliver_cached_events(struct nf_conn *ct)
{ {
struct net *net = nf_ct_net(ct); struct net *net = nf_ct_net(ct);
unsigned long events; unsigned long events, missed;
struct nf_ct_event_notifier *notify; struct nf_ct_event_notifier *notify;
struct nf_conntrack_ecache *e; struct nf_conntrack_ecache *e;
struct nf_ct_event item;
int ret;
rcu_read_lock(); rcu_read_lock();
notify = rcu_dereference(net->ct.nf_conntrack_event_cb); notify = rcu_dereference(net->ct.nf_conntrack_event_cb);
...@@ -47,31 +49,32 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct) ...@@ -47,31 +49,32 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct)
events = xchg(&e->cache, 0); events = xchg(&e->cache, 0);
if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct) && events) { if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct) || !events)
struct nf_ct_event item = { goto out_unlock;
.ct = ct,
.pid = 0,
.report = 0
};
int ret;
/* We make a copy of the missed event cache without taking /* We make a copy of the missed event cache without taking
* the lock, thus we may send missed events twice. However, * the lock, thus we may send missed events twice. However,
* this does not harm and it happens very rarely. */ * this does not harm and it happens very rarely. */
unsigned long missed = e->missed; missed = e->missed;
if (!((events | missed) & e->ctmask)) if (!((events | missed) & e->ctmask))
goto out_unlock; goto out_unlock;
item.ct = ct;
item.pid = 0;
item.report = 0;
ret = notify->fcn(events | missed, &item); ret = notify->fcn(events | missed, &item);
if (unlikely(ret < 0 || missed)) {
if (likely(ret >= 0 && !missed))
goto out_unlock;
spin_lock_bh(&ct->lock); spin_lock_bh(&ct->lock);
if (ret < 0) if (ret < 0)
e->missed |= events; e->missed |= events;
else else
e->missed &= ~missed; e->missed &= ~missed;
spin_unlock_bh(&ct->lock); spin_unlock_bh(&ct->lock);
}
}
out_unlock: out_unlock:
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -181,6 +181,60 @@ void nf_ct_helper_destroy(struct nf_conn *ct) ...@@ -181,6 +181,60 @@ void nf_ct_helper_destroy(struct nf_conn *ct)
} }
} }
static LIST_HEAD(nf_ct_helper_expectfn_list);
void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n)
{
spin_lock_bh(&nf_conntrack_lock);
list_add_rcu(&n->head, &nf_ct_helper_expectfn_list);
spin_unlock_bh(&nf_conntrack_lock);
}
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_register);
void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n)
{
spin_lock_bh(&nf_conntrack_lock);
list_del_rcu(&n->head);
spin_unlock_bh(&nf_conntrack_lock);
}
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
struct nf_ct_helper_expectfn *
nf_ct_helper_expectfn_find_by_name(const char *name)
{
struct nf_ct_helper_expectfn *cur;
bool found = false;
rcu_read_lock();
list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
if (!strcmp(cur->name, name)) {
found = true;
break;
}
}
rcu_read_unlock();
return found ? cur : NULL;
}
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name);
struct nf_ct_helper_expectfn *
nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
{
struct nf_ct_helper_expectfn *cur;
bool found = false;
rcu_read_lock();
list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
if (cur->expectfn == symbol) {
found = true;
break;
}
}
rcu_read_unlock();
return found ? cur : NULL;
}
EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
int nf_conntrack_helper_register(struct nf_conntrack_helper *me) int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
{ {
unsigned int h = helper_hash(&me->tuple); unsigned int h = helper_hash(&me->tuple);
......
...@@ -110,15 +110,16 @@ ctnetlink_dump_tuples(struct sk_buff *skb, ...@@ -110,15 +110,16 @@ ctnetlink_dump_tuples(struct sk_buff *skb,
struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l3proto *l3proto;
struct nf_conntrack_l4proto *l4proto; struct nf_conntrack_l4proto *l4proto;
rcu_read_lock();
l3proto = __nf_ct_l3proto_find(tuple->src.l3num); l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto);
if (unlikely(ret < 0)) if (ret >= 0) {
return ret; l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
tuple->dst.protonum);
l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto); ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto);
}
rcu_read_unlock();
return ret; return ret;
} }
...@@ -712,9 +713,11 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -712,9 +713,11 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct hlist_nulls_node *n; struct hlist_nulls_node *n;
struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh); struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family; u_int8_t l3proto = nfmsg->nfgen_family;
int res;
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
const struct ctnetlink_dump_filter *filter = cb->data; const struct ctnetlink_dump_filter *filter = cb->data;
#endif #endif
spin_lock_bh(&nf_conntrack_lock); spin_lock_bh(&nf_conntrack_lock);
last = (struct nf_conn *)cb->args[1]; last = (struct nf_conn *)cb->args[1];
for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) { for (; cb->args[0] < net->ct.htable_size; cb->args[0]++) {
...@@ -740,11 +743,14 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -740,11 +743,14 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
continue; continue;
} }
#endif #endif
if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, rcu_read_lock();
res =
ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, cb->nlh->nlmsg_seq,
NFNL_MSG_TYPE( NFNL_MSG_TYPE(cb->nlh->nlmsg_type),
cb->nlh->nlmsg_type), ct);
ct) < 0) { rcu_read_unlock();
if (res < 0) {
nf_conntrack_get(&ct->ct_general); nf_conntrack_get(&ct->ct_general);
cb->args[1] = (unsigned long)ct; cb->args[1] = (unsigned long)ct;
goto out; goto out;
...@@ -1649,14 +1655,16 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb, ...@@ -1649,14 +1655,16 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb,
if (!nest_parms) if (!nest_parms)
goto nla_put_failure; goto nla_put_failure;
rcu_read_lock();
l3proto = __nf_ct_l3proto_find(tuple->src.l3num); l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto); ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);
if (ret >= 0) {
if (unlikely(ret < 0)) l4proto = __nf_ct_l4proto_find(tuple->src.l3num,
goto nla_put_failure; tuple->dst.protonum);
l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto); ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);
}
rcu_read_unlock();
if (unlikely(ret < 0)) if (unlikely(ret < 0))
goto nla_put_failure; goto nla_put_failure;
...@@ -1675,6 +1683,11 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, ...@@ -1675,6 +1683,11 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
struct nf_conn *master = exp->master; struct nf_conn *master = exp->master;
long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ; long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ;
struct nf_conn_help *help; struct nf_conn_help *help;
#ifdef CONFIG_NF_NAT_NEEDED
struct nlattr *nest_parms;
struct nf_conntrack_tuple nat_tuple = {};
#endif
struct nf_ct_helper_expectfn *expfn;
if (timeout < 0) if (timeout < 0)
timeout = 0; timeout = 0;
...@@ -1688,9 +1701,29 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, ...@@ -1688,9 +1701,29 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
CTA_EXPECT_MASTER) < 0) CTA_EXPECT_MASTER) < 0)
goto nla_put_failure; goto nla_put_failure;
#ifdef CONFIG_NF_NAT_NEEDED
if (exp->saved_ip || exp->saved_proto.all) {
nest_parms = nla_nest_start(skb, CTA_EXPECT_NAT | NLA_F_NESTED);
if (!nest_parms)
goto nla_put_failure;
NLA_PUT_BE32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir));
nat_tuple.src.l3num = nf_ct_l3num(master);
nat_tuple.src.u3.ip = exp->saved_ip;
nat_tuple.dst.protonum = nf_ct_protonum(master);
nat_tuple.src.u = exp->saved_proto;
if (ctnetlink_exp_dump_tuple(skb, &nat_tuple,
CTA_EXPECT_NAT_TUPLE) < 0)
goto nla_put_failure;
nla_nest_end(skb, nest_parms);
}
#endif
NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout));
NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp));
NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags)); NLA_PUT_BE32(skb, CTA_EXPECT_FLAGS, htonl(exp->flags));
NLA_PUT_BE32(skb, CTA_EXPECT_CLASS, htonl(exp->class));
help = nfct_help(master); help = nfct_help(master);
if (help) { if (help) {
struct nf_conntrack_helper *helper; struct nf_conntrack_helper *helper;
...@@ -1699,6 +1732,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, ...@@ -1699,6 +1732,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
if (helper) if (helper)
NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name); NLA_PUT_STRING(skb, CTA_EXPECT_HELP_NAME, helper->name);
} }
expfn = nf_ct_helper_expectfn_find_by_symbol(exp->expectfn);
if (expfn != NULL)
NLA_PUT_STRING(skb, CTA_EXPECT_FN, expfn->name);
return 0; return 0;
...@@ -1856,6 +1892,9 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { ...@@ -1856,6 +1892,9 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
[CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING }, [CTA_EXPECT_HELP_NAME] = { .type = NLA_NUL_STRING },
[CTA_EXPECT_ZONE] = { .type = NLA_U16 }, [CTA_EXPECT_ZONE] = { .type = NLA_U16 },
[CTA_EXPECT_FLAGS] = { .type = NLA_U32 }, [CTA_EXPECT_FLAGS] = { .type = NLA_U32 },
[CTA_EXPECT_CLASS] = { .type = NLA_U32 },
[CTA_EXPECT_NAT] = { .type = NLA_NESTED },
[CTA_EXPECT_FN] = { .type = NLA_NUL_STRING },
}; };
static int static int
...@@ -2031,6 +2070,41 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x, ...@@ -2031,6 +2070,41 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static const struct nla_policy exp_nat_nla_policy[CTA_EXPECT_NAT_MAX+1] = {
[CTA_EXPECT_NAT_DIR] = { .type = NLA_U32 },
[CTA_EXPECT_NAT_TUPLE] = { .type = NLA_NESTED },
};
static int
ctnetlink_parse_expect_nat(const struct nlattr *attr,
struct nf_conntrack_expect *exp,
u_int8_t u3)
{
#ifdef CONFIG_NF_NAT_NEEDED
struct nlattr *tb[CTA_EXPECT_NAT_MAX+1];
struct nf_conntrack_tuple nat_tuple = {};
int err;
nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_nla_policy);
if (!tb[CTA_EXPECT_NAT_DIR] || !tb[CTA_EXPECT_NAT_TUPLE])
return -EINVAL;
err = ctnetlink_parse_tuple((const struct nlattr * const *)tb,
&nat_tuple, CTA_EXPECT_NAT_TUPLE, u3);
if (err < 0)
return err;
exp->saved_ip = nat_tuple.src.u3.ip;
exp->saved_proto = nat_tuple.src.u;
exp->dir = ntohl(nla_get_be32(tb[CTA_EXPECT_NAT_DIR]));
return 0;
#else
return -EOPNOTSUPP;
#endif
}
static int static int
ctnetlink_create_expect(struct net *net, u16 zone, ctnetlink_create_expect(struct net *net, u16 zone,
const struct nlattr * const cda[], const struct nlattr * const cda[],
...@@ -2042,6 +2116,8 @@ ctnetlink_create_expect(struct net *net, u16 zone, ...@@ -2042,6 +2116,8 @@ ctnetlink_create_expect(struct net *net, u16 zone,
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
struct nf_conn *ct; struct nf_conn *ct;
struct nf_conn_help *help; struct nf_conn_help *help;
struct nf_conntrack_helper *helper = NULL;
u_int32_t class = 0;
int err = 0; int err = 0;
/* caller guarantees that those three CTA_EXPECT_* exist */ /* caller guarantees that those three CTA_EXPECT_* exist */
...@@ -2060,6 +2136,40 @@ ctnetlink_create_expect(struct net *net, u16 zone, ...@@ -2060,6 +2136,40 @@ ctnetlink_create_expect(struct net *net, u16 zone,
if (!h) if (!h)
return -ENOENT; return -ENOENT;
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
/* Look for helper of this expectation */
if (cda[CTA_EXPECT_HELP_NAME]) {
const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
nf_ct_protonum(ct));
if (helper == NULL) {
#ifdef CONFIG_MODULES
if (request_module("nfct-helper-%s", helpname) < 0) {
err = -EOPNOTSUPP;
goto out;
}
helper = __nf_conntrack_helper_find(helpname,
nf_ct_l3num(ct),
nf_ct_protonum(ct));
if (helper) {
err = -EAGAIN;
goto out;
}
#endif
err = -EOPNOTSUPP;
goto out;
}
}
if (cda[CTA_EXPECT_CLASS] && helper) {
class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
if (class > helper->expect_class_max) {
err = -EINVAL;
goto out;
}
}
exp = nf_ct_expect_alloc(ct); exp = nf_ct_expect_alloc(ct);
if (!exp) { if (!exp) {
err = -ENOMEM; err = -ENOMEM;
...@@ -2086,18 +2196,35 @@ ctnetlink_create_expect(struct net *net, u16 zone, ...@@ -2086,18 +2196,35 @@ ctnetlink_create_expect(struct net *net, u16 zone,
} else } else
exp->flags = 0; exp->flags = 0;
} }
if (cda[CTA_EXPECT_FN]) {
const char *name = nla_data(cda[CTA_EXPECT_FN]);
struct nf_ct_helper_expectfn *expfn;
exp->class = 0; expfn = nf_ct_helper_expectfn_find_by_name(name);
if (expfn == NULL) {
err = -EINVAL;
goto err_out;
}
exp->expectfn = expfn->expectfn;
} else
exp->expectfn = NULL; exp->expectfn = NULL;
exp->class = class;
exp->master = ct; exp->master = ct;
exp->helper = NULL; exp->helper = helper;
memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));
memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3)); memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));
exp->mask.src.u.all = mask.src.u.all; exp->mask.src.u.all = mask.src.u.all;
if (cda[CTA_EXPECT_NAT]) {
err = ctnetlink_parse_expect_nat(cda[CTA_EXPECT_NAT],
exp, u3);
if (err < 0)
goto err_out;
}
err = nf_ct_expect_related_report(exp, pid, report); err = nf_ct_expect_related_report(exp, pid, report);
err_out:
nf_ct_expect_put(exp); nf_ct_expect_put(exp);
out: out:
nf_ct_put(nf_ct_tuplehash_to_ctrack(h)); nf_ct_put(nf_ct_tuplehash_to_ctrack(h));
return err; return err;
......
...@@ -423,7 +423,7 @@ static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv, ...@@ -423,7 +423,7 @@ static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv,
} }
static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff) unsigned int dataoff, unsigned int *timeouts)
{ {
struct net *net = nf_ct_net(ct); struct net *net = nf_ct_net(ct);
struct dccp_net *dn; struct dccp_net *dn;
...@@ -472,12 +472,17 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh) ...@@ -472,12 +472,17 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh)
ntohl(dhack->dccph_ack_nr_low); ntohl(dhack->dccph_ack_nr_low);
} }
static unsigned int *dccp_get_timeouts(struct net *net)
{
return dccp_pernet(net)->dccp_timeout;
}
static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff, enum ip_conntrack_info ctinfo, unsigned int dataoff, enum ip_conntrack_info ctinfo,
u_int8_t pf, unsigned int hooknum) u_int8_t pf, unsigned int hooknum,
unsigned int *timeouts)
{ {
struct net *net = nf_ct_net(ct); struct net *net = nf_ct_net(ct);
struct dccp_net *dn;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
struct dccp_hdr _dh, *dh; struct dccp_hdr _dh, *dh;
u_int8_t type, old_state, new_state; u_int8_t type, old_state, new_state;
...@@ -559,8 +564,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, ...@@ -559,8 +564,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
if (new_state != old_state) if (new_state != old_state)
nf_conntrack_event_cache(IPCT_PROTOINFO, ct); nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
dn = dccp_pernet(net); nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]);
return NF_ACCEPT; return NF_ACCEPT;
} }
...@@ -702,8 +706,60 @@ static int dccp_nlattr_size(void) ...@@ -702,8 +706,60 @@ static int dccp_nlattr_size(void)
return nla_total_size(0) /* CTA_PROTOINFO_DCCP */ return nla_total_size(0) /* CTA_PROTOINFO_DCCP */
+ nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1); + nla_policy_len(dccp_nla_policy, CTA_PROTOINFO_DCCP_MAX + 1);
} }
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_cttimeout.h>
static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
struct dccp_net *dn = dccp_pernet(&init_net);
unsigned int *timeouts = data;
int i;
/* set default DCCP timeouts. */
for (i=0; i<CT_DCCP_MAX; i++)
timeouts[i] = dn->dccp_timeout[i];
/* there's a 1:1 mapping between attributes and protocol states. */
for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++) {
if (tb[i]) {
timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ;
}
}
return 0;
}
static int
dccp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
int i;
for (i=CTA_TIMEOUT_DCCP_UNSPEC+1; i<CTA_TIMEOUT_DCCP_MAX+1; i++)
NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ));
return 0;
nla_put_failure:
return -ENOSPC;
}
static const struct nla_policy
dccp_timeout_nla_policy[CTA_TIMEOUT_DCCP_MAX+1] = {
[CTA_TIMEOUT_DCCP_REQUEST] = { .type = NLA_U32 },
[CTA_TIMEOUT_DCCP_RESPOND] = { .type = NLA_U32 },
[CTA_TIMEOUT_DCCP_PARTOPEN] = { .type = NLA_U32 },
[CTA_TIMEOUT_DCCP_OPEN] = { .type = NLA_U32 },
[CTA_TIMEOUT_DCCP_CLOSEREQ] = { .type = NLA_U32 },
[CTA_TIMEOUT_DCCP_CLOSING] = { .type = NLA_U32 },
[CTA_TIMEOUT_DCCP_TIMEWAIT] = { .type = NLA_U32 },
};
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
/* template, data assigned later */ /* template, data assigned later */
static struct ctl_table dccp_sysctl_table[] = { static struct ctl_table dccp_sysctl_table[] = {
...@@ -767,6 +823,7 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { ...@@ -767,6 +823,7 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
.invert_tuple = dccp_invert_tuple, .invert_tuple = dccp_invert_tuple,
.new = dccp_new, .new = dccp_new,
.packet = dccp_packet, .packet = dccp_packet,
.get_timeouts = dccp_get_timeouts,
.error = dccp_error, .error = dccp_error,
.print_tuple = dccp_print_tuple, .print_tuple = dccp_print_tuple,
.print_conntrack = dccp_print_conntrack, .print_conntrack = dccp_print_conntrack,
...@@ -779,6 +836,15 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { ...@@ -779,6 +836,15 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = dccp_timeout_nlattr_to_obj,
.obj_to_nlattr = dccp_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_DCCP_MAX,
.obj_size = sizeof(unsigned int) * CT_DCCP_MAX,
.nla_policy = dccp_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
}; };
static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
...@@ -789,6 +855,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { ...@@ -789,6 +855,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
.invert_tuple = dccp_invert_tuple, .invert_tuple = dccp_invert_tuple,
.new = dccp_new, .new = dccp_new,
.packet = dccp_packet, .packet = dccp_packet,
.get_timeouts = dccp_get_timeouts,
.error = dccp_error, .error = dccp_error,
.print_tuple = dccp_print_tuple, .print_tuple = dccp_print_tuple,
.print_conntrack = dccp_print_conntrack, .print_conntrack = dccp_print_conntrack,
...@@ -801,6 +868,15 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { ...@@ -801,6 +868,15 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = dccp_timeout_nlattr_to_obj,
.obj_to_nlattr = dccp_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_DCCP_MAX,
.obj_size = sizeof(unsigned int) * CT_DCCP_MAX,
.nla_policy = dccp_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
}; };
static __net_init int dccp_net_init(struct net *net) static __net_init int dccp_net_init(struct net *net)
......
...@@ -40,25 +40,70 @@ static int generic_print_tuple(struct seq_file *s, ...@@ -40,25 +40,70 @@ static int generic_print_tuple(struct seq_file *s,
return 0; return 0;
} }
static unsigned int *generic_get_timeouts(struct net *net)
{
return &nf_ct_generic_timeout;
}
/* Returns verdict for packet, or -1 for invalid. */ /* Returns verdict for packet, or -1 for invalid. */
static int packet(struct nf_conn *ct, static int generic_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
u_int8_t pf, u_int8_t pf,
unsigned int hooknum) unsigned int hooknum,
unsigned int *timeout)
{ {
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_generic_timeout); nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
return NF_ACCEPT; return NF_ACCEPT;
} }
/* Called when a new connection for this protocol found. */ /* Called when a new connection for this protocol found. */
static bool new(struct nf_conn *ct, const struct sk_buff *skb, static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff) unsigned int dataoff, unsigned int *timeouts)
{ {
return true; return true;
} }
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_cttimeout.h>
static int generic_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
unsigned int *timeout = data;
if (tb[CTA_TIMEOUT_GENERIC_TIMEOUT])
*timeout =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_GENERIC_TIMEOUT])) * HZ;
else {
/* Set default generic timeout. */
*timeout = nf_ct_generic_timeout;
}
return 0;
}
static int
generic_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeout = data;
NLA_PUT_BE32(skb, CTA_TIMEOUT_GENERIC_TIMEOUT, htonl(*timeout / HZ));
return 0;
nla_put_failure:
return -ENOSPC;
}
static const struct nla_policy
generic_timeout_nla_policy[CTA_TIMEOUT_GENERIC_MAX+1] = {
[CTA_TIMEOUT_GENERIC_TIMEOUT] = { .type = NLA_U32 },
};
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static struct ctl_table_header *generic_sysctl_header; static struct ctl_table_header *generic_sysctl_header;
static struct ctl_table generic_sysctl_table[] = { static struct ctl_table generic_sysctl_table[] = {
...@@ -93,8 +138,18 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = ...@@ -93,8 +138,18 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
.pkt_to_tuple = generic_pkt_to_tuple, .pkt_to_tuple = generic_pkt_to_tuple,
.invert_tuple = generic_invert_tuple, .invert_tuple = generic_invert_tuple,
.print_tuple = generic_print_tuple, .print_tuple = generic_print_tuple,
.packet = packet, .packet = generic_packet,
.new = new, .get_timeouts = generic_get_timeouts,
.new = generic_new,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = generic_timeout_nlattr_to_obj,
.obj_to_nlattr = generic_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_GENERIC_MAX,
.obj_size = sizeof(unsigned int),
.nla_policy = generic_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_header = &generic_sysctl_header, .ctl_table_header = &generic_sysctl_header,
.ctl_table = generic_sysctl_table, .ctl_table = generic_sysctl_table,
......
...@@ -41,8 +41,16 @@ ...@@ -41,8 +41,16 @@
#include <linux/netfilter/nf_conntrack_proto_gre.h> #include <linux/netfilter/nf_conntrack_proto_gre.h>
#include <linux/netfilter/nf_conntrack_pptp.h> #include <linux/netfilter/nf_conntrack_pptp.h>
#define GRE_TIMEOUT (30 * HZ) enum grep_conntrack {
#define GRE_STREAM_TIMEOUT (180 * HZ) GRE_CT_UNREPLIED,
GRE_CT_REPLIED,
GRE_CT_MAX
};
static unsigned int gre_timeouts[GRE_CT_MAX] = {
[GRE_CT_UNREPLIED] = 30*HZ,
[GRE_CT_REPLIED] = 180*HZ,
};
static int proto_gre_net_id __read_mostly; static int proto_gre_net_id __read_mostly;
struct netns_proto_gre { struct netns_proto_gre {
...@@ -227,13 +235,19 @@ static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct) ...@@ -227,13 +235,19 @@ static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct)
(ct->proto.gre.stream_timeout / HZ)); (ct->proto.gre.stream_timeout / HZ));
} }
static unsigned int *gre_get_timeouts(struct net *net)
{
return gre_timeouts;
}
/* Returns verdict for packet, and may modify conntrack */ /* Returns verdict for packet, and may modify conntrack */
static int gre_packet(struct nf_conn *ct, static int gre_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
u_int8_t pf, u_int8_t pf,
unsigned int hooknum) unsigned int hooknum,
unsigned int *timeouts)
{ {
/* If we've seen traffic both ways, this is a GRE connection. /* If we've seen traffic both ways, this is a GRE connection.
* Extend timeout. */ * Extend timeout. */
...@@ -252,15 +266,15 @@ static int gre_packet(struct nf_conn *ct, ...@@ -252,15 +266,15 @@ static int gre_packet(struct nf_conn *ct,
/* Called when a new connection for this protocol found. */ /* Called when a new connection for this protocol found. */
static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb, static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff) unsigned int dataoff, unsigned int *timeouts)
{ {
pr_debug(": "); pr_debug(": ");
nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
/* initialize to sane value. Ideally a conntrack helper /* initialize to sane value. Ideally a conntrack helper
* (e.g. in case of pptp) is increasing them */ * (e.g. in case of pptp) is increasing them */
ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; ct->proto.gre.stream_timeout = timeouts[GRE_CT_REPLIED];
ct->proto.gre.timeout = GRE_TIMEOUT; ct->proto.gre.timeout = timeouts[GRE_CT_UNREPLIED];
return true; return true;
} }
...@@ -278,6 +292,52 @@ static void gre_destroy(struct nf_conn *ct) ...@@ -278,6 +292,52 @@ static void gre_destroy(struct nf_conn *ct)
nf_ct_gre_keymap_destroy(master); nf_ct_gre_keymap_destroy(master);
} }
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_cttimeout.h>
static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
unsigned int *timeouts = data;
/* set default timeouts for GRE. */
timeouts[GRE_CT_UNREPLIED] = gre_timeouts[GRE_CT_UNREPLIED];
timeouts[GRE_CT_REPLIED] = gre_timeouts[GRE_CT_REPLIED];
if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) {
timeouts[GRE_CT_UNREPLIED] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_UNREPLIED])) * HZ;
}
if (tb[CTA_TIMEOUT_GRE_REPLIED]) {
timeouts[GRE_CT_REPLIED] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_GRE_REPLIED])) * HZ;
}
return 0;
}
static int
gre_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_UNREPLIED,
htonl(timeouts[GRE_CT_UNREPLIED] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_GRE_REPLIED,
htonl(timeouts[GRE_CT_REPLIED] / HZ));
return 0;
nla_put_failure:
return -ENOSPC;
}
static const struct nla_policy
gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = {
[CTA_TIMEOUT_GRE_UNREPLIED] = { .type = NLA_U32 },
[CTA_TIMEOUT_GRE_REPLIED] = { .type = NLA_U32 },
};
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
/* protocol helper struct */ /* protocol helper struct */
static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
.l3proto = AF_INET, .l3proto = AF_INET,
...@@ -287,6 +347,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { ...@@ -287,6 +347,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
.invert_tuple = gre_invert_tuple, .invert_tuple = gre_invert_tuple,
.print_tuple = gre_print_tuple, .print_tuple = gre_print_tuple,
.print_conntrack = gre_print_conntrack, .print_conntrack = gre_print_conntrack,
.get_timeouts = gre_get_timeouts,
.packet = gre_packet, .packet = gre_packet,
.new = gre_new, .new = gre_new,
.destroy = gre_destroy, .destroy = gre_destroy,
...@@ -297,6 +358,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { ...@@ -297,6 +358,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = gre_timeout_nlattr_to_obj,
.obj_to_nlattr = gre_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_GRE_MAX,
.obj_size = sizeof(unsigned int) * GRE_CT_MAX,
.nla_policy = gre_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
}; };
static int proto_gre_net_init(struct net *net) static int proto_gre_net_init(struct net *net)
......
...@@ -279,13 +279,19 @@ static int sctp_new_state(enum ip_conntrack_dir dir, ...@@ -279,13 +279,19 @@ static int sctp_new_state(enum ip_conntrack_dir dir,
return sctp_conntracks[dir][i][cur_state]; return sctp_conntracks[dir][i][cur_state];
} }
static unsigned int *sctp_get_timeouts(struct net *net)
{
return sctp_timeouts;
}
/* Returns verdict for packet, or -NF_ACCEPT for invalid. */ /* Returns verdict for packet, or -NF_ACCEPT for invalid. */
static int sctp_packet(struct nf_conn *ct, static int sctp_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
u_int8_t pf, u_int8_t pf,
unsigned int hooknum) unsigned int hooknum,
unsigned int *timeouts)
{ {
enum sctp_conntrack new_state, old_state; enum sctp_conntrack new_state, old_state;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
...@@ -370,7 +376,7 @@ static int sctp_packet(struct nf_conn *ct, ...@@ -370,7 +376,7 @@ static int sctp_packet(struct nf_conn *ct,
} }
spin_unlock_bh(&ct->lock); spin_unlock_bh(&ct->lock);
nf_ct_refresh_acct(ct, ctinfo, skb, sctp_timeouts[new_state]); nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);
if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED && if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED &&
dir == IP_CT_DIR_REPLY && dir == IP_CT_DIR_REPLY &&
...@@ -390,7 +396,7 @@ static int sctp_packet(struct nf_conn *ct, ...@@ -390,7 +396,7 @@ static int sctp_packet(struct nf_conn *ct,
/* Called when a new connection for this protocol found. */ /* Called when a new connection for this protocol found. */
static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff) unsigned int dataoff, unsigned int *timeouts)
{ {
enum sctp_conntrack new_state; enum sctp_conntrack new_state;
const struct sctphdr *sh; const struct sctphdr *sh;
...@@ -543,6 +549,57 @@ static int sctp_nlattr_size(void) ...@@ -543,6 +549,57 @@ static int sctp_nlattr_size(void)
} }
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_cttimeout.h>
static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
unsigned int *timeouts = data;
int i;
/* set default SCTP timeouts. */
for (i=0; i<SCTP_CONNTRACK_MAX; i++)
timeouts[i] = sctp_timeouts[i];
/* there's a 1:1 mapping between attributes and protocol states. */
for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) {
if (tb[i]) {
timeouts[i] = ntohl(nla_get_be32(tb[i])) * HZ;
}
}
return 0;
}
static int
sctp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
int i;
for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++)
NLA_PUT_BE32(skb, i, htonl(timeouts[i] / HZ));
return 0;
nla_put_failure:
return -ENOSPC;
}
static const struct nla_policy
sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = {
[CTA_TIMEOUT_SCTP_CLOSED] = { .type = NLA_U32 },
[CTA_TIMEOUT_SCTP_COOKIE_WAIT] = { .type = NLA_U32 },
[CTA_TIMEOUT_SCTP_COOKIE_ECHOED] = { .type = NLA_U32 },
[CTA_TIMEOUT_SCTP_ESTABLISHED] = { .type = NLA_U32 },
[CTA_TIMEOUT_SCTP_SHUTDOWN_SENT] = { .type = NLA_U32 },
[CTA_TIMEOUT_SCTP_SHUTDOWN_RECD] = { .type = NLA_U32 },
[CTA_TIMEOUT_SCTP_SHUTDOWN_ACK_SENT] = { .type = NLA_U32 },
};
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static unsigned int sctp_sysctl_table_users; static unsigned int sctp_sysctl_table_users;
static struct ctl_table_header *sctp_sysctl_header; static struct ctl_table_header *sctp_sysctl_header;
...@@ -664,6 +721,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { ...@@ -664,6 +721,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
.print_tuple = sctp_print_tuple, .print_tuple = sctp_print_tuple,
.print_conntrack = sctp_print_conntrack, .print_conntrack = sctp_print_conntrack,
.packet = sctp_packet, .packet = sctp_packet,
.get_timeouts = sctp_get_timeouts,
.new = sctp_new, .new = sctp_new,
.me = THIS_MODULE, .me = THIS_MODULE,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
...@@ -675,6 +733,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = { ...@@ -675,6 +733,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = sctp_timeout_nlattr_to_obj,
.obj_to_nlattr = sctp_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_SCTP_MAX,
.obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX,
.nla_policy = sctp_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_users = &sctp_sysctl_table_users, .ctl_table_users = &sctp_sysctl_table_users,
.ctl_table_header = &sctp_sysctl_header, .ctl_table_header = &sctp_sysctl_header,
...@@ -694,6 +761,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { ...@@ -694,6 +761,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
.print_tuple = sctp_print_tuple, .print_tuple = sctp_print_tuple,
.print_conntrack = sctp_print_conntrack, .print_conntrack = sctp_print_conntrack,
.packet = sctp_packet, .packet = sctp_packet,
.get_timeouts = sctp_get_timeouts,
.new = sctp_new, .new = sctp_new,
.me = THIS_MODULE, .me = THIS_MODULE,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
...@@ -704,6 +772,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = { ...@@ -704,6 +772,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = sctp_timeout_nlattr_to_obj,
.obj_to_nlattr = sctp_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_SCTP_MAX,
.obj_size = sizeof(unsigned int) * SCTP_CONNTRACK_MAX,
.nla_policy = sctp_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#endif #endif
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_users = &sctp_sysctl_table_users, .ctl_table_users = &sctp_sysctl_table_users,
......
...@@ -64,13 +64,7 @@ static const char *const tcp_conntrack_names[] = { ...@@ -64,13 +64,7 @@ static const char *const tcp_conntrack_names[] = {
#define HOURS * 60 MINS #define HOURS * 60 MINS
#define DAYS * 24 HOURS #define DAYS * 24 HOURS
/* RFC1122 says the R2 limit should be at least 100 seconds. static unsigned int tcp_timeouts[TCP_CONNTRACK_TIMEOUT_MAX] __read_mostly = {
Linux uses 15 packets as limit, which corresponds
to ~13-30min depending on RTO. */
static unsigned int nf_ct_tcp_timeout_max_retrans __read_mostly = 5 MINS;
static unsigned int nf_ct_tcp_timeout_unacknowledged __read_mostly = 5 MINS;
static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = {
[TCP_CONNTRACK_SYN_SENT] = 2 MINS, [TCP_CONNTRACK_SYN_SENT] = 2 MINS,
[TCP_CONNTRACK_SYN_RECV] = 60 SECS, [TCP_CONNTRACK_SYN_RECV] = 60 SECS,
[TCP_CONNTRACK_ESTABLISHED] = 5 DAYS, [TCP_CONNTRACK_ESTABLISHED] = 5 DAYS,
...@@ -80,6 +74,11 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = { ...@@ -80,6 +74,11 @@ static unsigned int tcp_timeouts[TCP_CONNTRACK_MAX] __read_mostly = {
[TCP_CONNTRACK_TIME_WAIT] = 2 MINS, [TCP_CONNTRACK_TIME_WAIT] = 2 MINS,
[TCP_CONNTRACK_CLOSE] = 10 SECS, [TCP_CONNTRACK_CLOSE] = 10 SECS,
[TCP_CONNTRACK_SYN_SENT2] = 2 MINS, [TCP_CONNTRACK_SYN_SENT2] = 2 MINS,
/* RFC1122 says the R2 limit should be at least 100 seconds.
Linux uses 15 packets as limit, which corresponds
to ~13-30min depending on RTO. */
[TCP_CONNTRACK_RETRANS] = 5 MINS,
[TCP_CONNTRACK_UNACK] = 5 MINS,
}; };
#define sNO TCP_CONNTRACK_NONE #define sNO TCP_CONNTRACK_NONE
...@@ -814,13 +813,19 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl, ...@@ -814,13 +813,19 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
return NF_ACCEPT; return NF_ACCEPT;
} }
static unsigned int *tcp_get_timeouts(struct net *net)
{
return tcp_timeouts;
}
/* Returns verdict for packet, or -1 for invalid. */ /* Returns verdict for packet, or -1 for invalid. */
static int tcp_packet(struct nf_conn *ct, static int tcp_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
u_int8_t pf, u_int8_t pf,
unsigned int hooknum) unsigned int hooknum,
unsigned int *timeouts)
{ {
struct net *net = nf_ct_net(ct); struct net *net = nf_ct_net(ct);
struct nf_conntrack_tuple *tuple; struct nf_conntrack_tuple *tuple;
...@@ -1015,14 +1020,14 @@ static int tcp_packet(struct nf_conn *ct, ...@@ -1015,14 +1020,14 @@ static int tcp_packet(struct nf_conn *ct,
ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans && if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans &&
tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans) timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS])
timeout = nf_ct_tcp_timeout_max_retrans; timeout = timeouts[TCP_CONNTRACK_RETRANS];
else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) & else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) &
IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED && IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED &&
tcp_timeouts[new_state] > nf_ct_tcp_timeout_unacknowledged) timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK])
timeout = nf_ct_tcp_timeout_unacknowledged; timeout = timeouts[TCP_CONNTRACK_UNACK];
else else
timeout = tcp_timeouts[new_state]; timeout = timeouts[new_state];
spin_unlock_bh(&ct->lock); spin_unlock_bh(&ct->lock);
if (new_state != old_state) if (new_state != old_state)
...@@ -1054,7 +1059,7 @@ static int tcp_packet(struct nf_conn *ct, ...@@ -1054,7 +1059,7 @@ static int tcp_packet(struct nf_conn *ct,
/* Called when a new connection for this protocol found. */ /* Called when a new connection for this protocol found. */
static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff) unsigned int dataoff, unsigned int *timeouts)
{ {
enum tcp_conntrack new_state; enum tcp_conntrack new_state;
const struct tcphdr *th; const struct tcphdr *th;
...@@ -1239,6 +1244,113 @@ static int tcp_nlattr_tuple_size(void) ...@@ -1239,6 +1244,113 @@ static int tcp_nlattr_tuple_size(void)
} }
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_cttimeout.h>
static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
unsigned int *timeouts = data;
int i;
/* set default TCP timeouts. */
for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++)
timeouts[i] = tcp_timeouts[i];
if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) {
timeouts[TCP_CONNTRACK_SYN_SENT] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_SYN_RECV]) {
timeouts[TCP_CONNTRACK_SYN_RECV] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_RECV]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_ESTABLISHED]) {
timeouts[TCP_CONNTRACK_ESTABLISHED] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_ESTABLISHED]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_FIN_WAIT]) {
timeouts[TCP_CONNTRACK_FIN_WAIT] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_FIN_WAIT]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]) {
timeouts[TCP_CONNTRACK_CLOSE_WAIT] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE_WAIT]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_LAST_ACK]) {
timeouts[TCP_CONNTRACK_LAST_ACK] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_LAST_ACK]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_TIME_WAIT]) {
timeouts[TCP_CONNTRACK_TIME_WAIT] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_TIME_WAIT]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_CLOSE]) {
timeouts[TCP_CONNTRACK_CLOSE] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_CLOSE]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_SYN_SENT2]) {
timeouts[TCP_CONNTRACK_SYN_SENT2] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_SYN_SENT2]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_RETRANS]) {
timeouts[TCP_CONNTRACK_RETRANS] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_RETRANS]))*HZ;
}
if (tb[CTA_TIMEOUT_TCP_UNACK]) {
timeouts[TCP_CONNTRACK_UNACK] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_TCP_UNACK]))*HZ;
}
return 0;
}
static int
tcp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT,
htonl(timeouts[TCP_CONNTRACK_SYN_SENT] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_RECV,
htonl(timeouts[TCP_CONNTRACK_SYN_RECV] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_ESTABLISHED,
htonl(timeouts[TCP_CONNTRACK_ESTABLISHED] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_FIN_WAIT,
htonl(timeouts[TCP_CONNTRACK_FIN_WAIT] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE_WAIT,
htonl(timeouts[TCP_CONNTRACK_CLOSE_WAIT] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_LAST_ACK,
htonl(timeouts[TCP_CONNTRACK_LAST_ACK] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_TIME_WAIT,
htonl(timeouts[TCP_CONNTRACK_TIME_WAIT] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_CLOSE,
htonl(timeouts[TCP_CONNTRACK_CLOSE] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_SYN_SENT2,
htonl(timeouts[TCP_CONNTRACK_SYN_SENT2] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_RETRANS,
htonl(timeouts[TCP_CONNTRACK_RETRANS] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_TCP_UNACK,
htonl(timeouts[TCP_CONNTRACK_UNACK] / HZ));
return 0;
nla_put_failure:
return -ENOSPC;
}
static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = {
[CTA_TIMEOUT_TCP_SYN_SENT] = { .type = NLA_U32 },
[CTA_TIMEOUT_TCP_SYN_RECV] = { .type = NLA_U32 },
[CTA_TIMEOUT_TCP_ESTABLISHED] = { .type = NLA_U32 },
[CTA_TIMEOUT_TCP_FIN_WAIT] = { .type = NLA_U32 },
[CTA_TIMEOUT_TCP_CLOSE_WAIT] = { .type = NLA_U32 },
[CTA_TIMEOUT_TCP_LAST_ACK] = { .type = NLA_U32 },
[CTA_TIMEOUT_TCP_TIME_WAIT] = { .type = NLA_U32 },
[CTA_TIMEOUT_TCP_CLOSE] = { .type = NLA_U32 },
[CTA_TIMEOUT_TCP_SYN_SENT2] = { .type = NLA_U32 },
};
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static unsigned int tcp_sysctl_table_users; static unsigned int tcp_sysctl_table_users;
static struct ctl_table_header *tcp_sysctl_header; static struct ctl_table_header *tcp_sysctl_header;
...@@ -1301,14 +1413,14 @@ static struct ctl_table tcp_sysctl_table[] = { ...@@ -1301,14 +1413,14 @@ static struct ctl_table tcp_sysctl_table[] = {
}, },
{ {
.procname = "nf_conntrack_tcp_timeout_max_retrans", .procname = "nf_conntrack_tcp_timeout_max_retrans",
.data = &nf_ct_tcp_timeout_max_retrans, .data = &tcp_timeouts[TCP_CONNTRACK_RETRANS],
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
}, },
{ {
.procname = "nf_conntrack_tcp_timeout_unacknowledged", .procname = "nf_conntrack_tcp_timeout_unacknowledged",
.data = &nf_ct_tcp_timeout_unacknowledged, .data = &tcp_timeouts[TCP_CONNTRACK_UNACK],
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
...@@ -1404,7 +1516,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = { ...@@ -1404,7 +1516,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
}, },
{ {
.procname = "ip_conntrack_tcp_timeout_max_retrans", .procname = "ip_conntrack_tcp_timeout_max_retrans",
.data = &nf_ct_tcp_timeout_max_retrans, .data = &tcp_timeouts[TCP_CONNTRACK_RETRANS],
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
...@@ -1445,6 +1557,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = ...@@ -1445,6 +1557,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
.print_tuple = tcp_print_tuple, .print_tuple = tcp_print_tuple,
.print_conntrack = tcp_print_conntrack, .print_conntrack = tcp_print_conntrack,
.packet = tcp_packet, .packet = tcp_packet,
.get_timeouts = tcp_get_timeouts,
.new = tcp_new, .new = tcp_new,
.error = tcp_error, .error = tcp_error,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
...@@ -1456,6 +1569,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly = ...@@ -1456,6 +1569,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
.nlattr_tuple_size = tcp_nlattr_tuple_size, .nlattr_tuple_size = tcp_nlattr_tuple_size,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = tcp_timeout_nlattr_to_obj,
.obj_to_nlattr = tcp_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_TCP_MAX,
.obj_size = sizeof(unsigned int) *
TCP_CONNTRACK_TIMEOUT_MAX,
.nla_policy = tcp_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_users = &tcp_sysctl_table_users, .ctl_table_users = &tcp_sysctl_table_users,
.ctl_table_header = &tcp_sysctl_header, .ctl_table_header = &tcp_sysctl_header,
...@@ -1477,6 +1600,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = ...@@ -1477,6 +1600,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
.print_tuple = tcp_print_tuple, .print_tuple = tcp_print_tuple,
.print_conntrack = tcp_print_conntrack, .print_conntrack = tcp_print_conntrack,
.packet = tcp_packet, .packet = tcp_packet,
.get_timeouts = tcp_get_timeouts,
.new = tcp_new, .new = tcp_new,
.error = tcp_error, .error = tcp_error,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
...@@ -1488,6 +1612,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly = ...@@ -1488,6 +1612,16 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
.nlattr_tuple_size = tcp_nlattr_tuple_size, .nlattr_tuple_size = tcp_nlattr_tuple_size,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = tcp_timeout_nlattr_to_obj,
.obj_to_nlattr = tcp_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_TCP_MAX,
.obj_size = sizeof(unsigned int) *
TCP_CONNTRACK_TIMEOUT_MAX,
.nla_policy = tcp_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_users = &tcp_sysctl_table_users, .ctl_table_users = &tcp_sysctl_table_users,
.ctl_table_header = &tcp_sysctl_header, .ctl_table_header = &tcp_sysctl_header,
......
...@@ -25,8 +25,16 @@ ...@@ -25,8 +25,16 @@
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; enum udp_conntrack {
static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; UDP_CT_UNREPLIED,
UDP_CT_REPLIED,
UDP_CT_MAX
};
static unsigned int udp_timeouts[UDP_CT_MAX] = {
[UDP_CT_UNREPLIED] = 30*HZ,
[UDP_CT_REPLIED] = 180*HZ,
};
static bool udp_pkt_to_tuple(const struct sk_buff *skb, static bool udp_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
...@@ -63,30 +71,38 @@ static int udp_print_tuple(struct seq_file *s, ...@@ -63,30 +71,38 @@ static int udp_print_tuple(struct seq_file *s,
ntohs(tuple->dst.u.udp.port)); ntohs(tuple->dst.u.udp.port));
} }
static unsigned int *udp_get_timeouts(struct net *net)
{
return udp_timeouts;
}
/* Returns verdict for packet, and may modify conntracktype */ /* Returns verdict for packet, and may modify conntracktype */
static int udp_packet(struct nf_conn *ct, static int udp_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
u_int8_t pf, u_int8_t pf,
unsigned int hooknum) unsigned int hooknum,
unsigned int *timeouts)
{ {
/* If we've seen traffic both ways, this is some kind of UDP /* If we've seen traffic both ways, this is some kind of UDP
stream. Extend timeout. */ stream. Extend timeout. */
if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream); nf_ct_refresh_acct(ct, ctinfo, skb,
timeouts[UDP_CT_REPLIED]);
/* Also, more likely to be important, and not a probe */ /* Also, more likely to be important, and not a probe */
if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
nf_conntrack_event_cache(IPCT_ASSURED, ct); nf_conntrack_event_cache(IPCT_ASSURED, ct);
} else } else {
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout); nf_ct_refresh_acct(ct, ctinfo, skb,
timeouts[UDP_CT_UNREPLIED]);
}
return NF_ACCEPT; return NF_ACCEPT;
} }
/* Called when a new connection for this protocol found. */ /* Called when a new connection for this protocol found. */
static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff) unsigned int dataoff, unsigned int *timeouts)
{ {
return true; return true;
} }
...@@ -136,20 +152,66 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, ...@@ -136,20 +152,66 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
return NF_ACCEPT; return NF_ACCEPT;
} }
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_cttimeout.h>
static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
unsigned int *timeouts = data;
/* set default timeouts for UDP. */
timeouts[UDP_CT_UNREPLIED] = udp_timeouts[UDP_CT_UNREPLIED];
timeouts[UDP_CT_REPLIED] = udp_timeouts[UDP_CT_REPLIED];
if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) {
timeouts[UDP_CT_UNREPLIED] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ;
}
if (tb[CTA_TIMEOUT_UDP_REPLIED]) {
timeouts[UDP_CT_REPLIED] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ;
}
return 0;
}
static int
udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_UNREPLIED,
htonl(timeouts[UDP_CT_UNREPLIED] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_UDP_REPLIED,
htonl(timeouts[UDP_CT_REPLIED] / HZ));
return 0;
nla_put_failure:
return -ENOSPC;
}
static const struct nla_policy
udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = {
[CTA_TIMEOUT_UDP_UNREPLIED] = { .type = NLA_U32 },
[CTA_TIMEOUT_UDP_REPLIED] = { .type = NLA_U32 },
};
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static unsigned int udp_sysctl_table_users; static unsigned int udp_sysctl_table_users;
static struct ctl_table_header *udp_sysctl_header; static struct ctl_table_header *udp_sysctl_header;
static struct ctl_table udp_sysctl_table[] = { static struct ctl_table udp_sysctl_table[] = {
{ {
.procname = "nf_conntrack_udp_timeout", .procname = "nf_conntrack_udp_timeout",
.data = &nf_ct_udp_timeout, .data = &udp_timeouts[UDP_CT_UNREPLIED],
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
}, },
{ {
.procname = "nf_conntrack_udp_timeout_stream", .procname = "nf_conntrack_udp_timeout_stream",
.data = &nf_ct_udp_timeout_stream, .data = &udp_timeouts[UDP_CT_REPLIED],
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
...@@ -160,14 +222,14 @@ static struct ctl_table udp_sysctl_table[] = { ...@@ -160,14 +222,14 @@ static struct ctl_table udp_sysctl_table[] = {
static struct ctl_table udp_compat_sysctl_table[] = { static struct ctl_table udp_compat_sysctl_table[] = {
{ {
.procname = "ip_conntrack_udp_timeout", .procname = "ip_conntrack_udp_timeout",
.data = &nf_ct_udp_timeout, .data = &udp_timeouts[UDP_CT_UNREPLIED],
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
}, },
{ {
.procname = "ip_conntrack_udp_timeout_stream", .procname = "ip_conntrack_udp_timeout_stream",
.data = &nf_ct_udp_timeout_stream, .data = &udp_timeouts[UDP_CT_REPLIED],
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
...@@ -186,6 +248,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = ...@@ -186,6 +248,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
.invert_tuple = udp_invert_tuple, .invert_tuple = udp_invert_tuple,
.print_tuple = udp_print_tuple, .print_tuple = udp_print_tuple,
.packet = udp_packet, .packet = udp_packet,
.get_timeouts = udp_get_timeouts,
.new = udp_new, .new = udp_new,
.error = udp_error, .error = udp_error,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
...@@ -194,6 +257,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = ...@@ -194,6 +257,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = udp_timeout_nlattr_to_obj,
.obj_to_nlattr = udp_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_UDP_MAX,
.obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
.nla_policy = udp_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_users = &udp_sysctl_table_users, .ctl_table_users = &udp_sysctl_table_users,
.ctl_table_header = &udp_sysctl_header, .ctl_table_header = &udp_sysctl_header,
...@@ -214,6 +286,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = ...@@ -214,6 +286,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
.invert_tuple = udp_invert_tuple, .invert_tuple = udp_invert_tuple,
.print_tuple = udp_print_tuple, .print_tuple = udp_print_tuple,
.packet = udp_packet, .packet = udp_packet,
.get_timeouts = udp_get_timeouts,
.new = udp_new, .new = udp_new,
.error = udp_error, .error = udp_error,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
...@@ -222,6 +295,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = ...@@ -222,6 +295,15 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = udp_timeout_nlattr_to_obj,
.obj_to_nlattr = udp_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_UDP_MAX,
.obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
.nla_policy = udp_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_users = &udp_sysctl_table_users, .ctl_table_users = &udp_sysctl_table_users,
.ctl_table_header = &udp_sysctl_header, .ctl_table_header = &udp_sysctl_header,
......
...@@ -24,8 +24,16 @@ ...@@ -24,8 +24,16 @@
#include <net/netfilter/nf_conntrack_ecache.h> #include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_log.h> #include <net/netfilter/nf_log.h>
static unsigned int nf_ct_udplite_timeout __read_mostly = 30*HZ; enum udplite_conntrack {
static unsigned int nf_ct_udplite_timeout_stream __read_mostly = 180*HZ; UDPLITE_CT_UNREPLIED,
UDPLITE_CT_REPLIED,
UDPLITE_CT_MAX
};
static unsigned int udplite_timeouts[UDPLITE_CT_MAX] = {
[UDPLITE_CT_UNREPLIED] = 30*HZ,
[UDPLITE_CT_REPLIED] = 180*HZ,
};
static bool udplite_pkt_to_tuple(const struct sk_buff *skb, static bool udplite_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
...@@ -60,31 +68,38 @@ static int udplite_print_tuple(struct seq_file *s, ...@@ -60,31 +68,38 @@ static int udplite_print_tuple(struct seq_file *s,
ntohs(tuple->dst.u.udp.port)); ntohs(tuple->dst.u.udp.port));
} }
static unsigned int *udplite_get_timeouts(struct net *net)
{
return udplite_timeouts;
}
/* Returns verdict for packet, and may modify conntracktype */ /* Returns verdict for packet, and may modify conntracktype */
static int udplite_packet(struct nf_conn *ct, static int udplite_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
u_int8_t pf, u_int8_t pf,
unsigned int hooknum) unsigned int hooknum,
unsigned int *timeouts)
{ {
/* If we've seen traffic both ways, this is some kind of UDP /* If we've seen traffic both ways, this is some kind of UDP
stream. Extend timeout. */ stream. Extend timeout. */
if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_refresh_acct(ct, ctinfo, skb,
nf_ct_udplite_timeout_stream); timeouts[UDPLITE_CT_REPLIED]);
/* Also, more likely to be important, and not a probe */ /* Also, more likely to be important, and not a probe */
if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
nf_conntrack_event_cache(IPCT_ASSURED, ct); nf_conntrack_event_cache(IPCT_ASSURED, ct);
} else } else {
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udplite_timeout); nf_ct_refresh_acct(ct, ctinfo, skb,
timeouts[UDPLITE_CT_UNREPLIED]);
}
return NF_ACCEPT; return NF_ACCEPT;
} }
/* Called when a new connection for this protocol found. */ /* Called when a new connection for this protocol found. */
static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb, static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff) unsigned int dataoff, unsigned int *timeouts)
{ {
return true; return true;
} }
...@@ -141,20 +156,66 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl, ...@@ -141,20 +156,66 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
return NF_ACCEPT; return NF_ACCEPT;
} }
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_cttimeout.h>
static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
{
unsigned int *timeouts = data;
/* set default timeouts for UDPlite. */
timeouts[UDPLITE_CT_UNREPLIED] = udplite_timeouts[UDPLITE_CT_UNREPLIED];
timeouts[UDPLITE_CT_REPLIED] = udplite_timeouts[UDPLITE_CT_REPLIED];
if (tb[CTA_TIMEOUT_UDPLITE_UNREPLIED]) {
timeouts[UDPLITE_CT_UNREPLIED] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_UNREPLIED])) * HZ;
}
if (tb[CTA_TIMEOUT_UDPLITE_REPLIED]) {
timeouts[UDPLITE_CT_REPLIED] =
ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_REPLIED])) * HZ;
}
return 0;
}
static int
udplite_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
{
const unsigned int *timeouts = data;
NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_UNREPLIED,
htonl(timeouts[UDPLITE_CT_UNREPLIED] / HZ));
NLA_PUT_BE32(skb, CTA_TIMEOUT_UDPLITE_REPLIED,
htonl(timeouts[UDPLITE_CT_REPLIED] / HZ));
return 0;
nla_put_failure:
return -ENOSPC;
}
static const struct nla_policy
udplite_timeout_nla_policy[CTA_TIMEOUT_UDPLITE_MAX+1] = {
[CTA_TIMEOUT_UDPLITE_UNREPLIED] = { .type = NLA_U32 },
[CTA_TIMEOUT_UDPLITE_REPLIED] = { .type = NLA_U32 },
};
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static unsigned int udplite_sysctl_table_users; static unsigned int udplite_sysctl_table_users;
static struct ctl_table_header *udplite_sysctl_header; static struct ctl_table_header *udplite_sysctl_header;
static struct ctl_table udplite_sysctl_table[] = { static struct ctl_table udplite_sysctl_table[] = {
{ {
.procname = "nf_conntrack_udplite_timeout", .procname = "nf_conntrack_udplite_timeout",
.data = &nf_ct_udplite_timeout, .data = &udplite_timeouts[UDPLITE_CT_UNREPLIED],
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
}, },
{ {
.procname = "nf_conntrack_udplite_timeout_stream", .procname = "nf_conntrack_udplite_timeout_stream",
.data = &nf_ct_udplite_timeout_stream, .data = &udplite_timeouts[UDPLITE_CT_REPLIED],
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_jiffies, .proc_handler = proc_dointvec_jiffies,
...@@ -172,6 +233,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = ...@@ -172,6 +233,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
.invert_tuple = udplite_invert_tuple, .invert_tuple = udplite_invert_tuple,
.print_tuple = udplite_print_tuple, .print_tuple = udplite_print_tuple,
.packet = udplite_packet, .packet = udplite_packet,
.get_timeouts = udplite_get_timeouts,
.new = udplite_new, .new = udplite_new,
.error = udplite_error, .error = udplite_error,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
...@@ -180,6 +242,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly = ...@@ -180,6 +242,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = udplite_timeout_nlattr_to_obj,
.obj_to_nlattr = udplite_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_UDPLITE_MAX,
.obj_size = sizeof(unsigned int) *
CTA_TIMEOUT_UDPLITE_MAX,
.nla_policy = udplite_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_users = &udplite_sysctl_table_users, .ctl_table_users = &udplite_sysctl_table_users,
.ctl_table_header = &udplite_sysctl_header, .ctl_table_header = &udplite_sysctl_header,
...@@ -196,6 +268,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = ...@@ -196,6 +268,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
.invert_tuple = udplite_invert_tuple, .invert_tuple = udplite_invert_tuple,
.print_tuple = udplite_print_tuple, .print_tuple = udplite_print_tuple,
.packet = udplite_packet, .packet = udplite_packet,
.get_timeouts = udplite_get_timeouts,
.new = udplite_new, .new = udplite_new,
.error = udplite_error, .error = udplite_error,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
...@@ -204,6 +277,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly = ...@@ -204,6 +277,16 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
.nla_policy = nf_ct_port_nla_policy, .nla_policy = nf_ct_port_nla_policy,
#endif #endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
.ctnl_timeout = {
.nlattr_to_obj = udplite_timeout_nlattr_to_obj,
.obj_to_nlattr = udplite_timeout_obj_to_nlattr,
.nlattr_max = CTA_TIMEOUT_UDPLITE_MAX,
.obj_size = sizeof(unsigned int) *
CTA_TIMEOUT_UDPLITE_MAX,
.nla_policy = udplite_timeout_nla_policy,
},
#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
.ctl_table_users = &udplite_sysctl_table_users, .ctl_table_users = &udplite_sysctl_table_users,
.ctl_table_header = &udplite_sysctl_header, .ctl_table_header = &udplite_sysctl_header,
......
/*
* (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
* (C) 2012 by Vyatta Inc. <http://www.vyatta.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation (or any later at your option).
*/
#include <linux/types.h>
#include <linux/netfilter.h>
#include <linux/skbuff.h>
#include <linux/vmalloc.h>
#include <linux/stddef.h>
#include <linux/err.h>
#include <linux/percpu.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_extend.h>
#include <net/netfilter/nf_conntrack_timeout.h>
struct ctnl_timeout *
(*nf_ct_timeout_find_get_hook)(const char *name) __read_mostly;
EXPORT_SYMBOL_GPL(nf_ct_timeout_find_get_hook);
void (*nf_ct_timeout_put_hook)(struct ctnl_timeout *timeout) __read_mostly;
EXPORT_SYMBOL_GPL(nf_ct_timeout_put_hook);
static struct nf_ct_ext_type timeout_extend __read_mostly = {
.len = sizeof(struct nf_conn_timeout),
.align = __alignof__(struct nf_conn_timeout),
.id = NF_CT_EXT_TIMEOUT,
};
int nf_conntrack_timeout_init(struct net *net)
{
int ret = 0;
if (net_eq(net, &init_net)) {
ret = nf_ct_extend_register(&timeout_extend);
if (ret < 0) {
printk(KERN_ERR "nf_ct_timeout: Unable to register "
"timeout extension.\n");
return ret;
}
}
return 0;
}
void nf_conntrack_timeout_fini(struct net *net)
{
if (net_eq(net, &init_net))
nf_ct_extend_unregister(&timeout_extend);
}
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment