Commit 9fb9cbb1 authored by Yasuyuki Kozakai's avatar Yasuyuki Kozakai Committed by David S. Miller

[NETFILTER]: Add nf_conntrack subsystem.

The existing connection tracking subsystem in netfilter can only
handle ipv4.  There were basically two choices present to add
connection tracking support for ipv6.  We could either duplicate all
of the ipv4 connection tracking code into an ipv6 counterpart, or (the
choice taken by these patches) we could design a generic layer that
could handle both ipv4 and ipv6 and thus requiring only one sub-protocol
(TCP, UDP, etc.) connection tracking helper module to be written.

In fact nf_conntrack is capable of working with any layer 3
protocol.

The existing ipv4 specific conntrack code could also not deal
with the pecularities of doing connection tracking on ipv6,
which is also cured here.  For example, these issues include:

1) ICMPv6 handling, which is used for neighbour discovery in
   ipv6 thus some messages such as these should not participate
   in connection tracking since effectively they are like ARP
   messages

2) fragmentation must be handled differently in ipv6, because
   the simplistic "defrag, connection track and NAT, refrag"
   (which the existing ipv4 connection tracking does) approach simply
   isn't feasible in ipv6

3) ipv6 extension header parsing must occur at the correct spots
   before and after connection tracking decisions, and there were
   no provisions for this in the existing connection tracking
   design

4) ipv6 has no need for stateful NAT

