Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6

Conflicts:

	drivers/infiniband/core/iwcm.c
	drivers/net/chelsio/cxgb2.c
	drivers/net/wireless/bcm43xx/bcm43xx_main.c
	drivers/net/wireless/prism54/islpci_eth.c
	drivers/usb/core/hub.h
	drivers/usb/input/hid-core.c
	net/core/netpoll.c

Fix up merge failures with Linus's head and fix new compilation failures.

Signed-Off-By: David Howells <[email protected]>
This commit is contained in:
David Howells 2006-12-05 14:37:56 +00:00 • committed by David Howells
commit 4c1ac1b491
1476 changed files with 67631 additions and 41020 deletions

View file

@ -104,13 +104,6 @@ config IP_MULTIPLE_TABLES
If unsure, say N.
config IP_ROUTE_FWMARK
bool "IP: use netfilter MARK value as routing key"
depends on IP_MULTIPLE_TABLES && NETFILTER
help
If you say Y here, you will be able to specify different routes for
packets with different mark values (see iptables(8), MARK target).
config IP_ROUTE_MULTIPATH
bool "IP: equal cost multipath"
depends on IP_ADVANCED_ROUTER
@ -625,5 +618,17 @@ config DEFAULT_TCP_CONG
default "reno" if DEFAULT_RENO
default "cubic"
config TCP_MD5SIG
bool "TCP: MD5 Signature Option support (RFC2385) (EXPERIMENTAL)"
depends on EXPERIMENTAL
select CRYPTO
select CRYPTO_MD5
---help---
RFC2385 specifices a method of giving MD5 protection to TCP sessions.
Its main (only?) use is to protect BGP sessions between core routers
on the Internet.
If unsure, say N.
source "net/ipv4/ipvs/Kconfig"

View file

@ -8,7 +8,8 @@ obj-y := route.o inetpeer.o protocol.o \
inet_timewait_sock.o inet_connection_sock.o \
tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
tcp_minisocks.o tcp_cong.o \
datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
datagram.o raw.o udp.o udplite.o \
arp.o icmp.o devinet.o af_inet.o igmp.o \
sysctl_net_ipv4.o fib_frontend.o fib_semantics.o
obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o

View file

@ -104,6 +104,7 @@
#include <net/inet_connection_sock.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <net/udplite.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/raw.h>
@ -204,7 +205,7 @@ int inet_listen(struct socket *sock, int backlog)
* we can only allow the backlog to be adjusted.
*/
if (old_state != TCP_LISTEN) {
err = inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
err = inet_csk_listen_start(sk, backlog);
if (err)
goto out;
}
@ -643,7 +644,7 @@ int inet_getname(struct socket *sock, struct sockaddr *uaddr,
sin->sin_port = inet->dport;
sin->sin_addr.s_addr = inet->daddr;
} else {
__u32 addr = inet->rcv_saddr;
__be32 addr = inet->rcv_saddr;
if (!addr)
addr = inet->saddr;
sin->sin_port = inet->sport;
@ -994,8 +995,8 @@ static int inet_sk_reselect_saddr(struct sock *sk)
struct inet_sock *inet = inet_sk(sk);
int err;
struct rtable *rt;
__u32 old_saddr = inet->saddr;
__u32 new_saddr;
__be32 old_saddr = inet->saddr;
__be32 new_saddr;
__be32 daddr = inet->daddr;
if (inet->opt && inet->opt->srr)
@ -1223,10 +1224,13 @@ static int __init init_ipv4_mibs(void)
tcp_statistics[1] = alloc_percpu(struct tcp_mib);
udp_statistics[0] = alloc_percpu(struct udp_mib);
udp_statistics[1] = alloc_percpu(struct udp_mib);
udplite_statistics[0] = alloc_percpu(struct udp_mib);
udplite_statistics[1] = alloc_percpu(struct udp_mib);
if (!
(net_statistics[0] && net_statistics[1] && ip_statistics[0]
&& ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1]
&& udp_statistics[0] && udp_statistics[1]))
&& udp_statistics[0] && udp_statistics[1]
&& udplite_statistics[0] && udplite_statistics[1] ) )
return -ENOMEM;
(void) tcp_mib_init();
@ -1313,6 +1317,8 @@ static int __init inet_init(void)
/* Setup TCP slab cache for open requests. */
tcp_init();
/* Add UDP-Lite (RFC 3828) */
udplite4_register();
/*
* Set the ICMP layer up

View file

@ -14,7 +14,7 @@
* into IP header for icv calculation. Options are already checked
* for validity, so paranoia is not required. */
static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr)
static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr)
{
unsigned char * optptr = (unsigned char*)(iph+1);
int l = iph->ihl*4 - sizeof(struct iphdr);
@ -162,7 +162,7 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
iph->frag_off = 0;
iph->check = 0;
if (ihl > sizeof(*iph)) {
u32 dummy;
__be32 dummy;
if (ip_clear_mutable_options(iph, &dummy))
goto out;
}

View file

@ -203,7 +203,7 @@ struct neigh_table arp_tbl = {
.gc_thresh3 = 1024,
};
int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir)
int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir)
{
switch (dev->type) {
case ARPHRD_ETHER:

File diff suppressed because it is too large Load diff

View file

@ -577,20 +577,20 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
* Determine a default network mask, based on the IP address.
*/
static __inline__ int inet_abc_len(u32 addr)
static __inline__ int inet_abc_len(__be32 addr)
{
int rc = -1; /* Something else, probably a multicast. */
if (ZERONET(addr))
rc = 0;
else {
addr = ntohl(addr);
__u32 haddr = ntohl(addr);
if (IN_CLASSA(addr))
if (IN_CLASSA(haddr))
rc = 8;
else if (IN_CLASSB(addr))
else if (IN_CLASSB(haddr))
rc = 16;
else if (IN_CLASSC(addr))
else if (IN_CLASSC(haddr))
rc = 24;
}
@ -1120,6 +1120,16 @@ static struct notifier_block ip_netdev_notifier = {
.notifier_call =inetdev_event,
};
static inline size_t inet_nlmsg_size(void)
{
return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
+ nla_total_size(4) /* IFA_ADDRESS */
+ nla_total_size(4) /* IFA_LOCAL */
+ nla_total_size(4) /* IFA_BROADCAST */
+ nla_total_size(4) /* IFA_ANYCAST */
+ nla_total_size(IFNAMSIZ); /* IFA_LABEL */
}
static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
u32 pid, u32 seq, int event, unsigned int flags)
{
@ -1208,15 +1218,13 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
u32 seq = nlh ? nlh->nlmsg_seq : 0;
int err = -ENOBUFS;
skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
if (skb == NULL)
goto errout;
err = inet_fill_ifaddr(skb, ifa, pid, seq, event, 0);
if (err < 0) {
kfree_skb(skb);
goto errout;
}
/* failure implies BUG in inet_nlmsg_size() */
BUG_ON(err < 0);
err = rtnl_notify(skb, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
errout:
@ -1556,12 +1564,12 @@ static void devinet_sysctl_register(struct in_device *in_dev,
{
int i;
struct net_device *dev = in_dev ? in_dev->dev : NULL;
struct devinet_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
struct devinet_sysctl_table *t = kmemdup(&devinet_sysctl, sizeof(*t),
GFP_KERNEL);
char *dev_name = NULL;
if (!t)
return;
memcpy(t, &devinet_sysctl, sizeof(*t));
for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
t->devinet_vars[i].de = NULL;

View file

@ -67,7 +67,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
if (x->encap) {
struct xfrm_encap_tmpl *encap = x->encap;
struct udphdr *uh;
u32 *udpdata32;
__be32 *udpdata32;
uh = (struct udphdr *)esph;
uh->source = encap->encap_sport;
@ -81,7 +81,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
esph = (struct ip_esp_hdr *)(uh + 1);
break;
case UDP_ENCAP_ESPINUDP_NON_IKE:
udpdata32 = (u32 *)(uh + 1);
udpdata32 = (__be32 *)(uh + 1);
udpdata32[0] = udpdata32[1] = 0;
esph = (struct ip_esp_hdr *)(udpdata32 + 2);
break;

View file

@ -768,8 +768,8 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
{
struct fib_result res;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = frn->fl_addr,
.fwmark = frn->fl_fwmark,
struct flowi fl = { .mark = frn->fl_mark,
.nl_u = { .ip4_u = { .daddr = frn->fl_addr,
.tos = frn->fl_tos,
.scope = frn->fl_scope } } };
if (tb) {
@ -811,7 +811,6 @@ static void nl_fib_input(struct sock *sk, int len)
pid = nlh->nlmsg_pid; /*pid of sending process */
NETLINK_CB(skb).pid = 0; /* from kernel */
NETLINK_CB(skb).dst_pid = pid;
NETLINK_CB(skb).dst_group = 0; /* unicast */
netlink_unicast(sk, skb, pid, MSG_DONTWAIT);
}

View file

@ -44,10 +44,6 @@ struct fib4_rule
__be32 srcmask;
__be32 dst;
__be32 dstmask;
#ifdef CONFIG_IP_ROUTE_FWMARK
u32 fwmark;
u32 fwmask;
#endif
#ifdef CONFIG_NET_CLS_ROUTE
u32 tclassid;
#endif
@ -160,11 +156,6 @@ static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
if (r->tos && (r->tos != fl->fl4_tos))
return 0;
#ifdef CONFIG_IP_ROUTE_FWMARK
if ((r->fwmark ^ fl->fl4_fwmark) & r->fwmask)
return 0;
#endif
return 1;
}
@ -179,14 +170,10 @@ static struct fib_table *fib_empty_table(void)
}
static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = {
[FRA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
[FRA_PRIORITY] = { .type = NLA_U32 },
FRA_GENERIC_POLICY,
[FRA_SRC] = { .type = NLA_U32 },
[FRA_DST] = { .type = NLA_U32 },
[FRA_FWMARK] = { .type = NLA_U32 },
[FRA_FWMASK] = { .type = NLA_U32 },
[FRA_FLOW] = { .type = NLA_U32 },
[FRA_TABLE] = { .type = NLA_U32 },
};
static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
@ -220,20 +207,6 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
if (tb[FRA_DST])
rule4->dst = nla_get_be32(tb[FRA_DST]);
#ifdef CONFIG_IP_ROUTE_FWMARK
if (tb[FRA_FWMARK]) {
rule4->fwmark = nla_get_u32(tb[FRA_FWMARK]);
if (rule4->fwmark)
/* compatibility: if the mark value is non-zero all bits
* are compared unless a mask is explicitly specified.
*/
rule4->fwmask = 0xFFFFFFFF;
}
if (tb[FRA_FWMASK])
rule4->fwmask = nla_get_u32(tb[FRA_FWMASK]);
#endif
#ifdef CONFIG_NET_CLS_ROUTE
if (tb[FRA_FLOW])
rule4->tclassid = nla_get_u32(tb[FRA_FLOW]);
@ -264,14 +237,6 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
if (frh->tos && (rule4->tos != frh->tos))
return 0;
#ifdef CONFIG_IP_ROUTE_FWMARK
if (tb[FRA_FWMARK] && (rule4->fwmark != nla_get_u32(tb[FRA_FWMARK])))
return 0;
if (tb[FRA_FWMASK] && (rule4->fwmask != nla_get_u32(tb[FRA_FWMASK])))
return 0;
#endif
#ifdef CONFIG_NET_CLS_ROUTE
if (tb[FRA_FLOW] && (rule4->tclassid != nla_get_u32(tb[FRA_FLOW])))
return 0;
@ -296,14 +261,6 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
frh->src_len = rule4->src_len;
frh->tos = rule4->tos;
#ifdef CONFIG_IP_ROUTE_FWMARK
if (rule4->fwmark)
NLA_PUT_U32(skb, FRA_FWMARK, rule4->fwmark);
if (rule4->fwmask || rule4->fwmark)
NLA_PUT_U32(skb, FRA_FWMASK, rule4->fwmask);
#endif
if (rule4->dst_len)
NLA_PUT_BE32(skb, FRA_DST, rule4->dst);
@ -342,6 +299,13 @@ static u32 fib4_rule_default_pref(void)
return 0;
}
static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
{
return nla_total_size(4) /* dst */
+ nla_total_size(4) /* src */
+ nla_total_size(4); /* flow */
}
static struct fib_rules_ops fib4_rules_ops = {
.family = AF_INET,
.rule_size = sizeof(struct fib4_rule),
@ -351,6 +315,7 @@ static struct fib_rules_ops fib4_rules_ops = {
.compare = fib4_rule_compare,
.fill = fib4_rule_fill,
.default_pref = fib4_rule_default_pref,
.nlmsg_payload = fib4_rule_nlmsg_payload,
.nlgroup = RTNLGRP_IPV4_RULE,
.policy = fib4_rule_policy,
.rules_list = &fib4_rules,

View file

@ -273,25 +273,49 @@ int ip_fib_check_default(__be32 gw, struct net_device *dev)
return -1;
}
static inline size_t fib_nlmsg_size(struct fib_info *fi)
{
size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg))
+ nla_total_size(4) /* RTA_TABLE */
+ nla_total_size(4) /* RTA_DST */
+ nla_total_size(4) /* RTA_PRIORITY */
+ nla_total_size(4); /* RTA_PREFSRC */
/* space for nested metrics */
payload += nla_total_size((RTAX_MAX * nla_total_size(4)));
if (fi->fib_nhs) {
/* Also handles the special case fib_nhs == 1 */
/* each nexthop is packed in an attribute */
size_t nhsize = nla_total_size(sizeof(struct rtnexthop));
/* may contain flow and gateway attribute */
nhsize += 2 * nla_total_size(4);
/* all nexthops are packed in a nested attribute */
payload += nla_total_size(fi->fib_nhs * nhsize);
}
return payload;
}
void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
int dst_len, u32 tb_id, struct nl_info *info)
{
struct sk_buff *skb;
int payload = sizeof(struct rtmsg) + 256;
u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0;
int err = -ENOBUFS;
skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL);
skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL);
if (skb == NULL)
goto errout;
err = fib_dump_info(skb, info->pid, seq, event, tb_id,
fa->fa_type, fa->fa_scope, key, dst_len,
fa->fa_tos, fa->fa_info, 0);
if (err < 0) {
kfree_skb(skb);
goto errout;
}
/* failure implies BUG in fib_nlmsg_size() */
BUG_ON(err < 0);
err = rtnl_notify(skb, info->pid, RTNLGRP_IPV4_ROUTE,
info->nlh, GFP_KERNEL);

View file

@ -332,7 +332,7 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
struct sk_buff *skb)
{
struct icmp_bxm *icmp_param = (struct icmp_bxm *)from;
unsigned int csum;
__wsum csum;
csum = skb_copy_and_csum_bits(icmp_param->skb,
icmp_param->offset + offset,
@ -356,7 +356,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
ip_flush_pending_frames(icmp_socket->sk);
else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) {
struct icmphdr *icmph = skb->h.icmph;
unsigned int csum = 0;
__wsum csum = 0;
struct sk_buff *skb1;
skb_queue_walk(&icmp_socket->sk->sk_write_queue, skb1) {
@ -931,7 +931,7 @@ int icmp_rcv(struct sk_buff *skb)
switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
if (!(u16)csum_fold(skb->csum))
if (!csum_fold(skb->csum))
break;
/* fall through */
case CHECKSUM_NONE:

View file

@ -932,7 +932,7 @@ int igmp_rcv(struct sk_buff *skb)
switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
if (!(u16)csum_fold(skb->csum))
if (!csum_fold(skb->csum))
break;
/* fall through */
case CHECKSUM_NONE:

View file

@ -343,7 +343,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk,
EXPORT_SYMBOL_GPL(inet_csk_route_req);
static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport,
const u32 rnd, const u16 synq_hsize)
const u32 rnd, const u32 synq_hsize)
{
return jhash_2words((__force u32)raddr, (__force u32)rport, rnd) & (synq_hsize - 1);
}

View file

@ -144,7 +144,7 @@ static struct net_device *ipgre_fb_tunnel_dev;
*/
#define HASH_SIZE 16
#define HASH(addr) ((addr^(addr>>4))&0xF)
#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
static struct ip_tunnel *tunnels[4][HASH_SIZE];
@ -157,7 +157,7 @@ static DEFINE_RWLOCK(ipgre_lock);
/* Given src, dst and key, find appropriate for input tunnel. */
static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key)
static struct ip_tunnel * ipgre_tunnel_lookup(__be32 remote, __be32 local, __be32 key)
{
unsigned h0 = HASH(remote);
unsigned h1 = HASH(key);
@ -194,9 +194,9 @@ static struct ip_tunnel * ipgre_tunnel_lookup(u32 remote, u32 local, u32 key)
static struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t)
{
u32 remote = t->parms.iph.daddr;
u32 local = t->parms.iph.saddr;
u32 key = t->parms.i_key;
__be32 remote = t->parms.iph.daddr;
__be32 local = t->parms.iph.saddr;
__be32 key = t->parms.i_key;
unsigned h = HASH(key);
int prio = 0;
@ -236,9 +236,9 @@ static void ipgre_tunnel_unlink(struct ip_tunnel *t)
static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int create)
{
u32 remote = parms->iph.daddr;
u32 local = parms->iph.saddr;
u32 key = parms->i_key;
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
__be32 key = parms->i_key;
struct ip_tunnel *t, **tp, *nt;
struct net_device *dev;
unsigned h = HASH(key);
@ -319,12 +319,12 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
*/
struct iphdr *iph = (struct iphdr*)skb->data;
u16 *p = (u16*)(skb->data+(iph->ihl<<2));
__be16 *p = (__be16*)(skb->data+(iph->ihl<<2));
int grehlen = (iph->ihl<<2) + 4;
int type = skb->h.icmph->type;
int code = skb->h.icmph->code;
struct ip_tunnel *t;
u16 flags;
__be16 flags;
flags = p[0];
if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
@ -370,7 +370,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
}
read_lock(&ipgre_lock);
t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((u32*)p) + (grehlen>>2) - 1) : 0);
t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((__be32*)p) + (grehlen>>2) - 1) : 0);
if (t == NULL || t->parms.iph.daddr == 0 || MULTICAST(t->parms.iph.daddr))
goto out;
@ -388,14 +388,14 @@ out:
#else
struct iphdr *iph = (struct iphdr*)dp;
struct iphdr *eiph;
u16 *p = (u16*)(dp+(iph->ihl<<2));
__be16 *p = (__be16*)(dp+(iph->ihl<<2));
int type = skb->h.icmph->type;
int code = skb->h.icmph->code;
int rel_type = 0;
int rel_code = 0;
__be32 rel_info = 0;
__u32 n = 0;
u16 flags;
__be16 flags;
int grehlen = (iph->ihl<<2) + 4;
struct sk_buff *skb2;
struct flowi fl;
@ -556,9 +556,9 @@ static int ipgre_rcv(struct sk_buff *skb)
{
struct iphdr *iph;
u8 *h;
u16 flags;
u16 csum = 0;
u32 key = 0;
__be16 flags;
__sum16 csum = 0;
__be32 key = 0;
u32 seqno = 0;
struct ip_tunnel *tunnel;
int offset = 4;
@ -568,7 +568,7 @@ static int ipgre_rcv(struct sk_buff *skb)
iph = skb->nh.iph;
h = skb->data;
flags = *(u16*)h;
flags = *(__be16*)h;
if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
/* - Version must be 0.
@ -580,7 +580,7 @@ static int ipgre_rcv(struct sk_buff *skb)
if (flags&GRE_CSUM) {
switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
csum = (u16)csum_fold(skb->csum);
csum = csum_fold(skb->csum);
if (!csum)
break;
/* fall through */
@ -592,11 +592,11 @@ static int ipgre_rcv(struct sk_buff *skb)
offset += 4;
}
if (flags&GRE_KEY) {
key = *(u32*)(h + offset);
key = *(__be32*)(h + offset);
offset += 4;
}
if (flags&GRE_SEQ) {
seqno = ntohl(*(u32*)(h + offset));
seqno = ntohl(*(__be32*)(h + offset));
offset += 4;
}
}
@ -605,7 +605,7 @@ static int ipgre_rcv(struct sk_buff *skb)
if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) {
secpath_reset(skb);
skb->protocol = *(u16*)(h + 2);
skb->protocol = *(__be16*)(h + 2);
/* WCCP version 1 and 2 protocol decoding.
* - Change protocol to IP
* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
@ -673,13 +673,13 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
struct iphdr *old_iph = skb->nh.iph;
struct iphdr *tiph;
u8 tos;
u16 df;
__be16 df;
struct rtable *rt; /* Route to the other host */
struct net_device *tdev; /* Device to other host */
struct iphdr *iph; /* Our new IP header */
int max_headroom; /* The extra header space needed */
int gre_hlen;
u32 dst;
__be32 dst;
int mtu;
if (tunnel->recursion++) {
@ -860,11 +860,11 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
}
((u16*)(iph+1))[0] = tunnel->parms.o_flags;
((u16*)(iph+1))[1] = skb->protocol;
((__be16*)(iph+1))[0] = tunnel->parms.o_flags;
((__be16*)(iph+1))[1] = skb->protocol;
if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
u32 *ptr = (u32*)(((u8*)iph) + tunnel->hlen - 4);
__be32 *ptr = (__be32*)(((u8*)iph) + tunnel->hlen - 4);
if (tunnel->parms.o_flags&GRE_SEQ) {
++tunnel->o_seqno;
@ -877,7 +877,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (tunnel->parms.o_flags&GRE_CSUM) {
*ptr = 0;
*(__u16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
*(__sum16*)ptr = ip_compute_csum((void*)(iph+1), skb->len - sizeof(struct iphdr));
}
}
@ -1068,7 +1068,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, unsigned sh
{
struct ip_tunnel *t = netdev_priv(dev);
struct iphdr *iph = (struct iphdr *)skb_push(skb, t->hlen);
u16 *p = (u16*)(iph+1);
__be16 *p = (__be16*)(iph+1);
memcpy(iph, &t->parms.iph, sizeof(struct iphdr));
p[0] = t->parms.o_flags;

View file

@ -288,9 +288,8 @@ int ip_output(struct sk_buff *skb)
!(IPCB(skb)->flags & IPSKB_REROUTED));
}
int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
int ip_queue_xmit(struct sk_buff *skb, struct sock *sk, int ipfragok)
{
struct sock *sk = skb->sk;
struct inet_sock *inet = inet_sk(sk);
struct ip_options *opt = inet->opt;
struct rtable *rt;
@ -342,7 +341,7 @@ packet_routed:
/* OK, we know where to send it, allocate and build IP header. */
iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr) + (opt ? opt->optlen : 0));
*((__u16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
iph->tot_len = htons(skb->len);
if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
iph->frag_off = htons(IP_DF);
@ -386,6 +385,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
dst_release(to->dst);
to->dst = dst_clone(from->dst);
to->dev = from->dev;
to->mark = from->mark;
/* Copy the flags to each fragment. */
IPCB(to)->flags = IPCB(from)->flags;
@ -394,7 +394,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->tc_index = from->tc_index;
#endif
#ifdef CONFIG_NETFILTER
to->nfmark = from->nfmark;
/* Connection association is same as pre-frag packet */
nf_conntrack_put(to->nfct);
to->nfct = from->nfct;
@ -683,7 +682,7 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk
if (memcpy_fromiovecend(to, iov, offset, len) < 0)
return -EFAULT;
} else {
unsigned int csum = 0;
__wsum csum = 0;
if (csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0)
return -EFAULT;
skb->csum = csum_block_add(skb->csum, csum, odd);
@ -691,11 +690,11 @@ ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk
return 0;
}
static inline unsigned int
static inline __wsum
csum_page(struct page *page, int offset, int copy)
{
char *kaddr;
unsigned int csum;
__wsum csum;
kaddr = kmap(page);
csum = csum_partial(kaddr + offset, copy, 0);
kunmap(page);
@ -1167,7 +1166,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page,
}
if (skb->ip_summed == CHECKSUM_NONE) {
unsigned int csum;
__wsum csum;
csum = csum_page(page, offset, len);
skb->csum = csum_block_add(skb->csum, csum, skb->len);
}
@ -1315,7 +1314,7 @@ void ip_flush_pending_frames(struct sock *sk)
static int ip_reply_glue_bits(void *dptr, char *to, int offset,
int len, int odd, struct sk_buff *skb)
{
unsigned int csum;
__wsum csum;
csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0);
skb->csum = csum_block_add(skb->csum, csum, odd);
@ -1385,7 +1384,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
&ipc, rt, MSG_DONTWAIT);
if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
if (arg->csumoffset >= 0)
*((u16 *)skb->h.raw + arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum));
*((__sum16 *)skb->h.raw + arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum));
skb->ip_summed = CHECKSUM_NONE;
ip_push_pending_frames(sk);
}

View file

@ -355,7 +355,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
sin = (struct sockaddr_in *)msg->msg_name;
if (sin) {
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset);
sin->sin_addr.s_addr = *(__be32*)(skb->nh.raw + serr->addr_offset);
sin->sin_port = serr->port;
memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
}

View file

