mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
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:
commit
4c1ac1b491
1476 changed files with 67631 additions and 41020 deletions
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, '.'))) {
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 } },
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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}},
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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]>");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
412
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
Normal file
412
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
Normal 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");
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
78
net/ipv4/netfilter/nf_nat_amanda.c
Normal file
78
net/ipv4/netfilter/nf_nat_amanda.c
Normal 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);
|
||||
647
net/ipv4/netfilter/nf_nat_core.c
Normal file
647
net/ipv4/netfilter/nf_nat_core.c
Normal 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);
|
||||
179
net/ipv4/netfilter/nf_nat_ftp.c
Normal file
179
net/ipv4/netfilter/nf_nat_ftp.c
Normal 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);
|
||||
596
net/ipv4/netfilter/nf_nat_h323.c
Normal file
596
net/ipv4/netfilter/nf_nat_h323.c
Normal 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");
|
||||
433
net/ipv4/netfilter/nf_nat_helper.c
Normal file
433
net/ipv4/netfilter/nf_nat_helper.c
Normal 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);
|
||||
101
net/ipv4/netfilter/nf_nat_irc.c
Normal file
101
net/ipv4/netfilter/nf_nat_irc.c
Normal 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);
|
||||
315
net/ipv4/netfilter/nf_nat_pptp.c
Normal file
315
net/ipv4/netfilter/nf_nat_pptp.c
Normal 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);
|
||||
179
net/ipv4/netfilter/nf_nat_proto_gre.c
Normal file
179
net/ipv4/netfilter/nf_nat_proto_gre.c
Normal 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);
|
||||
86
net/ipv4/netfilter/nf_nat_proto_icmp.c
Normal file
86
net/ipv4/netfilter/nf_nat_proto_icmp.c
Normal 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
|
||||
};
|
||||
148
net/ipv4/netfilter/nf_nat_proto_tcp.c
Normal file
148
net/ipv4/netfilter/nf_nat_proto_tcp.c
Normal 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
|
||||
};
|
||||
138
net/ipv4/netfilter/nf_nat_proto_udp.c
Normal file
138
net/ipv4/netfilter/nf_nat_proto_udp.c
Normal 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
|
||||
};
|
||||
54
net/ipv4/netfilter/nf_nat_proto_unknown.c
Normal file
54
net/ipv4/netfilter/nf_nat_proto_unknown.c
Normal 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,
|
||||
};
|
||||
343
net/ipv4/netfilter/nf_nat_rule.c
Normal file
343
net/ipv4/netfilter/nf_nat_rule.c
Normal 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);
|
||||
}
|
||||
283
net/ipv4/netfilter/nf_nat_sip.c
Normal file
283
net/ipv4/netfilter/nf_nat_sip.c
Normal 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);
|
||||
1332
net/ipv4/netfilter/nf_nat_snmp_basic.c
Normal file
1332
net/ipv4/netfilter/nf_nat_snmp_basic.c
Normal file
File diff suppressed because it is too large
Load diff
406
net/ipv4/netfilter/nf_nat_standalone.c
Normal file
406
net/ipv4/netfilter/nf_nat_standalone.c
Normal 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");
|
||||
52
net/ipv4/netfilter/nf_nat_tftp.c
Normal file
52
net/ipv4/netfilter/nf_nat_tftp.c
Normal 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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
|||
156
net/ipv4/tcp.c
156
net/ipv4/tcp.c
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in a new issue