[NETFILTER]: Remove IPv4 only connection tracking/NAT
Remove the obsolete IPv4 only connection tracking/NAT as scheduled in feature-removal-schedule. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
ce18afe57b
Коммит
587aa64163
|
@ -211,15 +211,6 @@ Who: Adrian Bunk <bunk@stusta.de>
|
|||
|
||||
---------------------------
|
||||
|
||||
What: IPv4 only connection tracking/NAT/helpers
|
||||
When: 2.6.22
|
||||
Why: The new layer 3 independant connection tracking replaces the old
|
||||
IPv4 only version. After some stabilization of the new code the
|
||||
old one will be removed.
|
||||
Who: Patrick McHardy <kaber@trash.net>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: ACPI hooks (X86_SPEEDSTEP_CENTRINO_ACPI) in speedstep-centrino driver
|
||||
When: December 2006
|
||||
Why: Speedstep-centrino driver with ACPI hooks and acpi-cpufreq driver are
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
header-y += ip_conntrack_helper.h
|
||||
header-y += ip_conntrack_protocol.h
|
||||
header-y += ip_conntrack_sctp.h
|
||||
header-y += ip_conntrack_tcp.h
|
||||
header-y += ip_conntrack_tftp.h
|
||||
header-y += ip_nat_pptp.h
|
||||
header-y += ipt_addrtype.h
|
||||
header-y += ipt_ah.h
|
||||
header-y += ipt_CLASSIFY.h
|
||||
|
@ -49,13 +43,5 @@ header-y += ipt_ttl.h
|
|||
header-y += ipt_TTL.h
|
||||
header-y += ipt_ULOG.h
|
||||
|
||||
unifdef-y += ip_conntrack.h
|
||||
unifdef-y += ip_conntrack_h323.h
|
||||
unifdef-y += ip_conntrack_irc.h
|
||||
unifdef-y += ip_conntrack_pptp.h
|
||||
unifdef-y += ip_conntrack_proto_gre.h
|
||||
unifdef-y += ip_conntrack_tuple.h
|
||||
unifdef-y += ip_nat.h
|
||||
unifdef-y += ip_nat_rule.h
|
||||
unifdef-y += ip_queue.h
|
||||
unifdef-y += ip_tables.h
|
||||
|
|
|
@ -1,402 +0,0 @@
|
|||
#ifndef _IP_CONNTRACK_H
|
||||
#define _IP_CONNTRACK_H
|
||||
|
||||
#include <linux/netfilter/nf_conntrack_common.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include <linux/timer.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_sctp.h>
|
||||
|
||||
/* per conntrack: protocol private data */
|
||||
union ip_conntrack_proto {
|
||||
/* insert conntrack proto private data here */
|
||||
struct ip_ct_gre gre;
|
||||
struct ip_ct_sctp sctp;
|
||||
struct ip_ct_tcp tcp;
|
||||
struct ip_ct_icmp icmp;
|
||||
};
|
||||
|
||||
union ip_conntrack_expect_proto {
|
||||
/* insert expect proto private data here */
|
||||
};
|
||||
|
||||
/* Add protocol helper include file here */
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
|
||||
|
||||
/* per conntrack: application helper private data */
|
||||
union ip_conntrack_help {
|
||||
/* insert conntrack helper private data (master) here */
|
||||
struct ip_ct_h323_master ct_h323_info;
|
||||
struct ip_ct_pptp_master ct_pptp_info;
|
||||
struct ip_ct_ftp_master ct_ftp_info;
|
||||
struct ip_ct_irc_master ct_irc_info;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IP_NF_NAT_NEEDED
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_pptp.h>
|
||||
|
||||
/* per conntrack: nat application helper private data */
|
||||
union ip_conntrack_nat_help {
|
||||
/* insert nat helper private data here */
|
||||
struct ip_nat_pptp nat_pptp_info;
|
||||
};
|
||||
#endif
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#ifdef CONFIG_NETFILTER_DEBUG
|
||||
#define IP_NF_ASSERT(x) \
|
||||
do { \
|
||||
if (!(x)) \
|
||||
/* Wooah! I'm tripping my conntrack in a frenzy of \
|
||||
netplay... */ \
|
||||
printk("NF_IP_ASSERT: %s:%i(%s)\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__); \
|
||||
} while(0)
|
||||
#else
|
||||
#define IP_NF_ASSERT(x)
|
||||
#endif
|
||||
|
||||
struct ip_conntrack_helper;
|
||||
|
||||
struct ip_conntrack
|
||||
{
|
||||
/* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
|
||||
plus 1 for any connection(s) we are `master' for */
|
||||
struct nf_conntrack ct_general;
|
||||
|
||||
/* Have we seen traffic both ways yet? (bitset) */
|
||||
unsigned long status;
|
||||
|
||||
/* Timer function; drops refcnt when it goes off. */
|
||||
struct timer_list timeout;
|
||||
|
||||
#ifdef CONFIG_IP_NF_CT_ACCT
|
||||
/* Accounting Information (same cache line as other written members) */
|
||||
struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
|
||||
#endif
|
||||
/* If we were expected by an expectation, this will be it */
|
||||
struct ip_conntrack *master;
|
||||
|
||||
/* Current number of expected connections */
|
||||
unsigned int expecting;
|
||||
|
||||
/* Unique ID that identifies this conntrack*/
|
||||
unsigned int id;
|
||||
|
||||
/* Helper, if any. */
|
||||
struct ip_conntrack_helper *helper;
|
||||
|
||||
/* Storage reserved for other modules: */
|
||||
union ip_conntrack_proto proto;
|
||||
|
||||
union ip_conntrack_help help;
|
||||
|
||||
#ifdef CONFIG_IP_NF_NAT_NEEDED
|
||||
struct {
|
||||
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
|
||||
} nat;
|
||||
#endif /* CONFIG_IP_NF_NAT_NEEDED */
|
||||
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
|
||||
u_int32_t mark;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK
|
||||
u_int32_t secmark;
|
||||
#endif
|
||||
|
||||
/* Traversed often, so hopefully in different cacheline to top */
|
||||
/* These are my tuples; original and reply */
|
||||
struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
|
||||
};
|
||||
|
||||
struct ip_conntrack_expect
|
||||
{
|
||||
/* Internal linked list (global expectation list) */
|
||||
struct list_head list;
|
||||
|
||||
/* We expect this tuple, with the following mask */
|
||||
struct ip_conntrack_tuple tuple, mask;
|
||||
|
||||
/* Function to call after setup and insertion */
|
||||
void (*expectfn)(struct ip_conntrack *new,
|
||||
struct ip_conntrack_expect *this);
|
||||
|
||||
/* The conntrack of the master connection */
|
||||
struct ip_conntrack *master;
|
||||
|
||||
/* Timer function; deletes the expectation. */
|
||||
struct timer_list timeout;
|
||||
|
||||
/* Usage count. */
|
||||
atomic_t use;
|
||||
|
||||
/* Unique ID */
|
||||
unsigned int id;
|
||||
|
||||
/* Flags */
|
||||
unsigned int flags;
|
||||
|
||||
#ifdef CONFIG_IP_NF_NAT_NEEDED
|
||||
__be32 saved_ip;
|
||||
/* This is the original per-proto part, used to map the
|
||||
* expected connection the way the recipient expects. */
|
||||
union ip_conntrack_manip_proto saved_proto;
|
||||
/* Direction relative to the master connection. */
|
||||
enum ip_conntrack_dir dir;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define IP_CT_EXPECT_PERMANENT 0x1
|
||||
|
||||
static inline struct ip_conntrack *
|
||||
tuplehash_to_ctrack(const struct ip_conntrack_tuple_hash *hash)
|
||||
{
|
||||
return container_of(hash, struct ip_conntrack,
|
||||
tuplehash[hash->tuple.dst.dir]);
|
||||
}
|
||||
|
||||
/* get master conntrack via master expectation */
|
||||
#define master_ct(conntr) (conntr->master)
|
||||
|
||||
/* Alter reply tuple (maybe alter helper). */
|
||||
extern void
|
||||
ip_conntrack_alter_reply(struct ip_conntrack *conntrack,
|
||||
const struct ip_conntrack_tuple *newreply);
|
||||
|
||||
/* Is this tuple taken? (ignoring any belonging to the given
|
||||
conntrack). */
|
||||
extern int
|
||||
ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack *ignored_conntrack);
|
||||
|
||||
/* Return conntrack_info and tuple hash for given skb. */
|
||||
static inline struct ip_conntrack *
|
||||
ip_conntrack_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
|
||||
{
|
||||
*ctinfo = skb->nfctinfo;
|
||||
return (struct ip_conntrack *)skb->nfct;
|
||||
}
|
||||
|
||||
/* decrement reference count on a conntrack */
|
||||
static inline void
|
||||
ip_conntrack_put(struct ip_conntrack *ct)
|
||||
{
|
||||
IP_NF_ASSERT(ct);
|
||||
nf_conntrack_put(&ct->ct_general);
|
||||
}
|
||||
|
||||
extern int invert_tuplepr(struct ip_conntrack_tuple *inverse,
|
||||
const struct ip_conntrack_tuple *orig);
|
||||
|
||||
extern void __ip_ct_refresh_acct(struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
const struct sk_buff *skb,
|
||||
unsigned long extra_jiffies,
|
||||
int do_acct);
|
||||
|
||||
/* Refresh conntrack for this many jiffies and do accounting */
|
||||
static inline void ip_ct_refresh_acct(struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
const struct sk_buff *skb,
|
||||
unsigned long extra_jiffies)
|
||||
{
|
||||
__ip_ct_refresh_acct(ct, ctinfo, skb, extra_jiffies, 1);
|
||||
}
|
||||
|
||||
/* Refresh conntrack for this many jiffies */
|
||||
static inline void ip_ct_refresh(struct ip_conntrack *ct,
|
||||
const struct sk_buff *skb,
|
||||
unsigned long extra_jiffies)
|
||||
{
|
||||
__ip_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0);
|
||||
}
|
||||
|
||||
/* These are for NAT. Icky. */
|
||||
/* Update TCP window tracking data when NAT mangles the packet */
|
||||
extern void ip_conntrack_tcp_update(struct sk_buff *skb,
|
||||
struct ip_conntrack *conntrack,
|
||||
enum ip_conntrack_dir dir);
|
||||
|
||||
/* Call me when a conntrack is destroyed. */
|
||||
extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack);
|
||||
|
||||
/* Fake conntrack entry for untracked connections */
|
||||
extern struct ip_conntrack ip_conntrack_untracked;
|
||||
|
||||
/* Returns new sk_buff, or NULL */
|
||||
struct sk_buff *
|
||||
ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user);
|
||||
|
||||
/* Iterate over all conntracks: if iter returns true, it's deleted. */
|
||||
extern void
|
||||
ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *data),
|
||||
void *data);
|
||||
|
||||
extern struct ip_conntrack_helper *
|
||||
__ip_conntrack_helper_find_byname(const char *);
|
||||
extern struct ip_conntrack_helper *
|
||||
ip_conntrack_helper_find_get(const struct ip_conntrack_tuple *tuple);
|
||||
extern void ip_conntrack_helper_put(struct ip_conntrack_helper *helper);
|
||||
|
||||
extern struct ip_conntrack_protocol *
|
||||
__ip_conntrack_proto_find(u_int8_t protocol);
|
||||
extern struct ip_conntrack_protocol *
|
||||
ip_conntrack_proto_find_get(u_int8_t protocol);
|
||||
extern void ip_conntrack_proto_put(struct ip_conntrack_protocol *proto);
|
||||
|
||||
extern void ip_ct_remove_expectations(struct ip_conntrack *ct);
|
||||
|
||||
extern struct ip_conntrack *ip_conntrack_alloc(struct ip_conntrack_tuple *,
|
||||
struct ip_conntrack_tuple *);
|
||||
|
||||
extern void ip_conntrack_free(struct ip_conntrack *ct);
|
||||
|
||||
extern void ip_conntrack_hash_insert(struct ip_conntrack *ct);
|
||||
|
||||
extern struct ip_conntrack_expect *
|
||||
__ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple);
|
||||
|
||||
extern struct ip_conntrack_expect *
|
||||
ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple);
|
||||
|
||||
extern struct ip_conntrack_tuple_hash *
|
||||
__ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack *ignored_conntrack);
|
||||
|
||||
extern void ip_conntrack_flush(void);
|
||||
|
||||
/* It's confirmed if it is, or has been in the hash table. */
|
||||
static inline int is_confirmed(struct ip_conntrack *ct)
|
||||
{
|
||||
return test_bit(IPS_CONFIRMED_BIT, &ct->status);
|
||||
}
|
||||
|
||||
static inline int is_dying(struct ip_conntrack *ct)
|
||||
{
|
||||
return test_bit(IPS_DYING_BIT, &ct->status);
|
||||
}
|
||||
|
||||
extern unsigned int ip_conntrack_htable_size;
|
||||
extern int ip_conntrack_checksum;
|
||||
|
||||
#define CONNTRACK_STAT_INC(count) (__get_cpu_var(ip_conntrack_stat).count++)
|
||||
#define CONNTRACK_STAT_INC_ATOMIC(count) \
|
||||
do { \
|
||||
local_bh_disable(); \
|
||||
__get_cpu_var(ip_conntrack_stat).count++; \
|
||||
local_bh_enable(); \
|
||||
} while (0)
|
||||
|
||||
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
struct ip_conntrack_ecache {
|
||||
struct ip_conntrack *ct;
|
||||
unsigned int events;
|
||||
};
|
||||
DECLARE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
|
||||
|
||||
#define CONNTRACK_ECACHE(x) (__get_cpu_var(ip_conntrack_ecache).x)
|
||||
|
||||
extern struct atomic_notifier_head ip_conntrack_chain;
|
||||
extern struct atomic_notifier_head ip_conntrack_expect_chain;
|
||||
|
||||
static inline int ip_conntrack_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_register(&ip_conntrack_chain, nb);
|
||||
}
|
||||
|
||||
static inline int ip_conntrack_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_unregister(&ip_conntrack_chain, nb);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ip_conntrack_expect_register_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_register(&ip_conntrack_expect_chain, nb);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ip_conntrack_expect_unregister_notifier(struct notifier_block *nb)
|
||||
{
|
||||
return atomic_notifier_chain_unregister(&ip_conntrack_expect_chain,
|
||||
nb);
|
||||
}
|
||||
|
||||
extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct);
|
||||
extern void __ip_ct_event_cache_init(struct ip_conntrack *ct);
|
||||
|
||||
static inline void
|
||||
ip_conntrack_event_cache(enum ip_conntrack_events event,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
struct ip_conntrack *ct = (struct ip_conntrack *)skb->nfct;
|
||||
struct ip_conntrack_ecache *ecache;
|
||||
|
||||
local_bh_disable();
|
||||
ecache = &__get_cpu_var(ip_conntrack_ecache);
|
||||
if (ct != ecache->ct)
|
||||
__ip_ct_event_cache_init(ct);
|
||||
ecache->events |= event;
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
static inline void ip_conntrack_event(enum ip_conntrack_events event,
|
||||
struct ip_conntrack *ct)
|
||||
{
|
||||
if (is_confirmed(ct) && !is_dying(ct))
|
||||
atomic_notifier_call_chain(&ip_conntrack_chain, event, ct);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
atomic_notifier_call_chain(&ip_conntrack_expect_chain, event, exp);
|
||||
}
|
||||
#else /* CONFIG_IP_NF_CONNTRACK_EVENTS */
|
||||
static inline void ip_conntrack_event_cache(enum ip_conntrack_events event,
|
||||
const struct sk_buff *skb) {}
|
||||
static inline void ip_conntrack_event(enum ip_conntrack_events event,
|
||||
struct ip_conntrack *ct) {}
|
||||
static inline void ip_ct_deliver_cached_events(const struct ip_conntrack *ct) {}
|
||||
static inline void
|
||||
ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
|
||||
struct ip_conntrack_expect *exp) {}
|
||||
#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
|
||||
|
||||
#ifdef CONFIG_IP_NF_NAT_NEEDED
|
||||
static inline int ip_nat_initialized(struct ip_conntrack *conntrack,
|
||||
enum ip_nat_manip_type manip)
|
||||
{
|
||||
if (manip == IP_NAT_MANIP_SRC)
|
||||
return test_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status);
|
||||
return test_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status);
|
||||
}
|
||||
#endif /* CONFIG_IP_NF_NAT_NEEDED */
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _IP_CONNTRACK_H */
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef _IP_CONNTRACK_AMANDA_H
|
||||
#define _IP_CONNTRACK_AMANDA_H
|
||||
/* AMANDA tracking. */
|
||||
|
||||
struct ip_conntrack_expect;
|
||||
extern unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
struct ip_conntrack_expect *exp);
|
||||
#endif /* _IP_CONNTRACK_AMANDA_H */
|
|
@ -1,61 +0,0 @@
|
|||
#ifndef _IP_CONNTRACK_CORE_H
|
||||
#define _IP_CONNTRACK_CORE_H
|
||||
#include <linux/netfilter.h>
|
||||
|
||||
#define MAX_IP_CT_PROTO 256
|
||||
extern struct ip_conntrack_protocol *ip_ct_protos[MAX_IP_CT_PROTO];
|
||||
|
||||
/* 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 ip_conntrack_in(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *));
|
||||
|
||||
extern int ip_conntrack_init(void);
|
||||
extern void ip_conntrack_cleanup(void);
|
||||
|
||||
struct ip_conntrack_protocol;
|
||||
|
||||
extern int
|
||||
ip_ct_get_tuple(const struct iphdr *iph,
|
||||
const struct sk_buff *skb,
|
||||
unsigned int dataoff,
|
||||
struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack_protocol *protocol);
|
||||
|
||||
extern int
|
||||
ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse,
|
||||
const struct ip_conntrack_tuple *orig,
|
||||
const struct ip_conntrack_protocol *protocol);
|
||||
|
||||
/* Find a connection corresponding to a tuple. */
|
||||
struct ip_conntrack_tuple_hash *
|
||||
ip_conntrack_find_get(const struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack *ignored_conntrack);
|
||||
|
||||
extern int __ip_conntrack_confirm(struct sk_buff **pskb);
|
||||
|
||||
/* Confirm a connection: returns NF_DROP if packet must be dropped. */
|
||||
static inline int ip_conntrack_confirm(struct sk_buff **pskb)
|
||||
{
|
||||
struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct;
|
||||
int ret = NF_ACCEPT;
|
||||
|
||||
if (ct) {
|
||||
if (!is_confirmed(ct) && !is_dying(ct))
|
||||
ret = __ip_conntrack_confirm(pskb);
|
||||
ip_ct_deliver_cached_events(ct);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern void ip_ct_unlink_expect(struct ip_conntrack_expect *exp);
|
||||
|
||||
extern struct list_head *ip_conntrack_hash;
|
||||
extern struct list_head ip_conntrack_expect_list;
|
||||
extern rwlock_t ip_conntrack_lock;
|
||||
#endif /* _IP_CONNTRACK_CORE_H */
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#ifndef _IP_CONNTRACK_FTP_H
|
||||
#define _IP_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 /* _IP_CONNTRACK_FTP_H */
|
|
@ -1,89 +0,0 @@
|
|||
#ifndef _IP_CONNTRACK_H323_H
|
||||
#define _IP_CONNTRACK_H323_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/netfilter/nf_conntrack_h323_asn1.h>
|
||||
|
||||
#define RAS_PORT 1719
|
||||
#define Q931_PORT 1720
|
||||
#define H323_RTP_CHANNEL_MAX 4 /* Audio, video, FAX and other */
|
||||
|
||||
/* This structure exists only once per master */
|
||||
struct ip_ct_h323_master {
|
||||
|
||||
/* Original and NATed Q.931 or H.245 signal ports */
|
||||
u_int16_t sig_port[IP_CT_DIR_MAX];
|
||||
|
||||
/* Original and NATed RTP ports */
|
||||
u_int16_t rtp_port[H323_RTP_CHANNEL_MAX][IP_CT_DIR_MAX];
|
||||
|
||||
union {
|
||||
/* RAS connection timeout */
|
||||
u_int32_t timeout;
|
||||
|
||||
/* Next TPKT length (for separate TPKT header and data) */
|
||||
u_int16_t tpkt_len[IP_CT_DIR_MAX];
|
||||
};
|
||||
};
|
||||
|
||||
struct ip_conntrack_expect;
|
||||
|
||||
extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
|
||||
__be32 * ip, u_int16_t * port);
|
||||
extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
|
||||
struct ip_conntrack_expect *this);
|
||||
extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
|
||||
struct ip_conntrack_expect *this);
|
||||
extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
|
||||
unsigned char **data, int dataoff,
|
||||
H245_TransportAddress * addr,
|
||||
__be32 ip, u_int16_t port);
|
||||
extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
|
||||
unsigned char **data, int dataoff,
|
||||
TransportAddress * addr,
|
||||
__be32 ip, u_int16_t port);
|
||||
extern int (*set_sig_addr_hook) (struct sk_buff ** pskb,
|
||||
struct ip_conntrack * ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data,
|
||||
TransportAddress * addr, int count);
|
||||
extern int (*set_ras_addr_hook) (struct sk_buff ** pskb,
|
||||
struct ip_conntrack * ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data,
|
||||
TransportAddress * addr, int count);
|
||||
extern int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb,
|
||||
struct ip_conntrack * ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
H245_TransportAddress * addr,
|
||||
u_int16_t port, u_int16_t rtp_port,
|
||||
struct ip_conntrack_expect * rtp_exp,
|
||||
struct ip_conntrack_expect * rtcp_exp);
|
||||
extern int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
H245_TransportAddress * addr, u_int16_t port,
|
||||
struct ip_conntrack_expect * exp);
|
||||
extern int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
TransportAddress * addr, u_int16_t port,
|
||||
struct ip_conntrack_expect * exp);
|
||||
extern int (*nat_callforwarding_hook) (struct sk_buff ** pskb,
|
||||
struct ip_conntrack * ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
TransportAddress * addr,
|
||||
u_int16_t port,
|
||||
struct ip_conntrack_expect * exp);
|
||||
extern int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, TransportAddress * addr,
|
||||
int idx, u_int16_t port,
|
||||
struct ip_conntrack_expect * exp);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,46 +0,0 @@
|
|||
/* IP connection tracking helpers. */
|
||||
#ifndef _IP_CONNTRACK_HELPER_H
|
||||
#define _IP_CONNTRACK_HELPER_H
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
|
||||
struct module;
|
||||
|
||||
struct ip_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 ip_conntrack_tuple tuple;
|
||||
struct ip_conntrack_tuple mask;
|
||||
|
||||
/* Function to call when data passes; return verdict, or -1 to
|
||||
invalidate. */
|
||||
int (*help)(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info conntrackinfo);
|
||||
|
||||
void (*destroy)(struct ip_conntrack *ct);
|
||||
|
||||
int (*to_nfattr)(struct sk_buff *skb, const struct ip_conntrack *ct);
|
||||
};
|
||||
|
||||
extern int ip_conntrack_helper_register(struct ip_conntrack_helper *);
|
||||
extern void ip_conntrack_helper_unregister(struct ip_conntrack_helper *);
|
||||
|
||||
/* Allocate space for an expectation: this is mandatory before calling
|
||||
ip_conntrack_expect_related. You will have to call put afterwards. */
|
||||
extern struct ip_conntrack_expect *
|
||||
ip_conntrack_expect_alloc(struct ip_conntrack *master);
|
||||
extern void ip_conntrack_expect_put(struct ip_conntrack_expect *exp);
|
||||
|
||||
/* Add an expected connection: can have more than one per connection */
|
||||
extern int ip_conntrack_expect_related(struct ip_conntrack_expect *exp);
|
||||
extern void ip_conntrack_unexpect_related(struct ip_conntrack_expect *exp);
|
||||
|
||||
#endif /*_IP_CONNTRACK_HELPER_H*/
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef _IP_CONNTRACK_ICMP_H
|
||||
#define _IP_CONNTRACK_ICMP_H
|
||||
|
||||
#include <net/netfilter/ipv4/nf_conntrack_icmp.h>
|
||||
|
||||
#endif /* _IP_CONNTRACK_ICMP_H */
|
|
@ -1,32 +0,0 @@
|
|||
/* IRC extension for IP connection tracking.
|
||||
* (C) 2000 by Harald Welte <laforge@gnumonks.org>
|
||||
* based on RR's ip_conntrack_ftp.h
|
||||
*
|
||||
* ip_conntrack_irc.h,v 1.6 2000/11/07 18:26:42 laforge Exp
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef _IP_CONNTRACK_IRC_H
|
||||
#define _IP_CONNTRACK_IRC_H
|
||||
|
||||
/* This structure exists only once per master */
|
||||
struct ip_ct_irc_master {
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
extern unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
struct ip_conntrack_expect *exp);
|
||||
|
||||
#define IRC_PORT 6667
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _IP_CONNTRACK_IRC_H */
|
|
@ -1,326 +0,0 @@
|
|||
/* PPTP constants and structs */
|
||||
#ifndef _CONNTRACK_PPTP_H
|
||||
#define _CONNTRACK_PPTP_H
|
||||
|
||||
/* state of the control session */
|
||||
enum pptp_ctrlsess_state {
|
||||
PPTP_SESSION_NONE, /* no session present */
|
||||
PPTP_SESSION_ERROR, /* some session error */
|
||||
PPTP_SESSION_STOPREQ, /* stop_sess request seen */
|
||||
PPTP_SESSION_REQUESTED, /* start_sess request seen */
|
||||
PPTP_SESSION_CONFIRMED, /* session established */
|
||||
};
|
||||
|
||||
/* state of the call inside the control session */
|
||||
enum pptp_ctrlcall_state {
|
||||
PPTP_CALL_NONE,
|
||||
PPTP_CALL_ERROR,
|
||||
PPTP_CALL_OUT_REQ,
|
||||
PPTP_CALL_OUT_CONF,
|
||||
PPTP_CALL_IN_REQ,
|
||||
PPTP_CALL_IN_REP,
|
||||
PPTP_CALL_IN_CONF,
|
||||
PPTP_CALL_CLEAR_REQ,
|
||||
};
|
||||
|
||||
|
||||
/* conntrack private data */
|
||||
struct ip_ct_pptp_master {
|
||||
enum pptp_ctrlsess_state sstate; /* session state */
|
||||
|
||||
/* everything below is going to be per-expectation in newnat,
|
||||
* since there could be more than one call within one session */
|
||||
enum pptp_ctrlcall_state cstate; /* call state */
|
||||
__be16 pac_call_id; /* call id of PAC, host byte order */
|
||||
__be16 pns_call_id; /* call id of PNS, host byte order */
|
||||
|
||||
/* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack
|
||||
* and therefore imposes a fixed limit on the number of maps */
|
||||
struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
|
||||
};
|
||||
|
||||
/* conntrack_expect private member */
|
||||
struct ip_ct_pptp_expect {
|
||||
enum pptp_ctrlcall_state cstate; /* call state */
|
||||
__be16 pac_call_id; /* call id of PAC */
|
||||
__be16 pns_call_id; /* call id of PNS */
|
||||
};
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define IP_CONNTR_PPTP PPTP_CONTROL_PORT
|
||||
|
||||
#define PPTP_CONTROL_PORT 1723
|
||||
|
||||
#define PPTP_PACKET_CONTROL 1
|
||||
#define PPTP_PACKET_MGMT 2
|
||||
|
||||
#define PPTP_MAGIC_COOKIE 0x1a2b3c4d
|
||||
|
||||
struct pptp_pkt_hdr {
|
||||
__u16 packetLength;
|
||||
__be16 packetType;
|
||||
__be32 magicCookie;
|
||||
};
|
||||
|
||||
/* PptpControlMessageType values */
|
||||
#define PPTP_START_SESSION_REQUEST 1
|
||||
#define PPTP_START_SESSION_REPLY 2
|
||||
#define PPTP_STOP_SESSION_REQUEST 3
|
||||
#define PPTP_STOP_SESSION_REPLY 4
|
||||
#define PPTP_ECHO_REQUEST 5
|
||||
#define PPTP_ECHO_REPLY 6
|
||||
#define PPTP_OUT_CALL_REQUEST 7
|
||||
#define PPTP_OUT_CALL_REPLY 8
|
||||
#define PPTP_IN_CALL_REQUEST 9
|
||||
#define PPTP_IN_CALL_REPLY 10
|
||||
#define PPTP_IN_CALL_CONNECT 11
|
||||
#define PPTP_CALL_CLEAR_REQUEST 12
|
||||
#define PPTP_CALL_DISCONNECT_NOTIFY 13
|
||||
#define PPTP_WAN_ERROR_NOTIFY 14
|
||||
#define PPTP_SET_LINK_INFO 15
|
||||
|
||||
#define PPTP_MSG_MAX 15
|
||||
|
||||
/* PptpGeneralError values */
|
||||
#define PPTP_ERROR_CODE_NONE 0
|
||||
#define PPTP_NOT_CONNECTED 1
|
||||
#define PPTP_BAD_FORMAT 2
|
||||
#define PPTP_BAD_VALUE 3
|
||||
#define PPTP_NO_RESOURCE 4
|
||||
#define PPTP_BAD_CALLID 5
|
||||
#define PPTP_REMOVE_DEVICE_ERROR 6
|
||||
|
||||
struct PptpControlHeader {
|
||||
__be16 messageType;
|
||||
__u16 reserved;
|
||||
};
|
||||
|
||||
/* FramingCapability Bitmap Values */
|
||||
#define PPTP_FRAME_CAP_ASYNC 0x1
|
||||
#define PPTP_FRAME_CAP_SYNC 0x2
|
||||
|
||||
/* BearerCapability Bitmap Values */
|
||||
#define PPTP_BEARER_CAP_ANALOG 0x1
|
||||
#define PPTP_BEARER_CAP_DIGITAL 0x2
|
||||
|
||||
struct PptpStartSessionRequest {
|
||||
__be16 protocolVersion;
|
||||
__u16 reserved1;
|
||||
__be32 framingCapability;
|
||||
__be32 bearerCapability;
|
||||
__be16 maxChannels;
|
||||
__be16 firmwareRevision;
|
||||
__u8 hostName[64];
|
||||
__u8 vendorString[64];
|
||||
};
|
||||
|
||||
/* PptpStartSessionResultCode Values */
|
||||
#define PPTP_START_OK 1
|
||||
#define PPTP_START_GENERAL_ERROR 2
|
||||
#define PPTP_START_ALREADY_CONNECTED 3
|
||||
#define PPTP_START_NOT_AUTHORIZED 4
|
||||
#define PPTP_START_UNKNOWN_PROTOCOL 5
|
||||
|
||||
struct PptpStartSessionReply {
|
||||
__be16 protocolVersion;
|
||||
__u8 resultCode;
|
||||
__u8 generalErrorCode;
|
||||
__be32 framingCapability;
|
||||
__be32 bearerCapability;
|
||||
__be16 maxChannels;
|
||||
__be16 firmwareRevision;
|
||||
__u8 hostName[64];
|
||||
__u8 vendorString[64];
|
||||
};
|
||||
|
||||
/* PptpStopReasons */
|
||||
#define PPTP_STOP_NONE 1
|
||||
#define PPTP_STOP_PROTOCOL 2
|
||||
#define PPTP_STOP_LOCAL_SHUTDOWN 3
|
||||
|
||||
struct PptpStopSessionRequest {
|
||||
__u8 reason;
|
||||
__u8 reserved1;
|
||||
__u16 reserved2;
|
||||
};
|
||||
|
||||
/* PptpStopSessionResultCode */
|
||||
#define PPTP_STOP_OK 1
|
||||
#define PPTP_STOP_GENERAL_ERROR 2
|
||||
|
||||
struct PptpStopSessionReply {
|
||||
__u8 resultCode;
|
||||
__u8 generalErrorCode;
|
||||
__u16 reserved1;
|
||||
};
|
||||
|
||||
struct PptpEchoRequest {
|
||||
__be32 identNumber;
|
||||
};
|
||||
|
||||
/* PptpEchoReplyResultCode */
|
||||
#define PPTP_ECHO_OK 1
|
||||
#define PPTP_ECHO_GENERAL_ERROR 2
|
||||
|
||||
struct PptpEchoReply {
|
||||
__be32 identNumber;
|
||||
__u8 resultCode;
|
||||
__u8 generalErrorCode;
|
||||
__u16 reserved;
|
||||
};
|
||||
|
||||
/* PptpFramingType */
|
||||
#define PPTP_ASYNC_FRAMING 1
|
||||
#define PPTP_SYNC_FRAMING 2
|
||||
#define PPTP_DONT_CARE_FRAMING 3
|
||||
|
||||
/* PptpCallBearerType */
|
||||
#define PPTP_ANALOG_TYPE 1
|
||||
#define PPTP_DIGITAL_TYPE 2
|
||||
#define PPTP_DONT_CARE_BEARER_TYPE 3
|
||||
|
||||
struct PptpOutCallRequest {
|
||||
__be16 callID;
|
||||
__be16 callSerialNumber;
|
||||
__be32 minBPS;
|
||||
__be32 maxBPS;
|
||||
__be32 bearerType;
|
||||
__be32 framingType;
|
||||
__be16 packetWindow;
|
||||
__be16 packetProcDelay;
|
||||
__be16 phoneNumberLength;
|
||||
__u16 reserved1;
|
||||
__u8 phoneNumber[64];
|
||||
__u8 subAddress[64];
|
||||
};
|
||||
|
||||
/* PptpCallResultCode */
|
||||
#define PPTP_OUTCALL_CONNECT 1
|
||||
#define PPTP_OUTCALL_GENERAL_ERROR 2
|
||||
#define PPTP_OUTCALL_NO_CARRIER 3
|
||||
#define PPTP_OUTCALL_BUSY 4
|
||||
#define PPTP_OUTCALL_NO_DIAL_TONE 5
|
||||
#define PPTP_OUTCALL_TIMEOUT 6
|
||||
#define PPTP_OUTCALL_DONT_ACCEPT 7
|
||||
|
||||
struct PptpOutCallReply {
|
||||
__be16 callID;
|
||||
__be16 peersCallID;
|
||||
__u8 resultCode;
|
||||
__u8 generalErrorCode;
|
||||
__be16 causeCode;
|
||||
__be32 connectSpeed;
|
||||
__be16 packetWindow;
|
||||
__be16 packetProcDelay;
|
||||
__be32 physChannelID;
|
||||
};
|
||||
|
||||
struct PptpInCallRequest {
|
||||
__be16 callID;
|
||||
__be16 callSerialNumber;
|
||||
__be32 callBearerType;
|
||||
__be32 physChannelID;
|
||||
__be16 dialedNumberLength;
|
||||
__be16 dialingNumberLength;
|
||||
__u8 dialedNumber[64];
|
||||
__u8 dialingNumber[64];
|
||||
__u8 subAddress[64];
|
||||
};
|
||||
|
||||
/* PptpInCallResultCode */
|
||||
#define PPTP_INCALL_ACCEPT 1
|
||||
#define PPTP_INCALL_GENERAL_ERROR 2
|
||||
#define PPTP_INCALL_DONT_ACCEPT 3
|
||||
|
||||
struct PptpInCallReply {
|
||||
__be16 callID;
|
||||
__be16 peersCallID;
|
||||
__u8 resultCode;
|
||||
__u8 generalErrorCode;
|
||||
__be16 packetWindow;
|
||||
__be16 packetProcDelay;
|
||||
__u16 reserved;
|
||||
};
|
||||
|
||||
struct PptpInCallConnected {
|
||||
__be16 peersCallID;
|
||||
__u16 reserved;
|
||||
__be32 connectSpeed;
|
||||
__be16 packetWindow;
|
||||
__be16 packetProcDelay;
|
||||
__be32 callFramingType;
|
||||
};
|
||||
|
||||
struct PptpClearCallRequest {
|
||||
__be16 callID;
|
||||
__u16 reserved;
|
||||
};
|
||||
|
||||
struct PptpCallDisconnectNotify {
|
||||
__be16 callID;
|
||||
__u8 resultCode;
|
||||
__u8 generalErrorCode;
|
||||
__be16 causeCode;
|
||||
__u16 reserved;
|
||||
__u8 callStatistics[128];
|
||||
};
|
||||
|
||||
struct PptpWanErrorNotify {
|
||||
__be16 peersCallID;
|
||||
__u16 reserved;
|
||||
__be32 crcErrors;
|
||||
__be32 framingErrors;
|
||||
__be32 hardwareOverRuns;
|
||||
__be32 bufferOverRuns;
|
||||
__be32 timeoutErrors;
|
||||
__be32 alignmentErrors;
|
||||
};
|
||||
|
||||
struct PptpSetLinkInfo {
|
||||
__be16 peersCallID;
|
||||
__u16 reserved;
|
||||
__be32 sendAccm;
|
||||
__be32 recvAccm;
|
||||
};
|
||||
|
||||
union pptp_ctrl_union {
|
||||
struct PptpStartSessionRequest sreq;
|
||||
struct PptpStartSessionReply srep;
|
||||
struct PptpStopSessionRequest streq;
|
||||
struct PptpStopSessionReply strep;
|
||||
struct PptpOutCallRequest ocreq;
|
||||
struct PptpOutCallReply ocack;
|
||||
struct PptpInCallRequest icreq;
|
||||
struct PptpInCallReply icack;
|
||||
struct PptpInCallConnected iccon;
|
||||
struct PptpClearCallRequest clrreq;
|
||||
struct PptpCallDisconnectNotify disc;
|
||||
struct PptpWanErrorNotify wanerr;
|
||||
struct PptpSetLinkInfo setlink;
|
||||
};
|
||||
|
||||
extern int
|
||||
(*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq);
|
||||
|
||||
extern int
|
||||
(*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq);
|
||||
|
||||
extern void
|
||||
(*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig,
|
||||
struct ip_conntrack_expect *exp_reply);
|
||||
|
||||
extern void
|
||||
(*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct,
|
||||
struct ip_conntrack_expect *exp);
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _CONNTRACK_PPTP_H */
|
|
@ -1,114 +0,0 @@
|
|||
#ifndef _CONNTRACK_PROTO_GRE_H
|
||||
#define _CONNTRACK_PROTO_GRE_H
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/* GRE PROTOCOL HEADER */
|
||||
|
||||
/* GRE Version field */
|
||||
#define GRE_VERSION_1701 0x0
|
||||
#define GRE_VERSION_PPTP 0x1
|
||||
|
||||
/* GRE Protocol field */
|
||||
#define GRE_PROTOCOL_PPTP 0x880B
|
||||
|
||||
/* GRE Flags */
|
||||
#define GRE_FLAG_C 0x80
|
||||
#define GRE_FLAG_R 0x40
|
||||
#define GRE_FLAG_K 0x20
|
||||
#define GRE_FLAG_S 0x10
|
||||
#define GRE_FLAG_A 0x80
|
||||
|
||||
#define GRE_IS_C(f) ((f)&GRE_FLAG_C)
|
||||
#define GRE_IS_R(f) ((f)&GRE_FLAG_R)
|
||||
#define GRE_IS_K(f) ((f)&GRE_FLAG_K)
|
||||
#define GRE_IS_S(f) ((f)&GRE_FLAG_S)
|
||||
#define GRE_IS_A(f) ((f)&GRE_FLAG_A)
|
||||
|
||||
/* GRE is a mess: Four different standards */
|
||||
struct gre_hdr {
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
__u16 rec:3,
|
||||
srr:1,
|
||||
seq:1,
|
||||
key:1,
|
||||
routing:1,
|
||||
csum:1,
|
||||
version:3,
|
||||
reserved:4,
|
||||
ack:1;
|
||||
#elif defined(__BIG_ENDIAN_BITFIELD)
|
||||
__u16 csum:1,
|
||||
routing:1,
|
||||
key:1,
|
||||
seq:1,
|
||||
srr:1,
|
||||
rec:3,
|
||||
ack:1,
|
||||
reserved:4,
|
||||
version:3;
|
||||
#else
|
||||
#error "Adjust your <asm/byteorder.h> defines"
|
||||
#endif
|
||||
__be16 protocol;
|
||||
};
|
||||
|
||||
/* modified GRE header for PPTP */
|
||||
struct gre_hdr_pptp {
|
||||
__u8 flags; /* bitfield */
|
||||
__u8 version; /* should be GRE_VERSION_PPTP */
|
||||
__be16 protocol; /* should be GRE_PROTOCOL_PPTP */
|
||||
__be16 payload_len; /* size of ppp payload, not inc. gre header */
|
||||
__be16 call_id; /* peer's call_id for this session */
|
||||
__be32 seq; /* sequence number. Present if S==1 */
|
||||
__be32 ack; /* seq number of highest packet recieved by */
|
||||
/* sender in this session */
|
||||
};
|
||||
|
||||
|
||||
/* this is part of ip_conntrack */
|
||||
struct ip_ct_gre {
|
||||
unsigned int stream_timeout;
|
||||
unsigned int timeout;
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
struct ip_conntrack_expect;
|
||||
struct ip_conntrack;
|
||||
|
||||
/* structure for original <-> reply keymap */
|
||||
struct ip_ct_gre_keymap {
|
||||
struct list_head list;
|
||||
|
||||
struct ip_conntrack_tuple tuple;
|
||||
};
|
||||
|
||||
/* add new tuple->key_reply pair to keymap */
|
||||
int ip_ct_gre_keymap_add(struct ip_conntrack *ct,
|
||||
struct ip_conntrack_tuple *t,
|
||||
int reply);
|
||||
|
||||
/* delete keymap entries */
|
||||
void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct);
|
||||
|
||||
|
||||
/* get pointer to gre key, if present */
|
||||
static inline __be32 *gre_key(struct gre_hdr *greh)
|
||||
{
|
||||
if (!greh->key)
|
||||
return NULL;
|
||||
if (greh->csum || greh->routing)
|
||||
return (__be32 *) (greh+sizeof(*greh)+4);
|
||||
return (__be32 *) (greh+sizeof(*greh));
|
||||
}
|
||||
|
||||
/* get pointer ot gre csum, if present */
|
||||
static inline __sum16 *gre_csum(struct gre_hdr *greh)
|
||||
{
|
||||
if (!greh->csum)
|
||||
return NULL;
|
||||
return (__sum16 *) (greh+sizeof(*greh));
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _CONNTRACK_PROTO_GRE_H */
|
|
@ -1,98 +0,0 @@
|
|||
/* Header for use in defining a given protocol for connection tracking. */
|
||||
#ifndef _IP_CONNTRACK_PROTOCOL_H
|
||||
#define _IP_CONNTRACK_PROTOCOL_H
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter/nfnetlink_conntrack.h>
|
||||
|
||||
struct seq_file;
|
||||
|
||||
struct ip_conntrack_protocol
|
||||
{
|
||||
/* Protocol number. */
|
||||
u_int8_t proto;
|
||||
|
||||
/* Protocol name */
|
||||
const char *name;
|
||||
|
||||
/* Try to fill in the third arg: dataoff is offset past IP
|
||||
hdr. Return true if possible. */
|
||||
int (*pkt_to_tuple)(const struct sk_buff *skb,
|
||||
unsigned int dataoff,
|
||||
struct ip_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 ip_conntrack_tuple *inverse,
|
||||
const struct ip_conntrack_tuple *orig);
|
||||
|
||||
/* Print out the per-protocol part of the tuple. Return like seq_* */
|
||||
int (*print_tuple)(struct seq_file *,
|
||||
const struct ip_conntrack_tuple *);
|
||||
|
||||
/* Print out the private part of the conntrack. */
|
||||
int (*print_conntrack)(struct seq_file *, const struct ip_conntrack *);
|
||||
|
||||
/* Returns verdict for packet, or -1 for invalid. */
|
||||
int (*packet)(struct ip_conntrack *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 ip_conntrack *conntrack, const struct sk_buff *skb);
|
||||
|
||||
/* Called when a conntrack entry is destroyed */
|
||||
void (*destroy)(struct ip_conntrack *conntrack);
|
||||
|
||||
int (*error)(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
|
||||
unsigned int hooknum);
|
||||
|
||||
/* convert protoinfo to nfnetink attributes */
|
||||
int (*to_nfattr)(struct sk_buff *skb, struct nfattr *nfa,
|
||||
const struct ip_conntrack *ct);
|
||||
|
||||
/* convert nfnetlink attributes to protoinfo */
|
||||
int (*from_nfattr)(struct nfattr *tb[], struct ip_conntrack *ct);
|
||||
|
||||
int (*tuple_to_nfattr)(struct sk_buff *skb,
|
||||
const struct ip_conntrack_tuple *t);
|
||||
int (*nfattr_to_tuple)(struct nfattr *tb[],
|
||||
struct ip_conntrack_tuple *t);
|
||||
|
||||
/* Module (if any) which this is connected to. */
|
||||
struct module *me;
|
||||
};
|
||||
|
||||
/* Protocol registration. */
|
||||
extern int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto);
|
||||
extern void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto);
|
||||
/* Existing built-in protocols */
|
||||
extern struct ip_conntrack_protocol ip_conntrack_protocol_tcp;
|
||||
extern struct ip_conntrack_protocol ip_conntrack_protocol_udp;
|
||||
extern struct ip_conntrack_protocol ip_conntrack_protocol_icmp;
|
||||
extern struct ip_conntrack_protocol ip_conntrack_generic_protocol;
|
||||
extern int ip_conntrack_protocol_tcp_init(void);
|
||||
|
||||
/* Log invalid packets */
|
||||
extern unsigned int ip_ct_log_invalid;
|
||||
|
||||
extern int ip_ct_port_tuple_to_nfattr(struct sk_buff *,
|
||||
const struct ip_conntrack_tuple *);
|
||||
extern int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[],
|
||||
struct ip_conntrack_tuple *);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
#ifdef DEBUG_INVALID_PACKETS
|
||||
#define LOG_INVALID(proto) \
|
||||
(ip_ct_log_invalid == (proto) || ip_ct_log_invalid == IPPROTO_RAW)
|
||||
#else
|
||||
#define LOG_INVALID(proto) \
|
||||
((ip_ct_log_invalid == (proto) || ip_ct_log_invalid == IPPROTO_RAW) \
|
||||
&& net_ratelimit())
|
||||
#endif
|
||||
#else
|
||||
#define LOG_INVALID(proto) 0
|
||||
#endif /* CONFIG_SYSCTL */
|
||||
|
||||
#endif /*_IP_CONNTRACK_PROTOCOL_H*/
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef _IP_CONNTRACK_SCTP_H
|
||||
#define _IP_CONNTRACK_SCTP_H
|
||||
|
||||
#include <linux/netfilter/nf_conntrack_sctp.h>
|
||||
|
||||
#endif /* _IP_CONNTRACK_SCTP_H */
|
|
@ -1,40 +0,0 @@
|
|||
#ifndef __IP_CONNTRACK_SIP_H__
|
||||
#define __IP_CONNTRACK_SIP_H__
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define SIP_PORT 5060
|
||||
#define SIP_TIMEOUT 3600
|
||||
|
||||
enum sip_header_pos {
|
||||
POS_REG_REQ_URI,
|
||||
POS_REQ_URI,
|
||||
POS_FROM,
|
||||
POS_TO,
|
||||
POS_VIA,
|
||||
POS_CONTACT,
|
||||
POS_CONTENT,
|
||||
POS_MEDIA,
|
||||
POS_OWNER,
|
||||
POS_CONNECTION,
|
||||
POS_SDP_HEADER,
|
||||
};
|
||||
|
||||
extern unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack *ct,
|
||||
const char **dptr);
|
||||
extern unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack_expect *exp,
|
||||
const char *dptr);
|
||||
|
||||
extern int ct_sip_get_info(const char *dptr, size_t dlen,
|
||||
unsigned int *matchoff,
|
||||
unsigned int *matchlen,
|
||||
enum sip_header_pos pos);
|
||||
extern int ct_sip_lnlen(const char *line, const char *limit);
|
||||
extern const char *ct_sip_search(const char *needle, const char *haystack,
|
||||
size_t needle_len, size_t haystack_len,
|
||||
int case_sensitive);
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* __IP_CONNTRACK_SIP_H__ */
|
|
@ -1,6 +0,0 @@
|
|||
#ifndef _IP_CONNTRACK_TCP_H
|
||||
#define _IP_CONNTRACK_TCP_H
|
||||
|
||||
#include <linux/netfilter/nf_conntrack_tcp.h>
|
||||
|
||||
#endif /* _IP_CONNTRACK_TCP_H */
|
|
@ -1,20 +0,0 @@
|
|||
#ifndef _IP_CT_TFTP
|
||||
#define _IP_CT_TFTP
|
||||
|
||||
#define TFTP_PORT 69
|
||||
|
||||
struct tftphdr {
|
||||
__be16 opcode;
|
||||
};
|
||||
|
||||
#define TFTP_OPCODE_READ 1
|
||||
#define TFTP_OPCODE_WRITE 2
|
||||
#define TFTP_OPCODE_DATA 3
|
||||
#define TFTP_OPCODE_ACK 4
|
||||
#define TFTP_OPCODE_ERROR 5
|
||||
|
||||
extern unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack_expect *exp);
|
||||
|
||||
#endif /* _IP_CT_TFTP */
|
|
@ -1,146 +0,0 @@
|
|||
#ifndef _IP_CONNTRACK_TUPLE_H
|
||||
#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
|
||||
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.
|
||||
*/
|
||||
|
||||
/* The protocol-specific manipulable parts of the tuple: always in
|
||||
network order! */
|
||||
union ip_conntrack_manip_proto
|
||||
{
|
||||
/* Add other protocols here. */
|
||||
u_int16_t all;
|
||||
|
||||
struct {
|
||||
__be16 port;
|
||||
} tcp;
|
||||
struct {
|
||||
__be16 port;
|
||||
} udp;
|
||||
struct {
|
||||
__be16 id;
|
||||
} icmp;
|
||||
struct {
|
||||
__be16 port;
|
||||
} sctp;
|
||||
struct {
|
||||
__be16 key; /* key is 32bit, pptp only uses 16 */
|
||||
} gre;
|
||||
};
|
||||
|
||||
/* The manipulable part of the tuple. */
|
||||
struct ip_conntrack_manip
|
||||
{
|
||||
__be32 ip;
|
||||
union ip_conntrack_manip_proto u;
|
||||
};
|
||||
|
||||
/* This contains the information to distinguish a connection. */
|
||||
struct ip_conntrack_tuple
|
||||
{
|
||||
struct ip_conntrack_manip src;
|
||||
|
||||
/* These are the parts of the tuple which are fixed. */
|
||||
struct {
|
||||
__be32 ip;
|
||||
union {
|
||||
/* Add other protocols here. */
|
||||
u_int16_t all;
|
||||
|
||||
struct {
|
||||
__be16 port;
|
||||
} tcp;
|
||||
struct {
|
||||
__be16 port;
|
||||
} udp;
|
||||
struct {
|
||||
u_int8_t type, code;
|
||||
} icmp;
|
||||
struct {
|
||||
__be16 port;
|
||||
} sctp;
|
||||
struct {
|
||||
__be16 key; /* key is 32bit,
|
||||
* pptp only uses 16 */
|
||||
} gre;
|
||||
} 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 IP_CT_TUPLE_U_BLANK(tuple) \
|
||||
do { \
|
||||
(tuple)->src.u.all = 0; \
|
||||
(tuple)->dst.u.all = 0; \
|
||||
} while (0)
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define DUMP_TUPLE(tp) \
|
||||
DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
|
||||
(tp), (tp)->dst.protonum, \
|
||||
NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
|
||||
NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
|
||||
|
||||
/* If we're the first tuple, it's the original dir. */
|
||||
#define DIRECTION(h) ((enum ip_conntrack_dir)(h)->tuple.dst.dir)
|
||||
|
||||
/* Connections have two entries in the hash table: one for each way */
|
||||
struct ip_conntrack_tuple_hash
|
||||
{
|
||||
struct list_head list;
|
||||
|
||||
struct ip_conntrack_tuple tuple;
|
||||
};
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
|
||||
const struct ip_conntrack_tuple *t2)
|
||||
{
|
||||
return t1->src.ip == t2->src.ip
|
||||
&& t1->src.u.all == t2->src.u.all;
|
||||
}
|
||||
|
||||
static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
|
||||
const struct ip_conntrack_tuple *t2)
|
||||
{
|
||||
return t1->dst.ip == t2->dst.ip
|
||||
&& t1->dst.u.all == t2->dst.u.all
|
||||
&& t1->dst.protonum == t2->dst.protonum;
|
||||
}
|
||||
|
||||
static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
|
||||
const struct ip_conntrack_tuple *t2)
|
||||
{
|
||||
return ip_ct_tuple_src_equal(t1, t2) && ip_ct_tuple_dst_equal(t1, t2);
|
||||
}
|
||||
|
||||
static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
|
||||
const struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack_tuple *mask)
|
||||
{
|
||||
return !(((t->src.ip ^ tuple->src.ip) & mask->src.ip)
|
||||
|| ((t->dst.ip ^ tuple->dst.ip) & mask->dst.ip)
|
||||
|| ((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->dst.protonum ^ tuple->dst.protonum)
|
||||
& mask->dst.protonum));
|
||||
}
|
||||
|
||||
#endif /* _IP_CONNTRACK_TUPLE_H */
|
|
@ -1,79 +0,0 @@
|
|||
#ifndef _IP_NAT_H
|
||||
#define _IP_NAT_H
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
|
||||
|
||||
#define IP_NAT_MAPPING_TYPE_MAX_NAMELEN 16
|
||||
|
||||
enum ip_nat_manip_type
|
||||
{
|
||||
IP_NAT_MANIP_SRC,
|
||||
IP_NAT_MANIP_DST
|
||||
};
|
||||
|
||||
/* SRC manip occurs POST_ROUTING or LOCAL_IN */
|
||||
#define HOOK2MANIP(hooknum) ((hooknum) != NF_IP_POST_ROUTING && (hooknum) != NF_IP_LOCAL_IN)
|
||||
|
||||
#define IP_NAT_RANGE_MAP_IPS 1
|
||||
#define IP_NAT_RANGE_PROTO_SPECIFIED 2
|
||||
#define IP_NAT_RANGE_PROTO_RANDOM 4 /* add randomness to "port" selection */
|
||||
|
||||
/* NAT sequence number modifications */
|
||||
struct ip_nat_seq {
|
||||
/* position of the last TCP sequence number
|
||||
* modification (if any) */
|
||||
u_int32_t correction_pos;
|
||||
/* sequence number offset before and after last modification */
|
||||
int16_t offset_before, offset_after;
|
||||
};
|
||||
|
||||
/* Single range specification. */
|
||||
struct ip_nat_range
|
||||
{
|
||||
/* Set to OR of flags above. */
|
||||
unsigned int flags;
|
||||
|
||||
/* Inclusive: network order. */
|
||||
__be32 min_ip, max_ip;
|
||||
|
||||
/* Inclusive: network order */
|
||||
union ip_conntrack_manip_proto min, max;
|
||||
};
|
||||
|
||||
/* For backwards compat: don't use in modern code. */
|
||||
struct ip_nat_multi_range_compat
|
||||
{
|
||||
unsigned int rangesize; /* Must be 1. */
|
||||
|
||||
/* hangs off end. */
|
||||
struct ip_nat_range range[1];
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/list.h>
|
||||
|
||||
/* Protects NAT hash tables, and NAT-private part of conntracks. */
|
||||
extern rwlock_t ip_nat_lock;
|
||||
|
||||
/* The structure embedded in the conntrack structure. */
|
||||
struct ip_nat_info
|
||||
{
|
||||
struct list_head bysource;
|
||||
struct ip_nat_seq seq[IP_CT_DIR_MAX];
|
||||
};
|
||||
|
||||
struct ip_conntrack;
|
||||
|
||||
/* Set up the info structure to map into this range. */
|
||||
extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack,
|
||||
const struct ip_nat_range *range,
|
||||
unsigned int hooknum);
|
||||
|
||||
/* Is this tuple already taken? (not by us)*/
|
||||
extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack *ignored_conntrack);
|
||||
|
||||
#else /* !__KERNEL__: iptables wants this to compile. */
|
||||
#define ip_nat_multi_range ip_nat_multi_range_compat
|
||||
#endif /*__KERNEL__*/
|
||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef _IP_NAT_CORE_H
|
||||
#define _IP_NAT_CORE_H
|
||||
#include <linux/list.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
|
||||
/* This header used to share core functionality between the standalone
|
||||
NAT module, and the compatibility layer's use of NAT for masquerading. */
|
||||
|
||||
extern unsigned int ip_nat_packet(struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info conntrackinfo,
|
||||
unsigned int hooknum,
|
||||
struct sk_buff **pskb);
|
||||
|
||||
extern int ip_nat_icmp_reply_translation(struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int hooknum,
|
||||
struct sk_buff **pskb);
|
||||
#endif /* _IP_NAT_CORE_H */
|
|
@ -1,33 +0,0 @@
|
|||
#ifndef _IP_NAT_HELPER_H
|
||||
#define _IP_NAT_HELPER_H
|
||||
/* NAT protocol helper routines. */
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
struct sk_buff;
|
||||
|
||||
/* These return true or false. */
|
||||
extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int match_offset,
|
||||
unsigned int match_len,
|
||||
const char *rep_buffer,
|
||||
unsigned int rep_len);
|
||||
extern int ip_nat_mangle_udp_packet(struct sk_buff **skb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int match_offset,
|
||||
unsigned int match_len,
|
||||
const char *rep_buffer,
|
||||
unsigned int rep_len);
|
||||
extern int ip_nat_seq_adjust(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo);
|
||||
|
||||
/* Setup NAT on this expected conntrack so it follows master, but goes
|
||||
* to port ct->master->saved_proto. */
|
||||
extern void ip_nat_follow_master(struct ip_conntrack *ct,
|
||||
struct ip_conntrack_expect *this);
|
||||
#endif
|
|
@ -1,11 +0,0 @@
|
|||
/* PPTP constants and structs */
|
||||
#ifndef _NAT_PPTP_H
|
||||
#define _NAT_PPTP_H
|
||||
|
||||
/* conntrack private data */
|
||||
struct ip_nat_pptp {
|
||||
__be16 pns_call_id; /* NAT'ed PNS call id */
|
||||
__be16 pac_call_id; /* NAT'ed PAC call id */
|
||||
};
|
||||
|
||||
#endif /* _NAT_PPTP_H */
|
|
@ -1,74 +0,0 @@
|
|||
/* Header for use in defining a given protocol. */
|
||||
#ifndef _IP_NAT_PROTOCOL_H
|
||||
#define _IP_NAT_PROTOCOL_H
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter/nfnetlink_conntrack.h>
|
||||
|
||||
struct iphdr;
|
||||
struct ip_nat_range;
|
||||
|
||||
struct ip_nat_protocol
|
||||
{
|
||||
/* Protocol name */
|
||||
const char *name;
|
||||
|
||||
/* Protocol number. */
|
||||
unsigned int protonum;
|
||||
|
||||
struct module *me;
|
||||
|
||||
/* Translate a packet to the target according to manip type.
|
||||
Return true if succeeded. */
|
||||
int (*manip_pkt)(struct sk_buff **pskb,
|
||||
unsigned int iphdroff,
|
||||
const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype);
|
||||
|
||||
/* Is the manipable part of the tuple between min and max incl? */
|
||||
int (*in_range)(const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const union ip_conntrack_manip_proto *min,
|
||||
const union ip_conntrack_manip_proto *max);
|
||||
|
||||
/* Alter the per-proto part of the tuple (depending on
|
||||
maniptype), to give a unique tuple in the given range if
|
||||
possible; return false if not. Per-protocol part of tuple
|
||||
is initialized to the incoming packet. */
|
||||
int (*unique_tuple)(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_nat_range *range,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const struct ip_conntrack *conntrack);
|
||||
|
||||
int (*range_to_nfattr)(struct sk_buff *skb,
|
||||
const struct ip_nat_range *range);
|
||||
|
||||
int (*nfattr_to_range)(struct nfattr *tb[],
|
||||
struct ip_nat_range *range);
|
||||
};
|
||||
|
||||
/* Protocol registration. */
|
||||
extern int ip_nat_protocol_register(struct ip_nat_protocol *proto);
|
||||
extern void ip_nat_protocol_unregister(struct ip_nat_protocol *proto);
|
||||
|
||||
extern struct ip_nat_protocol *ip_nat_proto_find_get(u_int8_t protocol);
|
||||
extern void ip_nat_proto_put(struct ip_nat_protocol *proto);
|
||||
|
||||
/* Built-in protocols. */
|
||||
extern struct ip_nat_protocol ip_nat_protocol_tcp;
|
||||
extern struct ip_nat_protocol ip_nat_protocol_udp;
|
||||
extern struct ip_nat_protocol ip_nat_protocol_icmp;
|
||||
extern struct ip_nat_protocol ip_nat_unknown_protocol;
|
||||
|
||||
extern int init_protocols(void) __init;
|
||||
extern void cleanup_protocols(void);
|
||||
extern struct ip_nat_protocol *find_nat_proto(u_int16_t protonum);
|
||||
|
||||
extern int ip_nat_port_range_to_nfattr(struct sk_buff *skb,
|
||||
const struct ip_nat_range *range);
|
||||
extern int ip_nat_port_nfattr_to_range(struct nfattr *tb[],
|
||||
struct ip_nat_range *range);
|
||||
|
||||
#endif /*_IP_NAT_PROTO_H*/
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef _IP_NAT_RULE_H
|
||||
#define _IP_NAT_RULE_H
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
extern int ip_nat_rule_init(void) __init;
|
||||
extern void ip_nat_rule_cleanup(void);
|
||||
extern int ip_nat_rule_find(struct sk_buff **pskb,
|
||||
unsigned int hooknum,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
struct ip_conntrack *ct,
|
||||
struct ip_nat_info *info);
|
||||
|
||||
extern unsigned int
|
||||
alloc_null_binding(struct ip_conntrack *conntrack,
|
||||
struct ip_nat_info *info,
|
||||
unsigned int hooknum);
|
||||
|
||||
extern unsigned int
|
||||
alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
|
||||
struct ip_nat_info *info,
|
||||
unsigned int hooknum);
|
||||
#endif
|
||||
#endif /* _IP_NAT_RULE_H */
|
|
@ -13,7 +13,7 @@ struct ipt_same_info
|
|||
u_int32_t *iparray;
|
||||
|
||||
/* hangs off end. */
|
||||
struct ip_nat_range range[IPT_SAME_MAX_RANGE];
|
||||
struct nf_nat_range range[IPT_SAME_MAX_RANGE];
|
||||
};
|
||||
|
||||
#endif /*_IPT_SAME_H*/
|
||||
|
|
|
@ -250,6 +250,11 @@ static inline int nf_ct_is_dying(struct nf_conn *ct)
|
|||
return test_bit(IPS_DYING_BIT, &ct->status);
|
||||
}
|
||||
|
||||
static inline int nf_ct_is_untracked(const struct sk_buff *skb)
|
||||
{
|
||||
return (skb->nfct == &nf_conntrack_untracked.ct_general);
|
||||
}
|
||||
|
||||
extern unsigned int nf_conntrack_htable_size;
|
||||
extern int nf_conntrack_checksum;
|
||||
extern atomic_t nf_conntrack_count;
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
#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>
|
||||
#include <linux/socket.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_CONNTRACK_SECMARK
|
||||
static inline u_int32_t *nf_ct_get_secmark(const struct sk_buff *skb,
|
||||
u_int32_t *ctinfo)
|
||||
{
|
||||
struct ip_conntrack *ct = ip_conntrack_get(skb, ctinfo);
|
||||
|
||||
if (ct)
|
||||
return &ct->secmark;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_IP_NF_CONNTRACK_SECMARK */
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
static inline int nf_ct_l3proto_try_module_get(unsigned short l3proto)
|
||||
{
|
||||
need_conntrack();
|
||||
return l3proto == PF_INET ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline void nf_ct_l3proto_module_put(unsigned short l3proto)
|
||||
{
|
||||
}
|
||||
|
||||
#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_CONNTRACK_SECMARK
|
||||
static inline u_int32_t *nf_ct_get_secmark(const struct sk_buff *skb,
|
||||
u_int32_t *ctinfo)
|
||||
{
|
||||
struct nf_conn *ct = nf_ct_get(skb, ctinfo);
|
||||
|
||||
if (ct)
|
||||
return &ct->secmark;
|
||||
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 */
|
|
@ -4,16 +4,6 @@
|
|||
#include <net/netfilter/nf_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
|
||||
/* Compatibility definitions for ipt_FOO modules */
|
||||
#define ip_nat_range nf_nat_range
|
||||
#define ip_conntrack_tuple nf_conntrack_tuple
|
||||
#define ip_conntrack_get nf_ct_get
|
||||
#define ip_conntrack nf_conn
|
||||
#define ip_nat_setup_info nf_nat_setup_info
|
||||
#define ip_nat_multi_range_compat nf_nat_multi_range_compat
|
||||
#define ip_ct_iterate_cleanup nf_ct_iterate_cleanup
|
||||
#define IP_NF_ASSERT NF_CT_ASSERT
|
||||
|
||||
extern int nf_nat_rule_init(void) __init;
|
||||
extern void nf_nat_rule_cleanup(void);
|
||||
extern int nf_nat_rule_find(struct sk_buff **pskb,
|
||||
|
|
|
@ -30,188 +30,6 @@ config NF_CONNTRACK_PROC_COMPAT
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
# connection tracking, helpers and protocols
|
||||
config IP_NF_CT_ACCT
|
||||
bool "Connection tracking flow accounting"
|
||||
depends on IP_NF_CONNTRACK
|
||||
help
|
||||
If this option is enabled, the connection tracking code will
|
||||
keep per-flow packet and byte counters.
|
||||
|
||||
Those counters can be used for flow-based accounting or the
|
||||
`connbytes' match.
|
||||
|
||||
If unsure, say `N'.
|
||||
|
||||
config IP_NF_CONNTRACK_MARK
|
||||
bool 'Connection mark tracking support'
|
||||
depends on IP_NF_CONNTRACK
|
||||
help
|
||||
This option enables support for connection marks, used by the
|
||||
`CONNMARK' target and `connmark' match. Similar to the mark value
|
||||
of packets, but this mark value is kept in the conntrack session
|
||||
instead of the individual packets.
|
||||
|
||||
config IP_NF_CONNTRACK_SECMARK
|
||||
bool 'Connection tracking security mark support'
|
||||
depends on IP_NF_CONNTRACK && NETWORK_SECMARK
|
||||
help
|
||||
This option enables security markings to be applied to
|
||||
connections. Typically they are copied to connections from
|
||||
packets using the CONNSECMARK target and copied back from
|
||||
connections to packets with the same target, with the packets
|
||||
being originally labeled via SECMARK.
|
||||
|
||||
If unsure, say 'N'.
|
||||
|
||||
config IP_NF_CONNTRACK_EVENTS
|
||||
bool "Connection tracking events (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && IP_NF_CONNTRACK
|
||||
help
|
||||
If this option is enabled, the connection tracking code will
|
||||
provide a notifier chain that can be used by other kernel code
|
||||
to get notified about changes in the connection tracking state.
|
||||
|
||||
IF unsure, say `N'.
|
||||
|
||||
config IP_NF_CONNTRACK_NETLINK
|
||||
tristate 'Connection tracking netlink interface (EXPERIMENTAL)'
|
||||
depends on EXPERIMENTAL && IP_NF_CONNTRACK && NETFILTER_NETLINK
|
||||
depends on IP_NF_CONNTRACK!=y || NETFILTER_NETLINK!=m
|
||||
depends on IP_NF_NAT=n || IP_NF_NAT
|
||||
help
|
||||
This option enables support for a netlink-based userspace interface
|
||||
|
||||
|
||||
config IP_NF_CT_PROTO_SCTP
|
||||
tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)'
|
||||
depends on IP_NF_CONNTRACK && EXPERIMENTAL
|
||||
help
|
||||
With this option enabled, the connection tracking code will
|
||||
be able to do state tracking on SCTP connections.
|
||||
|
||||
If you want to compile it as a module, say M here and read
|
||||
<file:Documentation/modules.txt>. If unsure, say `N'.
|
||||
|
||||
config IP_NF_FTP
|
||||
tristate "FTP protocol support"
|
||||
depends on IP_NF_CONNTRACK
|
||||
help
|
||||
Tracking FTP connections is problematic: special helpers are
|
||||
required for tracking them, and doing masquerading and other forms
|
||||
of Network Address Translation on them.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say Y.
|
||||
|
||||
config IP_NF_IRC
|
||||
tristate "IRC protocol support"
|
||||
depends on IP_NF_CONNTRACK
|
||||
---help---
|
||||
There is a commonly-used extension to IRC called
|
||||
Direct Client-to-Client Protocol (DCC). This enables users to send
|
||||
files to each other, and also chat to each other without the need
|
||||
of a server. DCC Sending is used anywhere you send files over IRC,
|
||||
and DCC Chat is most commonly used by Eggdrop bots. If you are
|
||||
using NAT, this extension will enable you to send files and initiate
|
||||
chats. Note that you do NOT need this extension to get files or
|
||||
have others initiate chats, or everything else in IRC.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say Y.
|
||||
|
||||
config IP_NF_NETBIOS_NS
|
||||
tristate "NetBIOS name service protocol support (EXPERIMENTAL)"
|
||||
depends on IP_NF_CONNTRACK && EXPERIMENTAL
|
||||
help
|
||||
NetBIOS name service requests are sent as broadcast messages from an
|
||||
unprivileged port and responded to with unicast messages to the
|
||||
same port. This make them hard to firewall properly because connection
|
||||
tracking doesn't deal with broadcasts. This helper tracks locally
|
||||
originating NetBIOS name service requests and the corresponding
|
||||
responses. It relies on correct IP address configuration, specifically
|
||||
netmask and broadcast address. When properly configured, the output
|
||||
of "ip address show" should look similar to this:
|
||||
|
||||
$ ip -4 address show eth0
|
||||
4: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000
|
||||
inet 172.16.2.252/24 brd 172.16.2.255 scope global eth0
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP_NF_TFTP
|
||||
tristate "TFTP protocol support"
|
||||
depends on IP_NF_CONNTRACK
|
||||
help
|
||||
TFTP connection tracking helper, this is required depending
|
||||
on how restrictive your ruleset is.
|
||||
If you are using a tftp client behind -j SNAT or -j MASQUERADING
|
||||
you will need this.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say Y.
|
||||
|
||||
config IP_NF_AMANDA
|
||||
tristate "Amanda backup protocol support"
|
||||
depends on IP_NF_CONNTRACK
|
||||
select TEXTSEARCH
|
||||
select TEXTSEARCH_KMP
|
||||
help
|
||||
If you are running the Amanda backup package <http://www.amanda.org/>
|
||||
on this machine or machines that will be MASQUERADED through this
|
||||
machine, then you may want to enable this feature. This allows the
|
||||
connection tracking and natting code to allow the sub-channels that
|
||||
Amanda requires for communication of the backup data, messages and
|
||||
index.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say Y.
|
||||
|
||||
config IP_NF_PPTP
|
||||
tristate 'PPTP protocol support'
|
||||
depends on IP_NF_CONNTRACK
|
||||
help
|
||||
This module adds support for PPTP (Point to Point Tunnelling
|
||||
Protocol, RFC2637) connection tracking and NAT.
|
||||
|
||||
If you are running PPTP sessions over a stateful firewall or NAT
|
||||
box, you may want to enable this feature.
|
||||
|
||||
Please note that not all PPTP modes of operation are supported yet.
|
||||
For more info, read top of the file
|
||||
net/ipv4/netfilter/ip_conntrack_pptp.c
|
||||
|
||||
If you want to compile it as a module, say M here and read
|
||||
Documentation/modules.txt. If unsure, say `N'.
|
||||
|
||||
config IP_NF_H323
|
||||
tristate 'H.323 protocol support (EXPERIMENTAL)'
|
||||
depends on IP_NF_CONNTRACK && EXPERIMENTAL
|
||||
help
|
||||
H.323 is a VoIP signalling protocol from ITU-T. As one of the most
|
||||
important VoIP protocols, it is widely used by voice hardware and
|
||||
software including voice gateways, IP phones, Netmeeting, OpenPhone,
|
||||
Gnomemeeting, etc.
|
||||
|
||||
With this module you can support H.323 on a connection tracking/NAT
|
||||
firewall.
|
||||
|
||||
This module supports RAS, Fast Start, H.245 Tunnelling, Call
|
||||
Forwarding, RTP/RTCP and T.120 based audio, video, fax, chat,
|
||||
whiteboard, file transfer, etc. For more information, please
|
||||
visit http://nath323.sourceforge.net/.
|
||||
|
||||
If you want to compile it as a module, say 'M' here and read
|
||||
Documentation/modules.txt. If unsure, say 'N'.
|
||||
|
||||
config IP_NF_SIP
|
||||
tristate "SIP protocol support (EXPERIMENTAL)"
|
||||
depends on IP_NF_CONNTRACK && EXPERIMENTAL
|
||||
help
|
||||
SIP is an application-layer control protocol that can establish,
|
||||
modify, and terminate multimedia sessions (conferences) such as
|
||||
Internet telephony calls. With the ip_conntrack_sip and
|
||||
the ip_nat_sip modules you can support the protocol on a connection
|
||||
tracking/NATing firewall.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say Y.
|
||||
|
||||
config IP_NF_QUEUE
|
||||
tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
|
||||
help
|
||||
|
@ -361,17 +179,6 @@ config IP_NF_TARGET_ULOG
|
|||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
# NAT + specific targets: ip_conntrack
|
||||
config IP_NF_NAT
|
||||
tristate "Full NAT"
|
||||
depends on IP_NF_IPTABLES && IP_NF_CONNTRACK
|
||||
help
|
||||
The Full NAT option allows masquerading, port forwarding and other
|
||||
forms of full Network Address Port Translation. It is controlled by
|
||||
the `nat' table in iptables: see the man page for iptables(8).
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
# NAT + specific targets: nf_conntrack
|
||||
config NF_NAT
|
||||
tristate "Full NAT"
|
||||
|
@ -383,11 +190,6 @@ config NF_NAT
|
|||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP_NF_NAT_NEEDED
|
||||
bool
|
||||
depends on IP_NF_NAT
|
||||
default y
|
||||
|
||||
config NF_NAT_NEEDED
|
||||
bool
|
||||
depends on NF_NAT
|
||||
|
@ -395,7 +197,7 @@ config NF_NAT_NEEDED
|
|||
|
||||
config IP_NF_TARGET_MASQUERADE
|
||||
tristate "MASQUERADE target support"
|
||||
depends on (NF_NAT || IP_NF_NAT)
|
||||
depends on NF_NAT
|
||||
help
|
||||
Masquerading is a special case of NAT: all outgoing connections are
|
||||
changed to seem to come from a particular interface's address, and
|
||||
|
@ -407,7 +209,7 @@ config IP_NF_TARGET_MASQUERADE
|
|||
|
||||
config IP_NF_TARGET_REDIRECT
|
||||
tristate "REDIRECT target support"
|
||||
depends on (NF_NAT || IP_NF_NAT)
|
||||
depends on NF_NAT
|
||||
help
|
||||
REDIRECT is a special case of NAT: all incoming connections are
|
||||
mapped onto the incoming interface's address, causing the packets to
|
||||
|
@ -418,7 +220,7 @@ config IP_NF_TARGET_REDIRECT
|
|||
|
||||
config IP_NF_TARGET_NETMAP
|
||||
tristate "NETMAP target support"
|
||||
depends on (NF_NAT || IP_NF_NAT)
|
||||
depends on NF_NAT
|
||||
help
|
||||
NETMAP is an implementation of static 1:1 NAT mapping of network
|
||||
addresses. It maps the network address part, while keeping the host
|
||||
|
@ -429,28 +231,13 @@ config IP_NF_TARGET_NETMAP
|
|||
|
||||
config IP_NF_TARGET_SAME
|
||||
tristate "SAME target support"
|
||||
depends on (NF_NAT || IP_NF_NAT)
|
||||
depends on NF_NAT
|
||||
help
|
||||
This option adds a `SAME' target, which works like the standard SNAT
|
||||
target, but attempts to give clients the same IP for all connections.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP_NF_NAT_SNMP_BASIC
|
||||
tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && IP_NF_NAT
|
||||
---help---
|
||||
|
||||
This module implements an Application Layer Gateway (ALG) for
|
||||
SNMP payloads. In conjunction with NAT, it allows a network
|
||||
management system to access multiple private networks with
|
||||
conflicting addresses. It works by modifying IP addresses
|
||||
inside SNMP payloads to match IP-layer NAT mapping.
|
||||
|
||||
This is the "basic" form of SNMP-ALG, as described in RFC 2962
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config NF_NAT_SNMP_BASIC
|
||||
tristate "Basic SNMP-ALG support (EXPERIMENTAL)"
|
||||
depends on EXPERIMENTAL && NF_NAT
|
||||
|
@ -477,78 +264,37 @@ config NF_NAT_PROTO_GRE
|
|||
tristate
|
||||
depends on NF_NAT && NF_CT_PROTO_GRE
|
||||
|
||||
config IP_NF_NAT_FTP
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES && IP_NF_CONNTRACK && IP_NF_NAT
|
||||
default IP_NF_NAT && IP_NF_FTP
|
||||
|
||||
config NF_NAT_FTP
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
|
||||
default NF_NAT && NF_CONNTRACK_FTP
|
||||
|
||||
config IP_NF_NAT_IRC
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
|
||||
default IP_NF_NAT if IP_NF_IRC=y
|
||||
default m if IP_NF_IRC=m
|
||||
|
||||
config NF_NAT_IRC
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
|
||||
default NF_NAT && NF_CONNTRACK_IRC
|
||||
|
||||
config IP_NF_NAT_TFTP
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
|
||||
default IP_NF_NAT if IP_NF_TFTP=y
|
||||
default m if IP_NF_TFTP=m
|
||||
|
||||
config NF_NAT_TFTP
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
|
||||
default NF_NAT && NF_CONNTRACK_TFTP
|
||||
|
||||
config IP_NF_NAT_AMANDA
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
|
||||
default IP_NF_NAT if IP_NF_AMANDA=y
|
||||
default m if IP_NF_AMANDA=m
|
||||
|
||||
config NF_NAT_AMANDA
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
|
||||
default NF_NAT && NF_CONNTRACK_AMANDA
|
||||
|
||||
config IP_NF_NAT_PPTP
|
||||
tristate
|
||||
depends on IP_NF_NAT!=n && IP_NF_PPTP!=n
|
||||
default IP_NF_NAT if IP_NF_PPTP=y
|
||||
default m if IP_NF_PPTP=m
|
||||
|
||||
config NF_NAT_PPTP
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
|
||||
default NF_NAT && NF_CONNTRACK_PPTP
|
||||
select NF_NAT_PROTO_GRE
|
||||
|
||||
config IP_NF_NAT_H323
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
|
||||
default IP_NF_NAT if IP_NF_H323=y
|
||||
default m if IP_NF_H323=m
|
||||
|
||||
config NF_NAT_H323
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
|
||||
default NF_NAT && NF_CONNTRACK_H323
|
||||
|
||||
config IP_NF_NAT_SIP
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
|
||||
default IP_NF_NAT if IP_NF_SIP=y
|
||||
default m if IP_NF_SIP=m
|
||||
|
||||
config NF_NAT_SIP
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
|
||||
|
@ -606,9 +352,8 @@ config IP_NF_TARGET_TTL
|
|||
config IP_NF_TARGET_CLUSTERIP
|
||||
tristate "CLUSTERIP target support (EXPERIMENTAL)"
|
||||
depends on IP_NF_MANGLE && EXPERIMENTAL
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK_IPV4
|
||||
select IP_NF_CONNTRACK_MARK if IP_NF_CONNTRACK
|
||||
select NF_CONNTRACK_MARK if NF_CONNTRACK_IPV4
|
||||
depends on NF_CONNTRACK_IPV4
|
||||
select NF_CONNTRACK_MARK
|
||||
help
|
||||
The CLUSTERIP target allows you to build load-balancing clusters of
|
||||
network servers without having a dedicated load-balancing
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
# Makefile for the netfilter modules on top of IPv4.
|
||||
#
|
||||
|
||||
# objects for the standalone - connection tracking / NAT
|
||||
ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o
|
||||
# objects for l3 independent conntrack
|
||||
nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
|
||||
ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y)
|
||||
|
@ -12,53 +10,14 @@ nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o
|
|||
endif
|
||||
endif
|
||||
|
||||
ip_nat-objs := ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o
|
||||
nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o
|
||||
ifneq ($(CONFIG_NF_NAT),)
|
||||
nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o
|
||||
iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o
|
||||
else
|
||||
iptable_nat-objs := ip_nat_rule.o ip_nat_standalone.o
|
||||
endif
|
||||
|
||||
ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o
|
||||
ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o
|
||||
|
||||
ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ../../netfilter/nf_conntrack_h323_asn1.o
|
||||
ip_nat_h323-objs := ip_nat_helper_h323.o
|
||||
|
||||
# connection tracking
|
||||
obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
|
||||
obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o
|
||||
|
||||
obj-$(CONFIG_IP_NF_NAT) += ip_nat.o
|
||||
obj-$(CONFIG_NF_NAT) += nf_nat.o
|
||||
|
||||
# conntrack netlink interface
|
||||
obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o
|
||||
|
||||
|
||||
# SCTP protocol connection tracking
|
||||
obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o
|
||||
|
||||
# connection tracking helpers
|
||||
obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
|
||||
obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
|
||||
obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
|
||||
obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
|
||||
obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
|
||||
obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
|
||||
obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o
|
||||
obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
|
||||
|
||||
# NAT helpers (ip_conntrack)
|
||||
obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
|
||||
obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
|
||||
obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
|
||||
obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
|
||||
obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
|
||||
obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
|
||||
obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o
|
||||
|
||||
# NAT helpers (nf_conntrack)
|
||||
obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
|
||||
obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
|
||||
|
@ -78,7 +37,6 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
|
|||
# the three instances of ip_tables
|
||||
obj-$(CONFIG_IP_NF_FILTER) += iptable_filter.o
|
||||
obj-$(CONFIG_IP_NF_MANGLE) += iptable_mangle.o
|
||||
obj-$(CONFIG_IP_NF_NAT) += iptable_nat.o
|
||||
obj-$(CONFIG_NF_NAT) += iptable_nat.o
|
||||
obj-$(CONFIG_IP_NF_RAW) += iptable_raw.o
|
||||
|
||||
|
@ -100,7 +58,6 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
|
|||
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
|
||||
obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
|
||||
|
|
|
@ -1,229 +0,0 @@
|
|||
/* Amanda extension for IP connection tracking, Version 0.2
|
||||
* (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
|
||||
* based on HW's ip_conntrack_irc.c as well as other modules
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Module load syntax:
|
||||
* insmod ip_conntrack_amanda.o [master_timeout=n]
|
||||
*
|
||||
* Where master_timeout is the timeout (in seconds) of the master
|
||||
* connection (port 10080). This defaults to 5 minutes but if
|
||||
* your clients take longer than 5 minutes to do their work
|
||||
* before getting back to the Amanda server, you can increase
|
||||
* this value.
|
||||
*
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/textsearch.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
|
||||
|
||||
static unsigned int master_timeout = 300;
|
||||
static char *ts_algo = "kmp";
|
||||
|
||||
MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
|
||||
MODULE_DESCRIPTION("Amanda connection tracking module");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_param(master_timeout, uint, 0600);
|
||||
MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
|
||||
module_param(ts_algo, charp, 0400);
|
||||
MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)");
|
||||
|
||||
unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
struct ip_conntrack_expect *exp);
|
||||
EXPORT_SYMBOL_GPL(ip_nat_amanda_hook);
|
||||
|
||||
enum amanda_strings {
|
||||
SEARCH_CONNECT,
|
||||
SEARCH_NEWLINE,
|
||||
SEARCH_DATA,
|
||||
SEARCH_MESG,
|
||||
SEARCH_INDEX,
|
||||
};
|
||||
|
||||
static struct {
|
||||
char *string;
|
||||
size_t len;
|
||||
struct ts_config *ts;
|
||||
} search[] = {
|
||||
[SEARCH_CONNECT] = {
|
||||
.string = "CONNECT ",
|
||||
.len = 8,
|
||||
},
|
||||
[SEARCH_NEWLINE] = {
|
||||
.string = "\n",
|
||||
.len = 1,
|
||||
},
|
||||
[SEARCH_DATA] = {
|
||||
.string = "DATA ",
|
||||
.len = 5,
|
||||
},
|
||||
[SEARCH_MESG] = {
|
||||
.string = "MESG ",
|
||||
.len = 5,
|
||||
},
|
||||
[SEARCH_INDEX] = {
|
||||
.string = "INDEX ",
|
||||
.len = 6,
|
||||
},
|
||||
};
|
||||
|
||||
static int help(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
struct ts_state ts;
|
||||
struct ip_conntrack_expect *exp;
|
||||
unsigned int dataoff, start, stop, off, i;
|
||||
char pbuf[sizeof("65535")], *tmp;
|
||||
u_int16_t port, len;
|
||||
int ret = NF_ACCEPT;
|
||||
typeof(ip_nat_amanda_hook) ip_nat_amanda;
|
||||
|
||||
/* Only look at packets from the Amanda server */
|
||||
if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
|
||||
return NF_ACCEPT;
|
||||
|
||||
/* increase the UDP timeout of the master connection as replies from
|
||||
* Amanda clients to the server can be quite delayed */
|
||||
ip_ct_refresh(ct, *pskb, master_timeout * HZ);
|
||||
|
||||
/* No data? */
|
||||
dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
|
||||
if (dataoff >= (*pskb)->len) {
|
||||
if (net_ratelimit())
|
||||
printk("amanda_help: skblen = %u\n", (*pskb)->len);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
start = skb_find_text(*pskb, dataoff, (*pskb)->len,
|
||||
search[SEARCH_CONNECT].ts, &ts);
|
||||
if (start == UINT_MAX)
|
||||
goto out;
|
||||
start += dataoff + search[SEARCH_CONNECT].len;
|
||||
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
stop = skb_find_text(*pskb, start, (*pskb)->len,
|
||||
search[SEARCH_NEWLINE].ts, &ts);
|
||||
if (stop == UINT_MAX)
|
||||
goto out;
|
||||
stop += start;
|
||||
|
||||
for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) {
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
off = skb_find_text(*pskb, start, stop, search[i].ts, &ts);
|
||||
if (off == UINT_MAX)
|
||||
continue;
|
||||
off += start + search[i].len;
|
||||
|
||||
len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off);
|
||||
if (skb_copy_bits(*pskb, off, pbuf, len))
|
||||
break;
|
||||
pbuf[len] = '\0';
|
||||
|
||||
port = simple_strtoul(pbuf, &tmp, 10);
|
||||
len = tmp - pbuf;
|
||||
if (port == 0 || len > 5)
|
||||
break;
|
||||
|
||||
exp = ip_conntrack_expect_alloc(ct);
|
||||
if (exp == NULL) {
|
||||
ret = NF_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
exp->expectfn = NULL;
|
||||
exp->flags = 0;
|
||||
|
||||
exp->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
|
||||
exp->tuple.src.u.tcp.port = 0;
|
||||
exp->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
|
||||
exp->tuple.dst.protonum = IPPROTO_TCP;
|
||||
exp->tuple.dst.u.tcp.port = htons(port);
|
||||
|
||||
exp->mask.src.ip = htonl(0xFFFFFFFF);
|
||||
exp->mask.src.u.tcp.port = 0;
|
||||
exp->mask.dst.ip = htonl(0xFFFFFFFF);
|
||||
exp->mask.dst.protonum = 0xFF;
|
||||
exp->mask.dst.u.tcp.port = htons(0xFFFF);
|
||||
|
||||
/* RCU read locked by nf_hook_slow */
|
||||
ip_nat_amanda = rcu_dereference(ip_nat_amanda_hook);
|
||||
if (ip_nat_amanda)
|
||||
ret = ip_nat_amanda(pskb, ctinfo, off - dataoff,
|
||||
len, exp);
|
||||
else if (ip_conntrack_expect_related(exp) != 0)
|
||||
ret = NF_DROP;
|
||||
ip_conntrack_expect_put(exp);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ip_conntrack_helper amanda_helper = {
|
||||
.max_expected = 3,
|
||||
.timeout = 180,
|
||||
.me = THIS_MODULE,
|
||||
.help = help,
|
||||
.name = "amanda",
|
||||
|
||||
.tuple = { .src = { .u = { .udp = {.port = __constant_htons(10080) } } },
|
||||
.dst = { .protonum = IPPROTO_UDP },
|
||||
},
|
||||
.mask = { .src = { .u = { 0xFFFF } },
|
||||
.dst = { .protonum = 0xFF },
|
||||
},
|
||||
};
|
||||
|
||||
static void __exit ip_conntrack_amanda_fini(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
ip_conntrack_helper_unregister(&amanda_helper);
|
||||
for (i = 0; i < ARRAY_SIZE(search); i++)
|
||||
textsearch_destroy(search[i].ts);
|
||||
}
|
||||
|
||||
static int __init ip_conntrack_amanda_init(void)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
ret = -ENOMEM;
|
||||
for (i = 0; i < ARRAY_SIZE(search); i++) {
|
||||
search[i].ts = textsearch_prepare(ts_algo, search[i].string,
|
||||
search[i].len,
|
||||
GFP_KERNEL, TS_AUTOLOAD);
|
||||
if (search[i].ts == NULL)
|
||||
goto err;
|
||||
}
|
||||
ret = ip_conntrack_helper_register(&amanda_helper);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
for (; i >= 0; i--) {
|
||||
if (search[i].ts)
|
||||
textsearch_destroy(search[i].ts);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
module_init(ip_conntrack_amanda_init);
|
||||
module_exit(ip_conntrack_amanda_fini);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,520 +0,0 @@
|
|||
/* FTP extension for IP connection tracking. */
|
||||
|
||||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
|
||||
MODULE_DESCRIPTION("ftp connection tracking helper");
|
||||
|
||||
/* This is slow, but it's simple. --RR */
|
||||
static char *ftp_buffer;
|
||||
static DEFINE_SPINLOCK(ip_ftp_lock);
|
||||
|
||||
#define MAX_PORTS 8
|
||||
static unsigned short ports[MAX_PORTS];
|
||||
static int ports_c;
|
||||
module_param_array(ports, ushort, &ports_c, 0400);
|
||||
|
||||
static int loose;
|
||||
module_param(loose, bool, 0600);
|
||||
|
||||
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);
|
||||
EXPORT_SYMBOL_GPL(ip_nat_ftp_hook);
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
static int try_rfc959(const char *, size_t, u_int32_t [], char);
|
||||
static int try_eprt(const char *, size_t, u_int32_t [], char);
|
||||
static int try_epsv_response(const char *, size_t, u_int32_t [], char);
|
||||
|
||||
static const struct ftp_search {
|
||||
const char *pattern;
|
||||
size_t plen;
|
||||
char skip;
|
||||
char term;
|
||||
enum ip_ct_ftp_type ftptype;
|
||||
int (*getnum)(const char *, size_t, u_int32_t[], char);
|
||||
} search[IP_CT_DIR_MAX][2] = {
|
||||
[IP_CT_DIR_ORIGINAL] = {
|
||||
{
|
||||
.pattern = "PORT",
|
||||
.plen = sizeof("PORT") - 1,
|
||||
.skip = ' ',
|
||||
.term = '\r',
|
||||
.ftptype = IP_CT_FTP_PORT,
|
||||
.getnum = try_rfc959,
|
||||
},
|
||||
{
|
||||
.pattern = "EPRT",
|
||||
.plen = sizeof("EPRT") - 1,
|
||||
.skip = ' ',
|
||||
.term = '\r',
|
||||
.ftptype = IP_CT_FTP_EPRT,
|
||||
.getnum = try_eprt,
|
||||
},
|
||||
},
|
||||
[IP_CT_DIR_REPLY] = {
|
||||
{
|
||||
.pattern = "227 ",
|
||||
.plen = sizeof("227 ") - 1,
|
||||
.skip = '(',
|
||||
.term = ')',
|
||||
.ftptype = IP_CT_FTP_PASV,
|
||||
.getnum = try_rfc959,
|
||||
},
|
||||
{
|
||||
.pattern = "229 ",
|
||||
.plen = sizeof("229 ") - 1,
|
||||
.skip = '(',
|
||||
.term = ')',
|
||||
.ftptype = IP_CT_FTP_EPSV,
|
||||
.getnum = try_epsv_response,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static int try_number(const char *data, size_t dlen, u_int32_t array[],
|
||||
int array_size, char sep, char term)
|
||||
{
|
||||
u_int32_t i, len;
|
||||
|
||||
memset(array, 0, sizeof(array[0])*array_size);
|
||||
|
||||
/* Keep data pointing at next char. */
|
||||
for (i = 0, len = 0; len < dlen && i < array_size; len++, data++) {
|
||||
if (*data >= '0' && *data <= '9') {
|
||||
array[i] = array[i]*10 + *data - '0';
|
||||
}
|
||||
else if (*data == sep)
|
||||
i++;
|
||||
else {
|
||||
/* Unexpected character; true if it's the
|
||||
terminator and we're finished. */
|
||||
if (*data == term && i == array_size - 1)
|
||||
return len;
|
||||
|
||||
DEBUGP("Char %u (got %u nums) `%u' unexpected\n",
|
||||
len, i, *data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
DEBUGP("Failed to fill %u numbers separated by %c\n", array_size, sep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0, or length of numbers: 192,168,1,1,5,6 */
|
||||
static int try_rfc959(const char *data, size_t dlen, u_int32_t array[6],
|
||||
char term)
|
||||
{
|
||||
return try_number(data, dlen, array, 6, ',', term);
|
||||
}
|
||||
|
||||
/* Grab port: number up to delimiter */
|
||||
static int get_port(const char *data, int start, size_t dlen, char delim,
|
||||
u_int32_t array[2])
|
||||
{
|
||||
u_int16_t port = 0;
|
||||
int i;
|
||||
|
||||
for (i = start; i < dlen; i++) {
|
||||
/* Finished? */
|
||||
if (data[i] == delim) {
|
||||
if (port == 0)
|
||||
break;
|
||||
array[0] = port >> 8;
|
||||
array[1] = port;
|
||||
return i + 1;
|
||||
}
|
||||
else if (data[i] >= '0' && data[i] <= '9')
|
||||
port = port*10 + data[i] - '0';
|
||||
else /* Some other crap */
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0, or length of numbers: |1|132.235.1.2|6275| */
|
||||
static int try_eprt(const char *data, size_t dlen, u_int32_t array[6],
|
||||
char term)
|
||||
{
|
||||
char delim;
|
||||
int length;
|
||||
|
||||
/* First character is delimiter, then "1" for IPv4, then
|
||||
delimiter again. */
|
||||
if (dlen <= 3) return 0;
|
||||
delim = data[0];
|
||||
if (isdigit(delim) || delim < 33 || delim > 126
|
||||
|| data[1] != '1' || data[2] != delim)
|
||||
return 0;
|
||||
|
||||
DEBUGP("EPRT: Got |1|!\n");
|
||||
/* Now we have IP address. */
|
||||
length = try_number(data + 3, dlen - 3, array, 4, '.', delim);
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
DEBUGP("EPRT: Got IP address!\n");
|
||||
/* Start offset includes initial "|1|", and trailing delimiter */
|
||||
return get_port(data, 3 + length + 1, dlen, delim, array+4);
|
||||
}
|
||||
|
||||
/* Returns 0, or length of numbers: |||6446| */
|
||||
static int try_epsv_response(const char *data, size_t dlen, u_int32_t array[6],
|
||||
char term)
|
||||
{
|
||||
char delim;
|
||||
|
||||
/* Three delimiters. */
|
||||
if (dlen <= 3) return 0;
|
||||
delim = data[0];
|
||||
if (isdigit(delim) || delim < 33 || delim > 126
|
||||
|| data[1] != delim || data[2] != delim)
|
||||
return 0;
|
||||
|
||||
return get_port(data, 3, dlen, delim, array+4);
|
||||
}
|
||||
|
||||
/* Return 1 for match, 0 for accept, -1 for partial. */
|
||||
static int find_pattern(const char *data, size_t dlen,
|
||||
const char *pattern, size_t plen,
|
||||
char skip, char term,
|
||||
unsigned int *numoff,
|
||||
unsigned int *numlen,
|
||||
u_int32_t array[6],
|
||||
int (*getnum)(const char *, size_t, u_int32_t[], char))
|
||||
{
|
||||
size_t i;
|
||||
|
||||
DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
|
||||
if (dlen == 0)
|
||||
return 0;
|
||||
|
||||
if (dlen <= plen) {
|
||||
/* Short packet: try for partial? */
|
||||
if (strnicmp(data, pattern, dlen) == 0)
|
||||
return -1;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
if (strnicmp(data, pattern, plen) != 0) {
|
||||
#if 0
|
||||
size_t i;
|
||||
|
||||
DEBUGP("ftp: string mismatch\n");
|
||||
for (i = 0; i < plen; i++) {
|
||||
DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
|
||||
i, data[i], data[i],
|
||||
pattern[i], pattern[i]);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUGP("Pattern matches!\n");
|
||||
/* Now we've found the constant string, try to skip
|
||||
to the 'skip' character */
|
||||
for (i = plen; data[i] != skip; i++)
|
||||
if (i == dlen - 1) return -1;
|
||||
|
||||
/* Skip over the last character */
|
||||
i++;
|
||||
|
||||
DEBUGP("Skipped up to `%c'!\n", skip);
|
||||
|
||||
*numoff = i;
|
||||
*numlen = getnum(data + i, dlen - i, array, term);
|
||||
if (!*numlen)
|
||||
return -1;
|
||||
|
||||
DEBUGP("Match succeeded!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Look up to see if we're just after a \n. */
|
||||
static int find_nl_seq(u32 seq, const struct ip_ct_ftp_master *info, int dir)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < info->seq_aft_nl_num[dir]; i++)
|
||||
if (info->seq_aft_nl[dir][i] == seq)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We don't update if it's older than what we have. */
|
||||
static void update_nl_seq(u32 nl_seq, struct ip_ct_ftp_master *info, int dir,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
unsigned int i, oldest = NUM_SEQ_TO_REMEMBER;
|
||||
|
||||
/* Look for oldest: if we find exact match, we're done. */
|
||||
for (i = 0; i < info->seq_aft_nl_num[dir]; i++) {
|
||||
if (info->seq_aft_nl[dir][i] == nl_seq)
|
||||
return;
|
||||
|
||||
if (oldest == info->seq_aft_nl_num[dir]
|
||||
|| before(info->seq_aft_nl[dir][i], oldest))
|
||||
oldest = i;
|
||||
}
|
||||
|
||||
if (info->seq_aft_nl_num[dir] < NUM_SEQ_TO_REMEMBER) {
|
||||
info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq;
|
||||
ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
|
||||
} else if (oldest != NUM_SEQ_TO_REMEMBER) {
|
||||
info->seq_aft_nl[dir][oldest] = nl_seq;
|
||||
ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
|
||||
}
|
||||
}
|
||||
|
||||
static int help(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
unsigned int dataoff, datalen;
|
||||
struct tcphdr _tcph, *th;
|
||||
char *fb_ptr;
|
||||
int ret;
|
||||
u32 seq, array[6] = { 0 };
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
unsigned int matchlen, matchoff;
|
||||
struct ip_ct_ftp_master *ct_ftp_info = &ct->help.ct_ftp_info;
|
||||
struct ip_conntrack_expect *exp;
|
||||
unsigned int i;
|
||||
int found = 0, ends_in_nl;
|
||||
typeof(ip_nat_ftp_hook) ip_nat_ftp;
|
||||
|
||||
/* Until there's been traffic both ways, don't look in packets. */
|
||||
if (ctinfo != IP_CT_ESTABLISHED
|
||||
&& ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
|
||||
DEBUGP("ftp: Conntrackinfo = %u\n", ctinfo);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
th = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
|
||||
sizeof(_tcph), &_tcph);
|
||||
if (th == NULL)
|
||||
return NF_ACCEPT;
|
||||
|
||||
dataoff = ip_hdrlen(*pskb) + th->doff * 4;
|
||||
/* No data? */
|
||||
if (dataoff >= (*pskb)->len) {
|
||||
DEBUGP("ftp: pskblen = %u\n", (*pskb)->len);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
datalen = (*pskb)->len - dataoff;
|
||||
|
||||
spin_lock_bh(&ip_ftp_lock);
|
||||
fb_ptr = skb_header_pointer(*pskb, dataoff,
|
||||
(*pskb)->len - dataoff, ftp_buffer);
|
||||
BUG_ON(fb_ptr == NULL);
|
||||
|
||||
ends_in_nl = (fb_ptr[datalen - 1] == '\n');
|
||||
seq = ntohl(th->seq) + datalen;
|
||||
|
||||
/* Look up to see if we're just after a \n. */
|
||||
if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) {
|
||||
/* Now if this ends in \n, update ftp info. */
|
||||
DEBUGP("ip_conntrack_ftp_help: wrong seq pos %s(%u) or %s(%u)\n",
|
||||
ct_ftp_info->seq_aft_nl[0][dir]
|
||||
old_seq_aft_nl_set ? "":"(UNSET) ", old_seq_aft_nl);
|
||||
ret = NF_ACCEPT;
|
||||
goto out_update_nl;
|
||||
}
|
||||
|
||||
/* Initialize IP array to expected address (it's not mentioned
|
||||
in EPSV responses) */
|
||||
array[0] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 24) & 0xFF;
|
||||
array[1] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 16) & 0xFF;
|
||||
array[2] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 8) & 0xFF;
|
||||
array[3] = ntohl(ct->tuplehash[dir].tuple.src.ip) & 0xFF;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(search[dir]); i++) {
|
||||
found = find_pattern(fb_ptr, (*pskb)->len - dataoff,
|
||||
search[dir][i].pattern,
|
||||
search[dir][i].plen,
|
||||
search[dir][i].skip,
|
||||
search[dir][i].term,
|
||||
&matchoff, &matchlen,
|
||||
array,
|
||||
search[dir][i].getnum);
|
||||
if (found) break;
|
||||
}
|
||||
if (found == -1) {
|
||||
/* We don't usually drop packets. After all, this is
|
||||
connection tracking, not packet filtering.
|
||||
However, it is necessary for accurate tracking in
|
||||
this case. */
|
||||
if (net_ratelimit())
|
||||
printk("conntrack_ftp: partial %s %u+%u\n",
|
||||
search[dir][i].pattern,
|
||||
ntohl(th->seq), datalen);
|
||||
ret = NF_DROP;
|
||||
goto out;
|
||||
} else if (found == 0) { /* No match */
|
||||
ret = NF_ACCEPT;
|
||||
goto out_update_nl;
|
||||
}
|
||||
|
||||
DEBUGP("conntrack_ftp: match `%s' (%u bytes at %u)\n",
|
||||
fb_ptr + matchoff, matchlen, ntohl(th->seq) + matchoff);
|
||||
|
||||
/* Allocate expectation which will be inserted */
|
||||
exp = ip_conntrack_expect_alloc(ct);
|
||||
if (exp == NULL) {
|
||||
ret = NF_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We refer to the reverse direction ("!dir") tuples here,
|
||||
* because we're expecting something in the other direction.
|
||||
* Doesn't matter unless NAT is happening. */
|
||||
exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
|
||||
|
||||
if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
|
||||
!= ct->tuplehash[dir].tuple.src.ip) {
|
||||
/* Enrico Scholz's passive FTP to partially RNAT'd ftp
|
||||
server: it really wants us to connect to a
|
||||
different IP address. Simply don't record it for
|
||||
NAT. */
|
||||
DEBUGP("conntrack_ftp: NOT RECORDING: %u,%u,%u,%u != %u.%u.%u.%u\n",
|
||||
array[0], array[1], array[2], array[3],
|
||||
NIPQUAD(ct->tuplehash[dir].tuple.src.ip));
|
||||
|
||||
/* Thanks to Cristiano Lincoln Mattos
|
||||
<lincoln@cesar.org.br> for reporting this potential
|
||||
problem (DMZ machines opening holes to internal
|
||||
networks, or the packet filter itself). */
|
||||
if (!loose) {
|
||||
ret = NF_ACCEPT;
|
||||
goto out_put_expect;
|
||||
}
|
||||
exp->tuple.dst.ip = htonl((array[0] << 24) | (array[1] << 16)
|
||||
| (array[2] << 8) | array[3]);
|
||||
}
|
||||
|
||||
exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
|
||||
exp->tuple.dst.u.tcp.port = htons(array[4] << 8 | array[5]);
|
||||
exp->tuple.src.u.tcp.port = 0; /* Don't care. */
|
||||
exp->tuple.dst.protonum = IPPROTO_TCP;
|
||||
exp->mask = ((struct ip_conntrack_tuple)
|
||||
{ { htonl(0xFFFFFFFF), { 0 } },
|
||||
{ htonl(0xFFFFFFFF), { .tcp = { htons(0xFFFF) } }, 0xFF }});
|
||||
|
||||
exp->expectfn = NULL;
|
||||
exp->flags = 0;
|
||||
|
||||
/* Now, NAT might want to mangle the packet, and register the
|
||||
* (possibly changed) expectation itself. */
|
||||
ip_nat_ftp = rcu_dereference(ip_nat_ftp_hook);
|
||||
if (ip_nat_ftp)
|
||||
ret = ip_nat_ftp(pskb, ctinfo, search[dir][i].ftptype,
|
||||
matchoff, matchlen, exp, &seq);
|
||||
else {
|
||||
/* Can't expect this? Best to drop packet now. */
|
||||
if (ip_conntrack_expect_related(exp) != 0)
|
||||
ret = NF_DROP;
|
||||
else
|
||||
ret = NF_ACCEPT;
|
||||
}
|
||||
|
||||
out_put_expect:
|
||||
ip_conntrack_expect_put(exp);
|
||||
|
||||
out_update_nl:
|
||||
/* Now if this ends in \n, update ftp info. Seq may have been
|
||||
* adjusted by NAT code. */
|
||||
if (ends_in_nl)
|
||||
update_nl_seq(seq, ct_ftp_info,dir, *pskb);
|
||||
out:
|
||||
spin_unlock_bh(&ip_ftp_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ip_conntrack_helper ftp[MAX_PORTS];
|
||||
static char ftp_names[MAX_PORTS][sizeof("ftp-65535")];
|
||||
|
||||
/* Not __exit: called from init() */
|
||||
static void ip_conntrack_ftp_fini(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ports_c; i++) {
|
||||
DEBUGP("ip_ct_ftp: unregistering helper for port %d\n",
|
||||
ports[i]);
|
||||
ip_conntrack_helper_unregister(&ftp[i]);
|
||||
}
|
||||
|
||||
kfree(ftp_buffer);
|
||||
}
|
||||
|
||||
static int __init ip_conntrack_ftp_init(void)
|
||||
{
|
||||
int i, ret;
|
||||
char *tmpname;
|
||||
|
||||
ftp_buffer = kmalloc(65536, GFP_KERNEL);
|
||||
if (!ftp_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ports_c == 0)
|
||||
ports[ports_c++] = FTP_PORT;
|
||||
|
||||
for (i = 0; i < ports_c; i++) {
|
||||
ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
|
||||
ftp[i].tuple.dst.protonum = IPPROTO_TCP;
|
||||
ftp[i].mask.src.u.tcp.port = htons(0xFFFF);
|
||||
ftp[i].mask.dst.protonum = 0xFF;
|
||||
ftp[i].max_expected = 1;
|
||||
ftp[i].timeout = 5 * 60; /* 5 minutes */
|
||||
ftp[i].me = THIS_MODULE;
|
||||
ftp[i].help = help;
|
||||
|
||||
tmpname = &ftp_names[i][0];
|
||||
if (ports[i] == FTP_PORT)
|
||||
sprintf(tmpname, "ftp");
|
||||
else
|
||||
sprintf(tmpname, "ftp-%d", ports[i]);
|
||||
ftp[i].name = tmpname;
|
||||
|
||||
DEBUGP("ip_ct_ftp: registering helper for port %d\n",
|
||||
ports[i]);
|
||||
ret = ip_conntrack_helper_register(&ftp[i]);
|
||||
|
||||
if (ret) {
|
||||
ip_conntrack_ftp_fini();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(ip_conntrack_ftp_init);
|
||||
module_exit(ip_conntrack_ftp_fini);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,684 +0,0 @@
|
|||
/*
|
||||
* ip_conntrack_pptp.c - Version 3.0
|
||||
*
|
||||
* Connection tracking support for PPTP (Point to Point Tunneling Protocol).
|
||||
* PPTP is a a protocol for creating virtual private networks.
|
||||
* It is a specification defined by Microsoft and some vendors
|
||||
* working with Microsoft. PPTP is built on top of a modified
|
||||
* version of the Internet Generic Routing Encapsulation Protocol.
|
||||
* GRE is defined in RFC 1701 and RFC 1702. Documentation of
|
||||
* PPTP can be found in RFC 2637
|
||||
*
|
||||
* (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*
|
||||
* Limitations:
|
||||
* - We blindly assume that control connections are always
|
||||
* established in PNS->PAC direction. This is a violation
|
||||
* of RFFC2673
|
||||
* - We can only support one single call within each session
|
||||
*
|
||||
* TODO:
|
||||
* - testing of incoming PPTP calls
|
||||
*
|
||||
* Changes:
|
||||
* 2002-02-05 - Version 1.3
|
||||
* - Call ip_conntrack_unexpect_related() from
|
||||
* pptp_destroy_siblings() to destroy expectations in case
|
||||
* CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
|
||||
* (Philip Craig <philipc@snapgear.com>)
|
||||
* - Add Version information at module loadtime
|
||||
* 2002-02-10 - Version 1.6
|
||||
* - move to C99 style initializers
|
||||
* - remove second expectation if first arrives
|
||||
* 2004-10-22 - Version 2.0
|
||||
* - merge Mandrake's 2.6.x port with recent 2.6.x API changes
|
||||
* - fix lots of linear skb assumptions from Mandrake's port
|
||||
* 2005-06-10 - Version 2.1
|
||||
* - use ip_conntrack_expect_free() instead of kfree() on the
|
||||
* expect's (which are from the slab for quite some time)
|
||||
* 2005-06-10 - Version 3.0
|
||||
* - port helper to post-2.6.11 API changes,
|
||||
* funded by Oxcoda NetBox Blue (http://www.netboxblue.com/)
|
||||
* 2005-07-30 - Version 3.1
|
||||
* - port helper to 2.6.13 API changes
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
|
||||
|
||||
#define IP_CT_PPTP_VERSION "3.1"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
|
||||
MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
|
||||
|
||||
static DEFINE_SPINLOCK(ip_pptp_lock);
|
||||
|
||||
int
|
||||
(*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq);
|
||||
|
||||
int
|
||||
(*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq);
|
||||
|
||||
void
|
||||
(*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig,
|
||||
struct ip_conntrack_expect *expect_reply);
|
||||
|
||||
void
|
||||
(*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct,
|
||||
struct ip_conntrack_expect *exp);
|
||||
|
||||
#if 0
|
||||
/* PptpControlMessageType names */
|
||||
const char *pptp_msg_name[] = {
|
||||
"UNKNOWN_MESSAGE",
|
||||
"START_SESSION_REQUEST",
|
||||
"START_SESSION_REPLY",
|
||||
"STOP_SESSION_REQUEST",
|
||||
"STOP_SESSION_REPLY",
|
||||
"ECHO_REQUEST",
|
||||
"ECHO_REPLY",
|
||||
"OUT_CALL_REQUEST",
|
||||
"OUT_CALL_REPLY",
|
||||
"IN_CALL_REQUEST",
|
||||
"IN_CALL_REPLY",
|
||||
"IN_CALL_CONNECT",
|
||||
"CALL_CLEAR_REQUEST",
|
||||
"CALL_DISCONNECT_NOTIFY",
|
||||
"WAN_ERROR_NOTIFY",
|
||||
"SET_LINK_INFO"
|
||||
};
|
||||
EXPORT_SYMBOL(pptp_msg_name);
|
||||
#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
#define SECS *HZ
|
||||
#define MINS * 60 SECS
|
||||
#define HOURS * 60 MINS
|
||||
|
||||
#define PPTP_GRE_TIMEOUT (10 MINS)
|
||||
#define PPTP_GRE_STREAM_TIMEOUT (5 HOURS)
|
||||
|
||||
static void pptp_expectfn(struct ip_conntrack *ct,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
typeof(ip_nat_pptp_hook_expectfn) ip_nat_pptp_expectfn;
|
||||
|
||||
DEBUGP("increasing timeouts\n");
|
||||
|
||||
/* increase timeout of GRE data channel conntrack entry */
|
||||
ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
|
||||
ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
|
||||
|
||||
/* Can you see how rusty this code is, compared with the pre-2.6.11
|
||||
* one? That's what happened to my shiny newnat of 2002 ;( -HW */
|
||||
|
||||
rcu_read_lock();
|
||||
ip_nat_pptp_expectfn = rcu_dereference(ip_nat_pptp_hook_expectfn);
|
||||
if (!ip_nat_pptp_expectfn) {
|
||||
struct ip_conntrack_tuple inv_t;
|
||||
struct ip_conntrack_expect *exp_other;
|
||||
|
||||
/* obviously this tuple inversion only works until you do NAT */
|
||||
invert_tuplepr(&inv_t, &exp->tuple);
|
||||
DEBUGP("trying to unexpect other dir: ");
|
||||
DUMP_TUPLE(&inv_t);
|
||||
|
||||
exp_other = ip_conntrack_expect_find_get(&inv_t);
|
||||
if (exp_other) {
|
||||
/* delete other expectation. */
|
||||
DEBUGP("found\n");
|
||||
ip_conntrack_unexpect_related(exp_other);
|
||||
ip_conntrack_expect_put(exp_other);
|
||||
} else {
|
||||
DEBUGP("not found\n");
|
||||
}
|
||||
} else {
|
||||
/* we need more than simple inversion */
|
||||
ip_nat_pptp_expectfn(ct, exp);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t)
|
||||
{
|
||||
struct ip_conntrack_tuple_hash *h;
|
||||
struct ip_conntrack_expect *exp;
|
||||
|
||||
DEBUGP("trying to timeout ct or exp for tuple ");
|
||||
DUMP_TUPLE(t);
|
||||
|
||||
h = ip_conntrack_find_get(t, NULL);
|
||||
if (h) {
|
||||
struct ip_conntrack *sibling = tuplehash_to_ctrack(h);
|
||||
DEBUGP("setting timeout of conntrack %p to 0\n", sibling);
|
||||
sibling->proto.gre.timeout = 0;
|
||||
sibling->proto.gre.stream_timeout = 0;
|
||||
if (del_timer(&sibling->timeout))
|
||||
sibling->timeout.function((unsigned long)sibling);
|
||||
ip_conntrack_put(sibling);
|
||||
return 1;
|
||||
} else {
|
||||
exp = ip_conntrack_expect_find_get(t);
|
||||
if (exp) {
|
||||
DEBUGP("unexpect_related of expect %p\n", exp);
|
||||
ip_conntrack_unexpect_related(exp);
|
||||
ip_conntrack_expect_put(exp);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* timeout GRE data connections */
|
||||
static void pptp_destroy_siblings(struct ip_conntrack *ct)
|
||||
{
|
||||
struct ip_conntrack_tuple t;
|
||||
|
||||
ip_ct_gre_keymap_destroy(ct);
|
||||
/* Since ct->sibling_list has literally rusted away in 2.6.11,
|
||||
* we now need another way to find out about our sibling
|
||||
* contrack and expects... -HW */
|
||||
|
||||
/* try original (pns->pac) tuple */
|
||||
memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t));
|
||||
t.dst.protonum = IPPROTO_GRE;
|
||||
t.src.u.gre.key = ct->help.ct_pptp_info.pns_call_id;
|
||||
t.dst.u.gre.key = ct->help.ct_pptp_info.pac_call_id;
|
||||
|
||||
if (!destroy_sibling_or_exp(&t))
|
||||
DEBUGP("failed to timeout original pns->pac ct/exp\n");
|
||||
|
||||
/* try reply (pac->pns) tuple */
|
||||
memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t));
|
||||
t.dst.protonum = IPPROTO_GRE;
|
||||
t.src.u.gre.key = ct->help.ct_pptp_info.pac_call_id;
|
||||
t.dst.u.gre.key = ct->help.ct_pptp_info.pns_call_id;
|
||||
|
||||
if (!destroy_sibling_or_exp(&t))
|
||||
DEBUGP("failed to timeout reply pac->pns ct/exp\n");
|
||||
}
|
||||
|
||||
/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
|
||||
static inline int
|
||||
exp_gre(struct ip_conntrack *ct,
|
||||
__be16 callid,
|
||||
__be16 peer_callid)
|
||||
{
|
||||
struct ip_conntrack_expect *exp_orig, *exp_reply;
|
||||
int ret = 1;
|
||||
typeof(ip_nat_pptp_hook_exp_gre) ip_nat_pptp_exp_gre;
|
||||
|
||||
exp_orig = ip_conntrack_expect_alloc(ct);
|
||||
if (exp_orig == NULL)
|
||||
goto out;
|
||||
|
||||
exp_reply = ip_conntrack_expect_alloc(ct);
|
||||
if (exp_reply == NULL)
|
||||
goto out_put_orig;
|
||||
|
||||
/* original direction, PNS->PAC */
|
||||
exp_orig->tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
|
||||
exp_orig->tuple.src.u.gre.key = peer_callid;
|
||||
exp_orig->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
|
||||
exp_orig->tuple.dst.u.gre.key = callid;
|
||||
exp_orig->tuple.dst.protonum = IPPROTO_GRE;
|
||||
|
||||
exp_orig->mask.src.ip = htonl(0xffffffff);
|
||||
exp_orig->mask.src.u.all = 0;
|
||||
exp_orig->mask.dst.u.gre.key = htons(0xffff);
|
||||
exp_orig->mask.dst.ip = htonl(0xffffffff);
|
||||
exp_orig->mask.dst.protonum = 0xff;
|
||||
|
||||
exp_orig->master = ct;
|
||||
exp_orig->expectfn = pptp_expectfn;
|
||||
exp_orig->flags = 0;
|
||||
|
||||
/* both expectations are identical apart from tuple */
|
||||
memcpy(exp_reply, exp_orig, sizeof(*exp_reply));
|
||||
|
||||
/* reply direction, PAC->PNS */
|
||||
exp_reply->tuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
|
||||
exp_reply->tuple.src.u.gre.key = callid;
|
||||
exp_reply->tuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
|
||||
exp_reply->tuple.dst.u.gre.key = peer_callid;
|
||||
exp_reply->tuple.dst.protonum = IPPROTO_GRE;
|
||||
|
||||
ip_nat_pptp_exp_gre = rcu_dereference(ip_nat_pptp_hook_exp_gre);
|
||||
if (ip_nat_pptp_exp_gre)
|
||||
ip_nat_pptp_exp_gre(exp_orig, exp_reply);
|
||||
if (ip_conntrack_expect_related(exp_orig) != 0)
|
||||
goto out_put_both;
|
||||
if (ip_conntrack_expect_related(exp_reply) != 0)
|
||||
goto out_unexpect_orig;
|
||||
|
||||
/* Add GRE keymap entries */
|
||||
if (ip_ct_gre_keymap_add(ct, &exp_orig->tuple, 0) != 0)
|
||||
goto out_unexpect_both;
|
||||
if (ip_ct_gre_keymap_add(ct, &exp_reply->tuple, 1) != 0) {
|
||||
ip_ct_gre_keymap_destroy(ct);
|
||||
goto out_unexpect_both;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
out_put_both:
|
||||
ip_conntrack_expect_put(exp_reply);
|
||||
out_put_orig:
|
||||
ip_conntrack_expect_put(exp_orig);
|
||||
out:
|
||||
return ret;
|
||||
|
||||
out_unexpect_both:
|
||||
ip_conntrack_unexpect_related(exp_reply);
|
||||
out_unexpect_orig:
|
||||
ip_conntrack_unexpect_related(exp_orig);
|
||||
goto out_put_both;
|
||||
}
|
||||
|
||||
static inline int
|
||||
pptp_inbound_pkt(struct sk_buff **pskb,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq,
|
||||
unsigned int reqlen,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
|
||||
u_int16_t msg;
|
||||
__be16 cid = 0, pcid = 0;
|
||||
typeof(ip_nat_pptp_hook_inbound) ip_nat_pptp_inbound;
|
||||
|
||||
msg = ntohs(ctlh->messageType);
|
||||
DEBUGP("inbound control message %s\n", pptp_msg_name[msg]);
|
||||
|
||||
switch (msg) {
|
||||
case PPTP_START_SESSION_REPLY:
|
||||
/* server confirms new control session */
|
||||
if (info->sstate < PPTP_SESSION_REQUESTED)
|
||||
goto invalid;
|
||||
if (pptpReq->srep.resultCode == PPTP_START_OK)
|
||||
info->sstate = PPTP_SESSION_CONFIRMED;
|
||||
else
|
||||
info->sstate = PPTP_SESSION_ERROR;
|
||||
break;
|
||||
|
||||
case PPTP_STOP_SESSION_REPLY:
|
||||
/* server confirms end of control session */
|
||||
if (info->sstate > PPTP_SESSION_STOPREQ)
|
||||
goto invalid;
|
||||
if (pptpReq->strep.resultCode == PPTP_STOP_OK)
|
||||
info->sstate = PPTP_SESSION_NONE;
|
||||
else
|
||||
info->sstate = PPTP_SESSION_ERROR;
|
||||
break;
|
||||
|
||||
case PPTP_OUT_CALL_REPLY:
|
||||
/* server accepted call, we now expect GRE frames */
|
||||
if (info->sstate != PPTP_SESSION_CONFIRMED)
|
||||
goto invalid;
|
||||
if (info->cstate != PPTP_CALL_OUT_REQ &&
|
||||
info->cstate != PPTP_CALL_OUT_CONF)
|
||||
goto invalid;
|
||||
|
||||
cid = pptpReq->ocack.callID;
|
||||
pcid = pptpReq->ocack.peersCallID;
|
||||
if (info->pns_call_id != pcid)
|
||||
goto invalid;
|
||||
DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg],
|
||||
ntohs(cid), ntohs(pcid));
|
||||
|
||||
if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) {
|
||||
info->cstate = PPTP_CALL_OUT_CONF;
|
||||
info->pac_call_id = cid;
|
||||
exp_gre(ct, cid, pcid);
|
||||
} else
|
||||
info->cstate = PPTP_CALL_NONE;
|
||||
break;
|
||||
|
||||
case PPTP_IN_CALL_REQUEST:
|
||||
/* server tells us about incoming call request */
|
||||
if (info->sstate != PPTP_SESSION_CONFIRMED)
|
||||
goto invalid;
|
||||
|
||||
cid = pptpReq->icreq.callID;
|
||||
DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
|
||||
info->cstate = PPTP_CALL_IN_REQ;
|
||||
info->pac_call_id = cid;
|
||||
break;
|
||||
|
||||
case PPTP_IN_CALL_CONNECT:
|
||||
/* server tells us about incoming call established */
|
||||
if (info->sstate != PPTP_SESSION_CONFIRMED)
|
||||
goto invalid;
|
||||
if (info->cstate != PPTP_CALL_IN_REP &&
|
||||
info->cstate != PPTP_CALL_IN_CONF)
|
||||
goto invalid;
|
||||
|
||||
pcid = pptpReq->iccon.peersCallID;
|
||||
cid = info->pac_call_id;
|
||||
|
||||
if (info->pns_call_id != pcid)
|
||||
goto invalid;
|
||||
|
||||
DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid));
|
||||
info->cstate = PPTP_CALL_IN_CONF;
|
||||
|
||||
/* we expect a GRE connection from PAC to PNS */
|
||||
exp_gre(ct, cid, pcid);
|
||||
break;
|
||||
|
||||
case PPTP_CALL_DISCONNECT_NOTIFY:
|
||||
/* server confirms disconnect */
|
||||
cid = pptpReq->disc.callID;
|
||||
DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
|
||||
info->cstate = PPTP_CALL_NONE;
|
||||
|
||||
/* untrack this call id, unexpect GRE packets */
|
||||
pptp_destroy_siblings(ct);
|
||||
break;
|
||||
|
||||
case PPTP_WAN_ERROR_NOTIFY:
|
||||
case PPTP_ECHO_REQUEST:
|
||||
case PPTP_ECHO_REPLY:
|
||||
/* I don't have to explain these ;) */
|
||||
break;
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
ip_nat_pptp_inbound = rcu_dereference(ip_nat_pptp_hook_inbound);
|
||||
if (ip_nat_pptp_inbound)
|
||||
return ip_nat_pptp_inbound(pskb, ct, ctinfo, ctlh, pptpReq);
|
||||
return NF_ACCEPT;
|
||||
|
||||
invalid:
|
||||
DEBUGP("invalid %s: type=%d cid=%u pcid=%u "
|
||||
"cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
|
||||
msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
|
||||
msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
|
||||
ntohs(info->pns_call_id), ntohs(info->pac_call_id));
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static inline int
|
||||
pptp_outbound_pkt(struct sk_buff **pskb,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq,
|
||||
unsigned int reqlen,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
|
||||
u_int16_t msg;
|
||||
__be16 cid = 0, pcid = 0;
|
||||
typeof(ip_nat_pptp_hook_outbound) ip_nat_pptp_outbound;
|
||||
|
||||
msg = ntohs(ctlh->messageType);
|
||||
DEBUGP("outbound control message %s\n", pptp_msg_name[msg]);
|
||||
|
||||
switch (msg) {
|
||||
case PPTP_START_SESSION_REQUEST:
|
||||
/* client requests for new control session */
|
||||
if (info->sstate != PPTP_SESSION_NONE)
|
||||
goto invalid;
|
||||
info->sstate = PPTP_SESSION_REQUESTED;
|
||||
break;
|
||||
case PPTP_STOP_SESSION_REQUEST:
|
||||
/* client requests end of control session */
|
||||
info->sstate = PPTP_SESSION_STOPREQ;
|
||||
break;
|
||||
|
||||
case PPTP_OUT_CALL_REQUEST:
|
||||
/* client initiating connection to server */
|
||||
if (info->sstate != PPTP_SESSION_CONFIRMED)
|
||||
goto invalid;
|
||||
info->cstate = PPTP_CALL_OUT_REQ;
|
||||
/* track PNS call id */
|
||||
cid = pptpReq->ocreq.callID;
|
||||
DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
|
||||
info->pns_call_id = cid;
|
||||
break;
|
||||
case PPTP_IN_CALL_REPLY:
|
||||
/* client answers incoming call */
|
||||
if (info->cstate != PPTP_CALL_IN_REQ &&
|
||||
info->cstate != PPTP_CALL_IN_REP)
|
||||
goto invalid;
|
||||
|
||||
cid = pptpReq->icack.callID;
|
||||
pcid = pptpReq->icack.peersCallID;
|
||||
if (info->pac_call_id != pcid)
|
||||
goto invalid;
|
||||
DEBUGP("%s, CID=%X PCID=%X\n", pptp_msg_name[msg],
|
||||
ntohs(cid), ntohs(pcid));
|
||||
|
||||
if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) {
|
||||
/* part two of the three-way handshake */
|
||||
info->cstate = PPTP_CALL_IN_REP;
|
||||
info->pns_call_id = cid;
|
||||
} else
|
||||
info->cstate = PPTP_CALL_NONE;
|
||||
break;
|
||||
|
||||
case PPTP_CALL_CLEAR_REQUEST:
|
||||
/* client requests hangup of call */
|
||||
if (info->sstate != PPTP_SESSION_CONFIRMED)
|
||||
goto invalid;
|
||||
/* FUTURE: iterate over all calls and check if
|
||||
* call ID is valid. We don't do this without newnat,
|
||||
* because we only know about last call */
|
||||
info->cstate = PPTP_CALL_CLEAR_REQ;
|
||||
break;
|
||||
case PPTP_SET_LINK_INFO:
|
||||
case PPTP_ECHO_REQUEST:
|
||||
case PPTP_ECHO_REPLY:
|
||||
/* I don't have to explain these ;) */
|
||||
break;
|
||||
default:
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
ip_nat_pptp_outbound = rcu_dereference(ip_nat_pptp_hook_outbound);
|
||||
if (ip_nat_pptp_outbound)
|
||||
return ip_nat_pptp_outbound(pskb, ct, ctinfo, ctlh, pptpReq);
|
||||
return NF_ACCEPT;
|
||||
|
||||
invalid:
|
||||
DEBUGP("invalid %s: type=%d cid=%u pcid=%u "
|
||||
"cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
|
||||
msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
|
||||
msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
|
||||
ntohs(info->pns_call_id), ntohs(info->pac_call_id));
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static const unsigned int pptp_msg_size[] = {
|
||||
[PPTP_START_SESSION_REQUEST] = sizeof(struct PptpStartSessionRequest),
|
||||
[PPTP_START_SESSION_REPLY] = sizeof(struct PptpStartSessionReply),
|
||||
[PPTP_STOP_SESSION_REQUEST] = sizeof(struct PptpStopSessionRequest),
|
||||
[PPTP_STOP_SESSION_REPLY] = sizeof(struct PptpStopSessionReply),
|
||||
[PPTP_OUT_CALL_REQUEST] = sizeof(struct PptpOutCallRequest),
|
||||
[PPTP_OUT_CALL_REPLY] = sizeof(struct PptpOutCallReply),
|
||||
[PPTP_IN_CALL_REQUEST] = sizeof(struct PptpInCallRequest),
|
||||
[PPTP_IN_CALL_REPLY] = sizeof(struct PptpInCallReply),
|
||||
[PPTP_IN_CALL_CONNECT] = sizeof(struct PptpInCallConnected),
|
||||
[PPTP_CALL_CLEAR_REQUEST] = sizeof(struct PptpClearCallRequest),
|
||||
[PPTP_CALL_DISCONNECT_NOTIFY] = sizeof(struct PptpCallDisconnectNotify),
|
||||
[PPTP_WAN_ERROR_NOTIFY] = sizeof(struct PptpWanErrorNotify),
|
||||
[PPTP_SET_LINK_INFO] = sizeof(struct PptpSetLinkInfo),
|
||||
};
|
||||
|
||||
/* track caller id inside control connection, call expect_related */
|
||||
static int
|
||||
conntrack_pptp_help(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
|
||||
|
||||
{
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
|
||||
struct tcphdr _tcph, *tcph;
|
||||
struct pptp_pkt_hdr _pptph, *pptph;
|
||||
struct PptpControlHeader _ctlh, *ctlh;
|
||||
union pptp_ctrl_union _pptpReq, *pptpReq;
|
||||
unsigned int tcplen = (*pskb)->len - ip_hdrlen(*pskb);
|
||||
unsigned int datalen, reqlen, nexthdr_off;
|
||||
int oldsstate, oldcstate;
|
||||
int ret;
|
||||
u_int16_t msg;
|
||||
|
||||
/* don't do any tracking before tcp handshake complete */
|
||||
if (ctinfo != IP_CT_ESTABLISHED
|
||||
&& ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
|
||||
DEBUGP("ctinfo = %u, skipping\n", ctinfo);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
nexthdr_off = ip_hdrlen(*pskb);
|
||||
tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph);
|
||||
BUG_ON(!tcph);
|
||||
nexthdr_off += tcph->doff * 4;
|
||||
datalen = tcplen - tcph->doff * 4;
|
||||
|
||||
pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph);
|
||||
if (!pptph) {
|
||||
DEBUGP("no full PPTP header, can't track\n");
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
nexthdr_off += sizeof(_pptph);
|
||||
datalen -= sizeof(_pptph);
|
||||
|
||||
/* if it's not a control message we can't do anything with it */
|
||||
if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
|
||||
ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
|
||||
DEBUGP("not a control packet\n");
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh);
|
||||
if (!ctlh)
|
||||
return NF_ACCEPT;
|
||||
nexthdr_off += sizeof(_ctlh);
|
||||
datalen -= sizeof(_ctlh);
|
||||
|
||||
reqlen = datalen;
|
||||
msg = ntohs(ctlh->messageType);
|
||||
if (msg > 0 && msg <= PPTP_MSG_MAX && reqlen < pptp_msg_size[msg])
|
||||
return NF_ACCEPT;
|
||||
if (reqlen > sizeof(*pptpReq))
|
||||
reqlen = sizeof(*pptpReq);
|
||||
|
||||
pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq);
|
||||
if (!pptpReq)
|
||||
return NF_ACCEPT;
|
||||
|
||||
oldsstate = info->sstate;
|
||||
oldcstate = info->cstate;
|
||||
|
||||
spin_lock_bh(&ip_pptp_lock);
|
||||
|
||||
/* FIXME: We just blindly assume that the control connection is always
|
||||
* established from PNS->PAC. However, RFC makes no guarantee */
|
||||
if (dir == IP_CT_DIR_ORIGINAL)
|
||||
/* client -> server (PNS -> PAC) */
|
||||
ret = pptp_outbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
|
||||
ctinfo);
|
||||
else
|
||||
/* server -> client (PAC -> PNS) */
|
||||
ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
|
||||
ctinfo);
|
||||
DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
|
||||
oldsstate, info->sstate, oldcstate, info->cstate);
|
||||
spin_unlock_bh(&ip_pptp_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* control protocol helper */
|
||||
static struct ip_conntrack_helper pptp = {
|
||||
.list = { NULL, NULL },
|
||||
.name = "pptp",
|
||||
.me = THIS_MODULE,
|
||||
.max_expected = 2,
|
||||
.timeout = 5 * 60,
|
||||
.tuple = { .src = { .ip = 0,
|
||||
.u = { .tcp = { .port =
|
||||
__constant_htons(PPTP_CONTROL_PORT) } }
|
||||
},
|
||||
.dst = { .ip = 0,
|
||||
.u = { .all = 0 },
|
||||
.protonum = IPPROTO_TCP
|
||||
}
|
||||
},
|
||||
.mask = { .src = { .ip = 0,
|
||||
.u = { .tcp = { .port = __constant_htons(0xffff) } }
|
||||
},
|
||||
.dst = { .ip = 0,
|
||||
.u = { .all = 0 },
|
||||
.protonum = 0xff
|
||||
}
|
||||
},
|
||||
.help = conntrack_pptp_help,
|
||||
.destroy = pptp_destroy_siblings,
|
||||
};
|
||||
|
||||
extern void ip_ct_proto_gre_fini(void);
|
||||
extern int __init ip_ct_proto_gre_init(void);
|
||||
|
||||
/* ip_conntrack_pptp initialization */
|
||||
static int __init ip_conntrack_helper_pptp_init(void)
|
||||
{
|
||||
int retcode;
|
||||
|
||||
retcode = ip_ct_proto_gre_init();
|
||||
if (retcode < 0)
|
||||
return retcode;
|
||||
|
||||
DEBUGP(" registering helper\n");
|
||||
if ((retcode = ip_conntrack_helper_register(&pptp))) {
|
||||
printk(KERN_ERR "Unable to register conntrack application "
|
||||
"helper for pptp: %d\n", retcode);
|
||||
ip_ct_proto_gre_fini();
|
||||
return retcode;
|
||||
}
|
||||
|
||||
printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ip_conntrack_helper_pptp_fini(void)
|
||||
{
|
||||
ip_conntrack_helper_unregister(&pptp);
|
||||
ip_ct_proto_gre_fini();
|
||||
printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
|
||||
}
|
||||
|
||||
module_init(ip_conntrack_helper_pptp_init);
|
||||
module_exit(ip_conntrack_helper_pptp_fini);
|
||||
|
||||
EXPORT_SYMBOL(ip_nat_pptp_hook_outbound);
|
||||
EXPORT_SYMBOL(ip_nat_pptp_hook_inbound);
|
||||
EXPORT_SYMBOL(ip_nat_pptp_hook_exp_gre);
|
||||
EXPORT_SYMBOL(ip_nat_pptp_hook_expectfn);
|
|
@ -1,314 +0,0 @@
|
|||
/* IRC extension for IP connection tracking, Version 1.21
|
||||
* (C) 2000-2002 by Harald Welte <laforge@gnumonks.org>
|
||||
* based on RR's ip_conntrack_ftp.c
|
||||
*
|
||||
* ip_conntrack_irc.c,v 1.21 2002/02/05 14:49:26 laforge Exp
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
**
|
||||
* Module load syntax:
|
||||
* insmod ip_conntrack_irc.o ports=port1,port2,...port<MAX_PORTS>
|
||||
* max_dcc_channels=n dcc_timeout=secs
|
||||
*
|
||||
* please give the ports of all IRC servers You wish to connect to.
|
||||
* If You don't specify ports, the default will be port 6667.
|
||||
* With max_dcc_channels you can define the maximum number of not
|
||||
* yet answered DCC channels per IRC session (default 8).
|
||||
* With dcc_timeout you can specify how long the system waits for
|
||||
* an expected DCC channel (default 300 seconds).
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#define MAX_PORTS 8
|
||||
static unsigned short ports[MAX_PORTS];
|
||||
static int ports_c;
|
||||
static unsigned int max_dcc_channels = 8;
|
||||
static unsigned int dcc_timeout = 300;
|
||||
/* This is slow, but it's simple. --RR */
|
||||
static char *irc_buffer;
|
||||
static DEFINE_SPINLOCK(irc_buffer_lock);
|
||||
|
||||
unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
struct ip_conntrack_expect *exp);
|
||||
EXPORT_SYMBOL_GPL(ip_nat_irc_hook);
|
||||
|
||||
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
||||
MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
|
||||
MODULE_LICENSE("GPL");
|
||||
module_param_array(ports, ushort, &ports_c, 0400);
|
||||
MODULE_PARM_DESC(ports, "port numbers of IRC servers");
|
||||
module_param(max_dcc_channels, uint, 0400);
|
||||
MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session");
|
||||
module_param(dcc_timeout, uint, 0400);
|
||||
MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
|
||||
|
||||
static const char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " };
|
||||
#define MINMATCHLEN 5
|
||||
|
||||
#if 0
|
||||
#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \
|
||||
__FILE__, __FUNCTION__ , ## args)
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
static int parse_dcc(char *data, char *data_end, u_int32_t *ip,
|
||||
u_int16_t *port, char **ad_beg_p, char **ad_end_p)
|
||||
/* tries to get the ip_addr and port out of a dcc command
|
||||
return value: -1 on failure, 0 on success
|
||||
data pointer to first byte of DCC command data
|
||||
data_end pointer to last byte of dcc command data
|
||||
ip returns parsed ip of dcc command
|
||||
port returns parsed port of dcc command
|
||||
ad_beg_p returns pointer to first byte of addr data
|
||||
ad_end_p returns pointer to last byte of addr data */
|
||||
{
|
||||
|
||||
/* at least 12: "AAAAAAAA P\1\n" */
|
||||
while (*data++ != ' ')
|
||||
if (data > data_end - 12)
|
||||
return -1;
|
||||
|
||||
*ad_beg_p = data;
|
||||
*ip = simple_strtoul(data, &data, 10);
|
||||
|
||||
/* skip blanks between ip and port */
|
||||
while (*data == ' ') {
|
||||
if (data >= data_end)
|
||||
return -1;
|
||||
data++;
|
||||
}
|
||||
|
||||
*port = simple_strtoul(data, &data, 10);
|
||||
*ad_end_p = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int help(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
unsigned int dataoff;
|
||||
struct tcphdr _tcph, *th;
|
||||
char *data, *data_limit, *ib_ptr;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
struct ip_conntrack_expect *exp;
|
||||
u32 seq;
|
||||
u_int32_t dcc_ip;
|
||||
u_int16_t dcc_port;
|
||||
int i, ret = NF_ACCEPT;
|
||||
char *addr_beg_p, *addr_end_p;
|
||||
typeof(ip_nat_irc_hook) ip_nat_irc;
|
||||
|
||||
DEBUGP("entered\n");
|
||||
|
||||
/* If packet is coming from IRC server */
|
||||
if (dir == IP_CT_DIR_REPLY)
|
||||
return NF_ACCEPT;
|
||||
|
||||
/* Until there's been traffic both ways, don't look in packets. */
|
||||
if (ctinfo != IP_CT_ESTABLISHED
|
||||
&& ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
|
||||
DEBUGP("Conntrackinfo = %u\n", ctinfo);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Not a full tcp header? */
|
||||
th = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
|
||||
sizeof(_tcph), &_tcph);
|
||||
if (th == NULL)
|
||||
return NF_ACCEPT;
|
||||
|
||||
/* No data? */
|
||||
dataoff = ip_hdrlen(*pskb) + th->doff * 4;
|
||||
if (dataoff >= (*pskb)->len)
|
||||
return NF_ACCEPT;
|
||||
|
||||
spin_lock_bh(&irc_buffer_lock);
|
||||
ib_ptr = skb_header_pointer(*pskb, dataoff,
|
||||
(*pskb)->len - dataoff, irc_buffer);
|
||||
BUG_ON(ib_ptr == NULL);
|
||||
|
||||
data = ib_ptr;
|
||||
data_limit = ib_ptr + (*pskb)->len - dataoff;
|
||||
|
||||
/* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
|
||||
* 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
|
||||
while (data < (data_limit - (19 + MINMATCHLEN))) {
|
||||
if (memcmp(data, "\1DCC ", 5)) {
|
||||
data++;
|
||||
continue;
|
||||
}
|
||||
|
||||
data += 5;
|
||||
/* we have at least (19+MINMATCHLEN)-5 bytes valid data left */
|
||||
|
||||
DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
|
||||
NIPQUAD(iph->saddr), ntohs(th->source),
|
||||
NIPQUAD(iph->daddr), ntohs(th->dest));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
|
||||
if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
|
||||
/* no match */
|
||||
continue;
|
||||
}
|
||||
|
||||
DEBUGP("DCC %s detected\n", dccprotos[i]);
|
||||
data += strlen(dccprotos[i]);
|
||||
/* we have at least
|
||||
* (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid
|
||||
* data left (== 14/13 bytes) */
|
||||
if (parse_dcc((char *)data, data_limit, &dcc_ip,
|
||||
&dcc_port, &addr_beg_p, &addr_end_p)) {
|
||||
/* unable to parse */
|
||||
DEBUGP("unable to parse dcc command\n");
|
||||
continue;
|
||||
}
|
||||
DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
|
||||
HIPQUAD(dcc_ip), dcc_port);
|
||||
|
||||
/* dcc_ip can be the internal OR external (NAT'ed) IP
|
||||
* Tiago Sousa <mirage@kaotik.org> */
|
||||
if (ct->tuplehash[dir].tuple.src.ip != htonl(dcc_ip)
|
||||
&& ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != htonl(dcc_ip)) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING
|
||||
"Forged DCC command from "
|
||||
"%u.%u.%u.%u: %u.%u.%u.%u:%u\n",
|
||||
NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
|
||||
HIPQUAD(dcc_ip), dcc_port);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
exp = ip_conntrack_expect_alloc(ct);
|
||||
if (exp == NULL) {
|
||||
ret = NF_DROP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* save position of address in dcc string,
|
||||
* necessary for NAT */
|
||||
DEBUGP("tcph->seq = %u\n", th->seq);
|
||||
seq = ntohl(th->seq) + (addr_beg_p - ib_ptr);
|
||||
|
||||
/* We refer to the reverse direction ("!dir")
|
||||
* tuples here, because we're expecting
|
||||
* something in the other * direction.
|
||||
* Doesn't matter unless NAT is happening. */
|
||||
exp->tuple = ((struct ip_conntrack_tuple)
|
||||
{ { 0, { 0 } },
|
||||
{ ct->tuplehash[!dir].tuple.dst.ip,
|
||||
{ .tcp = { htons(dcc_port) } },
|
||||
IPPROTO_TCP }});
|
||||
exp->mask = ((struct ip_conntrack_tuple)
|
||||
{ { 0, { 0 } },
|
||||
{ htonl(0xFFFFFFFF),
|
||||
{ .tcp = { htons(0xFFFF) } }, 0xFF }});
|
||||
exp->expectfn = NULL;
|
||||
exp->flags = 0;
|
||||
ip_nat_irc = rcu_dereference(ip_nat_irc_hook);
|
||||
if (ip_nat_irc)
|
||||
ret = ip_nat_irc(pskb, ctinfo,
|
||||
addr_beg_p - ib_ptr,
|
||||
addr_end_p - addr_beg_p,
|
||||
exp);
|
||||
else if (ip_conntrack_expect_related(exp) != 0)
|
||||
ret = NF_DROP;
|
||||
ip_conntrack_expect_put(exp);
|
||||
goto out;
|
||||
} /* for .. NUM_DCCPROTO */
|
||||
} /* while data < ... */
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&irc_buffer_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ip_conntrack_helper irc_helpers[MAX_PORTS];
|
||||
static char irc_names[MAX_PORTS][sizeof("irc-65535")];
|
||||
|
||||
static void ip_conntrack_irc_fini(void);
|
||||
|
||||
static int __init ip_conntrack_irc_init(void)
|
||||
{
|
||||
int i, ret;
|
||||
struct ip_conntrack_helper *hlpr;
|
||||
char *tmpname;
|
||||
|
||||
if (max_dcc_channels < 1) {
|
||||
printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
irc_buffer = kmalloc(65536, GFP_KERNEL);
|
||||
if (!irc_buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/* If no port given, default to standard irc port */
|
||||
if (ports_c == 0)
|
||||
ports[ports_c++] = IRC_PORT;
|
||||
|
||||
for (i = 0; i < ports_c; i++) {
|
||||
hlpr = &irc_helpers[i];
|
||||
hlpr->tuple.src.u.tcp.port = htons(ports[i]);
|
||||
hlpr->tuple.dst.protonum = IPPROTO_TCP;
|
||||
hlpr->mask.src.u.tcp.port = htons(0xFFFF);
|
||||
hlpr->mask.dst.protonum = 0xFF;
|
||||
hlpr->max_expected = max_dcc_channels;
|
||||
hlpr->timeout = dcc_timeout;
|
||||
hlpr->me = THIS_MODULE;
|
||||
hlpr->help = help;
|
||||
|
||||
tmpname = &irc_names[i][0];
|
||||
if (ports[i] == IRC_PORT)
|
||||
sprintf(tmpname, "irc");
|
||||
else
|
||||
sprintf(tmpname, "irc-%d", i);
|
||||
hlpr->name = tmpname;
|
||||
|
||||
DEBUGP("port #%d: %d\n", i, ports[i]);
|
||||
|
||||
ret = ip_conntrack_helper_register(hlpr);
|
||||
|
||||
if (ret) {
|
||||
printk("ip_conntrack_irc: ERROR registering port %d\n",
|
||||
ports[i]);
|
||||
ip_conntrack_irc_fini();
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is intentionally _NOT_ defined as __exit, because
|
||||
* it is needed by the init function */
|
||||
static void ip_conntrack_irc_fini(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ports_c; i++) {
|
||||
DEBUGP("unregistering port %d\n",
|
||||
ports[i]);
|
||||
ip_conntrack_helper_unregister(&irc_helpers[i]);
|
||||
}
|
||||
kfree(irc_buffer);
|
||||
}
|
||||
|
||||
module_init(ip_conntrack_irc_init);
|
||||
module_exit(ip_conntrack_irc_fini);
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* NetBIOS name service broadcast connection tracking helper
|
||||
*
|
||||
* (c) 2005 Patrick McHardy <kaber@trash.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
/*
|
||||
* This helper tracks locally originating NetBIOS name service
|
||||
* requests by issuing permanent expectations (valid until
|
||||
* timing out) matching all reply connections from the
|
||||
* destination network. The only NetBIOS specific thing is
|
||||
* actually the port number.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/if_addr.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
|
||||
#define NMBD_PORT 137
|
||||
|
||||
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
|
||||
MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int timeout = 3;
|
||||
module_param(timeout, uint, 0400);
|
||||
MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds");
|
||||
|
||||
static int help(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
struct ip_conntrack_expect *exp;
|
||||
struct iphdr *iph = ip_hdr(*pskb);
|
||||
struct rtable *rt = (struct rtable *)(*pskb)->dst;
|
||||
struct in_device *in_dev;
|
||||
__be32 mask = 0;
|
||||
|
||||
/* we're only interested in locally generated packets */
|
||||
if ((*pskb)->sk == NULL)
|
||||
goto out;
|
||||
if (rt == NULL || !(rt->rt_flags & RTCF_BROADCAST))
|
||||
goto out;
|
||||
if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
|
||||
goto out;
|
||||
|
||||
rcu_read_lock();
|
||||
in_dev = __in_dev_get_rcu(rt->u.dst.dev);
|
||||
if (in_dev != NULL) {
|
||||
for_primary_ifa(in_dev) {
|
||||
if (ifa->ifa_broadcast == iph->daddr) {
|
||||
mask = ifa->ifa_mask;
|
||||
break;
|
||||
}
|
||||
} endfor_ifa(in_dev);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (mask == 0)
|
||||
goto out;
|
||||
|
||||
exp = ip_conntrack_expect_alloc(ct);
|
||||
if (exp == NULL)
|
||||
goto out;
|
||||
|
||||
exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
|
||||
exp->tuple.src.u.udp.port = htons(NMBD_PORT);
|
||||
|
||||
exp->mask.src.ip = mask;
|
||||
exp->mask.src.u.udp.port = htons(0xFFFF);
|
||||
exp->mask.dst.ip = htonl(0xFFFFFFFF);
|
||||
exp->mask.dst.u.udp.port = htons(0xFFFF);
|
||||
exp->mask.dst.protonum = 0xFF;
|
||||
|
||||
exp->expectfn = NULL;
|
||||
exp->flags = IP_CT_EXPECT_PERMANENT;
|
||||
|
||||
ip_conntrack_expect_related(exp);
|
||||
ip_conntrack_expect_put(exp);
|
||||
|
||||
ip_ct_refresh(ct, *pskb, timeout * HZ);
|
||||
out:
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static struct ip_conntrack_helper helper = {
|
||||
.name = "netbios-ns",
|
||||
.tuple = {
|
||||
.src = {
|
||||
.u = {
|
||||
.udp = {
|
||||
.port = __constant_htons(NMBD_PORT),
|
||||
}
|
||||
}
|
||||
},
|
||||
.dst = {
|
||||
.protonum = IPPROTO_UDP,
|
||||
},
|
||||
},
|
||||
.mask = {
|
||||
.src = {
|
||||
.u = {
|
||||
.udp = {
|
||||
.port = __constant_htons(0xFFFF),
|
||||
}
|
||||
}
|
||||
},
|
||||
.dst = {
|
||||
.protonum = 0xFF,
|
||||
},
|
||||
},
|
||||
.max_expected = 1,
|
||||
.me = THIS_MODULE,
|
||||
.help = help,
|
||||
};
|
||||
|
||||
static int __init ip_conntrack_netbios_ns_init(void)
|
||||
{
|
||||
helper.timeout = timeout;
|
||||
return ip_conntrack_helper_register(&helper);
|
||||
}
|
||||
|
||||
static void __exit ip_conntrack_netbios_ns_fini(void)
|
||||
{
|
||||
ip_conntrack_helper_unregister(&helper);
|
||||
}
|
||||
|
||||
module_init(ip_conntrack_netbios_ns_init);
|
||||
module_exit(ip_conntrack_netbios_ns_fini);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,74 +0,0 @@
|
|||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
|
||||
|
||||
unsigned int ip_ct_generic_timeout __read_mostly = 600*HZ;
|
||||
|
||||
static int generic_pkt_to_tuple(const struct sk_buff *skb,
|
||||
unsigned int dataoff,
|
||||
struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
tuple->src.u.all = 0;
|
||||
tuple->dst.u.all = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int generic_invert_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack_tuple *orig)
|
||||
{
|
||||
tuple->src.u.all = 0;
|
||||
tuple->dst.u.all = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print out the per-protocol part of the tuple. */
|
||||
static int generic_print_tuple(struct seq_file *s,
|
||||
const struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print out the private part of the conntrack. */
|
||||
static int generic_print_conntrack(struct seq_file *s,
|
||||
const struct ip_conntrack *state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns verdict for packet, or -1 for invalid. */
|
||||
static int packet(struct ip_conntrack *conntrack,
|
||||
const struct sk_buff *skb,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_generic_timeout);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Called when a new connection for this protocol found. */
|
||||
static int new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ip_conntrack_protocol ip_conntrack_generic_protocol =
|
||||
{
|
||||
.proto = 0,
|
||||
.name = "unknown",
|
||||
.pkt_to_tuple = generic_pkt_to_tuple,
|
||||
.invert_tuple = generic_invert_tuple,
|
||||
.print_tuple = generic_print_tuple,
|
||||
.print_conntrack = generic_print_conntrack,
|
||||
.packet = packet,
|
||||
.new = new,
|
||||
};
|
|
@ -1,328 +0,0 @@
|
|||
/*
|
||||
* ip_conntrack_proto_gre.c - Version 3.0
|
||||
*
|
||||
* Connection tracking protocol helper module for GRE.
|
||||
*
|
||||
* GRE is a generic encapsulation protocol, which is generally not very
|
||||
* suited for NAT, as it has no protocol-specific part as port numbers.
|
||||
*
|
||||
* It has an optional key field, which may help us distinguishing two
|
||||
* connections between the same two hosts.
|
||||
*
|
||||
* GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
|
||||
*
|
||||
* PPTP is built on top of a modified version of GRE, and has a mandatory
|
||||
* field called "CallID", which serves us for the same purpose as the key
|
||||
* field in plain GRE.
|
||||
*
|
||||
* Documentation about PPTP can be found in RFC 2637
|
||||
*
|
||||
* (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
static DEFINE_RWLOCK(ip_ct_gre_lock);
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
|
||||
MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
|
||||
|
||||
/* shamelessly stolen from ip_conntrack_proto_udp.c */
|
||||
#define GRE_TIMEOUT (30*HZ)
|
||||
#define GRE_STREAM_TIMEOUT (180*HZ)
|
||||
|
||||
#if 0
|
||||
#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
|
||||
#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \
|
||||
NIPQUAD((x)->src.ip), ntohs((x)->src.u.gre.key), \
|
||||
NIPQUAD((x)->dst.ip), ntohs((x)->dst.u.gre.key))
|
||||
#else
|
||||
#define DEBUGP(x, args...)
|
||||
#define DUMP_TUPLE_GRE(x)
|
||||
#endif
|
||||
|
||||
/* GRE KEYMAP HANDLING FUNCTIONS */
|
||||
static LIST_HEAD(gre_keymap_list);
|
||||
|
||||
static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
|
||||
const struct ip_conntrack_tuple *t)
|
||||
{
|
||||
return ((km->tuple.src.ip == t->src.ip) &&
|
||||
(km->tuple.dst.ip == t->dst.ip) &&
|
||||
(km->tuple.dst.protonum == t->dst.protonum) &&
|
||||
(km->tuple.dst.u.all == t->dst.u.all));
|
||||
}
|
||||
|
||||
/* look up the source key for a given tuple */
|
||||
static __be16 gre_keymap_lookup(struct ip_conntrack_tuple *t)
|
||||
{
|
||||
struct ip_ct_gre_keymap *km;
|
||||
__be16 key = 0;
|
||||
|
||||
read_lock_bh(&ip_ct_gre_lock);
|
||||
list_for_each_entry(km, &gre_keymap_list, list) {
|
||||
if (gre_key_cmpfn(km, t)) {
|
||||
key = km->tuple.src.u.gre.key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&ip_ct_gre_lock);
|
||||
|
||||
DEBUGP("lookup src key 0x%x up key for ", key);
|
||||
DUMP_TUPLE_GRE(t);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/* add a single keymap entry, associate with specified master ct */
|
||||
int
|
||||
ip_ct_gre_keymap_add(struct ip_conntrack *ct,
|
||||
struct ip_conntrack_tuple *t, int reply)
|
||||
{
|
||||
struct ip_ct_gre_keymap **exist_km, *km;
|
||||
|
||||
if (!ct->helper || strcmp(ct->helper->name, "pptp")) {
|
||||
DEBUGP("refusing to add GRE keymap to non-pptp session\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!reply)
|
||||
exist_km = &ct->help.ct_pptp_info.keymap_orig;
|
||||
else
|
||||
exist_km = &ct->help.ct_pptp_info.keymap_reply;
|
||||
|
||||
if (*exist_km) {
|
||||
/* check whether it's a retransmission */
|
||||
list_for_each_entry(km, &gre_keymap_list, list) {
|
||||
if (gre_key_cmpfn(km, t) && km == *exist_km)
|
||||
return 0;
|
||||
}
|
||||
DEBUGP("trying to override keymap_%s for ct %p\n",
|
||||
reply? "reply":"orig", ct);
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
km = kmalloc(sizeof(*km), GFP_ATOMIC);
|
||||
if (!km)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(&km->tuple, t, sizeof(*t));
|
||||
*exist_km = km;
|
||||
|
||||
DEBUGP("adding new entry %p: ", km);
|
||||
DUMP_TUPLE_GRE(&km->tuple);
|
||||
|
||||
write_lock_bh(&ip_ct_gre_lock);
|
||||
list_add_tail(&km->list, &gre_keymap_list);
|
||||
write_unlock_bh(&ip_ct_gre_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* destroy the keymap entries associated with specified master ct */
|
||||
void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct)
|
||||
{
|
||||
DEBUGP("entering for ct %p\n", ct);
|
||||
|
||||
if (!ct->helper || strcmp(ct->helper->name, "pptp")) {
|
||||
DEBUGP("refusing to destroy GRE keymap to non-pptp session\n");
|
||||
return;
|
||||
}
|
||||
|
||||
write_lock_bh(&ip_ct_gre_lock);
|
||||
if (ct->help.ct_pptp_info.keymap_orig) {
|
||||
DEBUGP("removing %p from list\n",
|
||||
ct->help.ct_pptp_info.keymap_orig);
|
||||
list_del(&ct->help.ct_pptp_info.keymap_orig->list);
|
||||
kfree(ct->help.ct_pptp_info.keymap_orig);
|
||||
ct->help.ct_pptp_info.keymap_orig = NULL;
|
||||
}
|
||||
if (ct->help.ct_pptp_info.keymap_reply) {
|
||||
DEBUGP("removing %p from list\n",
|
||||
ct->help.ct_pptp_info.keymap_reply);
|
||||
list_del(&ct->help.ct_pptp_info.keymap_reply->list);
|
||||
kfree(ct->help.ct_pptp_info.keymap_reply);
|
||||
ct->help.ct_pptp_info.keymap_reply = NULL;
|
||||
}
|
||||
write_unlock_bh(&ip_ct_gre_lock);
|
||||
}
|
||||
|
||||
|
||||
/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
|
||||
|
||||
/* invert gre part of tuple */
|
||||
static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack_tuple *orig)
|
||||
{
|
||||
tuple->dst.u.gre.key = orig->src.u.gre.key;
|
||||
tuple->src.u.gre.key = orig->dst.u.gre.key;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* gre hdr info to tuple */
|
||||
static int gre_pkt_to_tuple(const struct sk_buff *skb,
|
||||
unsigned int dataoff,
|
||||
struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
struct gre_hdr_pptp _pgrehdr, *pgrehdr;
|
||||
__be16 srckey;
|
||||
struct gre_hdr _grehdr, *grehdr;
|
||||
|
||||
/* first only delinearize old RFC1701 GRE header */
|
||||
grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr);
|
||||
if (!grehdr || grehdr->version != GRE_VERSION_PPTP) {
|
||||
/* try to behave like "ip_conntrack_proto_generic" */
|
||||
tuple->src.u.all = 0;
|
||||
tuple->dst.u.all = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* PPTP header is variable length, only need up to the call_id field */
|
||||
pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr);
|
||||
if (!pgrehdr)
|
||||
return 1;
|
||||
|
||||
if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
|
||||
DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tuple->dst.u.gre.key = pgrehdr->call_id;
|
||||
srckey = gre_keymap_lookup(tuple);
|
||||
tuple->src.u.gre.key = srckey;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* print gre part of tuple */
|
||||
static int gre_print_tuple(struct seq_file *s,
|
||||
const struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
return seq_printf(s, "srckey=0x%x dstkey=0x%x ",
|
||||
ntohs(tuple->src.u.gre.key),
|
||||
ntohs(tuple->dst.u.gre.key));
|
||||
}
|
||||
|
||||
/* print private data for conntrack */
|
||||
static int gre_print_conntrack(struct seq_file *s,
|
||||
const struct ip_conntrack *ct)
|
||||
{
|
||||
return seq_printf(s, "timeout=%u, stream_timeout=%u ",
|
||||
(ct->proto.gre.timeout / HZ),
|
||||
(ct->proto.gre.stream_timeout / HZ));
|
||||
}
|
||||
|
||||
/* Returns verdict for packet, and may modify conntrack */
|
||||
static int gre_packet(struct ip_conntrack *ct,
|
||||
const struct sk_buff *skb,
|
||||
enum ip_conntrack_info conntrackinfo)
|
||||
{
|
||||
/* If we've seen traffic both ways, this is a GRE connection.
|
||||
* Extend timeout. */
|
||||
if (ct->status & IPS_SEEN_REPLY) {
|
||||
ip_ct_refresh_acct(ct, conntrackinfo, skb,
|
||||
ct->proto.gre.stream_timeout);
|
||||
/* Also, more likely to be important, and not a probe. */
|
||||
set_bit(IPS_ASSURED_BIT, &ct->status);
|
||||
ip_conntrack_event_cache(IPCT_STATUS, skb);
|
||||
} else
|
||||
ip_ct_refresh_acct(ct, conntrackinfo, skb,
|
||||
ct->proto.gre.timeout);
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Called when a new connection for this protocol found. */
|
||||
static int gre_new(struct ip_conntrack *ct,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
DEBUGP(": ");
|
||||
DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
|
||||
|
||||
/* initialize to sane value. Ideally a conntrack helper
|
||||
* (e.g. in case of pptp) is increasing them */
|
||||
ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
|
||||
ct->proto.gre.timeout = GRE_TIMEOUT;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Called when a conntrack entry has already been removed from the hashes
|
||||
* and is about to be deleted from memory */
|
||||
static void gre_destroy(struct ip_conntrack *ct)
|
||||
{
|
||||
struct ip_conntrack *master = ct->master;
|
||||
DEBUGP(" entering\n");
|
||||
|
||||
if (!master)
|
||||
DEBUGP("no master !?!\n");
|
||||
else
|
||||
ip_ct_gre_keymap_destroy(master);
|
||||
}
|
||||
|
||||
/* protocol helper struct */
|
||||
static struct ip_conntrack_protocol gre = {
|
||||
.proto = IPPROTO_GRE,
|
||||
.name = "gre",
|
||||
.pkt_to_tuple = gre_pkt_to_tuple,
|
||||
.invert_tuple = gre_invert_tuple,
|
||||
.print_tuple = gre_print_tuple,
|
||||
.print_conntrack = gre_print_conntrack,
|
||||
.packet = gre_packet,
|
||||
.new = gre_new,
|
||||
.destroy = gre_destroy,
|
||||
.me = THIS_MODULE,
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
.tuple_to_nfattr = ip_ct_port_tuple_to_nfattr,
|
||||
.nfattr_to_tuple = ip_ct_port_nfattr_to_tuple,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ip_conntrack_proto_gre initialization */
|
||||
int __init ip_ct_proto_gre_init(void)
|
||||
{
|
||||
return ip_conntrack_protocol_register(&gre);
|
||||
}
|
||||
|
||||
/* This cannot be __exit, as it is invoked from ip_conntrack_helper_pptp.c's
|
||||
* init() code on errors.
|
||||
*/
|
||||
void ip_ct_proto_gre_fini(void)
|
||||
{
|
||||
struct list_head *pos, *n;
|
||||
|
||||
/* delete all keymap entries */
|
||||
write_lock_bh(&ip_ct_gre_lock);
|
||||
list_for_each_safe(pos, n, &gre_keymap_list) {
|
||||
DEBUGP("deleting keymap %p at module unload time\n", pos);
|
||||
list_del(pos);
|
||||
kfree(pos);
|
||||
}
|
||||
write_unlock_bh(&ip_ct_gre_lock);
|
||||
|
||||
ip_conntrack_protocol_unregister(&gre);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ip_ct_gre_keymap_add);
|
||||
EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
|
|
@ -1,315 +0,0 @@
|
|||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/checksum.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
|
||||
|
||||
unsigned int ip_ct_icmp_timeout __read_mostly = 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 ip_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;
|
||||
}
|
||||
|
||||
/* Add 1; spaces filled with 0. */
|
||||
static const 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
|
||||
};
|
||||
|
||||
static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack_tuple *orig)
|
||||
{
|
||||
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 ip_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 ip_conntrack *conntrack)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns verdict for packet, or -1 for invalid. */
|
||||
static int icmp_packet(struct ip_conntrack *ct,
|
||||
const struct sk_buff *skb,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
/* 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);
|
||||
ip_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
|
||||
ip_ct_refresh_acct(ct, ctinfo, skb, ip_ct_icmp_timeout);
|
||||
}
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Called when a new connection for this protocol found. */
|
||||
static int icmp_new(struct ip_conntrack *conntrack,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
static const 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);
|
||||
DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
|
||||
return 0;
|
||||
}
|
||||
atomic_set(&conntrack->proto.icmp.count, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_error_message(struct sk_buff *skb,
|
||||
enum ip_conntrack_info *ctinfo,
|
||||
unsigned int hooknum)
|
||||
{
|
||||
struct ip_conntrack_tuple innertuple, origtuple;
|
||||
struct {
|
||||
struct icmphdr icmp;
|
||||
struct iphdr ip;
|
||||
} _in, *inside;
|
||||
struct ip_conntrack_protocol *innerproto;
|
||||
struct ip_conntrack_tuple_hash *h;
|
||||
int dataoff;
|
||||
|
||||
IP_NF_ASSERT(skb->nfct == NULL);
|
||||
|
||||
/* Not enough header? */
|
||||
inside = skb_header_pointer(skb, ip_hdrlen(skb), 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_track: fragment of proto %u\n",
|
||||
inside->ip.protocol);
|
||||
return -NF_ACCEPT;
|
||||
}
|
||||
|
||||
innerproto = ip_conntrack_proto_find_get(inside->ip.protocol);
|
||||
dataoff = ip_hdrlen(skb) + sizeof(inside->icmp) + inside->ip.ihl * 4;
|
||||
/* Are they talking about one of our connections? */
|
||||
if (!ip_ct_get_tuple(&inside->ip, skb, dataoff, &origtuple, innerproto)) {
|
||||
DEBUGP("icmp_error: ! get_tuple p=%u", inside->ip.protocol);
|
||||
ip_conntrack_proto_put(innerproto);
|
||||
return -NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Ordinarily, we'd expect the inverted tupleproto, but it's
|
||||
been preserved inside the ICMP. */
|
||||
if (!ip_ct_invert_tuple(&innertuple, &origtuple, innerproto)) {
|
||||
DEBUGP("icmp_error_track: Can't invert tuple\n");
|
||||
ip_conntrack_proto_put(innerproto);
|
||||
return -NF_ACCEPT;
|
||||
}
|
||||
ip_conntrack_proto_put(innerproto);
|
||||
|
||||
*ctinfo = IP_CT_RELATED;
|
||||
|
||||
h = ip_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 = ip_conntrack_find_get(&origtuple, NULL);
|
||||
|
||||
if (!h) {
|
||||
DEBUGP("icmp_error_track: no match\n");
|
||||
return -NF_ACCEPT;
|
||||
}
|
||||
/* Reverse direction from that found */
|
||||
if (DIRECTION(h) != IP_CT_DIR_REPLY)
|
||||
*ctinfo += IP_CT_IS_REPLY;
|
||||
} else {
|
||||
if (DIRECTION(h) == IP_CT_DIR_REPLY)
|
||||
*ctinfo += IP_CT_IS_REPLY;
|
||||
}
|
||||
|
||||
/* Update skb to refer to this connection */
|
||||
skb->nfct = &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, enum ip_conntrack_info *ctinfo,
|
||||
unsigned int hooknum)
|
||||
{
|
||||
struct icmphdr _ih, *icmph;
|
||||
|
||||
/* Not enough header? */
|
||||
icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih);
|
||||
if (icmph == NULL) {
|
||||
if (LOG_INVALID(IPPROTO_ICMP))
|
||||
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
|
||||
"ip_ct_icmp: short packet ");
|
||||
return -NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* See ip_conntrack_proto_tcp.c */
|
||||
if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING &&
|
||||
nf_ip_checksum(skb, hooknum, ip_hdrlen(skb), 0)) {
|
||||
if (LOG_INVALID(IPPROTO_ICMP))
|
||||
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
|
||||
"ip_ct_icmp: bad ICMP checksum ");
|
||||
return -NF_ACCEPT;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
"ip_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);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
static int icmp_tuple_to_nfattr(struct sk_buff *skb,
|
||||
const struct ip_conntrack_tuple *t)
|
||||
{
|
||||
NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(__be16),
|
||||
&t->src.u.icmp.id);
|
||||
NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t),
|
||||
&t->dst.u.icmp.type);
|
||||
NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t),
|
||||
&t->dst.u.icmp.code);
|
||||
|
||||
return 0;
|
||||
|
||||
nfattr_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int icmp_nfattr_to_tuple(struct nfattr *tb[],
|
||||
struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
if (!tb[CTA_PROTO_ICMP_TYPE-1]
|
||||
|| !tb[CTA_PROTO_ICMP_CODE-1]
|
||||
|| !tb[CTA_PROTO_ICMP_ID-1])
|
||||
return -EINVAL;
|
||||
|
||||
tuple->dst.u.icmp.type =
|
||||
*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]);
|
||||
tuple->dst.u.icmp.code =
|
||||
*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
|
||||
tuple->src.u.icmp.id =
|
||||
*(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
|
||||
|
||||
if (tuple->dst.u.icmp.type >= sizeof(invmap)
|
||||
|| !invmap[tuple->dst.u.icmp.type])
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ip_conntrack_protocol ip_conntrack_protocol_icmp =
|
||||
{
|
||||
.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,
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
.tuple_to_nfattr = icmp_tuple_to_nfattr,
|
||||
.nfattr_to_tuple = icmp_nfattr_to_tuple,
|
||||
#endif
|
||||
};
|
|
@ -1,659 +0,0 @@
|
|||
/*
|
||||
* Connection tracking protocol helper module for SCTP.
|
||||
*
|
||||
* SCTP is defined in RFC 2960. References to various sections in this code
|
||||
* are to this RFC.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Added support for proc manipulation of timeouts.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP(format, ...) printk(format, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
/* Protects conntrack->proto.sctp */
|
||||
static DEFINE_RWLOCK(sctp_lock);
|
||||
|
||||
/* FIXME: Examine ipfilter's timeouts and conntrack transitions more
|
||||
closely. They're more complex. --RR
|
||||
|
||||
And so for me for SCTP :D -Kiran */
|
||||
|
||||
static const char *sctp_conntrack_names[] = {
|
||||
"NONE",
|
||||
"CLOSED",
|
||||
"COOKIE_WAIT",
|
||||
"COOKIE_ECHOED",
|
||||
"ESTABLISHED",
|
||||
"SHUTDOWN_SENT",
|
||||
"SHUTDOWN_RECD",
|
||||
"SHUTDOWN_ACK_SENT",
|
||||
};
|
||||
|
||||
#define SECS * HZ
|
||||
#define MINS * 60 SECS
|
||||
#define HOURS * 60 MINS
|
||||
#define DAYS * 24 HOURS
|
||||
|
||||
static unsigned int ip_ct_sctp_timeout_closed __read_mostly = 10 SECS;
|
||||
static unsigned int ip_ct_sctp_timeout_cookie_wait __read_mostly = 3 SECS;
|
||||
static unsigned int ip_ct_sctp_timeout_cookie_echoed __read_mostly = 3 SECS;
|
||||
static unsigned int ip_ct_sctp_timeout_established __read_mostly = 5 DAYS;
|
||||
static unsigned int ip_ct_sctp_timeout_shutdown_sent __read_mostly = 300 SECS / 1000;
|
||||
static unsigned int ip_ct_sctp_timeout_shutdown_recd __read_mostly = 300 SECS / 1000;
|
||||
static unsigned int ip_ct_sctp_timeout_shutdown_ack_sent __read_mostly = 3 SECS;
|
||||
|
||||
static const unsigned int * sctp_timeouts[]
|
||||
= { NULL, /* SCTP_CONNTRACK_NONE */
|
||||
&ip_ct_sctp_timeout_closed, /* SCTP_CONNTRACK_CLOSED */
|
||||
&ip_ct_sctp_timeout_cookie_wait, /* SCTP_CONNTRACK_COOKIE_WAIT */
|
||||
&ip_ct_sctp_timeout_cookie_echoed, /* SCTP_CONNTRACK_COOKIE_ECHOED */
|
||||
&ip_ct_sctp_timeout_established, /* SCTP_CONNTRACK_ESTABLISHED */
|
||||
&ip_ct_sctp_timeout_shutdown_sent, /* SCTP_CONNTRACK_SHUTDOWN_SENT */
|
||||
&ip_ct_sctp_timeout_shutdown_recd, /* SCTP_CONNTRACK_SHUTDOWN_RECD */
|
||||
&ip_ct_sctp_timeout_shutdown_ack_sent /* SCTP_CONNTRACK_SHUTDOWN_ACK_SENT */
|
||||
};
|
||||
|
||||
#define sNO SCTP_CONNTRACK_NONE
|
||||
#define sCL SCTP_CONNTRACK_CLOSED
|
||||
#define sCW SCTP_CONNTRACK_COOKIE_WAIT
|
||||
#define sCE SCTP_CONNTRACK_COOKIE_ECHOED
|
||||
#define sES SCTP_CONNTRACK_ESTABLISHED
|
||||
#define sSS SCTP_CONNTRACK_SHUTDOWN_SENT
|
||||
#define sSR SCTP_CONNTRACK_SHUTDOWN_RECD
|
||||
#define sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT
|
||||
#define sIV SCTP_CONNTRACK_MAX
|
||||
|
||||
/*
|
||||
These are the descriptions of the states:
|
||||
|
||||
NOTE: These state names are tantalizingly similar to the states of an
|
||||
SCTP endpoint. But the interpretation of the states is a little different,
|
||||
considering that these are the states of the connection and not of an end
|
||||
point. Please note the subtleties. -Kiran
|
||||
|
||||
NONE - Nothing so far.
|
||||
COOKIE WAIT - We have seen an INIT chunk in the original direction, or also
|
||||
an INIT_ACK chunk in the reply direction.
|
||||
COOKIE ECHOED - We have seen a COOKIE_ECHO chunk in the original direction.
|
||||
ESTABLISHED - We have seen a COOKIE_ACK in the reply direction.
|
||||
SHUTDOWN_SENT - We have seen a SHUTDOWN chunk in the original direction.
|
||||
SHUTDOWN_RECD - We have seen a SHUTDOWN chunk in the reply directoin.
|
||||
SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite
|
||||
to that of the SHUTDOWN chunk.
|
||||
CLOSED - We have seen a SHUTDOWN_COMPLETE chunk in the direction of
|
||||
the SHUTDOWN chunk. Connection is closed.
|
||||
*/
|
||||
|
||||
/* TODO
|
||||
- I have assumed that the first INIT is in the original direction.
|
||||
This messes things when an INIT comes in the reply direction in CLOSED
|
||||
state.
|
||||
- Check the error type in the reply dir before transitioning from
|
||||
cookie echoed to closed.
|
||||
- Sec 5.2.4 of RFC 2960
|
||||
- Multi Homing support.
|
||||
*/
|
||||
|
||||
/* SCTP conntrack state transitions */
|
||||
static const enum sctp_conntrack sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = {
|
||||
{
|
||||
/* ORIGINAL */
|
||||
/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
|
||||
/* init */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA},
|
||||
/* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},
|
||||
/* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
|
||||
/* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA},
|
||||
/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA},
|
||||
/* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant have Stale cookie*/
|
||||
/* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA},/* 5.2.4 - Big TODO */
|
||||
/* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in orig dir */
|
||||
/* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL}
|
||||
},
|
||||
{
|
||||
/* REPLY */
|
||||
/* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA */
|
||||
/* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* INIT in sCL Big TODO */
|
||||
/* init_ack */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},
|
||||
/* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
|
||||
/* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA},
|
||||
/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA},
|
||||
/* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA},
|
||||
/* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in reply dir */
|
||||
/* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA},
|
||||
/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL}
|
||||
}
|
||||
};
|
||||
|
||||
static int sctp_pkt_to_tuple(const struct sk_buff *skb,
|
||||
unsigned int dataoff,
|
||||
struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
sctp_sctphdr_t _hdr, *hp;
|
||||
|
||||
DEBUGP(__FUNCTION__);
|
||||
DEBUGP("\n");
|
||||
|
||||
/* Actually only need first 8 bytes. */
|
||||
hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
|
||||
if (hp == NULL)
|
||||
return 0;
|
||||
|
||||
tuple->src.u.sctp.port = hp->source;
|
||||
tuple->dst.u.sctp.port = hp->dest;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sctp_invert_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack_tuple *orig)
|
||||
{
|
||||
DEBUGP(__FUNCTION__);
|
||||
DEBUGP("\n");
|
||||
|
||||
tuple->src.u.sctp.port = orig->dst.u.sctp.port;
|
||||
tuple->dst.u.sctp.port = orig->src.u.sctp.port;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print out the per-protocol part of the tuple. */
|
||||
static int sctp_print_tuple(struct seq_file *s,
|
||||
const struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
DEBUGP(__FUNCTION__);
|
||||
DEBUGP("\n");
|
||||
|
||||
return seq_printf(s, "sport=%hu dport=%hu ",
|
||||
ntohs(tuple->src.u.sctp.port),
|
||||
ntohs(tuple->dst.u.sctp.port));
|
||||
}
|
||||
|
||||
/* Print out the private part of the conntrack. */
|
||||
static int sctp_print_conntrack(struct seq_file *s,
|
||||
const struct ip_conntrack *conntrack)
|
||||
{
|
||||
enum sctp_conntrack state;
|
||||
|
||||
DEBUGP(__FUNCTION__);
|
||||
DEBUGP("\n");
|
||||
|
||||
read_lock_bh(&sctp_lock);
|
||||
state = conntrack->proto.sctp.state;
|
||||
read_unlock_bh(&sctp_lock);
|
||||
|
||||
return seq_printf(s, "%s ", sctp_conntrack_names[state]);
|
||||
}
|
||||
|
||||
#define for_each_sctp_chunk(skb, sch, _sch, offset, count) \
|
||||
for (offset = ip_hdrlen(skb) + sizeof(sctp_sctphdr_t), count = 0; \
|
||||
offset < skb->len && \
|
||||
(sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch)); \
|
||||
offset += (ntohs(sch->length) + 3) & ~3, count++)
|
||||
|
||||
/* Some validity checks to make sure the chunks are fine */
|
||||
static int do_basic_checks(struct ip_conntrack *conntrack,
|
||||
const struct sk_buff *skb,
|
||||
char *map)
|
||||
{
|
||||
u_int32_t offset, count;
|
||||
sctp_chunkhdr_t _sch, *sch;
|
||||
int flag;
|
||||
|
||||
DEBUGP(__FUNCTION__);
|
||||
DEBUGP("\n");
|
||||
|
||||
flag = 0;
|
||||
|
||||
for_each_sctp_chunk (skb, sch, _sch, offset, count) {
|
||||
DEBUGP("Chunk Num: %d Type: %d\n", count, sch->type);
|
||||
|
||||
if (sch->type == SCTP_CID_INIT
|
||||
|| sch->type == SCTP_CID_INIT_ACK
|
||||
|| sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cookie Ack/Echo chunks not the first OR
|
||||
* Init / Init Ack / Shutdown compl chunks not the only chunks
|
||||
* OR zero-length.
|
||||
*/
|
||||
if (((sch->type == SCTP_CID_COOKIE_ACK
|
||||
|| sch->type == SCTP_CID_COOKIE_ECHO
|
||||
|| flag)
|
||||
&& count !=0) || !sch->length) {
|
||||
DEBUGP("Basic checks failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (map) {
|
||||
set_bit(sch->type, (void *)map);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGP("Basic checks passed\n");
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
static int new_state(enum ip_conntrack_dir dir,
|
||||
enum sctp_conntrack cur_state,
|
||||
int chunk_type)
|
||||
{
|
||||
int i;
|
||||
|
||||
DEBUGP(__FUNCTION__);
|
||||
DEBUGP("\n");
|
||||
|
||||
DEBUGP("Chunk type: %d\n", chunk_type);
|
||||
|
||||
switch (chunk_type) {
|
||||
case SCTP_CID_INIT:
|
||||
DEBUGP("SCTP_CID_INIT\n");
|
||||
i = 0; break;
|
||||
case SCTP_CID_INIT_ACK:
|
||||
DEBUGP("SCTP_CID_INIT_ACK\n");
|
||||
i = 1; break;
|
||||
case SCTP_CID_ABORT:
|
||||
DEBUGP("SCTP_CID_ABORT\n");
|
||||
i = 2; break;
|
||||
case SCTP_CID_SHUTDOWN:
|
||||
DEBUGP("SCTP_CID_SHUTDOWN\n");
|
||||
i = 3; break;
|
||||
case SCTP_CID_SHUTDOWN_ACK:
|
||||
DEBUGP("SCTP_CID_SHUTDOWN_ACK\n");
|
||||
i = 4; break;
|
||||
case SCTP_CID_ERROR:
|
||||
DEBUGP("SCTP_CID_ERROR\n");
|
||||
i = 5; break;
|
||||
case SCTP_CID_COOKIE_ECHO:
|
||||
DEBUGP("SCTP_CID_COOKIE_ECHO\n");
|
||||
i = 6; break;
|
||||
case SCTP_CID_COOKIE_ACK:
|
||||
DEBUGP("SCTP_CID_COOKIE_ACK\n");
|
||||
i = 7; break;
|
||||
case SCTP_CID_SHUTDOWN_COMPLETE:
|
||||
DEBUGP("SCTP_CID_SHUTDOWN_COMPLETE\n");
|
||||
i = 8; break;
|
||||
default:
|
||||
/* Other chunks like DATA, SACK, HEARTBEAT and
|
||||
its ACK do not cause a change in state */
|
||||
DEBUGP("Unknown chunk type, Will stay in %s\n",
|
||||
sctp_conntrack_names[cur_state]);
|
||||
return cur_state;
|
||||
}
|
||||
|
||||
DEBUGP("dir: %d cur_state: %s chunk_type: %d new_state: %s\n",
|
||||
dir, sctp_conntrack_names[cur_state], chunk_type,
|
||||
sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]);
|
||||
|
||||
return sctp_conntracks[dir][i][cur_state];
|
||||
}
|
||||
|
||||
/* Returns verdict for packet, or -1 for invalid. */
|
||||
static int sctp_packet(struct ip_conntrack *conntrack,
|
||||
const struct sk_buff *skb,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
enum sctp_conntrack newconntrack, oldsctpstate;
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
sctp_sctphdr_t _sctph, *sh;
|
||||
sctp_chunkhdr_t _sch, *sch;
|
||||
u_int32_t offset, count;
|
||||
char map[256 / sizeof (char)] = {0};
|
||||
|
||||
DEBUGP(__FUNCTION__);
|
||||
DEBUGP("\n");
|
||||
|
||||
sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph);
|
||||
if (sh == NULL)
|
||||
return -1;
|
||||
|
||||
if (do_basic_checks(conntrack, skb, map) != 0)
|
||||
return -1;
|
||||
|
||||
/* Check the verification tag (Sec 8.5) */
|
||||
if (!test_bit(SCTP_CID_INIT, (void *)map)
|
||||
&& !test_bit(SCTP_CID_SHUTDOWN_COMPLETE, (void *)map)
|
||||
&& !test_bit(SCTP_CID_COOKIE_ECHO, (void *)map)
|
||||
&& !test_bit(SCTP_CID_ABORT, (void *)map)
|
||||
&& !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map)
|
||||
&& (sh->vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
|
||||
DEBUGP("Verification tag check failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
oldsctpstate = newconntrack = SCTP_CONNTRACK_MAX;
|
||||
for_each_sctp_chunk (skb, sch, _sch, offset, count) {
|
||||
write_lock_bh(&sctp_lock);
|
||||
|
||||
/* Special cases of Verification tag check (Sec 8.5.1) */
|
||||
if (sch->type == SCTP_CID_INIT) {
|
||||
/* Sec 8.5.1 (A) */
|
||||
if (sh->vtag != 0) {
|
||||
write_unlock_bh(&sctp_lock);
|
||||
return -1;
|
||||
}
|
||||
} else if (sch->type == SCTP_CID_ABORT) {
|
||||
/* Sec 8.5.1 (B) */
|
||||
if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
|
||||
&& !(sh->vtag == conntrack->proto.sctp.vtag
|
||||
[1 - CTINFO2DIR(ctinfo)])) {
|
||||
write_unlock_bh(&sctp_lock);
|
||||
return -1;
|
||||
}
|
||||
} else if (sch->type == SCTP_CID_SHUTDOWN_COMPLETE) {
|
||||
/* Sec 8.5.1 (C) */
|
||||
if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])
|
||||
&& !(sh->vtag == conntrack->proto.sctp.vtag
|
||||
[1 - CTINFO2DIR(ctinfo)]
|
||||
&& (sch->flags & 1))) {
|
||||
write_unlock_bh(&sctp_lock);
|
||||
return -1;
|
||||
}
|
||||
} else if (sch->type == SCTP_CID_COOKIE_ECHO) {
|
||||
/* Sec 8.5.1 (D) */
|
||||
if (!(sh->vtag == conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
|
||||
write_unlock_bh(&sctp_lock);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
oldsctpstate = conntrack->proto.sctp.state;
|
||||
newconntrack = new_state(CTINFO2DIR(ctinfo), oldsctpstate, sch->type);
|
||||
|
||||
/* Invalid */
|
||||
if (newconntrack == SCTP_CONNTRACK_MAX) {
|
||||
DEBUGP("ip_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n",
|
||||
CTINFO2DIR(ctinfo), sch->type, oldsctpstate);
|
||||
write_unlock_bh(&sctp_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If it is an INIT or an INIT ACK note down the vtag */
|
||||
if (sch->type == SCTP_CID_INIT
|
||||
|| sch->type == SCTP_CID_INIT_ACK) {
|
||||
sctp_inithdr_t _inithdr, *ih;
|
||||
|
||||
ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
|
||||
sizeof(_inithdr), &_inithdr);
|
||||
if (ih == NULL) {
|
||||
write_unlock_bh(&sctp_lock);
|
||||
return -1;
|
||||
}
|
||||
DEBUGP("Setting vtag %x for dir %d\n",
|
||||
ih->init_tag, !CTINFO2DIR(ctinfo));
|
||||
conntrack->proto.sctp.vtag[!CTINFO2DIR(ctinfo)] = ih->init_tag;
|
||||
}
|
||||
|
||||
conntrack->proto.sctp.state = newconntrack;
|
||||
if (oldsctpstate != newconntrack)
|
||||
ip_conntrack_event_cache(IPCT_PROTOINFO, skb);
|
||||
write_unlock_bh(&sctp_lock);
|
||||
}
|
||||
|
||||
ip_ct_refresh_acct(conntrack, ctinfo, skb, *sctp_timeouts[newconntrack]);
|
||||
|
||||
if (oldsctpstate == SCTP_CONNTRACK_COOKIE_ECHOED
|
||||
&& CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
|
||||
&& newconntrack == SCTP_CONNTRACK_ESTABLISHED) {
|
||||
DEBUGP("Setting assured bit\n");
|
||||
set_bit(IPS_ASSURED_BIT, &conntrack->status);
|
||||
ip_conntrack_event_cache(IPCT_STATUS, skb);
|
||||
}
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Called when a new connection for this protocol found. */
|
||||
static int sctp_new(struct ip_conntrack *conntrack,
|
||||
const struct sk_buff *skb)
|
||||
{
|
||||
enum sctp_conntrack newconntrack;
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
sctp_sctphdr_t _sctph, *sh;
|
||||
sctp_chunkhdr_t _sch, *sch;
|
||||
u_int32_t offset, count;
|
||||
char map[256 / sizeof (char)] = {0};
|
||||
|
||||
DEBUGP(__FUNCTION__);
|
||||
DEBUGP("\n");
|
||||
|
||||
sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph);
|
||||
if (sh == NULL)
|
||||
return 0;
|
||||
|
||||
if (do_basic_checks(conntrack, skb, map) != 0)
|
||||
return 0;
|
||||
|
||||
/* If an OOTB packet has any of these chunks discard (Sec 8.4) */
|
||||
if ((test_bit (SCTP_CID_ABORT, (void *)map))
|
||||
|| (test_bit (SCTP_CID_SHUTDOWN_COMPLETE, (void *)map))
|
||||
|| (test_bit (SCTP_CID_COOKIE_ACK, (void *)map))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
newconntrack = SCTP_CONNTRACK_MAX;
|
||||
for_each_sctp_chunk (skb, sch, _sch, offset, count) {
|
||||
/* Don't need lock here: this conntrack not in circulation yet */
|
||||
newconntrack = new_state (IP_CT_DIR_ORIGINAL,
|
||||
SCTP_CONNTRACK_NONE, sch->type);
|
||||
|
||||
/* Invalid: delete conntrack */
|
||||
if (newconntrack == SCTP_CONNTRACK_MAX) {
|
||||
DEBUGP("ip_conntrack_sctp: invalid new deleting.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Copy the vtag into the state info */
|
||||
if (sch->type == SCTP_CID_INIT) {
|
||||
if (sh->vtag == 0) {
|
||||
sctp_inithdr_t _inithdr, *ih;
|
||||
|
||||
ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t),
|
||||
sizeof(_inithdr), &_inithdr);
|
||||
if (ih == NULL)
|
||||
return 0;
|
||||
|
||||
DEBUGP("Setting vtag %x for new conn\n",
|
||||
ih->init_tag);
|
||||
|
||||
conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] =
|
||||
ih->init_tag;
|
||||
} else {
|
||||
/* Sec 8.5.1 (A) */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* If it is a shutdown ack OOTB packet, we expect a return
|
||||
shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */
|
||||
else {
|
||||
DEBUGP("Setting vtag %x for new conn OOTB\n",
|
||||
sh->vtag);
|
||||
conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag;
|
||||
}
|
||||
|
||||
conntrack->proto.sctp.state = newconntrack;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct ip_conntrack_protocol ip_conntrack_protocol_sctp = {
|
||||
.proto = IPPROTO_SCTP,
|
||||
.name = "sctp",
|
||||
.pkt_to_tuple = sctp_pkt_to_tuple,
|
||||
.invert_tuple = sctp_invert_tuple,
|
||||
.print_tuple = sctp_print_tuple,
|
||||
.print_conntrack = sctp_print_conntrack,
|
||||
.packet = sctp_packet,
|
||||
.new = sctp_new,
|
||||
.destroy = NULL,
|
||||
.me = THIS_MODULE,
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
.tuple_to_nfattr = ip_ct_port_tuple_to_nfattr,
|
||||
.nfattr_to_tuple = ip_ct_port_nfattr_to_tuple,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
static ctl_table ip_ct_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED,
|
||||
.procname = "ip_conntrack_sctp_timeout_closed",
|
||||
.data = &ip_ct_sctp_timeout_closed,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT,
|
||||
.procname = "ip_conntrack_sctp_timeout_cookie_wait",
|
||||
.data = &ip_ct_sctp_timeout_cookie_wait,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED,
|
||||
.procname = "ip_conntrack_sctp_timeout_cookie_echoed",
|
||||
.data = &ip_ct_sctp_timeout_cookie_echoed,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED,
|
||||
.procname = "ip_conntrack_sctp_timeout_established",
|
||||
.data = &ip_ct_sctp_timeout_established,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT,
|
||||
.procname = "ip_conntrack_sctp_timeout_shutdown_sent",
|
||||
.data = &ip_ct_sctp_timeout_shutdown_sent,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD,
|
||||
.procname = "ip_conntrack_sctp_timeout_shutdown_recd",
|
||||
.data = &ip_ct_sctp_timeout_shutdown_recd,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT,
|
||||
.procname = "ip_conntrack_sctp_timeout_shutdown_ack_sent",
|
||||
.data = &ip_ct_sctp_timeout_shutdown_ack_sent,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
static ctl_table ip_ct_netfilter_table[] = {
|
||||
{
|
||||
.ctl_name = NET_IPV4_NETFILTER,
|
||||
.procname = "netfilter",
|
||||
.mode = 0555,
|
||||
.child = ip_ct_sysctl_table,
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
static ctl_table ip_ct_ipv4_table[] = {
|
||||
{
|
||||
.ctl_name = NET_IPV4,
|
||||
.procname = "ipv4",
|
||||
.mode = 0555,
|
||||
.child = ip_ct_netfilter_table,
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
static ctl_table ip_ct_net_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_NET,
|
||||
.procname = "net",
|
||||
.mode = 0555,
|
||||
.child = ip_ct_ipv4_table,
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
static struct ctl_table_header *ip_ct_sysctl_header;
|
||||
#endif
|
||||
|
||||
static int __init ip_conntrack_proto_sctp_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ip_conntrack_protocol_register(&ip_conntrack_protocol_sctp);
|
||||
if (ret) {
|
||||
printk("ip_conntrack_proto_sctp: protocol register failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table);
|
||||
if (ip_ct_sysctl_header == NULL) {
|
||||
ret = -ENOMEM;
|
||||
printk("ip_conntrack_proto_sctp: can't register to sysctl.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
cleanup:
|
||||
ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp);
|
||||
#endif
|
||||
out:
|
||||
DEBUGP("SCTP conntrack module loading %s\n",
|
||||
ret ? "failed": "succeeded");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ip_conntrack_proto_sctp_fini(void)
|
||||
{
|
||||
ip_conntrack_protocol_unregister(&ip_conntrack_protocol_sctp);
|
||||
#ifdef CONFIG_SYSCTL
|
||||
unregister_sysctl_table(ip_ct_sysctl_header);
|
||||
#endif
|
||||
DEBUGP("SCTP conntrack module unloaded\n");
|
||||
}
|
||||
|
||||
module_init(ip_conntrack_proto_sctp_init);
|
||||
module_exit(ip_conntrack_proto_sctp_fini);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Kiran Kumar Immidi");
|
||||
MODULE_DESCRIPTION("Netfilter connection tracking protocol helper for SCTP");
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,148 +0,0 @@
|
|||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <net/checksum.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
|
||||
|
||||
unsigned int ip_ct_udp_timeout __read_mostly = 30*HZ;
|
||||
unsigned int ip_ct_udp_timeout_stream __read_mostly = 180*HZ;
|
||||
|
||||
static int udp_pkt_to_tuple(const struct sk_buff *skb,
|
||||
unsigned int dataoff,
|
||||
struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
struct udphdr _hdr, *hp;
|
||||
|
||||
/* Actually only need first 8 bytes. */
|
||||
hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
|
||||
if (hp == NULL)
|
||||
return 0;
|
||||
|
||||
tuple->src.u.udp.port = hp->source;
|
||||
tuple->dst.u.udp.port = hp->dest;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int udp_invert_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack_tuple *orig)
|
||||
{
|
||||
tuple->src.u.udp.port = orig->dst.u.udp.port;
|
||||
tuple->dst.u.udp.port = orig->src.u.udp.port;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print out the per-protocol part of the tuple. */
|
||||
static int udp_print_tuple(struct seq_file *s,
|
||||
const struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
return seq_printf(s, "sport=%hu dport=%hu ",
|
||||
ntohs(tuple->src.u.udp.port),
|
||||
ntohs(tuple->dst.u.udp.port));
|
||||
}
|
||||
|
||||
/* Print out the private part of the conntrack. */
|
||||
static int udp_print_conntrack(struct seq_file *s,
|
||||
const struct ip_conntrack *conntrack)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns verdict for packet, and may modify conntracktype */
|
||||
static int udp_packet(struct ip_conntrack *conntrack,
|
||||
const struct sk_buff *skb,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
/* If we've seen traffic both ways, this is some kind of UDP
|
||||
stream. Extend timeout. */
|
||||
if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
|
||||
ip_ct_refresh_acct(conntrack, ctinfo, skb,
|
||||
ip_ct_udp_timeout_stream);
|
||||
/* Also, more likely to be important, and not a probe */
|
||||
if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
|
||||
ip_conntrack_event_cache(IPCT_STATUS, skb);
|
||||
} else
|
||||
ip_ct_refresh_acct(conntrack, ctinfo, skb, ip_ct_udp_timeout);
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Called when a new connection for this protocol found. */
|
||||
static int udp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int udp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
|
||||
unsigned int hooknum)
|
||||
{
|
||||
const unsigned int hdrlen = ip_hdrlen(skb);
|
||||
unsigned int udplen = skb->len - hdrlen;
|
||||
struct udphdr _hdr, *hdr;
|
||||
|
||||
/* Header is too small? */
|
||||
hdr = skb_header_pointer(skb, hdrlen, sizeof(_hdr), &_hdr);
|
||||
if (hdr == NULL) {
|
||||
if (LOG_INVALID(IPPROTO_UDP))
|
||||
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
|
||||
"ip_ct_udp: short packet ");
|
||||
return -NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Truncated/malformed packets */
|
||||
if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
|
||||
if (LOG_INVALID(IPPROTO_UDP))
|
||||
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
|
||||
"ip_ct_udp: truncated/malformed packet ");
|
||||
return -NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Packet with no checksum */
|
||||
if (!hdr->check)
|
||||
return NF_ACCEPT;
|
||||
|
||||
/* Checksum invalid? Ignore.
|
||||
* We skip checking packets on the outgoing path
|
||||
* because the checksum is assumed to be correct.
|
||||
* FIXME: Source route IP option packets --RR */
|
||||
if (ip_conntrack_checksum && hooknum == NF_IP_PRE_ROUTING &&
|
||||
nf_ip_checksum(skb, hooknum, hdrlen, IPPROTO_UDP)) {
|
||||
if (LOG_INVALID(IPPROTO_UDP))
|
||||
nf_log_packet(PF_INET, 0, skb, NULL, NULL, NULL,
|
||||
"ip_ct_udp: bad UDP checksum ");
|
||||
return -NF_ACCEPT;
|
||||
}
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
struct ip_conntrack_protocol ip_conntrack_protocol_udp =
|
||||
{
|
||||
.proto = IPPROTO_UDP,
|
||||
.name = "udp",
|
||||
.pkt_to_tuple = udp_pkt_to_tuple,
|
||||
.invert_tuple = udp_invert_tuple,
|
||||
.print_tuple = udp_print_tuple,
|
||||
.print_conntrack = udp_print_conntrack,
|
||||
.packet = udp_packet,
|
||||
.new = udp_new,
|
||||
.error = udp_error,
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
.tuple_to_nfattr = ip_ct_port_tuple_to_nfattr,
|
||||
.nfattr_to_tuple = ip_ct_port_nfattr_to_tuple,
|
||||
#endif
|
||||
};
|
|
@ -1,520 +0,0 @@
|
|||
/* SIP extension for IP connection tracking.
|
||||
*
|
||||
* (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
|
||||
* based on RR's ip_conntrack_ftp.c and other modules.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
|
||||
MODULE_DESCRIPTION("SIP connection tracking helper");
|
||||
|
||||
#define MAX_PORTS 8
|
||||
static unsigned short ports[MAX_PORTS];
|
||||
static int ports_c;
|
||||
module_param_array(ports, ushort, &ports_c, 0400);
|
||||
MODULE_PARM_DESC(ports, "port numbers of sip servers");
|
||||
|
||||
static unsigned int sip_timeout = SIP_TIMEOUT;
|
||||
module_param(sip_timeout, uint, 0600);
|
||||
MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
|
||||
|
||||
unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack *ct,
|
||||
const char **dptr);
|
||||
EXPORT_SYMBOL_GPL(ip_nat_sip_hook);
|
||||
|
||||
unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack_expect *exp,
|
||||
const char *dptr);
|
||||
EXPORT_SYMBOL_GPL(ip_nat_sdp_hook);
|
||||
|
||||
static int digits_len(const char *dptr, const char *limit, int *shift);
|
||||
static int epaddr_len(const char *dptr, const char *limit, int *shift);
|
||||
static int skp_digits_len(const char *dptr, const char *limit, int *shift);
|
||||
static int skp_epaddr_len(const char *dptr, const char *limit, int *shift);
|
||||
|
||||
struct sip_header_nfo {
|
||||
const char *lname;
|
||||
const char *sname;
|
||||
const char *ln_str;
|
||||
size_t lnlen;
|
||||
size_t snlen;
|
||||
size_t ln_strlen;
|
||||
int case_sensitive;
|
||||
int (*match_len)(const char *, const char *, int *);
|
||||
};
|
||||
|
||||
static struct sip_header_nfo ct_sip_hdrs[] = {
|
||||
[POS_REG_REQ_URI] = { /* SIP REGISTER request URI */
|
||||
.lname = "sip:",
|
||||
.lnlen = sizeof("sip:") - 1,
|
||||
.ln_str = ":",
|
||||
.ln_strlen = sizeof(":") - 1,
|
||||
.match_len = epaddr_len
|
||||
},
|
||||
[POS_REQ_URI] = { /* SIP request URI */
|
||||
.lname = "sip:",
|
||||
.lnlen = sizeof("sip:") - 1,
|
||||
.ln_str = "@",
|
||||
.ln_strlen = sizeof("@") - 1,
|
||||
.match_len = epaddr_len
|
||||
},
|
||||
[POS_FROM] = { /* SIP From header */
|
||||
.lname = "From:",
|
||||
.lnlen = sizeof("From:") - 1,
|
||||
.sname = "\r\nf:",
|
||||
.snlen = sizeof("\r\nf:") - 1,
|
||||
.ln_str = "sip:",
|
||||
.ln_strlen = sizeof("sip:") - 1,
|
||||
.match_len = skp_epaddr_len,
|
||||
},
|
||||
[POS_TO] = { /* SIP To header */
|
||||
.lname = "To:",
|
||||
.lnlen = sizeof("To:") - 1,
|
||||
.sname = "\r\nt:",
|
||||
.snlen = sizeof("\r\nt:") - 1,
|
||||
.ln_str = "sip:",
|
||||
.ln_strlen = sizeof("sip:") - 1,
|
||||
.match_len = skp_epaddr_len,
|
||||
},
|
||||
[POS_VIA] = { /* SIP Via header */
|
||||
.lname = "Via:",
|
||||
.lnlen = sizeof("Via:") - 1,
|
||||
.sname = "\r\nv:",
|
||||
.snlen = sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */
|
||||
.ln_str = "UDP ",
|
||||
.ln_strlen = sizeof("UDP ") - 1,
|
||||
.match_len = epaddr_len,
|
||||
},
|
||||
[POS_CONTACT] = { /* SIP Contact header */
|
||||
.lname = "Contact:",
|
||||
.lnlen = sizeof("Contact:") - 1,
|
||||
.sname = "\r\nm:",
|
||||
.snlen = sizeof("\r\nm:") - 1,
|
||||
.ln_str = "sip:",
|
||||
.ln_strlen = sizeof("sip:") - 1,
|
||||
.match_len = skp_epaddr_len
|
||||
},
|
||||
[POS_CONTENT] = { /* SIP Content length header */
|
||||
.lname = "Content-Length:",
|
||||
.lnlen = sizeof("Content-Length:") - 1,
|
||||
.sname = "\r\nl:",
|
||||
.snlen = sizeof("\r\nl:") - 1,
|
||||
.ln_str = ":",
|
||||
.ln_strlen = sizeof(":") - 1,
|
||||
.match_len = skp_digits_len
|
||||
},
|
||||
[POS_MEDIA] = { /* SDP media info */
|
||||
.case_sensitive = 1,
|
||||
.lname = "\nm=",
|
||||
.lnlen = sizeof("\nm=") - 1,
|
||||
.sname = "\rm=",
|
||||
.snlen = sizeof("\rm=") - 1,
|
||||
.ln_str = "audio ",
|
||||
.ln_strlen = sizeof("audio ") - 1,
|
||||
.match_len = digits_len
|
||||
},
|
||||
[POS_OWNER] = { /* SDP owner address*/
|
||||
.case_sensitive = 1,
|
||||
.lname = "\no=",
|
||||
.lnlen = sizeof("\no=") - 1,
|
||||
.sname = "\ro=",
|
||||
.snlen = sizeof("\ro=") - 1,
|
||||
.ln_str = "IN IP4 ",
|
||||
.ln_strlen = sizeof("IN IP4 ") - 1,
|
||||
.match_len = epaddr_len
|
||||
},
|
||||
[POS_CONNECTION] = { /* SDP connection info */
|
||||
.case_sensitive = 1,
|
||||
.lname = "\nc=",
|
||||
.lnlen = sizeof("\nc=") - 1,
|
||||
.sname = "\rc=",
|
||||
.snlen = sizeof("\rc=") - 1,
|
||||
.ln_str = "IN IP4 ",
|
||||
.ln_strlen = sizeof("IN IP4 ") - 1,
|
||||
.match_len = epaddr_len
|
||||
},
|
||||
[POS_SDP_HEADER] = { /* SDP version header */
|
||||
.case_sensitive = 1,
|
||||
.lname = "\nv=",
|
||||
.lnlen = sizeof("\nv=") - 1,
|
||||
.sname = "\rv=",
|
||||
.snlen = sizeof("\rv=") - 1,
|
||||
.ln_str = "=",
|
||||
.ln_strlen = sizeof("=") - 1,
|
||||
.match_len = digits_len
|
||||
}
|
||||
};
|
||||
|
||||
/* get line lenght until first CR or LF seen. */
|
||||
int ct_sip_lnlen(const char *line, const char *limit)
|
||||
{
|
||||
const char *k = line;
|
||||
|
||||
while ((line <= limit) && (*line == '\r' || *line == '\n'))
|
||||
line++;
|
||||
|
||||
while (line <= limit) {
|
||||
if (*line == '\r' || *line == '\n')
|
||||
break;
|
||||
line++;
|
||||
}
|
||||
return line - k;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ct_sip_lnlen);
|
||||
|
||||
/* Linear string search, case sensitive. */
|
||||
const char *ct_sip_search(const char *needle, const char *haystack,
|
||||
size_t needle_len, size_t haystack_len,
|
||||
int case_sensitive)
|
||||
{
|
||||
const char *limit = haystack + (haystack_len - needle_len);
|
||||
|
||||
while (haystack <= limit) {
|
||||
if (case_sensitive) {
|
||||
if (strncmp(haystack, needle, needle_len) == 0)
|
||||
return haystack;
|
||||
} else {
|
||||
if (strnicmp(haystack, needle, needle_len) == 0)
|
||||
return haystack;
|
||||
}
|
||||
haystack++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ct_sip_search);
|
||||
|
||||
static int digits_len(const char *dptr, const char *limit, int *shift)
|
||||
{
|
||||
int len = 0;
|
||||
while (dptr <= limit && isdigit(*dptr)) {
|
||||
dptr++;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* get digits lenght, skiping blank spaces. */
|
||||
static int skp_digits_len(const char *dptr, const char *limit, int *shift)
|
||||
{
|
||||
for (; dptr <= limit && *dptr == ' '; dptr++)
|
||||
(*shift)++;
|
||||
|
||||
return digits_len(dptr, limit, shift);
|
||||
}
|
||||
|
||||
/* Simple ipaddr parser.. */
|
||||
static int parse_ipaddr(const char *cp, const char **endp,
|
||||
__be32 *ipaddr, const char *limit)
|
||||
{
|
||||
unsigned long int val;
|
||||
int i, digit = 0;
|
||||
|
||||
for (i = 0, *ipaddr = 0; cp <= limit && i < 4; i++) {
|
||||
digit = 0;
|
||||
if (!isdigit(*cp))
|
||||
break;
|
||||
|
||||
val = simple_strtoul(cp, (char **)&cp, 10);
|
||||
if (val > 0xFF)
|
||||
return -1;
|
||||
|
||||
((u_int8_t *)ipaddr)[i] = val;
|
||||
digit = 1;
|
||||
|
||||
if (*cp != '.')
|
||||
break;
|
||||
cp++;
|
||||
}
|
||||
if (!digit)
|
||||
return -1;
|
||||
|
||||
if (endp)
|
||||
*endp = cp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* skip ip address. returns it lenght. */
|
||||
static int epaddr_len(const char *dptr, const char *limit, int *shift)
|
||||
{
|
||||
const char *aux = dptr;
|
||||
__be32 ip;
|
||||
|
||||
if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) {
|
||||
DEBUGP("ip: %s parse failed.!\n", dptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Port number */
|
||||
if (*dptr == ':') {
|
||||
dptr++;
|
||||
dptr += digits_len(dptr, limit, shift);
|
||||
}
|
||||
return dptr - aux;
|
||||
}
|
||||
|
||||
/* get address length, skiping user info. */
|
||||
static int skp_epaddr_len(const char *dptr, const char *limit, int *shift)
|
||||
{
|
||||
int s = *shift;
|
||||
|
||||
/* Search for @, but stop at the end of the line.
|
||||
* We are inside a sip: URI, so we don't need to worry about
|
||||
* continuation lines. */
|
||||
while (dptr <= limit &&
|
||||
*dptr != '@' && *dptr != '\r' && *dptr != '\n') {
|
||||
(*shift)++;
|
||||
dptr++;
|
||||
}
|
||||
|
||||
if (dptr <= limit && *dptr == '@') {
|
||||
dptr++;
|
||||
(*shift)++;
|
||||
} else
|
||||
*shift = s;
|
||||
|
||||
return epaddr_len(dptr, limit, shift);
|
||||
}
|
||||
|
||||
/* Returns 0 if not found, -1 error parsing. */
|
||||
int ct_sip_get_info(const char *dptr, size_t dlen,
|
||||
unsigned int *matchoff,
|
||||
unsigned int *matchlen,
|
||||
enum sip_header_pos pos)
|
||||
{
|
||||
struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos];
|
||||
const char *limit, *aux, *k = dptr;
|
||||
int shift = 0;
|
||||
|
||||
limit = dptr + (dlen - hnfo->lnlen);
|
||||
|
||||
while (dptr <= limit) {
|
||||
if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
|
||||
(hnfo->sname == NULL ||
|
||||
strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) {
|
||||
dptr++;
|
||||
continue;
|
||||
}
|
||||
aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen,
|
||||
ct_sip_lnlen(dptr, limit),
|
||||
hnfo->case_sensitive);
|
||||
if (!aux) {
|
||||
DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str,
|
||||
hnfo->lname);
|
||||
return -1;
|
||||
}
|
||||
aux += hnfo->ln_strlen;
|
||||
|
||||
*matchlen = hnfo->match_len(aux, limit, &shift);
|
||||
if (!*matchlen)
|
||||
return -1;
|
||||
|
||||
*matchoff = (aux - k) + shift;
|
||||
|
||||
DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname,
|
||||
*matchlen);
|
||||
return 1;
|
||||
}
|
||||
DEBUGP("%s header not found.\n", hnfo->lname);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ct_sip_get_info);
|
||||
|
||||
static int set_expected_rtp(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
__be32 ipaddr, u_int16_t port,
|
||||
const char *dptr)
|
||||
{
|
||||
struct ip_conntrack_expect *exp;
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
int ret;
|
||||
typeof(ip_nat_sdp_hook) ip_nat_sdp;
|
||||
|
||||
exp = ip_conntrack_expect_alloc(ct);
|
||||
if (exp == NULL)
|
||||
return NF_DROP;
|
||||
|
||||
exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
|
||||
exp->tuple.src.u.udp.port = 0;
|
||||
exp->tuple.dst.ip = ipaddr;
|
||||
exp->tuple.dst.u.udp.port = htons(port);
|
||||
exp->tuple.dst.protonum = IPPROTO_UDP;
|
||||
|
||||
exp->mask.src.ip = htonl(0xFFFFFFFF);
|
||||
exp->mask.src.u.udp.port = 0;
|
||||
exp->mask.dst.ip = htonl(0xFFFFFFFF);
|
||||
exp->mask.dst.u.udp.port = htons(0xFFFF);
|
||||
exp->mask.dst.protonum = 0xFF;
|
||||
|
||||
exp->expectfn = NULL;
|
||||
exp->flags = 0;
|
||||
|
||||
ip_nat_sdp = rcu_dereference(ip_nat_sdp_hook);
|
||||
if (ip_nat_sdp)
|
||||
ret = ip_nat_sdp(pskb, ctinfo, exp, dptr);
|
||||
else {
|
||||
if (ip_conntrack_expect_related(exp) != 0)
|
||||
ret = NF_DROP;
|
||||
else
|
||||
ret = NF_ACCEPT;
|
||||
}
|
||||
ip_conntrack_expect_put(exp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sip_help(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
unsigned int dataoff, datalen;
|
||||
const char *dptr;
|
||||
int ret = NF_ACCEPT;
|
||||
int matchoff, matchlen;
|
||||
__be32 ipaddr;
|
||||
u_int16_t port;
|
||||
typeof(ip_nat_sip_hook) ip_nat_sip;
|
||||
|
||||
/* No Data ? */
|
||||
dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
|
||||
if (dataoff >= (*pskb)->len) {
|
||||
DEBUGP("skb->len = %u\n", (*pskb)->len);
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
ip_ct_refresh(ct, *pskb, sip_timeout * HZ);
|
||||
|
||||
if (!skb_is_nonlinear(*pskb))
|
||||
dptr = (*pskb)->data + dataoff;
|
||||
else {
|
||||
DEBUGP("Copy of skbuff not supported yet.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ip_nat_sip = rcu_dereference(ip_nat_sip_hook);
|
||||
if (ip_nat_sip) {
|
||||
if (!ip_nat_sip(pskb, ctinfo, ct, &dptr)) {
|
||||
ret = NF_DROP;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* After this point NAT, could have mangled skb, so
|
||||
we need to recalculate payload lenght. */
|
||||
datalen = (*pskb)->len - dataoff;
|
||||
|
||||
if (datalen < (sizeof("SIP/2.0 200") - 1))
|
||||
goto out;
|
||||
|
||||
/* RTP info only in some SDP pkts */
|
||||
if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 &&
|
||||
memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) {
|
||||
goto out;
|
||||
}
|
||||
/* Get ip and port address from SDP packet. */
|
||||
if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
|
||||
POS_CONNECTION) > 0) {
|
||||
|
||||
/* We'll drop only if there are parse problems. */
|
||||
if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr,
|
||||
dptr + datalen) < 0) {
|
||||
ret = NF_DROP;
|
||||
goto out;
|
||||
}
|
||||
if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
|
||||
POS_MEDIA) > 0) {
|
||||
|
||||
port = simple_strtoul(dptr + matchoff, NULL, 10);
|
||||
if (port < 1024) {
|
||||
ret = NF_DROP;
|
||||
goto out;
|
||||
}
|
||||
ret = set_expected_rtp(pskb, ct, ctinfo,
|
||||
ipaddr, port, dptr);
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ip_conntrack_helper sip[MAX_PORTS];
|
||||
static char sip_names[MAX_PORTS][10];
|
||||
|
||||
static void fini(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ports_c; i++) {
|
||||
DEBUGP("unregistering helper for port %d\n", ports[i]);
|
||||
ip_conntrack_helper_unregister(&sip[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
int i, ret;
|
||||
char *tmpname;
|
||||
|
||||
if (ports_c == 0)
|
||||
ports[ports_c++] = SIP_PORT;
|
||||
|
||||
for (i = 0; i < ports_c; i++) {
|
||||
/* Create helper structure */
|
||||
memset(&sip[i], 0, sizeof(struct ip_conntrack_helper));
|
||||
|
||||
sip[i].tuple.dst.protonum = IPPROTO_UDP;
|
||||
sip[i].tuple.src.u.udp.port = htons(ports[i]);
|
||||
sip[i].mask.src.u.udp.port = htons(0xFFFF);
|
||||
sip[i].mask.dst.protonum = 0xFF;
|
||||
sip[i].max_expected = 2;
|
||||
sip[i].timeout = 3 * 60; /* 3 minutes */
|
||||
sip[i].me = THIS_MODULE;
|
||||
sip[i].help = sip_help;
|
||||
|
||||
tmpname = &sip_names[i][0];
|
||||
if (ports[i] == SIP_PORT)
|
||||
sprintf(tmpname, "sip");
|
||||
else
|
||||
sprintf(tmpname, "sip-%d", i);
|
||||
sip[i].name = tmpname;
|
||||
|
||||
DEBUGP("port #%d: %d\n", i, ports[i]);
|
||||
|
||||
ret = ip_conntrack_helper_register(&sip[i]);
|
||||
if (ret) {
|
||||
printk("ERROR registering helper for port %d\n",
|
||||
ports[i]);
|
||||
fini();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
|
@ -1,962 +0,0 @@
|
|||
/* This file contains all the functions required for the standalone
|
||||
ip_conntrack module.
|
||||
|
||||
These are not required by the compatibility layer.
|
||||
*/
|
||||
|
||||
/* (C) 1999-2001 Paul `Rusty' Russell
|
||||
* (C) 2002-2005 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.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/percpu.h>
|
||||
#ifdef CONFIG_SYSCTL
|
||||
#include <linux/sysctl.h>
|
||||
#endif
|
||||
#include <net/checksum.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
extern atomic_t ip_conntrack_count;
|
||||
DECLARE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
|
||||
|
||||
static int kill_proto(struct ip_conntrack *i, void *data)
|
||||
{
|
||||
return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum ==
|
||||
*((u_int8_t *) data));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static int
|
||||
print_tuple(struct seq_file *s, const struct ip_conntrack_tuple *tuple,
|
||||
struct ip_conntrack_protocol *proto)
|
||||
{
|
||||
seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ",
|
||||
NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip));
|
||||
return proto->print_tuple(s, tuple);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IP_NF_CT_ACCT
|
||||
static unsigned int
|
||||
seq_print_counters(struct seq_file *s,
|
||||
const struct ip_conntrack_counter *counter)
|
||||
{
|
||||
return seq_printf(s, "packets=%llu bytes=%llu ",
|
||||
(unsigned long long)counter->packets,
|
||||
(unsigned long long)counter->bytes);
|
||||
}
|
||||
#else
|
||||
#define seq_print_counters(x, y) 0
|
||||
#endif
|
||||
|
||||
struct ct_iter_state {
|
||||
unsigned int bucket;
|
||||
};
|
||||
|
||||
static struct list_head *ct_get_first(struct seq_file *seq)
|
||||
{
|
||||
struct ct_iter_state *st = seq->private;
|
||||
|
||||
for (st->bucket = 0;
|
||||
st->bucket < ip_conntrack_htable_size;
|
||||
st->bucket++) {
|
||||
if (!list_empty(&ip_conntrack_hash[st->bucket]))
|
||||
return ip_conntrack_hash[st->bucket].next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head)
|
||||
{
|
||||
struct ct_iter_state *st = seq->private;
|
||||
|
||||
head = head->next;
|
||||
while (head == &ip_conntrack_hash[st->bucket]) {
|
||||
if (++st->bucket >= ip_conntrack_htable_size)
|
||||
return NULL;
|
||||
head = ip_conntrack_hash[st->bucket].next;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos)
|
||||
{
|
||||
struct list_head *head = ct_get_first(seq);
|
||||
|
||||
if (head)
|
||||
while (pos && (head = ct_get_next(seq, head)))
|
||||
pos--;
|
||||
return pos ? NULL : head;
|
||||
}
|
||||
|
||||
static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
read_lock_bh(&ip_conntrack_lock);
|
||||
return ct_get_idx(seq, *pos);
|
||||
}
|
||||
|
||||
static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
(*pos)++;
|
||||
return ct_get_next(s, v);
|
||||
}
|
||||
|
||||
static void ct_seq_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
read_unlock_bh(&ip_conntrack_lock);
|
||||
}
|
||||
|
||||
static int ct_seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
const struct ip_conntrack_tuple_hash *hash = v;
|
||||
const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash);
|
||||
struct ip_conntrack_protocol *proto;
|
||||
|
||||
IP_NF_ASSERT(conntrack);
|
||||
|
||||
/* we only want to print DIR_ORIGINAL */
|
||||
if (DIRECTION(hash))
|
||||
return 0;
|
||||
|
||||
proto = __ip_conntrack_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
|
||||
IP_NF_ASSERT(proto);
|
||||
|
||||
if (seq_printf(s, "%-8s %u %ld ",
|
||||
proto->name,
|
||||
conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
|
||||
timer_pending(&conntrack->timeout)
|
||||
? (long)(conntrack->timeout.expires - jiffies)/HZ
|
||||
: 0) != 0)
|
||||
return -ENOSPC;
|
||||
|
||||
if (proto->print_conntrack(s, conntrack))
|
||||
return -ENOSPC;
|
||||
|
||||
if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
|
||||
proto))
|
||||
return -ENOSPC;
|
||||
|
||||
if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_ORIGINAL]))
|
||||
return -ENOSPC;
|
||||
|
||||
if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
|
||||
if (seq_printf(s, "[UNREPLIED] "))
|
||||
return -ENOSPC;
|
||||
|
||||
if (print_tuple(s, &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
|
||||
proto))
|
||||
return -ENOSPC;
|
||||
|
||||
if (seq_print_counters(s, &conntrack->counters[IP_CT_DIR_REPLY]))
|
||||
return -ENOSPC;
|
||||
|
||||
if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
|
||||
if (seq_printf(s, "[ASSURED] "))
|
||||
return -ENOSPC;
|
||||
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
|
||||
if (seq_printf(s, "mark=%u ", conntrack->mark))
|
||||
return -ENOSPC;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK
|
||||
if (seq_printf(s, "secmark=%u ", conntrack->secmark))
|
||||
return -ENOSPC;
|
||||
#endif
|
||||
|
||||
if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
|
||||
return -ENOSPC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations ct_seq_ops = {
|
||||
.start = ct_seq_start,
|
||||
.next = ct_seq_next,
|
||||
.stop = ct_seq_stop,
|
||||
.show = ct_seq_show
|
||||
};
|
||||
|
||||
static int ct_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *seq;
|
||||
struct ct_iter_state *st;
|
||||
int ret;
|
||||
|
||||
st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
|
||||
if (st == NULL)
|
||||
return -ENOMEM;
|
||||
ret = seq_open(file, &ct_seq_ops);
|
||||
if (ret)
|
||||
goto out_free;
|
||||
seq = file->private_data;
|
||||
seq->private = st;
|
||||
memset(st, 0, sizeof(struct ct_iter_state));
|
||||
return ret;
|
||||
out_free:
|
||||
kfree(st);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations ct_file_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ct_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release_private,
|
||||
};
|
||||
|
||||
/* expects */
|
||||
static void *exp_seq_start(struct seq_file *s, loff_t *pos)
|
||||
{
|
||||
struct list_head *e = &ip_conntrack_expect_list;
|
||||
loff_t i;
|
||||
|
||||
/* strange seq_file api calls stop even if we fail,
|
||||
* thus we need to grab lock since stop unlocks */
|
||||
read_lock_bh(&ip_conntrack_lock);
|
||||
|
||||
if (list_empty(e))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i <= *pos; i++) {
|
||||
e = e->next;
|
||||
if (e == &ip_conntrack_expect_list)
|
||||
return NULL;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
struct list_head *e = v;
|
||||
|
||||
++*pos;
|
||||
e = e->next;
|
||||
|
||||
if (e == &ip_conntrack_expect_list)
|
||||
return NULL;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static void exp_seq_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
read_unlock_bh(&ip_conntrack_lock);
|
||||
}
|
||||
|
||||
static int exp_seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct ip_conntrack_expect *expect = v;
|
||||
|
||||
if (expect->timeout.function)
|
||||
seq_printf(s, "%ld ", timer_pending(&expect->timeout)
|
||||
? (long)(expect->timeout.expires - jiffies)/HZ : 0);
|
||||
else
|
||||
seq_printf(s, "- ");
|
||||
|
||||
seq_printf(s, "proto=%u ", expect->tuple.dst.protonum);
|
||||
|
||||
print_tuple(s, &expect->tuple,
|
||||
__ip_conntrack_proto_find(expect->tuple.dst.protonum));
|
||||
return seq_putc(s, '\n');
|
||||
}
|
||||
|
||||
static struct seq_operations exp_seq_ops = {
|
||||
.start = exp_seq_start,
|
||||
.next = exp_seq_next,
|
||||
.stop = exp_seq_stop,
|
||||
.show = exp_seq_show
|
||||
};
|
||||
|
||||
static int exp_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &exp_seq_ops);
|
||||
}
|
||||
|
||||
static const struct file_operations exp_file_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = exp_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release
|
||||
};
|
||||
|
||||
static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (*pos == 0)
|
||||
return SEQ_START_TOKEN;
|
||||
|
||||
for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) {
|
||||
if (!cpu_possible(cpu))
|
||||
continue;
|
||||
*pos = cpu+1;
|
||||
return &per_cpu(ip_conntrack_stat, cpu);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for (cpu = *pos; cpu < NR_CPUS; ++cpu) {
|
||||
if (!cpu_possible(cpu))
|
||||
continue;
|
||||
*pos = cpu+1;
|
||||
return &per_cpu(ip_conntrack_stat, cpu);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
|
||||
{
|
||||
}
|
||||
|
||||
static int ct_cpu_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
unsigned int nr_conntracks = atomic_read(&ip_conntrack_count);
|
||||
struct ip_conntrack_stat *st = v;
|
||||
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x "
|
||||
"%08x %08x %08x %08x %08x %08x %08x %08x \n",
|
||||
nr_conntracks,
|
||||
st->searched,
|
||||
st->found,
|
||||
st->new,
|
||||
st->invalid,
|
||||
st->ignore,
|
||||
st->delete,
|
||||
st->delete_list,
|
||||
st->insert,
|
||||
st->insert_failed,
|
||||
st->drop,
|
||||
st->early_drop,
|
||||
st->error,
|
||||
|
||||
st->expect_new,
|
||||
st->expect_create,
|
||||
st->expect_delete
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct seq_operations ct_cpu_seq_ops = {
|
||||
.start = ct_cpu_seq_start,
|
||||
.next = ct_cpu_seq_next,
|
||||
.stop = ct_cpu_seq_stop,
|
||||
.show = ct_cpu_seq_show,
|
||||
};
|
||||
|
||||
static int ct_cpu_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &ct_cpu_seq_ops);
|
||||
}
|
||||
|
||||
static const struct file_operations ct_cpu_seq_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ct_cpu_seq_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release_private,
|
||||
};
|
||||
#endif
|
||||
|
||||
static unsigned int ip_confirm(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
/* We've seen it coming out the other side: confirm it */
|
||||
return ip_conntrack_confirm(pskb);
|
||||
}
|
||||
|
||||
static unsigned int ip_conntrack_help(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
|
||||
/* This is where we call the helper: as the packet goes out. */
|
||||
ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
if (ct && ct->helper && ctinfo != IP_CT_RELATED + IP_CT_IS_REPLY) {
|
||||
unsigned int ret;
|
||||
ret = ct->helper->help(pskb, ct, ctinfo);
|
||||
if (ret != NF_ACCEPT)
|
||||
return ret;
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static unsigned int ip_conntrack_defrag(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE)
|
||||
/* Previously seen (loopback)? Ignore. Do this before
|
||||
fragment check. */
|
||||
if ((*pskb)->nfct)
|
||||
return NF_ACCEPT;
|
||||
#endif
|
||||
|
||||
/* Gather fragments. */
|
||||
if (ip_hdr(*pskb)->frag_off & htons(IP_MF | IP_OFFSET)) {
|
||||
*pskb = ip_ct_gather_frags(*pskb,
|
||||
hooknum == NF_IP_PRE_ROUTING ?
|
||||
IP_DEFRAG_CONNTRACK_IN :
|
||||
IP_DEFRAG_CONNTRACK_OUT);
|
||||
if (!*pskb)
|
||||
return NF_STOLEN;
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static unsigned int ip_conntrack_local(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
/* root is playing with raw sockets. */
|
||||
if ((*pskb)->len < sizeof(struct iphdr)
|
||||
|| ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
|
||||
if (net_ratelimit())
|
||||
printk("ipt_hook: happy cracking.\n");
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
return ip_conntrack_in(hooknum, pskb, in, out, okfn);
|
||||
}
|
||||
|
||||
/* Connection tracking may drop packets, but never alters them, so
|
||||
make it the first hook. */
|
||||
static struct nf_hook_ops ip_conntrack_ops[] = {
|
||||
{
|
||||
.hook = ip_conntrack_defrag,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_PRE_ROUTING,
|
||||
.priority = NF_IP_PRI_CONNTRACK_DEFRAG,
|
||||
},
|
||||
{
|
||||
.hook = ip_conntrack_in,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_PRE_ROUTING,
|
||||
.priority = NF_IP_PRI_CONNTRACK,
|
||||
},
|
||||
{
|
||||
.hook = ip_conntrack_defrag,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_LOCAL_OUT,
|
||||
.priority = NF_IP_PRI_CONNTRACK_DEFRAG,
|
||||
},
|
||||
{
|
||||
.hook = ip_conntrack_local,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_LOCAL_OUT,
|
||||
.priority = NF_IP_PRI_CONNTRACK,
|
||||
},
|
||||
{
|
||||
.hook = ip_conntrack_help,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_POST_ROUTING,
|
||||
.priority = NF_IP_PRI_CONNTRACK_HELPER,
|
||||
},
|
||||
{
|
||||
.hook = ip_conntrack_help,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_LOCAL_IN,
|
||||
.priority = NF_IP_PRI_CONNTRACK_HELPER,
|
||||
},
|
||||
{
|
||||
.hook = ip_confirm,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_POST_ROUTING,
|
||||
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
|
||||
},
|
||||
{
|
||||
.hook = ip_confirm,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_LOCAL_IN,
|
||||
.priority = NF_IP_PRI_CONNTRACK_CONFIRM,
|
||||
},
|
||||
};
|
||||
|
||||
/* Sysctl support */
|
||||
|
||||
int ip_conntrack_checksum __read_mostly = 1;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
|
||||
/* From ip_conntrack_core.c */
|
||||
extern int ip_conntrack_max;
|
||||
extern unsigned int ip_conntrack_htable_size;
|
||||
|
||||
/* From ip_conntrack_proto_tcp.c */
|
||||
extern unsigned int ip_ct_tcp_timeout_syn_sent;
|
||||
extern unsigned int ip_ct_tcp_timeout_syn_recv;
|
||||
extern unsigned int ip_ct_tcp_timeout_established;
|
||||
extern unsigned int ip_ct_tcp_timeout_fin_wait;
|
||||
extern unsigned int ip_ct_tcp_timeout_close_wait;
|
||||
extern unsigned int ip_ct_tcp_timeout_last_ack;
|
||||
extern unsigned int ip_ct_tcp_timeout_time_wait;
|
||||
extern unsigned int ip_ct_tcp_timeout_close;
|
||||
extern unsigned int ip_ct_tcp_timeout_max_retrans;
|
||||
extern int ip_ct_tcp_loose;
|
||||
extern int ip_ct_tcp_be_liberal;
|
||||
extern int ip_ct_tcp_max_retrans;
|
||||
|
||||
/* From ip_conntrack_proto_udp.c */
|
||||
extern unsigned int ip_ct_udp_timeout;
|
||||
extern unsigned int ip_ct_udp_timeout_stream;
|
||||
|
||||
/* From ip_conntrack_proto_icmp.c */
|
||||
extern unsigned int ip_ct_icmp_timeout;
|
||||
|
||||
/* From ip_conntrack_proto_generic.c */
|
||||
extern unsigned int ip_ct_generic_timeout;
|
||||
|
||||
/* Log invalid packets of a given protocol */
|
||||
static int log_invalid_proto_min = 0;
|
||||
static int log_invalid_proto_max = 255;
|
||||
|
||||
static struct ctl_table_header *ip_ct_sysctl_header;
|
||||
|
||||
static ctl_table ip_ct_sysctl_table[] = {
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_MAX,
|
||||
.procname = "ip_conntrack_max",
|
||||
.data = &ip_conntrack_max,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_COUNT,
|
||||
.procname = "ip_conntrack_count",
|
||||
.data = &ip_conntrack_count,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0444,
|
||||
.proc_handler = &proc_dointvec,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS,
|
||||
.procname = "ip_conntrack_buckets",
|
||||
.data = &ip_conntrack_htable_size,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0444,
|
||||
.proc_handler = &proc_dointvec,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_CHECKSUM,
|
||||
.procname = "ip_conntrack_checksum",
|
||||
.data = &ip_conntrack_checksum,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT,
|
||||
.procname = "ip_conntrack_tcp_timeout_syn_sent",
|
||||
.data = &ip_ct_tcp_timeout_syn_sent,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV,
|
||||
.procname = "ip_conntrack_tcp_timeout_syn_recv",
|
||||
.data = &ip_ct_tcp_timeout_syn_recv,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED,
|
||||
.procname = "ip_conntrack_tcp_timeout_established",
|
||||
.data = &ip_ct_tcp_timeout_established,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT,
|
||||
.procname = "ip_conntrack_tcp_timeout_fin_wait",
|
||||
.data = &ip_ct_tcp_timeout_fin_wait,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT,
|
||||
.procname = "ip_conntrack_tcp_timeout_close_wait",
|
||||
.data = &ip_ct_tcp_timeout_close_wait,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK,
|
||||
.procname = "ip_conntrack_tcp_timeout_last_ack",
|
||||
.data = &ip_ct_tcp_timeout_last_ack,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT,
|
||||
.procname = "ip_conntrack_tcp_timeout_time_wait",
|
||||
.data = &ip_ct_tcp_timeout_time_wait,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE,
|
||||
.procname = "ip_conntrack_tcp_timeout_close",
|
||||
.data = &ip_ct_tcp_timeout_close,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT,
|
||||
.procname = "ip_conntrack_udp_timeout",
|
||||
.data = &ip_ct_udp_timeout,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM,
|
||||
.procname = "ip_conntrack_udp_timeout_stream",
|
||||
.data = &ip_ct_udp_timeout_stream,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT,
|
||||
.procname = "ip_conntrack_icmp_timeout",
|
||||
.data = &ip_ct_icmp_timeout,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT,
|
||||
.procname = "ip_conntrack_generic_timeout",
|
||||
.data = &ip_ct_generic_timeout,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_LOG_INVALID,
|
||||
.procname = "ip_conntrack_log_invalid",
|
||||
.data = &ip_ct_log_invalid,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_minmax,
|
||||
.strategy = &sysctl_intvec,
|
||||
.extra1 = &log_invalid_proto_min,
|
||||
.extra2 = &log_invalid_proto_max,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS,
|
||||
.procname = "ip_conntrack_tcp_timeout_max_retrans",
|
||||
.data = &ip_ct_tcp_timeout_max_retrans,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec_jiffies,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_LOOSE,
|
||||
.procname = "ip_conntrack_tcp_loose",
|
||||
.data = &ip_ct_tcp_loose,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL,
|
||||
.procname = "ip_conntrack_tcp_be_liberal",
|
||||
.data = &ip_ct_tcp_be_liberal,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS,
|
||||
.procname = "ip_conntrack_tcp_max_retrans",
|
||||
.data = &ip_ct_tcp_max_retrans,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec,
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
#define NET_IP_CONNTRACK_MAX 2089
|
||||
|
||||
static ctl_table ip_ct_netfilter_table[] = {
|
||||
{
|
||||
.ctl_name = NET_IPV4_NETFILTER,
|
||||
.procname = "netfilter",
|
||||
.mode = 0555,
|
||||
.child = ip_ct_sysctl_table,
|
||||
},
|
||||
{
|
||||
.ctl_name = NET_IP_CONNTRACK_MAX,
|
||||
.procname = "ip_conntrack_max",
|
||||
.data = &ip_conntrack_max,
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = &proc_dointvec
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
static ctl_table ip_ct_ipv4_table[] = {
|
||||
{
|
||||
.ctl_name = NET_IPV4,
|
||||
.procname = "ipv4",
|
||||
.mode = 0555,
|
||||
.child = ip_ct_netfilter_table,
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
static ctl_table ip_ct_net_table[] = {
|
||||
{
|
||||
.ctl_name = CTL_NET,
|
||||
.procname = "net",
|
||||
.mode = 0555,
|
||||
.child = ip_ct_ipv4_table,
|
||||
},
|
||||
{ .ctl_name = 0 }
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL(ip_ct_log_invalid);
|
||||
#endif /* CONFIG_SYSCTL */
|
||||
|
||||
/* FIXME: Allow NULL functions and sub in pointers to generic for
|
||||
them. --RR */
|
||||
int ip_conntrack_protocol_register(struct ip_conntrack_protocol *proto)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
write_lock_bh(&ip_conntrack_lock);
|
||||
if (ip_ct_protos[proto->proto] != &ip_conntrack_generic_protocol) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
rcu_assign_pointer(ip_ct_protos[proto->proto], proto);
|
||||
out:
|
||||
write_unlock_bh(&ip_conntrack_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ip_conntrack_protocol_unregister(struct ip_conntrack_protocol *proto)
|
||||
{
|
||||
write_lock_bh(&ip_conntrack_lock);
|
||||
rcu_assign_pointer(ip_ct_protos[proto->proto],
|
||||
&ip_conntrack_generic_protocol);
|
||||
write_unlock_bh(&ip_conntrack_lock);
|
||||
synchronize_rcu();
|
||||
|
||||
/* Remove all contrack entries for this protocol */
|
||||
ip_ct_iterate_cleanup(kill_proto, &proto->proto);
|
||||
}
|
||||
|
||||
static int __init ip_conntrack_standalone_init(void)
|
||||
{
|
||||
#ifdef CONFIG_PROC_FS
|
||||
struct proc_dir_entry *proc, *proc_exp, *proc_stat;
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
ret = ip_conntrack_init();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
ret = -ENOMEM;
|
||||
proc = proc_net_fops_create("ip_conntrack", 0440, &ct_file_ops);
|
||||
if (!proc) goto cleanup_init;
|
||||
|
||||
proc_exp = proc_net_fops_create("ip_conntrack_expect", 0440,
|
||||
&exp_file_ops);
|
||||
if (!proc_exp) goto cleanup_proc;
|
||||
|
||||
proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, proc_net_stat);
|
||||
if (!proc_stat)
|
||||
goto cleanup_proc_exp;
|
||||
|
||||
proc_stat->proc_fops = &ct_cpu_seq_fops;
|
||||
proc_stat->owner = THIS_MODULE;
|
||||
#endif
|
||||
|
||||
ret = nf_register_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
|
||||
if (ret < 0) {
|
||||
printk("ip_conntrack: can't register hooks.\n");
|
||||
goto cleanup_proc_stat;
|
||||
}
|
||||
#ifdef CONFIG_SYSCTL
|
||||
ip_ct_sysctl_header = register_sysctl_table(ip_ct_net_table);
|
||||
if (ip_ct_sysctl_header == NULL) {
|
||||
printk("ip_conntrack: can't register to sysctl.\n");
|
||||
ret = -ENOMEM;
|
||||
goto cleanup_hooks;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
cleanup_hooks:
|
||||
nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
|
||||
#endif
|
||||
cleanup_proc_stat:
|
||||
#ifdef CONFIG_PROC_FS
|
||||
remove_proc_entry("ip_conntrack", proc_net_stat);
|
||||
cleanup_proc_exp:
|
||||
proc_net_remove("ip_conntrack_expect");
|
||||
cleanup_proc:
|
||||
proc_net_remove("ip_conntrack");
|
||||
cleanup_init:
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
ip_conntrack_cleanup();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ip_conntrack_standalone_fini(void)
|
||||
{
|
||||
synchronize_net();
|
||||
#ifdef CONFIG_SYSCTL
|
||||
unregister_sysctl_table(ip_ct_sysctl_header);
|
||||
#endif
|
||||
nf_unregister_hooks(ip_conntrack_ops, ARRAY_SIZE(ip_conntrack_ops));
|
||||
#ifdef CONFIG_PROC_FS
|
||||
remove_proc_entry("ip_conntrack", proc_net_stat);
|
||||
proc_net_remove("ip_conntrack_expect");
|
||||
proc_net_remove("ip_conntrack");
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
ip_conntrack_cleanup();
|
||||
}
|
||||
|
||||
module_init(ip_conntrack_standalone_init);
|
||||
module_exit(ip_conntrack_standalone_fini);
|
||||
|
||||
/* Some modules need us, but don't depend directly on any symbol.
|
||||
They should call this. */
|
||||
void need_conntrack(void)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_chain);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_expect_chain);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_register_notifier);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_unregister_notifier);
|
||||
EXPORT_SYMBOL_GPL(__ip_ct_event_cache_init);
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(ip_conntrack_ecache);
|
||||
#endif
|
||||
EXPORT_SYMBOL(ip_conntrack_protocol_register);
|
||||
EXPORT_SYMBOL(ip_conntrack_protocol_unregister);
|
||||
EXPORT_SYMBOL(ip_ct_get_tuple);
|
||||
EXPORT_SYMBOL(invert_tuplepr);
|
||||
EXPORT_SYMBOL(ip_conntrack_alter_reply);
|
||||
EXPORT_SYMBOL(ip_conntrack_destroyed);
|
||||
EXPORT_SYMBOL(need_conntrack);
|
||||
EXPORT_SYMBOL(ip_conntrack_helper_register);
|
||||
EXPORT_SYMBOL(ip_conntrack_helper_unregister);
|
||||
EXPORT_SYMBOL(ip_ct_iterate_cleanup);
|
||||
EXPORT_SYMBOL(__ip_ct_refresh_acct);
|
||||
|
||||
EXPORT_SYMBOL(ip_conntrack_expect_alloc);
|
||||
EXPORT_SYMBOL(ip_conntrack_expect_put);
|
||||
EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get);
|
||||
EXPORT_SYMBOL(ip_conntrack_expect_related);
|
||||
EXPORT_SYMBOL(ip_conntrack_unexpect_related);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_expect_list);
|
||||
EXPORT_SYMBOL_GPL(ip_ct_unlink_expect);
|
||||
|
||||
EXPORT_SYMBOL(ip_conntrack_tuple_taken);
|
||||
EXPORT_SYMBOL(ip_ct_gather_frags);
|
||||
EXPORT_SYMBOL(ip_conntrack_htable_size);
|
||||
EXPORT_SYMBOL(ip_conntrack_lock);
|
||||
EXPORT_SYMBOL(ip_conntrack_hash);
|
||||
EXPORT_SYMBOL(ip_conntrack_untracked);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_find_get);
|
||||
#ifdef CONFIG_IP_NF_NAT_NEEDED
|
||||
EXPORT_SYMBOL(ip_conntrack_tcp_update);
|
||||
#endif
|
||||
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_flush);
|
||||
EXPORT_SYMBOL_GPL(__ip_conntrack_find);
|
||||
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_alloc);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_free);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_hash_insert);
|
||||
|
||||
EXPORT_SYMBOL_GPL(ip_ct_remove_expectations);
|
||||
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_helper_find_get);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_helper_put);
|
||||
EXPORT_SYMBOL_GPL(__ip_conntrack_helper_find_byname);
|
||||
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_proto_find_get);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_proto_put);
|
||||
EXPORT_SYMBOL_GPL(__ip_conntrack_proto_find);
|
||||
EXPORT_SYMBOL_GPL(ip_conntrack_checksum);
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
EXPORT_SYMBOL_GPL(ip_ct_port_tuple_to_nfattr);
|
||||
EXPORT_SYMBOL_GPL(ip_ct_port_nfattr_to_tuple);
|
||||
#endif
|
|
@ -1,161 +0,0 @@
|
|||
/* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Version: 0.0.7
|
||||
*
|
||||
* Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org>
|
||||
* - port to newnat API
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_tftp.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
|
||||
MODULE_DESCRIPTION("tftp connection tracking helper");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define MAX_PORTS 8
|
||||
static unsigned short ports[MAX_PORTS];
|
||||
static int ports_c;
|
||||
module_param_array(ports, ushort, &ports_c, 0400);
|
||||
MODULE_PARM_DESC(ports, "port numbers of tftp servers");
|
||||
|
||||
#if 0
|
||||
#define DEBUGP(format, args...) printk("%s:%s:" format, \
|
||||
__FILE__, __FUNCTION__ , ## args)
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack_expect *exp);
|
||||
EXPORT_SYMBOL_GPL(ip_nat_tftp_hook);
|
||||
|
||||
static int tftp_help(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
struct tftphdr _tftph, *tfh;
|
||||
struct ip_conntrack_expect *exp;
|
||||
unsigned int ret = NF_ACCEPT;
|
||||
typeof(ip_nat_tftp_hook) ip_nat_tftp;
|
||||
|
||||
tfh = skb_header_pointer(*pskb,
|
||||
ip_hdrlen(*pskb) + sizeof(struct udphdr),
|
||||
sizeof(_tftph), &_tftph);
|
||||
if (tfh == NULL)
|
||||
return NF_ACCEPT;
|
||||
|
||||
switch (ntohs(tfh->opcode)) {
|
||||
/* RRQ and WRQ works the same way */
|
||||
case TFTP_OPCODE_READ:
|
||||
case TFTP_OPCODE_WRITE:
|
||||
DEBUGP("");
|
||||
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
|
||||
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
|
||||
|
||||
exp = ip_conntrack_expect_alloc(ct);
|
||||
if (exp == NULL)
|
||||
return NF_DROP;
|
||||
|
||||
exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
|
||||
exp->mask.src.ip = htonl(0xffffffff);
|
||||
exp->mask.src.u.udp.port = 0;
|
||||
exp->mask.dst.ip = htonl(0xffffffff);
|
||||
exp->mask.dst.u.udp.port = htons(0xffff);
|
||||
exp->mask.dst.protonum = 0xff;
|
||||
exp->expectfn = NULL;
|
||||
exp->flags = 0;
|
||||
|
||||
DEBUGP("expect: ");
|
||||
DUMP_TUPLE(&exp->tuple);
|
||||
DUMP_TUPLE(&exp->mask);
|
||||
ip_nat_tftp = rcu_dereference(ip_nat_tftp_hook);
|
||||
if (ip_nat_tftp)
|
||||
ret = ip_nat_tftp(pskb, ctinfo, exp);
|
||||
else if (ip_conntrack_expect_related(exp) != 0)
|
||||
ret = NF_DROP;
|
||||
ip_conntrack_expect_put(exp);
|
||||
break;
|
||||
case TFTP_OPCODE_DATA:
|
||||
case TFTP_OPCODE_ACK:
|
||||
DEBUGP("Data/ACK opcode\n");
|
||||
break;
|
||||
case TFTP_OPCODE_ERROR:
|
||||
DEBUGP("Error opcode\n");
|
||||
break;
|
||||
default:
|
||||
DEBUGP("Unknown opcode\n");
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static struct ip_conntrack_helper tftp[MAX_PORTS];
|
||||
static char tftp_names[MAX_PORTS][sizeof("tftp-65535")];
|
||||
|
||||
static void ip_conntrack_tftp_fini(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < ports_c; i++) {
|
||||
DEBUGP("unregistering helper for port %d\n",
|
||||
ports[i]);
|
||||
ip_conntrack_helper_unregister(&tftp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init ip_conntrack_tftp_init(void)
|
||||
{
|
||||
int i, ret;
|
||||
char *tmpname;
|
||||
|
||||
if (ports_c == 0)
|
||||
ports[ports_c++] = TFTP_PORT;
|
||||
|
||||
for (i = 0; i < ports_c; i++) {
|
||||
/* Create helper structure */
|
||||
memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper));
|
||||
|
||||
tftp[i].tuple.dst.protonum = IPPROTO_UDP;
|
||||
tftp[i].tuple.src.u.udp.port = htons(ports[i]);
|
||||
tftp[i].mask.dst.protonum = 0xFF;
|
||||
tftp[i].mask.src.u.udp.port = htons(0xFFFF);
|
||||
tftp[i].max_expected = 1;
|
||||
tftp[i].timeout = 5 * 60; /* 5 minutes */
|
||||
tftp[i].me = THIS_MODULE;
|
||||
tftp[i].help = tftp_help;
|
||||
|
||||
tmpname = &tftp_names[i][0];
|
||||
if (ports[i] == TFTP_PORT)
|
||||
sprintf(tmpname, "tftp");
|
||||
else
|
||||
sprintf(tmpname, "tftp-%d", i);
|
||||
tftp[i].name = tmpname;
|
||||
|
||||
DEBUGP("port #%d: %d\n", i, ports[i]);
|
||||
|
||||
ret=ip_conntrack_helper_register(&tftp[i]);
|
||||
if (ret) {
|
||||
printk("ERROR registering helper for port %d\n",
|
||||
ports[i]);
|
||||
ip_conntrack_tftp_fini();
|
||||
return(ret);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
module_init(ip_conntrack_tftp_init);
|
||||
module_exit(ip_conntrack_tftp_fini);
|
|
@ -1,85 +0,0 @@
|
|||
/* Amanda extension for TCP NAT alteration.
|
||||
* (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
|
||||
* based on a copy of HW's ip_nat_irc.c as well as other modules
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* Module load syntax:
|
||||
* insmod ip_nat_amanda.o
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/udp.h>
|
||||
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
|
||||
|
||||
|
||||
MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
|
||||
MODULE_DESCRIPTION("Amanda NAT helper");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int help(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
char buffer[sizeof("65535")];
|
||||
u_int16_t port;
|
||||
unsigned int ret;
|
||||
|
||||
/* Connection comes from client. */
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->dir = IP_CT_DIR_ORIGINAL;
|
||||
|
||||
/* When you see the packet, we need to NAT it the same as the
|
||||
* this one (ie. same IP: it will be TCP and master is UDP). */
|
||||
exp->expectfn = ip_nat_follow_master;
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(port);
|
||||
if (ip_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
return NF_DROP;
|
||||
|
||||
sprintf(buffer, "%u", port);
|
||||
ret = ip_nat_mangle_udp_packet(pskb, exp->master, ctinfo,
|
||||
matchoff, matchlen,
|
||||
buffer, strlen(buffer));
|
||||
if (ret != NF_ACCEPT)
|
||||
ip_conntrack_unexpect_related(exp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ip_nat_amanda_fini(void)
|
||||
{
|
||||
rcu_assign_pointer(ip_nat_amanda_hook, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static int __init ip_nat_amanda_init(void)
|
||||
{
|
||||
BUG_ON(rcu_dereference(ip_nat_amanda_hook));
|
||||
rcu_assign_pointer(ip_nat_amanda_hook, help);
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(ip_nat_amanda_init);
|
||||
module_exit(ip_nat_amanda_fini);
|
|
@ -1,633 +0,0 @@
|
|||
/* NAT for netfilter; shared with compatibility layer. */
|
||||
|
||||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/icmp.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/tcp.h> /* For tcp_prot in getorigdst */
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/jhash.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
DEFINE_RWLOCK(ip_nat_lock);
|
||||
|
||||
/* Calculated at init based on memory size */
|
||||
static unsigned int ip_nat_htable_size;
|
||||
|
||||
static struct list_head *bysource;
|
||||
|
||||
#define MAX_IP_NAT_PROTO 256
|
||||
static struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];
|
||||
|
||||
static inline struct ip_nat_protocol *
|
||||
__ip_nat_proto_find(u_int8_t protonum)
|
||||
{
|
||||
return rcu_dereference(ip_nat_protos[protonum]);
|
||||
}
|
||||
|
||||
struct ip_nat_protocol *
|
||||
ip_nat_proto_find_get(u_int8_t protonum)
|
||||
{
|
||||
struct ip_nat_protocol *p;
|
||||
|
||||
rcu_read_lock();
|
||||
p = __ip_nat_proto_find(protonum);
|
||||
if (!try_module_get(p->me))
|
||||
p = &ip_nat_unknown_protocol;
|
||||
rcu_read_unlock();
|
||||
|
||||
return p;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_nat_proto_find_get);
|
||||
|
||||
void
|
||||
ip_nat_proto_put(struct ip_nat_protocol *p)
|
||||
{
|
||||
module_put(p->me);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_nat_proto_put);
|
||||
|
||||
/* We keep an extra hash for each conntrack, for fast searching. */
|
||||
static inline unsigned int
|
||||
hash_by_src(const struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
/* Original src, to ensure we map it consistently if poss. */
|
||||
return jhash_3words((__force u32)tuple->src.ip, tuple->src.u.all,
|
||||
tuple->dst.protonum, 0) % ip_nat_htable_size;
|
||||
}
|
||||
|
||||
/* Noone using conntrack by the time this called. */
|
||||
static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
|
||||
{
|
||||
if (!(conn->status & IPS_NAT_DONE_MASK))
|
||||
return;
|
||||
|
||||
write_lock_bh(&ip_nat_lock);
|
||||
list_del(&conn->nat.info.bysource);
|
||||
write_unlock_bh(&ip_nat_lock);
|
||||
}
|
||||
|
||||
/* Is this tuple already taken? (not by us) */
|
||||
int
|
||||
ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack *ignored_conntrack)
|
||||
{
|
||||
/* Conntrack tracking doesn't keep track of outgoing tuples; only
|
||||
incoming ones. NAT means they don't have a fixed mapping,
|
||||
so we invert the tuple and look for the incoming reply.
|
||||
|
||||
We could keep a separate hash if this proves too slow. */
|
||||
struct ip_conntrack_tuple reply;
|
||||
|
||||
invert_tuplepr(&reply, tuple);
|
||||
return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
|
||||
}
|
||||
EXPORT_SYMBOL(ip_nat_used_tuple);
|
||||
|
||||
/* If we source map this tuple so reply looks like reply_tuple, will
|
||||
* that meet the constraints of range. */
|
||||
static int
|
||||
in_range(const struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_nat_range *range)
|
||||
{
|
||||
struct ip_nat_protocol *proto;
|
||||
int ret = 0;
|
||||
|
||||
/* If we are supposed to map IPs, then we must be in the
|
||||
range specified, otherwise let this drag us onto a new src IP. */
|
||||
if (range->flags & IP_NAT_RANGE_MAP_IPS) {
|
||||
if (ntohl(tuple->src.ip) < ntohl(range->min_ip)
|
||||
|| ntohl(tuple->src.ip) > ntohl(range->max_ip))
|
||||
return 0;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
proto = __ip_nat_proto_find(tuple->dst.protonum);
|
||||
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
|
||||
|| proto->in_range(tuple, IP_NAT_MANIP_SRC,
|
||||
&range->min, &range->max))
|
||||
ret = 1;
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
same_src(const struct ip_conntrack *ct,
|
||||
const struct ip_conntrack_tuple *tuple)
|
||||
{
|
||||
return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
|
||||
== tuple->dst.protonum
|
||||
&& ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip
|
||||
== tuple->src.ip
|
||||
&& ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all
|
||||
== tuple->src.u.all);
|
||||
}
|
||||
|
||||
/* Only called for SRC manip */
|
||||
static int
|
||||
find_appropriate_src(const struct ip_conntrack_tuple *tuple,
|
||||
struct ip_conntrack_tuple *result,
|
||||
const struct ip_nat_range *range)
|
||||
{
|
||||
unsigned int h = hash_by_src(tuple);
|
||||
struct ip_conntrack *ct;
|
||||
|
||||
read_lock_bh(&ip_nat_lock);
|
||||
list_for_each_entry(ct, &bysource[h], nat.info.bysource) {
|
||||
if (same_src(ct, tuple)) {
|
||||
/* Copy source part from reply tuple. */
|
||||
invert_tuplepr(result,
|
||||
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
|
||||
result->dst = tuple->dst;
|
||||
|
||||
if (in_range(result, range)) {
|
||||
read_unlock_bh(&ip_nat_lock);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&ip_nat_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For [FUTURE] fragmentation handling, we want the least-used
|
||||
src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
|
||||
if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
|
||||
1-65535, we don't do pro-rata allocation based on ports; we choose
|
||||
the ip with the lowest src-ip/dst-ip/proto usage.
|
||||
*/
|
||||
static void
|
||||
find_best_ips_proto(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_nat_range *range,
|
||||
const struct ip_conntrack *conntrack,
|
||||
enum ip_nat_manip_type maniptype)
|
||||
{
|
||||
__be32 *var_ipp;
|
||||
/* Host order */
|
||||
u_int32_t minip, maxip, j;
|
||||
|
||||
/* No IP mapping? Do nothing. */
|
||||
if (!(range->flags & IP_NAT_RANGE_MAP_IPS))
|
||||
return;
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC)
|
||||
var_ipp = &tuple->src.ip;
|
||||
else
|
||||
var_ipp = &tuple->dst.ip;
|
||||
|
||||
/* Fast path: only one choice. */
|
||||
if (range->min_ip == range->max_ip) {
|
||||
*var_ipp = range->min_ip;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Hashing source and destination IPs gives a fairly even
|
||||
* spread in practice (if there are a small number of IPs
|
||||
* involved, there usually aren't that many connections
|
||||
* anyway). The consistency means that servers see the same
|
||||
* client coming from the same IP (some Internet Banking sites
|
||||
* like this), even across reboots. */
|
||||
minip = ntohl(range->min_ip);
|
||||
maxip = ntohl(range->max_ip);
|
||||
j = jhash_2words((__force u32)tuple->src.ip, (__force u32)tuple->dst.ip, 0);
|
||||
*var_ipp = htonl(minip + j % (maxip - minip + 1));
|
||||
}
|
||||
|
||||
/* Manipulate the tuple into the range given. For NF_IP_POST_ROUTING,
|
||||
* we change the source to map into the range. For NF_IP_PRE_ROUTING
|
||||
* and NF_IP_LOCAL_OUT, we change the destination to map into the
|
||||
* range. It might not be possible to get a unique tuple, but we try.
|
||||
* At worst (or if we race), we will end up with a final duplicate in
|
||||
* __ip_conntrack_confirm and drop the packet. */
|
||||
static void
|
||||
get_unique_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_conntrack_tuple *orig_tuple,
|
||||
const struct ip_nat_range *range,
|
||||
struct ip_conntrack *conntrack,
|
||||
enum ip_nat_manip_type maniptype)
|
||||
{
|
||||
struct ip_nat_protocol *proto;
|
||||
|
||||
/* 1) If this srcip/proto/src-proto-part is currently mapped,
|
||||
and that same mapping gives a unique tuple within the given
|
||||
range, use that.
|
||||
|
||||
This is only required for source (ie. NAT/masq) mappings.
|
||||
So far, we don't do local source mappings, so multiple
|
||||
manips not an issue. */
|
||||
if (maniptype == IP_NAT_MANIP_SRC) {
|
||||
if (find_appropriate_src(orig_tuple, tuple, range)) {
|
||||
DEBUGP("get_unique_tuple: Found current src map\n");
|
||||
if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
|
||||
if (!ip_nat_used_tuple(tuple, conntrack))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 2) Select the least-used IP/proto combination in the given
|
||||
range. */
|
||||
*tuple = *orig_tuple;
|
||||
find_best_ips_proto(tuple, range, conntrack, maniptype);
|
||||
|
||||
/* 3) The per-protocol part of the manip is made to map into
|
||||
the range to make a unique tuple. */
|
||||
|
||||
rcu_read_lock();
|
||||
proto = __ip_nat_proto_find(orig_tuple->dst.protonum);
|
||||
|
||||
/* Change protocol info to have some randomization */
|
||||
if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) {
|
||||
proto->unique_tuple(tuple, range, maniptype, conntrack);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Only bother mapping if it's not already in range and unique */
|
||||
if ((!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)
|
||||
|| proto->in_range(tuple, maniptype, &range->min, &range->max))
|
||||
&& !ip_nat_used_tuple(tuple, conntrack))
|
||||
goto out;
|
||||
|
||||
/* Last change: get protocol to try to obtain unique tuple. */
|
||||
proto->unique_tuple(tuple, range, maniptype, conntrack);
|
||||
out:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ip_nat_setup_info(struct ip_conntrack *conntrack,
|
||||
const struct ip_nat_range *range,
|
||||
unsigned int hooknum)
|
||||
{
|
||||
struct ip_conntrack_tuple curr_tuple, new_tuple;
|
||||
struct ip_nat_info *info = &conntrack->nat.info;
|
||||
int have_to_hash = !(conntrack->status & IPS_NAT_DONE_MASK);
|
||||
enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
|
||||
|
||||
IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
|
||||
|| hooknum == NF_IP_POST_ROUTING
|
||||
|| hooknum == NF_IP_LOCAL_IN
|
||||
|| hooknum == NF_IP_LOCAL_OUT);
|
||||
BUG_ON(ip_nat_initialized(conntrack, maniptype));
|
||||
|
||||
/* What we've got will look like inverse of reply. Normally
|
||||
this is what is in the conntrack, except for prior
|
||||
manipulations (future optimization: if num_manips == 0,
|
||||
orig_tp =
|
||||
conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
|
||||
invert_tuplepr(&curr_tuple,
|
||||
&conntrack->tuplehash[IP_CT_DIR_REPLY].tuple);
|
||||
|
||||
get_unique_tuple(&new_tuple, &curr_tuple, range, conntrack, maniptype);
|
||||
|
||||
if (!ip_ct_tuple_equal(&new_tuple, &curr_tuple)) {
|
||||
struct ip_conntrack_tuple reply;
|
||||
|
||||
/* Alter conntrack table so will recognize replies. */
|
||||
invert_tuplepr(&reply, &new_tuple);
|
||||
ip_conntrack_alter_reply(conntrack, &reply);
|
||||
|
||||
/* Non-atomic: we own this at the moment. */
|
||||
if (maniptype == IP_NAT_MANIP_SRC)
|
||||
conntrack->status |= IPS_SRC_NAT;
|
||||
else
|
||||
conntrack->status |= IPS_DST_NAT;
|
||||
}
|
||||
|
||||
/* Place in source hash if this is the first time. */
|
||||
if (have_to_hash) {
|
||||
unsigned int srchash
|
||||
= hash_by_src(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
|
||||
.tuple);
|
||||
write_lock_bh(&ip_nat_lock);
|
||||
list_add(&info->bysource, &bysource[srchash]);
|
||||
write_unlock_bh(&ip_nat_lock);
|
||||
}
|
||||
|
||||
/* It's done. */
|
||||
if (maniptype == IP_NAT_MANIP_DST)
|
||||
set_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status);
|
||||
else
|
||||
set_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status);
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
EXPORT_SYMBOL(ip_nat_setup_info);
|
||||
|
||||
/* Returns true if succeeded. */
|
||||
static int
|
||||
manip_pkt(u_int16_t proto,
|
||||
struct sk_buff **pskb,
|
||||
unsigned int iphdroff,
|
||||
const struct ip_conntrack_tuple *target,
|
||||
enum ip_nat_manip_type maniptype)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct ip_nat_protocol *p;
|
||||
|
||||
if (!skb_make_writable(pskb, iphdroff + sizeof(*iph)))
|
||||
return 0;
|
||||
|
||||
iph = (void *)(*pskb)->data + iphdroff;
|
||||
|
||||
/* Manipulate protcol part. */
|
||||
|
||||
/* rcu_read_lock()ed by nf_hook_slow */
|
||||
p = __ip_nat_proto_find(proto);
|
||||
if (!p->manip_pkt(pskb, iphdroff, target, maniptype))
|
||||
return 0;
|
||||
|
||||
iph = (void *)(*pskb)->data + iphdroff;
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC) {
|
||||
nf_csum_replace4(&iph->check, iph->saddr, target->src.ip);
|
||||
iph->saddr = target->src.ip;
|
||||
} else {
|
||||
nf_csum_replace4(&iph->check, iph->daddr, target->dst.ip);
|
||||
iph->daddr = target->dst.ip;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Do packet manipulations according to ip_nat_setup_info. */
|
||||
unsigned int ip_nat_packet(struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int hooknum,
|
||||
struct sk_buff **pskb)
|
||||
{
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
unsigned long statusbit;
|
||||
enum ip_nat_manip_type mtype = HOOK2MANIP(hooknum);
|
||||
|
||||
if (mtype == IP_NAT_MANIP_SRC)
|
||||
statusbit = IPS_SRC_NAT;
|
||||
else
|
||||
statusbit = IPS_DST_NAT;
|
||||
|
||||
/* Invert if this is reply dir. */
|
||||
if (dir == IP_CT_DIR_REPLY)
|
||||
statusbit ^= IPS_NAT_MASK;
|
||||
|
||||
/* Non-atomic: these bits don't change. */
|
||||
if (ct->status & statusbit) {
|
||||
struct ip_conntrack_tuple target;
|
||||
|
||||
/* We are aiming to look like inverse of other direction. */
|
||||
invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
|
||||
|
||||
if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
|
||||
return NF_DROP;
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_nat_packet);
|
||||
|
||||
/* Dir is direction ICMP is coming from (opposite to packet it contains) */
|
||||
int ip_nat_icmp_reply_translation(struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int hooknum,
|
||||
struct sk_buff **pskb)
|
||||
{
|
||||
struct {
|
||||
struct icmphdr icmp;
|
||||
struct iphdr ip;
|
||||
} *inside;
|
||||
struct ip_conntrack_protocol *proto;
|
||||
struct ip_conntrack_tuple inner, target;
|
||||
int hdrlen = ip_hdrlen(*pskb);
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
unsigned long statusbit;
|
||||
enum ip_nat_manip_type manip = HOOK2MANIP(hooknum);
|
||||
|
||||
if (!skb_make_writable(pskb, hdrlen + sizeof(*inside)))
|
||||
return 0;
|
||||
|
||||
inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
|
||||
|
||||
/* We're actually going to mangle it beyond trivial checksum
|
||||
adjustment, so make sure the current checksum is correct. */
|
||||
if (nf_ip_checksum(*pskb, hooknum, hdrlen, 0))
|
||||
return 0;
|
||||
|
||||
/* Must be RELATED */
|
||||
IP_NF_ASSERT((*pskb)->nfctinfo == IP_CT_RELATED ||
|
||||
(*pskb)->nfctinfo == IP_CT_RELATED+IP_CT_IS_REPLY);
|
||||
|
||||
/* Redirects on non-null nats must be dropped, else they'll
|
||||
start talking to each other without our translation, and be
|
||||
confused... --RR */
|
||||
if (inside->icmp.type == ICMP_REDIRECT) {
|
||||
/* If NAT isn't finished, assume it and drop. */
|
||||
if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
|
||||
return 0;
|
||||
|
||||
if (ct->status & IPS_NAT_MASK)
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n",
|
||||
*pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
|
||||
|
||||
/* rcu_read_lock()ed by nf_hook_slow */
|
||||
proto = __ip_conntrack_proto_find(inside->ip.protocol);
|
||||
if (!ip_ct_get_tuple(&inside->ip, *pskb, ip_hdrlen(*pskb) +
|
||||
sizeof(struct icmphdr) + inside->ip.ihl*4,
|
||||
&inner, proto))
|
||||
return 0;
|
||||
|
||||
/* Change inner back to look like incoming packet. We do the
|
||||
opposite manip on this hook to normal, because it might not
|
||||
pass all hooks (locally-generated ICMP). Consider incoming
|
||||
packet: PREROUTING (DST manip), routing produces ICMP, goes
|
||||
through POSTROUTING (which must correct the DST manip). */
|
||||
if (!manip_pkt(inside->ip.protocol, pskb,
|
||||
ip_hdrlen(*pskb) + sizeof(inside->icmp),
|
||||
&ct->tuplehash[!dir].tuple,
|
||||
!manip))
|
||||
return 0;
|
||||
|
||||
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
|
||||
/* Reloading "inside" here since manip_pkt inner. */
|
||||
inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
|
||||
inside->icmp.checksum = 0;
|
||||
inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
|
||||
(*pskb)->len - hdrlen,
|
||||
0));
|
||||
}
|
||||
|
||||
/* Change outer to look the reply to an incoming packet
|
||||
* (proto 0 means don't invert per-proto part). */
|
||||
if (manip == IP_NAT_MANIP_SRC)
|
||||
statusbit = IPS_SRC_NAT;
|
||||
else
|
||||
statusbit = IPS_DST_NAT;
|
||||
|
||||
/* Invert if this is reply dir. */
|
||||
if (dir == IP_CT_DIR_REPLY)
|
||||
statusbit ^= IPS_NAT_MASK;
|
||||
|
||||
if (ct->status & statusbit) {
|
||||
invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
|
||||
if (!manip_pkt(0, pskb, 0, &target, manip))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_nat_icmp_reply_translation);
|
||||
|
||||
/* Protocol registration. */
|
||||
int ip_nat_protocol_register(struct ip_nat_protocol *proto)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
write_lock_bh(&ip_nat_lock);
|
||||
if (ip_nat_protos[proto->protonum] != &ip_nat_unknown_protocol) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
rcu_assign_pointer(ip_nat_protos[proto->protonum], proto);
|
||||
out:
|
||||
write_unlock_bh(&ip_nat_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ip_nat_protocol_register);
|
||||
|
||||
/* Noone stores the protocol anywhere; simply delete it. */
|
||||
void ip_nat_protocol_unregister(struct ip_nat_protocol *proto)
|
||||
{
|
||||
write_lock_bh(&ip_nat_lock);
|
||||
rcu_assign_pointer(ip_nat_protos[proto->protonum],
|
||||
&ip_nat_unknown_protocol);
|
||||
write_unlock_bh(&ip_nat_lock);
|
||||
synchronize_rcu();
|
||||
}
|
||||
EXPORT_SYMBOL(ip_nat_protocol_unregister);
|
||||
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
int
|
||||
ip_nat_port_range_to_nfattr(struct sk_buff *skb,
|
||||
const struct ip_nat_range *range)
|
||||
{
|
||||
NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16),
|
||||
&range->min.tcp.port);
|
||||
NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16),
|
||||
&range->max.tcp.port);
|
||||
|
||||
return 0;
|
||||
|
||||
nfattr_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* we have to return whether we actually parsed something or not */
|
||||
|
||||
if (tb[CTA_PROTONAT_PORT_MIN-1]) {
|
||||
ret = 1;
|
||||
range->min.tcp.port =
|
||||
*(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
|
||||
}
|
||||
|
||||
if (!tb[CTA_PROTONAT_PORT_MAX-1]) {
|
||||
if (ret)
|
||||
range->max.tcp.port = range->min.tcp.port;
|
||||
} else {
|
||||
ret = 1;
|
||||
range->max.tcp.port =
|
||||
*(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_nat_port_nfattr_to_range);
|
||||
EXPORT_SYMBOL_GPL(ip_nat_port_range_to_nfattr);
|
||||
#endif
|
||||
|
||||
static int __init ip_nat_init(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* Leave them the same for the moment. */
|
||||
ip_nat_htable_size = ip_conntrack_htable_size;
|
||||
|
||||
/* One vmalloc for both hash tables */
|
||||
bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size);
|
||||
if (!bysource)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Sew in builtin protocols. */
|
||||
write_lock_bh(&ip_nat_lock);
|
||||
for (i = 0; i < MAX_IP_NAT_PROTO; i++)
|
||||
rcu_assign_pointer(ip_nat_protos[i], &ip_nat_unknown_protocol);
|
||||
rcu_assign_pointer(ip_nat_protos[IPPROTO_TCP], &ip_nat_protocol_tcp);
|
||||
rcu_assign_pointer(ip_nat_protos[IPPROTO_UDP], &ip_nat_protocol_udp);
|
||||
rcu_assign_pointer(ip_nat_protos[IPPROTO_ICMP], &ip_nat_protocol_icmp);
|
||||
write_unlock_bh(&ip_nat_lock);
|
||||
|
||||
for (i = 0; i < ip_nat_htable_size; i++) {
|
||||
INIT_LIST_HEAD(&bysource[i]);
|
||||
}
|
||||
|
||||
/* FIXME: Man, this is a hack. <SIGH> */
|
||||
IP_NF_ASSERT(rcu_dereference(ip_conntrack_destroyed) == NULL);
|
||||
rcu_assign_pointer(ip_conntrack_destroyed, ip_nat_cleanup_conntrack);
|
||||
|
||||
/* Initialize fake conntrack so that NAT will skip it */
|
||||
ip_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clear NAT section of all conntracks, in case we're loaded again. */
|
||||
static int clean_nat(struct ip_conntrack *i, void *data)
|
||||
{
|
||||
memset(&i->nat, 0, sizeof(i->nat));
|
||||
i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ip_nat_cleanup(void)
|
||||
{
|
||||
ip_ct_iterate_cleanup(&clean_nat, NULL);
|
||||
rcu_assign_pointer(ip_conntrack_destroyed, NULL);
|
||||
synchronize_rcu();
|
||||
vfree(bysource);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(ip_nat_init);
|
||||
module_exit(ip_nat_cleanup);
|
|
@ -1,180 +0,0 @@
|
|||
/* FTP extension for TCP NAT alteration. */
|
||||
|
||||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <net/tcp.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
|
||||
MODULE_DESCRIPTION("ftp NAT helper");
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
/* FIXME: Time out? --RR */
|
||||
|
||||
static int
|
||||
mangle_rfc959_packet(struct sk_buff **pskb,
|
||||
__be32 newip,
|
||||
u_int16_t port,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
u32 *seq)
|
||||
{
|
||||
char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")];
|
||||
|
||||
sprintf(buffer, "%u,%u,%u,%u,%u,%u",
|
||||
NIPQUAD(newip), port>>8, port&0xFF);
|
||||
|
||||
DEBUGP("calling ip_nat_mangle_tcp_packet\n");
|
||||
|
||||
*seq += strlen(buffer) - matchlen;
|
||||
return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
|
||||
matchlen, buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
/* |1|132.235.1.2|6275| */
|
||||
static int
|
||||
mangle_eprt_packet(struct sk_buff **pskb,
|
||||
__be32 newip,
|
||||
u_int16_t port,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
u32 *seq)
|
||||
{
|
||||
char buffer[sizeof("|1|255.255.255.255|65535|")];
|
||||
|
||||
sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);
|
||||
|
||||
DEBUGP("calling ip_nat_mangle_tcp_packet\n");
|
||||
|
||||
*seq += strlen(buffer) - matchlen;
|
||||
return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
|
||||
matchlen, buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
/* |1|132.235.1.2|6275| */
|
||||
static int
|
||||
mangle_epsv_packet(struct sk_buff **pskb,
|
||||
__be32 newip,
|
||||
u_int16_t port,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
u32 *seq)
|
||||
{
|
||||
char buffer[sizeof("|||65535|")];
|
||||
|
||||
sprintf(buffer, "|||%u|", port);
|
||||
|
||||
DEBUGP("calling ip_nat_mangle_tcp_packet\n");
|
||||
|
||||
*seq += strlen(buffer) - matchlen;
|
||||
return ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
|
||||
matchlen, buffer, strlen(buffer));
|
||||
}
|
||||
|
||||
static int (*mangle[])(struct sk_buff **, __be32, u_int16_t,
|
||||
unsigned int,
|
||||
unsigned int,
|
||||
struct ip_conntrack *,
|
||||
enum ip_conntrack_info,
|
||||
u32 *seq)
|
||||
= { [IP_CT_FTP_PORT] = mangle_rfc959_packet,
|
||||
[IP_CT_FTP_PASV] = mangle_rfc959_packet,
|
||||
[IP_CT_FTP_EPRT] = mangle_eprt_packet,
|
||||
[IP_CT_FTP_EPSV] = mangle_epsv_packet
|
||||
};
|
||||
|
||||
/* So, this packet has hit the connection tracking matching code.
|
||||
Mangle it, and change the expectation to match the new version. */
|
||||
static unsigned int ip_nat_ftp(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)
|
||||
{
|
||||
__be32 newip;
|
||||
u_int16_t port;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
struct ip_conntrack *ct = exp->master;
|
||||
|
||||
DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);
|
||||
|
||||
/* Connection will come from wherever this packet goes, hence !dir */
|
||||
newip = ct->tuplehash[!dir].tuple.dst.ip;
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* When you see the packet, we need to NAT it the same as the
|
||||
* this one. */
|
||||
exp->expectfn = ip_nat_follow_master;
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(port);
|
||||
if (ip_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
return NF_DROP;
|
||||
|
||||
if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo,
|
||||
seq)) {
|
||||
ip_conntrack_unexpect_related(exp);
|
||||
return NF_DROP;
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static void __exit ip_nat_ftp_fini(void)
|
||||
{
|
||||
rcu_assign_pointer(ip_nat_ftp_hook, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static int __init ip_nat_ftp_init(void)
|
||||
{
|
||||
BUG_ON(rcu_dereference(ip_nat_ftp_hook));
|
||||
rcu_assign_pointer(ip_nat_ftp_hook, ip_nat_ftp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */
|
||||
static int warn_set(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
printk(KERN_INFO KBUILD_MODNAME
|
||||
": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
|
||||
return 0;
|
||||
}
|
||||
module_param_call(ports, warn_set, NULL, NULL, 0);
|
||||
|
||||
module_init(ip_nat_ftp_init);
|
||||
module_exit(ip_nat_ftp_fini);
|
|
@ -1,436 +0,0 @@
|
|||
/* ip_nat_helper.c - generic support functions for NAT helpers
|
||||
*
|
||||
* (C) 2000-2002 Harald Welte <laforge@netfilter.org>
|
||||
* (C) 2003-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.
|
||||
*
|
||||
* 14 Jan 2002 Harald Welte <laforge@gnumonks.org>:
|
||||
* - add support for SACK adjustment
|
||||
* 14 Mar 2002 Harald Welte <laforge@gnumonks.org>:
|
||||
* - merge SACK support into newnat API
|
||||
* 16 Aug 2002 Brian J. Murrell <netfilter@interlinx.bc.ca>:
|
||||
* - make ip_nat_resize_packet more generic (TCP and UDP)
|
||||
* - add ip_nat_mangle_udp_packet
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/icmp.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/udp.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos);
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#define DUMP_OFFSET(x)
|
||||
#endif
|
||||
|
||||
static DEFINE_SPINLOCK(ip_nat_seqofs_lock);
|
||||
|
||||
/* Setup TCP sequence correction given this change at this sequence */
|
||||
static inline void
|
||||
adjust_tcp_sequence(u32 seq,
|
||||
int sizediff,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
int dir;
|
||||
struct ip_nat_seq *this_way, *other_way;
|
||||
|
||||
DEBUGP("ip_nat_resize_packet: old_size = %u, new_size = %u\n",
|
||||
(*skb)->len, new_size);
|
||||
|
||||
dir = CTINFO2DIR(ctinfo);
|
||||
|
||||
this_way = &ct->nat.info.seq[dir];
|
||||
other_way = &ct->nat.info.seq[!dir];
|
||||
|
||||
DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
|
||||
DUMP_OFFSET(this_way);
|
||||
|
||||
spin_lock_bh(&ip_nat_seqofs_lock);
|
||||
|
||||
/* SYN adjust. If it's uninitialized, or this is after last
|
||||
* correction, record it: we don't handle more than one
|
||||
* adjustment in the window, but do deal with common case of a
|
||||
* retransmit */
|
||||
if (this_way->offset_before == this_way->offset_after
|
||||
|| before(this_way->correction_pos, seq)) {
|
||||
this_way->correction_pos = seq;
|
||||
this_way->offset_before = this_way->offset_after;
|
||||
this_way->offset_after += sizediff;
|
||||
}
|
||||
spin_unlock_bh(&ip_nat_seqofs_lock);
|
||||
|
||||
DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
|
||||
DUMP_OFFSET(this_way);
|
||||
}
|
||||
|
||||
/* Frobs data inside this packet, which is linear. */
|
||||
static void mangle_contents(struct sk_buff *skb,
|
||||
unsigned int dataoff,
|
||||
unsigned int match_offset,
|
||||
unsigned int match_len,
|
||||
const char *rep_buffer,
|
||||
unsigned int rep_len)
|
||||
{
|
||||
unsigned char *data;
|
||||
|
||||
BUG_ON(skb_is_nonlinear(skb));
|
||||
data = skb_network_header(skb) + dataoff;
|
||||
|
||||
/* move post-replacement */
|
||||
memmove(data + match_offset + rep_len,
|
||||
data + match_offset + match_len,
|
||||
skb->tail - (data + match_offset + match_len));
|
||||
|
||||
/* insert data from buffer */
|
||||
memcpy(data + match_offset, rep_buffer, rep_len);
|
||||
|
||||
/* update skb info */
|
||||
if (rep_len > match_len) {
|
||||
DEBUGP("ip_nat_mangle_packet: Extending packet by "
|
||||
"%u from %u bytes\n", rep_len - match_len,
|
||||
skb->len);
|
||||
skb_put(skb, rep_len - match_len);
|
||||
} else {
|
||||
DEBUGP("ip_nat_mangle_packet: Shrinking packet from "
|
||||
"%u from %u bytes\n", match_len - rep_len,
|
||||
skb->len);
|
||||
__skb_trim(skb, skb->len + rep_len - match_len);
|
||||
}
|
||||
|
||||
/* fix IP hdr checksum information */
|
||||
ip_hdr(skb)->tot_len = htons(skb->len);
|
||||
ip_send_check(ip_hdr(skb));
|
||||
}
|
||||
|
||||
/* Unusual, but possible case. */
|
||||
static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
|
||||
{
|
||||
struct sk_buff *nskb;
|
||||
|
||||
if ((*pskb)->len + extra > 65535)
|
||||
return 0;
|
||||
|
||||
nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC);
|
||||
if (!nskb)
|
||||
return 0;
|
||||
|
||||
/* Transfer socket to new skb. */
|
||||
if ((*pskb)->sk)
|
||||
skb_set_owner_w(nskb, (*pskb)->sk);
|
||||
kfree_skb(*pskb);
|
||||
*pskb = nskb;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generic function for mangling variable-length address changes inside
|
||||
* NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
|
||||
* command in FTP).
|
||||
*
|
||||
* Takes care about all the nasty sequence number changes, checksumming,
|
||||
* skb enlargement, ...
|
||||
*
|
||||
* */
|
||||
int
|
||||
ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int match_offset,
|
||||
unsigned int match_len,
|
||||
const char *rep_buffer,
|
||||
unsigned int rep_len)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct tcphdr *tcph;
|
||||
int oldlen, datalen;
|
||||
|
||||
if (!skb_make_writable(pskb, (*pskb)->len))
|
||||
return 0;
|
||||
|
||||
if (rep_len > match_len
|
||||
&& rep_len - match_len > skb_tailroom(*pskb)
|
||||
&& !enlarge_skb(pskb, rep_len - match_len))
|
||||
return 0;
|
||||
|
||||
SKB_LINEAR_ASSERT(*pskb);
|
||||
|
||||
iph = ip_hdr(*pskb);
|
||||
tcph = (void *)iph + iph->ihl*4;
|
||||
|
||||
oldlen = (*pskb)->len - iph->ihl*4;
|
||||
mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
|
||||
match_offset, match_len, rep_buffer, rep_len);
|
||||
|
||||
datalen = (*pskb)->len - iph->ihl*4;
|
||||
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
|
||||
tcph->check = 0;
|
||||
tcph->check = tcp_v4_check(datalen,
|
||||
iph->saddr, iph->daddr,
|
||||
csum_partial((char *)tcph,
|
||||
datalen, 0));
|
||||
} else
|
||||
nf_proto_csum_replace2(&tcph->check, *pskb,
|
||||
htons(oldlen), htons(datalen), 1);
|
||||
|
||||
if (rep_len != match_len) {
|
||||
set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
|
||||
adjust_tcp_sequence(ntohl(tcph->seq),
|
||||
(int)rep_len - (int)match_len,
|
||||
ct, ctinfo);
|
||||
/* Tell TCP window tracking about seq change */
|
||||
ip_conntrack_tcp_update(*pskb, ct, CTINFO2DIR(ctinfo));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(ip_nat_mangle_tcp_packet);
|
||||
|
||||
/* Generic function for mangling variable-length address changes inside
|
||||
* NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
|
||||
* command in the Amanda protocol)
|
||||
*
|
||||
* Takes care about all the nasty sequence number changes, checksumming,
|
||||
* skb enlargement, ...
|
||||
*
|
||||
* XXX - This function could be merged with ip_nat_mangle_tcp_packet which
|
||||
* should be fairly easy to do.
|
||||
*/
|
||||
int
|
||||
ip_nat_mangle_udp_packet(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int match_offset,
|
||||
unsigned int match_len,
|
||||
const char *rep_buffer,
|
||||
unsigned int rep_len)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
struct udphdr *udph;
|
||||
int datalen, oldlen;
|
||||
|
||||
/* UDP helpers might accidentally mangle the wrong packet */
|
||||
iph = ip_hdr(*pskb);
|
||||
if ((*pskb)->len < iph->ihl*4 + sizeof(*udph) +
|
||||
match_offset + match_len)
|
||||
return 0;
|
||||
|
||||
if (!skb_make_writable(pskb, (*pskb)->len))
|
||||
return 0;
|
||||
|
||||
if (rep_len > match_len
|
||||
&& rep_len - match_len > skb_tailroom(*pskb)
|
||||
&& !enlarge_skb(pskb, rep_len - match_len))
|
||||
return 0;
|
||||
|
||||
iph = ip_hdr(*pskb);
|
||||
udph = (void *)iph + iph->ihl*4;
|
||||
|
||||
oldlen = (*pskb)->len - iph->ihl*4;
|
||||
mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph),
|
||||
match_offset, match_len, rep_buffer, rep_len);
|
||||
|
||||
/* update the length of the UDP packet */
|
||||
datalen = (*pskb)->len - iph->ihl*4;
|
||||
udph->len = htons(datalen);
|
||||
|
||||
/* fix udp checksum if udp checksum was previously calculated */
|
||||
if (!udph->check && (*pskb)->ip_summed != CHECKSUM_PARTIAL)
|
||||
return 1;
|
||||
|
||||
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
|
||||
udph->check = 0;
|
||||
udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
|
||||
datalen, IPPROTO_UDP,
|
||||
csum_partial((char *)udph,
|
||||
datalen, 0));
|
||||
if (!udph->check)
|
||||
udph->check = CSUM_MANGLED_0;
|
||||
} else
|
||||
nf_proto_csum_replace2(&udph->check, *pskb,
|
||||
htons(oldlen), htons(datalen), 1);
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
|
||||
|
||||
/* Adjust one found SACK option including checksum correction */
|
||||
static void
|
||||
sack_adjust(struct sk_buff *skb,
|
||||
struct tcphdr *tcph,
|
||||
unsigned int sackoff,
|
||||
unsigned int sackend,
|
||||
struct ip_nat_seq *natseq)
|
||||
{
|
||||
while (sackoff < sackend) {
|
||||
struct tcp_sack_block_wire *sack;
|
||||
__be32 new_start_seq, new_end_seq;
|
||||
|
||||
sack = (void *)skb->data + sackoff;
|
||||
if (after(ntohl(sack->start_seq) - natseq->offset_before,
|
||||
natseq->correction_pos))
|
||||
new_start_seq = htonl(ntohl(sack->start_seq)
|
||||
- natseq->offset_after);
|
||||
else
|
||||
new_start_seq = htonl(ntohl(sack->start_seq)
|
||||
- natseq->offset_before);
|
||||
|
||||
if (after(ntohl(sack->end_seq) - natseq->offset_before,
|
||||
natseq->correction_pos))
|
||||
new_end_seq = htonl(ntohl(sack->end_seq)
|
||||
- natseq->offset_after);
|
||||
else
|
||||
new_end_seq = htonl(ntohl(sack->end_seq)
|
||||
- natseq->offset_before);
|
||||
|
||||
DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
|
||||
ntohl(sack->start_seq), new_start_seq,
|
||||
ntohl(sack->end_seq), new_end_seq);
|
||||
|
||||
nf_proto_csum_replace4(&tcph->check, skb,
|
||||
sack->start_seq, new_start_seq, 0);
|
||||
nf_proto_csum_replace4(&tcph->check, skb,
|
||||
sack->end_seq, new_end_seq, 0);
|
||||
sack->start_seq = new_start_seq;
|
||||
sack->end_seq = new_end_seq;
|
||||
sackoff += sizeof(*sack);
|
||||
}
|
||||
}
|
||||
|
||||
/* TCP SACK sequence number adjustment */
|
||||
static inline unsigned int
|
||||
ip_nat_sack_adjust(struct sk_buff **pskb,
|
||||
struct tcphdr *tcph,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
unsigned int dir, optoff, optend;
|
||||
|
||||
optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr);
|
||||
optend = ip_hdrlen(*pskb) + tcph->doff * 4;
|
||||
|
||||
if (!skb_make_writable(pskb, optend))
|
||||
return 0;
|
||||
|
||||
dir = CTINFO2DIR(ctinfo);
|
||||
|
||||
while (optoff < optend) {
|
||||
/* Usually: option, length. */
|
||||
unsigned char *op = (*pskb)->data + optoff;
|
||||
|
||||
switch (op[0]) {
|
||||
case TCPOPT_EOL:
|
||||
return 1;
|
||||
case TCPOPT_NOP:
|
||||
optoff++;
|
||||
continue;
|
||||
default:
|
||||
/* no partial options */
|
||||
if (optoff + 1 == optend
|
||||
|| optoff + op[1] > optend
|
||||
|| op[1] < 2)
|
||||
return 0;
|
||||
if (op[0] == TCPOPT_SACK
|
||||
&& op[1] >= 2+TCPOLEN_SACK_PERBLOCK
|
||||
&& ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
|
||||
sack_adjust(*pskb, tcph, optoff+2,
|
||||
optoff+op[1],
|
||||
&ct->nat.info.seq[!dir]);
|
||||
optoff += op[1];
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */
|
||||
int
|
||||
ip_nat_seq_adjust(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
struct tcphdr *tcph;
|
||||
int dir;
|
||||
__be32 newseq, newack;
|
||||
struct ip_nat_seq *this_way, *other_way;
|
||||
|
||||
dir = CTINFO2DIR(ctinfo);
|
||||
|
||||
this_way = &ct->nat.info.seq[dir];
|
||||
other_way = &ct->nat.info.seq[!dir];
|
||||
|
||||
if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
|
||||
return 0;
|
||||
|
||||
tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb);
|
||||
if (after(ntohl(tcph->seq), this_way->correction_pos))
|
||||
newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
|
||||
else
|
||||
newseq = htonl(ntohl(tcph->seq) + this_way->offset_before);
|
||||
|
||||
if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
|
||||
other_way->correction_pos))
|
||||
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after);
|
||||
else
|
||||
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
|
||||
|
||||
nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0);
|
||||
nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0);
|
||||
|
||||
DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n",
|
||||
ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
|
||||
ntohl(newack));
|
||||
|
||||
tcph->seq = newseq;
|
||||
tcph->ack_seq = newack;
|
||||
|
||||
if (!ip_nat_sack_adjust(pskb, tcph, ct, ctinfo))
|
||||
return 0;
|
||||
|
||||
ip_conntrack_tcp_update(*pskb, ct, dir);
|
||||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(ip_nat_seq_adjust);
|
||||
|
||||
/* Setup NAT on this expected conntrack so it follows master. */
|
||||
/* If we fail to get a free NAT slot, we'll get dropped on confirm */
|
||||
void ip_nat_follow_master(struct ip_conntrack *ct,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
struct ip_nat_range range;
|
||||
|
||||
/* This must be a fresh one. */
|
||||
BUG_ON(ct->status & IPS_NAT_DONE_MASK);
|
||||
|
||||
/* Change src to where master sends to */
|
||||
range.flags = IP_NAT_RANGE_MAP_IPS;
|
||||
range.min_ip = range.max_ip
|
||||
= ct->master->tuplehash[!exp->dir].tuple.dst.ip;
|
||||
/* hook doesn't matter, but it has to do source manip */
|
||||
ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
|
||||
|
||||
/* For DST manip, map port here to where it's expected. */
|
||||
range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
|
||||
range.min = range.max = exp->saved_proto;
|
||||
range.min_ip = range.max_ip
|
||||
= ct->master->tuplehash[!exp->dir].tuple.src.ip;
|
||||
/* hook doesn't matter, but it has to do destination manip */
|
||||
ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
|
||||
}
|
||||
EXPORT_SYMBOL(ip_nat_follow_master);
|
|
@ -1,611 +0,0 @@
|
|||
/*
|
||||
* H.323 extension for NAT alteration.
|
||||
*
|
||||
* Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
|
||||
*
|
||||
* This source code is licensed under General Public License version 2.
|
||||
*
|
||||
* Based on the 'brute force' H.323 NAT module by
|
||||
* Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <net/tcp.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_addr(struct sk_buff **pskb,
|
||||
unsigned char **data, int dataoff,
|
||||
unsigned int addroff, __be32 ip, u_int16_t port)
|
||||
{
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
struct {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
} __attribute__ ((__packed__)) buf;
|
||||
struct tcphdr _tcph, *th;
|
||||
|
||||
buf.ip = ip;
|
||||
buf.port = htons(port);
|
||||
addroff += dataoff;
|
||||
|
||||
if (ip_hdr(*pskb)->protocol == IPPROTO_TCP) {
|
||||
if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
|
||||
addroff, sizeof(buf),
|
||||
(char *) &buf, sizeof(buf))) {
|
||||
if (net_ratelimit())
|
||||
printk("ip_nat_h323: ip_nat_mangle_tcp_packet"
|
||||
" error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Relocate data pointer */
|
||||
th = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
|
||||
sizeof(_tcph), &_tcph);
|
||||
if (th == NULL)
|
||||
return -1;
|
||||
*data = (*pskb)->data + ip_hdrlen(*pskb) +
|
||||
th->doff * 4 + dataoff;
|
||||
} else {
|
||||
if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
|
||||
addroff, sizeof(buf),
|
||||
(char *) &buf, sizeof(buf))) {
|
||||
if (net_ratelimit())
|
||||
printk("ip_nat_h323: ip_nat_mangle_udp_packet"
|
||||
" error\n");
|
||||
return -1;
|
||||
}
|
||||
/* ip_nat_mangle_udp_packet uses skb_make_writable() to copy
|
||||
* or pull everything in a linear buffer, so we can safely
|
||||
* use the skb pointers now */
|
||||
*data = ((*pskb)->data + ip_hdrlen(*pskb) +
|
||||
sizeof(struct udphdr));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_h225_addr(struct sk_buff **pskb,
|
||||
unsigned char **data, int dataoff,
|
||||
TransportAddress * addr,
|
||||
__be32 ip, u_int16_t port)
|
||||
{
|
||||
return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_h245_addr(struct sk_buff **pskb,
|
||||
unsigned char **data, int dataoff,
|
||||
H245_TransportAddress * addr,
|
||||
__be32 ip, u_int16_t port)
|
||||
{
|
||||
return set_addr(pskb, data, dataoff,
|
||||
addr->unicastAddress.iPAddress.network, ip, port);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data,
|
||||
TransportAddress * addr, int count)
|
||||
{
|
||||
struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
int i;
|
||||
__be32 ip;
|
||||
u_int16_t port;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (get_h225_addr(*data, &addr[i], &ip, &port)) {
|
||||
if (ip == ct->tuplehash[dir].tuple.src.ip &&
|
||||
port == info->sig_port[dir]) {
|
||||
/* GW->GK */
|
||||
|
||||
/* Fix for Gnomemeeting */
|
||||
if (i > 0 &&
|
||||
get_h225_addr(*data, &addr[0],
|
||||
&ip, &port) &&
|
||||
(ntohl(ip) & 0xff000000) == 0x7f000000)
|
||||
i = 0;
|
||||
|
||||
DEBUGP
|
||||
("ip_nat_ras: set signal address "
|
||||
"%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(ip), port,
|
||||
NIPQUAD(ct->tuplehash[!dir].tuple.dst.
|
||||
ip), info->sig_port[!dir]);
|
||||
return set_h225_addr(pskb, data, 0, &addr[i],
|
||||
ct->tuplehash[!dir].
|
||||
tuple.dst.ip,
|
||||
info->sig_port[!dir]);
|
||||
} else if (ip == ct->tuplehash[dir].tuple.dst.ip &&
|
||||
port == info->sig_port[dir]) {
|
||||
/* GK->GW */
|
||||
DEBUGP
|
||||
("ip_nat_ras: set signal address "
|
||||
"%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(ip), port,
|
||||
NIPQUAD(ct->tuplehash[!dir].tuple.src.
|
||||
ip), info->sig_port[!dir]);
|
||||
return set_h225_addr(pskb, data, 0, &addr[i],
|
||||
ct->tuplehash[!dir].
|
||||
tuple.src.ip,
|
||||
info->sig_port[!dir]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data,
|
||||
TransportAddress * addr, int count)
|
||||
{
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
int i;
|
||||
__be32 ip;
|
||||
u_int16_t port;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (get_h225_addr(*data, &addr[i], &ip, &port) &&
|
||||
ip == ct->tuplehash[dir].tuple.src.ip &&
|
||||
port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port)) {
|
||||
DEBUGP("ip_nat_ras: set rasAddress "
|
||||
"%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(ip), port,
|
||||
NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
|
||||
ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
|
||||
port));
|
||||
return set_h225_addr(pskb, data, 0, &addr[i],
|
||||
ct->tuplehash[!dir].tuple.dst.ip,
|
||||
ntohs(ct->tuplehash[!dir].tuple.
|
||||
dst.u.udp.port));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
H245_TransportAddress * addr,
|
||||
u_int16_t port, u_int16_t rtp_port,
|
||||
struct ip_conntrack_expect *rtp_exp,
|
||||
struct ip_conntrack_expect *rtcp_exp)
|
||||
{
|
||||
struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
int i;
|
||||
u_int16_t nated_port;
|
||||
|
||||
/* Set expectations for NAT */
|
||||
rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
|
||||
rtp_exp->expectfn = ip_nat_follow_master;
|
||||
rtp_exp->dir = !dir;
|
||||
rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
|
||||
rtcp_exp->expectfn = ip_nat_follow_master;
|
||||
rtcp_exp->dir = !dir;
|
||||
|
||||
/* Lookup existing expects */
|
||||
for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
|
||||
if (info->rtp_port[i][dir] == rtp_port) {
|
||||
/* Expected */
|
||||
|
||||
/* Use allocated ports first. This will refresh
|
||||
* the expects */
|
||||
rtp_exp->tuple.dst.u.udp.port =
|
||||
htons(info->rtp_port[i][dir]);
|
||||
rtcp_exp->tuple.dst.u.udp.port =
|
||||
htons(info->rtp_port[i][dir] + 1);
|
||||
break;
|
||||
} else if (info->rtp_port[i][dir] == 0) {
|
||||
/* Not expected */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run out of expectations */
|
||||
if (i >= H323_RTP_CHANNEL_MAX) {
|
||||
if (net_ratelimit())
|
||||
printk("ip_nat_h323: out of expectations\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to get a pair of ports. */
|
||||
for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
|
||||
nated_port != 0; nated_port += 2) {
|
||||
rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
|
||||
if (ip_conntrack_expect_related(rtp_exp) == 0) {
|
||||
rtcp_exp->tuple.dst.u.udp.port =
|
||||
htons(nated_port + 1);
|
||||
if (ip_conntrack_expect_related(rtcp_exp) == 0)
|
||||
break;
|
||||
ip_conntrack_unexpect_related(rtp_exp);
|
||||
}
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("ip_nat_h323: out of RTP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (set_h245_addr(pskb, data, dataoff, addr,
|
||||
ct->tuplehash[!dir].tuple.dst.ip,
|
||||
(port & 1) ? nated_port + 1 : nated_port) == 0) {
|
||||
/* Save ports */
|
||||
info->rtp_port[i][dir] = rtp_port;
|
||||
info->rtp_port[i][!dir] = nated_port;
|
||||
} else {
|
||||
ip_conntrack_unexpect_related(rtp_exp);
|
||||
ip_conntrack_unexpect_related(rtcp_exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
DEBUGP("ip_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(rtp_exp->tuple.src.ip),
|
||||
ntohs(rtp_exp->tuple.src.u.udp.port),
|
||||
NIPQUAD(rtp_exp->tuple.dst.ip),
|
||||
ntohs(rtp_exp->tuple.dst.u.udp.port));
|
||||
DEBUGP("ip_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(rtcp_exp->tuple.src.ip),
|
||||
ntohs(rtcp_exp->tuple.src.u.udp.port),
|
||||
NIPQUAD(rtcp_exp->tuple.dst.ip),
|
||||
ntohs(rtcp_exp->tuple.dst.u.udp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_t120(struct sk_buff **pskb, struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
H245_TransportAddress * addr, u_int16_t port,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
u_int16_t nated_port = port;
|
||||
|
||||
/* Set expectations for NAT */
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->expectfn = ip_nat_follow_master;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (; nated_port != 0; nated_port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (ip_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("ip_nat_h323: out of TCP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (set_h245_addr(pskb, data, dataoff, addr,
|
||||
ct->tuplehash[!dir].tuple.dst.ip, nated_port) < 0) {
|
||||
ip_conntrack_unexpect_related(exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP("ip_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
|
||||
NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* This conntrack expect function replaces ip_conntrack_h245_expect()
|
||||
* which was set by ip_conntrack_helper_h323.c. It calls both
|
||||
* ip_nat_follow_master() and ip_conntrack_h245_expect()
|
||||
****************************************************************************/
|
||||
static void ip_nat_h245_expect(struct ip_conntrack *new,
|
||||
struct ip_conntrack_expect *this)
|
||||
{
|
||||
ip_nat_follow_master(new, this);
|
||||
ip_conntrack_h245_expect(new, this);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
TransportAddress * addr, u_int16_t port,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
u_int16_t nated_port = port;
|
||||
|
||||
/* Set expectations for NAT */
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->expectfn = ip_nat_h245_expect;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* Check existing expects */
|
||||
if (info->sig_port[dir] == port)
|
||||
nated_port = info->sig_port[!dir];
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (; nated_port != 0; nated_port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (ip_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("ip_nat_q931: out of TCP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (set_h225_addr(pskb, data, dataoff, addr,
|
||||
ct->tuplehash[!dir].tuple.dst.ip,
|
||||
nated_port) == 0) {
|
||||
/* Save ports */
|
||||
info->sig_port[dir] = port;
|
||||
info->sig_port[!dir] = nated_port;
|
||||
} else {
|
||||
ip_conntrack_unexpect_related(exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP("ip_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
|
||||
NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* This conntrack expect function replaces ip_conntrack_q931_expect()
|
||||
* which was set by ip_conntrack_helper_h323.c.
|
||||
****************************************************************************/
|
||||
static void ip_nat_q931_expect(struct ip_conntrack *new,
|
||||
struct ip_conntrack_expect *this)
|
||||
{
|
||||
struct ip_nat_range range;
|
||||
|
||||
if (this->tuple.src.ip != 0) { /* Only accept calls from GK */
|
||||
ip_nat_follow_master(new, this);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* This must be a fresh one. */
|
||||
BUG_ON(new->status & IPS_NAT_DONE_MASK);
|
||||
|
||||
/* Change src to where master sends to */
|
||||
range.flags = IP_NAT_RANGE_MAP_IPS;
|
||||
range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip;
|
||||
|
||||
/* hook doesn't matter, but it has to do source manip */
|
||||
ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
|
||||
|
||||
/* For DST manip, map port here to where it's expected. */
|
||||
range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
|
||||
range.min = range.max = this->saved_proto;
|
||||
range.min_ip = range.max_ip =
|
||||
new->master->tuplehash[!this->dir].tuple.src.ip;
|
||||
|
||||
/* hook doesn't matter, but it has to do destination manip */
|
||||
ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
|
||||
|
||||
out:
|
||||
ip_conntrack_q931_expect(new, this);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, TransportAddress * addr, int idx,
|
||||
u_int16_t port, struct ip_conntrack_expect *exp)
|
||||
{
|
||||
struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
u_int16_t nated_port = port;
|
||||
__be32 ip;
|
||||
|
||||
/* Set expectations for NAT */
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->expectfn = ip_nat_q931_expect;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* Check existing expects */
|
||||
if (info->sig_port[dir] == port)
|
||||
nated_port = info->sig_port[!dir];
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (; nated_port != 0; nated_port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (ip_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("ip_nat_ras: out of TCP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (set_h225_addr(pskb, data, 0, &addr[idx],
|
||||
ct->tuplehash[!dir].tuple.dst.ip,
|
||||
nated_port) == 0) {
|
||||
/* Save ports */
|
||||
info->sig_port[dir] = port;
|
||||
info->sig_port[!dir] = nated_port;
|
||||
|
||||
/* Fix for Gnomemeeting */
|
||||
if (idx > 0 &&
|
||||
get_h225_addr(*data, &addr[0], &ip, &port) &&
|
||||
(ntohl(ip) & 0xff000000) == 0x7f000000) {
|
||||
set_h225_addr_hook(pskb, data, 0, &addr[0],
|
||||
ct->tuplehash[!dir].tuple.dst.ip,
|
||||
info->sig_port[!dir]);
|
||||
}
|
||||
} else {
|
||||
ip_conntrack_unexpect_related(exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
DEBUGP("ip_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
|
||||
NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static void ip_nat_callforwarding_expect(struct ip_conntrack *new,
|
||||
struct ip_conntrack_expect *this)
|
||||
{
|
||||
struct ip_nat_range range;
|
||||
|
||||
/* This must be a fresh one. */
|
||||
BUG_ON(new->status & IPS_NAT_DONE_MASK);
|
||||
|
||||
/* Change src to where master sends to */
|
||||
range.flags = IP_NAT_RANGE_MAP_IPS;
|
||||
range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.ip;
|
||||
|
||||
/* hook doesn't matter, but it has to do source manip */
|
||||
ip_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
|
||||
|
||||
/* For DST manip, map port here to where it's expected. */
|
||||
range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
|
||||
range.min = range.max = this->saved_proto;
|
||||
range.min_ip = range.max_ip = this->saved_ip;
|
||||
|
||||
/* hook doesn't matter, but it has to do destination manip */
|
||||
ip_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
|
||||
|
||||
ip_conntrack_q931_expect(new, this);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_callforwarding(struct sk_buff **pskb, struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
TransportAddress * addr, u_int16_t port,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
u_int16_t nated_port;
|
||||
|
||||
/* Set expectations for NAT */
|
||||
exp->saved_ip = exp->tuple.dst.ip;
|
||||
exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->expectfn = ip_nat_callforwarding_expect;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (nated_port = port; nated_port != 0; nated_port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (ip_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("ip_nat_q931: out of TCP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (!set_h225_addr(pskb, data, dataoff, addr,
|
||||
ct->tuplehash[!dir].tuple.dst.ip,
|
||||
nated_port) == 0) {
|
||||
ip_conntrack_unexpect_related(exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
DEBUGP("ip_nat_q931: expect Call Forwarding "
|
||||
"%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
|
||||
NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int __init init(void)
|
||||
{
|
||||
BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_t120_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_h245_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_q931_hook) != NULL);
|
||||
|
||||
rcu_assign_pointer(set_h245_addr_hook, set_h245_addr);
|
||||
rcu_assign_pointer(set_h225_addr_hook, set_h225_addr);
|
||||
rcu_assign_pointer(set_sig_addr_hook, set_sig_addr);
|
||||
rcu_assign_pointer(set_ras_addr_hook, set_ras_addr);
|
||||
rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp);
|
||||
rcu_assign_pointer(nat_t120_hook, nat_t120);
|
||||
rcu_assign_pointer(nat_h245_hook, nat_h245);
|
||||
rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding);
|
||||
rcu_assign_pointer(nat_q931_hook, nat_q931);
|
||||
|
||||
DEBUGP("ip_nat_h323: init success\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static void __exit fini(void)
|
||||
{
|
||||
rcu_assign_pointer(set_h245_addr_hook, NULL);
|
||||
rcu_assign_pointer(set_h225_addr_hook, NULL);
|
||||
rcu_assign_pointer(set_sig_addr_hook, NULL);
|
||||
rcu_assign_pointer(set_ras_addr_hook, NULL);
|
||||
rcu_assign_pointer(nat_rtp_rtcp_hook, NULL);
|
||||
rcu_assign_pointer(nat_t120_hook, NULL);
|
||||
rcu_assign_pointer(nat_h245_hook, NULL);
|
||||
rcu_assign_pointer(nat_callforwarding_hook, NULL);
|
||||
rcu_assign_pointer(nat_q931_hook, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
module_init(init);
|
||||
module_exit(fini);
|
||||
|
||||
MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
|
||||
MODULE_DESCRIPTION("H.323 NAT helper");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,350 +0,0 @@
|
|||
/*
|
||||
* ip_nat_pptp.c - Version 3.0
|
||||
*
|
||||
* NAT support for PPTP (Point to Point Tunneling Protocol).
|
||||
* PPTP is a a protocol for creating virtual private networks.
|
||||
* It is a specification defined by Microsoft and some vendors
|
||||
* working with Microsoft. PPTP is built on top of a modified
|
||||
* version of the Internet Generic Routing Encapsulation Protocol.
|
||||
* GRE is defined in RFC 1701 and RFC 1702. Documentation of
|
||||
* PPTP can be found in RFC 2637
|
||||
*
|
||||
* (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*
|
||||
* TODO: - NAT to a unique tuple, not to TCP source port
|
||||
* (needs netfilter tuple reservation)
|
||||
*
|
||||
* Changes:
|
||||
* 2002-02-10 - Version 1.3
|
||||
* - Use ip_nat_mangle_tcp_packet() because of cloned skb's
|
||||
* in local connections (Philip Craig <philipc@snapgear.com>)
|
||||
* - add checks for magicCookie and pptp version
|
||||
* - make argument list of pptp_{out,in}bound_packet() shorter
|
||||
* - move to C99 style initializers
|
||||
* - print version number at module loadtime
|
||||
* 2003-09-22 - Version 1.5
|
||||
* - use SNATed tcp sourceport as callid, since we get called before
|
||||
* TCP header is mangled (Philip Craig <philipc@snapgear.com>)
|
||||
* 2004-10-22 - Version 2.0
|
||||
* - kernel 2.6.x version
|
||||
* 2005-06-10 - Version 3.0
|
||||
* - kernel >= 2.6.11 version,
|
||||
* funded by Oxcoda NetBox Blue (http://www.netboxblue.com/)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_pptp.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
|
||||
|
||||
#define IP_NAT_PPTP_VERSION "3.0"
|
||||
|
||||
#define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off)))
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
|
||||
MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
|
||||
|
||||
|
||||
#if 0
|
||||
extern const char *pptp_msg_name[];
|
||||
#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \
|
||||
__FUNCTION__, ## args)
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
static void pptp_nat_expected(struct ip_conntrack *ct,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
struct ip_conntrack *master = ct->master;
|
||||
struct ip_conntrack_expect *other_exp;
|
||||
struct ip_conntrack_tuple t;
|
||||
struct ip_ct_pptp_master *ct_pptp_info;
|
||||
struct ip_nat_pptp *nat_pptp_info;
|
||||
struct ip_nat_range range;
|
||||
|
||||
ct_pptp_info = &master->help.ct_pptp_info;
|
||||
nat_pptp_info = &master->nat.help.nat_pptp_info;
|
||||
|
||||
/* And here goes the grand finale of corrosion... */
|
||||
|
||||
if (exp->dir == IP_CT_DIR_ORIGINAL) {
|
||||
DEBUGP("we are PNS->PAC\n");
|
||||
/* therefore, build tuple for PAC->PNS */
|
||||
t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
|
||||
t.src.u.gre.key = master->help.ct_pptp_info.pac_call_id;
|
||||
t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
|
||||
t.dst.u.gre.key = master->help.ct_pptp_info.pns_call_id;
|
||||
t.dst.protonum = IPPROTO_GRE;
|
||||
} else {
|
||||
DEBUGP("we are PAC->PNS\n");
|
||||
/* build tuple for PNS->PAC */
|
||||
t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
|
||||
t.src.u.gre.key = master->nat.help.nat_pptp_info.pns_call_id;
|
||||
t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
|
||||
t.dst.u.gre.key = master->nat.help.nat_pptp_info.pac_call_id;
|
||||
t.dst.protonum = IPPROTO_GRE;
|
||||
}
|
||||
|
||||
DEBUGP("trying to unexpect other dir: ");
|
||||
DUMP_TUPLE(&t);
|
||||
other_exp = ip_conntrack_expect_find_get(&t);
|
||||
if (other_exp) {
|
||||
ip_conntrack_unexpect_related(other_exp);
|
||||
ip_conntrack_expect_put(other_exp);
|
||||
DEBUGP("success\n");
|
||||
} else {
|
||||
DEBUGP("not found!\n");
|
||||
}
|
||||
|
||||
/* This must be a fresh one. */
|
||||
BUG_ON(ct->status & IPS_NAT_DONE_MASK);
|
||||
|
||||
/* Change src to where master sends to */
|
||||
range.flags = IP_NAT_RANGE_MAP_IPS;
|
||||
range.min_ip = range.max_ip
|
||||
= ct->master->tuplehash[!exp->dir].tuple.dst.ip;
|
||||
if (exp->dir == IP_CT_DIR_ORIGINAL) {
|
||||
range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
|
||||
range.min = range.max = exp->saved_proto;
|
||||
}
|
||||
/* hook doesn't matter, but it has to do source manip */
|
||||
ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
|
||||
|
||||
/* For DST manip, map port here to where it's expected. */
|
||||
range.flags = IP_NAT_RANGE_MAP_IPS;
|
||||
range.min_ip = range.max_ip
|
||||
= ct->master->tuplehash[!exp->dir].tuple.src.ip;
|
||||
if (exp->dir == IP_CT_DIR_REPLY) {
|
||||
range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
|
||||
range.min = range.max = exp->saved_proto;
|
||||
}
|
||||
/* hook doesn't matter, but it has to do destination manip */
|
||||
ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
|
||||
}
|
||||
|
||||
/* outbound packets == from PNS to PAC */
|
||||
static int
|
||||
pptp_outbound_pkt(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq)
|
||||
|
||||
{
|
||||
struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
|
||||
struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
|
||||
u_int16_t msg;
|
||||
__be16 new_callid;
|
||||
unsigned int cid_off;
|
||||
|
||||
new_callid = ct_pptp_info->pns_call_id;
|
||||
|
||||
switch (msg = ntohs(ctlh->messageType)) {
|
||||
case PPTP_OUT_CALL_REQUEST:
|
||||
cid_off = offsetof(union pptp_ctrl_union, ocreq.callID);
|
||||
/* FIXME: ideally we would want to reserve a call ID
|
||||
* here. current netfilter NAT core is not able to do
|
||||
* this :( For now we use TCP source port. This breaks
|
||||
* multiple calls within one control session */
|
||||
|
||||
/* save original call ID in nat_info */
|
||||
nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
|
||||
|
||||
/* don't use tcph->source since we are at a DSTmanip
|
||||
* hook (e.g. PREROUTING) and pkt is not mangled yet */
|
||||
new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
|
||||
|
||||
/* save new call ID in ct info */
|
||||
ct_pptp_info->pns_call_id = new_callid;
|
||||
break;
|
||||
case PPTP_IN_CALL_REPLY:
|
||||
cid_off = offsetof(union pptp_ctrl_union, icack.callID);
|
||||
break;
|
||||
case PPTP_CALL_CLEAR_REQUEST:
|
||||
cid_off = offsetof(union pptp_ctrl_union, clrreq.callID);
|
||||
break;
|
||||
default:
|
||||
DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
|
||||
(msg <= PPTP_MSG_MAX)?
|
||||
pptp_msg_name[msg]:pptp_msg_name[0]);
|
||||
/* fall through */
|
||||
|
||||
case PPTP_SET_LINK_INFO:
|
||||
/* only need to NAT in case PAC is behind NAT box */
|
||||
case PPTP_START_SESSION_REQUEST:
|
||||
case PPTP_START_SESSION_REPLY:
|
||||
case PPTP_STOP_SESSION_REQUEST:
|
||||
case PPTP_STOP_SESSION_REPLY:
|
||||
case PPTP_ECHO_REQUEST:
|
||||
case PPTP_ECHO_REPLY:
|
||||
/* no need to alter packet */
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass
|
||||
* down to here */
|
||||
DEBUGP("altering call id from 0x%04x to 0x%04x\n",
|
||||
ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
|
||||
|
||||
/* mangle packet */
|
||||
if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
|
||||
cid_off + sizeof(struct pptp_pkt_hdr) +
|
||||
sizeof(struct PptpControlHeader),
|
||||
sizeof(new_callid), (char *)&new_callid,
|
||||
sizeof(new_callid)) == 0)
|
||||
return NF_DROP;
|
||||
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static void
|
||||
pptp_exp_gre(struct ip_conntrack_expect *expect_orig,
|
||||
struct ip_conntrack_expect *expect_reply)
|
||||
{
|
||||
struct ip_conntrack *ct = expect_orig->master;
|
||||
struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
|
||||
struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
|
||||
|
||||
/* save original PAC call ID in nat_info */
|
||||
nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
|
||||
|
||||
/* alter expectation for PNS->PAC direction */
|
||||
expect_orig->saved_proto.gre.key = ct_pptp_info->pns_call_id;
|
||||
expect_orig->tuple.src.u.gre.key = nat_pptp_info->pns_call_id;
|
||||
expect_orig->tuple.dst.u.gre.key = ct_pptp_info->pac_call_id;
|
||||
expect_orig->dir = IP_CT_DIR_ORIGINAL;
|
||||
|
||||
/* alter expectation for PAC->PNS direction */
|
||||
expect_reply->saved_proto.gre.key = nat_pptp_info->pns_call_id;
|
||||
expect_reply->tuple.src.u.gre.key = nat_pptp_info->pac_call_id;
|
||||
expect_reply->tuple.dst.u.gre.key = ct_pptp_info->pns_call_id;
|
||||
expect_reply->dir = IP_CT_DIR_REPLY;
|
||||
}
|
||||
|
||||
/* inbound packets == from PAC to PNS */
|
||||
static int
|
||||
pptp_inbound_pkt(struct sk_buff **pskb,
|
||||
struct ip_conntrack *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq)
|
||||
{
|
||||
struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
|
||||
u_int16_t msg;
|
||||
__be16 new_pcid;
|
||||
unsigned int pcid_off;
|
||||
|
||||
new_pcid = nat_pptp_info->pns_call_id;
|
||||
|
||||
switch (msg = ntohs(ctlh->messageType)) {
|
||||
case PPTP_OUT_CALL_REPLY:
|
||||
pcid_off = offsetof(union pptp_ctrl_union, ocack.peersCallID);
|
||||
break;
|
||||
case PPTP_IN_CALL_CONNECT:
|
||||
pcid_off = offsetof(union pptp_ctrl_union, iccon.peersCallID);
|
||||
break;
|
||||
case PPTP_IN_CALL_REQUEST:
|
||||
/* only need to nat in case PAC is behind NAT box */
|
||||
return NF_ACCEPT;
|
||||
case PPTP_WAN_ERROR_NOTIFY:
|
||||
pcid_off = offsetof(union pptp_ctrl_union, wanerr.peersCallID);
|
||||
break;
|
||||
case PPTP_CALL_DISCONNECT_NOTIFY:
|
||||
pcid_off = offsetof(union pptp_ctrl_union, disc.callID);
|
||||
break;
|
||||
case PPTP_SET_LINK_INFO:
|
||||
pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)?
|
||||
pptp_msg_name[msg]:pptp_msg_name[0]);
|
||||
/* fall through */
|
||||
|
||||
case PPTP_START_SESSION_REQUEST:
|
||||
case PPTP_START_SESSION_REPLY:
|
||||
case PPTP_STOP_SESSION_REQUEST:
|
||||
case PPTP_STOP_SESSION_REPLY:
|
||||
case PPTP_ECHO_REQUEST:
|
||||
case PPTP_ECHO_REPLY:
|
||||
/* no need to alter packet */
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST,
|
||||
* WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */
|
||||
|
||||
/* mangle packet */
|
||||
DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
|
||||
ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
|
||||
|
||||
if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
|
||||
pcid_off + sizeof(struct pptp_pkt_hdr) +
|
||||
sizeof(struct PptpControlHeader),
|
||||
sizeof(new_pcid), (char *)&new_pcid,
|
||||
sizeof(new_pcid)) == 0)
|
||||
return NF_DROP;
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
|
||||
extern int __init ip_nat_proto_gre_init(void);
|
||||
extern void __exit ip_nat_proto_gre_fini(void);
|
||||
|
||||
static int __init ip_nat_helper_pptp_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGP("%s: registering NAT helper\n", __FILE__);
|
||||
|
||||
ret = ip_nat_proto_gre_init();
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
BUG_ON(rcu_dereference(ip_nat_pptp_hook_outbound));
|
||||
rcu_assign_pointer(ip_nat_pptp_hook_outbound, pptp_outbound_pkt);
|
||||
|
||||
BUG_ON(rcu_dereference(ip_nat_pptp_hook_inbound));
|
||||
rcu_assign_pointer(ip_nat_pptp_hook_inbound, pptp_inbound_pkt);
|
||||
|
||||
BUG_ON(rcu_dereference(ip_nat_pptp_hook_exp_gre));
|
||||
rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, pptp_exp_gre);
|
||||
|
||||
BUG_ON(rcu_dereference(ip_nat_pptp_hook_expectfn));
|
||||
rcu_assign_pointer(ip_nat_pptp_hook_expectfn, pptp_nat_expected);
|
||||
|
||||
printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ip_nat_helper_pptp_fini(void)
|
||||
{
|
||||
DEBUGP("cleanup_module\n" );
|
||||
|
||||
rcu_assign_pointer(ip_nat_pptp_hook_expectfn, NULL);
|
||||
rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, NULL);
|
||||
rcu_assign_pointer(ip_nat_pptp_hook_inbound, NULL);
|
||||
rcu_assign_pointer(ip_nat_pptp_hook_outbound, NULL);
|
||||
synchronize_rcu();
|
||||
|
||||
ip_nat_proto_gre_fini();
|
||||
|
||||
printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
|
||||
}
|
||||
|
||||
module_init(ip_nat_helper_pptp_init);
|
||||
module_exit(ip_nat_helper_pptp_fini);
|
|
@ -1,122 +0,0 @@
|
|||
/* IRC extension for TCP NAT alteration.
|
||||
* (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
|
||||
* (C) 2004 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
|
||||
* based on a copy of RR's ip_nat_ftp.c
|
||||
*
|
||||
* ip_nat_irc.c,v 1.16 2001/12/06 07:42:10 laforge Exp
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <net/tcp.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
|
||||
MODULE_DESCRIPTION("IRC (DCC) NAT helper");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int help(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
u_int16_t port;
|
||||
unsigned int ret;
|
||||
|
||||
/* "4294967296 65635 " */
|
||||
char buffer[18];
|
||||
|
||||
DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
|
||||
expect->seq, exp_irc_info->len,
|
||||
ntohl(tcph->seq));
|
||||
|
||||
/* Reply comes from server. */
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->dir = IP_CT_DIR_REPLY;
|
||||
|
||||
/* When you see the packet, we need to NAT it the same as the
|
||||
* this one. */
|
||||
exp->expectfn = ip_nat_follow_master;
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(port);
|
||||
if (ip_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
return NF_DROP;
|
||||
|
||||
/* strlen("\1DCC CHAT chat AAAAAAAA P\1\n")=27
|
||||
* strlen("\1DCC SCHAT chat AAAAAAAA P\1\n")=28
|
||||
* strlen("\1DCC SEND F AAAAAAAA P S\1\n")=26
|
||||
* strlen("\1DCC MOVE F AAAAAAAA P S\1\n")=26
|
||||
* strlen("\1DCC TSEND F AAAAAAAA P S\1\n")=27
|
||||
* AAAAAAAAA: bound addr (1.0.0.0==16777216, min 8 digits,
|
||||
* 255.255.255.255==4294967296, 10 digits)
|
||||
* P: bound port (min 1 d, max 5d (65635))
|
||||
* F: filename (min 1 d )
|
||||
* S: size (min 1 d )
|
||||
* 0x01, \n: terminators
|
||||
*/
|
||||
|
||||
/* AAA = "us", ie. where server normally talks to. */
|
||||
sprintf(buffer, "%u %u",
|
||||
ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip),
|
||||
port);
|
||||
DEBUGP("ip_nat_irc: Inserting '%s' == %u.%u.%u.%u, port %u\n",
|
||||
buffer, NIPQUAD(exp->tuple.src.ip), port);
|
||||
|
||||
ret = ip_nat_mangle_tcp_packet(pskb, exp->master, ctinfo,
|
||||
matchoff, matchlen, buffer,
|
||||
strlen(buffer));
|
||||
if (ret != NF_ACCEPT)
|
||||
ip_conntrack_unexpect_related(exp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ip_nat_irc_fini(void)
|
||||
{
|
||||
rcu_assign_pointer(ip_nat_irc_hook, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static int __init ip_nat_irc_init(void)
|
||||
{
|
||||
BUG_ON(rcu_dereference(ip_nat_irc_hook));
|
||||
rcu_assign_pointer(ip_nat_irc_hook, help);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */
|
||||
static int warn_set(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
printk(KERN_INFO KBUILD_MODNAME
|
||||
": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
|
||||
return 0;
|
||||
}
|
||||
module_param_call(ports, warn_set, NULL, NULL, 0);
|
||||
|
||||
module_init(ip_nat_irc_init);
|
||||
module_exit(ip_nat_irc_fini);
|
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
* ip_nat_proto_gre.c - Version 2.0
|
||||
*
|
||||
* NAT protocol helper module for GRE.
|
||||
*
|
||||
* GRE is a generic encapsulation protocol, which is generally not very
|
||||
* suited for NAT, as it has no protocol-specific part as port numbers.
|
||||
*
|
||||
* It has an optional key field, which may help us distinguishing two
|
||||
* connections between the same two hosts.
|
||||
*
|
||||
* GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
|
||||
*
|
||||
* PPTP is built on top of a modified version of GRE, and has a mandatory
|
||||
* field called "CallID", which serves us for the same purpose as the key
|
||||
* field in plain GRE.
|
||||
*
|
||||
* Documentation about PPTP can be found in RFC 2637
|
||||
*
|
||||
* (C) 2000-2005 by Harald Welte <laforge@gnumonks.org>
|
||||
*
|
||||
* Development of this code funded by Astaro AG (http://www.astaro.com/)
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
|
||||
MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
|
||||
|
||||
#if 0
|
||||
#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \
|
||||
__FUNCTION__, ## args)
|
||||
#else
|
||||
#define DEBUGP(x, args...)
|
||||
#endif
|
||||
|
||||
/* is key in given range between min and max */
|
||||
static int
|
||||
gre_in_range(const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const union ip_conntrack_manip_proto *min,
|
||||
const union ip_conntrack_manip_proto *max)
|
||||
{
|
||||
__be16 key;
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC)
|
||||
key = tuple->src.u.gre.key;
|
||||
else
|
||||
key = tuple->dst.u.gre.key;
|
||||
|
||||
return ntohs(key) >= ntohs(min->gre.key)
|
||||
&& ntohs(key) <= ntohs(max->gre.key);
|
||||
}
|
||||
|
||||
/* generate unique tuple ... */
|
||||
static int
|
||||
gre_unique_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_nat_range *range,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const struct ip_conntrack *conntrack)
|
||||
{
|
||||
static u_int16_t key;
|
||||
__be16 *keyptr;
|
||||
unsigned int min, i, range_size;
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC)
|
||||
keyptr = &tuple->src.u.gre.key;
|
||||
else
|
||||
keyptr = &tuple->dst.u.gre.key;
|
||||
|
||||
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
|
||||
DEBUGP("%p: NATing GRE PPTP\n", conntrack);
|
||||
min = 1;
|
||||
range_size = 0xffff;
|
||||
} else {
|
||||
min = ntohs(range->min.gre.key);
|
||||
range_size = ntohs(range->max.gre.key) - min + 1;
|
||||
}
|
||||
|
||||
DEBUGP("min = %u, range_size = %u\n", min, range_size);
|
||||
|
||||
for (i = 0; i < range_size; i++, key++) {
|
||||
*keyptr = htons(min + key % range_size);
|
||||
if (!ip_nat_used_tuple(tuple, conntrack))
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUGP("%p: no NAT mapping\n", conntrack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* manipulate a GRE packet according to maniptype */
|
||||
static int
|
||||
gre_manip_pkt(struct sk_buff **pskb,
|
||||
unsigned int iphdroff,
|
||||
const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype)
|
||||
{
|
||||
struct gre_hdr *greh;
|
||||
struct gre_hdr_pptp *pgreh;
|
||||
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
||||
unsigned int hdroff = iphdroff + iph->ihl*4;
|
||||
|
||||
/* pgreh includes two optional 32bit fields which are not required
|
||||
* to be there. That's where the magic '8' comes from */
|
||||
if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh)-8))
|
||||
return 0;
|
||||
|
||||
greh = (void *)(*pskb)->data + hdroff;
|
||||
pgreh = (struct gre_hdr_pptp *) greh;
|
||||
|
||||
/* we only have destination manip of a packet, since 'source key'
|
||||
* is not present in the packet itself */
|
||||
if (maniptype == IP_NAT_MANIP_DST) {
|
||||
/* key manipulation is always dest */
|
||||
switch (greh->version) {
|
||||
case 0:
|
||||
if (!greh->key) {
|
||||
DEBUGP("can't nat GRE w/o key\n");
|
||||
break;
|
||||
}
|
||||
if (greh->csum) {
|
||||
/* FIXME: Never tested this code... */
|
||||
nf_proto_csum_replace4(gre_csum(greh), *pskb,
|
||||
*(gre_key(greh)),
|
||||
tuple->dst.u.gre.key, 0);
|
||||
}
|
||||
*(gre_key(greh)) = tuple->dst.u.gre.key;
|
||||
break;
|
||||
case GRE_VERSION_PPTP:
|
||||
DEBUGP("call_id -> 0x%04x\n",
|
||||
ntohs(tuple->dst.u.gre.key));
|
||||
pgreh->call_id = tuple->dst.u.gre.key;
|
||||
break;
|
||||
default:
|
||||
DEBUGP("can't nat unknown GRE version\n");
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* nat helper struct */
|
||||
static struct ip_nat_protocol gre = {
|
||||
.name = "GRE",
|
||||
.protonum = IPPROTO_GRE,
|
||||
.manip_pkt = gre_manip_pkt,
|
||||
.in_range = gre_in_range,
|
||||
.unique_tuple = gre_unique_tuple,
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
.range_to_nfattr = ip_nat_port_range_to_nfattr,
|
||||
.nfattr_to_range = ip_nat_port_nfattr_to_range,
|
||||
#endif
|
||||
};
|
||||
|
||||
int __init ip_nat_proto_gre_init(void)
|
||||
{
|
||||
return ip_nat_protocol_register(&gre);
|
||||
}
|
||||
|
||||
void __exit ip_nat_proto_gre_fini(void)
|
||||
{
|
||||
ip_nat_protocol_unregister(&gre);
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/if.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
|
||||
|
||||
static int
|
||||
icmp_in_range(const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const union ip_conntrack_manip_proto *min,
|
||||
const union ip_conntrack_manip_proto *max)
|
||||
{
|
||||
return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) &&
|
||||
ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id);
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_unique_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_nat_range *range,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const struct ip_conntrack *conntrack)
|
||||
{
|
||||
static u_int16_t id;
|
||||
unsigned int range_size;
|
||||
unsigned int i;
|
||||
|
||||
range_size = ntohs(range->max.icmp.id) - ntohs(range->min.icmp.id) + 1;
|
||||
/* If no range specified... */
|
||||
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED))
|
||||
range_size = 0xFFFF;
|
||||
|
||||
for (i = 0; i < range_size; i++, id++) {
|
||||
tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) +
|
||||
(id % range_size));
|
||||
if (!ip_nat_used_tuple(tuple, conntrack))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
icmp_manip_pkt(struct sk_buff **pskb,
|
||||
unsigned int iphdroff,
|
||||
const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype)
|
||||
{
|
||||
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
||||
struct icmphdr *hdr;
|
||||
unsigned int hdroff = iphdroff + iph->ihl*4;
|
||||
|
||||
if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
|
||||
return 0;
|
||||
|
||||
hdr = (struct icmphdr *)((*pskb)->data + hdroff);
|
||||
nf_proto_csum_replace2(&hdr->checksum, *pskb,
|
||||
hdr->un.echo.id, tuple->src.u.icmp.id, 0);
|
||||
hdr->un.echo.id = tuple->src.u.icmp.id;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ip_nat_protocol ip_nat_protocol_icmp = {
|
||||
.name = "ICMP",
|
||||
.protonum = IPPROTO_ICMP,
|
||||
.me = THIS_MODULE,
|
||||
.manip_pkt = icmp_manip_pkt,
|
||||
.in_range = icmp_in_range,
|
||||
.unique_tuple = icmp_unique_tuple,
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
.range_to_nfattr = ip_nat_port_range_to_nfattr,
|
||||
.nfattr_to_range = ip_nat_port_nfattr_to_range,
|
||||
#endif
|
||||
};
|
|
@ -1,154 +0,0 @@
|
|||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/netfilter/nfnetlink_conntrack.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_core.h>
|
||||
|
||||
static int
|
||||
tcp_in_range(const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const union ip_conntrack_manip_proto *min,
|
||||
const union ip_conntrack_manip_proto *max)
|
||||
{
|
||||
__be16 port;
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC)
|
||||
port = tuple->src.u.tcp.port;
|
||||
else
|
||||
port = tuple->dst.u.tcp.port;
|
||||
|
||||
return ntohs(port) >= ntohs(min->tcp.port)
|
||||
&& ntohs(port) <= ntohs(max->tcp.port);
|
||||
}
|
||||
|
||||
static int
|
||||
tcp_unique_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_nat_range *range,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const struct ip_conntrack *conntrack)
|
||||
{
|
||||
static u_int16_t port;
|
||||
__be16 *portptr;
|
||||
unsigned int range_size, min, i;
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC)
|
||||
portptr = &tuple->src.u.tcp.port;
|
||||
else
|
||||
portptr = &tuple->dst.u.tcp.port;
|
||||
|
||||
/* If no range specified... */
|
||||
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
|
||||
/* If it's dst rewrite, can't change port */
|
||||
if (maniptype == IP_NAT_MANIP_DST)
|
||||
return 0;
|
||||
|
||||
/* Map privileged onto privileged. */
|
||||
if (ntohs(*portptr) < 1024) {
|
||||
/* Loose convention: >> 512 is credential passing */
|
||||
if (ntohs(*portptr)<512) {
|
||||
min = 1;
|
||||
range_size = 511 - min + 1;
|
||||
} else {
|
||||
min = 600;
|
||||
range_size = 1023 - min + 1;
|
||||
}
|
||||
} else {
|
||||
min = 1024;
|
||||
range_size = 65535 - 1024 + 1;
|
||||
}
|
||||
} else {
|
||||
min = ntohs(range->min.tcp.port);
|
||||
range_size = ntohs(range->max.tcp.port) - min + 1;
|
||||
}
|
||||
|
||||
/* Start from random port to avoid prediction */
|
||||
if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
|
||||
port = net_random();
|
||||
|
||||
for (i = 0; i < range_size; i++, port++) {
|
||||
*portptr = htons(min + port % range_size);
|
||||
if (!ip_nat_used_tuple(tuple, conntrack)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tcp_manip_pkt(struct sk_buff **pskb,
|
||||
unsigned int iphdroff,
|
||||
const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype)
|
||||
{
|
||||
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
||||
struct tcphdr *hdr;
|
||||
unsigned int hdroff = iphdroff + iph->ihl*4;
|
||||
__be32 oldip, newip;
|
||||
__be16 *portptr, newport, oldport;
|
||||
int hdrsize = 8; /* TCP connection tracking guarantees this much */
|
||||
|
||||
/* this could be a inner header returned in icmp packet; in such
|
||||
cases we cannot update the checksum field since it is outside of
|
||||
the 8 bytes of transport layer headers we are guaranteed */
|
||||
if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
|
||||
hdrsize = sizeof(struct tcphdr);
|
||||
|
||||
if (!skb_make_writable(pskb, hdroff + hdrsize))
|
||||
return 0;
|
||||
|
||||
iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
||||
hdr = (struct tcphdr *)((*pskb)->data + hdroff);
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC) {
|
||||
/* Get rid of src ip and src pt */
|
||||
oldip = iph->saddr;
|
||||
newip = tuple->src.ip;
|
||||
newport = tuple->src.u.tcp.port;
|
||||
portptr = &hdr->source;
|
||||
} else {
|
||||
/* Get rid of dst ip and dst pt */
|
||||
oldip = iph->daddr;
|
||||
newip = tuple->dst.ip;
|
||||
newport = tuple->dst.u.tcp.port;
|
||||
portptr = &hdr->dest;
|
||||
}
|
||||
|
||||
oldport = *portptr;
|
||||
*portptr = newport;
|
||||
|
||||
if (hdrsize < sizeof(*hdr))
|
||||
return 1;
|
||||
|
||||
nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
|
||||
nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ip_nat_protocol ip_nat_protocol_tcp = {
|
||||
.name = "TCP",
|
||||
.protonum = IPPROTO_TCP,
|
||||
.me = THIS_MODULE,
|
||||
.manip_pkt = tcp_manip_pkt,
|
||||
.in_range = tcp_in_range,
|
||||
.unique_tuple = tcp_unique_tuple,
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
.range_to_nfattr = ip_nat_port_range_to_nfattr,
|
||||
.nfattr_to_range = ip_nat_port_nfattr_to_range,
|
||||
#endif
|
||||
};
|
|
@ -1,144 +0,0 @@
|
|||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/if.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
|
||||
|
||||
static int
|
||||
udp_in_range(const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const union ip_conntrack_manip_proto *min,
|
||||
const union ip_conntrack_manip_proto *max)
|
||||
{
|
||||
__be16 port;
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC)
|
||||
port = tuple->src.u.udp.port;
|
||||
else
|
||||
port = tuple->dst.u.udp.port;
|
||||
|
||||
return ntohs(port) >= ntohs(min->udp.port)
|
||||
&& ntohs(port) <= ntohs(max->udp.port);
|
||||
}
|
||||
|
||||
static int
|
||||
udp_unique_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_nat_range *range,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const struct ip_conntrack *conntrack)
|
||||
{
|
||||
static u_int16_t port;
|
||||
__be16 *portptr;
|
||||
unsigned int range_size, min, i;
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC)
|
||||
portptr = &tuple->src.u.udp.port;
|
||||
else
|
||||
portptr = &tuple->dst.u.udp.port;
|
||||
|
||||
/* If no range specified... */
|
||||
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
|
||||
/* If it's dst rewrite, can't change port */
|
||||
if (maniptype == IP_NAT_MANIP_DST)
|
||||
return 0;
|
||||
|
||||
if (ntohs(*portptr) < 1024) {
|
||||
/* Loose convention: >> 512 is credential passing */
|
||||
if (ntohs(*portptr)<512) {
|
||||
min = 1;
|
||||
range_size = 511 - min + 1;
|
||||
} else {
|
||||
min = 600;
|
||||
range_size = 1023 - min + 1;
|
||||
}
|
||||
} else {
|
||||
min = 1024;
|
||||
range_size = 65535 - 1024 + 1;
|
||||
}
|
||||
} else {
|
||||
min = ntohs(range->min.udp.port);
|
||||
range_size = ntohs(range->max.udp.port) - min + 1;
|
||||
}
|
||||
|
||||
/* Start from random port to avoid prediction */
|
||||
if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
|
||||
port = net_random();
|
||||
|
||||
for (i = 0; i < range_size; i++, port++) {
|
||||
*portptr = htons(min + port % range_size);
|
||||
if (!ip_nat_used_tuple(tuple, conntrack))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
udp_manip_pkt(struct sk_buff **pskb,
|
||||
unsigned int iphdroff,
|
||||
const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype)
|
||||
{
|
||||
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
||||
struct udphdr *hdr;
|
||||
unsigned int hdroff = iphdroff + iph->ihl*4;
|
||||
__be32 oldip, newip;
|
||||
__be16 *portptr, newport;
|
||||
|
||||
if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
|
||||
return 0;
|
||||
|
||||
iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
||||
hdr = (struct udphdr *)((*pskb)->data + hdroff);
|
||||
|
||||
if (maniptype == IP_NAT_MANIP_SRC) {
|
||||
/* Get rid of src ip and src pt */
|
||||
oldip = iph->saddr;
|
||||
newip = tuple->src.ip;
|
||||
newport = tuple->src.u.udp.port;
|
||||
portptr = &hdr->source;
|
||||
} else {
|
||||
/* Get rid of dst ip and dst pt */
|
||||
oldip = iph->daddr;
|
||||
newip = tuple->dst.ip;
|
||||
newport = tuple->dst.u.udp.port;
|
||||
portptr = &hdr->dest;
|
||||
}
|
||||
|
||||
if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) {
|
||||
nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
|
||||
nf_proto_csum_replace2(&hdr->check, *pskb, *portptr, newport, 0);
|
||||
if (!hdr->check)
|
||||
hdr->check = CSUM_MANGLED_0;
|
||||
}
|
||||
*portptr = newport;
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ip_nat_protocol ip_nat_protocol_udp = {
|
||||
.name = "UDP",
|
||||
.protonum = IPPROTO_UDP,
|
||||
.me = THIS_MODULE,
|
||||
.manip_pkt = udp_manip_pkt,
|
||||
.in_range = udp_in_range,
|
||||
.unique_tuple = udp_unique_tuple,
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
|
||||
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
|
||||
.range_to_nfattr = ip_nat_port_range_to_nfattr,
|
||||
.nfattr_to_range = ip_nat_port_nfattr_to_range,
|
||||
#endif
|
||||
};
|
|
@ -1,55 +0,0 @@
|
|||
/* The "unknown" protocol. This is what is used for protocols we
|
||||
* don't understand. It's returned by ip_ct_find_proto().
|
||||
*/
|
||||
|
||||
/* (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.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/if.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
|
||||
|
||||
static int unknown_in_range(const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type manip_type,
|
||||
const union ip_conntrack_manip_proto *min,
|
||||
const union ip_conntrack_manip_proto *max)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int unknown_unique_tuple(struct ip_conntrack_tuple *tuple,
|
||||
const struct ip_nat_range *range,
|
||||
enum ip_nat_manip_type maniptype,
|
||||
const struct ip_conntrack *conntrack)
|
||||
{
|
||||
/* Sorry: we can't help you; if it's not unique, we can't frob
|
||||
anything. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
unknown_manip_pkt(struct sk_buff **pskb,
|
||||
unsigned int iphdroff,
|
||||
const struct ip_conntrack_tuple *tuple,
|
||||
enum ip_nat_manip_type maniptype)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ip_nat_protocol ip_nat_unknown_protocol = {
|
||||
.name = "unknown",
|
||||
/* .me isn't set: getting a ref to this cannot fail. */
|
||||
.manip_pkt = unknown_manip_pkt,
|
||||
.in_range = unknown_in_range,
|
||||
.unique_tuple = unknown_unique_tuple,
|
||||
};
|
|
@ -1,314 +0,0 @@
|
|||
/* (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.
|
||||
*/
|
||||
|
||||
/* Everything about the rules for NAT. */
|
||||
#include <linux/types.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/route.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
#define NAT_VALID_HOOKS ((1<<NF_IP_PRE_ROUTING) | (1<<NF_IP_POST_ROUTING) | (1<<NF_IP_LOCAL_OUT))
|
||||
|
||||
static struct
|
||||
{
|
||||
struct ipt_replace repl;
|
||||
struct ipt_standard entries[3];
|
||||
struct ipt_error term;
|
||||
} nat_initial_table __initdata
|
||||
= { { "nat", NAT_VALID_HOOKS, 4,
|
||||
sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
|
||||
{ [NF_IP_PRE_ROUTING] = 0,
|
||||
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
|
||||
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
|
||||
{ [NF_IP_PRE_ROUTING] = 0,
|
||||
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
|
||||
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
|
||||
0, NULL, { } },
|
||||
{
|
||||
/* PRE_ROUTING */
|
||||
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
|
||||
0,
|
||||
sizeof(struct ipt_entry),
|
||||
sizeof(struct ipt_standard),
|
||||
0, { 0, 0 }, { } },
|
||||
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
|
||||
-NF_ACCEPT - 1 } },
|
||||
/* POST_ROUTING */
|
||||
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
|
||||
0,
|
||||
sizeof(struct ipt_entry),
|
||||
sizeof(struct ipt_standard),
|
||||
0, { 0, 0 }, { } },
|
||||
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
|
||||
-NF_ACCEPT - 1 } },
|
||||
/* LOCAL_OUT */
|
||||
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
|
||||
0,
|
||||
sizeof(struct ipt_entry),
|
||||
sizeof(struct ipt_standard),
|
||||
0, { 0, 0 }, { } },
|
||||
{ { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
|
||||
-NF_ACCEPT - 1 } }
|
||||
},
|
||||
/* ERROR */
|
||||
{ { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
|
||||
0,
|
||||
sizeof(struct ipt_entry),
|
||||
sizeof(struct ipt_error),
|
||||
0, { 0, 0 }, { } },
|
||||
{ { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
|
||||
{ } },
|
||||
"ERROR"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static struct xt_table nat_table = {
|
||||
.name = "nat",
|
||||
.valid_hooks = NAT_VALID_HOOKS,
|
||||
.lock = RW_LOCK_UNLOCKED,
|
||||
.me = THIS_MODULE,
|
||||
.af = AF_INET,
|
||||
};
|
||||
|
||||
/* Source NAT */
|
||||
static unsigned int ipt_snat_target(struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
unsigned int hooknum,
|
||||
const struct xt_target *target,
|
||||
const void *targinfo)
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
const struct ip_nat_multi_range_compat *mr = targinfo;
|
||||
|
||||
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
|
||||
|
||||
ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
|
||||
/* Connection must be valid and new. */
|
||||
IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
|
||||
|| ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
|
||||
IP_NF_ASSERT(out);
|
||||
|
||||
return ip_nat_setup_info(ct, &mr->range[0], hooknum);
|
||||
}
|
||||
|
||||
/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
|
||||
static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
|
||||
{
|
||||
static int warned = 0;
|
||||
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
|
||||
struct rtable *rt;
|
||||
|
||||
if (ip_route_output_key(&rt, &fl) != 0)
|
||||
return;
|
||||
|
||||
if (rt->rt_src != srcip && !warned) {
|
||||
printk("NAT: no longer support implicit source local NAT\n");
|
||||
printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n",
|
||||
NIPQUAD(srcip), NIPQUAD(dstip));
|
||||
warned = 1;
|
||||
}
|
||||
ip_rt_put(rt);
|
||||
}
|
||||
|
||||
static unsigned int ipt_dnat_target(struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
unsigned int hooknum,
|
||||
const struct xt_target *target,
|
||||
const void *targinfo)
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
const struct ip_nat_multi_range_compat *mr = targinfo;
|
||||
|
||||
IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
|
||||
|| hooknum == NF_IP_LOCAL_OUT);
|
||||
|
||||
ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
|
||||
/* Connection must be valid and new. */
|
||||
IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
|
||||
|
||||
if (hooknum == NF_IP_LOCAL_OUT
|
||||
&& mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
|
||||
warn_if_extra_mangle(ip_hdr(*pskb)->daddr,
|
||||
mr->range[0].min_ip);
|
||||
|
||||
return ip_nat_setup_info(ct, &mr->range[0], hooknum);
|
||||
}
|
||||
|
||||
static int ipt_snat_checkentry(const char *tablename,
|
||||
const void *entry,
|
||||
const struct xt_target *target,
|
||||
void *targinfo,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct ip_nat_multi_range_compat *mr = targinfo;
|
||||
|
||||
/* Must be a valid range */
|
||||
if (mr->rangesize != 1) {
|
||||
printk("SNAT: multiple ranges no longer supported\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ipt_dnat_checkentry(const char *tablename,
|
||||
const void *entry,
|
||||
const struct xt_target *target,
|
||||
void *targinfo,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
struct ip_nat_multi_range_compat *mr = targinfo;
|
||||
|
||||
/* Must be a valid range */
|
||||
if (mr->rangesize != 1) {
|
||||
printk("DNAT: multiple ranges no longer supported\n");
|
||||
return 0;
|
||||
}
|
||||
if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
|
||||
printk("DNAT: port randomization not supported\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline unsigned int
|
||||
alloc_null_binding(struct ip_conntrack *conntrack,
|
||||
struct ip_nat_info *info,
|
||||
unsigned int hooknum)
|
||||
{
|
||||
/* Force range to this IP; let proto decide mapping for
|
||||
per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
|
||||
Use reply in case it's already been mangled (eg local packet).
|
||||
*/
|
||||
__be32 ip
|
||||
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
|
||||
? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
|
||||
: conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
|
||||
struct ip_nat_range range
|
||||
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } };
|
||||
|
||||
DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n", conntrack,
|
||||
NIPQUAD(ip));
|
||||
return ip_nat_setup_info(conntrack, &range, hooknum);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
|
||||
struct ip_nat_info *info,
|
||||
unsigned int hooknum)
|
||||
{
|
||||
__be32 ip
|
||||
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
|
||||
? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
|
||||
: conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
|
||||
u_int16_t all
|
||||
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
|
||||
? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
|
||||
: conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
|
||||
struct ip_nat_range range
|
||||
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };
|
||||
|
||||
DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
|
||||
conntrack, NIPQUAD(ip));
|
||||
return ip_nat_setup_info(conntrack, &range, hooknum);
|
||||
}
|
||||
|
||||
int ip_nat_rule_find(struct sk_buff **pskb,
|
||||
unsigned int hooknum,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
struct ip_conntrack *ct,
|
||||
struct ip_nat_info *info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ipt_do_table(pskb, hooknum, in, out, &nat_table);
|
||||
|
||||
if (ret == NF_ACCEPT) {
|
||||
if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
|
||||
/* NUL mapping */
|
||||
ret = alloc_null_binding(ct, info, hooknum);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct xt_target ipt_snat_reg = {
|
||||
.name = "SNAT",
|
||||
.family = AF_INET,
|
||||
.target = ipt_snat_target,
|
||||
.targetsize = sizeof(struct ip_nat_multi_range_compat),
|
||||
.table = "nat",
|
||||
.hooks = 1 << NF_IP_POST_ROUTING,
|
||||
.checkentry = ipt_snat_checkentry,
|
||||
};
|
||||
|
||||
static struct xt_target ipt_dnat_reg = {
|
||||
.name = "DNAT",
|
||||
.family = AF_INET,
|
||||
.target = ipt_dnat_target,
|
||||
.targetsize = sizeof(struct ip_nat_multi_range_compat),
|
||||
.table = "nat",
|
||||
.hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
|
||||
.checkentry = ipt_dnat_checkentry,
|
||||
};
|
||||
|
||||
int __init ip_nat_rule_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ipt_register_table(&nat_table, &nat_initial_table.repl);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = xt_register_target(&ipt_snat_reg);
|
||||
if (ret != 0)
|
||||
goto unregister_table;
|
||||
|
||||
ret = xt_register_target(&ipt_dnat_reg);
|
||||
if (ret != 0)
|
||||
goto unregister_snat;
|
||||
|
||||
return ret;
|
||||
|
||||
unregister_snat:
|
||||
xt_unregister_target(&ipt_snat_reg);
|
||||
unregister_table:
|
||||
xt_unregister_table(&nat_table);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ip_nat_rule_cleanup(void)
|
||||
{
|
||||
xt_unregister_target(&ipt_dnat_reg);
|
||||
xt_unregister_target(&ipt_snat_reg);
|
||||
ipt_unregister_table(&nat_table);
|
||||
}
|
|
@ -1,282 +0,0 @@
|
|||
/* SIP extension for UDP NAT alteration.
|
||||
*
|
||||
* (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
|
||||
* based on RR's ip_nat_ftp.c and other modules.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
|
||||
MODULE_DESCRIPTION("SIP NAT helper");
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
struct addr_map {
|
||||
struct {
|
||||
char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
|
||||
char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
|
||||
unsigned int srclen, srciplen;
|
||||
unsigned int dstlen, dstiplen;
|
||||
} addr[IP_CT_DIR_MAX];
|
||||
};
|
||||
|
||||
static void addr_map_init(struct ip_conntrack *ct, struct addr_map *map)
|
||||
{
|
||||
struct ip_conntrack_tuple *t;
|
||||
enum ip_conntrack_dir dir;
|
||||
unsigned int n;
|
||||
|
||||
for (dir = 0; dir < IP_CT_DIR_MAX; dir++) {
|
||||
t = &ct->tuplehash[dir].tuple;
|
||||
|
||||
n = sprintf(map->addr[dir].src, "%u.%u.%u.%u",
|
||||
NIPQUAD(t->src.ip));
|
||||
map->addr[dir].srciplen = n;
|
||||
n += sprintf(map->addr[dir].src + n, ":%u",
|
||||
ntohs(t->src.u.udp.port));
|
||||
map->addr[dir].srclen = n;
|
||||
|
||||
n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u",
|
||||
NIPQUAD(t->dst.ip));
|
||||
map->addr[dir].dstiplen = n;
|
||||
n += sprintf(map->addr[dir].dst + n, ":%u",
|
||||
ntohs(t->dst.u.udp.port));
|
||||
map->addr[dir].dstlen = n;
|
||||
}
|
||||
}
|
||||
|
||||
static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack *ct, const char **dptr, size_t dlen,
|
||||
enum sip_header_pos pos, struct addr_map *map)
|
||||
{
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
unsigned int matchlen, matchoff, addrlen;
|
||||
char *addr;
|
||||
|
||||
if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0)
|
||||
return 1;
|
||||
|
||||
if ((matchlen == map->addr[dir].srciplen ||
|
||||
matchlen == map->addr[dir].srclen) &&
|
||||
memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) {
|
||||
addr = map->addr[!dir].dst;
|
||||
addrlen = map->addr[!dir].dstlen;
|
||||
} else if ((matchlen == map->addr[dir].dstiplen ||
|
||||
matchlen == map->addr[dir].dstlen) &&
|
||||
memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) {
|
||||
addr = map->addr[!dir].src;
|
||||
addrlen = map->addr[!dir].srclen;
|
||||
} else
|
||||
return 1;
|
||||
|
||||
if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
|
||||
matchoff, matchlen, addr, addrlen))
|
||||
return 0;
|
||||
*dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static unsigned int ip_nat_sip(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack *ct,
|
||||
const char **dptr)
|
||||
{
|
||||
enum sip_header_pos pos;
|
||||
struct addr_map map;
|
||||
int dataoff, datalen;
|
||||
|
||||
dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
|
||||
datalen = (*pskb)->len - dataoff;
|
||||
if (datalen < sizeof("SIP/2.0") - 1)
|
||||
return NF_DROP;
|
||||
|
||||
addr_map_init(ct, &map);
|
||||
|
||||
/* Basic rules: requests and responses. */
|
||||
if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) {
|
||||
/* 10.2: Constructing the REGISTER Request:
|
||||
*
|
||||
* The "userinfo" and "@" components of the SIP URI MUST NOT
|
||||
* be present.
|
||||
*/
|
||||
if (datalen >= sizeof("REGISTER") - 1 &&
|
||||
strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0)
|
||||
pos = POS_REG_REQ_URI;
|
||||
else
|
||||
pos = POS_REQ_URI;
|
||||
|
||||
if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map))
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) ||
|
||||
!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) ||
|
||||
!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) ||
|
||||
!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map))
|
||||
return NF_DROP;
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static unsigned int mangle_sip_packet(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack *ct,
|
||||
const char **dptr, size_t dlen,
|
||||
char *buffer, int bufflen,
|
||||
enum sip_header_pos pos)
|
||||
{
|
||||
unsigned int matchlen, matchoff;
|
||||
|
||||
if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0)
|
||||
return 0;
|
||||
|
||||
if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
|
||||
matchoff, matchlen, buffer, bufflen))
|
||||
return 0;
|
||||
|
||||
/* We need to reload this. Thanks Patrick. */
|
||||
*dptr = (*pskb)->data + ip_hdrlen(*pskb) + sizeof(struct udphdr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mangle_content_len(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack *ct,
|
||||
const char *dptr)
|
||||
{
|
||||
unsigned int dataoff, matchoff, matchlen;
|
||||
char buffer[sizeof("65536")];
|
||||
int bufflen;
|
||||
|
||||
dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
|
||||
|
||||
/* Get actual SDP lenght */
|
||||
if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
|
||||
&matchlen, POS_SDP_HEADER) > 0) {
|
||||
|
||||
/* since ct_sip_get_info() give us a pointer passing 'v='
|
||||
we need to add 2 bytes in this count. */
|
||||
int c_len = (*pskb)->len - dataoff - matchoff + 2;
|
||||
|
||||
/* Now, update SDP lenght */
|
||||
if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
|
||||
&matchlen, POS_CONTENT) > 0) {
|
||||
|
||||
bufflen = sprintf(buffer, "%u", c_len);
|
||||
|
||||
return ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
|
||||
matchoff, matchlen,
|
||||
buffer, bufflen);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int mangle_sdp(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack *ct,
|
||||
__be32 newip, u_int16_t port,
|
||||
const char *dptr)
|
||||
{
|
||||
char buffer[sizeof("nnn.nnn.nnn.nnn")];
|
||||
unsigned int dataoff, bufflen;
|
||||
|
||||
dataoff = ip_hdrlen(*pskb) + sizeof(struct udphdr);
|
||||
|
||||
/* Mangle owner and contact info. */
|
||||
bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
|
||||
if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
|
||||
buffer, bufflen, POS_OWNER))
|
||||
return 0;
|
||||
|
||||
if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
|
||||
buffer, bufflen, POS_CONNECTION))
|
||||
return 0;
|
||||
|
||||
/* Mangle media port. */
|
||||
bufflen = sprintf(buffer, "%u", port);
|
||||
if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
|
||||
buffer, bufflen, POS_MEDIA))
|
||||
return 0;
|
||||
|
||||
return mangle_content_len(pskb, ctinfo, ct, dptr);
|
||||
}
|
||||
|
||||
/* So, this packet has hit the connection tracking matching code.
|
||||
Mangle it, and change the expectation to match the new version. */
|
||||
static unsigned int ip_nat_sdp(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack_expect *exp,
|
||||
const char *dptr)
|
||||
{
|
||||
struct ip_conntrack *ct = exp->master;
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
__be32 newip;
|
||||
u_int16_t port;
|
||||
|
||||
DEBUGP("ip_nat_sdp():\n");
|
||||
|
||||
/* Connection will come from reply */
|
||||
newip = ct->tuplehash[!dir].tuple.dst.ip;
|
||||
|
||||
exp->tuple.dst.ip = newip;
|
||||
exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* When you see the packet, we need to NAT it the same as the
|
||||
this one. */
|
||||
exp->expectfn = ip_nat_follow_master;
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
|
||||
exp->tuple.dst.u.udp.port = htons(port);
|
||||
if (ip_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (port == 0)
|
||||
return NF_DROP;
|
||||
|
||||
if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) {
|
||||
ip_conntrack_unexpect_related(exp);
|
||||
return NF_DROP;
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
rcu_assign_pointer(ip_nat_sip_hook, NULL);
|
||||
rcu_assign_pointer(ip_nat_sdp_hook, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
BUG_ON(rcu_dereference(ip_nat_sip_hook));
|
||||
BUG_ON(rcu_dereference(ip_nat_sdp_hook));
|
||||
rcu_assign_pointer(ip_nat_sip_hook, ip_nat_sip);
|
||||
rcu_assign_pointer(ip_nat_sdp_hook, ip_nat_sdp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,387 +0,0 @@
|
|||
/* This file contains all the functions required for the standalone
|
||||
ip_nat module.
|
||||
|
||||
These are not required by the compatibility layer.
|
||||
*/
|
||||
|
||||
/* (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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 23 Apr 2001: Harald Welte <laforge@gnumonks.org>
|
||||
* - new API and handling of conntrack/nat helpers
|
||||
* - now capable of multiple expectations for one master
|
||||
* */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/checksum.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_nat.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_core.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XFRM
|
||||
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
struct ip_conntrack_tuple *t;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
enum ip_conntrack_dir dir;
|
||||
unsigned long statusbit;
|
||||
|
||||
ct = ip_conntrack_get(skb, &ctinfo);
|
||||
if (ct == NULL)
|
||||
return;
|
||||
dir = CTINFO2DIR(ctinfo);
|
||||
t = &ct->tuplehash[dir].tuple;
|
||||
|
||||
if (dir == IP_CT_DIR_ORIGINAL)
|
||||
statusbit = IPS_DST_NAT;
|
||||
else
|
||||
statusbit = IPS_SRC_NAT;
|
||||
|
||||
if (ct->status & statusbit) {
|
||||
fl->fl4_dst = t->dst.ip;
|
||||
if (t->dst.protonum == IPPROTO_TCP ||
|
||||
t->dst.protonum == IPPROTO_UDP)
|
||||
fl->fl_ip_dport = t->dst.u.tcp.port;
|
||||
}
|
||||
|
||||
statusbit ^= IPS_NAT_MASK;
|
||||
|
||||
if (ct->status & statusbit) {
|
||||
fl->fl4_src = t->src.ip;
|
||||
if (t->dst.protonum == IPPROTO_TCP ||
|
||||
t->dst.protonum == IPPROTO_UDP)
|
||||
fl->fl_ip_sport = t->src.u.tcp.port;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned int
|
||||
ip_nat_fn(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct ip_nat_info *info;
|
||||
/* maniptype == SRC for postrouting. */
|
||||
enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
|
||||
|
||||
/* We never see fragments: conntrack defrags on pre-routing
|
||||
and local-out, and ip_nat_out protects post-routing. */
|
||||
IP_NF_ASSERT(!(ip_hdr(*pskb)->frag_off
|
||||
& htons(IP_MF|IP_OFFSET)));
|
||||
|
||||
ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
/* Can't track? It's not due to stress, or conntrack would
|
||||
have dropped it. Hence it's the user's responsibilty to
|
||||
packet filter it out, or implement conntrack/NAT for that
|
||||
protocol. 8) --RR */
|
||||
if (!ct) {
|
||||
/* Exception: ICMP redirect to new connection (not in
|
||||
hash table yet). We must not let this through, in
|
||||
case we're doing NAT to the same network. */
|
||||
if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) {
|
||||
struct icmphdr _hdr, *hp;
|
||||
|
||||
hp = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
|
||||
sizeof(_hdr), &_hdr);
|
||||
if (hp != NULL &&
|
||||
hp->type == ICMP_REDIRECT)
|
||||
return NF_DROP;
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* Don't try to NAT if this packet is not conntracked */
|
||||
if (ct == &ip_conntrack_untracked)
|
||||
return NF_ACCEPT;
|
||||
|
||||
switch (ctinfo) {
|
||||
case IP_CT_RELATED:
|
||||
case IP_CT_RELATED+IP_CT_IS_REPLY:
|
||||
if (ip_hdr(*pskb)->protocol == IPPROTO_ICMP) {
|
||||
if (!ip_nat_icmp_reply_translation(ct, ctinfo,
|
||||
hooknum, pskb))
|
||||
return NF_DROP;
|
||||
else
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
|
||||
case IP_CT_NEW:
|
||||
info = &ct->nat.info;
|
||||
|
||||
/* Seen it before? This can happen for loopback, retrans,
|
||||
or local packets.. */
|
||||
if (!ip_nat_initialized(ct, maniptype)) {
|
||||
unsigned int ret;
|
||||
|
||||
if (unlikely(is_confirmed(ct)))
|
||||
/* NAT module was loaded late */
|
||||
ret = alloc_null_binding_confirmed(ct, info,
|
||||
hooknum);
|
||||
else if (hooknum == NF_IP_LOCAL_IN)
|
||||
/* LOCAL_IN hook doesn't have a chain! */
|
||||
ret = alloc_null_binding(ct, info, hooknum);
|
||||
else
|
||||
ret = ip_nat_rule_find(pskb, hooknum,
|
||||
in, out, ct,
|
||||
info);
|
||||
|
||||
if (ret != NF_ACCEPT) {
|
||||
return ret;
|
||||
}
|
||||
} else
|
||||
DEBUGP("Already setup manip %s for ct %p\n",
|
||||
maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
|
||||
ct);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* ESTABLISHED */
|
||||
IP_NF_ASSERT(ctinfo == IP_CT_ESTABLISHED
|
||||
|| ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
|
||||
info = &ct->nat.info;
|
||||
}
|
||||
|
||||
IP_NF_ASSERT(info);
|
||||
return ip_nat_packet(ct, ctinfo, hooknum, pskb);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
ip_nat_in(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
unsigned int ret;
|
||||
__be32 daddr = ip_hdr(*pskb)->daddr;
|
||||
|
||||
ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
|
||||
if (ret != NF_DROP && ret != NF_STOLEN
|
||||
&& daddr != ip_hdr(*pskb)->daddr) {
|
||||
dst_release((*pskb)->dst);
|
||||
(*pskb)->dst = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
ip_nat_out(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
#ifdef CONFIG_XFRM
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
#endif
|
||||
unsigned int ret;
|
||||
|
||||
/* root is playing with raw sockets. */
|
||||
if ((*pskb)->len < sizeof(struct iphdr)
|
||||
|| ip_hdrlen(*pskb) < sizeof(struct iphdr))
|
||||
return NF_ACCEPT;
|
||||
|
||||
ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
|
||||
#ifdef CONFIG_XFRM
|
||||
if (ret != NF_DROP && ret != NF_STOLEN
|
||||
&& (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
|
||||
if (ct->tuplehash[dir].tuple.src.ip !=
|
||||
ct->tuplehash[!dir].tuple.dst.ip
|
||||
|| ct->tuplehash[dir].tuple.src.u.all !=
|
||||
ct->tuplehash[!dir].tuple.dst.u.all
|
||||
)
|
||||
return ip_xfrm_me_harder(pskb) == 0 ? ret : NF_DROP;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
ip_nat_local_fn(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
unsigned int ret;
|
||||
|
||||
/* root is playing with raw sockets. */
|
||||
if ((*pskb)->len < sizeof(struct iphdr)
|
||||
|| ip_hdrlen(*pskb) < sizeof(struct iphdr))
|
||||
return NF_ACCEPT;
|
||||
|
||||
ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
|
||||
if (ret != NF_DROP && ret != NF_STOLEN
|
||||
&& (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
|
||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||
|
||||
if (ct->tuplehash[dir].tuple.dst.ip !=
|
||||
ct->tuplehash[!dir].tuple.src.ip) {
|
||||
if (ip_route_me_harder(pskb, RTN_UNSPEC))
|
||||
ret = NF_DROP;
|
||||
}
|
||||
#ifdef CONFIG_XFRM
|
||||
else if (ct->tuplehash[dir].tuple.dst.u.all !=
|
||||
ct->tuplehash[!dir].tuple.src.u.all)
|
||||
if (ip_xfrm_me_harder(pskb))
|
||||
ret = NF_DROP;
|
||||
#endif
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
ip_nat_adjust(unsigned int hooknum,
|
||||
struct sk_buff **pskb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
|
||||
ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
|
||||
DEBUGP("ip_nat_standalone: adjusting sequence number\n");
|
||||
if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
|
||||
return NF_DROP;
|
||||
}
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
/* We must be after connection tracking and before packet filtering. */
|
||||
|
||||
static struct nf_hook_ops ip_nat_ops[] = {
|
||||
/* Before packet filtering, change destination */
|
||||
{
|
||||
.hook = ip_nat_in,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_PRE_ROUTING,
|
||||
.priority = NF_IP_PRI_NAT_DST,
|
||||
},
|
||||
/* After packet filtering, change source */
|
||||
{
|
||||
.hook = ip_nat_out,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_POST_ROUTING,
|
||||
.priority = NF_IP_PRI_NAT_SRC,
|
||||
},
|
||||
/* After conntrack, adjust sequence number */
|
||||
{
|
||||
.hook = ip_nat_adjust,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_POST_ROUTING,
|
||||
.priority = NF_IP_PRI_NAT_SEQ_ADJUST,
|
||||
},
|
||||
/* Before packet filtering, change destination */
|
||||
{
|
||||
.hook = ip_nat_local_fn,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_LOCAL_OUT,
|
||||
.priority = NF_IP_PRI_NAT_DST,
|
||||
},
|
||||
/* After packet filtering, change source */
|
||||
{
|
||||
.hook = ip_nat_fn,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_LOCAL_IN,
|
||||
.priority = NF_IP_PRI_NAT_SRC,
|
||||
},
|
||||
/* After conntrack, adjust sequence number */
|
||||
{
|
||||
.hook = ip_nat_adjust,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_IP_LOCAL_IN,
|
||||
.priority = NF_IP_PRI_NAT_SEQ_ADJUST,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ip_nat_standalone_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
need_conntrack();
|
||||
|
||||
#ifdef CONFIG_XFRM
|
||||
BUG_ON(ip_nat_decode_session != NULL);
|
||||
ip_nat_decode_session = nat_decode_session;
|
||||
#endif
|
||||
ret = ip_nat_rule_init();
|
||||
if (ret < 0) {
|
||||
printk("ip_nat_init: can't setup rules.\n");
|
||||
goto cleanup_decode_session;
|
||||
}
|
||||
ret = nf_register_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops));
|
||||
if (ret < 0) {
|
||||
printk("ip_nat_init: can't register hooks.\n");
|
||||
goto cleanup_rule_init;
|
||||
}
|
||||
return ret;
|
||||
|
||||
cleanup_rule_init:
|
||||
ip_nat_rule_cleanup();
|
||||
cleanup_decode_session:
|
||||
#ifdef CONFIG_XFRM
|
||||
ip_nat_decode_session = NULL;
|
||||
synchronize_net();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ip_nat_standalone_fini(void)
|
||||
{
|
||||
nf_unregister_hooks(ip_nat_ops, ARRAY_SIZE(ip_nat_ops));
|
||||
ip_nat_rule_cleanup();
|
||||
#ifdef CONFIG_XFRM
|
||||
ip_nat_decode_session = NULL;
|
||||
synchronize_net();
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(ip_nat_standalone_init);
|
||||
module_exit(ip_nat_standalone_fini);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,70 +0,0 @@
|
|||
/* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Version: 0.0.7
|
||||
*
|
||||
* Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org>
|
||||
* - Port to newnat API
|
||||
*
|
||||
* This module currently supports DNAT:
|
||||
* iptables -t nat -A PREROUTING -d x.x.x.x -j DNAT --to-dest x.x.x.y
|
||||
*
|
||||
* and SNAT:
|
||||
* iptables -t nat -A POSTROUTING { -j MASQUERADE , -j SNAT --to-source x.x.x.x }
|
||||
*
|
||||
* It has not been tested with
|
||||
* -j SNAT --to-source x.x.x.x-x.x.x.y since I only have one external ip
|
||||
* If you do test this please let me know if it works or not.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_tftp.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_helper.h>
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
||||
MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
|
||||
MODULE_DESCRIPTION("tftp NAT helper");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int help(struct sk_buff **pskb,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
struct ip_conntrack_expect *exp)
|
||||
{
|
||||
struct ip_conntrack *ct = exp->master;
|
||||
|
||||
exp->saved_proto.udp.port
|
||||
= ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
|
||||
exp->dir = IP_CT_DIR_REPLY;
|
||||
exp->expectfn = ip_nat_follow_master;
|
||||
if (ip_conntrack_expect_related(exp) != 0)
|
||||
return NF_DROP;
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static void __exit ip_nat_tftp_fini(void)
|
||||
{
|
||||
rcu_assign_pointer(ip_nat_tftp_hook, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static int __init ip_nat_tftp_init(void)
|
||||
{
|
||||
BUG_ON(rcu_dereference(ip_nat_tftp_hook));
|
||||
rcu_assign_pointer(ip_nat_tftp_hook, help);
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(ip_nat_tftp_init);
|
||||
module_exit(ip_nat_tftp_fini);
|
|
@ -21,15 +21,12 @@
|
|||
#include <linux/if_arp.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <net/checksum.h>
|
||||
|
||||
#include <linux/netfilter_arp.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/checksum.h>
|
||||
|
||||
#define CLUSTERIP_VERSION "0.8"
|
||||
|
||||
|
@ -310,15 +307,16 @@ target(struct sk_buff **pskb,
|
|||
const void *targinfo)
|
||||
{
|
||||
const struct ipt_clusterip_tgt_info *cipinfo = targinfo;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
u_int32_t *mark, hash;
|
||||
u_int32_t 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() */
|
||||
|
||||
mark = nf_ct_get_mark((*pskb), &ctinfo);
|
||||
if (mark == NULL) {
|
||||
ct = nf_ct_get(*pskb, &ctinfo);
|
||||
if (ct == NULL) {
|
||||
printk(KERN_ERR "CLUSTERIP: no conntrack!\n");
|
||||
/* FIXME: need to drop invalid ones, since replies
|
||||
* to outgoing connections of other nodes will be
|
||||
|
@ -341,7 +339,7 @@ target(struct sk_buff **pskb,
|
|||
|
||||
switch (ctinfo) {
|
||||
case IP_CT_NEW:
|
||||
*mark = hash;
|
||||
ct->mark = hash;
|
||||
break;
|
||||
case IP_CT_RELATED:
|
||||
case IP_CT_RELATED+IP_CT_IS_REPLY:
|
||||
|
@ -358,7 +356,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, *mark);
|
||||
DEBUGP("hash=%u ct_hash=%u ", hash, ct->mark);
|
||||
if (!clusterip_responsible(cipinfo->config, hash)) {
|
||||
DEBUGP("not responsible\n");
|
||||
return NF_DROP;
|
||||
|
|
|
@ -19,12 +19,8 @@
|
|||
#include <net/ip.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/route.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#include <net/netfilter/nf_nat_rule.h>
|
||||
#else
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#endif
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -48,7 +44,7 @@ masquerade_check(const char *tablename,
|
|||
void *targinfo,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ip_nat_multi_range_compat *mr = targinfo;
|
||||
const struct nf_nat_multi_range_compat *mr = targinfo;
|
||||
|
||||
if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
|
||||
DEBUGP("masquerade_check: bad MAP_IPS.\n");
|
||||
|
@ -69,33 +65,26 @@ masquerade_target(struct sk_buff **pskb,
|
|||
const struct xt_target *target,
|
||||
const void *targinfo)
|
||||
{
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
struct nf_conn *ct;
|
||||
struct nf_conn_nat *nat;
|
||||
#endif
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct ip_nat_range newrange;
|
||||
const struct ip_nat_multi_range_compat *mr;
|
||||
struct nf_nat_range newrange;
|
||||
const struct nf_nat_multi_range_compat *mr;
|
||||
struct rtable *rt;
|
||||
__be32 newsrc;
|
||||
|
||||
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
|
||||
NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING);
|
||||
|
||||
ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
ct = nf_ct_get(*pskb, &ctinfo);
|
||||
nat = nfct_nat(ct);
|
||||
#endif
|
||||
IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
|
||||
|
||||
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
|
||||
|| ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
|
||||
|
||||
/* Source address is 0.0.0.0 - locally generated packet that is
|
||||
* probably not supposed to be masqueraded.
|
||||
*/
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0)
|
||||
#else
|
||||
if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0)
|
||||
#endif
|
||||
return NF_ACCEPT;
|
||||
|
||||
mr = targinfo;
|
||||
|
@ -107,40 +96,30 @@ masquerade_target(struct sk_buff **pskb,
|
|||
}
|
||||
|
||||
write_lock_bh(&masq_lock);
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
nat->masq_index = out->ifindex;
|
||||
#else
|
||||
ct->nat.masq_index = out->ifindex;
|
||||
#endif
|
||||
write_unlock_bh(&masq_lock);
|
||||
|
||||
/* Transfer from original range. */
|
||||
newrange = ((struct ip_nat_range)
|
||||
newrange = ((struct nf_nat_range)
|
||||
{ mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
|
||||
newsrc, newsrc,
|
||||
mr->range[0].min, mr->range[0].max });
|
||||
|
||||
/* Hand modified range to generic setup. */
|
||||
return ip_nat_setup_info(ct, &newrange, hooknum);
|
||||
return nf_nat_setup_info(ct, &newrange, hooknum);
|
||||
}
|
||||
|
||||
static inline int
|
||||
device_cmp(struct ip_conntrack *i, void *ifindex)
|
||||
device_cmp(struct nf_conn *i, void *ifindex)
|
||||
{
|
||||
int ret;
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
struct nf_conn_nat *nat = nfct_nat(i);
|
||||
int ret;
|
||||
|
||||
if (!nat)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
read_lock_bh(&masq_lock);
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
ret = (nat->masq_index == (int)(long)ifindex);
|
||||
#else
|
||||
ret = (i->nat.masq_index == (int)(long)ifindex);
|
||||
#endif
|
||||
read_unlock_bh(&masq_lock);
|
||||
|
||||
return ret;
|
||||
|
@ -156,9 +135,9 @@ static int masq_device_event(struct notifier_block *this,
|
|||
/* Device was downed. Search entire table for
|
||||
conntracks which were associated with that device,
|
||||
and forget them. */
|
||||
IP_NF_ASSERT(dev->ifindex != 0);
|
||||
NF_CT_ASSERT(dev->ifindex != 0);
|
||||
|
||||
ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
|
||||
nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
|
@ -174,9 +153,9 @@ static int masq_inet_event(struct notifier_block *this,
|
|||
/* IP address was deleted. Search entire table for
|
||||
conntracks which were associated with that device,
|
||||
and forget them. */
|
||||
IP_NF_ASSERT(dev->ifindex != 0);
|
||||
NF_CT_ASSERT(dev->ifindex != 0);
|
||||
|
||||
ip_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
|
||||
nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
|
||||
}
|
||||
|
||||
return NOTIFY_DONE;
|
||||
|
@ -194,7 +173,7 @@ static struct xt_target masquerade = {
|
|||
.name = "MASQUERADE",
|
||||
.family = AF_INET,
|
||||
.target = masquerade_target,
|
||||
.targetsize = sizeof(struct ip_nat_multi_range_compat),
|
||||
.targetsize = sizeof(struct nf_nat_multi_range_compat),
|
||||
.table = "nat",
|
||||
.hooks = 1 << NF_IP_POST_ROUTING,
|
||||
.checkentry = masquerade_check,
|
||||
|
|
|
@ -16,11 +16,7 @@
|
|||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#include <net/netfilter/nf_nat_rule.h>
|
||||
#else
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#endif
|
||||
|
||||
#define MODULENAME "NETMAP"
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -40,7 +36,7 @@ check(const char *tablename,
|
|||
void *targinfo,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ip_nat_multi_range_compat *mr = targinfo;
|
||||
const struct nf_nat_multi_range_compat *mr = targinfo;
|
||||
|
||||
if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
|
||||
DEBUGP(MODULENAME":check: bad MAP_IPS.\n");
|
||||
|
@ -61,16 +57,16 @@ target(struct sk_buff **pskb,
|
|||
const struct xt_target *target,
|
||||
const void *targinfo)
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
__be32 new_ip, netmask;
|
||||
const struct ip_nat_multi_range_compat *mr = targinfo;
|
||||
struct ip_nat_range newrange;
|
||||
const struct nf_nat_multi_range_compat *mr = targinfo;
|
||||
struct nf_nat_range newrange;
|
||||
|
||||
IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
|
||||
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING
|
||||
|| hooknum == NF_IP_POST_ROUTING
|
||||
|| hooknum == NF_IP_LOCAL_OUT);
|
||||
ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
ct = nf_ct_get(*pskb, &ctinfo);
|
||||
|
||||
netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
|
||||
|
||||
|
@ -80,20 +76,20 @@ target(struct sk_buff **pskb,
|
|||
new_ip = ip_hdr(*pskb)->saddr & ~netmask;
|
||||
new_ip |= mr->range[0].min_ip & netmask;
|
||||
|
||||
newrange = ((struct ip_nat_range)
|
||||
newrange = ((struct nf_nat_range)
|
||||
{ mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
|
||||
new_ip, new_ip,
|
||||
mr->range[0].min, mr->range[0].max });
|
||||
|
||||
/* Hand modified range to generic setup. */
|
||||
return ip_nat_setup_info(ct, &newrange, hooknum);
|
||||
return nf_nat_setup_info(ct, &newrange, hooknum);
|
||||
}
|
||||
|
||||
static struct xt_target target_module = {
|
||||
.name = MODULENAME,
|
||||
.family = AF_INET,
|
||||
.target = target,
|
||||
.targetsize = sizeof(struct ip_nat_multi_range_compat),
|
||||
.targetsize = sizeof(struct nf_nat_multi_range_compat),
|
||||
.table = "nat",
|
||||
.hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING) |
|
||||
(1 << NF_IP_LOCAL_OUT),
|
||||
|
|
|
@ -19,11 +19,7 @@
|
|||
#include <net/checksum.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#include <net/netfilter/nf_nat_rule.h>
|
||||
#else
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
|
||||
|
@ -43,7 +39,7 @@ redirect_check(const char *tablename,
|
|||
void *targinfo,
|
||||
unsigned int hook_mask)
|
||||
{
|
||||
const struct ip_nat_multi_range_compat *mr = targinfo;
|
||||
const struct nf_nat_multi_range_compat *mr = targinfo;
|
||||
|
||||
if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
|
||||
DEBUGP("redirect_check: bad MAP_IPS.\n");
|
||||
|
@ -64,17 +60,17 @@ redirect_target(struct sk_buff **pskb,
|
|||
const struct xt_target *target,
|
||||
const void *targinfo)
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
__be32 newdst;
|
||||
const struct ip_nat_multi_range_compat *mr = targinfo;
|
||||
struct ip_nat_range newrange;
|
||||
const struct nf_nat_multi_range_compat *mr = targinfo;
|
||||
struct nf_nat_range newrange;
|
||||
|
||||
IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
|
||||
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING
|
||||
|| hooknum == NF_IP_LOCAL_OUT);
|
||||
|
||||
ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
|
||||
ct = nf_ct_get(*pskb, &ctinfo);
|
||||
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
|
||||
|
||||
/* Local packets: make them go to loopback */
|
||||
if (hooknum == NF_IP_LOCAL_OUT)
|
||||
|
@ -96,20 +92,20 @@ redirect_target(struct sk_buff **pskb,
|
|||
}
|
||||
|
||||
/* Transfer from original range. */
|
||||
newrange = ((struct ip_nat_range)
|
||||
newrange = ((struct nf_nat_range)
|
||||
{ mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
|
||||
newdst, newdst,
|
||||
mr->range[0].min, mr->range[0].max });
|
||||
|
||||
/* Hand modified range to generic setup. */
|
||||
return ip_nat_setup_info(ct, &newrange, hooknum);
|
||||
return nf_nat_setup_info(ct, &newrange, hooknum);
|
||||
}
|
||||
|
||||
static struct xt_target redirect_reg = {
|
||||
.name = "REDIRECT",
|
||||
.family = AF_INET,
|
||||
.target = redirect_target,
|
||||
.targetsize = sizeof(struct ip_nat_multi_range_compat),
|
||||
.targetsize = sizeof(struct nf_nat_multi_range_compat),
|
||||
.table = "nat",
|
||||
.hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
|
||||
.checkentry = redirect_check,
|
||||
|
|
|
@ -35,11 +35,7 @@
|
|||
#include <net/checksum.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
#include <net/netfilter/nf_nat_rule.h>
|
||||
#else
|
||||
#include <linux/netfilter_ipv4/ip_nat_rule.h>
|
||||
#endif
|
||||
#include <linux/netfilter_ipv4/ipt_SAME.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -138,17 +134,17 @@ same_target(struct sk_buff **pskb,
|
|||
const struct xt_target *target,
|
||||
const void *targinfo)
|
||||
{
|
||||
struct ip_conntrack *ct;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
u_int32_t tmpip, aindex;
|
||||
__be32 new_ip;
|
||||
const struct ipt_same_info *same = targinfo;
|
||||
struct ip_nat_range newrange;
|
||||
const struct ip_conntrack_tuple *t;
|
||||
struct nf_nat_range newrange;
|
||||
const struct nf_conntrack_tuple *t;
|
||||
|
||||
IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
|
||||
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
|
||||
hooknum == NF_IP_POST_ROUTING);
|
||||
ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
ct = nf_ct_get(*pskb, &ctinfo);
|
||||
|
||||
t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
|
||||
|
||||
|
@ -157,17 +153,10 @@ same_target(struct sk_buff **pskb,
|
|||
Here we calculate the index in same->iparray which
|
||||
holds the ipaddress we should use */
|
||||
|
||||
#ifdef CONFIG_NF_NAT_NEEDED
|
||||
tmpip = ntohl(t->src.u3.ip);
|
||||
|
||||
if (!(same->info & IPT_SAME_NODST))
|
||||
tmpip += ntohl(t->dst.u3.ip);
|
||||
#else
|
||||
tmpip = ntohl(t->src.ip);
|
||||
|
||||
if (!(same->info & IPT_SAME_NODST))
|
||||
tmpip += ntohl(t->dst.ip);
|
||||
#endif
|
||||
aindex = tmpip % same->ipnum;
|
||||
|
||||
new_ip = htonl(same->iparray[aindex]);
|
||||
|
@ -178,13 +167,13 @@ same_target(struct sk_buff **pskb,
|
|||
NIPQUAD(new_ip));
|
||||
|
||||
/* Transfer from original range. */
|
||||
newrange = ((struct ip_nat_range)
|
||||
newrange = ((struct nf_nat_range)
|
||||
{ same->range[0].flags, new_ip, new_ip,
|
||||
/* FIXME: Use ports from correct range! */
|
||||
same->range[0].min, same->range[0].max });
|
||||
|
||||
/* Hand modified range to generic setup. */
|
||||
return ip_nat_setup_info(ct, &newrange, hooknum);
|
||||
return nf_nat_setup_info(ct, &newrange, hooknum);
|
||||
}
|
||||
|
||||
static struct xt_target same_reg = {
|
||||
|
|
|
@ -33,7 +33,7 @@ static int set_addr(struct sk_buff **pskb,
|
|||
unsigned int addroff, __be32 ip, __be16 port)
|
||||
{
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
struct nf_conn *ct = nf_ct_get(*pskb, &ctinfo);
|
||||
struct {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
|
@ -383,7 +383,7 @@ static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct,
|
|||
static void ip_nat_q931_expect(struct nf_conn *new,
|
||||
struct nf_conntrack_expect *this)
|
||||
{
|
||||
struct ip_nat_range range;
|
||||
struct nf_nat_range range;
|
||||
|
||||
if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */
|
||||
nf_nat_follow_master(new, this);
|
||||
|
|
|
@ -53,7 +53,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
|
|||
struct nf_conntrack_tuple t;
|
||||
struct nf_ct_pptp_master *ct_pptp_info;
|
||||
struct nf_nat_pptp *nat_pptp_info;
|
||||
struct ip_nat_range range;
|
||||
struct nf_nat_range range;
|
||||
|
||||
ct_pptp_info = &nfct_help(master)->help.ct_pptp_info;
|
||||
nat_pptp_info = &nfct_nat(master)->help.nat_pptp_info;
|
||||
|
|
|
@ -25,6 +25,7 @@ config NETFILTER_NETLINK_LOG
|
|||
and is also scheduled to replace the old syslog-based ipt_LOG
|
||||
and ip6t_LOG modules.
|
||||
|
||||
# Rename this to NF_CONNTRACK in a 2.6.25
|
||||
config NF_CONNTRACK_ENABLED
|
||||
tristate "Netfilter connection tracking support"
|
||||
help
|
||||
|
@ -39,42 +40,9 @@ config NF_CONNTRACK_ENABLED
|
|||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
choice
|
||||
prompt "Netfilter connection tracking support"
|
||||
depends on NF_CONNTRACK_ENABLED
|
||||
|
||||
config NF_CONNTRACK_SUPPORT
|
||||
bool "Layer 3 Independent Connection tracking"
|
||||
help
|
||||
Layer 3 independent connection tracking is experimental scheme
|
||||
which generalize ip_conntrack to support other layer 3 protocols.
|
||||
|
||||
This is required to do Masquerading or other kinds of Network
|
||||
Address Translation (except for Fast NAT). It can also be used to
|
||||
enhance packet filtering (see `Connection state match support'
|
||||
below).
|
||||
|
||||
config IP_NF_CONNTRACK_SUPPORT
|
||||
bool "Layer 3 Dependent Connection tracking (OBSOLETE)"
|
||||
help
|
||||
The old, Layer 3 dependent ip_conntrack subsystem of netfilter.
|
||||
|
||||
This is required to do Masquerading or other kinds of Network
|
||||
Address Translation (except for Fast NAT). It can also be used to
|
||||
enhance packet filtering (see `Connection state match support'
|
||||
below).
|
||||
|
||||
endchoice
|
||||
|
||||
config NF_CONNTRACK
|
||||
tristate
|
||||
default m if NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=m
|
||||
default y if NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=y
|
||||
|
||||
config IP_NF_CONNTRACK
|
||||
tristate
|
||||
default m if IP_NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=m
|
||||
default y if IP_NF_CONNTRACK_SUPPORT && NF_CONNTRACK_ENABLED=y
|
||||
default NF_CONNTRACK_ENABLED
|
||||
|
||||
config NF_CT_ACCT
|
||||
bool "Connection tracking flow accounting"
|
||||
|
@ -303,9 +271,8 @@ config NETFILTER_XT_TARGET_CONNMARK
|
|||
tristate '"CONNMARK" target support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_MANGLE || IP6_NF_MANGLE
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
select IP_NF_CONNTRACK_MARK if IP_NF_CONNTRACK
|
||||
select NF_CONNTRACK_MARK if NF_CONNTRACK
|
||||
depends on NF_CONNTRACK
|
||||
select NF_CONNTRACK_MARK
|
||||
help
|
||||
This option adds a `CONNMARK' target, which allows one to manipulate
|
||||
the connection mark value. Similar to the MARK target, but
|
||||
|
@ -366,7 +333,7 @@ config NETFILTER_XT_TARGET_NOTRACK
|
|||
tristate '"NOTRACK" target support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_RAW || IP6_NF_RAW
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
depends on NF_CONNTRACK
|
||||
help
|
||||
The NOTRACK target allows a select rule to specify
|
||||
which packets *not* to enter the conntrack/NAT
|
||||
|
@ -387,9 +354,7 @@ config NETFILTER_XT_TARGET_SECMARK
|
|||
|
||||
config NETFILTER_XT_TARGET_CONNSECMARK
|
||||
tristate '"CONNSECMARK" target support'
|
||||
depends on NETFILTER_XTABLES && \
|
||||
((NF_CONNTRACK && NF_CONNTRACK_SECMARK) || \
|
||||
(IP_NF_CONNTRACK && IP_NF_CONNTRACK_SECMARK))
|
||||
depends on NETFILTER_XTABLES && NF_CONNTRACK && NF_CONNTRACK_SECMARK
|
||||
help
|
||||
The CONNSECMARK target copies security markings from packets
|
||||
to connections, and restores security markings from connections
|
||||
|
@ -437,9 +402,8 @@ config NETFILTER_XT_MATCH_COMMENT
|
|||
config NETFILTER_XT_MATCH_CONNBYTES
|
||||
tristate '"connbytes" per-connection counter match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
select IP_NF_CT_ACCT if IP_NF_CONNTRACK
|
||||
select NF_CT_ACCT if NF_CONNTRACK
|
||||
depends on NF_CONNTRACK
|
||||
select NF_CT_ACCT
|
||||
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.
|
||||
|
@ -450,9 +414,8 @@ config NETFILTER_XT_MATCH_CONNBYTES
|
|||
config NETFILTER_XT_MATCH_CONNMARK
|
||||
tristate '"connmark" connection mark match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
select IP_NF_CONNTRACK_MARK if IP_NF_CONNTRACK
|
||||
select NF_CONNTRACK_MARK if NF_CONNTRACK
|
||||
depends on NF_CONNTRACK
|
||||
select NF_CONNTRACK_MARK
|
||||
help
|
||||
This option adds a `connmark' match, which allows you to match the
|
||||
connection mark value previously set for the session by `CONNMARK'.
|
||||
|
@ -464,7 +427,7 @@ config NETFILTER_XT_MATCH_CONNMARK
|
|||
config NETFILTER_XT_MATCH_CONNTRACK
|
||||
tristate '"conntrack" connection tracking match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
depends on NF_CONNTRACK
|
||||
help
|
||||
This is a general conntrack match module, a superset of the state match.
|
||||
|
||||
|
@ -508,7 +471,7 @@ config NETFILTER_XT_MATCH_ESP
|
|||
config NETFILTER_XT_MATCH_HELPER
|
||||
tristate '"helper" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
depends on NF_CONNTRACK
|
||||
help
|
||||
Helper matching allows you to match packets in dynamic connections
|
||||
tracked by a conntrack-helper, ie. ip_conntrack_ftp
|
||||
|
@ -632,7 +595,7 @@ config NETFILTER_XT_MATCH_SCTP
|
|||
config NETFILTER_XT_MATCH_STATE
|
||||
tristate '"state" match support'
|
||||
depends on NETFILTER_XTABLES
|
||||
depends on IP_NF_CONNTRACK || NF_CONNTRACK
|
||||
depends on NF_CONNTRACK
|
||||
help
|
||||
Connection state matching allows you to match packets based on their
|
||||
relationship to a tracked connection (ie. previous packets). This
|
||||
|
|
|
@ -30,10 +30,7 @@ MODULE_ALIAS("ipt_CONNMARK");
|
|||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_CONNMARK.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
|
||||
#include <net/netfilter/nf_conntrack_ecache.h>
|
||||
#endif
|
||||
|
||||
static unsigned int
|
||||
target(struct sk_buff **pskb,
|
||||
|
@ -44,40 +41,33 @@ target(struct sk_buff **pskb,
|
|||
const void *targinfo)
|
||||
{
|
||||
const struct xt_connmark_target_info *markinfo = targinfo;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
u_int32_t diff;
|
||||
u_int32_t mark;
|
||||
u_int32_t newmark;
|
||||
u_int32_t ctinfo;
|
||||
u_int32_t *ctmark = nf_ct_get_mark(*pskb, &ctinfo);
|
||||
|
||||
if (ctmark) {
|
||||
ct = nf_ct_get(*pskb, &ctinfo);
|
||||
if (ct) {
|
||||
switch(markinfo->mode) {
|
||||
case XT_CONNMARK_SET:
|
||||
newmark = (*ctmark & ~markinfo->mask) | markinfo->mark;
|
||||
if (newmark != *ctmark) {
|
||||
*ctmark = newmark;
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
|
||||
ip_conntrack_event_cache(IPCT_MARK, *pskb);
|
||||
#else
|
||||
newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
|
||||
if (newmark != ct->mark) {
|
||||
ct->mark = newmark;
|
||||
nf_conntrack_event_cache(IPCT_MARK, *pskb);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case XT_CONNMARK_SAVE:
|
||||
newmark = (*ctmark & ~markinfo->mask) |
|
||||
newmark = (ct->mark & ~markinfo->mask) |
|
||||
((*pskb)->mark & markinfo->mask);
|
||||
if (*ctmark != newmark) {
|
||||
*ctmark = newmark;
|
||||
#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
|
||||
ip_conntrack_event_cache(IPCT_MARK, *pskb);
|
||||
#else
|
||||
if (ct->mark != newmark) {
|
||||
ct->mark = newmark;
|
||||
nf_conntrack_event_cache(IPCT_MARK, *pskb);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case XT_CONNMARK_RESTORE:
|
||||
mark = (*pskb)->mark;
|
||||
diff = (*ctmark ^ mark) & markinfo->mask;
|
||||
diff = (ct->mark ^ mark) & markinfo->mask;
|
||||
(*pskb)->mark = mark ^ diff;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_CONNSECMARK.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
|
||||
#define PFX "CONNSECMARK: "
|
||||
|
||||
|
@ -36,12 +36,12 @@ MODULE_ALIAS("ip6t_CONNSECMARK");
|
|||
static void secmark_save(struct sk_buff *skb)
|
||||
{
|
||||
if (skb->secmark) {
|
||||
u32 *connsecmark;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
|
||||
connsecmark = nf_ct_get_secmark(skb, &ctinfo);
|
||||
if (connsecmark && !*connsecmark)
|
||||
*connsecmark = skb->secmark;
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (ct && !ct->secmark)
|
||||
ct->secmark = skb->secmark;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,12 +52,12 @@ static void secmark_save(struct sk_buff *skb)
|
|||
static void secmark_restore(struct sk_buff *skb)
|
||||
{
|
||||
if (!skb->secmark) {
|
||||
u32 *connsecmark;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
|
||||
connsecmark = nf_ct_get_secmark(skb, &ctinfo);
|
||||
if (connsecmark && *connsecmark)
|
||||
skb->secmark = *connsecmark;
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (ct && ct->secmark)
|
||||
skb->secmark = ct->secmark;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_NOTRACK");
|
||||
|
@ -26,7 +26,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 */
|
||||
nf_ct_untrack(*pskb);
|
||||
(*pskb)->nfct = &nf_conntrack_untracked.ct_general;
|
||||
(*pskb)->nfctinfo = IP_CT_NEW;
|
||||
nf_conntrack_get((*pskb)->nfct);
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_connbytes.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
#include <asm/bitops.h>
|
||||
|
@ -35,13 +35,17 @@ match(const struct sk_buff *skb,
|
|||
int *hotdrop)
|
||||
{
|
||||
const struct xt_connbytes_info *sinfo = matchinfo;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
u_int64_t what = 0; /* initialize to make gcc happy */
|
||||
u_int64_t bytes = 0;
|
||||
u_int64_t pkts = 0;
|
||||
const struct ip_conntrack_counter *counters;
|
||||
|
||||
if (!(counters = nf_ct_get_counters(skb)))
|
||||
return 0; /* no match */
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (!ct)
|
||||
return 0;
|
||||
counters = ct->counters;
|
||||
|
||||
switch (sinfo->what) {
|
||||
case XT_CONNBYTES_PKTS:
|
||||
|
|
|
@ -21,16 +21,15 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_connmark.h>
|
||||
|
||||
MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
|
||||
MODULE_DESCRIPTION("IP tables connmark match module");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_connmark");
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_connmark.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
|
@ -42,12 +41,14 @@ match(const struct sk_buff *skb,
|
|||
int *hotdrop)
|
||||
{
|
||||
const struct xt_connmark_info *info = matchinfo;
|
||||
u_int32_t ctinfo;
|
||||
const u_int32_t *ctmark = nf_ct_get_mark(skb, &ctinfo);
|
||||
if (!ctmark)
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (!ct)
|
||||
return 0;
|
||||
|
||||
return (((*ctmark) & info->mask) == info->mark) ^ info->invert;
|
||||
return (((ct->mark) & info->mask) == info->mark) ^ info->invert;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -10,121 +10,15 @@
|
|||
|
||||
#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/x_tables.h>
|
||||
#include <linux/netfilter/xt_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
|
||||
MODULE_DESCRIPTION("iptables connection tracking match module");
|
||||
MODULE_ALIAS("ipt_conntrack");
|
||||
|
||||
#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,
|
||||
const struct net_device *out,
|
||||
const struct xt_match *match,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_conntrack_info *sinfo = matchinfo;
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
unsigned int statebit;
|
||||
|
||||
ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
|
||||
|
||||
#define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & invflg))
|
||||
|
||||
if (ct == &ip_conntrack_untracked)
|
||||
statebit = XT_CONNTRACK_STATE_UNTRACKED;
|
||||
else if (ct)
|
||||
statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
|
||||
else
|
||||
statebit = XT_CONNTRACK_STATE_INVALID;
|
||||
|
||||
if (sinfo->flags & XT_CONNTRACK_STATE) {
|
||||
if (ct) {
|
||||
if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
|
||||
statebit |= XT_CONNTRACK_STATE_SNAT;
|
||||
if (test_bit(IPS_DST_NAT_BIT, &ct->status))
|
||||
statebit |= XT_CONNTRACK_STATE_DNAT;
|
||||
}
|
||||
if (FWINV((statebit & sinfo->statemask) == 0,
|
||||
XT_CONNTRACK_STATE))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ct == NULL) {
|
||||
if (sinfo->flags & ~XT_CONNTRACK_STATE)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sinfo->flags & XT_CONNTRACK_PROTO &&
|
||||
FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum !=
|
||||
sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum,
|
||||
XT_CONNTRACK_PROTO))
|
||||
return 0;
|
||||
|
||||
if (sinfo->flags & XT_CONNTRACK_ORIGSRC &&
|
||||
FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip &
|
||||
sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
|
||||
sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
|
||||
XT_CONNTRACK_ORIGSRC))
|
||||
return 0;
|
||||
|
||||
if (sinfo->flags & XT_CONNTRACK_ORIGDST &&
|
||||
FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip &
|
||||
sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
|
||||
sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
|
||||
XT_CONNTRACK_ORIGDST))
|
||||
return 0;
|
||||
|
||||
if (sinfo->flags & XT_CONNTRACK_REPLSRC &&
|
||||
FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip &
|
||||
sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) !=
|
||||
sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
|
||||
XT_CONNTRACK_REPLSRC))
|
||||
return 0;
|
||||
|
||||
if (sinfo->flags & XT_CONNTRACK_REPLDST &&
|
||||
FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip &
|
||||
sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) !=
|
||||
sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
|
||||
XT_CONNTRACK_REPLDST))
|
||||
return 0;
|
||||
|
||||
if (sinfo->flags & XT_CONNTRACK_STATUS &&
|
||||
FWINV((ct->status & sinfo->statusmask) == 0,
|
||||
XT_CONNTRACK_STATUS))
|
||||
return 0;
|
||||
|
||||
if (sinfo->flags & XT_CONNTRACK_EXPIRES) {
|
||||
unsigned long expires = timer_pending(&ct->timeout) ?
|
||||
(ct->timeout.expires - jiffies)/HZ : 0;
|
||||
|
||||
if (FWINV(!(expires >= sinfo->expires_min &&
|
||||
expires <= sinfo->expires_max),
|
||||
XT_CONNTRACK_EXPIRES))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else /* CONFIG_IP_NF_CONNTRACK */
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
|
@ -220,8 +114,6 @@ match(const struct sk_buff *skb,
|
|||
return 1;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NF_IP_CONNTRACK */
|
||||
|
||||
static int
|
||||
checkentry(const char *tablename,
|
||||
const void *ip,
|
||||
|
|
|
@ -13,18 +13,11 @@
|
|||
#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/x_tables.h>
|
||||
#include <linux/netfilter/xt_helper.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Martin Josefsson <gandalf@netfilter.org>");
|
||||
|
@ -38,55 +31,6 @@ MODULE_ALIAS("ip6t_helper");
|
|||
#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,
|
||||
const struct net_device *out,
|
||||
const struct xt_match *match,
|
||||
const void *matchinfo,
|
||||
int offset,
|
||||
unsigned int protoff,
|
||||
int *hotdrop)
|
||||
{
|
||||
const struct xt_helper_info *info = matchinfo;
|
||||
struct ip_conntrack *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
int ret = info->invert;
|
||||
|
||||
ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
|
||||
if (!ct) {
|
||||
DEBUGP("xt_helper: Eek! invalid conntrack?\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ct->master) {
|
||||
DEBUGP("xt_helper: conntrack %p has no master\n", ct);
|
||||
return ret;
|
||||
}
|
||||
|
||||
read_lock_bh(&ip_conntrack_lock);
|
||||
if (!ct->master->helper) {
|
||||
DEBUGP("xt_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(&ip_conntrack_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else /* CONFIG_IP_NF_CONNTRACK */
|
||||
|
||||
static int
|
||||
match(const struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
|
@ -134,7 +78,6 @@ out_unlock:
|
|||
read_unlock_bh(&nf_conntrack_lock);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int check(const char *tablename,
|
||||
const void *inf,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/netfilter/nf_conntrack_compat.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_state.h>
|
||||
|
||||
|
@ -36,7 +36,7 @@ match(const struct sk_buff *skb,
|
|||
|
||||
if (nf_ct_is_untracked(skb))
|
||||
statebit = XT_STATE_UNTRACKED;
|
||||
else if (!nf_ct_get_ctinfo(skb, &ctinfo))
|
||||
else if (!nf_ct_get(skb, &ctinfo))
|
||||
statebit = XT_STATE_INVALID;
|
||||
else
|
||||
statebit = XT_STATE_BIT(ctinfo);
|
||||
|
|
Загрузка…
Ссылка в новой задаче