@ -101,6 +101,7 @@
#define CONF_NAMESERVERS_MAX 3 /* Maximum number of nameservers
- '3' from resolv.h */
#define NONE __constant_htonl(INADDR_NONE)
/*
* Public IP configuration
@ -129,19 +130,19 @@ int ic_proto_enabled __initdata = 0
static int ic_host_name_set __initdata = 0; /* Host name set by us? */
u32 ic_myaddr = INADDR_NONE; /* My IP address */
static u32 ic_netmask = INADDR_NONE; /* Netmask for local subnet */
u32 ic_gateway = INADDR_NONE; /* Gateway IP address */
__be32 ic_myaddr = NONE; /* My IP address */
static __be32 ic_netmask = NONE; /* Netmask for local subnet */
__be32 ic_gateway = NONE; /* Gateway IP address */
u32 ic_servaddr = INADDR_NONE; /* Boot server IP address */
__be32 ic_servaddr = NONE; /* Boot server IP address */
u32 root_server_addr = INADDR_NONE; /* Address of NFS server */
__be32 root_server_addr = NONE; /* Address of NFS server */
u8 root_server_path[256] = { 0, }; /* Path to mount as root */
/* Persistent data: */
static int ic_proto_used; /* Protocol used, if any */
static u32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */
static u8 ic_domain[64]; /* DNS (not NIS) domain name */
/*
@ -172,7 +173,7 @@ struct ic_device {
struct net_device *dev;
unsigned short flags;
short able;
u32 xid;
__be32 xid;
};
static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */
@ -223,7 +224,7 @@ static int __init ic_open_devs(void)
d->flags = oflags;
d->able = able;
if (able & IC_BOOTP)
get_random_bytes(&d->xid, sizeof(u32));
get_random_bytes(&d->xid, sizeof(__be32));
else
d->xid = 0;
ic_proto_have_if |= able;
@ -269,7 +270,7 @@ static void __init ic_close_devs(void)
*/
static inline void
set_sockaddr(struct sockaddr_in *sin, u32 addr, u16 port)
set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port)
{
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = addr;
@ -332,7 +333,7 @@ static int __init ic_setup_routes(void)
{
/* No need to setup device routes, only the default route... */
if (ic_gateway != INADDR_NONE) {
if (ic_gateway != NONE) {
struct rtentry rm;
int err;
@ -368,10 +369,10 @@ static int __init ic_defaults(void)
if (!ic_host_name_set)
sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr));
if (root_server_addr == INADDR_NONE)
if (root_server_addr == NONE)
root_server_addr = ic_servaddr;
if (ic_netmask == INADDR_NONE) {
if (ic_netmask == NONE) {
if (IN_CLASSA(ntohl(ic_myaddr)))
ic_netmask = htonl(IN_CLASSA_NET);
else if (IN_CLASSB(ntohl(ic_myaddr)))
@ -420,7 +421,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
{
struct arphdr *rarp;
unsigned char *rarp_ptr;
u32 sip, tip;
__be32 sip, tip;
unsigned char *sha, *tha; /* s for "source", t for "target" */
struct ic_device *d;
@ -485,12 +486,12 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
goto drop_unlock;
/* Discard packets which are not from specified server. */
if (ic_servaddr != INADDR_NONE && ic_servaddr != sip)
if (ic_servaddr != NONE && ic_servaddr != sip)
goto drop_unlock;
/* We have a winner! */
ic_dev = dev;
if (ic_myaddr == INADDR_NONE)
if (ic_myaddr == NONE)
ic_myaddr = tip;
ic_servaddr = sip;
ic_got_reply = IC_RARP;
@ -530,13 +531,13 @@ struct bootp_pkt { /* BOOTP packet format */
u8 htype; /* HW address type */
u8 hlen; /* HW address length */
u8 hops; /* Used only by gateways */
u32 xid; /* Transaction ID */
u16 secs; /* Seconds since we started */
u16 flags; /* Just what it says */
u32 client_ip; /* Client's IP address if known */
u32 your_ip; /* Assigned IP address */
u32 server_ip; /* (Next, e.g. NFS) Server's IP address */
u32 relay_ip; /* IP address of BOOTP relay */
__be32 xid; /* Transaction ID */
__be16 secs; /* Seconds since we started */
__be16 flags; /* Just what it says */
__be32 client_ip; /* Client's IP address if known */
__be32 your_ip; /* Assigned IP address */
__be32 server_ip; /* (Next, e.g. NFS) Server's IP address */
__be32 relay_ip; /* IP address of BOOTP relay */
u8 hw_addr[16]; /* Client's HW address */
u8 serv_name[64]; /* Server host name */
u8 boot_file[128]; /* Name of boot file */
@ -576,7 +577,7 @@ static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 };
static void __init
ic_dhcp_init_options(u8 *options)
{
u8 mt = ((ic_servaddr == INADDR_NONE)
u8 mt = ((ic_servaddr == NONE)
? DHCPDISCOVER : DHCPREQUEST);
u8 *e = options;
@ -666,7 +667,7 @@ static inline void ic_bootp_init(void)
int i;
for (i = 0; i < CONF_NAMESERVERS_MAX; i++)
ic_nameservers[i] = INADDR_NONE;
ic_nameservers[i] = NONE;
dev_add_pack(&bootp_packet_type);
}
@ -708,7 +709,7 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
h->frag_off = htons(IP_DF);
h->ttl = 64;
h->protocol = IPPROTO_UDP;
h->daddr = INADDR_BROADCAST;
h->daddr = htonl(INADDR_BROADCAST);
h->check = ip_fast_csum((unsigned char *) h, h->ihl);
/* Construct UDP header */
@ -730,8 +731,8 @@ static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_d
b->htype = dev->type; /* can cause undefined behavior */
}
b->hlen = dev->addr_len;
b->your_ip = INADDR_NONE;
b->server_ip = INADDR_NONE;
b->your_ip = NONE;
b->server_ip = NONE;
memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
b->secs = htons(jiffies_diff / HZ);
b->xid = d->xid;
@ -788,11 +789,11 @@ static void __init ic_do_bootp_ext(u8 *ext)
switch (*ext++) {
case 1: /* Subnet mask */
if (ic_netmask == INADDR_NONE)
if (ic_netmask == NONE)
memcpy(&ic_netmask, ext+1, 4);
break;
case 3: /* Default gateway */
if (ic_gateway == INADDR_NONE)
if (ic_gateway == NONE)
memcpy(&ic_gateway, ext+1, 4);
break;
case 6: /* DNS server */
@ -800,7 +801,7 @@ static void __init ic_do_bootp_ext(u8 *ext)
if (servers > CONF_NAMESERVERS_MAX)
servers = CONF_NAMESERVERS_MAX;
for (i = 0; i < servers; i++) {
if (ic_nameservers[i] == INADDR_NONE)
if (ic_nameservers[i] == NONE)
memcpy(&ic_nameservers[i], ext+1+4*i, 4);
}
break;
@ -917,7 +918,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
#ifdef IPCONFIG_DHCP
if (ic_proto_enabled & IC_USE_DHCP) {
u32 server_id = INADDR_NONE;
__be32 server_id = NONE;
int mt = 0;
ext = &b->exten[4];
@ -949,7 +950,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
/* While in the process of accepting one offer,
* ignore all others.
*/
if (ic_myaddr != INADDR_NONE)
if (ic_myaddr != NONE)
goto drop_unlock;
/* Let's accept that offer. */
@ -965,7 +966,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
* precedence over the bootp header one if
* they are different.
*/
if ((server_id != INADDR_NONE) &&
if ((server_id != NONE) &&
(b->server_ip != server_id))
b->server_ip = ic_servaddr;
break;
@ -979,8 +980,8 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
default:
/* Urque. Forget it*/
ic_myaddr = INADDR_NONE;
ic_servaddr = INADDR_NONE;
ic_myaddr = NONE;
ic_servaddr = NONE;
goto drop_unlock;
};
@ -1004,9 +1005,9 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
ic_dev = dev;
ic_myaddr = b->your_ip;
ic_servaddr = b->server_ip;
if (ic_gateway == INADDR_NONE && b->relay_ip)
if (ic_gateway == NONE && b->relay_ip)
ic_gateway = b->relay_ip;
if (ic_nameservers[0] == INADDR_NONE)
if (ic_nameservers[0] == NONE)
ic_nameservers[0] = ic_servaddr;
ic_got_reply = IC_BOOTP;
@ -1150,7 +1151,7 @@ static int __init ic_dynamic(void)
#endif
if (!ic_got_reply) {
ic_myaddr = INADDR_NONE;
ic_myaddr = NONE;
return -1;
}
@ -1182,12 +1183,12 @@ static int pnp_seq_show(struct seq_file *seq, void *v)
seq_printf(seq,
"domain %s\n", ic_domain);
for (i = 0; i < CONF_NAMESERVERS_MAX; i++) {
if (ic_nameservers[i] != INADDR_NONE)
if (ic_nameservers[i] != NONE)
seq_printf(seq,
"nameserver %u.%u.%u.%u\n",
NIPQUAD(ic_nameservers[i]));
}
if (ic_servaddr != INADDR_NONE)
if (ic_servaddr != NONE)
seq_printf(seq,
"bootserver %u.%u.%u.%u\n",
NIPQUAD(ic_servaddr));
@ -1213,9 +1214,9 @@ static struct file_operations pnp_seq_fops = {
* need to have root_server_addr set _before_ IPConfig gets called as it
* can override it.
*/
u32 __init root_nfs_parse_addr(char *name)
__be32 __init root_nfs_parse_addr(char *name)
{
u32 addr;
__be32 addr;
int octets = 0;
char *cp, *cq;
@ -1237,7 +1238,7 @@ u32 __init root_nfs_parse_addr(char *name)
addr = in_aton(name);
memmove(name, cp, strlen(cp) + 1);
} else
addr = INADDR_NONE;
addr = NONE;
return addr;
}
@ -1248,7 +1249,7 @@ u32 __init root_nfs_parse_addr(char *name)
static int __init ip_auto_config(void)
{
u32 addr;
__be32 addr;
#ifdef CONFIG_PROC_FS
proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops);
@ -1277,11 +1278,11 @@ static int __init ip_auto_config(void)
* interfaces and no default was set), use BOOTP or RARP to get the
* missing values.
*/
if (ic_myaddr == INADDR_NONE ||
if (ic_myaddr == NONE ||
#ifdef CONFIG_ROOT_NFS
(MAJOR(ROOT_DEV) == UNNAMED_MAJOR
&& root_server_addr == INADDR_NONE
&& ic_servaddr == INADDR_NONE) ||
&& root_server_addr == NONE
&& ic_servaddr == NONE) ||
#endif
ic_first_dev->next) {
#ifdef IPCONFIG_DYNAMIC
@ -1334,7 +1335,7 @@ static int __init ip_auto_config(void)
}
addr = root_nfs_parse_addr(root_server_path);
if (root_server_addr == INADDR_NONE)
if (root_server_addr == NONE)
root_server_addr = addr;
/*
@ -1461,19 +1462,19 @@ static int __init ip_auto_config_setup(char *addrs)
switch (num) {
case 0:
if ((ic_myaddr = in_aton(ip)) == INADDR_ANY)
ic_myaddr = INADDR_NONE;
ic_myaddr = NONE;
break;
case 1:
if ((ic_servaddr = in_aton(ip)) == INADDR_ANY)
ic_servaddr = INADDR_NONE;
ic_servaddr = NONE;
break;
case 2:
if ((ic_gateway = in_aton(ip)) == INADDR_ANY)
ic_gateway = INADDR_NONE;
ic_gateway = NONE;
break;
case 3:
if ((ic_netmask = in_aton(ip)) == INADDR_ANY)
ic_netmask = INADDR_NONE;
ic_netmask = NONE;
break;
case 4:
if ((dp = strchr(ip, '.'))) {

View file

@ -118,7 +118,7 @@
#include <net/xfrm.h>
#define HASH_SIZE 16
#define HASH(addr) ((addr^(addr>>4))&0xF)
#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF)
static int ipip_fb_tunnel_init(struct net_device *dev);
static int ipip_tunnel_init(struct net_device *dev);
@ -134,7 +134,7 @@ static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunne
static DEFINE_RWLOCK(ipip_lock);
static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local)
static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local)
{
unsigned h0 = HASH(remote);
unsigned h1 = HASH(local);
@ -160,8 +160,8 @@ static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local)
static struct ip_tunnel **ipip_bucket(struct ip_tunnel *t)
{
u32 remote = t->parms.iph.daddr;
u32 local = t->parms.iph.saddr;
__be32 remote = t->parms.iph.daddr;
__be32 local = t->parms.iph.saddr;
unsigned h = 0;
int prio = 0;
@ -203,8 +203,8 @@ static void ipip_tunnel_link(struct ip_tunnel *t)
static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create)
{
u32 remote = parms->iph.daddr;
u32 local = parms->iph.saddr;
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
struct ip_tunnel *t, **tp, *nt;
struct net_device *dev;
unsigned h = 0;
@ -519,13 +519,13 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
struct net_device_stats *stats = &tunnel->stat;
struct iphdr *tiph = &tunnel->parms.iph;
u8 tos = tunnel->parms.iph.tos;
u16 df = tiph->frag_off;
__be16 df = tiph->frag_off;
struct rtable *rt; /* Route to the other host */
struct net_device *tdev; /* Device to other host */
struct iphdr *old_iph = skb->nh.iph;
struct iphdr *iph; /* Our new IP header */
int max_headroom; /* The extra header space needed */
u32 dst = tiph->daddr;
__be32 dst = tiph->daddr;
int mtu;
if (tunnel->recursion++) {

View file

@ -1493,7 +1493,7 @@ static int pim_rcv(struct sk_buff * skb)
if (pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) ||
(pim->flags&PIM_NULL_REGISTER) ||
(ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
(u16)csum_fold(skb_checksum(skb, 0, skb->len, 0))))
csum_fold(skb_checksum(skb, 0, skb->len, 0))))
goto drop;
/* check if the inner packet is destined to mcast group */

View file

@ -80,10 +80,9 @@ ip_vs_app_inc_new(struct ip_vs_app *app, __u16 proto, __u16 port)
if (!pp->unregister_app)
return -EOPNOTSUPP;
inc = kmalloc(sizeof(struct ip_vs_app), GFP_KERNEL);
inc = kmemdup(app, sizeof(*inc), GFP_KERNEL);
if (!inc)
return -ENOMEM;
memcpy(inc, app, sizeof(*inc));
INIT_LIST_HEAD(&inc->p_list);
INIT_LIST_HEAD(&inc->incs_list);
inc->app = app;

View file

@ -536,9 +536,9 @@ static unsigned int ip_vs_post_routing(unsigned int hooknum,
return NF_STOP;
}
u16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
{
return (u16) csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
}
static inline struct sk_buff *

View file

@ -118,13 +118,7 @@ void ip_vs_protocol_timeout_change(int flags)
int *
ip_vs_create_timeout_table(int *table, int size)
{
int *t;
t = kmalloc(size, GFP_ATOMIC);
if (t == NULL)
return NULL;
memcpy(t, table, size);
return t;
return kmemdup(table, size, GFP_ATOMIC);
}

View file

@ -84,7 +84,7 @@ tcp_conn_schedule(struct sk_buff *skb,
}
if (th->syn &&
(svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol,
(svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol,
skb->nh.iph->daddr, th->dest))) {
if (ip_vs_todrop()) {
/*
@ -116,9 +116,9 @@ tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip,
__be16 oldport, __be16 newport)
{
tcph->check =
ip_vs_check_diff(~oldip, newip,
ip_vs_check_diff(oldport ^ htons(0xFFFF),
newport, tcph->check));
csum_fold(ip_vs_check_diff4(oldip, newip,
ip_vs_check_diff2(oldport, newport,
~csum_unfold(tcph->check))));
}
@ -490,16 +490,18 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction,
static struct list_head tcp_apps[TCP_APP_TAB_SIZE];
static DEFINE_SPINLOCK(tcp_app_lock);
static inline __u16 tcp_app_hashkey(__u16 port)
static inline __u16 tcp_app_hashkey(__be16 port)
{
return ((port >> TCP_APP_TAB_BITS) ^ port) & TCP_APP_TAB_MASK;
return (((__force u16)port >> TCP_APP_TAB_BITS) ^ (__force u16)port)
& TCP_APP_TAB_MASK;
}
static int tcp_register_app(struct ip_vs_app *inc)
{
struct ip_vs_app *i;
__u16 hash, port = inc->port;
__u16 hash;
__be16 port = inc->port;
int ret = 0;
hash = tcp_app_hashkey(port);

View file

@ -89,7 +89,7 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
return 0;
}
if ((svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol,
if ((svc = ip_vs_service_get(skb->mark, skb->nh.iph->protocol,
skb->nh.iph->daddr, uh->dest))) {
if (ip_vs_todrop()) {
/*
@ -121,11 +121,11 @@ udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip,
__be16 oldport, __be16 newport)
{
uhdr->check =
ip_vs_check_diff(~oldip, newip,
ip_vs_check_diff(oldport ^ htons(0xFFFF),
newport, uhdr->check));
csum_fold(ip_vs_check_diff4(oldip, newip,
ip_vs_check_diff2(oldport, newport,
~csum_unfold(uhdr->check))));
if (!uhdr->check)
uhdr->check = -1;
uhdr->check = CSUM_MANGLED_0;
}
static int
@ -173,7 +173,7 @@ udp_snat_handler(struct sk_buff **pskb,
cp->protocol,
(*pskb)->csum);
if (udph->check == 0)
udph->check = -1;
udph->check = CSUM_MANGLED_0;
IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
pp->name, udph->check,
(char*)&(udph->check) - (char*)udph);
@ -228,7 +228,7 @@ udp_dnat_handler(struct sk_buff **pskb,
cp->protocol,
(*pskb)->csum);
if (udph->check == 0)
udph->check = -1;
udph->check = CSUM_MANGLED_0;
(*pskb)->ip_summed = CHECKSUM_UNNECESSARY;
}
return 1;
@ -282,16 +282,18 @@ udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
static struct list_head udp_apps[UDP_APP_TAB_SIZE];
static DEFINE_SPINLOCK(udp_app_lock);
static inline __u16 udp_app_hashkey(__u16 port)
static inline __u16 udp_app_hashkey(__be16 port)
{
return ((port >> UDP_APP_TAB_BITS) ^ port) & UDP_APP_TAB_MASK;
return (((__force u16)port >> UDP_APP_TAB_BITS) ^ (__force u16)port)
& UDP_APP_TAB_MASK;
}
static int udp_register_app(struct ip_vs_app *inc)
{
struct ip_vs_app *i;
__u16 hash, port = inc->port;
__u16 hash;
__be16 port = inc->port;
int ret = 0;
hash = udp_app_hashkey(port);

View file

@ -27,9 +27,7 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
fl.nl_u.ip4_u.saddr = iph->saddr;
fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
#ifdef CONFIG_IP_ROUTE_FWMARK
fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
#endif
fl.mark = (*pskb)->mark;
if (ip_route_output_key(&rt, &fl) != 0)
return -1;
@ -164,17 +162,17 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info)
return 0;
}
unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol)
{
struct iphdr *iph = skb->nh.iph;
unsigned int csum = 0;
__sum16 csum = 0;
switch (skb->ip_summed) {
case CHECKSUM_COMPLETE:
if (hook != NF_IP_PRE_ROUTING && hook != NF_IP_LOCAL_IN)
break;
if ((protocol == 0 && !(u16)csum_fold(skb->csum)) ||
if ((protocol == 0 && !csum_fold(skb->csum)) ||
!csum_tcpudp_magic(iph->saddr, iph->daddr,
skb->len - dataoff, protocol,
skb->csum)) {

View file

@ -6,7 +6,7 @@ menu "IP: Netfilter Configuration"
depends on INET && NETFILTER
config NF_CONNTRACK_IPV4
tristate "IPv4 support for new connection tracking (EXPERIMENTAL)"
tristate "IPv4 connection tracking support (required for NAT) (EXPERIMENTAL)"
depends on EXPERIMENTAL && NF_CONNTRACK
---help---
Connection tracking keeps a record of what packets have passed
@ -19,21 +19,18 @@ config NF_CONNTRACK_IPV4
To compile it as a module, choose M here. If unsure, say N.
config NF_CONNTRACK_PROC_COMPAT
bool "proc/sysctl compatibility with old connection tracking"
depends on NF_CONNTRACK_IPV4
default y
help
This option enables /proc and sysctl compatibility with the old
layer 3 dependant connection tracking. This is needed to keep
old programs that have not been adapted to the new names working.
If unsure, say Y.
# connection tracking, helpers and protocols
config IP_NF_CONNTRACK
tristate "Connection tracking (required for masq/NAT)"
---help---
Connection tracking keeps a record of what packets have passed
through your machine, in order to figure out how they are related
into connections.
This is 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).
To compile it as a module, choose M here. If unsure, say N.
config IP_NF_CT_ACCT
bool "Connection tracking flow accounting"
depends on IP_NF_CONNTRACK
@ -315,20 +312,6 @@ config IP_NF_MATCH_ADDRTYPE
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_MATCH_HASHLIMIT
tristate 'hashlimit match support'
depends on IP_NF_IPTABLES
help
This option adds a new iptables `hashlimit' match.
As opposed to `limit', this match dynamically creates a hash table
of limit buckets, based on your selection of source/destination
ip addresses and/or ports.
It enables you to express policies like `10kpps for any given
destination IP' or `500pps from any given source IP' with a single
IPtables rule.
# `filter', generic and specific targets
config IP_NF_FILTER
tristate "Packet filtering"
@ -404,7 +387,7 @@ config IP_NF_TARGET_TCPMSS
To compile it as a module, choose M here. If unsure, say N.
# NAT + specific targets
# NAT + specific targets: ip_conntrack
config IP_NF_NAT
tristate "Full NAT"
depends on IP_NF_IPTABLES && IP_NF_CONNTRACK
@ -415,14 +398,30 @@ config IP_NF_NAT
To compile it as a module, choose M here. If unsure, say N.
# NAT + specific targets: nf_conntrack
config NF_NAT
tristate "Full NAT"
depends on IP_NF_IPTABLES && 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.
config IP_NF_NAT_NEEDED
bool
depends on IP_NF_NAT != n
depends on IP_NF_NAT
default y
config NF_NAT_NEEDED
bool
depends on NF_NAT
default y
config IP_NF_TARGET_MASQUERADE
tristate "MASQUERADE target support"
depends on IP_NF_NAT
depends on (NF_NAT || IP_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
@ -434,7 +433,7 @@ config IP_NF_TARGET_MASQUERADE
config IP_NF_TARGET_REDIRECT
tristate "REDIRECT target support"
depends on IP_NF_NAT
depends on (NF_NAT || IP_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
@ -445,7 +444,7 @@ config IP_NF_TARGET_REDIRECT
config IP_NF_TARGET_NETMAP
tristate "NETMAP target support"
depends on IP_NF_NAT
depends on (NF_NAT || IP_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
@ -456,7 +455,7 @@ config IP_NF_TARGET_NETMAP
config IP_NF_TARGET_SAME
tristate "SAME target support"
depends on IP_NF_NAT
depends on (NF_NAT || IP_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.
@ -478,19 +477,52 @@ config IP_NF_NAT_SNMP_BASIC
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
---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.
# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker.
# From kconfig-language.txt:
#
# <expr> '&&' <expr> (6)
#
# (6) Returns the result of min(/expr/, /expr/).
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
# If they want FTP, set to $CONFIG_IP_NF_NAT (m or y),
# or $CONFIG_IP_NF_FTP (m or y), whichever is weaker. Argh.
config IP_NF_NAT_FTP
config 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_FTP=y
default m if IP_NF_FTP=m
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
default NF_NAT && NF_CONNTRACK_IRC
config IP_NF_NAT_TFTP
tristate
@ -498,30 +530,56 @@ config IP_NF_NAT_TFTP
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
default NF_NAT && NF_CONNTRACK_SIP
# mangle + specific targets
config IP_NF_MANGLE
tristate "Packet mangling"

View file

@ -5,17 +5,23 @@
# 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
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),)
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 ip_conntrack_helper_h323_asn1.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_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
@ -34,7 +40,7 @@ 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
# 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
@ -43,6 +49,19 @@ 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
obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o
obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o
obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
# NAT protocols (nf_nat)
obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o
# generic IP tables
obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
@ -50,10 +69,10 @@ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
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
# matches
obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
@ -89,6 +108,11 @@ obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o
# objects for l3 independent conntrack
nf_conntrack_ipv4-objs := nf_conntrack_l3proto_ipv4.o nf_conntrack_proto_icmp.o
ifeq ($(CONFIG_NF_CONNTRACK_PROC_COMPAT),y)
ifeq ($(CONFIG_PROC_FS),y)
nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o
endif
endif
# l3 independent conntrack
obj-$(CONFIG_NF_CONNTRACK_IPV4) += nf_conntrack_ipv4.o

View file

@ -92,6 +92,7 @@ static int help(struct sk_buff **pskb,
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)
@ -161,9 +162,11 @@ static int help(struct sk_buff **pskb,
exp->mask.dst.protonum = 0xFF;
exp->mask.dst.u.tcp.port = htons(0xFFFF);
if (ip_nat_amanda_hook)
ret = ip_nat_amanda_hook(pskb, ctinfo, off - dataoff,
len, exp);
/* 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);
@ -180,7 +183,7 @@ static struct ip_conntrack_helper amanda_helper = {
.help = help,
.name = "amanda",
.tuple = { .src = { .u = { __constant_htons(10080) } },
.tuple = { .src = { .u = { .udp = {.port = __constant_htons(10080) } } },
.dst = { .protonum = IPPROTO_UDP },
},
.mask = { .src = { .u = { 0xFFFF } },

View file

@ -40,9 +40,6 @@
/* ip_conntrack_lock protects the main hash table, protocol/helper/expected
registrations, conntrack timers*/
#define ASSERT_READ_LOCK(x)
#define ASSERT_WRITE_LOCK(x)
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
@ -201,7 +198,6 @@ ip_ct_invert_tuple(struct ip_conntrack_tuple *inverse,
/* ip_conntrack_expect helper functions */
void ip_ct_unlink_expect(struct ip_conntrack_expect *exp)
{
ASSERT_WRITE_LOCK(&ip_conntrack_lock);
IP_NF_ASSERT(!timer_pending(&exp->timeout));
list_del(&exp->list);
CONNTRACK_STAT_INC(expect_delete);
@ -225,22 +221,22 @@ __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple)
struct ip_conntrack_expect *i;
list_for_each_entry(i, &ip_conntrack_expect_list, list) {
if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) {
atomic_inc(&i->use);
if (ip_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
return i;
}
}
return NULL;
}
/* Just find a expectation corresponding to a tuple. */
struct ip_conntrack_expect *
ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple)
ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple)
{
struct ip_conntrack_expect *i;
read_lock_bh(&ip_conntrack_lock);
i = __ip_conntrack_expect_find(tuple);
if (i)
atomic_inc(&i->use);
read_unlock_bh(&ip_conntrack_lock);
return i;
@ -294,7 +290,6 @@ static void
clean_from_lists(struct ip_conntrack *ct)
{
DEBUGP("clean_from_lists(%p)\n", ct);
ASSERT_WRITE_LOCK(&ip_conntrack_lock);
list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list);
@ -373,7 +368,6 @@ __ip_conntrack_find(const struct ip_conntrack_tuple *tuple,
struct ip_conntrack_tuple_hash *h;
unsigned int hash = hash_conntrack(tuple);
ASSERT_READ_LOCK(&ip_conntrack_lock);
list_for_each_entry(h, &ip_conntrack_hash[hash], list) {
if (tuplehash_to_ctrack(h) != ignored_conntrack &&
ip_ct_tuple_equal(tuple, &h->tuple)) {

View file

@ -310,6 +310,7 @@ static int help(struct sk_buff **pskb,
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
@ -433,9 +434,10 @@ static int help(struct sk_buff **pskb,
/* Now, NAT might want to mangle the packet, and register the
* (possibly changed) expectation itself. */
if (ip_nat_ftp_hook)
ret = ip_nat_ftp_hook(pskb, ctinfo, search[dir][i].ftptype,
matchoff, matchlen, exp, &seq);
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)

View file

@ -237,6 +237,7 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
u_int16_t rtp_port;
struct ip_conntrack_expect *rtp_exp;
struct ip_conntrack_expect *rtcp_exp;
typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp;
/* Read RTP or RTCP address */
if (!get_h245_addr(*data, addr, &ip, &port) ||
@ -279,11 +280,11 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
rtcp_exp->flags = 0;
if (ct->tuplehash[dir].tuple.src.ip !=
ct->tuplehash[!dir].tuple.dst.ip && nat_rtp_rtcp_hook) {
ct->tuplehash[!dir].tuple.dst.ip &&
(nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook))) {
/* NAT needed */
ret = nat_rtp_rtcp_hook(pskb, ct, ctinfo, data, dataoff,
addr, port, rtp_port, rtp_exp,
rtcp_exp);
ret = nat_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
addr, port, rtp_port, rtp_exp, rtcp_exp);
} else { /* Conntrack only */
rtp_exp->expectfn = NULL;
rtcp_exp->expectfn = NULL;
@ -328,6 +329,7 @@ static int expect_t120(struct sk_buff **pskb,
__be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp = NULL;
typeof(nat_t120_hook) nat_t120;
/* Read T.120 address */
if (!get_h245_addr(*data, addr, &ip, &port) ||
@ -350,10 +352,11 @@ static int expect_t120(struct sk_buff **pskb,
exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */
if (ct->tuplehash[dir].tuple.src.ip !=
ct->tuplehash[!dir].tuple.dst.ip && nat_t120_hook) {
ct->tuplehash[!dir].tuple.dst.ip &&
(nat_t120 = rcu_dereference(nat_t120_hook))) {
/* NAT needed */
ret = nat_t120_hook(pskb, ct, ctinfo, data, dataoff, addr,
port, exp);
ret = nat_t120(pskb, ct, ctinfo, data, dataoff, addr,
port, exp);
} else { /* Conntrack only */
exp->expectfn = NULL;
if (ip_conntrack_expect_related(exp) == 0) {
@ -651,6 +654,7 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
__be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp = NULL;
typeof(nat_h245_hook) nat_h245;
/* Read h245Address */
if (!get_h225_addr(*data, addr, &ip, &port) ||
@ -673,10 +677,11 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
exp->flags = 0;
if (ct->tuplehash[dir].tuple.src.ip !=
ct->tuplehash[!dir].tuple.dst.ip && nat_h245_hook) {
ct->tuplehash[!dir].tuple.dst.ip &&
(nat_h245 = rcu_dereference(nat_h245_hook))) {
/* NAT needed */
ret = nat_h245_hook(pskb, ct, ctinfo, data, dataoff, addr,
port, exp);
ret = nat_h245(pskb, ct, ctinfo, data, dataoff, addr,
port, exp);
} else { /* Conntrack only */
exp->expectfn = ip_conntrack_h245_expect;
@ -712,6 +717,7 @@ static int expect_callforwarding(struct sk_buff **pskb,
__be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp = NULL;
typeof(nat_callforwarding_hook) nat_callforwarding;
/* Read alternativeAddress */
if (!get_h225_addr(*data, addr, &ip, &port) || port == 0)
@ -759,10 +765,11 @@ static int expect_callforwarding(struct sk_buff **pskb,
exp->flags = 0;
if (ct->tuplehash[dir].tuple.src.ip !=
ct->tuplehash[!dir].tuple.dst.ip && nat_callforwarding_hook) {
ct->tuplehash[!dir].tuple.dst.ip &&
(nat_callforwarding = rcu_dereference(nat_callforwarding_hook))) {
/* Need NAT */
ret = nat_callforwarding_hook(pskb, ct, ctinfo, data, dataoff,
addr, port, exp);
ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff,
addr, port, exp);
} else { /* Conntrack only */
exp->expectfn = ip_conntrack_q931_expect;
@ -793,6 +800,7 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
int i;
__be32 ip;
u_int16_t port;
typeof(set_h225_addr_hook) set_h225_addr;
DEBUGP("ip_ct_q931: Setup\n");
@ -803,8 +811,10 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
return -1;
}
set_h225_addr = rcu_dereference(set_h225_addr_hook);
if ((setup->options & eSetup_UUIE_destCallSignalAddress) &&
(set_h225_addr_hook) &&
(set_h225_addr) &&
get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) &&
ip != ct->tuplehash[!dir].tuple.src.ip) {
DEBUGP("ip_ct_q931: set destCallSignalAddress "
@ -812,17 +822,17 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
NIPQUAD(ip), port,
NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port));
ret = set_h225_addr_hook(pskb, data, dataoff,
&setup->destCallSignalAddress,
ct->tuplehash[!dir].tuple.src.ip,
ntohs(ct->tuplehash[!dir].tuple.src.
u.tcp.port));
ret = set_h225_addr(pskb, data, dataoff,
&setup->destCallSignalAddress,
ct->tuplehash[!dir].tuple.src.ip,
ntohs(ct->tuplehash[!dir].tuple.src.
u.tcp.port));
if (ret < 0)
return -1;
}
if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) &&
(set_h225_addr_hook) &&
(set_h225_addr) &&
get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port)
&& ip != ct->tuplehash[!dir].tuple.dst.ip) {
DEBUGP("ip_ct_q931: set sourceCallSignalAddress "
@ -830,11 +840,11 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
NIPQUAD(ip), port,
NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port));
ret = set_h225_addr_hook(pskb, data, dataoff,
&setup->sourceCallSignalAddress,
ct->tuplehash[!dir].tuple.dst.ip,
ntohs(ct->tuplehash[!dir].tuple.dst.
u.tcp.port));
ret = set_h225_addr(pskb, data, dataoff,
&setup->sourceCallSignalAddress,
ct->tuplehash[!dir].tuple.dst.ip,
ntohs(ct->tuplehash[!dir].tuple.dst.
u.tcp.port));
if (ret < 0)
return -1;
}
@ -1153,7 +1163,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_q931 = {
.me = THIS_MODULE,
.max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ ,
.timeout = 240,
.tuple = {.src = {.u = {__constant_htons(Q931_PORT)}},
.tuple = {.src = {.u = {.tcp = {.port = __constant_htons(Q931_PORT)}}},
.dst = {.protonum = IPPROTO_TCP}},
.mask = {.src = {.u = {0xFFFF}},
.dst = {.protonum = 0xFF}},
@ -1231,6 +1241,7 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
__be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp;
typeof(nat_q931_hook) nat_q931;
/* Look for the first related address */
for (i = 0; i < count; i++) {
@ -1258,9 +1269,9 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
exp->mask.dst.protonum = 0xFF;
exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */
if (nat_q931_hook) { /* Need NAT */
ret = nat_q931_hook(pskb, ct, ctinfo, data, addr, i,
port, exp);
nat_q931 = rcu_dereference(nat_q931_hook);
if (nat_q931) { /* Need NAT */
ret = nat_q931(pskb, ct, ctinfo, data, addr, i, port, exp);
} else { /* Conntrack only */
exp->expectfn = ip_conntrack_q931_expect;
@ -1288,11 +1299,14 @@ static int process_grq(struct sk_buff **pskb, struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, GatekeeperRequest * grq)
{
typeof(set_ras_addr_hook) set_ras_addr;
DEBUGP("ip_ct_ras: GRQ\n");
if (set_ras_addr_hook) /* NATed */
return set_ras_addr_hook(pskb, ct, ctinfo, data,
&grq->rasAddress, 1);
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr) /* NATed */
return set_ras_addr(pskb, ct, ctinfo, data,
&grq->rasAddress, 1);
return 0;
}
@ -1362,6 +1376,7 @@ static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct,
{
struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
int ret;
typeof(set_ras_addr_hook) set_ras_addr;
DEBUGP("ip_ct_ras: RRQ\n");
@ -1371,10 +1386,11 @@ static int process_rrq(struct sk_buff **pskb, struct ip_conntrack *ct,
if (ret < 0)
return -1;
if (set_ras_addr_hook) {
ret = set_ras_addr_hook(pskb, ct, ctinfo, data,
rrq->rasAddress.item,
rrq->rasAddress.count);
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr) {
ret = set_ras_addr(pskb, ct, ctinfo, data,
rrq->rasAddress.item,
rrq->rasAddress.count);
if (ret < 0)
return -1;
}
@ -1397,13 +1413,15 @@ static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct,
int dir = CTINFO2DIR(ctinfo);
int ret;
struct ip_conntrack_expect *exp;
typeof(set_sig_addr_hook) set_sig_addr;
DEBUGP("ip_ct_ras: RCF\n");
if (set_sig_addr_hook) {
ret = set_sig_addr_hook(pskb, ct, ctinfo, data,
rcf->callSignalAddress.item,
rcf->callSignalAddress.count);
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr) {
ret = set_sig_addr(pskb, ct, ctinfo, data,
rcf->callSignalAddress.item,
rcf->callSignalAddress.count);
if (ret < 0)
return -1;
}
@ -1417,7 +1435,7 @@ static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct,
DEBUGP
("ip_ct_ras: set RAS connection timeout to %u seconds\n",
info->timeout);
ip_ct_refresh_acct(ct, ctinfo, NULL, info->timeout * HZ);
ip_ct_refresh(ct, *pskb, info->timeout * HZ);
/* Set expect timeout */
read_lock_bh(&ip_conntrack_lock);
@ -1448,13 +1466,15 @@ static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct,
struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
int dir = CTINFO2DIR(ctinfo);
int ret;
typeof(set_sig_addr_hook) set_sig_addr;
DEBUGP("ip_ct_ras: URQ\n");
if (set_sig_addr_hook) {
ret = set_sig_addr_hook(pskb, ct, ctinfo, data,
urq->callSignalAddress.item,
urq->callSignalAddress.count);
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr) {
ret = set_sig_addr(pskb, ct, ctinfo, data,
urq->callSignalAddress.item,
urq->callSignalAddress.count);
if (ret < 0)
return -1;
}
@ -1465,7 +1485,7 @@ static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct,
info->sig_port[!dir] = 0;
/* Give it 30 seconds for UCF or URJ */
ip_ct_refresh_acct(ct, ctinfo, NULL, 30 * HZ);
ip_ct_refresh(ct, *pskb, 30 * HZ);
return 0;
}
@ -1479,28 +1499,30 @@ static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct,
int dir = CTINFO2DIR(ctinfo);
__be32 ip;
u_int16_t port;
typeof(set_h225_addr_hook) set_h225_addr;
DEBUGP("ip_ct_ras: ARQ\n");
set_h225_addr = rcu_dereference(set_h225_addr_hook);
if ((arq->options & eAdmissionRequest_destCallSignalAddress) &&
get_h225_addr(*data, &arq->destCallSignalAddress, &ip, &port) &&
ip == ct->tuplehash[dir].tuple.src.ip &&
port == info->sig_port[dir] && set_h225_addr_hook) {
port == info->sig_port[dir] && set_h225_addr) {
/* Answering ARQ */
return set_h225_addr_hook(pskb, data, 0,
&arq->destCallSignalAddress,
ct->tuplehash[!dir].tuple.dst.ip,
info->sig_port[!dir]);
return set_h225_addr(pskb, data, 0,
&arq->destCallSignalAddress,
ct->tuplehash[!dir].tuple.dst.ip,
info->sig_port[!dir]);
}
if ((arq->options & eAdmissionRequest_srcCallSignalAddress) &&
get_h225_addr(*data, &arq->srcCallSignalAddress, &ip, &port) &&
ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr_hook) {
ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr) {
/* Calling ARQ */
return set_h225_addr_hook(pskb, data, 0,
&arq->srcCallSignalAddress,
ct->tuplehash[!dir].tuple.dst.ip,
port);
return set_h225_addr(pskb, data, 0,
&arq->srcCallSignalAddress,
ct->tuplehash[!dir].tuple.dst.ip,
port);
}
return 0;
@ -1516,6 +1538,7 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct,
__be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp;
typeof(set_sig_addr_hook) set_sig_addr;
DEBUGP("ip_ct_ras: ACF\n");
@ -1523,10 +1546,10 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct,
return 0;
if (ip == ct->tuplehash[dir].tuple.dst.ip) { /* Answering ACF */
if (set_sig_addr_hook)
return set_sig_addr_hook(pskb, ct, ctinfo, data,
&acf->destCallSignalAddress,
1);
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr)
return set_sig_addr(pskb, ct, ctinfo, data,
&acf->destCallSignalAddress, 1);
return 0;
}
@ -1566,11 +1589,14 @@ static int process_lrq(struct sk_buff **pskb, struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, LocationRequest * lrq)
{
typeof(set_ras_addr_hook) set_ras_addr;
DEBUGP("ip_ct_ras: LRQ\n");
if (set_ras_addr_hook)
return set_ras_addr_hook(pskb, ct, ctinfo, data,
&lrq->replyAddress, 1);
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr)
return set_ras_addr(pskb, ct, ctinfo, data,
&lrq->replyAddress, 1);
return 0;
}
@ -1629,20 +1655,24 @@ static int process_irr(struct sk_buff **pskb, struct ip_conntrack *ct,
unsigned char **data, InfoRequestResponse * irr)
{
int ret;
typeof(set_ras_addr_hook) set_ras_addr;
typeof(set_sig_addr_hook) set_sig_addr;
DEBUGP("ip_ct_ras: IRR\n");
if (set_ras_addr_hook) {
ret = set_ras_addr_hook(pskb, ct, ctinfo, data,
&irr->rasAddress, 1);
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr) {
ret = set_ras_addr(pskb, ct, ctinfo, data,
&irr->rasAddress, 1);
if (ret < 0)
return -1;
}
if (set_sig_addr_hook) {
ret = set_sig_addr_hook(pskb, ct, ctinfo, data,
irr->callSignalAddress.item,
irr->callSignalAddress.count);
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr) {
ret = set_sig_addr(pskb, ct, ctinfo, data,
irr->callSignalAddress.item,
irr->callSignalAddress.count);
if (ret < 0)
return -1;
}
@ -1746,7 +1776,7 @@ static struct ip_conntrack_helper ip_conntrack_helper_ras = {
.me = THIS_MODULE,
.max_expected = 32,
.timeout = 240,
.tuple = {.src = {.u = {__constant_htons(RAS_PORT)}},
.tuple = {.src = {.u = {.tcp = {.port = __constant_htons(RAS_PORT)}}},
.dst = {.protonum = IPPROTO_UDP}},
.mask = {.src = {.u = {0xFFFE}},
.dst = {.protonum = 0xFF}},

View file

@ -1,874 +0,0 @@
/****************************************************************************
* ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323
* conntrack/NAT module.
*
* Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@users.sourceforge.net>
*
* This source code is licensed under General Public License version 2.
*
* See ip_conntrack_helper_h323_asn1.h for details.
*
****************************************************************************/
#ifdef __KERNEL__
#include <linux/kernel.h>
#else
#include <stdio.h>
#endif
#include <linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h>
/* Trace Flag */
#ifndef H323_TRACE
#define H323_TRACE 0
#endif
#if H323_TRACE
#define TAB_SIZE 4
#define IFTHEN(cond, act) if(cond){act;}
#ifdef __KERNEL__
#define PRINT printk
#else
#define PRINT printf
#endif
#define FNAME(name) name,
#else
#define IFTHEN(cond, act)
#define PRINT(fmt, args...)
#define FNAME(name)
#endif
/* ASN.1 Types */
#define NUL 0
#define BOOL 1
#define OID 2
#define INT 3
#define ENUM 4
#define BITSTR 5
#define NUMSTR 6
#define NUMDGT 6
#define TBCDSTR 6
#define OCTSTR 7
#define PRTSTR 7
#define IA5STR 7
#define GENSTR 7
#define BMPSTR 8
#define SEQ 9
#define SET 9
#define SEQOF 10
#define SETOF 10
#define CHOICE 11
/* Constraint Types */
#define FIXD 0
/* #define BITS 1-8 */
#define BYTE 9
#define WORD 10
#define CONS 11
#define SEMI 12
#define UNCO 13
/* ASN.1 Type Attributes */
#define SKIP 0
#define STOP 1
#define DECODE 2
#define EXT 4
#define OPEN 8
#define OPT 16
/* ASN.1 Field Structure */
typedef struct field_t {
#if H323_TRACE
char *name;
#endif
unsigned char type;
unsigned char sz;
unsigned char lb;
unsigned char ub;
unsigned short attr;
unsigned short offset;
struct field_t *fields;
} field_t;
/* Bit Stream */
typedef struct {
unsigned char *buf;
unsigned char *beg;
unsigned char *end;
unsigned char *cur;
unsigned bit;
} bitstr_t;
/* Tool Functions */
#define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;}
#define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;}
#define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;}
#define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND)
static unsigned get_len(bitstr_t * bs);
static unsigned get_bit(bitstr_t * bs);
static unsigned get_bits(bitstr_t * bs, unsigned b);
static unsigned get_bitmap(bitstr_t * bs, unsigned b);
static unsigned get_uint(bitstr_t * bs, int b);
/* Decoder Functions */
static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_int(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level);
static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level);
/* Decoder Functions Vector */
typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int);
static decoder_t Decoders[] = {
decode_nul,
decode_bool,
decode_oid,
decode_int,
decode_enum,
decode_bitstr,
decode_numstr,
decode_octstr,
decode_bmpstr,
decode_seq,
decode_seqof,
decode_choice,
};
/****************************************************************************
* H.323 Types
****************************************************************************/
#include "ip_conntrack_helper_h323_types.c"
/****************************************************************************
* Functions
****************************************************************************/
/* Assume bs is aligned && v < 16384 */
unsigned get_len(bitstr_t * bs)
{
unsigned v;
v = *bs->cur++;
if (v & 0x80) {
v &= 0x3f;
v <<= 8;
v += *bs->cur++;
}
return v;
}
/****************************************************************************/
unsigned get_bit(bitstr_t * bs)
{
unsigned b = (*bs->cur) & (0x80 >> bs->bit);
INC_BIT(bs);
return b;
}
/****************************************************************************/
/* Assume b <= 8 */
unsigned get_bits(bitstr_t * bs, unsigned b)
{
unsigned v, l;
v = (*bs->cur) & (0xffU >> bs->bit);
l = b + bs->bit;
if (l < 8) {
v >>= 8 - l;
bs->bit = l;
} else if (l == 8) {
bs->cur++;
bs->bit = 0;
} else { /* l > 8 */
v <<= 8;
v += *(++bs->cur);
v >>= 16 - l;
bs->bit = l - 8;
}
return v;
}
/****************************************************************************/
/* Assume b <= 32 */
unsigned get_bitmap(bitstr_t * bs, unsigned b)
{
unsigned v, l, shift, bytes;
if (!b)
return 0;
l = bs->bit + b;
if (l < 8) {
v = (unsigned) (*bs->cur) << (bs->bit + 24);
bs->bit = l;
} else if (l == 8) {
v = (unsigned) (*bs->cur++) << (bs->bit + 24);
bs->bit = 0;
} else {
for (bytes = l >> 3, shift = 24, v = 0; bytes;
bytes--, shift -= 8)
v |= (unsigned) (*bs->cur++) << shift;
if (l < 32) {
v |= (unsigned) (*bs->cur) << shift;
v <<= bs->bit;
} else if (l > 32) {
v <<= bs->bit;
v |= (*bs->cur) >> (8 - bs->bit);
}
bs->bit = l & 0x7;
}
v &= 0xffffffff << (32 - b);
return v;
}
/****************************************************************************
* Assume bs is aligned and sizeof(unsigned int) == 4
****************************************************************************/
unsigned get_uint(bitstr_t * bs, int b)
{
unsigned v = 0;
switch (b) {
case 4:
v |= *bs->cur++;
v <<= 8;
case 3:
v |= *bs->cur++;
v <<= 8;
case 2:
v |= *bs->cur++;
v <<= 8;
case 1:
v |= *bs->cur++;
break;
}
return v;
}
/****************************************************************************/
int decode_nul(bitstr_t * bs, field_t * f, char *base, int level)
{
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_bool(bitstr_t * bs, field_t * f, char *base, int level)
{
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
INC_BIT(bs);
CHECK_BOUND(bs, 0);
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_oid(bitstr_t * bs, field_t * f, char *base, int level)
{
int len;
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
BYTE_ALIGN(bs);
CHECK_BOUND(bs, 1);
len = *bs->cur++;
bs->cur += len;
CHECK_BOUND(bs, 0);
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_int(bitstr_t * bs, field_t * f, char *base, int level)
{
unsigned len;
PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
switch (f->sz) {
case BYTE: /* Range == 256 */
BYTE_ALIGN(bs);
bs->cur++;
break;
case WORD: /* 257 <= Range <= 64K */
BYTE_ALIGN(bs);
bs->cur += 2;
break;
case CONS: /* 64K < Range < 4G */
len = get_bits(bs, 2) + 1;
BYTE_ALIGN(bs);
if (base && (f->attr & DECODE)) { /* timeToLive */
unsigned v = get_uint(bs, len) + f->lb;
PRINT(" = %u", v);
*((unsigned *) (base + f->offset)) = v;
}
bs->cur += len;
break;
case UNCO:
BYTE_ALIGN(bs);
CHECK_BOUND(bs, 2);
len = get_len(bs);
bs->cur += len;
break;
default: /* 2 <= Range <= 255 */
INC_BITS(bs, f->sz);
break;
}
PRINT("\n");
CHECK_BOUND(bs, 0);
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_enum(bitstr_t * bs, field_t * f, char *base, int level)
{
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
if ((f->attr & EXT) && get_bit(bs)) {
INC_BITS(bs, 7);
} else {
INC_BITS(bs, f->sz);
}
CHECK_BOUND(bs, 0);
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level)
{
unsigned len;
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
BYTE_ALIGN(bs);
switch (f->sz) {
case FIXD: /* fixed length > 16 */
len = f->lb;
break;
case WORD: /* 2-byte length */
CHECK_BOUND(bs, 2);
len = (*bs->cur++) << 8;
len += (*bs->cur++) + f->lb;
break;
case SEMI:
CHECK_BOUND(bs, 2);
len = get_len(bs);
break;
default:
len = 0;
break;
}
bs->cur += len >> 3;
bs->bit = len & 7;
CHECK_BOUND(bs, 0);
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level)
{
unsigned len;
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
/* 2 <= Range <= 255 */
len = get_bits(bs, f->sz) + f->lb;
BYTE_ALIGN(bs);
INC_BITS(bs, (len << 2));
CHECK_BOUND(bs, 0);
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level)
{
unsigned len;
PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
switch (f->sz) {
case FIXD: /* Range == 1 */
if (f->lb > 2) {
BYTE_ALIGN(bs);
if (base && (f->attr & DECODE)) {
/* The IP Address */
IFTHEN(f->lb == 4,
PRINT(" = %d.%d.%d.%d:%d",
bs->cur[0], bs->cur[1],
bs->cur[2], bs->cur[3],
bs->cur[4] * 256 + bs->cur[5]));
*((unsigned *) (base + f->offset)) =
bs->cur - bs->buf;
}
}
len = f->lb;
break;
case BYTE: /* Range == 256 */
BYTE_ALIGN(bs);
CHECK_BOUND(bs, 1);
len = (*bs->cur++) + f->lb;
break;
case SEMI:
BYTE_ALIGN(bs);
CHECK_BOUND(bs, 2);
len = get_len(bs) + f->lb;
break;
default: /* 2 <= Range <= 255 */
len = get_bits(bs, f->sz) + f->lb;
BYTE_ALIGN(bs);
break;
}
bs->cur += len;
PRINT("\n");
CHECK_BOUND(bs, 0);
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level)
{
unsigned len;
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
switch (f->sz) {
case BYTE: /* Range == 256 */
BYTE_ALIGN(bs);
CHECK_BOUND(bs, 1);
len = (*bs->cur++) + f->lb;
break;
default: /* 2 <= Range <= 255 */
len = get_bits(bs, f->sz) + f->lb;
BYTE_ALIGN(bs);
break;
}
bs->cur += len << 1;
CHECK_BOUND(bs, 0);
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
{
unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len;
int err;
field_t *son;
unsigned char *beg = NULL;
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
/* Decode? */
base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;
/* Extensible? */
ext = (f->attr & EXT) ? get_bit(bs) : 0;
/* Get fields bitmap */
bmp = get_bitmap(bs, f->sz);
if (base)
*(unsigned *) base = bmp;
/* Decode the root components */
for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) {
if (son->attr & STOP) {
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
son->name);
return H323_ERROR_STOP;
}
if (son->attr & OPT) { /* Optional component */
if (!((0x80000000U >> (opt++)) & bmp)) /* Not exist */
continue;
}
/* Decode */
if (son->attr & OPEN) { /* Open field */
CHECK_BOUND(bs, 2);
len = get_len(bs);
CHECK_BOUND(bs, len);
if (!base) {
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE,
" ", son->name);
bs->cur += len;
continue;
}
beg = bs->cur;
/* Decode */
if ((err = (Decoders[son->type]) (bs, son, base,
level + 1)) <
H323_ERROR_NONE)
return err;
bs->cur = beg + len;
bs->bit = 0;
} else if ((err = (Decoders[son->type]) (bs, son, base,
level + 1)) <
H323_ERROR_NONE)
return err;
}
/* No extension? */
if (!ext)
return H323_ERROR_NONE;
/* Get the extension bitmap */
bmp2_len = get_bits(bs, 7) + 1;
CHECK_BOUND(bs, (bmp2_len + 7) >> 3);
bmp2 = get_bitmap(bs, bmp2_len);
bmp |= bmp2 >> f->sz;
if (base)
*(unsigned *) base = bmp;
BYTE_ALIGN(bs);
/* Decode the extension components */
for (opt = 0; opt < bmp2_len; opt++, i++, son++) {
if (i < f->ub && son->attr & STOP) {
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
son->name);
return H323_ERROR_STOP;
}
if (!((0x80000000 >> opt) & bmp2)) /* Not present */
continue;
/* Check Range */
if (i >= f->ub) { /* Newer Version? */
CHECK_BOUND(bs, 2);
len = get_len(bs);
CHECK_BOUND(bs, len);
bs->cur += len;
continue;
}
CHECK_BOUND(bs, 2);
len = get_len(bs);
CHECK_BOUND(bs, len);
if (!base || !(son->attr & DECODE)) {
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
son->name);
bs->cur += len;
continue;
}
beg = bs->cur;
if ((err = (Decoders[son->type]) (bs, son, base,
level + 1)) <
H323_ERROR_NONE)
return err;
bs->cur = beg + len;
bs->bit = 0;
}
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level)
{
unsigned count, effective_count = 0, i, len = 0;
int err;
field_t *son;
unsigned char *beg = NULL;
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
/* Decode? */
base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;
/* Decode item count */
switch (f->sz) {
case BYTE:
BYTE_ALIGN(bs);
CHECK_BOUND(bs, 1);
count = *bs->cur++;
break;
case WORD:
BYTE_ALIGN(bs);
CHECK_BOUND(bs, 2);
count = *bs->cur++;
count <<= 8;
count = *bs->cur++;
break;
case SEMI:
BYTE_ALIGN(bs);
CHECK_BOUND(bs, 2);
count = get_len(bs);
break;
default:
count = get_bits(bs, f->sz);
break;
}
count += f->lb;
/* Write Count */
if (base) {
effective_count = count > f->ub ? f->ub : count;
*(unsigned *) base = effective_count;
base += sizeof(unsigned);
}
/* Decode nested field */
son = f->fields;
if (base)
base -= son->offset;
for (i = 0; i < count; i++) {
if (son->attr & OPEN) {
BYTE_ALIGN(bs);
len = get_len(bs);
CHECK_BOUND(bs, len);
if (!base || !(son->attr & DECODE)) {
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE,
" ", son->name);
bs->cur += len;
continue;
}
beg = bs->cur;
if ((err = (Decoders[son->type]) (bs, son,
i <
effective_count ?
base : NULL,
level + 1)) <
H323_ERROR_NONE)
return err;
bs->cur = beg + len;
bs->bit = 0;
} else
if ((err = (Decoders[son->type]) (bs, son,
i <
effective_count ?
base : NULL,
level + 1)) <
H323_ERROR_NONE)
return err;
if (base)
base += son->offset;
}
return H323_ERROR_NONE;
}
/****************************************************************************/
int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
{
unsigned type, ext, len = 0;
int err;
field_t *son;
unsigned char *beg = NULL;
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
/* Decode? */
base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;
/* Decode the choice index number */
if ((f->attr & EXT) && get_bit(bs)) {
ext = 1;
type = get_bits(bs, 7) + f->lb;
} else {
ext = 0;
type = get_bits(bs, f->sz);
}
/* Write Type */
if (base)
*(unsigned *) base = type;
/* Check Range */
if (type >= f->ub) { /* Newer version? */
BYTE_ALIGN(bs);
len = get_len(bs);
CHECK_BOUND(bs, len);
bs->cur += len;
return H323_ERROR_NONE;
}
/* Transfer to son level */
son = &f->fields[type];
if (son->attr & STOP) {
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name);
return H323_ERROR_STOP;
}
if (ext || (son->attr & OPEN)) {
BYTE_ALIGN(bs);
len = get_len(bs);
CHECK_BOUND(bs, len);
if (!base || !(son->attr & DECODE)) {
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
son->name);
bs->cur += len;
return H323_ERROR_NONE;
}
beg = bs->cur;
if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) <
H323_ERROR_NONE)
return err;
bs->cur = beg + len;
bs->bit = 0;
} else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) <
H323_ERROR_NONE)
return err;
return H323_ERROR_NONE;
}
/****************************************************************************/
int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras)
{
static field_t ras_message = {
FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT,
0, _RasMessage
};
bitstr_t bs;
bs.buf = bs.beg = bs.cur = buf;
bs.end = buf + sz;
bs.bit = 0;
return decode_choice(&bs, &ras_message, (char *) ras, 0);
}
/****************************************************************************/
static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg,
size_t sz, H323_UserInformation * uuie)
{
static field_t h323_userinformation = {
FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT,
0, _H323_UserInformation
};
bitstr_t bs;
bs.buf = buf;
bs.beg = bs.cur = beg;
bs.end = beg + sz;
bs.bit = 0;
return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0);
}
/****************************************************************************/
int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
MultimediaSystemControlMessage *
mscm)
{
static field_t multimediasystemcontrolmessage = {
FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4,
DECODE | EXT, 0, _MultimediaSystemControlMessage
};
bitstr_t bs;
bs.buf = bs.beg = bs.cur = buf;
bs.end = buf + sz;
bs.bit = 0;
return decode_choice(&bs, &multimediasystemcontrolmessage,
(char *) mscm, 0);
}
/****************************************************************************/
int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931)
{
unsigned char *p = buf;
int len;
if (!p || sz < 1)
return H323_ERROR_BOUND;
/* Protocol Discriminator */
if (*p != 0x08) {
PRINT("Unknown Protocol Discriminator\n");
return H323_ERROR_RANGE;
}
p++;
sz--;
/* CallReferenceValue */
if (sz < 1)
return H323_ERROR_BOUND;
len = *p++;
sz--;
if (sz < len)
return H323_ERROR_BOUND;
p += len;
sz -= len;
/* Message Type */
if (sz < 1)
return H323_ERROR_BOUND;
q931->MessageType = *p++;
PRINT("MessageType = %02X\n", q931->MessageType);
if (*p & 0x80) {
p++;
sz--;
}
/* Decode Information Elements */
while (sz > 0) {
if (*p == 0x7e) { /* UserUserIE */
if (sz < 3)
break;
p++;
len = *p++ << 8;
len |= *p++;
sz -= 3;
if (sz < len)
break;
p++;
len--;
return DecodeH323_UserInformation(buf, p, len,
&q931->UUIE);
}
p++;
sz--;
if (sz < 1)
break;
len = *p++;
if (sz < len)
break;
p += len;
sz -= len;
}
PRINT("Q.931 UUIE not found\n");
return H323_ERROR_BOUND;
}

File diff suppressed because it is too large Load diff

View file

@ -124,6 +124,8 @@ EXPORT_SYMBOL(pptp_msg_name);
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 */
@ -133,7 +135,9 @@ static void pptp_expectfn(struct ip_conntrack *ct,
/* 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 */
if (!ip_nat_pptp_hook_expectfn) {
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;
@ -142,7 +146,7 @@ static void pptp_expectfn(struct ip_conntrack *ct,
DEBUGP("trying to unexpect other dir: ");
DUMP_TUPLE(&inv_t);
exp_other = ip_conntrack_expect_find(&inv_t);
exp_other = ip_conntrack_expect_find_get(&inv_t);
if (exp_other) {
/* delete other expectation. */
DEBUGP("found\n");
@ -153,8 +157,9 @@ static void pptp_expectfn(struct ip_conntrack *ct,
}
} else {
/* we need more than simple inversion */
ip_nat_pptp_hook_expectfn(ct, exp);
ip_nat_pptp_expectfn(ct, exp);
}
rcu_read_unlock();
}
static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t)
@ -176,7 +181,7 @@ static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t)
ip_conntrack_put(sibling);
return 1;
} else {
exp = ip_conntrack_expect_find(t);
exp = ip_conntrack_expect_find_get(t);
if (exp) {
DEBUGP("unexpect_related of expect %p\n", exp);
ip_conntrack_unexpect_related(exp);
@ -226,6 +231,7 @@ exp_gre(struct ip_conntrack *ct,
{
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)
@ -262,8 +268,9 @@ exp_gre(struct ip_conntrack *ct,
exp_reply->tuple.dst.u.gre.key = peer_callid;
exp_reply->tuple.dst.protonum = IPPROTO_GRE;
if (ip_nat_pptp_hook_exp_gre)
ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply);
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)
@ -303,6 +310,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
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]);
@ -402,9 +410,9 @@ pptp_inbound_pkt(struct sk_buff **pskb,
goto invalid;
}
if (ip_nat_pptp_hook_inbound)
return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh,
pptpReq);
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:
@ -427,6 +435,7 @@ pptp_outbound_pkt(struct sk_buff **pskb,
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]);
@ -492,9 +501,9 @@ pptp_outbound_pkt(struct sk_buff **pskb,
goto invalid;
}
if (ip_nat_pptp_hook_outbound)
return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh,
pptpReq);
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:

