mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 22:40:54 -04:00
Support full CONE NAT and ADDRESS RESTRICTED CONE NAT
Adding support for Full cone NAT and Address Restricted Cone NAT by using the NATTYPE module. Change-Id: Ib17f87757b86fdb88bbe25bab7d7193b0530f812 Git-commit: 4d71eea17c1eb4362f9d1ae13fce53815b6c9574 Git-repo: source.codeaurora.org/quic/le/kernel/msm/commit/?h=msm-3.4 Signed-off-by: Paras Singh Jain <parassin@codeaurora.org>
This commit is contained in:
parent
6a91a7d54b
commit
989de097d6
4 changed files with 603 additions and 0 deletions
32
include/uapi/linux/netfilter_ipv4/ipt_NATTYPE.h
Normal file
32
include/uapi/linux/netfilter_ipv4/ipt_NATTYPE.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#ifndef _IPT_NATTYPE_H_target
|
||||
#define _IPT_NATTYPE_H_target
|
||||
|
||||
#define NATTYPE_TIMEOUT 300
|
||||
|
||||
enum nattype_mode {
|
||||
MODE_DNAT,
|
||||
MODE_FORWARD_IN,
|
||||
MODE_FORWARD_OUT
|
||||
};
|
||||
|
||||
enum nattype_type {
|
||||
TYPE_PORT_ADDRESS_RESTRICTED,
|
||||
TYPE_ENDPOINT_INDEPENDENT,
|
||||
TYPE_ADDRESS_RESTRICTED
|
||||
};
|
||||
|
||||
|
||||
struct ipt_nattype_info {
|
||||
__u16 mode;
|
||||
__u16 type;
|
||||
__u32 padding;
|
||||
};
|
||||
|
||||
#endif /*_IPT_NATTYPE_H_target*/
|
||||
|
||||
|
|
@ -230,6 +230,17 @@ config IP_NF_TARGET_MASQUERADE
|
|||
This is a backwards-compat option for the user's convenience
|
||||
(e.g. when running oldconfig). It selects NETFILTER_XT_TARGET_MASQUERADE.
|
||||
|
||||
config IP_NF_TARGET_NATTYPE_MODULE
|
||||
tristate "NATTYPE target support"
|
||||
depends on NF_NAT
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
help
|
||||
NATTYPE is a special case of NAT: used to support FULL Cone NAT
|
||||
and ADDRESS Restricted Cone NAT. All incoming connections are
|
||||
allowed if there is an outgoing connection using that port.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP_NF_TARGET_NETMAP
|
||||
tristate "NETMAP target support"
|
||||
depends on NETFILTER_ADVANCED
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o
|
|||
# targets
|
||||
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_NATTYPE_MODULE) += ipt_NATTYPE.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
|
||||
obj-$(CONFIG_IP_NF_TARGET_SYNPROXY) += ipt_SYNPROXY.o
|
||||
|
||||
|
|
|
|||
559
net/ipv4/netfilter/ipt_NATTYPE.c
Normal file
559
net/ipv4/netfilter/ipt_NATTYPE.c
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/module.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack_core.h>
|
||||
#include <net/netfilter/nf_nat_rule.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv4/ipt_NATTYPE.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#if !defined(NATTYPE_DEBUG)
|
||||
#define DEBUGP(type, args...)
|
||||
#else
|
||||
static const char * const types[] = {"TYPE_PORT_ADDRESS_RESTRICTED",
|
||||
"TYPE_ENDPOINT_INDEPENDENT",
|
||||
"TYPE_ADDRESS_RESTRICTED"};
|
||||
static const char * const modes[] = {"MODE_DNAT", "MODE_FORWARD_IN",
|
||||
"MODE_FORWARD_OUT"};
|
||||
#define DEBUGP(args...) pr_debug(args)
|
||||
#endif
|
||||
|
||||
struct ipt_nattype {
|
||||
struct list_head list;
|
||||
struct timer_list timeout;
|
||||
unsigned short proto; /* Protocol: TCP or UDP */
|
||||
struct nf_nat_ipv4_range range; /* LAN side src info*/
|
||||
unsigned short nat_port; /* Routed NAT port */
|
||||
unsigned int dest_addr; /* Original egress packets dst addr */
|
||||
unsigned short dest_port;/* Original egress packets destination port */
|
||||
};
|
||||
|
||||
static LIST_HEAD(nattype_list);
|
||||
static DEFINE_SPINLOCK(nattype_lock);
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* nattype_nte_debug_print()
|
||||
*/
|
||||
static void nattype_nte_debug_print(const struct ipt_nattype *nte,
|
||||
const char *s)
|
||||
{
|
||||
DEBUGP("%p: %s - proto[%d], src[%pI4:%d], nat[<x>:%d], dest[%pI4:%d]\n",
|
||||
nte, s, nte->proto,
|
||||
&nte->range.min_ip, ntohs(nte->range.min.all),
|
||||
ntohs(nte->nat_port),
|
||||
&nte->dest_addr, ntohs(nte->dest_port));
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE nattype_free()
|
||||
* Free the object.
|
||||
*/
|
||||
static void nattype_free(struct ipt_nattype *nte)
|
||||
{
|
||||
nattype_nte_debug_print(nte, "free");
|
||||
kfree(nte);
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE nattype_refresh_timer()
|
||||
* Refresh the timer for this object.
|
||||
*/
|
||||
static bool nattype_refresh_timer(struct ipt_nattype *nte)
|
||||
{
|
||||
if (del_timer(&nte->timeout)) {
|
||||
nte->timeout.expires = jiffies + NATTYPE_TIMEOUT * HZ;
|
||||
add_timer(&nte->timeout);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE nattype_timer_timeout()
|
||||
* The timer has gone off, self-destruct
|
||||
*/
|
||||
static void nattype_timer_timeout(unsigned long in_nattype)
|
||||
{
|
||||
struct ipt_nattype *nte = (void *)in_nattype;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* The race with list deletion is solved by ensuring
|
||||
* that either this code or the list deletion code
|
||||
* but not both will remove the oject.
|
||||
*/
|
||||
nattype_nte_debug_print(nte, "timeout");
|
||||
spin_lock_bh(&nattype_lock);
|
||||
list_del(&nte->list);
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
nattype_free(nte);
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE nattype_packet_in_match()
|
||||
* Ingress packet, try to match with this nattype entry.
|
||||
*/
|
||||
static bool nattype_packet_in_match(const struct ipt_nattype *nte,
|
||||
struct sk_buff *skb,
|
||||
const struct ipt_nattype_info *info)
|
||||
{
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
u16 dst_port = 0;
|
||||
|
||||
/* If the protocols are not the same, no sense in looking
|
||||
* further.
|
||||
*/
|
||||
if (nte->proto != iph->protocol) {
|
||||
DEBUGP("%s: protocol failed: nte proto:", __func__);
|
||||
DEBUGP(" %d, packet proto: %d\n",
|
||||
nte->proto, iph->protocol);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* In ADDRESS_RESTRICT, the egress destination must match the source
|
||||
* of this ingress packet.
|
||||
*/
|
||||
if (info->type == TYPE_ADDRESS_RESTRICTED) {
|
||||
if (nte->dest_addr != iph->saddr) {
|
||||
DEBUGP("%s: dest/src check", __func__);
|
||||
DEBUGP(" failed: dest_addr: %pI4, src dest: %pI4\n",
|
||||
&nte->dest_addr, &iph->saddr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Obtain the destination port value for TCP or UDP. The nattype
|
||||
* entries are stored in native (not host).
|
||||
*/
|
||||
if (iph->protocol == IPPROTO_TCP) {
|
||||
struct tcphdr _tcph;
|
||||
struct tcphdr *tcph;
|
||||
|
||||
tcph = skb_header_pointer(skb, ip_hdrlen(skb),
|
||||
sizeof(_tcph), &_tcph);
|
||||
if (!tcph)
|
||||
return false;
|
||||
dst_port = tcph->dest;
|
||||
} else if (iph->protocol == IPPROTO_UDP) {
|
||||
struct udphdr _udph;
|
||||
struct udphdr *udph;
|
||||
|
||||
udph = skb_header_pointer(skb, ip_hdrlen(skb),
|
||||
sizeof(_udph), &_udph);
|
||||
if (!udph)
|
||||
return false;
|
||||
dst_port = udph->dest;
|
||||
}
|
||||
|
||||
/* Our NAT port must match the ingress pacekt's
|
||||
* destination packet.
|
||||
*/
|
||||
if (nte->nat_port != dst_port) {
|
||||
DEBUGP("%s fail: ", __func__);
|
||||
DEBUGP(" nat port: %d,dest_port: %d\n",
|
||||
ntohs(nte->nat_port), ntohs(dst_port));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* In either EI or AR mode, the ingress packet's src port
|
||||
* can be anything.
|
||||
*/
|
||||
nattype_nte_debug_print(nte, "INGRESS MATCH");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE nattype_compare
|
||||
* Compare two entries, return true if relevant fields are the same.
|
||||
*/
|
||||
static bool nattype_compare(struct ipt_nattype *n1, struct ipt_nattype *n2)
|
||||
{
|
||||
/* netfilter NATTYPE Protocol
|
||||
* compare.
|
||||
*/
|
||||
if (n1->proto != n2->proto) {
|
||||
DEBUGP("%s: protocol mismatch: %d:%d\n",
|
||||
__func__, n1->proto, n2->proto);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE LAN Source compare.
|
||||
* Since we always keep min/max values the same,
|
||||
* just compare the min values.
|
||||
*/
|
||||
if (n1->range.min_ip != n2->range.min_ip) {
|
||||
DEBUGP("%s: r.min_ip mismatch: %pI4:%pI4\n",
|
||||
__func__, &n1->range.min_ip, &n2->range.min_ip);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n1->range.min.all != n2->range.min.all) {
|
||||
DEBUGP("%s: r.min mismatch: %d:%d\n",
|
||||
__func__,
|
||||
ntohs(n1->range.min.all),
|
||||
ntohs(n2->range.min.all));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* NAT port
|
||||
*/
|
||||
if (n1->nat_port != n2->nat_port) {
|
||||
DEBUGP("%s: nat_port mistmatch: %d:%d\n",
|
||||
__func__, ntohs(n1->nat_port), ntohs(n2->nat_port));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Destination compare
|
||||
*/
|
||||
if (n1->dest_addr != n2->dest_addr) {
|
||||
DEBUGP("%s: dest_addr mismatch: %pI4:%pI4\n",
|
||||
__func__, &n1->dest_addr, &n2->dest_addr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n1->dest_port != n2->dest_port) {
|
||||
DEBUGP("%s: dest_port mismatch: %d:%d\n",
|
||||
__func__, ntohs(n1->dest_port), ntohs(n2->dest_port));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* netfilter NATTYPE nattype_nat()
|
||||
* Ingress packet on PRE_ROUTING hook, find match, update conntrack
|
||||
* to allow
|
||||
**/
|
||||
static unsigned int nattype_nat(struct sk_buff *skb,
|
||||
const struct xt_action_param *par)
|
||||
{
|
||||
struct ipt_nattype *nte;
|
||||
|
||||
if (par->hooknum != NF_INET_PRE_ROUTING)
|
||||
return XT_CONTINUE;
|
||||
spin_lock_bh(&nattype_lock);
|
||||
list_for_each_entry(nte, &nattype_list, list) {
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct nf_nat_ipv4_range newrange;
|
||||
unsigned int ret;
|
||||
|
||||
if (!nattype_packet_in_match(nte, skb, par->targinfo))
|
||||
continue;
|
||||
|
||||
/* Copy the LAN source data into the ingress' pacekts
|
||||
* conntrack in the reply direction.
|
||||
*/
|
||||
newrange = nte->range;
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
|
||||
/* netfilter NATTYPE Find the
|
||||
* ingress packet's conntrack.
|
||||
*/
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (!ct) {
|
||||
DEBUGP("ingress packet conntrack not found\n");
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
/* Expand the ingress conntrack
|
||||
* to include the reply as source
|
||||
*/
|
||||
DEBUGP("Expand ingress conntrack=%p, type=%d, src[%pI4:%d]\n",
|
||||
ct, ctinfo, &newrange.min_ip, ntohs(newrange.min.all));
|
||||
ret = nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
|
||||
DEBUGP("Expand returned: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE nattype_forward()
|
||||
* Ingress and Egress packet forwarding hook
|
||||
*/
|
||||
static unsigned int nattype_forward(struct sk_buff *skb,
|
||||
const struct xt_action_param *par)
|
||||
{
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
void *protoh = (void *)iph + iph->ihl * 4;
|
||||
struct ipt_nattype *nte;
|
||||
struct ipt_nattype *nte2;
|
||||
struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
const struct ipt_nattype_info *info = par->targinfo;
|
||||
u16 nat_port;
|
||||
|
||||
if (par->hooknum != NF_INET_FORWARD)
|
||||
return XT_CONTINUE;
|
||||
|
||||
/* Ingress packet,
|
||||
* refresh the timer if we find an entry.
|
||||
*/
|
||||
if (info->mode == MODE_FORWARD_IN) {
|
||||
spin_lock_bh(&nattype_lock);
|
||||
list_for_each_entry(nte, &nattype_list, list) {
|
||||
/* netfilter NATTYPE
|
||||
* Compare the ingress packet with the existing
|
||||
* entries looking for a match.
|
||||
*/
|
||||
if (!nattype_packet_in_match(nte, skb, info))
|
||||
continue;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Refresh the timer, if we fail, break
|
||||
* out and forward fail as though we never
|
||||
* found the entry.
|
||||
*/
|
||||
if (!nattype_refresh_timer(nte))
|
||||
break;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* The entry is found and refreshed, the
|
||||
* entry values should not change so print
|
||||
* them outside the lock.
|
||||
*/
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
nattype_nte_debug_print(nte, "refresh");
|
||||
DEBUGP("FORWARD_IN_ACCEPT\n");
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
DEBUGP("FORWARD_IN_FAIL\n");
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Egress packet, create a new rule in our list. If conntrack does
|
||||
* not have an entry, skip this packet.
|
||||
*/
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (!ct || (ctinfo == IP_CT_NEW && ctinfo == IP_CT_RELATED))
|
||||
return XT_CONTINUE;
|
||||
|
||||
nat_port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Allocate a new entry
|
||||
*/
|
||||
nte = kzalloc(sizeof(*nte), GFP_ATOMIC | __GFP_NOWARN);
|
||||
if (!nte) {
|
||||
DEBUGP("kernel malloc fail\n");
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&nte->list);
|
||||
|
||||
nte->proto = iph->protocol;
|
||||
nte->nat_port = nat_port;
|
||||
nte->dest_addr = iph->daddr;
|
||||
nte->range.min_ip = iph->saddr;
|
||||
nte->range.max_ip = nte->range.min_ip;
|
||||
|
||||
if (iph->protocol == IPPROTO_TCP) {
|
||||
nte->range.min.tcp.port = ((struct tcphdr *)protoh)->source;
|
||||
nte->range.max.tcp.port = nte->range.min.tcp.port;
|
||||
nte->dest_port = ((struct tcphdr *)protoh)->dest;
|
||||
} else if (iph->protocol == IPPROTO_UDP) {
|
||||
nte->range.min.udp.port = ((struct udphdr *)protoh)->source;
|
||||
nte->range.max.udp.port = nte->range.min.udp.port;
|
||||
nte->dest_port = ((struct udphdr *)protoh)->dest;
|
||||
}
|
||||
nte->range.flags = (NF_NAT_RANGE_MAP_IPS |
|
||||
NF_NAT_RANGE_PROTO_SPECIFIED);
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Initialize the self-destruct timer.
|
||||
*/
|
||||
init_timer(&nte->timeout);
|
||||
nte->timeout.data = (unsigned long)nte;
|
||||
nte->timeout.function = nattype_timer_timeout;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* We have created the new nte; however, it might not be unique.
|
||||
* Search the list for a matching entry. If found, throw away
|
||||
* the new entry and refresh the old. If not found, atomically
|
||||
* insert the new entry on the list.
|
||||
*/
|
||||
spin_lock_bh(&nattype_lock);
|
||||
list_for_each_entry(nte2, &nattype_list, list) {
|
||||
if (!nattype_compare(nte, nte2))
|
||||
continue;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* If we can not refresh this entry, insert our new
|
||||
* entry as this one is timed out and will be removed
|
||||
* from the list shortly.
|
||||
*/
|
||||
if (!nattype_refresh_timer(nte2))
|
||||
break;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Found and refreshed an existing entry. Its values
|
||||
* do not change so print the values outside of the lock.
|
||||
*
|
||||
* Free up the new entry.
|
||||
*/
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
nattype_nte_debug_print(nte2, "refresh");
|
||||
nattype_free(nte);
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Add the new entry to the list.
|
||||
*/
|
||||
nte->timeout.expires = jiffies + (NATTYPE_TIMEOUT * HZ);
|
||||
add_timer(&nte->timeout);
|
||||
list_add(&nte->list, &nattype_list);
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
nattype_nte_debug_print(nte, "ADD");
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* nattype_target()
|
||||
* One of the iptables hooks has a packet for us to analyze, do so.
|
||||
*/
|
||||
static unsigned int nattype_target(struct sk_buff *skb,
|
||||
const struct xt_action_param *par)
|
||||
{
|
||||
const struct ipt_nattype_info *info = par->targinfo;
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* The default behavior for Linux is PORT and ADDRESS restricted. So
|
||||
* we do not need to create rules/entries if we are in that mode.
|
||||
*/
|
||||
if (info->type == TYPE_PORT_ADDRESS_RESTRICTED)
|
||||
return XT_CONTINUE;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Check if we have enough data in the skb.
|
||||
*/
|
||||
if (skb->len < ip_hdrlen(skb))
|
||||
return XT_CONTINUE;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* We can not perform endpoint filtering on anything but UDP and TCP.
|
||||
*/
|
||||
if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)
|
||||
return XT_CONTINUE;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Check for LAND attack and ignore.
|
||||
*/
|
||||
if (iph->daddr == iph->saddr)
|
||||
return XT_CONTINUE;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Check that we have valid source and destination addresses.
|
||||
*/
|
||||
if (iph->daddr == (__be32)0 || iph->saddr == (__be32)0)
|
||||
return XT_CONTINUE;
|
||||
|
||||
DEBUGP("%s: type = %s, mode = %s\n",
|
||||
__func_, types[info->type], modes[info->mode]);
|
||||
|
||||
switch (info->mode) {
|
||||
case MODE_DNAT:
|
||||
return nattype_nat(skb, par);
|
||||
case MODE_FORWARD_OUT:
|
||||
case MODE_FORWARD_IN:
|
||||
return nattype_forward(skb, par);
|
||||
}
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* nattype_check()
|
||||
* check info (mode/type) set by iptables.
|
||||
*/
|
||||
static int nattype_check(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct ipt_nattype_info *info = par->targinfo;
|
||||
struct list_head *cur, *tmp;
|
||||
|
||||
if (info->type != TYPE_PORT_ADDRESS_RESTRICTED &&
|
||||
info->type != TYPE_ENDPOINT_INDEPENDENT &&
|
||||
info->type != TYPE_ADDRESS_RESTRICTED) {
|
||||
DEBUGP("%s: unknown type: %d\n", __func__, info->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info->mode != MODE_DNAT && info->mode != MODE_FORWARD_IN &&
|
||||
info->mode != MODE_FORWARD_OUT) {
|
||||
DEBUGP("%s: unknown mode - %d.\n", __func__, info->mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DEBUGP("%s: type = %s, mode = %s\n",
|
||||
__func__, types[info->type], modes[info->mode]);
|
||||
|
||||
if (par->hook_mask & ~((1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_FORWARD))) {
|
||||
DEBUGP("%s: bad hooks %x.\n", __func__, par->hook_mask);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* Remove all entries from the nattype list.
|
||||
*/
|
||||
drain:
|
||||
spin_lock_bh(&nattype_lock);
|
||||
list_for_each_safe(cur, tmp, &nattype_list) {
|
||||
struct ipt_nattype *nte = (void *)cur;
|
||||
|
||||
/* netfilter NATTYPE
|
||||
* If the timeout is in process, it will tear
|
||||
* us down. Since it is waiting on the spinlock
|
||||
* we have to give up the spinlock to give the
|
||||
* timeout on another CPU a chance to run.
|
||||
*/
|
||||
if (!del_timer(&nte->timeout)) {
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
goto drain;
|
||||
}
|
||||
|
||||
DEBUGP("%p: removing from list\n", nte);
|
||||
list_del(&nte->list);
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
nattype_free(nte);
|
||||
goto drain;
|
||||
}
|
||||
spin_unlock_bh(&nattype_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct xt_target nattype = {
|
||||
.name = "NATTYPE",
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = nattype_target,
|
||||
.checkentry = nattype_check,
|
||||
.targetsize = sizeof(struct ipt_nattype_info),
|
||||
.hooks = ((1 << NF_INET_PRE_ROUTING) |
|
||||
(1 << NF_INET_FORWARD)),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
return xt_register_target(&nattype);
|
||||
}
|
||||
|
||||
static void __exit fini(void)
|
||||
{
|
||||
xt_unregister_target(&nattype);
|
||||
}
|
||||
|
||||
module_init(init);
|
||||
module_exit(fini);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Loading…
Reference in a new issue