1
0
Fork 0

[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>
hifive-unleashed-5.1
Patrick McHardy 2007-03-14 16:37:25 -07:00 committed by David S. Miller
parent ce18afe57b
commit 587aa64163
80 changed files with 122 additions and 19135 deletions

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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*/

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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*/

View File

@ -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 */

View File

@ -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__ */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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*/

View File

@ -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 */

View File

@ -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*/

View File

@ -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;

View File

@ -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 */

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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);

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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,
};

View File

@ -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);

View File

@ -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
};

View File

@ -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");

File diff suppressed because it is too large Load Diff

View File

@ -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
};

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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
};

View File

@ -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
};

View File

@ -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
};

View File

@ -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,
};

View File

@ -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);
}

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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");

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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),

View File

@ -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,

View File

@ -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 = {

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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:

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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);