View file

@ -114,6 +114,7 @@ static int help(struct sk_buff **pskb,
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");
@ -222,11 +223,12 @@ static int help(struct sk_buff **pskb,
{ .tcp = { htons(0xFFFF) } }, 0xFF }});
exp->expectfn = NULL;
exp->flags = 0;
if (ip_nat_irc_hook)
ret = ip_nat_irc_hook(pskb, ctinfo,
addr_beg_p - ib_ptr,
addr_end_p - addr_beg_p,
exp);
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);

View file

@ -153,6 +153,7 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct ip_conntrack *ct)
return ret;
nfattr_failure:
ip_conntrack_proto_put(proto);
return -1;
}
@ -319,8 +320,6 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
} else if (events & (IPCT_NEW | IPCT_RELATED)) {
type = IPCTNL_MSG_CT_NEW;
flags = NLM_F_CREATE|NLM_F_EXCL;
/* dump everything */
events = ~0UL;
group = NFNLGRP_CONNTRACK_NEW;
} else if (events & (IPCT_STATUS | IPCT_PROTOINFO)) {
type = IPCTNL_MSG_CT_NEW;
@ -355,28 +354,35 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0)
goto nfattr_failure;
NFA_NEST_END(skb, nest_parms);
/* NAT stuff is now a status flag */
if ((events & IPCT_STATUS || events & IPCT_NATINFO)
&& ctnetlink_dump_status(skb, ct) < 0)
goto nfattr_failure;
if (events & IPCT_REFRESH
&& ctnetlink_dump_timeout(skb, ct) < 0)
goto nfattr_failure;
if (events & IPCT_PROTOINFO
&& ctnetlink_dump_protoinfo(skb, ct) < 0)
goto nfattr_failure;
if (events & IPCT_HELPINFO
&& ctnetlink_dump_helpinfo(skb, ct) < 0)
goto nfattr_failure;
if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
goto nfattr_failure;
if (events & IPCT_DESTROY) {
if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)
goto nfattr_failure;
} else {
if (ctnetlink_dump_status(skb, ct) < 0)
goto nfattr_failure;
if (events & IPCT_MARK
&& ctnetlink_dump_mark(skb, ct) < 0)
goto nfattr_failure;
if (ctnetlink_dump_timeout(skb, ct) < 0)
goto nfattr_failure;
if (events & IPCT_PROTOINFO
&& ctnetlink_dump_protoinfo(skb, ct) < 0)
goto nfattr_failure;
if ((events & IPCT_HELPER || ct->helper)
&& ctnetlink_dump_helpinfo(skb, ct) < 0)
goto nfattr_failure;
if ((events & IPCT_MARK || ct->mark)
&& ctnetlink_dump_mark(skb, ct) < 0)
goto nfattr_failure;
if (events & IPCT_COUNTER_FILLING &&
(ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0))
goto nfattr_failure;
}
nlh->nlmsg_len = skb->tail - b;
nfnetlink_send(skb, 0, group, 0);
@ -742,7 +748,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
ip_conntrack_put(ct);
return -ENOMEM;
}
NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
IPCTNL_MSG_CT_NEW, 1, ct);
@ -945,9 +950,11 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
ct->status |= IPS_CONFIRMED;
err = ctnetlink_change_status(ct, cda);
if (err < 0)
goto err;
if (cda[CTA_STATUS-1]) {
err = ctnetlink_change_status(ct, cda);
if (err < 0)
goto err;
}
if (cda[CTA_PROTOINFO-1]) {
err = ctnetlink_change_protoinfo(ct, cda);
@ -1256,7 +1263,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
exp = ip_conntrack_expect_find(&tuple);
exp = ip_conntrack_expect_find_get(&tuple);
if (!exp)
return -ENOENT;
@ -1272,8 +1279,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb2)
goto out;
NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid;
err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,
nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
1, exp);
@ -1310,7 +1316,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
return err;
/* bump usage count to 2 */
exp = ip_conntrack_expect_find(&tuple);
exp = ip_conntrack_expect_find_get(&tuple);
if (!exp)
return -ENOENT;