The ipv4 specific conntrack layer is kept around, until all of
the ipv4 specific conntrack helpers are ported over to nf_conntrack
and it is feature complete.  Once that occurs, the old conntrack
stuff will get placed into the feature-removal-schedule and we will
fully kill it off 6 months later.
Signed-off-by: default avatarYasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp>
Signed-off-by: default avatarHarald Welte <laforge@netfilter.org>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
parent 6730c3c1
#ifndef _NF_CONNTRACK_COMMON_H
#define _NF_CONNTRACK_COMMON_H
/* Connection state tracking for netfilter. This is separated from,
but required by, the NAT layer; it can also be used by an iptables
extension. */
enum ip_conntrack_info
{
/* Part of an established connection (either direction). */
IP_CT_ESTABLISHED,
/* Like NEW, but related to an existing connection, or ICMP error
(in either direction). */
IP_CT_RELATED,
/* Started a new connection to track (only
IP_CT_DIR_ORIGINAL); may be a retransmission. */
IP_CT_NEW,
/* >= this indicates reply direction */
IP_CT_IS_REPLY,
/* Number of distinct IP_CT types (no NEW in reply dirn). */
IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
};
/* Bitset representing status of connection. */
enum ip_conntrack_status {
/* It's an expected connection: bit 0 set. This bit never changed */
IPS_EXPECTED_BIT = 0,
IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
/* We've seen packets both ways: bit 1 set. Can be set, not unset. */
IPS_SEEN_REPLY_BIT = 1,
IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
/* Conntrack should never be early-expired. */
IPS_ASSURED_BIT = 2,
IPS_ASSURED = (1 << IPS_ASSURED_BIT),
/* Connection is confirmed: originating packet has left box */
IPS_CONFIRMED_BIT = 3,
IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
/* Connection needs src nat in orig dir. This bit never changed. */
IPS_SRC_NAT_BIT = 4,
IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT),
/* Connection needs dst nat in orig dir. This bit never changed. */
IPS_DST_NAT_BIT = 5,
IPS_DST_NAT = (1 << IPS_DST_NAT_BIT),
/* Both together. */
IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT),
/* Connection needs TCP sequence adjusted. */
IPS_SEQ_ADJUST_BIT = 6,
IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT),
/* NAT initialization bits. */
IPS_SRC_NAT_DONE_BIT = 7,
IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT),
IPS_DST_NAT_DONE_BIT = 8,
IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT),
/* Both together */
IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
/* Connection is dying (removed from lists), can not be unset. */
IPS_DYING_BIT = 9,
IPS_DYING = (1 << IPS_DYING_BIT),
};
/* Connection tracking event bits */
enum ip_conntrack_events
{
/* New conntrack */
IPCT_NEW_BIT = 0,
IPCT_NEW = (1 << IPCT_NEW_BIT),
/* Expected connection */
IPCT_RELATED_BIT = 1,
IPCT_RELATED = (1 << IPCT_RELATED_BIT),
/* Destroyed conntrack */
IPCT_DESTROY_BIT = 2,
IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),
/* Timer has been refreshed */
IPCT_REFRESH_BIT = 3,
IPCT_REFRESH = (1 << IPCT_REFRESH_BIT),
/* Status has changed */
IPCT_STATUS_BIT = 4,
IPCT_STATUS = (1 << IPCT_STATUS_BIT),
/* Update of protocol info */
IPCT_PROTOINFO_BIT = 5,
IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT),
/* Volatile protocol info */
IPCT_PROTOINFO_VOLATILE_BIT = 6,
IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT),
/* New helper for conntrack */
IPCT_HELPER_BIT = 7,
IPCT_HELPER = (1 << IPCT_HELPER_BIT),
/* Update of helper info */
IPCT_HELPINFO_BIT = 8,
IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT),
/* Volatile helper info */
IPCT_HELPINFO_VOLATILE_BIT = 9,
IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT),
/* NAT info */
IPCT_NATINFO_BIT = 10,
IPCT_NATINFO = (1 << IPCT_NATINFO_BIT),
/* Counter highest bit has been set */
IPCT_COUNTER_FILLING_BIT = 11,
IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT),
};
enum ip_conntrack_expect_events {
IPEXP_NEW_BIT = 0,
IPEXP_NEW = (1 << IPEXP_NEW_BIT),
};
#ifdef __KERNEL__
struct ip_conntrack_counter
{
u_int32_t packets;
u_int32_t bytes;
};
struct ip_conntrack_stat
{
unsigned int searched;
unsigned int found;
unsigned int new;
unsigned int invalid;
unsigned int ignore;
unsigned int delete;
unsigned int delete_list;
unsigned int insert;
unsigned int insert_failed;
unsigned int drop;
unsigned int early_drop;
unsigned int error;
unsigned int expect_new;
unsigned int expect_create;
unsigned int expect_delete;
};
#endif /* __KERNEL__ */
#endif /* _NF_CONNTRACK_COMMON_H */
#ifndef _NF_CONNTRACK_FTP_H
#define _NF_CONNTRACK_FTP_H
/* FTP tracking. */
/* This enum is exposed to userspace */
enum ip_ct_ftp_type
{
/* PORT command from client */
IP_CT_FTP_PORT,
/* PASV response from server */
IP_CT_FTP_PASV,
/* EPRT command from client */
IP_CT_FTP_EPRT,
/* EPSV response from server */
IP_CT_FTP_EPSV,
};
#ifdef __KERNEL__
#define FTP_PORT 21
#define NUM_SEQ_TO_REMEMBER 2
/* This structure exists only once per master */
struct ip_ct_ftp_master {
/* Valid seq positions for cmd matching after newline */
u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
/* 0 means seq_match_aft_nl not set */
int seq_aft_nl_num[IP_CT_DIR_MAX];
};
struct ip_conntrack_expect;
/* For NAT to hook in when we find a packet which describes what other
* connection we should expect. */
extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
enum ip_ct_ftp_type type,
unsigned int matchoff,
unsigned int matchlen,
struct ip_conntrack_expect *exp,
u32 *seq);
#endif /* __KERNEL__ */
#endif /* _NF_CONNTRACK_FTP_H */
#ifndef _NF_CONNTRACK_SCTP_H
#define _NF_CONNTRACK_SCTP_H
/* SCTP tracking. */
#include <linux/netfilter/nf_conntrack_tuple_common.h>
enum sctp_conntrack {
SCTP_CONNTRACK_NONE,
SCTP_CONNTRACK_CLOSED,
SCTP_CONNTRACK_COOKIE_WAIT,
SCTP_CONNTRACK_COOKIE_ECHOED,
SCTP_CONNTRACK_ESTABLISHED,
SCTP_CONNTRACK_SHUTDOWN_SENT,
SCTP_CONNTRACK_SHUTDOWN_RECD,
SCTP_CONNTRACK_SHUTDOWN_ACK_SENT,
SCTP_CONNTRACK_MAX
};
struct ip_ct_sctp
{
enum sctp_conntrack state;
u_int32_t vtag[IP_CT_DIR_MAX];
u_int32_t ttag[IP_CT_DIR_MAX];
};
#endif /* _NF_CONNTRACK_SCTP_H */
#ifndef _NF_CONNTRACK_TCP_H
#define _NF_CONNTRACK_TCP_H
/* TCP tracking. */
/* This is exposed to userspace (ctnetlink) */
enum tcp_conntrack {
TCP_CONNTRACK_NONE,
TCP_CONNTRACK_SYN_SENT,
TCP_CONNTRACK_SYN_RECV,
TCP_CONNTRACK_ESTABLISHED,
TCP_CONNTRACK_FIN_WAIT,
TCP_CONNTRACK_CLOSE_WAIT,
TCP_CONNTRACK_LAST_ACK,
TCP_CONNTRACK_TIME_WAIT,
TCP_CONNTRACK_CLOSE,
TCP_CONNTRACK_LISTEN,
TCP_CONNTRACK_MAX,
TCP_CONNTRACK_IGNORE
};
/* Window scaling is advertised by the sender */
#define IP_CT_TCP_FLAG_WINDOW_SCALE 0x01
/* SACK is permitted by the sender */
#define IP_CT_TCP_FLAG_SACK_PERM 0x02
/* This sender sent FIN first */
#define IP_CT_TCP_FLAG_CLOSE_INIT 0x03
#ifdef __KERNEL__
struct ip_ct_tcp_state {
u_int32_t td_end; /* max of seq + len */
u_int32_t td_maxend; /* max of ack + max(win, 1) */
u_int32_t td_maxwin; /* max(win) */
u_int8_t td_scale; /* window scale factor */
u_int8_t loose; /* used when connection picked up from the middle */
u_int8_t flags; /* per direction options */
};
struct ip_ct_tcp
{
struct ip_ct_tcp_state seen[2]; /* connection parameters per direction */
u_int8_t state; /* state of the connection (enum tcp_conntrack) */
/* For detecting stale connections */
u_int8_t last_dir; /* Direction of the last packet (enum ip_conntrack_dir) */
u_int8_t retrans; /* Number of retransmitted packets */
u_int8_t last_index; /* Index of the last packet */
u_int32_t last_seq; /* Last sequence number seen in dir */
u_int32_t last_ack; /* Last sequence number seen in opposite dir */
u_int32_t last_end; /* Last seq + len */
};
#endif /* __KERNEL__ */
#endif /* _NF_CONNTRACK_TCP_H */
#ifndef _NF_CONNTRACK_TUPLE_COMMON_H
#define _NF_CONNTRACK_TUPLE_COMMON_H
enum ip_conntrack_dir
{
IP_CT_DIR_ORIGINAL,
IP_CT_DIR_REPLY,
IP_CT_DIR_MAX
};
#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
#endif /* _NF_CONNTRACK_TUPLE_COMMON_H */
#ifndef _IP_CONNTRACK_H
#define _IP_CONNTRACK_H
/* Connection state tracking for netfilter. This is separated from,
but required by, the NAT layer; it can also be used by an iptables
extension. */
enum ip_conntrack_info
{
/* Part of an established connection (either direction). */
IP_CT_ESTABLISHED,
/* Like NEW, but related to an existing connection, or ICMP error
(in either direction). */
IP_CT_RELATED,
/* Started a new connection to track (only
IP_CT_DIR_ORIGINAL); may be a retransmission. */
IP_CT_NEW,
/* >= this indicates reply direction */
IP_CT_IS_REPLY,
/* Number of distinct IP_CT types (no NEW in reply dirn). */
IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
};
/* Bitset representing status of connection. */
enum ip_conntrack_status {
/* It's an expected connection: bit 0 set. This bit never changed */
IPS_EXPECTED_BIT = 0,
IPS_EXPECTED = (1 << IPS_EXPECTED_BIT),
/* We've seen packets both ways: bit 1 set. Can be set, not unset. */
IPS_SEEN_REPLY_BIT = 1,
IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT),
/* Conntrack should never be early-expired. */
IPS_ASSURED_BIT = 2,
IPS_ASSURED = (1 << IPS_ASSURED_BIT),
/* Connection is confirmed: originating packet has left box */
IPS_CONFIRMED_BIT = 3,
IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT),
/* Connection needs src nat in orig dir. This bit never changed. */
IPS_SRC_NAT_BIT = 4,
IPS_SRC_NAT = (1 << IPS_SRC_NAT_BIT),
/* Connection needs dst nat in orig dir. This bit never changed. */
IPS_DST_NAT_BIT = 5,
IPS_DST_NAT = (1 << IPS_DST_NAT_BIT),
/* Both together. */
IPS_NAT_MASK = (IPS_DST_NAT | IPS_SRC_NAT),
/* Connection needs TCP sequence adjusted. */
IPS_SEQ_ADJUST_BIT = 6,
IPS_SEQ_ADJUST = (1 << IPS_SEQ_ADJUST_BIT),
/* NAT initialization bits. */
IPS_SRC_NAT_DONE_BIT = 7,
IPS_SRC_NAT_DONE = (1 << IPS_SRC_NAT_DONE_BIT),
IPS_DST_NAT_DONE_BIT = 8,
IPS_DST_NAT_DONE = (1 << IPS_DST_NAT_DONE_BIT),
/* Both together */
IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
/* Connection is dying (removed from lists), can not be unset. */
IPS_DYING_BIT = 9,
IPS_DYING = (1 << IPS_DYING_BIT),
};
/* Connection tracking event bits */
enum ip_conntrack_events
{
/* New conntrack */
IPCT_NEW_BIT = 0,
IPCT_NEW = (1 << IPCT_NEW_BIT),
/* Expected connection */
IPCT_RELATED_BIT = 1,
IPCT_RELATED = (1 << IPCT_RELATED_BIT),
/* Destroyed conntrack */
IPCT_DESTROY_BIT = 2,
IPCT_DESTROY = (1 << IPCT_DESTROY_BIT),
/* Timer has been refreshed */
IPCT_REFRESH_BIT = 3,
IPCT_REFRESH = (1 << IPCT_REFRESH_BIT),
/* Status has changed */
IPCT_STATUS_BIT = 4,
IPCT_STATUS = (1 << IPCT_STATUS_BIT),
/* Update of protocol info */
IPCT_PROTOINFO_BIT = 5,
IPCT_PROTOINFO = (1 << IPCT_PROTOINFO_BIT),
/* Volatile protocol info */
IPCT_PROTOINFO_VOLATILE_BIT = 6,
IPCT_PROTOINFO_VOLATILE = (1 << IPCT_PROTOINFO_VOLATILE_BIT),
/* New helper for conntrack */
IPCT_HELPER_BIT = 7,
IPCT_HELPER = (1 << IPCT_HELPER_BIT),
/* Update of helper info */
IPCT_HELPINFO_BIT = 8,
IPCT_HELPINFO = (1 << IPCT_HELPINFO_BIT),
/* Volatile helper info */
IPCT_HELPINFO_VOLATILE_BIT = 9,
IPCT_HELPINFO_VOLATILE = (1 << IPCT_HELPINFO_VOLATILE_BIT),
/* NAT info */
IPCT_NATINFO_BIT = 10,
IPCT_NATINFO = (1 << IPCT_NATINFO_BIT),
/* Counter highest bit has been set */
IPCT_COUNTER_FILLING_BIT = 11,
IPCT_COUNTER_FILLING = (1 << IPCT_COUNTER_FILLING_BIT),
};
enum ip_conntrack_expect_events {
IPEXP_NEW_BIT = 0,
IPEXP_NEW = (1 << IPEXP_NEW_BIT),
};
#include <linux/netfilter/nf_conntrack_common.h>
#ifdef __KERNEL__
#include <linux/config.h>
......@@ -194,12 +69,6 @@ do { \
#define IP_NF_ASSERT(x)
#endif
struct ip_conntrack_counter
{
u_int32_t packets;
u_int32_t bytes;
};
struct ip_conntrack_helper;
struct ip_conntrack
......@@ -426,25 +295,6 @@ static inline int is_dying(struct ip_conntrack *ct)
extern unsigned int ip_conntrack_htable_size;
struct ip_conntrack_stat
{
unsigned int searched;
unsigned int found;
unsigned int new;
unsigned int invalid;
unsigned int ignore;
unsigned int delete;
unsigned int delete_list;
unsigned int insert;
unsigned int insert_failed;
unsigned int drop;
unsigned int early_drop;
unsigned int error;
unsigned int expect_new;
unsigned int expect_create;
unsigned int expect_delete;
};
#define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++)
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
......
#ifndef _IP_CONNTRACK_FTP_H
#define _IP_CONNTRACK_FTP_H
/* FTP tracking. */
#ifdef __KERNEL__
#include <linux/netfilter/nf_conntrack_ftp.h>
#define FTP_PORT 21
#endif /* __KERNEL__ */
enum ip_ct_ftp_type
{
/* PORT command from client */
IP_CT_FTP_PORT,
/* PASV response from server */
IP_CT_FTP_PASV,
/* EPRT command from client */
IP_CT_FTP_EPRT,
/* EPSV response from server */
IP_CT_FTP_EPSV,
};
#define NUM_SEQ_TO_REMEMBER 2
/* This structure exists only once per master */
struct ip_ct_ftp_master {
/* Valid seq positions for cmd matching after newline */
u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
/* 0 means seq_match_aft_nl not set */
int seq_aft_nl_num[IP_CT_DIR_MAX];
};
struct ip_conntrack_expect;
/* For NAT to hook in when we find a packet which describes what other
* connection we should expect. */
extern unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
enum ip_ct_ftp_type type,
unsigned int matchoff,
unsigned int matchlen,
struct ip_conntrack_expect *exp,
u32 *seq);
#endif /* _IP_CONNTRACK_FTP_H */
#ifndef _IP_CONNTRACK_ICMP_H
#define _IP_CONNTRACK_ICMP_H
/* ICMP tracking. */
#include <asm/atomic.h>
struct ip_ct_icmp
{
/* Optimization: when number in == number out, forget immediately. */
atomic_t count;
};
#include <net/netfilter/ipv4/nf_conntrack_icmp.h>
#endif /* _IP_CONNTRACK_ICMP_H */
#ifndef _IP_CONNTRACK_SCTP_H
#define _IP_CONNTRACK_SCTP_H
/* SCTP tracking. */
enum sctp_conntrack {
SCTP_CONNTRACK_NONE,
SCTP_CONNTRACK_CLOSED,
SCTP_CONNTRACK_COOKIE_WAIT,
SCTP_CONNTRACK_COOKIE_ECHOED,
SCTP_CONNTRACK_ESTABLISHED,
SCTP_CONNTRACK_SHUTDOWN_SENT,
SCTP_CONNTRACK_SHUTDOWN_RECD,
SCTP_CONNTRACK_SHUTDOWN_ACK_SENT,
SCTP_CONNTRACK_MAX
};
struct ip_ct_sctp
{
enum sctp_conntrack state;
u_int32_t vtag[IP_CT_DIR_MAX];
u_int32_t ttag[IP_CT_DIR_MAX];
};
#include <linux/netfilter/nf_conntrack_sctp.h>
#endif /* _IP_CONNTRACK_SCTP_H */
#ifndef _IP_CONNTRACK_TCP_H
#define _IP_CONNTRACK_TCP_H
/* TCP tracking. */
enum tcp_conntrack {
TCP_CONNTRACK_NONE,
TCP_CONNTRACK_SYN_SENT,
TCP_CONNTRACK_SYN_RECV,
TCP_CONNTRACK_ESTABLISHED,
TCP_CONNTRACK_FIN_WAIT,
TCP_CONNTRACK_CLOSE_WAIT,
TCP_CONNTRACK_LAST_ACK,
TCP_CONNTRACK_TIME_WAIT,
TCP_CONNTRACK_CLOSE,
TCP_CONNTRACK_LISTEN,
TCP_CONNTRACK_MAX,
TCP_CONNTRACK_IGNORE
};
/* Window scaling is advertised by the sender */
#define IP_CT_TCP_FLAG_WINDOW_SCALE 0x01
/* SACK is permitted by the sender */
#define IP_CT_TCP_FLAG_SACK_PERM 0x02
/* This sender sent FIN first */
#define IP_CT_TCP_FLAG_CLOSE_INIT 0x03
struct ip_ct_tcp_state {
u_int32_t td_end; /* max of seq + len */
u_int32_t td_maxend; /* max of ack + max(win, 1) */
u_int32_t td_maxwin; /* max(win) */
u_int8_t td_scale; /* window scale factor */
u_int8_t loose; /* used when connection picked up from the middle */
u_int8_t flags; /* per direction options */
};
struct ip_ct_tcp
{
struct ip_ct_tcp_state seen[2]; /* connection parameters per direction */
u_int8_t state; /* state of the connection (enum tcp_conntrack) */
/* For detecting stale connections */
u_int8_t last_dir; /* Direction of the last packet (enum ip_conntrack_dir) */
u_int8_t retrans; /* Number of retransmitted packets */
u_int8_t last_index; /* Index of the last packet */
u_int32_t last_seq; /* Last sequence number seen in dir */
u_int32_t last_ack; /* Last sequence number seen in opposite dir */
u_int32_t last_end; /* Last seq + len */
};
#include <linux/netfilter/nf_conntrack_tcp.h>
#endif /* _IP_CONNTRACK_TCP_H */
......@@ -2,6 +2,7 @@
#define _IP_CONNTRACK_TUPLE_H
#include <linux/types.h>
#include <linux/netfilter/nf_conntrack_tuple_common.h>
/* A `tuple' is a structure containing the information to uniquely
identify a connection. ie. if two packets have the same tuple, they
......@@ -88,13 +89,6 @@ struct ip_conntrack_tuple
(tuple)->dst.u.all = 0; \
} while (0)
enum ip_conntrack_dir
{
IP_CT_DIR_ORIGINAL,
IP_CT_DIR_REPLY,
IP_CT_DIR_MAX
};
#ifdef __KERNEL__
#define DUMP_TUPLE(tp) \
......@@ -103,8 +97,6 @@ DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
#define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
/* If we're the first tuple, it's the original dir. */
#define DIRECTION(h) ((enum ip_conntrack_dir)(h)->tuple.dst.dir)
......
......@@ -59,6 +59,7 @@
enum nf_ip6_hook_priorities {
NF_IP6_PRI_FIRST = INT_MIN,
NF_IP6_PRI_CONNTRACK_DEFRAG = -400,
NF_IP6_PRI_SELINUX_FIRST = -225,
NF_IP6_PRI_CONNTRACK = -200,
NF_IP6_PRI_BRIDGE_SABOTAGE_FORWARD = -175,
......
......@@ -274,6 +274,9 @@ struct sk_buff {
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
__u8 ipvs_property:1;
#endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct sk_buff *nfct_reasm;
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
struct nf_bridge_info *nf_bridge;
#endif
......@@ -1313,10 +1316,26 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct)
if (nfct)
atomic_inc(&nfct->use);
}
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
{
if (skb)
atomic_inc(&skb->users);
}
static inline void nf_conntrack_put_reasm(struct sk_buff *skb)
{
if (skb)
kfree_skb(skb);
}
#endif
static inline void nf_reset(struct sk_buff *skb)
{
nf_conntrack_put(skb->nfct);
skb->nfct = NULL;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_conntrack_put_reasm(skb->nfct_reasm);
skb->nfct_reasm = NULL;
#endif
}
#ifdef CONFIG_BRIDGE_NETFILTER
......
......@@ -205,6 +205,7 @@ enum
NET_ECONET=16,
NET_SCTP=17,
NET_LLC=18,
NET_NETFILTER=19,
};
/* /proc/sys/kernel/random */
......@@ -270,6 +271,42 @@ enum
NET_UNIX_MAX_DGRAM_QLEN=3,
};
/* /proc/sys/net/netfilter */
enum
{
NET_NF_CONNTRACK_MAX=1,
NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2,
NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3,
NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4,
NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5,
NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6,
NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7,
NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8,
NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9,
NET_NF_CONNTRACK_UDP_TIMEOUT=10,
NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11,
NET_NF_CONNTRACK_ICMP_TIMEOUT=12,
NET_NF_CONNTRACK_GENERIC_TIMEOUT=13,
NET_NF_CONNTRACK_BUCKETS=14,
NET_NF_CONNTRACK_LOG_INVALID=15,
NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS=16,
NET_NF_CONNTRACK_TCP_LOOSE=17,
NET_NF_CONNTRACK_TCP_BE_LIBERAL=18,
NET_NF_CONNTRACK_TCP_MAX_RETRANS=19,
NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED=20,
NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT=21,
NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED=22,
NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED=23,
NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT=24,
NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD=25,
NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT=26,
NET_NF_CONNTRACK_COUNT=27,
NET_NF_CONNTRACK_ICMPV6_TIMEOUT=28,
NET_NF_CONNTRACK_FRAG6_TIMEOUT=29,
NET_NF_CONNTRACK_FRAG6_LOW_THRESH=30,
NET_NF_CONNTRACK_FRAG6_HIGH_THRESH=31,
};
/* /proc/sys/net/ipv4 */
enum
{
......
#ifndef _NF_CONNTRACK_ICMP_H
#define _NF_CONNTRACK_ICMP_H
/* ICMP tracking. */
#include <asm/atomic.h>
struct ip_ct_icmp
{
/* Optimization: when number in == number out, forget immediately. */
atomic_t count;
};
#endif /* _NF_CONNTRACK_ICMP_H */
/*
* IPv4 support for nf_conntrack.
*
* 23 Mar 2004: Yasuyuki Kozakai @ USAGI <yasuyuki.kozakai@toshiba.co.jp>
* - move L3 protocol dependent part from include/linux/netfilter_ipv4/
* ip_conntarck.h
*/
#ifndef _NF_CONNTRACK_IPV4_H
#define _NF_CONNTRACK_IPV4_H
#ifdef CONFIG_IP_NF_NAT_NEEDED
#include <linux/netfilter_ipv4/ip_nat.h>
/* per conntrack: nat application helper private data */
union ip_conntrack_nat_help {
/* insert nat helper private data here */
};
struct nf_conntrack_ipv4_nat {
struct ip_nat_info info;
union ip_conntrack_nat_help help;
#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
int masq_index;
#endif
};
#endif /* CONFIG_IP_NF_NAT_NEEDED */
struct nf_conntrack_ipv4 {
#ifdef CONFIG_IP_NF_NAT_NEEDED
struct nf_conntrack_ipv4_nat *nat;
#endif
};
/* Returns new sk_buff, or NULL */
struct sk_buff *
nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
/* call to create an explicit dependency on nf_conntrack_l3proto_ipv4. */
extern void need_ip_conntrack(void);
#endif /*_NF_CONNTRACK_IPV4_H*/
/*
* ICMPv6 tracking.
*
* 21 Apl 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
* - separated from nf_conntrack_icmp.h
*
* Derived from include/linux/netfiter_ipv4/ip_conntrack_icmp.h
*/
#ifndef _NF_CONNTRACK_ICMPV6_H
#define _NF_CONNTRACK_ICMPV6_H
#include <asm/atomic.h>
#ifndef ICMPV6_NI_QUERY
#define ICMPV6_NI_QUERY 139
#endif
#ifndef ICMPV6_NI_REPLY
#define ICMPV6_NI_REPLY 140
#endif
struct nf_ct_icmpv6
{
/* Optimization: when number in == number out, forget immediately. */
atomic_t count;
};
#endif /* _NF_CONNTRACK_ICMPV6_H */
This diff is collapsed.
#ifndef _NF_CONNTRACK_COMPAT_H
#define _NF_CONNTRACK_COMPAT_H
#ifdef __KERNEL__
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
#include <linux/netfilter_ipv4/ip_conntrack.h>
#ifdef CONFIG_IP_NF_CONNTRACK_MARK
static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb,
u_int32_t *ctinfo)
{
struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo);
if (ct)
return &ct->mark;
else
return NULL;
}
#endif /* CONFIG_IP_NF_CONNTRACK_MARK */
#ifdef CONFIG_IP_NF_CT_ACCT
static inline struct ip_conntrack_counter *
nf_ct_get_counters(const struct sk_buff *skb)
{
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct = ip_conntrack_get(skb, &ctinfo);
if (ct)
return ct->counters;
else
return NULL;
}
#endif /* CONFIG_IP_NF_CT_ACCT */
static inline int nf_ct_is_untracked(const struct sk_buff *skb)
{
return (skb->nfct == &ip_conntrack_untracked.ct_general);
}
static inline void nf_ct_untrack(struct sk_buff *skb)
{
skb->nfct = &ip_conntrack_untracked.ct_general;
}
static inline int nf_ct_get_ctinfo(const struct sk_buff *skb,
enum ip_conntrack_info *ctinfo)
{
struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo);
return (ct != NULL);
}
#else /* CONFIG_IP_NF_CONNTRACK */
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/nf_conntrack.h>
#ifdef CONFIG_NF_CONNTRACK_MARK
static inline u_int32_t *nf_ct_get_mark(const struct sk_buff *skb,
u_int32_t *ctinfo)
{
struct nf_conn *ct = nf_ct_get(skb, ctinfo);
if (ct)
return &ct->mark;
else
return NULL;
}
#endif /* CONFIG_NF_CONNTRACK_MARK */
#ifdef CONFIG_NF_CT_ACCT
static inline struct ip_conntrack_counter *
nf_ct_get_counters(const struct sk_buff *skb)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
if (ct)
return ct->counters;
else
return NULL;
}
#endif /* CONFIG_NF_CT_ACCT */
static inline int nf_ct_is_untracked(const struct sk_buff *skb)
{
return (skb->nfct == &nf_conntrack_untracked.ct_general);
}
static inline void nf_ct_untrack(struct sk_buff *skb)
{
skb->nfct = &nf_conntrack_untracked.ct_general;
}
static inline int nf_ct_get_ctinfo(const struct sk_buff *skb,
enum ip_conntrack_info *ctinfo)
{
struct nf_conn *ct = nf_ct_get(skb, ctinfo);
return (ct != NULL);
}
#endif /* CONFIG_IP_NF_CONNTRACK */
#endif /* __KERNEL__ */
#endif /* _NF_CONNTRACK_COMPAT_H */
/*
* This header is used to share core functionality between the
* standalone connection tracking module, and the compatibility layer's use
* of connection tracking.
*
* 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
* - generalize L3 protocol dependent part.
*
* Derived from include/linux/netfiter_ipv4/ip_conntrack_core.h
*/
#ifndef _NF_CONNTRACK_CORE_H
#define _NF_CONNTRACK_CORE_H
#include <linux/netfilter.h>
/* This header is used to share core functionality between the
standalone connection tracking module, and the compatibility layer's use
of connection tracking. */
extern unsigned int nf_conntrack_in(int pf,
unsigned int hooknum,
struct sk_buff **pskb);
extern int nf_conntrack_init(void);
extern void nf_conntrack_cleanup(void);
struct nf_conntrack_l3proto;
extern struct nf_conntrack_l3proto *nf_ct_find_l3proto(u_int16_t pf);
/* Like above, but you already have conntrack read lock. */
extern struct nf_conntrack_l3proto *__nf_ct_find_l3proto(u_int16_t l3proto);
struct nf_conntrack_protocol;
extern int
nf_ct_get_tuple(const struct sk_buff *skb,
unsigned int nhoff,
unsigned int dataoff,
u_int16_t l3num,
u_int8_t protonum,
struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_l3proto *l3proto,
const struct nf_conntrack_protocol *protocol);
extern int
nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig,
const struct nf_conntrack_l3proto *l3proto,
const struct nf_conntrack_protocol *protocol);
/* Find a connection corresponding to a tuple. */
extern struct nf_conntrack_tuple_hash *
nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple,
const struct nf_conn *ignored_conntrack);
extern int __nf_conntrack_confirm(struct sk_buff **pskb);
/* Confirm a connection: returns NF_DROP if packet must be dropped. */
static inline int nf_conntrack_confirm(struct sk_buff **pskb)
{
struct nf_conn *ct = (struct nf_conn *)(*pskb)->nfct;
int ret = NF_ACCEPT;
if (ct) {
if (!nf_ct_is_confirmed(ct))
ret = __nf_conntrack_confirm(pskb);
nf_ct_deliver_cached_events(ct);
}
return ret;
}
extern void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb);
extern struct list_head *nf_conntrack_hash;
extern struct list_head nf_conntrack_expect_list;
extern rwlock_t nf_conntrack_lock ;
#endif /* _NF_CONNTRACK_CORE_H */
/*
* connection tracking helpers.
*
* 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
* - generalize L3 protocol dependent part.
*
* Derived from include/linux/netfiter_ipv4/ip_conntrack_helper.h
*/
#ifndef _NF_CONNTRACK_HELPER_H
#define _NF_CONNTRACK_HELPER_H
#include <net/netfilter/nf_conntrack.h>
struct module;
struct nf_conntrack_helper
{
struct list_head list; /* Internal use. */
const char *name; /* name of the module */
struct module *me; /* pointer to self */
unsigned int max_expected; /* Maximum number of concurrent
* expected connections */
unsigned int timeout; /* timeout for expecteds */
/* Mask of things we will help (compared against server response) */
struct nf_conntrack_tuple tuple;
struct nf_conntrack_tuple mask;
/* Function to call when data passes; return verdict, or -1 to
invalidate. */
int (*help)(struct sk_buff **pskb,
unsigned int protoff,
struct nf_conn *ct,
enum ip_conntrack_info conntrackinfo);
};
extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
/* Allocate space for an expectation: this is mandatory before calling
nf_conntrack_expect_related. You will have to call put afterwards. */
extern struct nf_conntrack_expect *
nf_conntrack_expect_alloc(struct nf_conn *master);
extern void nf_conntrack_expect_put(struct nf_conntrack_expect *exp);
/* Add an expected connection: can have more than one per connection */
extern int nf_conntrack_expect_related(struct nf_conntrack_expect *exp);
extern void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp);
#endif /*_NF_CONNTRACK_HELPER_H*/
/*
* Copyright (C)2003,2004 USAGI/WIDE Project
*
* Header for use in defining a given L3 protocol for connection tracking.
*
* Author:
* Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
*
* Derived from include/netfilter_ipv4/ip_conntrack_protocol.h
*/
#ifndef _NF_CONNTRACK_L3PROTO_H
#define _NF_CONNTRACK_L3PROTO_H
#include <linux/seq_file.h>
#include <net/netfilter/nf_conntrack.h>
struct nf_conntrack_l3proto
{
/* Next pointer. */
struct list_head list;
/* L3 Protocol Family number. ex) PF_INET */
u_int16_t l3proto;
/* Protocol name */
const char *name;
/*
* Try to fill in the third arg: nhoff is offset of l3 proto
* hdr. Return true if possible.
*/
int (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple);
/*
* Invert the per-proto part of the tuple: ie. turn xmit into reply.
* Some packets can't be inverted: return 0 in that case.
*/
int (*invert_tuple)(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig);
/* Print out the per-protocol part of the tuple. */
int (*print_tuple)(struct seq_file *s,
const struct nf_conntrack_tuple *);
/* Print out the private part of the conntrack. */
int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
/* Returns verdict for packet, or -1 for invalid. */
int (*packet)(struct nf_conn *conntrack,
const struct sk_buff *skb,
enum ip_conntrack_info ctinfo);
/*
* Called when a new connection for this protocol found;
* returns TRUE if it's OK. If so, packet() called next.
*/
int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb);
/* Called when a conntrack entry is destroyed */
void (*destroy)(struct nf_conn *conntrack);
/*
* Called before tracking.
* *dataoff: offset of protocol header (TCP, UDP,...) in *pskb
* *protonum: protocol number
*/
int (*prepare)(struct sk_buff **pskb, unsigned int hooknum,
unsigned int *dataoff, u_int8_t *protonum);
u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple);
/* Module (if any) which this is connected to. */
struct module *me;
};
extern struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX];
/* Protocol registration. */
extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
static inline struct nf_conntrack_l3proto *
nf_ct_find_l3proto(u_int16_t l3proto)
{
return nf_ct_l3protos[l3proto];
}
/* Existing built-in protocols */
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
extern struct nf_conntrack_l3proto nf_conntrack_generic_l3proto;
#endif /*_NF_CONNTRACK_L3PROTO_H*/
/*
* Header for use in defining a given protocol for connection tracking.
*
* 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
* - generalized L3 protocol dependent part.
*
* Derived from include/linux/netfiter_ipv4/ip_conntrack_protcol.h
*/
#ifndef _NF_CONNTRACK_PROTOCOL_H
#define _NF_CONNTRACK_PROTOCOL_H
#include <net/netfilter/nf_conntrack.h>
struct seq_file;
struct nf_conntrack_protocol
{
/* Next pointer. */
struct list_head list;
/* L3 Protocol number. */
u_int16_t l3proto;
/* Protocol number. */
u_int8_t proto;
/* Protocol name */
const char *name;
/* Try to fill in the third arg: dataoff is offset past network protocol
hdr. Return true if possible. */
int (*pkt_to_tuple)(const struct sk_buff *skb,
unsigned int dataoff,
struct nf_conntrack_tuple *tuple);
/* Invert the per-proto part of the tuple: ie. turn xmit into reply.
* Some packets can't be inverted: return 0 in that case.
*/
int (*invert_tuple)(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig);
/* Print out the per-protocol part of the tuple. Return like seq_* */
int (*print_tuple)(struct seq_file *s,
const struct nf_conntrack_tuple *);
/* Print out the private part of the conntrack. */
int (*print_conntrack)(struct seq_file *s, const struct nf_conn *);
/* Returns verdict for packet, or -1 for invalid. */
int (*packet)(struct nf_conn *conntrack,
const struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
int pf,
unsigned int hooknum);
/* Called when a new connection for this protocol found;
* returns TRUE if it's OK. If so, packet() called next. */
int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb,
unsigned int dataoff);
/* Called when a conntrack entry is destroyed */
void (*destroy)(struct nf_conn *conntrack);
int (*error)(struct sk_buff *skb, unsigned int dataoff,
enum ip_conntrack_info *ctinfo,
int pf, unsigned int hooknum);
/* Module (if any) which this is connected to. */
struct module *me;
};
/* Existing built-in protocols */
extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp6;
extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4;
extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6;
extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
#define MAX_NF_CT_PROTO 256
extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX];
extern struct nf_conntrack_protocol *
nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol);
/* Protocol registration. */
extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto);
extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto);
/* Log invalid packets */
extern unsigned int nf_ct_log_invalid;
#ifdef CONFIG_SYSCTL
#ifdef DEBUG_INVALID_PACKETS
#define LOG_INVALID(proto) \
(nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW)
#else
#define LOG_INVALID(proto) \
((nf_ct_log_invalid == (proto) || nf_ct_log_invalid == IPPROTO_RAW) \
&& net_ratelimit())
#endif
#else
#define LOG_INVALID(proto) 0
#endif /* CONFIG_SYSCTL */
#endif /*_NF_CONNTRACK_PROTOCOL_H*/
/*
* Definitions and Declarations for tuple.
*
* 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
* - generalize L3 protocol dependent part.
*
* Derived from include/linux/netfiter_ipv4/ip_conntrack_tuple.h
*/
#ifndef _NF_CONNTRACK_TUPLE_H
#define _NF_CONNTRACK_TUPLE_H
#include <linux/netfilter/nf_conntrack_tuple_common.h>
/* A `tuple' is a structure containing the information to uniquely
identify a connection. ie. if two packets have the same tuple, they
are in the same connection; if not, they are not.
We divide the structure along "manipulatable" and
"non-manipulatable" lines, for the benefit of the NAT code.
*/
#define NF_CT_TUPLE_L3SIZE 4
/* The l3 protocol-specific manipulable parts of the tuple: always in
network order! */
union nf_conntrack_man_l3proto {
u_int32_t all[NF_CT_TUPLE_L3SIZE];
u_int32_t ip;
u_int32_t ip6[4];
};
/* The protocol-specific manipulable parts of the tuple: always in
network order! */
union nf_conntrack_man_proto
{
/* Add other protocols here. */
u_int16_t all;
struct {
u_int16_t port;
} tcp;
struct {
u_int16_t port;
} udp;
struct {
u_int16_t id;
} icmp;
struct {
u_int16_t port;
} sctp;
};
/* The manipulable part of the tuple. */
struct nf_conntrack_man
{
union nf_conntrack_man_l3proto u3;
union nf_conntrack_man_proto u;
/* Layer 3 protocol */
u_int16_t l3num;
};
/* This contains the information to distinguish a connection. */
struct nf_conntrack_tuple
{
struct nf_conntrack_man src;
/* These are the parts of the tuple which are fixed. */
struct {
union {
u_int32_t all[NF_CT_TUPLE_L3SIZE];
u_int32_t ip;
u_int32_t ip6[4];
} u3;
union {
/* Add other protocols here. */
u_int16_t all;
struct {
u_int16_t port;
} tcp;
struct {
u_int16_t port;
} udp;
struct {
u_int8_t type, code;
} icmp;
struct {
u_int16_t port;
} sctp;
} u;
/* The protocol. */
u_int8_t protonum;
/* The direction (for tuplehash) */
u_int8_t dir;
} dst;
};
/* This is optimized opposed to a memset of the whole structure. Everything we
* really care about is the source/destination unions */
#define NF_CT_TUPLE_U_BLANK(tuple) \
do { \
(tuple)->src.u.all = 0; \
(tuple)->dst.u.all = 0; \
memset(&(tuple)->src.u3, 0, sizeof((tuple)->src.u3)); \
memset(&(tuple)->dst.u3, 0, sizeof((tuple)->dst.u3)); \
} while (0)
#ifdef __KERNEL__
#define NF_CT_DUMP_TUPLE(tp) \
DEBUGP("tuple %p: %u %u %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu -> %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x %hu\n", \
(tp), (tp)->src.l3num, (tp)->dst.protonum, \
NIP6(*(struct in6_addr *)(tp)->src.u3.all), ntohs((tp)->src.u.all), \
NIP6(*(struct in6_addr *)(tp)->dst.u3.all), ntohs((tp)->dst.u.all))
/* If we're the first tuple, it's the original dir. */
#define NF_CT_DIRECTION(h) \
((enum ip_conntrack_dir)(h)->tuple.dst.dir)
/* Connections have two entries in the hash table: one for each way */
struct nf_conntrack_tuple_hash
{
struct list_head list;
struct nf_conntrack_tuple tuple;
};
#endif /* __KERNEL__ */
static inline int nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1,
const struct nf_conntrack_tuple *t2)
{
return (t1->src.u3.all[0] == t2->src.u3.all[0] &&
t1->src.u3.all[1] == t2->src.u3.all[1] &&
t1->src.u3.all[2] == t2->src.u3.all[2] &&
t1->src.u3.all[3] == t2->src.u3.all[3] &&
t1->src.u.all == t2->src.u.all &&
t1->src.l3num == t2->src.l3num &&
t1->dst.protonum == t2->dst.protonum);
}
static inline int nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1,
const struct nf_conntrack_tuple *t2)
{
return (t1->dst.u3.all[0] == t2->dst.u3.all[0] &&
t1->dst.u3.all[1] == t2->dst.u3.all[1] &&
t1->dst.u3.all[2] == t2->dst.u3.all[2] &&
t1->dst.u3.all[3] == t2->dst.u3.all[3] &&
t1->dst.u.all == t2->dst.u.all &&
t1->src.l3num == t2->src.l3num &&
t1->dst.protonum == t2->dst.protonum);
}
static inline int nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1,
const struct nf_conntrack_tuple *t2)
{
return nf_ct_tuple_src_equal(t1, t2) && nf_ct_tuple_dst_equal(t1, t2);
}
static inline int nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t,
const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *mask)
{
int count = 0;
for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
if ((t->src.u3.all[count] ^ tuple->src.u3.all[count]) &
mask->src.u3.all[count])
return 0;
}
for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
if ((t->dst.u3.all[count] ^ tuple->dst.u3.all[count]) &
mask->dst.u3.all[count])
return 0;
}
if ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all ||
(t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all ||
(t->src.l3num ^ tuple->src.l3num) & mask->src.l3num ||
(t->dst.protonum ^ tuple->dst.protonum) & mask->dst.protonum)
return 0;
return 1;
}
#endif /* _NF_CONNTRACK_TUPLE_H */
......@@ -336,6 +336,9 @@ void __kfree_skb(struct sk_buff *skb)
}
#ifdef CONFIG_NETFILTER
nf_conntrack_put(skb->nfct);
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_conntrack_put_reasm(skb->nfct_reasm);
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
nf_bridge_put(skb->nf_bridge);
#endif
......@@ -414,9 +417,17 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
C(nfct);
nf_conntrack_get(skb->nfct);
C(nfctinfo);
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
C(nfct_reasm);
nf_conntrack_get_reasm(skb->nfct_reasm);
#endif
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
C(ipvs_property);
#endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
C(nfct_reasm);
nf_conntrack_get_reasm(skb->nfct_reasm);
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
C(nf_bridge);
nf_bridge_get(skb->nf_bridge);
......@@ -474,6 +485,10 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->nfct = old->nfct;
nf_conntrack_get(old->nfct);
new->nfctinfo = old->nfctinfo;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
new->nfct_reasm = old->nfct_reasm;
nf_conntrack_get_reasm(old->nfct_reasm);
#endif
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
new->ipvs_property = old->ipvs_property;
#endif
......
......@@ -5,6 +5,20 @@
menu "IP: Netfilter Configuration"
depends on INET && NETFILTER
config NF_CONNTRACK_IPV4
tristate "IPv4 support for new connection tracking (EXPERIMENTAL)"
depends on EXPERIMENTAL && NF_CONNTRACK
---help---
Connection tracking keeps a record of what packets have passed
through your machine, in order to figure out how they are related
into connections.
This is IPv4 support on Layer 3 independent connection tracking.
Layer 3 independent connection tracking is experimental scheme
which generalize ip_conntrack to support other layer 3 protocols.
To compile it as a module, choose M here. If unsure, say N.
# connection tracking, helpers and protocols
config IP_NF_CONNTRACK
tristate "Connection tracking (required for masq/NAT)"
......@@ -317,7 +331,8 @@ config IP_NF_MATCH_TCPMSS
config IP_NF_MATCH_HELPER
tristate "Helper match support"
depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
depends on IP_NF_IPTABLES
depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
help
Helper matching allows you to match packets in dynamic connections
tracked by a conntrack-helper, ie. ip_conntrack_ftp
......@@ -326,7 +341,8 @@ config IP_NF_MATCH_HELPER
config IP_NF_MATCH_STATE
tristate "Connection state match support"
depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
depends on IP_NF_IPTABLES
depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
help
Connection state matching allows you to match packets based on their
relationship to a tracked connection (ie. previous packets). This
......@@ -336,7 +352,8 @@ config IP_NF_MATCH_STATE
config IP_NF_MATCH_CONNTRACK
tristate "Connection tracking match support"
depends on IP_NF_CONNTRACK && IP_NF_IPTABLES
depends on IP_NF_IPTABLES
depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
help
This is a general conntrack match module, a superset of the state match.
......@@ -422,7 +439,8 @@ config IP_NF_MATCH_COMMENT
config IP_NF_MATCH_CONNMARK
tristate 'Connection mark match support'
depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES
depends on IP_NF_IPTABLES
depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
help
This option adds a `connmark' match, which allows you to match the
connection mark value previously set for the session by `CONNMARK'.
......@@ -433,7 +451,8 @@ config IP_NF_MATCH_CONNMARK
config IP_NF_MATCH_CONNBYTES
tristate 'Connection byte/packet counter match support'
depends on IP_NF_CT_ACCT && IP_NF_IPTABLES
depends on IP_NF_IPTABLES
depends on IP_NF_CT_ACCT || (NF_CT_ACCT && NF_CONNTRACK_IPV4)
help
This option adds a `connbytes' match, which allows you to match the
number of bytes and/or packets for each direction within a connection.
......@@ -747,7 +766,8 @@ config IP_NF_TARGET_TTL
config IP_NF_TARGET_CONNMARK
tristate 'CONNMARK target support'
depends on IP_NF_CONNTRACK_MARK && IP_NF_MANGLE
depends on IP_NF_MANGLE
depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
help
This option adds a `CONNMARK' target, which allows one to manipulate
the connection mark value. Similar to the MARK target, but
......@@ -759,7 +779,8 @@ config IP_NF_TARGET_CONNMARK
config IP_NF_TARGET_CLUSTERIP
tristate "CLUSTERIP target support (EXPERIMENTAL)"
depends on IP_NF_CONNTRACK_MARK && IP_NF_IPTABLES && EXPERIMENTAL
depends on IP_NF_IPTABLES && EXPERIMENTAL
depends on IP_NF_CONNTRACK_MARK || (NF_CONNTRACK_MARK && NF_CONNTRACK_IPV4)
help
The CLUSTERIP target allows you to build load-balancing clusters of
network servers without having a dedicated load-balancing
......@@ -782,7 +803,7 @@ config IP_NF_RAW
config IP_NF_TARGET_NOTRACK
tristate 'NOTRACK target support'
depends on IP_NF_RAW
depends on IP_NF_CONNTRACK
depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
help
The NOTRACK target allows a select rule to specify
which packets *not* to enter the conntrack/NAT
......
......@@ -103,3 +103,9 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o
obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
# objects for l3 independent conntrack
nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
# l3 independent conntrack
obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
......@@ -1376,7 +1376,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
ip_conntrack_expect_put(exp);
}
}
write_unlock(&ip_conntrack_lock);
write_unlock_bh(&ip_conntrack_lock);
} else {
/* This basically means we have to flush everything*/
write_lock_bh(&ip_conntrack_lock);
......
......@@ -29,7 +29,7 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <net/netfilter/nf_conntrack_compat.h>
#define CLUSTERIP_VERSION "0.8"
......@@ -316,14 +316,14 @@ target(struct sk_buff **pskb,
{
const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
u_int32_t hash;
u_int32_t *mark, hash;
/* don't need to clusterip_config_get() here, since refcount
* is only decremented by destroy() - and ip_tables guarantees
* that the ->target() function isn't called after ->destroy() */
if (!ct) {
mark = nf_ct_get_mark((*pskb), &ctinfo);
if (mark == NULL) {
printk(KERN_ERR "CLUSTERIP: no conntrack!\n");
/* FIXME: need to drop invalid ones, since replies
* to outgoing connections of other nodes will be
......@@ -346,7 +346,7 @@ target(struct sk_buff **pskb,
switch (ctinfo) {
case IP_CT_NEW:
ct->mark = hash;
*mark = hash;
break;
case IP_CT_RELATED:
case IP_CT_RELATED+IP_CT_IS_REPLY:
......@@ -363,7 +363,7 @@ target(struct sk_buff **pskb,
#ifdef DEBUG_CLUSTERP
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
#endif
DEBUGP("hash=%u ct_hash=%u ", hash, ct->mark);
DEBUGP("hash=%u ct_hash=%u ", hash, *mark);
if (!clusterip_responsible(cipinfo->config, hash)) {
DEBUGP("not responsible\n");
return NF_DROP;
......
......@@ -29,7 +29,7 @@ MODULE_LICENSE("GPL");
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <net/netfilter/nf_conntrack_compat.h>
static unsigned int
target(struct sk_buff **pskb,
......@@ -43,24 +43,24 @@ target(struct sk_buff **pskb,
u_int32_t diff;
u_int32_t nfmark;
u_int32_t newmark;
u_int32_t ctinfo;
u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
if (ct) {
if (ctmark) {
switch(markinfo->mode) {
case IPT_CONNMARK_SET:
newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
if (newmark != ct->mark)
ct->mark = newmark;
newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
if (newmark != *ctmark)
*ctmark = newmark;
break;
case IPT_CONNMARK_SAVE:
newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
if (ct->mark != newmark)
ct->mark = newmark;
newmark = (*ctmark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
if (*ctmark != newmark)
*ctmark = newmark;
break;
case IPT_CONNMARK_RESTORE:
nfmark = (*pskb)->nfmark;
diff = (ct->mark ^ nfmark) & markinfo->mask;
diff = (*ctmark ^ nfmark) & markinfo->mask;
if (diff != 0)
(*pskb)->nfmark = nfmark ^ diff;
break;
......
......@@ -5,7 +5,7 @@
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <net/netfilter/nf_conntrack_compat.h>
static unsigned int
target(struct sk_buff **pskb,
......@@ -23,7 +23,7 @@ target(struct sk_buff **pskb,
If there is a real ct entry correspondig to this packet,
it'll hang aroun till timing out. We don't deal with it
for performance reasons. JK */
(*pskb)->nfct = &ip_conntrack_untracked.ct_general;
nf_ct_untrack(*pskb);
(*pskb)->nfctinfo = IP_CT_NEW;
nf_conntrack_get((*pskb)->nfct);
......
......@@ -10,7 +10,7 @@
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <net/netfilter/nf_conntrack_compat.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_connbytes.h>
......@@ -46,60 +46,59 @@ match(const struct sk_buff *skb,
int *hotdrop)
{
const struct ipt_connbytes_info *sinfo = matchinfo;
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct;
u_int64_t what = 0; /* initialize to make gcc happy */
const struct ip_conntrack_counter *counters;
if (!(ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)))
if (!(counters = nf_ct_get_counters(skb)))
return 0; /* no match */
switch (sinfo->what) {
case IPT_CONNBYTES_PKTS:
switch (sinfo->direction) {
case IPT_CONNBYTES_DIR_ORIGINAL:
what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
what = counters[IP_CT_DIR_ORIGINAL].packets;
break;
case IPT_CONNBYTES_DIR_REPLY:
what = ct->counters[IP_CT_DIR_REPLY].packets;
what = counters[IP_CT_DIR_REPLY].packets;
break;
case IPT_CONNBYTES_DIR_BOTH:
what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
what += ct->counters[IP_CT_DIR_REPLY].packets;
what = counters[IP_CT_DIR_ORIGINAL].packets;
what += counters[IP_CT_DIR_REPLY].packets;
break;
}
break;
case IPT_CONNBYTES_BYTES:
switch (sinfo->direction) {
case IPT_CONNBYTES_DIR_ORIGINAL:
what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
what = counters[IP_CT_DIR_ORIGINAL].bytes;
break;
case IPT_CONNBYTES_DIR_REPLY:
what = ct->counters[IP_CT_DIR_REPLY].bytes;
what = counters[IP_CT_DIR_REPLY].bytes;
break;
case IPT_CONNBYTES_DIR_BOTH:
what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
what += ct->counters[IP_CT_DIR_REPLY].bytes;
what = counters[IP_CT_DIR_ORIGINAL].bytes;
what += counters[IP_CT_DIR_REPLY].bytes;
break;
}
break;
case IPT_CONNBYTES_AVGPKT:
switch (sinfo->direction) {
case IPT_CONNBYTES_DIR_ORIGINAL:
what = div64_64(ct->counters[IP_CT_DIR_ORIGINAL].bytes,
ct->counters[IP_CT_DIR_ORIGINAL].packets);
what = div64_64(counters[IP_CT_DIR_ORIGINAL].bytes,
counters[IP_CT_DIR_ORIGINAL].packets);
break;
case IPT_CONNBYTES_DIR_REPLY:
what = div64_64(ct->counters[IP_CT_DIR_REPLY].bytes,
ct->counters[IP_CT_DIR_REPLY].packets);
what = div64_64(counters[IP_CT_DIR_REPLY].bytes,
counters[IP_CT_DIR_REPLY].packets);
break;
case IPT_CONNBYTES_DIR_BOTH:
{
u_int64_t bytes;
u_int64_t pkts;
bytes = ct->counters[IP_CT_DIR_ORIGINAL].bytes +
ct->counters[IP_CT_DIR_REPLY].bytes;
pkts = ct->counters[IP_CT_DIR_ORIGINAL].packets+
ct->counters[IP_CT_DIR_REPLY].packets;
bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
counters[IP_CT_DIR_REPLY].bytes;
pkts = counters[IP_CT_DIR_ORIGINAL].packets+
counters[IP_CT_DIR_REPLY].packets;
/* FIXME_THEORETICAL: what to do if sum
* overflows ? */
......
......@@ -28,7 +28,7 @@ MODULE_LICENSE("GPL");
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_connmark.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <net/netfilter/nf_conntrack_compat.h>
static int
match(const struct sk_buff *skb,
......@@ -39,12 +39,12 @@ match(const struct sk_buff *skb,
int *hotdrop)
{
const struct ipt_connmark_info *info = matchinfo;
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
if (!ct)
u_int32_t ctinfo;
const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo);
if (!ctmark)
return 0;
return ((ct->mark & info->mask) == info->mark) ^ info->invert;
return (((*ctmark) & info->mask) == info->mark) ^ info->invert;
}
static int
......
......@@ -10,7 +10,14 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
#else
#include <net/netfilter/nf_conntrack.h>
#endif
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_conntrack.h>
......@@ -18,6 +25,8 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
MODULE_DESCRIPTION("iptables connection tracking match module");
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
static int
match(const struct sk_buff *skb,
const struct net_device *in,
......@@ -102,6 +111,93 @@ match(const struct sk_buff *skb,
return 1;
}
#else /* CONFIG_IP_NF_CONNTRACK */
static int
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
int *hotdrop)
{
const struct ipt_conntrack_info *sinfo = matchinfo;
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
unsigned int statebit;
ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
if (ct == &nf_conntrack_untracked)
statebit = IPT_CONNTRACK_STATE_UNTRACKED;
else if (ct)
statebit = IPT_CONNTRACK_STATE_BIT(ctinfo);
else
statebit = IPT_CONNTRACK_STATE_INVALID;
if(sinfo->flags & IPT_CONNTRACK_STATE) {
if (ct) {
if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip !=
ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip)
statebit |= IPT_CONNTRACK_STATE_SNAT;
if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip !=
ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip)
statebit |= IPT_CONNTRACK_STATE_DNAT;
}
if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_PROTO) {
if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_ORIGDST) {
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_REPLSRC) {
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_REPLDST) {
if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_STATUS) {
if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS))
return 0;
}
if(sinfo->flags & IPT_CONNTRACK_EXPIRES) {
unsigned long expires;
if(!ct)
return 0;
expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0;
if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES))
return 0;
}
return 1;
}
#endif /* CONFIG_NF_IP_CONNTRACK */
static int check(const char *tablename,
const struct ipt_ip *ip,
void *matchinfo,
......
......@@ -13,9 +13,15 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#else
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_helper.h>
#endif
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_helper.h>
......@@ -29,6 +35,7 @@ MODULE_DESCRIPTION("iptables helper match module");
#define DEBUGP(format, args...)
#endif
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
static int
match(const struct sk_buff *skb,
const struct net_device *in,
......@@ -73,6 +80,53 @@ out_unlock:
return ret;
}
#else /* CONFIG_IP_NF_CONNTRACK */
static int
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const void *matchinfo,
int offset,
int *hotdrop)
{
const struct ipt_helper_info *info = matchinfo;
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
int ret = info->invert;
ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
if (!ct) {
DEBUGP("ipt_helper: Eek! invalid conntrack?\n");
return ret;
}
if (!ct->master) {
DEBUGP("ipt_helper: conntrack %p has no master\n", ct);
return ret;
}
read_lock_bh(&nf_conntrack_lock);
if (!ct->master->helper) {
DEBUGP("ipt_helper: master ct %p has no helper\n",
exp->expectant);
goto out_unlock;
}
DEBUGP("master's name = %s , info->name = %s\n",
ct->master->helper->name, info->name);
if (info->name[0] == '\0')
ret ^= 1;
else
ret ^= !strncmp(ct->master->helper->name, info->name,
strlen(ct->master->helper->name));
out_unlock:
read_unlock_bh(&nf_conntrack_lock);
return ret;
}
#endif
static int check(const char *tablename,
const struct ipt_ip *ip,
void *matchinfo,
......
......@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <net/netfilter/nf_conntrack_compat.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_state.h>
......@@ -30,9 +30,9 @@ match(const struct sk_buff *skb,
enum ip_conntrack_info ctinfo;
unsigned int statebit;
if (skb->nfct == &ip_conntrack_untracked.ct_general)
if (nf_ct_is_untracked(skb))
statebit = IPT_STATE_UNTRACKED;
else if (!ip_conntrack_get(skb, &ctinfo))
else if (!nf_ct_get_ctinfo(skb, &ctinfo))
statebit = IPT_STATE_INVALID;
else
statebit = IPT_STATE_BIT(ctinfo);
......
This diff is collapsed.
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
* - enable working with Layer 3 protocol independent connection tracking.
*
* Derived from net/ipv4/netfilter/ip_conntrack_proto_icmp.c
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/netfilter.h>
#include <linux/in.h>
#include <linux/icmp.h>
#include <linux/seq_file.h>
#include <net/ip.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4.h>
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_protocol.h>
#include <net/netfilter/nf_conntrack_core.h>
unsigned long nf_ct_icmp_timeout = 30*HZ;
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
static int icmp_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff,
struct nf_conntrack_tuple *tuple)
{
struct icmphdr _hdr, *hp;
hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
if (hp == NULL)
return 0;
tuple->dst.u.icmp.type = hp->type;
tuple->src.u.icmp.id = hp->un.echo.id;
tuple->dst.u.icmp.code = hp->code;
return 1;
}
static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *orig)
{
/* Add 1; spaces filled with 0. */
static u_int8_t invmap[]
= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
[ICMP_ECHOREPLY] = ICMP_ECHO + 1,
[ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
[ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
[ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
[ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
[ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
[ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1};
if (orig->dst.u.icmp.type >= sizeof(invmap)
|| !invmap[orig->dst.u.icmp.type])
return 0;
tuple->src.u.icmp.id = orig->src.u.icmp.id;
tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1;
tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
return 1;
}
/* Print out the per-protocol part of the tuple. */
static int icmp_print_tuple(struct seq_file *s,
const struct nf_conntrack_tuple *tuple)
{
return seq_printf(s, "type=%u code=%u id=%u ",
tuple->dst.u.icmp.type,
tuple->dst.u.icmp.code,
ntohs(tuple->src.u.icmp.id));
}
/* Print out the private part of the conntrack. */
static int icmp_print_conntrack(struct seq_file *s,
const struct nf_conn *conntrack)
{
return 0;
}
/* Returns verdict for packet, or -1 for invalid. */
static int icmp_packet(struct nf_conn *ct,
const struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
int pf,
unsigned int hooknum)
{
/* Try to delete connection immediately after all replies:
won't actually vanish as we still have skb, and del_timer
means this will only run once even if count hits zero twice
(theoretically possible with SMP) */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
if (atomic_dec_and_test(&ct->proto.icmp.count)
&& del_timer(&ct->timeout))
ct->timeout.function((unsigned long)ct);
} else {
atomic_inc(&ct->proto.icmp.count);
nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout);
}
return NF_ACCEPT;
}
/* Called when a new connection for this protocol found. */
static int icmp_new(struct nf_conn *conntrack,
const struct sk_buff *skb, unsigned int dataoff)
{
static u_int8_t valid_new[]
= { [ICMP_ECHO] = 1,
[ICMP_TIMESTAMP] = 1,
[ICMP_INFO_REQUEST] = 1,
[ICMP_ADDRESS] = 1 };
if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
|| !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
/* Can't create a new ICMP `conn' with this. */
DEBUGP("icmp: can't create new conn with type %u\n",
conntrack->tuplehash[0].tuple.dst.u.icmp.type);
NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
return 0;
}
atomic_set(&conntrack->proto.icmp.count, 0);
return 1;
}
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
static int
icmp_error_message(struct sk_buff *skb,
enum ip_conntrack_info *ctinfo,
unsigned int hooknum)
{
struct nf_conntrack_tuple innertuple, origtuple;
struct {
struct icmphdr icmp;
struct iphdr ip;
} _in, *inside;
struct nf_conntrack_protocol *innerproto;
struct nf_conntrack_tuple_hash *h;
int dataoff;
NF_CT_ASSERT(skb->nfct == NULL);
/* Not enough header? */
inside = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_in), &_in);
if (inside == NULL)
return -NF_ACCEPT;
/* Ignore ICMP's containing fragments (shouldn't happen) */
if (inside->ip.frag_off & htons(IP_OFFSET)) {
DEBUGP("icmp_error_message: fragment of proto %u\n",
inside->ip.protocol);
return -NF_ACCEPT;
}
innerproto = nf_ct_find_proto(PF_INET, inside->ip.protocol);
dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp);
/* Are they talking about one of our connections? */
if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
inside->ip.protocol, &origtuple,
&nf_conntrack_l3proto_ipv4, innerproto)) {
DEBUGP("icmp_error_message: ! get_tuple p=%u",
inside->ip.protocol);
return -NF_ACCEPT;
}
/* Ordinarily, we'd expect the inverted tupleproto, but it's
been preserved inside the ICMP. */
if (!nf_ct_invert_tuple(&innertuple, &origtuple,
&nf_conntrack_l3proto_ipv4, innerproto)) {
DEBUGP("icmp_error_message: no match\n");
return -NF_ACCEPT;
}
*ctinfo = IP_CT_RELATED;
h = nf_conntrack_find_get(&innertuple, NULL);
if (!h) {
/* Locally generated ICMPs will match inverted if they
haven't been SNAT'ed yet */
/* FIXME: NAT code has to handle half-done double NAT --RR */
if (hooknum == NF_IP_LOCAL_OUT)
h = nf_conntrack_find_get(&origtuple, NULL);
if (!h) {
DEBUGP("icmp_error_message: no match\n");
return -NF_ACCEPT;
}
/* Reverse direction from that found */
if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
*ctinfo += IP_CT_IS_REPLY;
} else {
if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
*ctinfo += IP_CT_IS_REPLY;
}
/* Update skb to refer to this connection */
skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
skb->nfctinfo = *ctinfo;
return -NF_ACCEPT;
}
/* Small and modified version of icmp_rcv */
static int
icmp_error(struct sk_buff *skb, unsigned int dataoff,
enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
{
struct icmphdr _ih, *icmph;
/* Not enough header? */
icmph = skb_header_pointer(skb, skb->nh.iph->ihl*4, sizeof(_ih), &_ih);
if (icmph == NULL) {
if (LOG_INVALID(IPPROTO_ICMP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
"nf_ct_icmp: short packet ");
return -NF_ACCEPT;
}
/* See ip_conntrack_proto_tcp.c */
if (hooknum != NF_IP_PRE_ROUTING)
goto checksum_skipped;
switch (skb->ip_summed) {
case CHECKSUM_HW:
if (!(u16)csum_fold(skb->csum))
break;
if (LOG_INVALID(IPPROTO_ICMP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
"nf_ct_icmp: bad HW ICMP checksum ");
return -NF_ACCEPT;
case CHECKSUM_NONE:
if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))) {
if (LOG_INVALID(IPPROTO_ICMP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL,
NULL,
"nf_ct_icmp: bad ICMP checksum ");
return -NF_ACCEPT;
}
default:
break;
}
checksum_skipped:
/*
* 18 is the highest 'known' ICMP type. Anything else is a mystery
*
* RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently
* discarded.
*/
if (icmph->type > NR_ICMP_TYPES) {
if (LOG_INVALID(IPPROTO_ICMP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
"nf_ct_icmp: invalid ICMP type ");
return -NF_ACCEPT;
}
/* Need to track icmp error message? */
if (icmph->type != ICMP_DEST_UNREACH
&& icmph->type != ICMP_SOURCE_QUENCH
&& icmph->type != ICMP_TIME_EXCEEDED
&& icmph->type != ICMP_PARAMETERPROB
&& icmph->type != ICMP_REDIRECT)
return NF_ACCEPT;
return icmp_error_message(skb, ctinfo, hooknum);
}
struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
{
.list = { NULL, NULL },
.l3proto = PF_INET,
.proto = IPPROTO_ICMP,
.name = "icmp",
.pkt_to_tuple = icmp_pkt_to_tuple,
.invert_tuple = icmp_invert_tuple,
.print_tuple = icmp_print_tuple,
.print_conntrack = icmp_print_conntrack,
.packet = icmp_packet,
.new = icmp_new,
.error = icmp_error,
.destroy = NULL,
.me = NULL
};
EXPORT_SYMBOL(nf_conntrack_protocol_icmp);
......@@ -176,6 +176,11 @@ resubmit:
if (ipprot->flags & INET6_PROTO_FINAL) {
struct ipv6hdr *hdr;
/* Free reference early: we don't need it any more,
and it may hold ip_conntrack module loaded
indefinitely. */
nf_reset(skb);
skb_postpull_rcsum(skb, skb->nh.raw,
skb->h.raw - skb->nh.raw);
hdr = skb->nh.ipv6h;
......
......@@ -441,9 +441,15 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
#ifdef CONFIG_NETFILTER
to->nfmark = from->nfmark;
/* Connection association is same as pre-frag packet */
nf_conntrack_put(to->nfct);
to->nfct = from->nfct;
nf_conntrack_get(to->nfct);
to->nfctinfo = from->nfctinfo;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
nf_conntrack_put_reasm(to->nfct_reasm);
to->nfct_reasm = from->nfct_reasm;
nf_conntrack_get_reasm(to->nfct_reasm);
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
nf_bridge_put(to->nf_bridge);
to->nf_bridge = from->nf_bridge;
......
......@@ -278,5 +278,19 @@ config IP6_NF_RAW
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `N'.
config NF_CONNTRACK_IPV6
tristate "IPv6 support for new connection tracking (EXPERIMENTAL)"
depends on EXPERIMENTAL && NF_CONNTRACK
---help---
Connection tracking keeps a record of what packets have passed
through your machine, in order to figure out how they are related
into connections.
This is IPv6 support on Layer 3 independent connection tracking.
Layer 3 independent connection tracking is experimental scheme
which generalize ip_conntrack to support other layer 3 protocols.
To compile it as a module, choose M here. If unsure, say N.
endmenu
......@@ -27,3 +27,9 @@ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
# objects for l3 independent conntrack
nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
# l3 independent conntrack
obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o
This diff is collapsed.
/*
* Copyright (C)2003,2004 USAGI/WIDE Project
*
* 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.
*
* Author:
* Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
*
* 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
* - ICMPv6 tracking support. Derived from the original ip_conntrack code
* net/ipv4/netfilter/ip_conntrack_proto_icmp.c which had the following
* copyright information:
* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
*/
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/in6.h>
#include <linux/icmpv6.h>
#include <linux/ipv6.h>
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
#include <linux/seq_file.h>
#include <linux/netfilter_ipv6.h>
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_protocol.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/ipv6/nf_conntrack_icmpv6.h>
unsigned long nf_ct_icmpv6_timeout = 30*HZ;
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff,
struct nf_conntrack_tuple *tuple)
{
struct icmp6hdr _hdr, *hp;
hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
if (hp == NULL)
return 0;
tuple->dst.u.icmp.type = hp->icmp6_type;
tuple->src.u.icmp.id = hp->icmp6_identifier;
tuple->dst.u.icmp.code = hp->icmp6_code;
return 1;
}
static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *orig)
{
/* Add 1; spaces filled with 0. */
static u_int8_t invmap[] = {
[ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1,
[ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1,
[ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1,
[ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1
};
__u8 type = orig->dst.u.icmp.type - 128;
if (type >= sizeof(invmap) || !invmap[type])
return 0;
tuple->src.u.icmp.id = orig->src.u.icmp.id;
tuple->dst.u.icmp.type = invmap[type] - 1;
tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
return 1;
}
/* Print out the per-protocol part of the tuple. */
static int icmpv6_print_tuple(struct seq_file *s,
const struct nf_conntrack_tuple *tuple)
{
return seq_printf(s, "type=%u code=%u id=%u ",
tuple->dst.u.icmp.type,
tuple->dst.u.icmp.code,
ntohs(tuple->src.u.icmp.id));
}
/* Print out the private part of the conntrack. */
static int icmpv6_print_conntrack(struct seq_file *s,
const struct nf_conn *conntrack)
{
return 0;
}
/* Returns verdict for packet, or -1 for invalid. */
static int icmpv6_packet(struct nf_conn *ct,
const struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
int pf,
unsigned int hooknum)
{
/* Try to delete connection immediately after all replies:
won't actually vanish as we still have skb, and del_timer
means this will only run once even if count hits zero twice
(theoretically possible with SMP) */
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
if (atomic_dec_and_test(&ct->proto.icmp.count)
&& del_timer(&ct->timeout))
ct->timeout.function((unsigned long)ct);
} else {
atomic_inc(&ct->proto.icmp.count);
nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout);
}
return NF_ACCEPT;
}
/* Called when a new connection for this protocol found. */
static int icmpv6_new(struct nf_conn *conntrack,
const struct sk_buff *skb,
unsigned int dataoff)
{
static u_int8_t valid_new[] = {
[ICMPV6_ECHO_REQUEST - 128] = 1,
[ICMPV6_NI_QUERY - 128] = 1
};
if (conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128 >= sizeof(valid_new)
|| !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type - 128]) {
/* Can't create a new ICMPv6 `conn' with this. */
DEBUGP("icmp: can't create new conn with type %u\n",
conntrack->tuplehash[0].tuple.dst.u.icmp.type);
NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
return 0;
}
atomic_set(&conntrack->proto.icmp.count, 0);
return 1;
}
extern int
nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len);
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
static int
icmpv6_error_message(struct sk_buff *skb,
unsigned int icmp6off,
enum ip_conntrack_info *ctinfo,
unsigned int hooknum)
{
struct nf_conntrack_tuple intuple, origtuple;
struct nf_conntrack_tuple_hash *h;
struct icmp6hdr _hdr, *hp;
unsigned int inip6off;
struct nf_conntrack_protocol *inproto;
u_int8_t inprotonum;
unsigned int inprotoff;
NF_CT_ASSERT(skb->nfct == NULL);
hp = skb_header_pointer(skb, icmp6off, sizeof(_hdr), &_hdr);
if (hp == NULL) {
DEBUGP("icmpv6_error: Can't get ICMPv6 hdr.\n");
return -NF_ACCEPT;
}
inip6off = icmp6off + sizeof(_hdr);
if (skb_copy_bits(skb, inip6off+offsetof(struct ipv6hdr, nexthdr),
&inprotonum, sizeof(inprotonum)) != 0) {
DEBUGP("icmpv6_error: Can't get nexthdr in inner IPv6 header.\n");
return -NF_ACCEPT;
}
inprotoff = nf_ct_ipv6_skip_exthdr(skb,
inip6off + sizeof(struct ipv6hdr),
&inprotonum,
skb->len - inip6off
- sizeof(struct ipv6hdr));
if ((inprotoff < 0) || (inprotoff > skb->len) ||
(inprotonum == NEXTHDR_FRAGMENT)) {
DEBUGP("icmpv6_error: Can't get protocol header in ICMPv6 payload.\n");
return -NF_ACCEPT;
}
inproto = nf_ct_find_proto(PF_INET6, inprotonum);
/* Are they talking about one of our connections? */
if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum,
&origtuple, &nf_conntrack_l3proto_ipv6, inproto)) {
DEBUGP("icmpv6_error: Can't get tuple\n");
return -NF_ACCEPT;
}
/* Ordinarily, we'd expect the inverted tupleproto, but it's
been preserved inside the ICMP. */
if (!nf_ct_invert_tuple(&intuple, &origtuple,
&nf_conntrack_l3proto_ipv6, inproto)) {
DEBUGP("icmpv6_error: Can't invert tuple\n");
return -NF_ACCEPT;
}
*ctinfo = IP_CT_RELATED;
h = nf_conntrack_find_get(&intuple, NULL);
if (!h) {
DEBUGP("icmpv6_error: no match\n");
return -NF_ACCEPT;
} else {
if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
*ctinfo += IP_CT_IS_REPLY;
}
/* Update skb to refer to this connection */
skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
skb->nfctinfo = *ctinfo;
return -NF_ACCEPT;
}
static int
icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
enum ip_conntrack_info *ctinfo, int pf, unsigned int hooknum)
{
struct icmp6hdr _ih, *icmp6h;
icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
if (icmp6h == NULL) {
if (LOG_INVALID(IPPROTO_ICMPV6))
nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
"nf_ct_icmpv6: short packet ");
return -NF_ACCEPT;
}
if (hooknum != NF_IP6_PRE_ROUTING)
goto skipped;
/* Ignore it if the checksum's bogus. */
if (csum_ipv6_magic(&skb->nh.ipv6h->saddr, &skb->nh.ipv6h->daddr,
skb->len - dataoff, IPPROTO_ICMPV6,
skb_checksum(skb, dataoff,
skb->len - dataoff, 0))) {
nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
"nf_ct_icmpv6: ICMPv6 checksum failed\n");
return -NF_ACCEPT;
}
skipped:
/* is not error message ? */
if (icmp6h->icmp6_type >= 128)
return NF_ACCEPT;
return icmpv6_error_message(skb, dataoff, ctinfo, hooknum);
}
struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 =
{
.l3proto = PF_INET6,
.proto = IPPROTO_ICMPV6,
.name = "icmpv6",
.pkt_to_tuple = icmpv6_pkt_to_tuple,
.invert_tuple = icmpv6_invert_tuple,
.print_tuple = icmpv6_print_tuple,
.print_conntrack = icmpv6_print_conntrack,
.packet = icmpv6_packet,
.new = icmpv6_new,
.error = icmpv6_error,
};
EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6);
This diff is collapsed.
......@@ -174,9 +174,11 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
/* Not releasing hash table! */
if (clone)
if (clone) {
nf_reset(clone);
rawv6_rcv(sk, clone);
}
}
sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr,
IP6CB(skb)->iif);
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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