View file

@ -34,8 +34,6 @@
#include <linux/interrupt.h>
static DEFINE_RWLOCK(ip_ct_gre_lock);
#define ASSERT_READ_LOCK(x)
#define ASSERT_WRITE_LOCK(x)
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>

View file

@ -52,20 +52,56 @@ unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb,
const char *dptr);
EXPORT_SYMBOL_GPL(ip_nat_sdp_hook);
int ct_sip_get_info(const char *dptr, size_t dlen,
unsigned int *matchoff,
unsigned int *matchlen,
struct sip_header_nfo *hnfo);
EXPORT_SYMBOL_GPL(ct_sip_get_info);
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 ct_sip_hdrs[] = {
{ /* Via header */
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:",
@ -74,7 +110,7 @@ struct sip_header_nfo ct_sip_hdrs[] = {
.ln_strlen = sizeof("UDP ") - 1,
.match_len = epaddr_len,
},
{ /* Contact header */
[POS_CONTACT] = { /* SIP Contact header */
.lname = "Contact:",
.lnlen = sizeof("Contact:") - 1,
.sname = "\r\nm:",
@ -83,7 +119,7 @@ struct sip_header_nfo ct_sip_hdrs[] = {
.ln_strlen = sizeof("sip:") - 1,
.match_len = skp_epaddr_len
},
{ /* Content length header */
[POS_CONTENT] = { /* SIP Content length header */
.lname = "Content-Length:",
.lnlen = sizeof("Content-Length:") - 1,
.sname = "\r\nl:",
@ -92,7 +128,8 @@ struct sip_header_nfo ct_sip_hdrs[] = {
.ln_strlen = sizeof(":") - 1,
.match_len = skp_digits_len
},
{ /* SDP media info */
[POS_MEDIA] = { /* SDP media info */
.case_sensitive = 1,
.lname = "\nm=",
.lnlen = sizeof("\nm=") - 1,
.sname = "\rm=",
@ -101,7 +138,8 @@ struct sip_header_nfo ct_sip_hdrs[] = {
.ln_strlen = sizeof("audio ") - 1,
.match_len = digits_len
},
{ /* SDP owner address*/
[POS_OWNER] = { /* SDP owner address*/
.case_sensitive = 1,
.lname = "\no=",
.lnlen = sizeof("\no=") - 1,
.sname = "\ro=",
@ -110,7 +148,8 @@ struct sip_header_nfo ct_sip_hdrs[] = {
.ln_strlen = sizeof("IN IP4 ") - 1,
.match_len = epaddr_len
},
{ /* SDP connection info */
[POS_CONNECTION] = { /* SDP connection info */
.case_sensitive = 1,
.lname = "\nc=",
.lnlen = sizeof("\nc=") - 1,
.sname = "\rc=",
@ -119,16 +158,8 @@ struct sip_header_nfo ct_sip_hdrs[] = {
.ln_strlen = sizeof("IN IP4 ") - 1,
.match_len = epaddr_len
},
{ /* Requests headers */
.lname = "sip:",
.lnlen = sizeof("sip:") - 1,
.sname = "sip:",
.snlen = sizeof("sip:") - 1, /* yes, i know.. ;) */
.ln_str = "@",
.ln_strlen = sizeof("@") - 1,
.match_len = epaddr_len
},
{ /* SDP version header */
[POS_SDP_HEADER] = { /* SDP version header */
.case_sensitive = 1,
.lname = "\nv=",
.lnlen = sizeof("\nv=") - 1,
.sname = "\rv=",
@ -138,7 +169,6 @@ struct sip_header_nfo ct_sip_hdrs[] = {
.match_len = digits_len
}
};
EXPORT_SYMBOL_GPL(ct_sip_hdrs);
/* get line lenght until first CR or LF seen. */
int ct_sip_lnlen(const char *line, const char *limit)
@ -159,13 +189,19 @@ 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)
size_t needle_len, size_t haystack_len,
int case_sensitive)
{
const char *limit = haystack + (haystack_len - needle_len);
while (haystack <= limit) {
if (memcmp(haystack, needle, needle_len) == 0)
return haystack;
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;
@ -263,8 +299,9 @@ static int skp_epaddr_len(const char *dptr, const char *limit, int *shift)
int ct_sip_get_info(const char *dptr, size_t dlen,
unsigned int *matchoff,
unsigned int *matchlen,
struct sip_header_nfo *hnfo)
enum sip_header_pos pos)
{
struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos];
const char *limit, *aux, *k = dptr;
int shift = 0;
@ -272,12 +309,14 @@ int ct_sip_get_info(const char *dptr, size_t dlen,
while (dptr <= limit) {
if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
(strncmp(dptr, hnfo->sname, hnfo->snlen) != 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));
ct_sip_lnlen(dptr, limit),
hnfo->case_sensitive);
if (!aux) {
DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str,
hnfo->lname);
@ -298,6 +337,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen,
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,
@ -308,6 +348,7 @@ static int set_expected_rtp(struct sk_buff **pskb,
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)
@ -328,8 +369,9 @@ static int set_expected_rtp(struct sk_buff **pskb,
exp->expectfn = NULL;
exp->flags = 0;
if (ip_nat_sdp_hook)
ret = ip_nat_sdp_hook(pskb, ctinfo, exp, dptr);
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;
@ -351,6 +393,7 @@ static int sip_help(struct sk_buff **pskb,
int matchoff, matchlen;
__be32 ipaddr;
u_int16_t port;
typeof(ip_nat_sip_hook) ip_nat_sip;
/* No Data ? */
dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
@ -368,8 +411,9 @@ static int sip_help(struct sk_buff **pskb,
goto out;
}
if (ip_nat_sip_hook) {
if (!ip_nat_sip_hook(pskb, ctinfo, ct, &dptr)) {
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;
}
@ -389,7 +433,7 @@ static int sip_help(struct sk_buff **pskb,
}
/* Get ip and port address from SDP packet. */
if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
&ct_sip_hdrs[POS_CONNECTION]) > 0) {
POS_CONNECTION) > 0) {
/* We'll drop only if there are parse problems. */
if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr,
@ -398,7 +442,7 @@ static int sip_help(struct sk_buff **pskb,
goto out;
}
if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
&ct_sip_hdrs[POS_MEDIA]) > 0) {
POS_MEDIA) > 0) {
port = simple_strtoul(dptr + matchoff, NULL, 10);
if (port < 1024) {

View file

@ -28,9 +28,6 @@
#include <net/ip.h>
#include <net/route.h>
#define ASSERT_READ_LOCK(x)
#define ASSERT_WRITE_LOCK(x)
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
@ -139,7 +136,6 @@ static int ct_seq_show(struct seq_file *s, void *v)
const struct ip_conntrack *conntrack = tuplehash_to_ctrack(hash);
struct ip_conntrack_protocol *proto;
ASSERT_READ_LOCK(&ip_conntrack_lock);
IP_NF_ASSERT(conntrack);
/* we only want to print DIR_ORIGINAL */
@ -926,7 +922,7 @@ 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);
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);

View file

@ -50,6 +50,7 @@ static int tftp_help(struct sk_buff **pskb,
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,
(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr),
@ -81,8 +82,9 @@ static int tftp_help(struct sk_buff **pskb,
DEBUGP("expect: ");
DUMP_TUPLE(&exp->tuple);
DUMP_TUPLE(&exp->mask);
if (ip_nat_tftp_hook)
ret = ip_nat_tftp_hook(pskb, ctinfo, exp);
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);

View file

@ -70,15 +70,14 @@ static unsigned int help(struct sk_buff **pskb,
static void __exit ip_nat_amanda_fini(void)
{
ip_nat_amanda_hook = NULL;
/* Make sure noone calls it, meanwhile. */
synchronize_net();
rcu_assign_pointer(ip_nat_amanda_hook, NULL);
synchronize_rcu();
}
static int __init ip_nat_amanda_init(void)
{
BUG_ON(ip_nat_amanda_hook);
ip_nat_amanda_hook = help;
BUG_ON(rcu_dereference(ip_nat_amanda_hook));
rcu_assign_pointer(ip_nat_amanda_hook, help);
return 0;
}

View file

@ -362,12 +362,10 @@ manip_pkt(u_int16_t proto,
iph = (void *)(*pskb)->data + iphdroff;
if (maniptype == IP_NAT_MANIP_SRC) {
iph->check = nf_csum_update(~iph->saddr, target->src.ip,
iph->check);
nf_csum_replace4(&iph->check, iph->saddr, target->src.ip);
iph->saddr = target->src.ip;
} else {
iph->check = nf_csum_update(~iph->daddr, target->dst.ip,
iph->check);
nf_csum_replace4(&iph->check, iph->daddr, target->dst.ip);
iph->daddr = target->dst.ip;
}
return 1;

View file

@ -156,15 +156,14 @@ static unsigned int ip_nat_ftp(struct sk_buff **pskb,
static void __exit ip_nat_ftp_fini(void)
{
ip_nat_ftp_hook = NULL;
/* Make sure noone calls it, meanwhile. */
synchronize_net();
rcu_assign_pointer(ip_nat_ftp_hook, NULL);
synchronize_rcu();
}
static int __init ip_nat_ftp_init(void)
{
BUG_ON(ip_nat_ftp_hook);
ip_nat_ftp_hook = ip_nat_ftp;
BUG_ON(rcu_dereference(ip_nat_ftp_hook));
rcu_assign_pointer(ip_nat_ftp_hook, ip_nat_ftp);
return 0;
}

View file

@ -188,10 +188,8 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
csum_partial((char *)tcph,
datalen, 0));
} else
tcph->check = nf_proto_csum_update(*pskb,
htons(oldlen) ^ htons(0xFFFF),
htons(datalen),
tcph->check, 1);
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);
@ -264,12 +262,10 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb,
csum_partial((char *)udph,
datalen, 0));
if (!udph->check)
udph->check = -1;
udph->check = CSUM_MANGLED_0;
} else
udph->check = nf_proto_csum_update(*pskb,
htons(oldlen) ^ htons(0xFFFF),
htons(datalen),
udph->check, 1);
nf_proto_csum_replace2(&udph->check, *pskb,
htons(oldlen), htons(datalen), 1);
return 1;
}
EXPORT_SYMBOL(ip_nat_mangle_udp_packet);
@ -307,14 +303,10 @@ sack_adjust(struct sk_buff *skb,
ntohl(sack->start_seq), new_start_seq,
ntohl(sack->end_seq), new_end_seq);
tcph->check = nf_proto_csum_update(skb,
~sack->start_seq,
new_start_seq,
tcph->check, 0);
tcph->check = nf_proto_csum_update(skb,
~sack->end_seq,
new_end_seq,
tcph->check, 0);
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);
@ -397,10 +389,8 @@ ip_nat_seq_adjust(struct sk_buff **pskb,
else
newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq,
tcph->check, 0);
tcph->check = nf_proto_csum_update(*pskb, ~tcph->ack_seq, newack,
tcph->check, 0);
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),

View file

@ -563,25 +563,25 @@ static int nat_callforwarding(struct sk_buff **pskb, struct ip_conntrack *ct,
/****************************************************************************/
static int __init init(void)
{
BUG_ON(set_h245_addr_hook != NULL);
BUG_ON(set_h225_addr_hook != NULL);
BUG_ON(set_sig_addr_hook != NULL);
BUG_ON(set_ras_addr_hook != NULL);
BUG_ON(nat_rtp_rtcp_hook != NULL);
BUG_ON(nat_t120_hook != NULL);
BUG_ON(nat_h245_hook != NULL);
BUG_ON(nat_callforwarding_hook != NULL);
BUG_ON(nat_q931_hook != NULL);
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);
set_h245_addr_hook = set_h245_addr;
set_h225_addr_hook = set_h225_addr;
set_sig_addr_hook = set_sig_addr;
set_ras_addr_hook = set_ras_addr;
nat_rtp_rtcp_hook = nat_rtp_rtcp;
nat_t120_hook = nat_t120;
nat_h245_hook = nat_h245;
nat_callforwarding_hook = nat_callforwarding;
nat_q931_hook = nat_q931;
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;
@ -590,16 +590,16 @@ static int __init init(void)
/****************************************************************************/
static void __exit fini(void)
{
set_h245_addr_hook = NULL;
set_h225_addr_hook = NULL;
set_sig_addr_hook = NULL;
set_ras_addr_hook = NULL;
nat_rtp_rtcp_hook = NULL;
nat_t120_hook = NULL;
nat_h245_hook = NULL;
nat_callforwarding_hook = NULL;
nat_q931_hook = NULL;
synchronize_net();
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();
}
/****************************************************************************/

View file

@ -101,7 +101,7 @@ static void pptp_nat_expected(struct ip_conntrack *ct,
DEBUGP("trying to unexpect other dir: ");
DUMP_TUPLE(&t);
other_exp = ip_conntrack_expect_find(&t);
other_exp = ip_conntrack_expect_find_get(&t);
if (other_exp) {
ip_conntrack_unexpect_related(other_exp);
ip_conntrack_expect_put(other_exp);
@ -315,17 +315,17 @@ static int __init ip_nat_helper_pptp_init(void)
if (ret < 0)
return ret;
BUG_ON(ip_nat_pptp_hook_outbound);
ip_nat_pptp_hook_outbound = &pptp_outbound_pkt;
BUG_ON(rcu_dereference(ip_nat_pptp_hook_outbound));
rcu_assign_pointer(ip_nat_pptp_hook_outbound, pptp_outbound_pkt);
BUG_ON(ip_nat_pptp_hook_inbound);
ip_nat_pptp_hook_inbound = &pptp_inbound_pkt;
BUG_ON(rcu_dereference(ip_nat_pptp_hook_inbound));
rcu_assign_pointer(ip_nat_pptp_hook_inbound, pptp_inbound_pkt);
BUG_ON(ip_nat_pptp_hook_exp_gre);
ip_nat_pptp_hook_exp_gre = &pptp_exp_gre;
BUG_ON(rcu_dereference(ip_nat_pptp_hook_exp_gre));
rcu_assign_pointer(ip_nat_pptp_hook_exp_gre, pptp_exp_gre);
BUG_ON(ip_nat_pptp_hook_expectfn);
ip_nat_pptp_hook_expectfn = &pptp_nat_expected;
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;
@ -335,14 +335,13 @@ static void __exit ip_nat_helper_pptp_fini(void)
{
DEBUGP("cleanup_module\n" );
ip_nat_pptp_hook_expectfn = NULL;
ip_nat_pptp_hook_exp_gre = NULL;
ip_nat_pptp_hook_inbound = NULL;
ip_nat_pptp_hook_outbound = NULL;
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();
/* Make sure noone calls it, meanwhile */
synchronize_net();
printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
}

View file

@ -98,15 +98,14 @@ static unsigned int help(struct sk_buff **pskb,
static void __exit ip_nat_irc_fini(void)
{
ip_nat_irc_hook = NULL;
/* Make sure noone calls it, meanwhile. */
synchronize_net();
rcu_assign_pointer(ip_nat_irc_hook, NULL);
synchronize_rcu();
}
static int __init ip_nat_irc_init(void)
{
BUG_ON(ip_nat_irc_hook);
ip_nat_irc_hook = help;
BUG_ON(rcu_dereference(ip_nat_irc_hook));
rcu_assign_pointer(ip_nat_irc_hook, help);
return 0;
}

View file

@ -129,11 +129,9 @@ gre_manip_pkt(struct sk_buff **pskb,
}
if (greh->csum) {
/* FIXME: Never tested this code... */
*(gre_csum(greh)) =
nf_proto_csum_update(*pskb,
~*(gre_key(greh)),
tuple->dst.u.gre.key,
*(gre_csum(greh)), 0);
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;

View file

@ -24,8 +24,8 @@ icmp_in_range(const struct ip_conntrack_tuple *tuple,
const union ip_conntrack_manip_proto *min,
const union ip_conntrack_manip_proto *max)
{
return (tuple->src.u.icmp.id >= min->icmp.id
&& tuple->src.u.icmp.id <= max->icmp.id);
return ntohs(tuple->src.u.icmp.id) >= ntohs(min->icmp.id) &&
ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id);
}
static int
@ -66,10 +66,8 @@ icmp_manip_pkt(struct sk_buff **pskb,
return 0;
hdr = (struct icmphdr *)((*pskb)->data + hdroff);
hdr->checksum = nf_proto_csum_update(*pskb,
hdr->un.echo.id ^ htons(0xFFFF),
tuple->src.u.icmp.id,
hdr->checksum, 0);
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;
}

View file

@ -129,9 +129,8 @@ tcp_manip_pkt(struct sk_buff **pskb,
if (hdrsize < sizeof(*hdr))
return 1;
hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1);
hdr->check = nf_proto_csum_update(*pskb, oldport ^ htons(0xFFFF), newport,
hdr->check, 0);
nf_proto_csum_replace4(&hdr->check, *pskb, oldip, newip, 1);
nf_proto_csum_replace2(&hdr->check, *pskb, oldport, newport, 0);
return 1;
}

View file

@ -115,13 +115,10 @@ udp_manip_pkt(struct sk_buff **pskb,
}
if (hdr->check || (*pskb)->ip_summed == CHECKSUM_PARTIAL) {
hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip,
hdr->check, 1);
hdr->check = nf_proto_csum_update(*pskb,
*portptr ^ htons(0xFFFF), newport,
hdr->check, 0);
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 = -1;
hdr->check = CSUM_MANGLED_0;
}
*portptr = newport;
return 1;

View file

@ -29,18 +29,123 @@ MODULE_DESCRIPTION("SIP NAT helper");
#define DEBUGP(format, args...)
#endif
extern struct sip_header_nfo ct_sip_hdrs[];
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 + (*pskb)->nh.iph->ihl*4 + 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 = (*pskb)->nh.iph->ihl*4 + 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,
struct sip_header_nfo *hnfo)
enum sip_header_pos pos)
{
unsigned int matchlen, matchoff;
if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, hnfo) <= 0)
if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, pos) <= 0)
return 0;
if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
@ -52,77 +157,6 @@ static unsigned int mangle_sip_packet(struct sk_buff **pskb,
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 ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
unsigned int bufflen, dataoff;
__be32 ip;
__be16 port;
dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
ip = ct->tuplehash[!dir].tuple.dst.ip;
port = ct->tuplehash[!dir].tuple.dst.u.udp.port;
bufflen = sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(ip), ntohs(port));
/* short packet ? */
if (((*pskb)->len - dataoff) < (sizeof("SIP/2.0") - 1))
return 0;
/* Basic rules: requests and responses. */
if (memcmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) == 0) {
const char *aux;
if ((ctinfo) < IP_CT_IS_REPLY) {
mangle_sip_packet(pskb, ctinfo, ct, dptr,
(*pskb)->len - dataoff,
buffer, bufflen,
&ct_sip_hdrs[POS_CONTACT]);
return 1;
}
if (!mangle_sip_packet(pskb, ctinfo, ct, dptr,
(*pskb)->len - dataoff,
buffer, bufflen, &ct_sip_hdrs[POS_VIA]))
return 0;
/* This search should ignore case, but later.. */
aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1,
(*pskb)->len - dataoff);
if (!aux)
return 0;
if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"),
ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff)))
return 1;
return mangle_sip_packet(pskb, ctinfo, ct, dptr,
(*pskb)->len - dataoff,
buffer, bufflen,
&ct_sip_hdrs[POS_CONTACT]);
}
if ((ctinfo) < IP_CT_IS_REPLY) {
if (!mangle_sip_packet(pskb, ctinfo, ct, dptr,
(*pskb)->len - dataoff,
buffer, bufflen, &ct_sip_hdrs[POS_VIA]))
return 0;
/* Mangle Contact if exists only. - watch udp_nat_mangle()! */
mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff,
buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]);
return 1;
}
/* This mangle requests headers. */
return mangle_sip_packet(pskb, ctinfo, ct, dptr,
ct_sip_lnlen(*dptr,
*dptr + (*pskb)->len - dataoff),
buffer, bufflen, &ct_sip_hdrs[POS_REQ_HEADER]);
}
static int mangle_content_len(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
struct ip_conntrack *ct,
@ -136,7 +170,7 @@ static int mangle_content_len(struct sk_buff **pskb,
/* Get actual SDP lenght */
if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
&matchlen, &ct_sip_hdrs[POS_SDP_HEADER]) > 0) {
&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. */
@ -144,7 +178,7 @@ static int mangle_content_len(struct sk_buff **pskb,
/* Now, update SDP lenght */
if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
&matchlen, &ct_sip_hdrs[POS_CONTENT]) > 0) {
&matchlen, POS_CONTENT) > 0) {
bufflen = sprintf(buffer, "%u", c_len);
@ -170,17 +204,17 @@ static unsigned int mangle_sdp(struct sk_buff **pskb,
/* 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, &ct_sip_hdrs[POS_OWNER]))
buffer, bufflen, POS_OWNER))
return 0;
if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
buffer, bufflen, &ct_sip_hdrs[POS_CONNECTION]))
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, &ct_sip_hdrs[POS_MEDIA]))
buffer, bufflen, POS_MEDIA))
return 0;
return mangle_content_len(pskb, ctinfo, ct, dptr);
@ -230,18 +264,17 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb,
static void __exit fini(void)
{
ip_nat_sip_hook = NULL;
ip_nat_sdp_hook = NULL;
/* Make sure noone calls it, meanwhile. */
synchronize_net();
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(ip_nat_sip_hook);
BUG_ON(ip_nat_sdp_hook);
ip_nat_sip_hook = ip_nat_sip;
ip_nat_sdp_hook = ip_nat_sdp;
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;
}

View file

@ -64,7 +64,7 @@ MODULE_DESCRIPTION("Basic SNMP Application Layer Gateway");
#define SNMP_PORT 161
#define SNMP_TRAP_PORT 162
#define NOCT1(n) (u_int8_t )((n) & 0xff)
#define NOCT1(n) (*(u8 *)n)
static int debug;
static DEFINE_SPINLOCK(snmp_lock);
@ -613,7 +613,7 @@ struct snmp_v1_trap
static inline void mangle_address(unsigned char *begin,
unsigned char *addr,
const struct oct1_map *map,
u_int16_t *check);
__sum16 *check);
struct snmp_cnv
{
unsigned int class;
@ -873,38 +873,24 @@ static unsigned char snmp_request_decode(struct asn1_ctx *ctx,
* Fast checksum update for possibly oddly-aligned UDP byte, from the
* code example in the draft.
*/
static void fast_csum(unsigned char *csum,
static void fast_csum(__sum16 *csum,
const unsigned char *optr,
const unsigned char *nptr,
int odd)
int offset)
{
long x, old, new;
x = csum[0] * 256 + csum[1];
x =~ x & 0xFFFF;
if (odd) old = optr[0] * 256;
else old = optr[0];
x -= old & 0xFFFF;
if (x <= 0) {
x--;
x &= 0xFFFF;
unsigned char s[4];
if (offset & 1) {
s[0] = s[2] = 0;
s[1] = ~*optr;
s[3] = *nptr;
} else {
s[1] = s[3] = 0;
s[0] = ~*optr;
s[2] = *nptr;
}
if (odd) new = nptr[0] * 256;
else new = nptr[0];
x += new & 0xFFFF;
if (x & 0x10000) {
x++;
x &= 0xFFFF;
}
x =~ x & 0xFFFF;
csum[0] = x / 256;
csum[1] = x & 0xFF;
*csum = csum_fold(csum_partial(s, 4, ~csum_unfold(*csum)));
}
/*
@ -915,9 +901,9 @@ static void fast_csum(unsigned char *csum,
static inline void mangle_address(unsigned char *begin,
unsigned char *addr,
const struct oct1_map *map,
u_int16_t *check)
__sum16 *check)
{
if (map->from == NOCT1(*addr)) {
if (map->from == NOCT1(addr)) {
u_int32_t old;
if (debug)
@ -927,11 +913,8 @@ static inline void mangle_address(unsigned char *begin,
/* Update UDP checksum if being used */
if (*check) {
unsigned char odd = !((addr - begin) % 2);
fast_csum((unsigned char *)check,
&map->from, &map->to, odd);
fast_csum(check,
&map->from, &map->to, addr - begin);
}
if (debug)
@ -943,7 +926,7 @@ static inline void mangle_address(unsigned char *begin,
static unsigned char snmp_trap_decode(struct asn1_ctx *ctx,
struct snmp_v1_trap *trap,
const struct oct1_map *map,
u_int16_t *check)
__sum16 *check)
{
unsigned int cls, con, tag, len;
unsigned char *end;
@ -1037,7 +1020,7 @@ static void hex_dump(unsigned char *buf, size_t len)
static int snmp_parse_mangle(unsigned char *msg,
u_int16_t len,
const struct oct1_map *map,
u_int16_t *check)
__sum16 *check)
{
unsigned char *eoc, *end;
unsigned int cls, con, tag, vers, pdutype;
@ -1223,12 +1206,12 @@ static int snmp_translate(struct ip_conntrack *ct,
*/
if (dir == IP_CT_DIR_ORIGINAL) {
/* SNAT traps */
map.from = NOCT1(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip);
map.to = NOCT1(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip);
map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip);
map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip);
} else {
/* DNAT replies */
map.from = NOCT1(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
map.to = NOCT1(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip);
map.from = NOCT1(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
map.to = NOCT1(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip);
}
if (map.from == map.to)
@ -1294,11 +1277,11 @@ static struct ip_conntrack_helper snmp_helper = {
.help = help,
.name = "snmp",
.tuple = { .src = { .u = { __constant_htons(SNMP_PORT) } },
.dst = { .protonum = IPPROTO_UDP },
.tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_PORT)}}},
.dst = {.protonum = IPPROTO_UDP},
},
.mask = { .src = { .u = { 0xFFFF } },
.dst = { .protonum = 0xFF },
.mask = {.src = {.u = {0xFFFF}},
.dst = {.protonum = 0xFF},
},
};
@ -1309,11 +1292,11 @@ static struct ip_conntrack_helper snmp_trap_helper = {
.help = help,
.name = "snmp_trap",
.tuple = { .src = { .u = { __constant_htons(SNMP_TRAP_PORT) } },
.dst = { .protonum = IPPROTO_UDP },
.tuple = {.src = {.u = {.udp = {.port = __constant_htons(SNMP_TRAP_PORT)}}},
.dst = {.protonum = IPPROTO_UDP},
},
.mask = { .src = { .u = { 0xFFFF } },
.dst = { .protonum = 0xFF },
.mask = {.src = {.u = {0xFFFF}},
.dst = {.protonum = 0xFF},
},
};

View file

@ -44,12 +44,6 @@
#define DEBUGP(format, args...)
#endif
#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \
: ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \
: ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \
: ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \
: "*ERROR*")))
#ifdef CONFIG_XFRM
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{

View file

@ -55,15 +55,14 @@ static unsigned int help(struct sk_buff **pskb,
static void __exit ip_nat_tftp_fini(void)
{
ip_nat_tftp_hook = NULL;
/* Make sure noone calls it, meanwhile. */
synchronize_net();
rcu_assign_pointer(ip_nat_tftp_hook, NULL);
synchronize_rcu();
}
static int __init ip_nat_tftp_init(void)
{
BUG_ON(ip_nat_tftp_hook);
ip_nat_tftp_hook = help;
BUG_ON(rcu_dereference(ip_nat_tftp_hook));
rcu_assign_pointer(ip_nat_tftp_hook, help);
return 0;
}

View file

@ -243,7 +243,7 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
pmsg->data_len = data_len;
pmsg->timestamp_sec = entry->skb->tstamp.off_sec;
pmsg->timestamp_usec = entry->skb->tstamp.off_usec;
pmsg->mark = entry->skb->nfmark;
pmsg->mark = entry->skb->mark;
pmsg->hook = entry->info->hook;
pmsg->hw_protocol = entry->skb->protocol;

View file

@ -40,8 +40,6 @@
#define DEBUGP
#endif
#define ASSERT_READ_LOCK(x)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <[email protected]>");
MODULE_DESCRIPTION("iptables target for CLUSTERIP");
@ -123,7 +121,6 @@ __clusterip_config_find(__be32 clusterip)
{
struct list_head *pos;
ASSERT_READ_LOCK(&clusterip_lock);
list_for_each(pos, &clusterip_configs) {
struct clusterip_config *c = list_entry(pos,
struct clusterip_config, list);
@ -170,7 +167,6 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip,
struct net_device *dev)
{
struct clusterip_config *c;
char buffer[16];
c = kzalloc(sizeof(*c), GFP_ATOMIC);
if (!c)
@ -187,12 +183,17 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip,
atomic_set(&c->entries, 1);
#ifdef CONFIG_PROC_FS
/* create proc dir entry */
sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
c->pde = create_proc_entry(buffer, S_IWUSR|S_IRUSR, clusterip_procdir);
if (!c->pde) {
kfree(c);
return NULL;
{
char buffer[16];
/* create proc dir entry */
sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
c->pde = create_proc_entry(buffer, S_IWUSR|S_IRUSR,
clusterip_procdir);
if (!c->pde) {
kfree(c);
return NULL;
}
}
c->pde->proc_fops = &clusterip_proc_fops;
c->pde->data = c;
@ -205,6 +206,7 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip,
return c;
}
#ifdef CONFIG_PROC_FS
static int
clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum)
{
@ -232,6 +234,7 @@ clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum)
return 1;
}
#endif
static inline u_int32_t
clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config)
@ -737,8 +740,10 @@ static int __init ipt_clusterip_init(void)
CLUSTERIP_VERSION);
return 0;
#ifdef CONFIG_PROC_FS
cleanup_hook:
nf_unregister_hook(&cip_arp_ops);
#endif /* CONFIG_PROC_FS */
cleanup_target:
ipt_unregister_target(&clusterip_tgt);
return ret;

View file

@ -28,17 +28,16 @@ static inline int
set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
{
struct iphdr *iph = (*pskb)->nh.iph;
u_int16_t oldtos;
if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
__u8 oldtos;
if (!skb_make_writable(pskb, sizeof(struct iphdr)))
return 0;
iph = (*pskb)->nh.iph;
oldtos = iph->tos;
iph->tos &= ~IPT_ECN_IP_MASK;
iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
htons(iph->tos), iph->check);
nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
}
return 1;
}
@ -72,10 +71,8 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
if (einfo->operation & IPT_ECN_OP_SET_CWR)
tcph->cwr = einfo->proto.tcp.cwr;
tcph->check = nf_proto_csum_update((*pskb),
oldval ^ htons(0xFFFF),
((__be16 *)tcph)[6],
tcph->check, 0);
nf_proto_csum_replace2(&tcph->check, *pskb,
oldval, ((__be16 *)tcph)[6], 0);
return 1;
}

View file

@ -171,11 +171,15 @@ static void dump_packet(const struct nf_loginfo *info,
}
break;
}
case IPPROTO_UDP: {
case IPPROTO_UDP:
case IPPROTO_UDPLITE: {
struct udphdr _udph, *uh;
/* Max length: 10 "PROTO=UDP " */
printk("PROTO=UDP ");
if (ih->protocol == IPPROTO_UDP)
/* Max length: 10 "PROTO=UDP " */
printk("PROTO=UDP " );
else /* Max length: 14 "PROTO=UDPLITE " */
printk("PROTO=UDPLITE ");
if (ntohs(ih->frag_off) & IP_OFFSET)
break;
@ -341,6 +345,7 @@ static void dump_packet(const struct nf_loginfo *info,
/* IP: 40+46+6+11+127 = 230 */
/* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */
/* UDP: 10+max(25,20) = 35 */
/* UDPLITE: 14+max(25,20) = 39 */
/* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
/* ESP: 10+max(25)+15 = 50 */
/* AH: 9+max(25)+15 = 49 */
@ -425,13 +430,8 @@ ipt_log_target(struct sk_buff **pskb,
li.u.log.level = loginfo->level;
li.u.log.logflags = loginfo->logflags;
if (loginfo->logflags & IPT_LOG_NFLOG)
nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
"%s", loginfo->prefix);
else
ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
loginfo->prefix);
ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
loginfo->prefix);
return IPT_CONTINUE;
}

View file

@ -2,7 +2,7 @@
(depending on route). */
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
* (C) 2002-2006 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
@ -20,7 +20,11 @@
#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/ip_tables.h>
MODULE_LICENSE("GPL");
@ -65,23 +69,33 @@ masquerade_target(struct sk_buff **pskb,
const struct xt_target *target,
const void *targinfo)
{
#ifdef CONFIG_NF_NAT_NEEDED
struct nf_conn_nat *nat;
#endif
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
const struct ip_nat_multi_range_compat *mr;
struct ip_nat_range newrange;
const struct ip_nat_multi_range_compat *mr;
struct rtable *rt;
__be32 newsrc;
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
ct = ip_conntrack_get(*pskb, &ctinfo);
#ifdef CONFIG_NF_NAT_NEEDED
nat = nfct_nat(ct);
#endif
IP_NF_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;
@ -93,7 +107,11 @@ 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. */
@ -109,10 +127,17 @@ masquerade_target(struct sk_buff **pskb,
static inline int
device_cmp(struct ip_conntrack *i, void *ifindex)
{
#ifdef CONFIG_NF_NAT_NEEDED
struct nf_conn_nat *nat = nfct_nat(i);
#endif
int ret;
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;

View file

@ -15,7 +15,11 @@
#include <linux/netdevice.h>
#include <linux/netfilter.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
#define MODULENAME "NETMAP"
MODULE_LICENSE("GPL");

View file

@ -1,6 +1,6 @@
/* Redirect. Simple mapping which alters dst to a local IP address. */
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
* (C) 2002-2006 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
@ -18,7 +18,11 @@
#include <net/protocol.h>
#include <net/checksum.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
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <[email protected]>");

View file

@ -76,7 +76,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
/* This packet will not be the same as the other: clear nf fields */
nf_reset(nskb);
nskb->nfmark = 0;
nskb->mark = 0;
skb_init_secmark(nskb);
tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
@ -114,6 +114,14 @@ static void send_reset(struct sk_buff *oldskb, int hook)
tcph->window = 0;
tcph->urg_ptr = 0;
/* Adjust TCP checksum */
tcph->check = 0;
tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
nskb->nh.iph->saddr,
nskb->nh.iph->daddr,
csum_partial((char *)tcph,
sizeof(struct tcphdr), 0));
/* Set DF, id = 0 */
nskb->nh.iph->frag_off = htons(IP_DF);
nskb->nh.iph->id = 0;
@ -129,14 +137,8 @@ static void send_reset(struct sk_buff *oldskb, int hook)
if (ip_route_me_harder(&nskb, addr_type))
goto free_nskb;
/* Adjust TCP checksum */
nskb->ip_summed = CHECKSUM_NONE;
tcph->check = 0;
tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
nskb->nh.iph->saddr,
nskb->nh.iph->daddr,
csum_partial((char *)tcph,
sizeof(struct tcphdr), 0));
/* Adjust IP TTL */
nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);

View file

@ -34,7 +34,11 @@
#include <net/protocol.h>
#include <net/checksum.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/ipt_SAME.h>
MODULE_LICENSE("GPL");
@ -152,11 +156,17 @@ 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]);

View file

@ -97,10 +97,8 @@ ipt_tcpmss_target(struct sk_buff **pskb,
opt[i+2] = (newmss & 0xff00) >> 8;
opt[i+3] = (newmss & 0x00ff);
tcph->check = nf_proto_csum_update(*pskb,
htons(oldmss)^htons(0xFFFF),
htons(newmss),
tcph->check, 0);
nf_proto_csum_replace2(&tcph->check, *pskb,
htons(oldmss), htons(newmss), 0);
return IPT_CONTINUE;
}
}
@ -126,28 +124,22 @@ ipt_tcpmss_target(struct sk_buff **pskb,
opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
tcph->check = nf_proto_csum_update(*pskb,
htons(tcplen) ^ htons(0xFFFF),
htons(tcplen + TCPOLEN_MSS),
tcph->check, 1);
nf_proto_csum_replace2(&tcph->check, *pskb,
htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
opt[0] = TCPOPT_MSS;
opt[1] = TCPOLEN_MSS;
opt[2] = (newmss & 0xff00) >> 8;
opt[3] = (newmss & 0x00ff);
tcph->check = nf_proto_csum_update(*pskb, htonl(~0), *((__be32 *)opt),
tcph->check, 0);
nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
oldval = ((__be16 *)tcph)[6];
tcph->doff += TCPOLEN_MSS/4;
tcph->check = nf_proto_csum_update(*pskb,
oldval ^ htons(0xFFFF),
((__be16 *)tcph)[6],
tcph->check, 0);
nf_proto_csum_replace2(&tcph->check, *pskb,
oldval, ((__be16 *)tcph)[6], 0);
newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
iph->check = nf_csum_update(iph->tot_len ^ htons(0xFFFF),
newtotlen, iph->check);
nf_csum_replace2(&iph->check, iph->tot_len, newtotlen);
iph->tot_len = newtotlen;
return IPT_CONTINUE;
}

View file

@ -30,16 +30,15 @@ target(struct sk_buff **pskb,
{
const struct ipt_tos_target_info *tosinfo = targinfo;
struct iphdr *iph = (*pskb)->nh.iph;
u_int16_t oldtos;
if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
__u8 oldtos;
if (!skb_make_writable(pskb, sizeof(struct iphdr)))
return NF_DROP;
iph = (*pskb)->nh.iph;
oldtos = iph->tos;
iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
htons(iph->tos), iph->check);
nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
}
return IPT_CONTINUE;
}

View file

@ -54,9 +54,8 @@ ipt_ttl_target(struct sk_buff **pskb,
}
if (new_ttl != iph->ttl) {
iph->check = nf_csum_update(htons((iph->ttl << 8)) ^ htons(0xFFFF),
htons(new_ttl << 8),
iph->check);
nf_csum_replace2(&iph->check, htons(iph->ttl << 8),
htons(new_ttl << 8));
iph->ttl = new_ttl;
}

View file

@ -239,7 +239,7 @@ static void ipt_ulog_packet(unsigned int hooknum,
pm->data_len = copy_len;
pm->timestamp_sec = skb->tstamp.off_sec;
pm->timestamp_usec = skb->tstamp.off_usec;
pm->mark = skb->nfmark;
pm->mark = skb->mark;
pm->hook = hooknum;
if (prefix != NULL)
strncpy(pm->prefix, prefix, sizeof(pm->prefix));

View file

@ -1,733 +0,0 @@
/* iptables match extension to limit the number of packets per second
* seperately for each hashbucket (sourceip/sourceport/dstip/dstport)
*
* (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
*
* $Id: ipt_hashlimit.c 3244 2004-10-20 16:24:29Z laforge@netfilter.org $
*
* Development of this code was funded by Astaro AG, http://www.astaro.com/
*
* based on ipt_limit.c by:
* Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
* Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
* Rusty Russell <rusty@rustcorp.com.au>
*
* The general idea is to create a hash table for every dstip and have a
* seperate limit counter per tuple. This way you can do something like 'limit
* the number of syn packets for each of my internal addresses.
*
* Ideally this would just be implemented as a general 'hash' match, which would
* allow us to attach any iptables target to it's hash buckets. But this is
* not possible in the current iptables architecture. As always, pkttables for
* 2.7.x will help ;)
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/random.h>
#include <linux/jhash.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_hashlimit.h>
/* FIXME: this is just for IP_NF_ASSERRT */
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/mutex.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <[email protected]>");
MODULE_DESCRIPTION("iptables match for limiting per hash-bucket");
/* need to declare this at the top */
static struct proc_dir_entry *hashlimit_procdir;
static struct file_operations dl_file_ops;
/* hash table crap */
struct dsthash_dst {
__be32 src_ip;
__be32 dst_ip;
/* ports have to be consecutive !!! */
__be16 src_port;
__be16 dst_port;
};
struct dsthash_ent {
/* static / read-only parts in the beginning */
struct hlist_node node;
struct dsthash_dst dst;
/* modified structure members in the end */
unsigned long expires; /* precalculated expiry time */
struct {
unsigned long prev; /* last modification */
u_int32_t credit;
u_int32_t credit_cap, cost;
} rateinfo;
};
struct ipt_hashlimit_htable {
struct hlist_node node; /* global list of all htables */
atomic_t use;
struct hashlimit_cfg cfg; /* config */
/* used internally */
spinlock_t lock; /* lock for list_head */
u_int32_t rnd; /* random seed for hash */
int rnd_initialized;
struct timer_list timer; /* timer for gc */
atomic_t count; /* number entries in table */
/* seq_file stuff */
struct proc_dir_entry *pde;
struct hlist_head hash[0]; /* hashtable itself */
};
static DEFINE_SPINLOCK(hashlimit_lock); /* protects htables list */
static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */
static HLIST_HEAD(hashlimit_htables);
static kmem_cache_t *hashlimit_cachep __read_mostly;
static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
{
return (ent->dst.dst_ip == b->dst_ip
&& ent->dst.dst_port == b->dst_port
&& ent->dst.src_port == b->src_port
&& ent->dst.src_ip == b->src_ip);
}
static inline u_int32_t
hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst)
{
return (jhash_3words((__force u32)dst->dst_ip,
((__force u32)dst->dst_port<<16 |
(__force u32)dst->src_port),
(__force u32)dst->src_ip, ht->rnd) % ht->cfg.size);
}
static inline struct dsthash_ent *
__dsthash_find(const struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst)
{
struct dsthash_ent *ent;
struct hlist_node *pos;
u_int32_t hash = hash_dst(ht, dst);
if (!hlist_empty(&ht->hash[hash]))
hlist_for_each_entry(ent, pos, &ht->hash[hash], node) {
if (dst_cmp(ent, dst)) {
return ent;
}
}
return NULL;
}
/* allocate dsthash_ent, initialize dst, put in htable and lock it */
static struct dsthash_ent *
__dsthash_alloc_init(struct ipt_hashlimit_htable *ht, struct dsthash_dst *dst)
{
struct dsthash_ent *ent;
/* initialize hash with random val at the time we allocate
* the first hashtable entry */
if (!ht->rnd_initialized) {
get_random_bytes(&ht->rnd, 4);
ht->rnd_initialized = 1;
}
if (ht->cfg.max &&
atomic_read(&ht->count) >= ht->cfg.max) {
/* FIXME: do something. question is what.. */
if (net_ratelimit())
printk(KERN_WARNING
"ipt_hashlimit: max count of %u reached\n",
ht->cfg.max);
return NULL;
}
ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC);
if (!ent) {
if (net_ratelimit())
printk(KERN_ERR
"ipt_hashlimit: can't allocate dsthash_ent\n");
return NULL;
}
atomic_inc(&ht->count);
ent->dst.dst_ip = dst->dst_ip;
ent->dst.dst_port = dst->dst_port;
ent->dst.src_ip = dst->src_ip;
ent->dst.src_port = dst->src_port;
hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]);
return ent;
}
static inline void
__dsthash_free(struct ipt_hashlimit_htable *ht, struct dsthash_ent *ent)
{
hlist_del(&ent->node);
kmem_cache_free(hashlimit_cachep, ent);
atomic_dec(&ht->count);
}
static void htable_gc(unsigned long htlong);
static int htable_create(struct ipt_hashlimit_info *minfo)
{
int i;
unsigned int size;
struct ipt_hashlimit_htable *hinfo;
if (minfo->cfg.size)
size = minfo->cfg.size;
else {
size = (((num_physpages << PAGE_SHIFT) / 16384)
/ sizeof(struct list_head));
if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
size = 8192;
if (size < 16)
size = 16;
}
/* FIXME: don't use vmalloc() here or anywhere else -HW */
hinfo = vmalloc(sizeof(struct ipt_hashlimit_htable)
+ (sizeof(struct list_head) * size));
if (!hinfo) {
printk(KERN_ERR "ipt_hashlimit: Unable to create hashtable\n");
return -1;
}
minfo->hinfo = hinfo;
/* copy match config into hashtable config */
memcpy(&hinfo->cfg, &minfo->cfg, sizeof(hinfo->cfg));
hinfo->cfg.size = size;
if (!hinfo->cfg.max)
hinfo->cfg.max = 8 * hinfo->cfg.size;
else if (hinfo->cfg.max < hinfo->cfg.size)
hinfo->cfg.max = hinfo->cfg.size;
for (i = 0; i < hinfo->cfg.size; i++)
INIT_HLIST_HEAD(&hinfo->hash[i]);
atomic_set(&hinfo->count, 0);
atomic_set(&hinfo->use, 1);
hinfo->rnd_initialized = 0;
spin_lock_init(&hinfo->lock);
hinfo->pde = create_proc_entry(minfo->name, 0, hashlimit_procdir);
if (!hinfo->pde) {
vfree(hinfo);
return -1;
}
hinfo->pde->proc_fops = &dl_file_ops;
hinfo->pde->data = hinfo;
init_timer(&hinfo->timer);
hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval);
hinfo->timer.data = (unsigned long )hinfo;
hinfo->timer.function = htable_gc;
add_timer(&hinfo->timer);
spin_lock_bh(&hashlimit_lock);
hlist_add_head(&hinfo->node, &hashlimit_htables);
spin_unlock_bh(&hashlimit_lock);
return 0;
}
static int select_all(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he)
{
return 1;
}
static int select_gc(struct ipt_hashlimit_htable *ht, struct dsthash_ent *he)
{
return (jiffies >= he->expires);
}
static void htable_selective_cleanup(struct ipt_hashlimit_htable *ht,
int (*select)(struct ipt_hashlimit_htable *ht,
struct dsthash_ent *he))
{
int i;
IP_NF_ASSERT(ht->cfg.size && ht->cfg.max);
/* lock hash table and iterate over it */
spin_lock_bh(&ht->lock);
for (i = 0; i < ht->cfg.size; i++) {
struct dsthash_ent *dh;
struct hlist_node *pos, *n;
hlist_for_each_entry_safe(dh, pos, n, &ht->hash[i], node) {
if ((*select)(ht, dh))
__dsthash_free(ht, dh);
}
}
spin_unlock_bh(&ht->lock);
}
/* hash table garbage collector, run by timer */
static void htable_gc(unsigned long htlong)
{
struct ipt_hashlimit_htable *ht = (struct ipt_hashlimit_htable *)htlong;
htable_selective_cleanup(ht, select_gc);
/* re-add the timer accordingly */
ht->timer.expires = jiffies + msecs_to_jiffies(ht->cfg.gc_interval);
add_timer(&ht->timer);
}
static void htable_destroy(struct ipt_hashlimit_htable *hinfo)
{
/* remove timer, if it is pending */
if (timer_pending(&hinfo->timer))
del_timer(&hinfo->timer);
/* remove proc entry */
remove_proc_entry(hinfo->pde->name, hashlimit_procdir);
htable_selective_cleanup(hinfo, select_all);
vfree(hinfo);
}
static struct ipt_hashlimit_htable *htable_find_get(char *name)
{
struct ipt_hashlimit_htable *hinfo;
struct hlist_node *pos;
spin_lock_bh(&hashlimit_lock);
hlist_for_each_entry(hinfo, pos, &hashlimit_htables, node) {
if (!strcmp(name, hinfo->pde->name)) {
atomic_inc(&hinfo->use);
spin_unlock_bh(&hashlimit_lock);
return hinfo;
}
}
spin_unlock_bh(&hashlimit_lock);
return NULL;
}
static void htable_put(struct ipt_hashlimit_htable *hinfo)
{
if (atomic_dec_and_test(&hinfo->use)) {
spin_lock_bh(&hashlimit_lock);
hlist_del(&hinfo->node);
spin_unlock_bh(&hashlimit_lock);
htable_destroy(hinfo);
}
}
/* The algorithm used is the Simple Token Bucket Filter (TBF)
* see net/sched/sch_tbf.c in the linux source tree
*/
/* Rusty: This is my (non-mathematically-inclined) understanding of
this algorithm. The `average rate' in jiffies becomes your initial
amount of credit `credit' and the most credit you can ever have
`credit_cap'. The `peak rate' becomes the cost of passing the
test, `cost'.
`prev' tracks the last packet hit: you gain one credit per jiffy.
If you get credit balance more than this, the extra credit is
discarded. Every time the match passes, you lose `cost' credits;
if you don't have that many, the test fails.
See Alexey's formal explanation in net/sched/sch_tbf.c.
To get the maximum range, we multiply by this factor (ie. you get N
credits per jiffy). We want to allow a rate as low as 1 per day
(slowest userspace tool allows), which means
CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32 ie.
*/
#define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
/* Repeated shift and or gives us all 1s, final shift and add 1 gives
* us the power of 2 below the theoretical max, so GCC simply does a
* shift. */
#define _POW2_BELOW2(x) ((x)|((x)>>1))
#define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
#define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
#define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
#define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
#define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
/* Precision saver. */
static inline u_int32_t
user2credits(u_int32_t user)
{
/* If multiplying would overflow... */
if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
/* Divide first. */
return (user / IPT_HASHLIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
return (user * HZ * CREDITS_PER_JIFFY) / IPT_HASHLIMIT_SCALE;
}
static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
{
dh->rateinfo.credit += (now - xchg(&dh->rateinfo.prev, now))
* CREDITS_PER_JIFFY;
if (dh->rateinfo.credit > dh->rateinfo.credit_cap)
dh->rateinfo.credit = dh->rateinfo.credit_cap;
}
static int
hashlimit_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)
{
struct ipt_hashlimit_info *r =
((struct ipt_hashlimit_info *)matchinfo)->u.master;
struct ipt_hashlimit_htable *hinfo = r->hinfo;
unsigned long now = jiffies;
struct dsthash_ent *dh;
struct dsthash_dst dst;
/* build 'dst' according to hinfo->cfg and current packet */
memset(&dst, 0, sizeof(dst));
if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DIP)
dst.dst_ip = skb->nh.iph->daddr;
if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SIP)
dst.src_ip = skb->nh.iph->saddr;
if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT
||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) {
__be16 _ports[2], *ports;
switch (skb->nh.iph->protocol) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_SCTP:
case IPPROTO_DCCP:
ports = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_ports), &_ports);
break;
default:
_ports[0] = _ports[1] = 0;
ports = _ports;
break;
}
if (!ports) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
*hotdrop = 1;
return 0;
}
if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT)
dst.src_port = ports[0];
if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT)
dst.dst_port = ports[1];
}
spin_lock_bh(&hinfo->lock);
dh = __dsthash_find(hinfo, &dst);
if (!dh) {
dh = __dsthash_alloc_init(hinfo, &dst);
if (!dh) {
/* enomem... don't match == DROP */
if (net_ratelimit())
printk(KERN_ERR "%s: ENOMEM\n", __FUNCTION__);
spin_unlock_bh(&hinfo->lock);
return 0;
}
dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire);
dh->rateinfo.prev = jiffies;
dh->rateinfo.credit = user2credits(hinfo->cfg.avg *
hinfo->cfg.burst);
dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg *
hinfo->cfg.burst);
dh->rateinfo.cost = user2credits(hinfo->cfg.avg);
} else {
/* update expiration timeout */
dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire);
rateinfo_recalc(dh, now);
}
if (dh->rateinfo.credit >= dh->rateinfo.cost) {
/* We're underlimit. */
dh->rateinfo.credit -= dh->rateinfo.cost;
spin_unlock_bh(&hinfo->lock);
return 1;
}
spin_unlock_bh(&hinfo->lock);
/* default case: we're overlimit, thus don't match */
return 0;
}
static int
hashlimit_checkentry(const char *tablename,
const void *inf,
const struct xt_match *match,
void *matchinfo,
unsigned int hook_mask)
{
struct ipt_hashlimit_info *r = matchinfo;
/* Check for overflow. */
if (r->cfg.burst == 0
|| user2credits(r->cfg.avg * r->cfg.burst) <
user2credits(r->cfg.avg)) {
printk(KERN_ERR "ipt_hashlimit: Overflow, try lower: %u/%u\n",
r->cfg.avg, r->cfg.burst);
return 0;
}
if (r->cfg.mode == 0
|| r->cfg.mode > (IPT_HASHLIMIT_HASH_DPT
|IPT_HASHLIMIT_HASH_DIP
|IPT_HASHLIMIT_HASH_SIP
|IPT_HASHLIMIT_HASH_SPT))
return 0;
if (!r->cfg.gc_interval)
return 0;
if (!r->cfg.expire)
return 0;
if (r->name[sizeof(r->name) - 1] != '\0')
return 0;
/* This is the best we've got: We cannot release and re-grab lock,
* since checkentry() is called before ip_tables.c grabs ipt_mutex.
* We also cannot grab the hashtable spinlock, since htable_create will
* call vmalloc, and that can sleep. And we cannot just re-search
* the list of htable's in htable_create(), since then we would
* create duplicate proc files. -HW */
mutex_lock(&hlimit_mutex);
r->hinfo = htable_find_get(r->name);
if (!r->hinfo && (htable_create(r) != 0)) {
mutex_unlock(&hlimit_mutex);
return 0;
}
mutex_unlock(&hlimit_mutex);
/* Ugly hack: For SMP, we only want to use one set */
r->u.master = r;
return 1;
}
static void
hashlimit_destroy(const struct xt_match *match, void *matchinfo)
{
struct ipt_hashlimit_info *r = matchinfo;
htable_put(r->hinfo);
}
#ifdef CONFIG_COMPAT
struct compat_ipt_hashlimit_info {
char name[IFNAMSIZ];
struct hashlimit_cfg cfg;
compat_uptr_t hinfo;
compat_uptr_t master;
};
static void compat_from_user(void *dst, void *src)
{
int off = offsetof(struct compat_ipt_hashlimit_info, hinfo);
memcpy(dst, src, off);
memset(dst + off, 0, sizeof(struct compat_ipt_hashlimit_info) - off);
}
static int compat_to_user(void __user *dst, void *src)
{
int off = offsetof(struct compat_ipt_hashlimit_info, hinfo);
return copy_to_user(dst, src, off) ? -EFAULT : 0;
}
#endif
static struct ipt_match ipt_hashlimit = {
.name = "hashlimit",
.match = hashlimit_match,
.matchsize = sizeof(struct ipt_hashlimit_info),
#ifdef CONFIG_COMPAT
.compatsize = sizeof(struct compat_ipt_hashlimit_info),
.compat_from_user = compat_from_user,
.compat_to_user = compat_to_user,
#endif
.checkentry = hashlimit_checkentry,
.destroy = hashlimit_destroy,
.me = THIS_MODULE
};
/* PROC stuff */
static void *dl_seq_start(struct seq_file *s, loff_t *pos)
{
struct proc_dir_entry *pde = s->private;
struct ipt_hashlimit_htable *htable = pde->data;
unsigned int *bucket;
spin_lock_bh(&htable->lock);
if (*pos >= htable->cfg.size)
return NULL;
bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC);
if (!bucket)
return ERR_PTR(-ENOMEM);
*bucket = *pos;
return bucket;
}
static void *dl_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
struct proc_dir_entry *pde = s->private;
struct ipt_hashlimit_htable *htable = pde->data;
unsigned int *bucket = (unsigned int *)v;
*pos = ++(*bucket);
if (*pos >= htable->cfg.size) {
kfree(v);
return NULL;
}
return bucket;
}
static void dl_seq_stop(struct seq_file *s, void *v)
{
struct proc_dir_entry *pde = s->private;
struct ipt_hashlimit_htable *htable = pde->data;
unsigned int *bucket = (unsigned int *)v;
kfree(bucket);
spin_unlock_bh(&htable->lock);
}
static inline int dl_seq_real_show(struct dsthash_ent *ent, struct seq_file *s)
{
/* recalculate to show accurate numbers */
rateinfo_recalc(ent, jiffies);
return seq_printf(s, "%ld %u.%u.%u.%u:%u->%u.%u.%u.%u:%u %u %u %u\n",
(long)(ent->expires - jiffies)/HZ,
NIPQUAD(ent->dst.src_ip), ntohs(ent->dst.src_port),
NIPQUAD(ent->dst.dst_ip), ntohs(ent->dst.dst_port),
ent->rateinfo.credit, ent->rateinfo.credit_cap,
ent->rateinfo.cost);
}
static int dl_seq_show(struct seq_file *s, void *v)
{
struct proc_dir_entry *pde = s->private;
struct ipt_hashlimit_htable *htable = pde->data;
unsigned int *bucket = (unsigned int *)v;
struct dsthash_ent *ent;
struct hlist_node *pos;
if (!hlist_empty(&htable->hash[*bucket]))
hlist_for_each_entry(ent, pos, &htable->hash[*bucket], node) {
if (dl_seq_real_show(ent, s)) {
/* buffer was filled and unable to print that tuple */
return 1;
}
}
return 0;
}
static struct seq_operations dl_seq_ops = {
.start = dl_seq_start,
.next = dl_seq_next,
.stop = dl_seq_stop,
.show = dl_seq_show
};
static int dl_proc_open(struct inode *inode, struct file *file)
{
int ret = seq_open(file, &dl_seq_ops);
if (!ret) {
struct seq_file *sf = file->private_data;
sf->private = PDE(inode);
}
return ret;
}
static struct file_operations dl_file_ops = {
.owner = THIS_MODULE,
.open = dl_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
static int init_or_fini(int fini)
{
int ret = 0;
if (fini)
goto cleanup;
if (ipt_register_match(&ipt_hashlimit)) {
ret = -EINVAL;
goto cleanup_nothing;
}
hashlimit_cachep = kmem_cache_create("ipt_hashlimit",
sizeof(struct dsthash_ent), 0,
0, NULL, NULL);
if (!hashlimit_cachep) {
printk(KERN_ERR "Unable to create ipt_hashlimit slab cache\n");
ret = -ENOMEM;
goto cleanup_unreg_match;
}
hashlimit_procdir = proc_mkdir("ipt_hashlimit", proc_net);
if (!hashlimit_procdir) {
printk(KERN_ERR "Unable to create proc dir entry\n");
ret = -ENOMEM;
goto cleanup_free_slab;
}
return ret;
cleanup:
remove_proc_entry("ipt_hashlimit", proc_net);
cleanup_free_slab:
kmem_cache_destroy(hashlimit_cachep);
cleanup_unreg_match:
ipt_unregister_match(&ipt_hashlimit);
cleanup_nothing:
return ret;
}
static int __init ipt_hashlimit_init(void)
{
return init_or_fini(0);
}
static void __exit ipt_hashlimit_fini(void)
{
init_or_fini(1);
}
module_init(ipt_hashlimit_init);
module_exit(ipt_hashlimit_fini);

View file

@ -132,7 +132,7 @@ ipt_local_hook(unsigned int hook,
unsigned int ret;
u_int8_t tos;
__be32 saddr, daddr;
unsigned long nfmark;
u_int32_t mark;
/* root is playing with raw sockets. */
if ((*pskb)->len < sizeof(struct iphdr)
@ -143,7 +143,7 @@ ipt_local_hook(unsigned int hook,
}
/* Save things which could affect route */
nfmark = (*pskb)->nfmark;
mark = (*pskb)->mark;
saddr = (*pskb)->nh.iph->saddr;
daddr = (*pskb)->nh.iph->daddr;
tos = (*pskb)->nh.iph->tos;
@ -153,9 +153,7 @@ ipt_local_hook(unsigned int hook,
if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE
&& ((*pskb)->nh.iph->saddr != saddr
|| (*pskb)->nh.iph->daddr != daddr
#ifdef CONFIG_IP_ROUTE_FWMARK
|| (*pskb)->nfmark != nfmark
#endif
|| (*pskb)->mark != mark
|| (*pskb)->nh.iph->tos != tos))
if (ip_route_me_harder(pskb, RTN_UNSPEC))
ret = NF_DROP;

View file

@ -27,7 +27,7 @@
#include <linux/netfilter_ipv4.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_protocol.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
@ -38,12 +38,10 @@
#define DEBUGP(format, args...)
#endif
DECLARE_PER_CPU(struct nf_conntrack_stat, nf_conntrack_stat);
static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple)
{
u_int32_t _addrs[2], *ap;
__be32 _addrs[2], *ap;
ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr),
sizeof(u_int32_t) * 2, _addrs);
if (ap == NULL)
@ -113,10 +111,12 @@ ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
return NF_ACCEPT;
}
int nat_module_is_loaded = 0;
int nf_nat_module_is_loaded = 0;
EXPORT_SYMBOL_GPL(nf_nat_module_is_loaded);
static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple)
{
if (nat_module_is_loaded)
if (nf_nat_module_is_loaded)
return NF_CT_F_NAT;
return NF_CT_F_BASIC;
@ -268,43 +268,59 @@ static struct nf_hook_ops ipv4_conntrack_ops[] = {
},
};
#ifdef CONFIG_SYSCTL
/* From nf_conntrack_proto_icmp.c */
extern unsigned int nf_ct_icmp_timeout;
static struct ctl_table_header *nf_ct_ipv4_sysctl_header;
#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
static int log_invalid_proto_min = 0;
static int log_invalid_proto_max = 255;
static ctl_table nf_ct_sysctl_table[] = {
static ctl_table ip_ct_sysctl_table[] = {
{
.ctl_name = NET_NF_CONNTRACK_ICMP_TIMEOUT,
.procname = "nf_conntrack_icmp_timeout",
.data = &nf_ct_icmp_timeout,
.ctl_name = NET_IPV4_NF_CONNTRACK_MAX,
.procname = "ip_conntrack_max",
.data = &nf_conntrack_max,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV4_NF_CONNTRACK_COUNT,
.procname = "ip_conntrack_count",
.data = &nf_conntrack_count,
.maxlen = sizeof(int),
.mode = 0444,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS,
.procname = "ip_conntrack_buckets",
.data = &nf_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 = &nf_conntrack_checksum,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec,
},
{
.ctl_name = NET_IPV4_NF_CONNTRACK_LOG_INVALID,
.procname = "ip_conntrack_log_invalid",
.data = &nf_ct_log_invalid,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
.proc_handler = &proc_dointvec_minmax,
.strategy = &sysctl_intvec,
.extra1 = &log_invalid_proto_min,
.extra2 = &log_invalid_proto_max,
},
{ .ctl_name = 0 }
};
static ctl_table nf_ct_netfilter_table[] = {
{
.ctl_name = NET_NETFILTER,
.procname = "netfilter",
.mode = 0555,
.child = nf_ct_sysctl_table,
},
{ .ctl_name = 0 }
.ctl_name = 0
}
};
static ctl_table nf_ct_net_table[] = {
{
.ctl_name = CTL_NET,
.procname = "net",
.mode = 0555,
.child = nf_ct_netfilter_table,
},
{ .ctl_name = 0 }
};
#endif
#endif /* CONFIG_SYSCTL && CONFIG_NF_CONNTRACK_PROC_COMPAT */
/* Fast function for those who don't want to parse /proc (and I don't
blame them). */
@ -396,10 +412,8 @@ static int ipv4_nfattr_to_tuple(struct nfattr *tb[],
if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
return -EINVAL;
t->src.u3.ip =
*(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
t->dst.u3.ip =
*(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
t->src.u3.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
t->dst.u3.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
return 0;
}
@ -425,15 +439,16 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = ipv4_tuple_to_nfattr,
.nfattr_to_tuple = ipv4_nfattr_to_tuple,
#endif
#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
.ctl_table_path = nf_net_ipv4_netfilter_sysctl_path,
.ctl_table = ip_ct_sysctl_table,
#endif
.me = THIS_MODULE,
};
extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp4;
extern struct nf_conntrack_protocol nf_conntrack_protocol_udp4;
extern struct nf_conntrack_protocol nf_conntrack_protocol_icmp;
MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
MODULE_ALIAS("ip_conntrack");
MODULE_LICENSE("GPL");
static int __init nf_conntrack_l3proto_ipv4_init(void)
@ -448,19 +463,19 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
return ret;
}
ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp4);
ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp4);
if (ret < 0) {
printk("nf_conntrack_ipv4: can't register tcp.\n");
goto cleanup_sockopt;
}
ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp4);
ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp4);
if (ret < 0) {
printk("nf_conntrack_ipv4: can't register udp.\n");
goto cleanup_tcp;
}
ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmp);
ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmp);
if (ret < 0) {
printk("nf_conntrack_ipv4: can't register icmp.\n");
goto cleanup_udp;
@ -478,28 +493,24 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
printk("nf_conntrack_ipv4: can't register hooks.\n");
goto cleanup_ipv4;
}
#ifdef CONFIG_SYSCTL
nf_ct_ipv4_sysctl_header = register_sysctl_table(nf_ct_net_table, 0);
if (nf_ct_ipv4_sysctl_header == NULL) {
printk("nf_conntrack: can't register to sysctl.\n");
ret = -ENOMEM;
#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
ret = nf_conntrack_ipv4_compat_init();
if (ret < 0)
goto cleanup_hooks;
}
#endif
return ret;
#ifdef CONFIG_SYSCTL
#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
cleanup_hooks:
nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
#endif
cleanup_ipv4:
nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
cleanup_icmp:
nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp);
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp);
cleanup_udp:
nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4);
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4);
cleanup_tcp:
nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4);
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
cleanup_sockopt:
nf_unregister_sockopt(&so_getorigdst);
return ret;
@ -508,18 +519,16 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
static void __exit nf_conntrack_l3proto_ipv4_fini(void)
{
synchronize_net();
#ifdef CONFIG_SYSCTL
unregister_sysctl_table(nf_ct_ipv4_sysctl_header);
#if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
nf_conntrack_ipv4_compat_fini();
#endif
nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmp);
nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp4);
nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp4);
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp);
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4);
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
nf_unregister_sockopt(&so_getorigdst);
}
module_init(nf_conntrack_l3proto_ipv4_init);
module_exit(nf_conntrack_l3proto_ipv4_fini);
EXPORT_SYMBOL(nf_ct_ipv4_gather_frags);

View file

@ -0,0 +1,412 @@
/* ip_conntrack proc compat - based on ip_conntrack_standalone.c
*
* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 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/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/percpu.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_expect.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
#ifdef CONFIG_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 < nf_conntrack_htable_size;
st->bucket++) {
if (!list_empty(&nf_conntrack_hash[st->bucket]))
return nf_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 == &nf_conntrack_hash[st->bucket]) {
if (++st->bucket >= nf_conntrack_htable_size)
return NULL;
head = nf_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(&nf_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(&nf_conntrack_lock);
}
static int ct_seq_show(struct seq_file *s, void *v)
{
const struct nf_conntrack_tuple_hash *hash = v;
const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
struct nf_conntrack_l3proto *l3proto;
struct nf_conntrack_l4proto *l4proto;
NF_CT_ASSERT(ct);
/* we only want to print DIR_ORIGINAL */
if (NF_CT_DIRECTION(hash))
return 0;
if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num != AF_INET)
return 0;
l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL]
.tuple.src.l3num);
NF_CT_ASSERT(l3proto);
l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL]
.tuple.src.l3num,
ct->tuplehash[IP_CT_DIR_ORIGINAL]
.tuple.dst.protonum);
NF_CT_ASSERT(l4proto);
if (seq_printf(s, "%-8s %u %ld ",
l4proto->name,
ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum,
timer_pending(&ct->timeout)
? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0)
return -ENOSPC;
if (l3proto->print_conntrack(s, ct))
return -ENOSPC;
if (l4proto->print_conntrack(s, ct))
return -ENOSPC;
if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
l3proto, l4proto))
return -ENOSPC;
if (seq_print_counters(s, &ct->counters[IP_CT_DIR_ORIGINAL]))
return -ENOSPC;
if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
if (seq_printf(s, "[UNREPLIED] "))
return -ENOSPC;
if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
l3proto, l4proto))
return -ENOSPC;
if (seq_print_counters(s, &ct->counters[IP_CT_DIR_REPLY]))
return -ENOSPC;
if (test_bit(IPS_ASSURED_BIT, &ct->status))
if (seq_printf(s, "[ASSURED] "))
return -ENOSPC;
#ifdef CONFIG_NF_CONNTRACK_MARK
if (seq_printf(s, "mark=%u ", ct->mark))
return -ENOSPC;
#endif
#ifdef CONFIG_NF_CONNTRACK_SECMARK
if (seq_printf(s, "secmark=%u ", ct->secmark))
return -ENOSPC;
#endif
if (seq_printf(s, "use=%u\n", atomic_read(&ct->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 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 = &nf_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(&nf_conntrack_lock);
if (list_empty(e))
return NULL;
for (i = 0; i <= *pos; i++) {
e = e->next;
if (e == &nf_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 == &nf_conntrack_expect_list)
return NULL;
return e;
}
static void exp_seq_stop(struct seq_file *s, void *v)
{
read_unlock_bh(&nf_conntrack_lock);
}
static int exp_seq_show(struct seq_file *s, void *v)
{
struct nf_conntrack_expect *exp = v;
if (exp->tuple.src.l3num != AF_INET)
return 0;
if (exp->timeout.function)
seq_printf(s, "%ld ", timer_pending(&exp->timeout)
? (long)(exp->timeout.expires - jiffies)/HZ : 0);
else
seq_printf(s, "- ");
seq_printf(s, "proto=%u ", exp->tuple.dst.protonum);
print_tuple(s, &exp->tuple,
__nf_ct_l3proto_find(exp->tuple.src.l3num),
__nf_ct_l4proto_find(exp->tuple.src.l3num,
exp->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 struct file_operations ip_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(nf_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(nf_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(&nf_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 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,
};
int __init nf_conntrack_ipv4_compat_init(void)
{
struct proc_dir_entry *proc, *proc_exp, *proc_stat;
proc = proc_net_fops_create("ip_conntrack", 0440, &ct_file_ops);
if (!proc)
goto err1;
proc_exp = proc_net_fops_create("ip_conntrack_expect", 0440,
&ip_exp_file_ops);
if (!proc_exp)
goto err2;
proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, proc_net_stat);
if (!proc_stat)
goto err3;
proc_stat->proc_fops = &ct_cpu_seq_fops;
proc_stat->owner = THIS_MODULE;
return 0;
err3:
proc_net_remove("ip_conntrack_expect");
err2:
proc_net_remove("ip_conntrack");
err1:
return -ENOMEM;
}
void __exit nf_conntrack_ipv4_compat_fini(void)
{
remove_proc_entry("ip_conntrack", proc_net_stat);
proc_net_remove("ip_conntrack_expect");
proc_net_remove("ip_conntrack");
}

View file

@ -22,10 +22,10 @@
#include <net/checksum.h>
#include <linux/netfilter_ipv4.h>
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_protocol.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_core.h>
unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ;
static unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ;
#if 0
#define DEBUGP printk
@ -152,7 +152,7 @@ icmp_error_message(struct sk_buff *skb,
struct icmphdr icmp;
struct iphdr ip;
} _in, *inside;
struct nf_conntrack_protocol *innerproto;
struct nf_conntrack_l4proto *innerproto;
struct nf_conntrack_tuple_hash *h;
int dataoff;
@ -170,7 +170,7 @@ icmp_error_message(struct sk_buff *skb,
return -NF_ACCEPT;
}
innerproto = __nf_ct_proto_find(PF_INET, inside->ip.protocol);
innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp);
/* Are they talking about one of our connections? */
if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
@ -311,7 +311,7 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[],
tuple->dst.u.icmp.code =
*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
tuple->src.u.icmp.id =
*(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
*(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
if (tuple->dst.u.icmp.type >= sizeof(invmap)
|| !invmap[tuple->dst.u.icmp.type])
@ -321,11 +321,42 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[],
}
#endif
struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
#ifdef CONFIG_SYSCTL
static struct ctl_table_header *icmp_sysctl_header;
static struct ctl_table icmp_sysctl_table[] = {
{
.ctl_name = NET_NF_CONNTRACK_ICMP_TIMEOUT,
.procname = "nf_conntrack_icmp_timeout",
.data = &nf_ct_icmp_timeout,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
},
{
.ctl_name = 0
}
};
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
static struct ctl_table icmp_compat_sysctl_table[] = {
{
.ctl_name = NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT,
.procname = "ip_conntrack_icmp_timeout",
.data = &nf_ct_icmp_timeout,
.maxlen = sizeof(unsigned int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
},
{
.ctl_name = 0
}
};
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp =
{
.list = { NULL, NULL },
.l3proto = PF_INET,
.proto = IPPROTO_ICMP,
.l4proto = IPPROTO_ICMP,
.name = "icmp",
.pkt_to_tuple = icmp_pkt_to_tuple,
.invert_tuple = icmp_invert_tuple,
@ -341,6 +372,12 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
.tuple_to_nfattr = icmp_tuple_to_nfattr,
.nfattr_to_tuple = icmp_nfattr_to_tuple,
#endif
#ifdef CONFIG_SYSCTL
.ctl_table_header = &icmp_sysctl_header,
.ctl_table = icmp_sysctl_table,
#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
.ctl_compat_table = icmp_compat_sysctl_table,
#endif
#endif
};
EXPORT_SYMBOL(nf_conntrack_protocol_icmp);
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_icmp);

View file

@ -0,0 +1,78 @@
/* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <net/netfilter/nf_nat_helper.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_amanda.h>
MODULE_AUTHOR("Brian J. Murrell <[email protected]>");
MODULE_DESCRIPTION("Amanda NAT helper");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_nat_amanda");
static unsigned int help(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
unsigned int matchoff,
unsigned int matchlen,
struct nf_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 = nf_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 (nf_conntrack_expect_related(exp) == 0)
break;
}
if (port == 0)
return NF_DROP;
sprintf(buffer, "%u", port);
ret = nf_nat_mangle_udp_packet(pskb, exp->master, ctinfo,
matchoff, matchlen,
buffer, strlen(buffer));
if (ret != NF_ACCEPT)
nf_conntrack_unexpect_related(exp);
return ret;
}
static void __exit nf_nat_amanda_fini(void)
{
rcu_assign_pointer(nf_nat_amanda_hook, NULL);
synchronize_rcu();
}
static int __init nf_nat_amanda_init(void)
{
BUG_ON(rcu_dereference(nf_nat_amanda_hook));
rcu_assign_pointer(nf_nat_amanda_hook, help);
return 0;
}
module_init(nf_nat_amanda_init);
module_exit(nf_nat_amanda_fini);

View file

@ -0,0 +1,647 @@
/* NAT for netfilter; shared with compatibility layer. */
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 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/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.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_protocol.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_helper.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
static DEFINE_RWLOCK(nf_nat_lock);
static struct nf_conntrack_l3proto *l3proto = NULL;
/* Calculated at init based on memory size */
static unsigned int nf_nat_htable_size;
static struct list_head *bysource;
#define MAX_IP_NAT_PROTO 256
static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO];
static inline struct nf_nat_protocol *
__nf_nat_proto_find(u_int8_t protonum)
{
return nf_nat_protos[protonum];
}
struct nf_nat_protocol *
nf_nat_proto_find_get(u_int8_t protonum)
{
struct nf_nat_protocol *p;
/* we need to disable preemption to make sure 'p' doesn't get
* removed until we've grabbed the reference */
preempt_disable();
p = __nf_nat_proto_find(protonum);
if (!try_module_get(p->me))
p = &nf_nat_unknown_protocol;
preempt_enable();
return p;
}
EXPORT_SYMBOL_GPL(nf_nat_proto_find_get);
void
nf_nat_proto_put(struct nf_nat_protocol *p)
{
module_put(p->me);
}
EXPORT_SYMBOL_GPL(nf_nat_proto_put);
/* We keep an extra hash for each conntrack, for fast searching. */
static inline unsigned int
hash_by_src(const struct nf_conntrack_tuple *tuple)
{
/* Original src, to ensure we map it consistently if poss. */
return jhash_3words((__force u32)tuple->src.u3.ip, tuple->src.u.all,
tuple->dst.protonum, 0) % nf_nat_htable_size;
}
/* Noone using conntrack by the time this called. */
static void nf_nat_cleanup_conntrack(struct nf_conn *conn)
{
struct nf_conn_nat *nat;
if (!(conn->status & IPS_NAT_DONE_MASK))
return;
nat = nfct_nat(conn);
write_lock_bh(&nf_nat_lock);
list_del(&nat->info.bysource);
write_unlock_bh(&nf_nat_lock);
}
/* Is this tuple already taken? (not by us) */
int
nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
const struct nf_conn *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 nf_conntrack_tuple reply;
nf_ct_invert_tuplepr(&reply, tuple);
return nf_conntrack_tuple_taken(&reply, ignored_conntrack);
}
EXPORT_SYMBOL(nf_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 nf_conntrack_tuple *tuple,
const struct nf_nat_range *range)
{
struct nf_nat_protocol *proto;
proto = __nf_nat_proto_find(tuple->dst.protonum);
/* 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.u3.ip) < ntohl(range->min_ip) ||
ntohl(tuple->src.u3.ip) > ntohl(range->max_ip))
return 0;
}
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
proto->in_range(tuple, IP_NAT_MANIP_SRC,
&range->min, &range->max))
return 1;
return 0;
}
static inline int
same_src(const struct nf_conn *ct,
const struct nf_conntrack_tuple *tuple)
{
const struct nf_conntrack_tuple *t;
t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
return (t->dst.protonum == tuple->dst.protonum &&
t->src.u3.ip == tuple->src.u3.ip &&
t->src.u.all == tuple->src.u.all);
}
/* Only called for SRC manip */
static int
find_appropriate_src(const struct nf_conntrack_tuple *tuple,
struct nf_conntrack_tuple *result,
const struct nf_nat_range *range)
{
unsigned int h = hash_by_src(tuple);
struct nf_conn_nat *nat;
struct nf_conn *ct;
read_lock_bh(&nf_nat_lock);
list_for_each_entry(nat, &bysource[h], info.bysource) {
ct = (struct nf_conn *)((char *)nat - offsetof(struct nf_conn, data));
if (same_src(ct, tuple)) {
/* Copy source part from reply tuple. */
nf_ct_invert_tuplepr(result,
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
result->dst = tuple->dst;
if (in_range(result, range)) {
read_unlock_bh(&nf_nat_lock);
return 1;
}
}
}
read_unlock_bh(&nf_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 nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
const struct nf_conn *ct,
enum nf_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.u3.ip;
else
var_ipp = &tuple->dst.u3.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.u3.ip,
(__force u32)tuple->dst.u3.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 nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *orig_tuple,
const struct nf_nat_range *range,
struct nf_conn *ct,
enum nf_nat_manip_type maniptype)
{
struct nf_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 (!nf_nat_used_tuple(tuple, ct))
return;
}
}
/* 2) Select the least-used IP/proto combination in the given
range. */
*tuple = *orig_tuple;
find_best_ips_proto(tuple, range, ct, maniptype);
/* 3) The per-protocol part of the manip is made to map into
the range to make a unique tuple. */
proto = nf_nat_proto_find_get(orig_tuple->dst.protonum);
/* 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)) &&
!nf_nat_used_tuple(tuple, ct)) {
nf_nat_proto_put(proto);
return;
}
/* Last change: get protocol to try to obtain unique tuple. */
proto->unique_tuple(tuple, range, maniptype, ct);
nf_nat_proto_put(proto);
}
unsigned int
nf_nat_setup_info(struct nf_conn *ct,
const struct nf_nat_range *range,
unsigned int hooknum)
{
struct nf_conntrack_tuple curr_tuple, new_tuple;
struct nf_conn_nat *nat = nfct_nat(ct);
struct nf_nat_info *info = &nat->info;
int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK);
enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
hooknum == NF_IP_POST_ROUTING ||
hooknum == NF_IP_LOCAL_IN ||
hooknum == NF_IP_LOCAL_OUT);
BUG_ON(nf_nat_initialized(ct, 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) */
nf_ct_invert_tuplepr(&curr_tuple,
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype);
if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) {
struct nf_conntrack_tuple reply;
/* Alter conntrack table so will recognize replies. */
nf_ct_invert_tuplepr(&reply, &new_tuple);
nf_conntrack_alter_reply(ct, &reply);
/* Non-atomic: we own this at the moment. */
if (maniptype == IP_NAT_MANIP_SRC)
ct->status |= IPS_SRC_NAT;
else
ct->status |= IPS_DST_NAT;
}
/* Place in source hash if this is the first time. */
if (have_to_hash) {
unsigned int srchash;
srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
write_lock_bh(&nf_nat_lock);
list_add(&info->bysource, &bysource[srchash]);
write_unlock_bh(&nf_nat_lock);
}
/* It's done. */
if (maniptype == IP_NAT_MANIP_DST)
set_bit(IPS_DST_NAT_DONE_BIT, &ct->status);
else
set_bit(IPS_SRC_NAT_DONE_BIT, &ct->status);
return NF_ACCEPT;
}
EXPORT_SYMBOL(nf_nat_setup_info);
/* Returns true if succeeded. */
static int
manip_pkt(u_int16_t proto,
struct sk_buff **pskb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *target,
enum nf_nat_manip_type maniptype)
{
struct iphdr *iph;
struct nf_nat_protocol *p;
if (!skb_make_writable(pskb, iphdroff + sizeof(*iph)))
return 0;
iph = (void *)(*pskb)->data + iphdroff;
/* Manipulate protcol part. */
p = nf_nat_proto_find_get(proto);
if (!p->manip_pkt(pskb, iphdroff, target, maniptype)) {
nf_nat_proto_put(p);
return 0;
}
nf_nat_proto_put(p);
iph = (void *)(*pskb)->data + iphdroff;
if (maniptype == IP_NAT_MANIP_SRC) {
nf_csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
iph->saddr = target->src.u3.ip;
} else {
nf_csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
iph->daddr = target->dst.u3.ip;
}
return 1;
}
/* Do packet manipulations according to nf_nat_setup_info. */
unsigned int nf_nat_packet(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
struct sk_buff **pskb)
{
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned long statusbit;
enum nf_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 nf_conntrack_tuple target;
/* We are aiming to look like inverse of other direction. */
nf_ct_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(nf_nat_packet);
/* Dir is direction ICMP is coming from (opposite to packet it contains) */
int nf_nat_icmp_reply_translation(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int hooknum,
struct sk_buff **pskb)
{
struct {
struct icmphdr icmp;
struct iphdr ip;
} *inside;
struct nf_conntrack_tuple inner, target;
int hdrlen = (*pskb)->nh.iph->ihl * 4;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned long statusbit;
enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
if (!skb_make_writable(pskb, hdrlen + sizeof(*inside)))
return 0;
inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
/* 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 */
NF_CT_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");
if (!nf_ct_get_tuple(*pskb,
(*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr),
(*pskb)->nh.iph->ihl*4 +
sizeof(struct icmphdr) + inside->ip.ihl*4,
(u_int16_t)AF_INET,
inside->ip.protocol,
&inner,
l3proto,
__nf_ct_l4proto_find((u_int16_t)PF_INET,
inside->ip.protocol)))
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,
(*pskb)->nh.iph->ihl*4 + 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 + (*pskb)->nh.iph->ihl*4;
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) {
nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
if (!manip_pkt(0, pskb, 0, &target, manip))
return 0;
}
return 1;
}
EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
/* Protocol registration. */
int nf_nat_protocol_register(struct nf_nat_protocol *proto)
{
int ret = 0;
write_lock_bh(&nf_nat_lock);
if (nf_nat_protos[proto->protonum] != &nf_nat_unknown_protocol) {
ret = -EBUSY;
goto out;
}
nf_nat_protos[proto->protonum] = proto;
out:
write_unlock_bh(&nf_nat_lock);
return ret;
}
EXPORT_SYMBOL(nf_nat_protocol_register);
/* Noone stores the protocol anywhere; simply delete it. */
void nf_nat_protocol_unregister(struct nf_nat_protocol *proto)
{
write_lock_bh(&nf_nat_lock);
nf_nat_protos[proto->protonum] = &nf_nat_unknown_protocol;
write_unlock_bh(&nf_nat_lock);
/* Someone could be still looking at the proto in a bh. */
synchronize_net();
}
EXPORT_SYMBOL(nf_nat_protocol_unregister);
#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \
defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE)
int
nf_nat_port_range_to_nfattr(struct sk_buff *skb,
const struct nf_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;
}
EXPORT_SYMBOL_GPL(nf_nat_port_nfattr_to_range);
int
nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_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(nf_nat_port_range_to_nfattr);
#endif
static int __init nf_nat_init(void)
{
size_t i;
/* Leave them the same for the moment. */
nf_nat_htable_size = nf_conntrack_htable_size;
/* One vmalloc for both hash tables */
bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size);
if (!bysource)
return -ENOMEM;
/* Sew in builtin protocols. */
write_lock_bh(&nf_nat_lock);
for (i = 0; i < MAX_IP_NAT_PROTO; i++)
nf_nat_protos[i] = &nf_nat_unknown_protocol;
nf_nat_protos[IPPROTO_TCP] = &nf_nat_protocol_tcp;
nf_nat_protos[IPPROTO_UDP] = &nf_nat_protocol_udp;
nf_nat_protos[IPPROTO_ICMP] = &nf_nat_protocol_icmp;
write_unlock_bh(&nf_nat_lock);
for (i = 0; i < nf_nat_htable_size; i++) {
INIT_LIST_HEAD(&bysource[i]);
}
/* FIXME: Man, this is a hack. <SIGH> */
NF_CT_ASSERT(nf_conntrack_destroyed == NULL);
nf_conntrack_destroyed = &nf_nat_cleanup_conntrack;
/* Initialize fake conntrack so that NAT will skip it */
nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
return 0;
}
/* Clear NAT section of all conntracks, in case we're loaded again. */
static int clean_nat(struct nf_conn *i, void *data)
{
struct nf_conn_nat *nat = nfct_nat(i);
if (!nat)
return 0;
memset(nat, 0, sizeof(nat));
i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
return 0;
}
static void __exit nf_nat_cleanup(void)
{
nf_ct_iterate_cleanup(&clean_nat, NULL);
nf_conntrack_destroyed = NULL;
vfree(bysource);
nf_ct_l3proto_put(l3proto);
}
MODULE_LICENSE("GPL");
module_init(nf_nat_init);
module_exit(nf_nat_cleanup);

View file

@ -0,0 +1,179 @@
/* FTP extension for TCP NAT alteration. */
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 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/moduleparam.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/netfilter_ipv4.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_helper.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_ftp.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rusty Russell <[email protected]>");
MODULE_DESCRIPTION("ftp NAT helper");
MODULE_ALIAS("ip_nat_ftp");
#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 nf_conn *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 nf_nat_mangle_tcp_packet\n");
*seq += strlen(buffer) - matchlen;
return nf_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 nf_conn *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 nf_nat_mangle_tcp_packet\n");
*seq += strlen(buffer) - matchlen;
return nf_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 nf_conn *ct,
enum ip_conntrack_info ctinfo,
u32 *seq)
{
char buffer[sizeof("|||65535|")];
sprintf(buffer, "|||%u|", port);
DEBUGP("calling nf_nat_mangle_tcp_packet\n");
*seq += strlen(buffer) - matchlen;
return nf_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 nf_conn *,
enum ip_conntrack_info, u32 *seq)
= {
[NF_CT_FTP_PORT] = mangle_rfc959_packet,
[NF_CT_FTP_PASV] = mangle_rfc959_packet,
[NF_CT_FTP_EPRT] = mangle_eprt_packet,
[NF_CT_FTP_EPSV] = mangle_epsv_packet
};
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int nf_nat_ftp(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
enum nf_ct_ftp_type type,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conntrack_expect *exp,
u32 *seq)
{
__be32 newip;
u_int16_t port;
int dir = CTINFO2DIR(ctinfo);
struct nf_conn *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.u3.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 = nf_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 (nf_conntrack_expect_related(exp) == 0)
break;
}
if (port == 0)
return NF_DROP;
if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo,
seq)) {
nf_conntrack_unexpect_related(exp);
return NF_DROP;
}
return NF_ACCEPT;
}
static void __exit nf_nat_ftp_fini(void)
{
rcu_assign_pointer(nf_nat_ftp_hook, NULL);
synchronize_rcu();
}
static int __init nf_nat_ftp_init(void)
{
BUG_ON(rcu_dereference(nf_nat_ftp_hook));
rcu_assign_pointer(nf_nat_ftp_hook, nf_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(nf_nat_ftp_init);
module_exit(nf_nat_ftp_fini);

View file

@ -0,0 +1,596 @@
/*
* 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/moduleparam.h>
#include <linux/tcp.h>
#include <net/tcp.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_helper.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_h323.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, __be16 port)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo);
struct {
__be32 ip;
__be16 port;
} __attribute__ ((__packed__)) buf;
struct tcphdr _tcph, *th;
buf.ip = ip;
buf.port = port;
addroff += dataoff;
if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo,
addroff, sizeof(buf),
(char *) &buf, sizeof(buf))) {
if (net_ratelimit())
printk("nf_nat_h323: nf_nat_mangle_tcp_packet"
" error\n");
return -1;
}
/* Relocate data pointer */
th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return -1;
*data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
th->doff * 4 + dataoff;
} else {
if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
addroff, sizeof(buf),
(char *) &buf, sizeof(buf))) {
if (net_ratelimit())
printk("nf_nat_h323: nf_nat_mangle_udp_packet"
" error\n");
return -1;
}
/* nf_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 + (*pskb)->nh.iph->ihl * 4 +
sizeof(struct udphdr);
}
return 0;
}
/****************************************************************************/
static int set_h225_addr(struct sk_buff **pskb,
unsigned char **data, int dataoff,
TransportAddress *taddr,
union nf_conntrack_address *addr, __be16 port)
{
return set_addr(pskb, data, dataoff, taddr->ipAddress.ip,
addr->ip, port);
}
/****************************************************************************/
static int set_h245_addr(struct sk_buff **pskb,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr,
union nf_conntrack_address *addr, __be16 port)
{
return set_addr(pskb, data, dataoff,
taddr->unicastAddress.iPAddress.network,
addr->ip, port);
}
/****************************************************************************/
static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data,
TransportAddress *taddr, int count)
{
struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
int dir = CTINFO2DIR(ctinfo);
int i;
__be16 port;
union nf_conntrack_address addr;
for (i = 0; i < count; i++) {
if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) {
if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
port == info->sig_port[dir]) {
/* GW->GK */
/* Fix for Gnomemeeting */
if (i > 0 &&
get_h225_addr(ct, *data, &taddr[0],
&addr, &port) &&
(ntohl(addr.ip) & 0xff000000) == 0x7f000000)
i = 0;
DEBUGP
("nf_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, &taddr[i],
&ct->tuplehash[!dir].
tuple.dst.u3,
info->sig_port[!dir]);
} else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
port == info->sig_port[dir]) {
/* GK->GW */
DEBUGP
("nf_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, &taddr[i],
&ct->tuplehash[!dir].
tuple.src.u3,
info->sig_port[!dir]);
}
}
}
return 0;
}
/****************************************************************************/
static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data,
TransportAddress *taddr, int count)
{
int dir = CTINFO2DIR(ctinfo);
int i;
__be16 port;
union nf_conntrack_address addr;
for (i = 0; i < count; i++) {
if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
port == ct->tuplehash[dir].tuple.src.u.udp.port) {
DEBUGP("nf_nat_ras: set rasAddress "
"%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
NIPQUAD(ip), ntohs(port),
NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
port));
return set_h225_addr(pskb, data, 0, &taddr[i],
&ct->tuplehash[!dir].tuple.dst.u3,
ct->tuplehash[!dir].tuple.
dst.u.udp.port);
}
}
return 0;
}
/****************************************************************************/
static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr,
__be16 port, __be16 rtp_port,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp)
{
struct nf_ct_h323_master *info = &nfct_help(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 = nf_nat_follow_master;
rtp_exp->dir = !dir;
rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
rtcp_exp->expectfn = nf_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 = info->rtp_port[i][dir];
rtcp_exp->tuple.dst.u.udp.port =
htons(ntohs(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("nf_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 (nf_conntrack_expect_related(rtp_exp) == 0) {
rtcp_exp->tuple.dst.u.udp.port =
htons(nated_port + 1);
if (nf_conntrack_expect_related(rtcp_exp) == 0)
break;
nf_conntrack_unexpect_related(rtp_exp);
}
}
if (nated_port == 0) { /* No port available */
if (net_ratelimit())
printk("nf_nat_h323: out of RTP ports\n");
return 0;
}
/* Modify signal */
if (set_h245_addr(pskb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons((port & htons(1)) ? nated_port + 1 :
nated_port)) == 0) {
/* Save ports */
info->rtp_port[i][dir] = rtp_port;
info->rtp_port[i][!dir] = htons(nated_port);
} else {
nf_conntrack_unexpect_related(rtp_exp);
nf_conntrack_unexpect_related(rtcp_exp);
return -1;
}
/* Success */
DEBUGP("nf_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("nf_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 nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
H245_TransportAddress *taddr, __be16 port,
struct nf_conntrack_expect *exp)
{
int dir = CTINFO2DIR(ctinfo);
u_int16_t nated_port = ntohs(port);
/* Set expectations for NAT */
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
exp->expectfn = nf_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 (nf_conntrack_expect_related(exp) == 0)
break;
}
if (nated_port == 0) { /* No port available */
if (net_ratelimit())
printk("nf_nat_h323: out of TCP ports\n");
return 0;
}
/* Modify signal */
if (set_h245_addr(pskb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) < 0) {
nf_conntrack_unexpect_related(exp);
return -1;
}
DEBUGP("nf_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;
}
/****************************************************************************/
static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
TransportAddress *taddr, __be16 port,
struct nf_conntrack_expect *exp)
{
struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
int dir = CTINFO2DIR(ctinfo);
u_int16_t nated_port = ntohs(port);
/* Set expectations for NAT */
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
exp->expectfn = nf_nat_follow_master;
exp->dir = !dir;
/* Check existing expects */
if (info->sig_port[dir] == port)
nated_port = ntohs(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 (nf_conntrack_expect_related(exp) == 0)
break;
}
if (nated_port == 0) { /* No port available */
if (net_ratelimit())
printk("nf_nat_q931: out of TCP ports\n");
return 0;
}
/* Modify signal */
if (set_h225_addr(pskb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) == 0) {
/* Save ports */
info->sig_port[dir] = port;
info->sig_port[!dir] = htons(nated_port);
} else {
nf_conntrack_unexpect_related(exp);
return -1;
}
DEBUGP("nf_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 nf_conntrack_q931_expect()
* which was set by nf_conntrack_h323.c.
****************************************************************************/
static void ip_nat_q931_expect(struct nf_conn *new,
struct nf_conntrack_expect *this)
{
struct ip_nat_range range;
if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */
nf_nat_follow_master(new, this);
return;
}
/* 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.u3.ip;
/* hook doesn't matter, but it has to do source manip */
nf_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.u3.ip;
/* hook doesn't matter, but it has to do destination manip */
nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
}
/****************************************************************************/
static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, TransportAddress *taddr, int idx,
__be16 port, struct nf_conntrack_expect *exp)
{
struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
int dir = CTINFO2DIR(ctinfo);
u_int16_t nated_port = ntohs(port);
union nf_conntrack_address addr;
/* 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 = ntohs(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 (nf_conntrack_expect_related(exp) == 0)
break;
}
if (nated_port == 0) { /* No port available */
if (net_ratelimit())
printk("nf_nat_ras: out of TCP ports\n");
return 0;
}
/* Modify signal */
if (set_h225_addr(pskb, data, 0, &taddr[idx],
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) == 0) {
/* Save ports */
info->sig_port[dir] = port;
info->sig_port[!dir] = htons(nated_port);
/* Fix for Gnomemeeting */
if (idx > 0 &&
get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
(ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
set_h225_addr_hook(pskb, data, 0, &taddr[0],
&ct->tuplehash[!dir].tuple.dst.u3,
info->sig_port[!dir]);
}
} else {
nf_conntrack_unexpect_related(exp);
return -1;
}
/* Success */
DEBUGP("nf_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 nf_conn *new,
struct nf_conntrack_expect *this)
{
struct nf_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.u3.ip;
/* hook doesn't matter, but it has to do source manip */
nf_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 */
nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
}
/****************************************************************************/
static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned char **data, int dataoff,
TransportAddress *taddr, __be16 port,
struct nf_conntrack_expect *exp)
{
int dir = CTINFO2DIR(ctinfo);
u_int16_t nated_port;
/* Set expectations for NAT */
exp->saved_ip = exp->tuple.dst.u3.ip;
exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.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 = ntohs(port); nated_port != 0; nated_port++) {
exp->tuple.dst.u.tcp.port = htons(nated_port);
if (nf_conntrack_expect_related(exp) == 0)
break;
}
if (nated_port == 0) { /* No port available */
if (net_ratelimit())
printk("nf_nat_q931: out of TCP ports\n");
return 0;
}
/* Modify signal */
if (!set_h225_addr(pskb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) == 0) {
nf_conntrack_unexpect_related(exp);
return -1;
}
/* Success */
DEBUGP("nf_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("nf_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 <[email protected]>");
MODULE_DESCRIPTION("H.323 NAT helper");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_nat_h323");

View file

@ -0,0 +1,433 @@
/* ip_nat_helper.c - generic support functions for NAT helpers
*
* (C) 2000-2002 Harald Welte <laforge@netfilter.org>
* (C) 2003-2006 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/kmod.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/checksum.h>
#include <net/tcp.h>
#include <linux/netfilter_ipv4.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_protocol.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_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(nf_nat_seqofs_lock);
/* Setup TCP sequence correction given this change at this sequence */
static inline void
adjust_tcp_sequence(u32 seq,
int sizediff,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
int dir;
struct nf_nat_seq *this_way, *other_way;
struct nf_conn_nat *nat = nfct_nat(ct);
DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n",
(*skb)->len, new_size);
dir = CTINFO2DIR(ctinfo);
this_way = &nat->info.seq[dir];
other_way = &nat->info.seq[!dir];
DEBUGP("nf_nat_resize_packet: Seq_offset before: ");
DUMP_OFFSET(this_way);
spin_lock_bh(&nf_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(&nf_nat_seqofs_lock);
DEBUGP("nf_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 = (unsigned char *)skb->nh.iph + 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("nf_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("nf_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 */
skb->nh.iph->tot_len = htons(skb->len);
ip_send_check(skb->nh.iph);
}
/* 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
nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len)
{
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 = (*pskb)->nh.iph;
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(tcph, 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 */
nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4,
ct, CTINFO2DIR(ctinfo));
}
return 1;
}
EXPORT_SYMBOL(nf_nat_mangle_tcp_packet);
/* Generic function for mangling variable-length address changes inside
* NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
* command in the Amanda protocol)
*
* Takes care about all the nasty sequence number changes, checksumming,
* skb enlargement, ...
*
* XXX - This function could be merged with nf_nat_mangle_tcp_packet which
* should be fairly easy to do.
*/
int
nf_nat_mangle_udp_packet(struct sk_buff **pskb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
unsigned int match_offset,
unsigned int match_len,
const char *rep_buffer,
unsigned int rep_len)
{
struct iphdr *iph;
struct udphdr *udph;
int datalen, oldlen;
/* UDP helpers might accidentally mangle the wrong packet */
iph = (*pskb)->nh.iph;
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 = (*pskb)->nh.iph;
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(nf_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 nf_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
nf_nat_sack_adjust(struct sk_buff **pskb,
struct tcphdr *tcph,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
unsigned int dir, optoff, optend;
struct nf_conn_nat *nat = nfct_nat(ct);
optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr);
optend = (*pskb)->nh.iph->ihl*4 + 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],
&nat->info.seq[!dir]);
optoff += op[1];
}
}
return 1;
}
/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */
int
nf_nat_seq_adjust(struct sk_buff **pskb,
struct nf_conn *ct,
enum ip_conntrack_info ctinfo)
{
struct tcphdr *tcph;
int dir;
__be32 newseq, newack;
struct nf_conn_nat *nat = nfct_nat(ct);
struct nf_nat_seq *this_way, *other_way;
dir = CTINFO2DIR(ctinfo);
this_way = &nat->info.seq[dir];
other_way = &nat->info.seq[!dir];
if (!skb_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
return 0;
tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
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 (!nf_nat_sack_adjust(pskb, tcph, ct, ctinfo))
return 0;
nf_conntrack_tcp_update(*pskb, (*pskb)->nh.iph->ihl*4, ct, dir);
return 1;
}
EXPORT_SYMBOL(nf_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 nf_nat_follow_master(struct nf_conn *ct,
struct nf_conntrack_expect *exp)
{
struct nf_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.u3.ip;
/* hook doesn't matter, but it has to do source manip */
nf_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.u3.ip;
/* hook doesn't matter, but it has to do destination manip */
nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
}
EXPORT_SYMBOL(nf_nat_follow_master);

View file

@ -0,0 +1,101 @@
/* 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
*
* 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/moduleparam.h>
#include <linux/tcp.h>
#include <linux/kernel.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_helper.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_irc.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
MODULE_AUTHOR("Harald Welte <[email protected]>");
MODULE_DESCRIPTION("IRC (DCC) NAT helper");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_nat_irc");
static unsigned int help(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
unsigned int matchoff,
unsigned int matchlen,
struct nf_conntrack_expect *exp)
{
char buffer[sizeof("4294967296 65635")];
u_int32_t ip;
u_int16_t port;
unsigned int ret;
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;
exp->expectfn = nf_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 (nf_conntrack_expect_related(exp) == 0)
break;
}
if (port == 0)
return NF_DROP;
ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip);
sprintf(buffer, "%u %u", ip, port);
DEBUGP("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n",
buffer, NIPQUAD(ip), port);
ret = nf_nat_mangle_tcp_packet(pskb, exp->master, ctinfo,
matchoff, matchlen, buffer,
strlen(buffer));
if (ret != NF_ACCEPT)
nf_conntrack_unexpect_related(exp);
return ret;
}
static void __exit nf_nat_irc_fini(void)
{
rcu_assign_pointer(nf_nat_irc_hook, NULL);
synchronize_rcu();
}
static int __init nf_nat_irc_init(void)
{
BUG_ON(rcu_dereference(nf_nat_irc_hook));
rcu_assign_pointer(nf_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(nf_nat_irc_init);
module_exit(nf_nat_irc_fini);

View file

@ -0,0 +1,315 @@
/*
* nf_nat_pptp.c
*
* 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)
*/
#include <linux/module.h>
#include <linux/tcp.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_helper.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_proto_gre.h>
#include <linux/netfilter/nf_conntrack_pptp.h>
#define NF_NAT_PPTP_VERSION "3.0"
#define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off)))
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <[email protected]>");
MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
MODULE_ALIAS("ip_nat_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 nf_conn *ct,
struct nf_conntrack_expect *exp)
{
struct nf_conn *master = ct->master;
struct nf_conntrack_expect *other_exp;
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;
ct_pptp_info = &nfct_help(master)->help.ct_pptp_info;
nat_pptp_info = &nfct_nat(master)->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.l3num = AF_INET;
t.src.u3.ip = master->tuplehash[!exp->dir].tuple.src.u3.ip;
t.src.u.gre.key = ct_pptp_info->pac_call_id;
t.dst.u3.ip = master->tuplehash[!exp->dir].tuple.dst.u3.ip;
t.dst.u.gre.key = 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.l3num = AF_INET;
t.src.u3.ip = master->tuplehash[exp->dir].tuple.src.u3.ip;
t.src.u.gre.key = nat_pptp_info->pns_call_id;
t.dst.u3.ip = master->tuplehash[exp->dir].tuple.dst.u3.ip;
t.dst.u.gre.key = nat_pptp_info->pac_call_id;
t.dst.protonum = IPPROTO_GRE;
}
DEBUGP("trying to unexpect other dir: ");
NF_CT_DUMP_TUPLE(&t);
other_exp = nf_conntrack_expect_find_get(&t);
if (other_exp) {
nf_conntrack_unexpect_related(other_exp);
nf_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.u3.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 */
nf_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.u3.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 */
nf_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 nf_conn *ct,
enum ip_conntrack_info ctinfo,
struct PptpControlHeader *ctlh,
union pptp_ctrl_union *pptpReq)
{
struct nf_ct_pptp_master *ct_pptp_info;
struct nf_nat_pptp *nat_pptp_info;
u_int16_t msg;
__be16 new_callid;
unsigned int cid_off;
ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info;
nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info;
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 (nf_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 nf_conntrack_expect *expect_orig,
struct nf_conntrack_expect *expect_reply)
{
struct nf_conn *ct = expect_orig->master;
struct nf_ct_pptp_master *ct_pptp_info;
struct nf_nat_pptp *nat_pptp_info;
ct_pptp_info = &nfct_help(ct)->help.ct_pptp_info;
nat_pptp_info = &nfct_nat(ct)->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 nf_conn *ct,
enum ip_conntrack_info ctinfo,
struct PptpControlHeader *ctlh,
union pptp_ctrl_union *pptpReq)
{
struct nf_nat_pptp *nat_pptp_info;
u_int16_t msg;
__be16 new_pcid;
unsigned int pcid_off;
nat_pptp_info = &nfct_nat(ct)->help.nat_pptp_info;
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 (nf_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;
}
static int __init nf_nat_helper_pptp_init(void)
{
nf_nat_need_gre();
BUG_ON(rcu_dereference(nf_nat_pptp_hook_outbound));
rcu_assign_pointer(nf_nat_pptp_hook_outbound, pptp_outbound_pkt);
BUG_ON(rcu_dereference(nf_nat_pptp_hook_inbound));
rcu_assign_pointer(nf_nat_pptp_hook_inbound, pptp_inbound_pkt);
BUG_ON(rcu_dereference(nf_nat_pptp_hook_exp_gre));
rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, pptp_exp_gre);
BUG_ON(rcu_dereference(nf_nat_pptp_hook_expectfn));
rcu_assign_pointer(nf_nat_pptp_hook_expectfn, pptp_nat_expected);
return 0;
}
static void __exit nf_nat_helper_pptp_fini(void)
{
rcu_assign_pointer(nf_nat_pptp_hook_expectfn, NULL);
rcu_assign_pointer(nf_nat_pptp_hook_exp_gre, NULL);
rcu_assign_pointer(nf_nat_pptp_hook_inbound, NULL);
rcu_assign_pointer(nf_nat_pptp_hook_outbound, NULL);
synchronize_rcu();
}
module_init(nf_nat_helper_pptp_init);
module_exit(nf_nat_helper_pptp_fini);

View file

@ -0,0 +1,179 @@
/*
* nf_nat_proto_gre.c
*
* 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/skbuff.h>
#include <linux/ip.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
#include <linux/netfilter/nf_conntrack_proto_gre.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <[email protected]>");
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 nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype,
const union nf_conntrack_man_proto *min,
const union nf_conntrack_man_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 nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *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 (!nf_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 nf_conntrack_tuple *tuple,
enum nf_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)
return 1;
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;
}
return 1;
}
static struct nf_nat_protocol gre __read_mostly = {
.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 = nf_nat_port_range_to_nfattr,
.nfattr_to_range = nf_nat_port_nfattr_to_range,
#endif
};
int __init nf_nat_proto_gre_init(void)
{
return nf_nat_protocol_register(&gre);
}
void __exit nf_nat_proto_gre_fini(void)
{
nf_nat_protocol_unregister(&gre);
}
module_init(nf_nat_proto_gre_init);
module_exit(nf_nat_proto_gre_fini);
void nf_nat_need_gre(void)
{
return;
}
EXPORT_SYMBOL_GPL(nf_nat_need_gre);

View file

@ -0,0 +1,86 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 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/ip.h>
#include <linux/icmp.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
static int
icmp_in_range(const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype,
const union nf_conntrack_man_proto *min,
const union nf_conntrack_man_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 nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
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 (!nf_nat_used_tuple(tuple, ct))
return 1;
}
return 0;
}
static int
icmp_manip_pkt(struct sk_buff **pskb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_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 nf_nat_protocol nf_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 = nf_nat_port_range_to_nfattr,
.nfattr_to_range = nf_nat_port_nfattr_to_range,
#endif
};

View file

@ -0,0 +1,148 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 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/ip.h>
#include <linux/tcp.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
#include <net/netfilter/nf_nat_core.h>
static int
tcp_in_range(const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype,
const union nf_conntrack_man_proto *min,
const union nf_conntrack_man_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 nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
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;
}
for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size);
if (!nf_nat_used_tuple(tuple, ct))
return 1;
}
return 0;
}
static int
tcp_manip_pkt(struct sk_buff **pskb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_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.u3.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.u3.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 nf_nat_protocol nf_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 = nf_nat_port_range_to_nfattr,
.nfattr_to_range = nf_nat_port_nfattr_to_range,
#endif
};

View file

@ -0,0 +1,138 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 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/ip.h>
#include <linux/udp.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
static int
udp_in_range(const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype,
const union nf_conntrack_man_proto *min,
const union nf_conntrack_man_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 nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
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;
}
for (i = 0; i < range_size; i++, port++) {
*portptr = htons(min + port % range_size);
if (!nf_nat_used_tuple(tuple, ct))
return 1;
}
return 0;
}
static int
udp_manip_pkt(struct sk_buff **pskb,
unsigned int iphdroff,
const struct nf_conntrack_tuple *tuple,
enum nf_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.u3.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.u3.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 nf_nat_protocol nf_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 = nf_nat_port_range_to_nfattr,
.nfattr_to_range = nf_nat_port_nfattr_to_range,
#endif
};

View file

@ -0,0 +1,54 @@
/* 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-2006 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 <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
static int unknown_in_range(const struct nf_conntrack_tuple *tuple,
enum nf_nat_manip_type manip_type,
const union nf_conntrack_man_proto *min,
const union nf_conntrack_man_proto *max)
{
return 1;
}
static int unknown_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct)
{
/* 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 nf_conntrack_tuple *tuple,
enum nf_nat_manip_type maniptype)
{
return 1;
}
struct nf_nat_protocol nf_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

@ -0,0 +1,343 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 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 <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_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 = {
.repl = {
.name = "nat",
.valid_hooks = NAT_VALID_HOOKS,
.num_entries = 4,
.size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
.hook_entry = {
[NF_IP_PRE_ROUTING] = 0,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
.underflow = {
[NF_IP_PRE_ROUTING] = 0,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
[NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
},
.entries = {
/* PRE_ROUTING */
{
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
},
.target = {
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
/* POST_ROUTING */
{
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
},
.target = {
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
/* LOCAL_OUT */
{
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_standard),
},
.target = {
.target = {
.u = {
.target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
},
},
.verdict = -NF_ACCEPT - 1,
},
},
},
/* ERROR */
.term = {
.entry = {
.target_offset = sizeof(struct ipt_entry),
.next_offset = sizeof(struct ipt_error),
},
.target = {
.target = {
.u = {
.user = {
.target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
.name = IPT_ERROR_TARGET,
},
},
},
.errorname = "ERROR",
},
}
};
static struct ipt_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 nf_conn *ct;
enum ip_conntrack_info ctinfo;
const struct nf_nat_multi_range_compat *mr = targinfo;
NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING);
ct = nf_ct_get(*pskb, &ctinfo);
/* Connection must be valid and new. */
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
NF_CT_ASSERT(out);
return nf_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 nf_conn *ct;
enum ip_conntrack_info ctinfo;
const struct nf_nat_multi_range_compat *mr = targinfo;
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
hooknum == NF_IP_LOCAL_OUT);
ct = nf_ct_get(*pskb, &ctinfo);
/* Connection must be valid and new. */
NF_CT_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((*pskb)->nh.iph->daddr,
mr->range[0].min_ip);
return nf_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 nf_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 nf_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;
}
return 1;
}
inline unsigned int
alloc_null_binding(struct nf_conn *ct,
struct nf_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
? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip
: ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
struct nf_nat_range range
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } };
DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n",
ct, NIPQUAD(ip));
return nf_nat_setup_info(ct, &range, hooknum);
}
unsigned int
alloc_null_binding_confirmed(struct nf_conn *ct,
struct nf_nat_info *info,
unsigned int hooknum)
{
__be32 ip
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip
: ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
u_int16_t all
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
: ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all);
struct nf_nat_range range
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };
DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
ct, NIPQUAD(ip));
return nf_nat_setup_info(ct, &range, hooknum);
}
int nf_nat_rule_find(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
struct nf_conn *ct,
struct nf_nat_info *info)
{
int ret;
ret = ipt_do_table(pskb, hooknum, in, out, &nat_table);
if (ret == NF_ACCEPT) {
if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
/* NUL mapping */
ret = alloc_null_binding(ct, info, hooknum);
}
return ret;
}
static struct ipt_target ipt_snat_reg = {
.name = "SNAT",
.target = ipt_snat_target,
.targetsize = sizeof(struct nf_nat_multi_range_compat),
.table = "nat",
.hooks = 1 << NF_IP_POST_ROUTING,
.checkentry = ipt_snat_checkentry,
.family = AF_INET,
};
static struct xt_target ipt_dnat_reg = {
.name = "DNAT",
.target = ipt_dnat_target,
.targetsize = sizeof(struct nf_nat_multi_range_compat),
.table = "nat",
.hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT),
.checkentry = ipt_dnat_checkentry,
.family = AF_INET,
};
int __init nf_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:
ipt_unregister_table(&nat_table);
return ret;
}
void nf_nat_rule_cleanup(void)
{
xt_unregister_target(&ipt_dnat_reg);
xt_unregister_target(&ipt_snat_reg);
ipt_unregister_table(&nat_table);
}

View file

@ -0,0 +1,283 @@
/* 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 <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_helper.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_sip.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Hentschel <[email protected]>");
MODULE_DESCRIPTION("SIP NAT helper");
MODULE_ALIAS("ip_nat_sip");
#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 nf_conn *ct, struct addr_map *map)
{
struct nf_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.u3.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.u3.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 nf_conn *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(ct, *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 (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
matchoff, matchlen, addr, addrlen))
return 0;
*dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
return 1;
}
static unsigned int ip_nat_sip(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
const char **dptr)
{
enum sip_header_pos pos;
struct addr_map map;
int dataoff, datalen;
dataoff = (*pskb)->nh.iph->ihl*4 + 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 nf_conn *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(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0)
return 0;
if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
matchoff, matchlen, buffer, bufflen))
return 0;
/* We need to reload this. Thanks Patrick. */
*dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
return 1;
}
static int mangle_content_len(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
const char *dptr)
{
unsigned int dataoff, matchoff, matchlen;
char buffer[sizeof("65536")];
int bufflen;
dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
/* Get actual SDP lenght */
if (ct_sip_get_info(ct, 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 length */
if (ct_sip_get_info(ct, dptr, (*pskb)->len - dataoff, &matchoff,
&matchlen, POS_CONTENT) > 0) {
bufflen = sprintf(buffer, "%u", c_len);
return nf_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 nf_conn *ct,
__be32 newip, u_int16_t port,
const char *dptr)
{
char buffer[sizeof("nnn.nnn.nnn.nnn")];
unsigned int dataoff, bufflen;
dataoff = (*pskb)->nh.iph->ihl*4 + 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_IP4))
return 0;
if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
buffer, bufflen, POS_CONNECTION_IP4))
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 nf_conntrack_expect *exp,
const char *dptr)
{
struct nf_conn *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.u3.ip;
exp->tuple.dst.u3.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 = nf_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 (nf_conntrack_expect_related(exp) == 0)
break;
}
if (port == 0)
return NF_DROP;
if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) {
nf_conntrack_unexpect_related(exp);
return NF_DROP;
}
return NF_ACCEPT;
}
static void __exit nf_nat_sip_fini(void)
{
rcu_assign_pointer(nf_nat_sip_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_hook, NULL);
synchronize_rcu();
}
static int __init nf_nat_sip_init(void)
{
BUG_ON(rcu_dereference(nf_nat_sip_hook));
BUG_ON(rcu_dereference(nf_nat_sdp_hook));
rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp);
return 0;
}
module_init(nf_nat_sip_init);
module_exit(nf_nat_sip_fini);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,406 @@
/* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 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/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 <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_helper.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
#define HOOKNAME(hooknum) ((hooknum) == NF_IP_POST_ROUTING ? "POST_ROUTING" \
: ((hooknum) == NF_IP_PRE_ROUTING ? "PRE_ROUTING" \
: ((hooknum) == NF_IP_LOCAL_OUT ? "LOCAL_OUT" \
: ((hooknum) == NF_IP_LOCAL_IN ? "LOCAL_IN" \
: "*ERROR*")))
#ifdef CONFIG_XFRM
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{
struct nf_conn *ct;
struct nf_conntrack_tuple *t;
enum ip_conntrack_info ctinfo;
enum ip_conntrack_dir dir;
unsigned long statusbit;
ct = nf_ct_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.u3.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.u3.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
nf_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 nf_conn *ct;
enum ip_conntrack_info ctinfo;
struct nf_conn_nat *nat;
struct nf_nat_info *info;
/* maniptype == SRC for postrouting. */
enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
/* We never see fragments: conntrack defrags on pre-routing
and local-out, and nf_nat_out protects post-routing. */
NF_CT_ASSERT(!((*pskb)->nh.iph->frag_off
& htons(IP_MF|IP_OFFSET)));
ct = nf_ct_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 ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
struct icmphdr _hdr, *hp;
hp = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4,
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 == &nf_conntrack_untracked)
return NF_ACCEPT;
nat = nfct_nat(ct);
if (!nat)
return NF_DROP;
switch (ctinfo) {
case IP_CT_RELATED:
case IP_CT_RELATED+IP_CT_IS_REPLY:
if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
if (!nf_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 = &nat->info;
/* Seen it before? This can happen for loopback, retrans,
or local packets.. */
if (!nf_nat_initialized(ct, maniptype)) {
unsigned int ret;
if (unlikely(nf_ct_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 = nf_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 */
NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
info = &nat->info;
}
NF_CT_ASSERT(info);
return nf_nat_packet(ct, ctinfo, hooknum, pskb);
}
static unsigned int
nf_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 = (*pskb)->nh.iph->daddr;
ret = nf_nat_fn(hooknum, pskb, in, out, okfn);
if (ret != NF_DROP && ret != NF_STOLEN &&
daddr != (*pskb)->nh.iph->daddr) {
dst_release((*pskb)->dst);
(*pskb)->dst = NULL;
}
return ret;
}
static unsigned int
nf_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 nf_conn *ct;
enum ip_conntrack_info ctinfo;
#endif
unsigned int ret;
/* root is playing with raw sockets. */
if ((*pskb)->len < sizeof(struct iphdr) ||
(*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
return NF_ACCEPT;
ret = nf_nat_fn(hooknum, pskb, in, out, okfn);
#ifdef CONFIG_XFRM
if (ret != NF_DROP && ret != NF_STOLEN &&
(ct = nf_ct_get(*pskb, &ctinfo)) != NULL) {
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
if (ct->tuplehash[dir].tuple.src.u3.ip !=
ct->tuplehash[!dir].tuple.dst.u3.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
nf_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 nf_conn *ct;
enum ip_conntrack_info ctinfo;
unsigned int ret;
/* root is playing with raw sockets. */
if ((*pskb)->len < sizeof(struct iphdr) ||
(*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
return NF_ACCEPT;
ret = nf_nat_fn(hooknum, pskb, in, out, okfn);
if (ret != NF_DROP && ret != NF_STOLEN &&
(ct = nf_ct_get(*pskb, &ctinfo)) != NULL) {
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
if (ct->tuplehash[dir].tuple.dst.u3.ip !=
ct->tuplehash[!dir].tuple.src.u3.ip
#ifdef CONFIG_XFRM
|| ct->tuplehash[dir].tuple.dst.u.all !=
ct->tuplehash[!dir].tuple.src.u.all
#endif
)
if (ip_route_me_harder(pskb, RTN_UNSPEC))
ret = NF_DROP;
}
return ret;
}
static unsigned int
nf_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 nf_conn *ct;
enum ip_conntrack_info ctinfo;
ct = nf_ct_get(*pskb, &ctinfo);
if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
DEBUGP("nf_nat_standalone: adjusting sequence number\n");
if (!nf_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 nf_nat_ops[] = {
/* Before packet filtering, change destination */
{
.hook = nf_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 = nf_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 = nf_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 = nf_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 = nf_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 = nf_nat_adjust,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_IN,
.priority = NF_IP_PRI_NAT_SEQ_ADJUST,
},
};
static int __init nf_nat_standalone_init(void)
{
int size, ret = 0;
need_conntrack();
size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) +
sizeof(struct nf_conn_nat);
ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size);
if (ret < 0) {
printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n");
return ret;
}
size = ALIGN(size, __alignof__(struct nf_conn_help)) +
sizeof(struct nf_conn_help);
ret = nf_conntrack_register_cache(NF_CT_F_NAT|NF_CT_F_HELP,
"nf_nat:help", size);
if (ret < 0) {
printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n");
goto cleanup_register_cache;
}
#ifdef CONFIG_XFRM
BUG_ON(ip_nat_decode_session != NULL);
ip_nat_decode_session = nat_decode_session;
#endif
ret = nf_nat_rule_init();
if (ret < 0) {
printk("nf_nat_init: can't setup rules.\n");
goto cleanup_decode_session;
}
ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
if (ret < 0) {
printk("nf_nat_init: can't register hooks.\n");
goto cleanup_rule_init;
}
nf_nat_module_is_loaded = 1;
return ret;
cleanup_rule_init:
nf_nat_rule_cleanup();
cleanup_decode_session:
#ifdef CONFIG_XFRM
ip_nat_decode_session = NULL;
synchronize_net();
#endif
nf_conntrack_unregister_cache(NF_CT_F_NAT|NF_CT_F_HELP);
cleanup_register_cache:
nf_conntrack_unregister_cache(NF_CT_F_NAT);
return ret;
}
static void __exit nf_nat_standalone_fini(void)
{
nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
nf_nat_rule_cleanup();
nf_nat_module_is_loaded = 0;
#ifdef CONFIG_XFRM
ip_nat_decode_session = NULL;
synchronize_net();
#endif
/* Conntrack caches are unregistered in nf_conntrack_cleanup */
}
module_init(nf_nat_standalone_init);
module_exit(nf_nat_standalone_fini);
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_nat");

View file

@ -0,0 +1,52 @@
/* (C) 2001-2002 Magnus Boden <[email protected]>
*
* 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/moduleparam.h>
#include <linux/udp.h>
#include <net/netfilter/nf_nat_helper.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_tftp.h>
MODULE_AUTHOR("Magnus Boden <[email protected]>");
MODULE_DESCRIPTION("TFTP NAT helper");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ip_nat_tftp");
static unsigned int help(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp)
{
struct nf_conn *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 = nf_nat_follow_master;
if (nf_conntrack_expect_related(exp) != 0)
return NF_DROP;
return NF_ACCEPT;
}
static void __exit nf_nat_tftp_fini(void)
{
rcu_assign_pointer(nf_nat_tftp_hook, NULL);
synchronize_rcu();
}
static int __init nf_nat_tftp_init(void)
{
BUG_ON(rcu_dereference(nf_nat_tftp_hook));
rcu_assign_pointer(nf_nat_tftp_hook, help);
return 0;
}
module_init(nf_nat_tftp_init);
module_exit(nf_nat_tftp_fini);

View file

@ -38,6 +38,7 @@
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <net/udplite.h>
#include <linux/inetdevice.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
@ -66,6 +67,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
atomic_read(&tcp_memory_allocated));
seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
atomic_read(&ip_frag_mem));
@ -304,6 +306,17 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
fold_field((void **) udp_statistics,
snmp4_udp_list[i].entry));
/* the UDP and UDP-Lite MIBs are the same */
seq_puts(seq, "\nUdpLite:");
for (i = 0; snmp4_udp_list[i].name != NULL; i++)
seq_printf(seq, " %s", snmp4_udp_list[i].name);
seq_puts(seq, "\nUdpLite:");
for (i = 0; snmp4_udp_list[i].name != NULL; i++)
seq_printf(seq, " %lu",
fold_field((void **) udplite_statistics,
snmp4_udp_list[i].entry) );
seq_putc(seq, '\n');
return 0;
}

View file

@ -854,8 +854,8 @@ static void raw_seq_stop(struct seq_file *seq, void *v)
static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
{
struct inet_sock *inet = inet_sk(sp);
unsigned int dest = inet->daddr,
src = inet->rcv_saddr;
__be32 dest = inet->daddr,
src = inet->rcv_saddr;
__u16 destp = 0,
srcp = inet->num;

View file

@ -566,11 +566,9 @@ static inline u32 rt_score(struct rtable *rt)
static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
{
return ((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) |
(fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) |
#ifdef CONFIG_IP_ROUTE_FWMARK
(fl1->nl_u.ip4_u.fwmark ^ fl2->nl_u.ip4_u.fwmark) |
#endif
return ((__force u32)((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) |
(fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr)) |
(fl1->mark ^ fl2->mark) |
(*(u16 *)&fl1->nl_u.ip4_u.tos ^
*(u16 *)&fl2->nl_u.ip4_u.tos) |
(fl1->oif ^ fl2->oif) |
@ -1643,9 +1641,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
rth->fl.fl4_tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->fl.fl4_fwmark= skb->nfmark;
#endif
rth->fl.mark = skb->mark;
rth->fl.fl4_src = saddr;
rth->rt_src = saddr;
#ifdef CONFIG_NET_CLS_ROUTE
@ -1789,9 +1785,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
rth->fl.fl4_tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->fl.fl4_fwmark= skb->nfmark;
#endif
rth->fl.mark = skb->mark;
rth->fl.fl4_src = saddr;
rth->rt_src = saddr;
rth->rt_gateway = daddr;
@ -1920,10 +1914,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
.saddr = saddr,
.tos = tos,
.scope = RT_SCOPE_UNIVERSE,
#ifdef CONFIG_IP_ROUTE_FWMARK
.fwmark = skb->nfmark
#endif
} },
.mark = skb->mark,
.iif = dev->ifindex };
unsigned flags = 0;
u32 itag = 0;
@ -2034,9 +2026,7 @@ local_input:
rth->fl.fl4_dst = daddr;
rth->rt_dst = daddr;
rth->fl.fl4_tos = tos;
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->fl.fl4_fwmark= skb->nfmark;
#endif
rth->fl.mark = skb->mark;
rth->fl.fl4_src = saddr;
rth->rt_src = saddr;
#ifdef CONFIG_NET_CLS_ROUTE
@ -2113,9 +2103,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
rth->fl.fl4_src == saddr &&
rth->fl.iif == iif &&
rth->fl.oif == 0 &&
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->fl.fl4_fwmark == skb->nfmark &&
#endif
rth->fl.mark == skb->mark &&
rth->fl.fl4_tos == tos) {
rth->u.dst.lastuse = jiffies;
dst_hold(&rth->u.dst);
@ -2239,9 +2227,7 @@ static inline int __mkroute_output(struct rtable **result,
rth->fl.fl4_tos = tos;
rth->fl.fl4_src = oldflp->fl4_src;
rth->fl.oif = oldflp->oif;
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->fl.fl4_fwmark= oldflp->fl4_fwmark;
#endif
rth->fl.mark = oldflp->mark;
rth->rt_dst = fl->fl4_dst;
rth->rt_src = fl->fl4_src;
rth->rt_iif = oldflp->oif ? : dev_out->ifindex;
@ -2385,10 +2371,8 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
.scope = ((tos & RTO_ONLINK) ?
RT_SCOPE_LINK :
RT_SCOPE_UNIVERSE),
#ifdef CONFIG_IP_ROUTE_FWMARK
.fwmark = oldflp->fl4_fwmark
#endif
} },
.mark = oldflp->mark,
.iif = loopback_dev.ifindex,
.oif = oldflp->oif };
struct fib_result res;
@ -2583,9 +2567,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
rth->fl.fl4_src == flp->fl4_src &&
rth->fl.iif == 0 &&
rth->fl.oif == flp->oif &&
#ifdef CONFIG_IP_ROUTE_FWMARK
rth->fl.fl4_fwmark == flp->fl4_fwmark &&
#endif
rth->fl.mark == flp->mark &&
!((rth->fl.fl4_tos ^ flp->fl4_tos) &
(IPTOS_RT_MASK | RTO_ONLINK))) {
@ -2647,7 +2629,8 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
struct rtable *rt = (struct rtable*)skb->dst;
struct rtmsg *r;
struct nlmsghdr *nlh;
struct rta_cacheinfo ci;
long expires;
u32 id = 0, ts = 0, tsage = 0, error;
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*r), flags);
if (nlh == NULL)
@ -2694,20 +2677,13 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
goto nla_put_failure;
ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse);
ci.rta_used = rt->u.dst.__use;
ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt);
if (rt->u.dst.expires)
ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies);
else
ci.rta_expires = 0;
ci.rta_error = rt->u.dst.error;
ci.rta_id = ci.rta_ts = ci.rta_tsage = 0;
error = rt->u.dst.error;
expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0;
if (rt->peer) {
ci.rta_id = rt->peer->ip_id_count;
id = rt->peer->ip_id_count;
if (rt->peer->tcp_ts_stamp) {
ci.rta_ts = rt->peer->tcp_ts;
ci.rta_tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp;
ts = rt->peer->tcp_ts;
tsage = xtime.tv_sec - rt->peer->tcp_ts_stamp;
}
}
@ -2726,7 +2702,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
} else {
if (err == -EMSGSIZE)
goto nla_put_failure;
ci.rta_error = err;
error = err;
}
}
} else
@ -2734,7 +2710,9 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
NLA_PUT_U32(skb, RTA_IIF, rt->fl.iif);
}
NLA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci);
if (rtnl_put_cacheinfo(skb, &rt->u.dst, id, ts, tsage,
expires, error) < 0)
goto nla_put_failure;
return nlmsg_end(skb, nlh);

View file

@ -35,23 +35,23 @@ module_init(init_syncookies);
#define COOKIEBITS 24 /* Upper bits store count */
#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
static u32 cookie_hash(u32 saddr, u32 daddr, u32 sport, u32 dport,
static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
u32 count, int c)
{
__u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS];
memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c]));
tmp[0] = saddr;
tmp[1] = daddr;
tmp[2] = (sport << 16) + dport;
tmp[0] = (__force u32)saddr;
tmp[1] = (__force u32)daddr;
tmp[2] = ((__force u32)sport << 16) + (__force u32)dport;
tmp[3] = count;
sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
return tmp[17];
}
static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport,
__u16 dport, __u32 sseq, __u32 count,
static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport,
__be16 dport, __u32 sseq, __u32 count,
__u32 data)
{
/*
@ -80,8 +80,8 @@ static __u32 secure_tcp_syn_cookie(__u32 saddr, __u32 daddr, __u16 sport,
* "maxdiff" if the current (passed-in) "count". The return value
* is (__u32)-1 if this test fails.
*/
static __u32 check_tcp_syn_cookie(__u32 cookie, __u32 saddr, __u32 daddr,
__u16 sport, __u16 dport, __u32 sseq,
static __u32 check_tcp_syn_cookie(__u32 cookie, __be32 saddr, __be32 daddr,
__be16 sport, __be16 dport, __u32 sseq,
__u32 count, __u32 maxdiff)
{
__u32 diff;
@ -220,7 +220,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
}
ireq = inet_rsk(req);
treq = tcp_rsk(req);
treq->rcv_isn = htonl(skb->h.th->seq) - 1;
treq->rcv_isn = ntohl(skb->h.th->seq) - 1;
treq->snt_isn = cookie;
req->mss = mss;
ireq->rmt_port = skb->h.th->source;

View file

@ -129,6 +129,67 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
return ret;
}
static int proc_tcp_available_congestion_control(ctl_table *ctl,
int write, struct file * filp,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX, };
int ret;
tbl.data = kmalloc(tbl.maxlen, GFP_USER);
if (!tbl.data)
return -ENOMEM;
tcp_get_available_congestion_control(tbl.data, TCP_CA_BUF_MAX);
ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos);
kfree(tbl.data);
return ret;
}
static int proc_allowed_congestion_control(ctl_table *ctl,
int write, struct file * filp,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX };
int ret;
tbl.data = kmalloc(tbl.maxlen, GFP_USER);
if (!tbl.data)
return -ENOMEM;
tcp_get_allowed_congestion_control(tbl.data, tbl.maxlen);
ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos);
if (write && ret == 0)
ret = tcp_set_allowed_congestion_control(tbl.data);
kfree(tbl.data);
return ret;
}
static int strategy_allowed_congestion_control(ctl_table *table, int __user *name,
int nlen, void __user *oldval,
size_t __user *oldlenp,
void __user *newval, size_t newlen,
void **context)
{
ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX };
int ret;
tbl.data = kmalloc(tbl.maxlen, GFP_USER);
if (!tbl.data)
return -ENOMEM;
tcp_get_available_congestion_control(tbl.data, tbl.maxlen);
ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen,
context);
if (ret == 0 && newval && newlen)
ret = tcp_set_allowed_congestion_control(tbl.data);
kfree(tbl.data);
return ret;
}
ctl_table ipv4_table[] = {
{
.ctl_name = NET_IPV4_TCP_TIMESTAMPS,
@ -731,6 +792,21 @@ ctl_table ipv4_table[] = {
.proc_handler = &proc_dointvec,
},
#endif /* CONFIG_NETLABEL */
{
.ctl_name = NET_TCP_AVAIL_CONG_CONTROL,
.procname = "tcp_available_congestion_control",
.maxlen = TCP_CA_BUF_MAX,
.mode = 0444,
.proc_handler = &proc_tcp_available_congestion_control,
},
{
.ctl_name = NET_TCP_ALLOWED_CONG_CONTROL,
.procname = "tcp_allowed_congestion_control",
.maxlen = TCP_CA_BUF_MAX,
.mode = 0644,
.proc_handler = &proc_allowed_congestion_control,
.strategy = &strategy_allowed_congestion_control,
},
{ .ctl_name = 0 }
};

View file

@ -258,6 +258,7 @@
#include <linux/bootmem.h>
#include <linux/cache.h>
#include <linux/err.h>
#include <linux/crypto.h>
#include <net/icmp.h>
#include <net/tcp.h>
@ -462,11 +463,12 @@ static inline int forced_push(struct tcp_sock *tp)
static inline void skb_entail(struct sock *sk, struct tcp_sock *tp,
struct sk_buff *skb)
{
skb->csum = 0;
TCP_SKB_CB(skb)->seq = tp->write_seq;
TCP_SKB_CB(skb)->end_seq = tp->write_seq;
TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
TCP_SKB_CB(skb)->sacked = 0;
struct tcp_skb_cb *tcb = TCP_SKB_CB(skb);
skb->csum = 0;
tcb->seq = tcb->end_seq = tp->write_seq;
tcb->flags = TCPCB_FLAG_ACK;
tcb->sacked = 0;
skb_header_release(skb);
__skb_queue_tail(&sk->sk_write_queue, skb);
sk_charge_skb(sk, skb);
@ -1942,6 +1944,13 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
}
break;
#ifdef CONFIG_TCP_MD5SIG
case TCP_MD5SIG:
/* Read the IP->Key mappings from userspace */
err = tp->af_specific->md5_parse(sk, optval, optlen);
break;
#endif
default:
err = -ENOPROTOOPT;
break;
@ -2154,7 +2163,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
struct tcphdr *th;
unsigned thlen;
unsigned int seq;
unsigned int delta;
__be32 delta;
unsigned int oldlen;
unsigned int len;
@ -2207,7 +2216,8 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
do {
th->fin = th->psh = 0;
th->check = ~csum_fold(th->check + delta);
th->check = ~csum_fold((__force __wsum)((__force u32)th->check +
(__force u32)delta));
if (skb->ip_summed != CHECKSUM_PARTIAL)
th->check = csum_fold(csum_partial(skb->h.raw, thlen,
skb->csum));
@ -2221,7 +2231,8 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
} while (skb->next);
delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len);
th->check = ~csum_fold(th->check + delta);
th->check = ~csum_fold((__force __wsum)((__force u32)th->check +
(__force u32)delta));
if (skb->ip_summed != CHECKSUM_PARTIAL)
th->check = csum_fold(csum_partial(skb->h.raw, thlen,
skb->csum));
@ -2231,6 +2242,135 @@ out:
}
EXPORT_SYMBOL(tcp_tso_segment);
#ifdef CONFIG_TCP_MD5SIG
static unsigned long tcp_md5sig_users;
static struct tcp_md5sig_pool **tcp_md5sig_pool;
static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
{
int cpu;
for_each_possible_cpu(cpu) {
struct tcp_md5sig_pool *p = *per_cpu_ptr(pool, cpu);
if (p) {
if (p->md5_desc.tfm)
crypto_free_hash(p->md5_desc.tfm);
kfree(p);
p = NULL;
}
}
free_percpu(pool);
}
void tcp_free_md5sig_pool(void)
{
struct tcp_md5sig_pool **pool = NULL;
spin_lock(&tcp_md5sig_pool_lock);
if (--tcp_md5sig_users == 0) {
pool = tcp_md5sig_pool;
tcp_md5sig_pool = NULL;
}
spin_unlock(&tcp_md5sig_pool_lock);
if (pool)
__tcp_free_md5sig_pool(pool);
}
EXPORT_SYMBOL(tcp_free_md5sig_pool);
static struct tcp_md5sig_pool **__tcp_alloc_md5sig_pool(void)
{
int cpu;
struct tcp_md5sig_pool **pool;
pool = alloc_percpu(struct tcp_md5sig_pool *);
if (!pool)
return NULL;
for_each_possible_cpu(cpu) {
struct tcp_md5sig_pool *p;
struct crypto_hash *hash;
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
goto out_free;
*per_cpu_ptr(pool, cpu) = p;
hash = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
if (!hash || IS_ERR(hash))
goto out_free;
p->md5_desc.tfm = hash;
}
return pool;
out_free:
__tcp_free_md5sig_pool(pool);
return NULL;
}
struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void)
{
struct tcp_md5sig_pool **pool;
int alloc = 0;
retry:
spin_lock(&tcp_md5sig_pool_lock);
pool = tcp_md5sig_pool;
if (tcp_md5sig_users++ == 0) {
alloc = 1;
spin_unlock(&tcp_md5sig_pool_lock);
} else if (!pool) {
tcp_md5sig_users--;
spin_unlock(&tcp_md5sig_pool_lock);
cpu_relax();
goto retry;
} else
spin_unlock(&tcp_md5sig_pool_lock);
if (alloc) {
/* we cannot hold spinlock here because this may sleep. */
struct tcp_md5sig_pool **p = __tcp_alloc_md5sig_pool();
spin_lock(&tcp_md5sig_pool_lock);
if (!p) {
tcp_md5sig_users--;
spin_unlock(&tcp_md5sig_pool_lock);
return NULL;
}
pool = tcp_md5sig_pool;
if (pool) {
/* oops, it has already been assigned. */
spin_unlock(&tcp_md5sig_pool_lock);
__tcp_free_md5sig_pool(p);
} else {
tcp_md5sig_pool = pool = p;
spin_unlock(&tcp_md5sig_pool_lock);
}
}
return pool;
}
EXPORT_SYMBOL(tcp_alloc_md5sig_pool);
struct tcp_md5sig_pool *__tcp_get_md5sig_pool(int cpu)
{
struct tcp_md5sig_pool **p;
spin_lock(&tcp_md5sig_pool_lock);
p = tcp_md5sig_pool;
if (p)
tcp_md5sig_users++;
spin_unlock(&tcp_md5sig_pool_lock);
return (p ? *per_cpu_ptr(p, cpu) : NULL);
}
EXPORT_SYMBOL(__tcp_get_md5sig_pool);
void __tcp_put_md5sig_pool(void) {
__tcp_free_md5sig_pool(tcp_md5sig_pool);
}
EXPORT_SYMBOL(__tcp_put_md5sig_pool);
#endif
extern void __skb_cb_too_small_for_tcp(int, int);
extern struct tcp_congestion_ops tcp_reno;

View file

@ -113,7 +113,7 @@ int tcp_set_default_congestion_control(const char *name)
spin_lock(&tcp_cong_list_lock);
ca = tcp_ca_find(name);
#ifdef CONFIG_KMOD
if (!ca) {
if (!ca && capable(CAP_SYS_MODULE)) {
spin_unlock(&tcp_cong_list_lock);
request_module("tcp_%s", name);
@ -123,6 +123,7 @@ int tcp_set_default_congestion_control(const char *name)
#endif
if (ca) {
ca->non_restricted = 1; /* default is always allowed */
list_move(&ca->list, &tcp_cong_list);
ret = 0;
}
@ -139,6 +140,22 @@ static int __init tcp_congestion_default(void)
late_initcall(tcp_congestion_default);
/* Build string with list of available congestion control values */
void tcp_get_available_congestion_control(char *buf, size_t maxlen)
{
struct tcp_congestion_ops *ca;
size_t offs = 0;
rcu_read_lock();
list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
offs += snprintf(buf + offs, maxlen - offs,
"%s%s",
offs == 0 ? "" : " ", ca->name);
}
rcu_read_unlock();
}
/* Get current default congestion control */
void tcp_get_default_congestion_control(char *name)
{
@ -152,6 +169,64 @@ void tcp_get_default_congestion_control(char *name)
rcu_read_unlock();
}
/* Built list of non-restricted congestion control values */
void tcp_get_allowed_congestion_control(char *buf, size_t maxlen)
{
struct tcp_congestion_ops *ca;
size_t offs = 0;
*buf = '\0';
rcu_read_lock();
list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
if (!ca->non_restricted)
continue;
offs += snprintf(buf + offs, maxlen - offs,
"%s%s",
offs == 0 ? "" : " ", ca->name);
}
rcu_read_unlock();
}
/* Change list of non-restricted congestion control */
int tcp_set_allowed_congestion_control(char *val)
{
struct tcp_congestion_ops *ca;
char *clone, *name;
int ret = 0;
clone = kstrdup(val, GFP_USER);
if (!clone)
return -ENOMEM;
spin_lock(&tcp_cong_list_lock);
/* pass 1 check for bad entries */
while ((name = strsep(&clone, " ")) && *name) {
ca = tcp_ca_find(name);
if (!ca) {
ret = -ENOENT;
goto out;
}
}
/* pass 2 clear */
list_for_each_entry_rcu(ca, &tcp_cong_list, list)
ca->non_restricted = 0;
/* pass 3 mark as allowed */
while ((name = strsep(&val, " ")) && *name) {
ca = tcp_ca_find(name);
WARN_ON(!ca);
if (ca)
ca->non_restricted = 1;
}
out:
spin_unlock(&tcp_cong_list_lock);
return ret;
}
/* Change congestion control for socket */
int tcp_set_congestion_control(struct sock *sk, const char *name)
{
@ -161,12 +236,25 @@ int tcp_set_congestion_control(struct sock *sk, const char *name)
rcu_read_lock();
ca = tcp_ca_find(name);
/* no change asking for existing value */
if (ca == icsk->icsk_ca_ops)
goto out;
#ifdef CONFIG_KMOD
/* not found attempt to autoload module */
if (!ca && capable(CAP_SYS_MODULE)) {
rcu_read_unlock();
request_module("tcp_%s", name);
rcu_read_lock();
ca = tcp_ca_find(name);
}
#endif
if (!ca)
err = -ENOENT;
else if (!(ca->non_restricted || capable(CAP_NET_ADMIN)))
err = -EPERM;
else if (!try_module_get(ca->owner))
err = -EBUSY;
@ -268,6 +356,7 @@ EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd);
struct tcp_congestion_ops tcp_reno = {
.name = "reno",
.non_restricted = 1,
.owner = THIS_MODULE,
.ssthresh = tcp_reno_ssthresh,
.cong_avoid = tcp_reno_cong_avoid,

View file

@ -26,12 +26,12 @@ struct htcp {
u32 alpha; /* Fixed point arith, << 7 */
u8 beta; /* Fixed point arith, << 7 */
u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */
u32 last_cong; /* Time since last congestion event end */
u32 undo_last_cong;
u16 pkts_acked;
u32 packetcount;
u32 minRTT;
u32 maxRTT;
u32 last_cong; /* Time since last congestion event end */
u32 undo_last_cong;
u32 undo_maxRTT;
u32 undo_old_maxB;

View file

@ -2677,6 +2677,14 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
opt_rx->sack_ok) {
TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th;
}
#ifdef CONFIG_TCP_MD5SIG
case TCPOPT_MD5SIG:
/*
* The MD5 Hash has already been
* checked (see tcp_v{4,6}_do_rcv()).
*/
break;
#endif
};
ptr+=opsize-2;
length-=opsize;
@ -3782,9 +3790,9 @@ static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen)
return err;
}
static int __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb)
static __sum16 __tcp_checksum_complete_user(struct sock *sk, struct sk_buff *skb)
{
int result;
__sum16 result;
if (sock_owned_by_user(sk)) {
local_bh_enable();
@ -4230,6 +4238,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
mb();
tcp_set_state(sk, TCP_ESTABLISHED);
security_inet_conn_established(sk, skb);
/* Make sure socket is routed, for correct metrics. */
icsk->icsk_af_ops->rebuild_header(sk);

Some files were not shown because too many files have changed in this diff Show more