mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-07 13:15:12 +02:00
Merge branch 'RAWNAT'
This commit is contained in:
@@ -6,6 +6,8 @@
|
|||||||
- fuzzy: fix bogus comparison logic leftover from move to new 1.4.3 API
|
- fuzzy: fix bogus comparison logic leftover from move to new 1.4.3 API
|
||||||
- ipp2p: fix bogus varargs call
|
- ipp2p: fix bogus varargs call
|
||||||
- ipp2p: fix typo in error message
|
- ipp2p: fix typo in error message
|
||||||
|
- added rawpost table (for use with RAWNAT)
|
||||||
|
- added RAWSNAT/RAWDNAT targets
|
||||||
|
|
||||||
|
|
||||||
Xtables-addons 1.14 (March 31 2009)
|
Xtables-addons 1.14 (March 31 2009)
|
||||||
|
@@ -11,6 +11,7 @@ obj-${build_DHCPMAC} += xt_DHCPMAC.o
|
|||||||
obj-${build_ECHO} += xt_ECHO.o
|
obj-${build_ECHO} += xt_ECHO.o
|
||||||
obj-${build_IPMARK} += xt_IPMARK.o
|
obj-${build_IPMARK} += xt_IPMARK.o
|
||||||
obj-${build_LOGMARK} += xt_LOGMARK.o
|
obj-${build_LOGMARK} += xt_LOGMARK.o
|
||||||
|
obj-${build_RAWNAT} += xt_RAWNAT.o iptable_rawpost.o ip6table_rawpost.o
|
||||||
obj-${build_SYSRQ} += xt_SYSRQ.o
|
obj-${build_SYSRQ} += xt_SYSRQ.o
|
||||||
obj-${build_STEAL} += xt_STEAL.o
|
obj-${build_STEAL} += xt_STEAL.o
|
||||||
obj-${build_TARPIT} += xt_TARPIT.o
|
obj-${build_TARPIT} += xt_TARPIT.o
|
||||||
|
@@ -4,6 +4,7 @@ obj-${build_DHCPMAC} += libxt_DHCPMAC.so libxt_dhcpmac.so
|
|||||||
obj-${build_ECHO} += libxt_ECHO.so
|
obj-${build_ECHO} += libxt_ECHO.so
|
||||||
obj-${build_IPMARK} += libxt_IPMARK.so
|
obj-${build_IPMARK} += libxt_IPMARK.so
|
||||||
obj-${build_LOGMARK} += libxt_LOGMARK.so
|
obj-${build_LOGMARK} += libxt_LOGMARK.so
|
||||||
|
obj-${build_RAWNAT} += libxt_RAWDNAT.so libxt_RAWSNAT.so
|
||||||
obj-${build_STEAL} += libxt_STEAL.so
|
obj-${build_STEAL} += libxt_STEAL.so
|
||||||
obj-${build_SYSRQ} += libxt_SYSRQ.so
|
obj-${build_SYSRQ} += libxt_SYSRQ.so
|
||||||
obj-${build_TARPIT} += libxt_TARPIT.so
|
obj-${build_TARPIT} += libxt_TARPIT.so
|
||||||
|
87
extensions/compat_rawpost.h
Normal file
87
extensions/compat_rawpost.h
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#ifndef XTA_COMPAT_RAWPOST_H
|
||||||
|
#define XTA_COMPAT_RAWPOST_H 1
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
|
||||||
|
typedef struct sk_buff sk_buff_t;
|
||||||
|
#else
|
||||||
|
typedef struct sk_buff *sk_buff_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 21)
|
||||||
|
#define XT_TARGET_INIT(__name, __size) \
|
||||||
|
{ \
|
||||||
|
.target.u.user = { \
|
||||||
|
.target_size = XT_ALIGN(__size), \
|
||||||
|
.name = __name, \
|
||||||
|
}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IPT_ENTRY_INIT(__size) \
|
||||||
|
{ \
|
||||||
|
.target_offset = sizeof(struct ipt_entry), \
|
||||||
|
.next_offset = (__size), \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IPT_STANDARD_INIT(__verdict) \
|
||||||
|
{ \
|
||||||
|
.entry = IPT_ENTRY_INIT(sizeof(struct ipt_standard)), \
|
||||||
|
.target = XT_TARGET_INIT(IPT_STANDARD_TARGET, \
|
||||||
|
sizeof(struct xt_standard_target)), \
|
||||||
|
.target.verdict = -(__verdict) - 1, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IPT_ERROR_INIT \
|
||||||
|
{ \
|
||||||
|
.entry = IPT_ENTRY_INIT(sizeof(struct ipt_error)), \
|
||||||
|
.target = XT_TARGET_INIT(IPT_ERROR_TARGET, \
|
||||||
|
sizeof(struct ipt_error_target)), \
|
||||||
|
.target.errorname = "ERROR", \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IP6T_ENTRY_INIT(__size) \
|
||||||
|
{ \
|
||||||
|
.target_offset = sizeof(struct ip6t_entry), \
|
||||||
|
.next_offset = (__size), \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IP6T_STANDARD_INIT(__verdict) \
|
||||||
|
{ \
|
||||||
|
.entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)), \
|
||||||
|
.target = XT_TARGET_INIT(IP6T_STANDARD_TARGET, \
|
||||||
|
sizeof(struct ip6t_standard_target)), \
|
||||||
|
.target.verdict = -(__verdict) - 1, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IP6T_ERROR_INIT \
|
||||||
|
{ \
|
||||||
|
.entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)), \
|
||||||
|
.target = XT_TARGET_INIT(IP6T_ERROR_TARGET, \
|
||||||
|
sizeof(struct ip6t_error_target)), \
|
||||||
|
.target.errorname = "ERROR", \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* 2.6.21 */
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 20)
|
||||||
|
# include <linux/netfilter_ipv6/ip6_tables.h>
|
||||||
|
/* Standard entry */
|
||||||
|
struct ip6t_standard
|
||||||
|
{
|
||||||
|
struct ip6t_entry entry;
|
||||||
|
struct ip6t_standard_target target;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip6t_error_target
|
||||||
|
{
|
||||||
|
struct ip6t_entry_target target;
|
||||||
|
char errorname[IP6T_FUNCTION_MAXNAMELEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip6t_error
|
||||||
|
{
|
||||||
|
struct ip6t_entry entry;
|
||||||
|
struct ip6t_error_target target;
|
||||||
|
};
|
||||||
|
#endif /* 2.6.20 */
|
||||||
|
|
||||||
|
#endif /* XTA_COMPAT_RAWPOST_H */
|
@@ -447,6 +447,24 @@ int xtnu_ip_route_output_key(void *net, struct rtable **rp, struct flowi *flp)
|
|||||||
return ip_route_output_flow(rp, flp, NULL, 0);
|
return ip_route_output_flow(rp, flp, NULL, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xtnu_ip_route_output_key);
|
EXPORT_SYMBOL_GPL(xtnu_ip_route_output_key);
|
||||||
|
|
||||||
|
void xtnu_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
|
||||||
|
__be32 from, __be32 to, bool pseudohdr)
|
||||||
|
{
|
||||||
|
__be32 diff[] = {~from, to};
|
||||||
|
|
||||||
|
if (skb->ip_summed != CHECKSUM_PARTIAL) {
|
||||||
|
*sum = csum_fold(csum_partial(diff, sizeof(diff),
|
||||||
|
~csum_unfold(*sum)));
|
||||||
|
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
|
||||||
|
skb->csum = ~csum_partial(diff, sizeof(diff),
|
||||||
|
~skb->csum);
|
||||||
|
} else if (pseudohdr) {
|
||||||
|
*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
|
||||||
|
csum_unfold(*sum)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(xtnu_proto_csum_replace4);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
||||||
@@ -468,7 +486,7 @@ static inline __wsum xtnu_csum_unfold(__sum16 n)
|
|||||||
return (__force __wsum)n;
|
return (__force __wsum)n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void xtnu_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
|
void xtnu_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
|
||||||
{
|
{
|
||||||
__be32 diff[] = {~from, to};
|
__be32 diff[] = {~from, to};
|
||||||
*sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
|
*sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
|
||||||
|
@@ -69,8 +69,11 @@
|
|||||||
|
|
||||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
||||||
# define csum_replace2 xtnu_csum_replace2
|
# define csum_replace2 xtnu_csum_replace2
|
||||||
|
# define csum_replace4 xtnu_csum_replace4
|
||||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
|
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
|
||||||
# define csum_replace2 nf_csum_replace2
|
# define csum_replace2 nf_csum_replace2
|
||||||
|
# define csum_replace4 nf_csum_replace4
|
||||||
|
# define inet_proto_csum_replace4 xtnu_proto_csum_replace4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(NIP6) && !defined(NIP6_FMT)
|
#if !defined(NIP6) && !defined(NIP6_FMT)
|
||||||
|
@@ -138,6 +138,9 @@ extern struct xt_match *xtnu_request_find_match(unsigned int,
|
|||||||
const char *, uint8_t);
|
const char *, uint8_t);
|
||||||
extern int xtnu_neigh_hh_output(struct hh_cache *, struct sk_buff *);
|
extern int xtnu_neigh_hh_output(struct hh_cache *, struct sk_buff *);
|
||||||
extern void xtnu_csum_replace2(__u16 __bitwise *, __be16, __be16);
|
extern void xtnu_csum_replace2(__u16 __bitwise *, __be16, __be16);
|
||||||
|
extern void xtnu_csum_replace4(__u16 __bitwise *, __be32, __be32);
|
||||||
|
extern void xtnu_proto_csum_replace4(__u16 __bitwise *, struct sk_buff *,
|
||||||
|
__be32, __be32, bool);
|
||||||
extern int xtnu_skb_linearize(struct sk_buff *);
|
extern int xtnu_skb_linearize(struct sk_buff *);
|
||||||
|
|
||||||
#endif /* _COMPAT_XTNU_H */
|
#endif /* _COMPAT_XTNU_H */
|
||||||
|
105
extensions/ip6table_rawpost.c
Normal file
105
extensions/ip6table_rawpost.c
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* rawpost table for ip6_tables
|
||||||
|
* written by Jan Engelhardt <jengelh [at] medozas de>, 2008 - 2009
|
||||||
|
* placed in the Public Domain
|
||||||
|
*/
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||||
|
#include <net/ip.h>
|
||||||
|
#include "compat_xtables.h"
|
||||||
|
#include "compat_rawpost.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RAWPOST_VALID_HOOKS = 1 << NF_INET_POST_ROUTING,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct ip6t_replace repl;
|
||||||
|
struct ip6t_standard entries[1];
|
||||||
|
struct ip6t_error term;
|
||||||
|
} rawpost6_initial __initdata = {
|
||||||
|
.repl = {
|
||||||
|
.name = "rawpost",
|
||||||
|
.valid_hooks = RAWPOST_VALID_HOOKS,
|
||||||
|
.num_entries = 2,
|
||||||
|
.size = sizeof(struct ip6t_standard) +
|
||||||
|
sizeof(struct ip6t_error),
|
||||||
|
.hook_entry = {
|
||||||
|
[NF_INET_POST_ROUTING] = 0,
|
||||||
|
},
|
||||||
|
.underflow = {
|
||||||
|
[NF_INET_POST_ROUTING] = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.entries = {
|
||||||
|
IP6T_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
|
||||||
|
},
|
||||||
|
.term = IP6T_ERROR_INIT, /* ERROR */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct xt_table *rawpost6_ptable;
|
||||||
|
|
||||||
|
static struct xt_table rawpost6_itable = {
|
||||||
|
.name = "rawpost",
|
||||||
|
.af = NFPROTO_IPV6,
|
||||||
|
.valid_hooks = RAWPOST_VALID_HOOKS,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int rawpost6_hook_fn(unsigned int hook, sk_buff_t *skb,
|
||||||
|
const struct net_device *in, const struct net_device *out,
|
||||||
|
int (*okfn)(struct sk_buff *))
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
|
||||||
|
return ip6t_do_table(skb, hook, in, out, rawpost6_ptable);
|
||||||
|
#else
|
||||||
|
return ip6t_do_table(skb, hook, in, out, rawpost6_ptable, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nf_hook_ops rawpost6_hook_ops __read_mostly = {
|
||||||
|
.hook = rawpost6_hook_fn,
|
||||||
|
.pf = NFPROTO_IPV6,
|
||||||
|
.hooknum = NF_INET_POST_ROUTING,
|
||||||
|
.priority = NF_IP6_PRI_LAST,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rawpost6_table_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rwlock_init(&rawpost6_itable.lock);
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
|
||||||
|
rawpost6_ptable = ip6t_register_table(&init_net, &rawpost6_itable,
|
||||||
|
&rawpost6_initial.repl);
|
||||||
|
if (IS_ERR(rawpost6_ptable))
|
||||||
|
return PTR_ERR(rawpost6_ptable);
|
||||||
|
#else
|
||||||
|
ret = ip6t_register_table(&rawpost6_itable, &rawpost6_initial.repl);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
rawpost6_ptable = &rawpost6_itable;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret = nf_register_hook(&rawpost6_hook_ops);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
out:
|
||||||
|
ip6t_unregister_table(rawpost6_ptable);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit rawpost6_table_exit(void)
|
||||||
|
{
|
||||||
|
nf_unregister_hook(&rawpost6_hook_ops);
|
||||||
|
ip6t_unregister_table(rawpost6_ptable);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(rawpost6_table_init);
|
||||||
|
module_exit(rawpost6_table_exit);
|
||||||
|
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
|
||||||
|
MODULE_LICENSE("GPL");
|
107
extensions/iptable_rawpost.c
Normal file
107
extensions/iptable_rawpost.c
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* rawpost table for ip_tables
|
||||||
|
* written by Jan Engelhardt <jengelh [at] medozas de>, 2008 - 2009
|
||||||
|
* placed in the Public Domain
|
||||||
|
*/
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <net/ip.h>
|
||||||
|
#include "compat_xtables.h"
|
||||||
|
#include "compat_rawpost.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RAWPOST_VALID_HOOKS = 1 << NF_INET_POST_ROUTING,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct ipt_replace repl;
|
||||||
|
struct ipt_standard entries[1];
|
||||||
|
struct ipt_error term;
|
||||||
|
} rawpost4_initial __initdata = {
|
||||||
|
.repl = {
|
||||||
|
.name = "rawpost",
|
||||||
|
.valid_hooks = RAWPOST_VALID_HOOKS,
|
||||||
|
.num_entries = 2,
|
||||||
|
.size = sizeof(struct ipt_standard) +
|
||||||
|
sizeof(struct ipt_error),
|
||||||
|
.hook_entry = {
|
||||||
|
[NF_INET_POST_ROUTING] = 0,
|
||||||
|
},
|
||||||
|
.underflow = {
|
||||||
|
[NF_INET_POST_ROUTING] = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.entries = {
|
||||||
|
IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
|
||||||
|
},
|
||||||
|
.term = IPT_ERROR_INIT, /* ERROR */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct xt_table *rawpost4_ptable;
|
||||||
|
|
||||||
|
static struct xt_table rawpost4_itable = {
|
||||||
|
.name = "rawpost",
|
||||||
|
.af = NFPROTO_IPV4,
|
||||||
|
.valid_hooks = RAWPOST_VALID_HOOKS,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int rawpost4_hook_fn(unsigned int hook, sk_buff_t *skb,
|
||||||
|
const struct net_device *in, const struct net_device *out,
|
||||||
|
int (*okfn)(struct sk_buff *))
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
|
||||||
|
return ipt_do_table(skb, hook, in, out, rawpost4_ptable);
|
||||||
|
#else
|
||||||
|
return ipt_do_table(skb, hook, in, out, rawpost4_ptable, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct nf_hook_ops rawpost4_hook_ops __read_mostly = {
|
||||||
|
.hook = rawpost4_hook_fn,
|
||||||
|
.pf = NFPROTO_IPV4,
|
||||||
|
.hooknum = NF_INET_POST_ROUTING,
|
||||||
|
.priority = NF_IP_PRI_LAST,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rawpost4_table_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
rwlock_init(&rawpost4_itable.lock);
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
|
||||||
|
rawpost4_ptable = ipt_register_table(&init_net, &rawpost4_itable,
|
||||||
|
&rawpost4_initial.repl);
|
||||||
|
if (IS_ERR(rawpost4_ptable))
|
||||||
|
return PTR_ERR(rawpost4_ptable);
|
||||||
|
#else
|
||||||
|
ret = ipt_register_table(&rawpost4_itable, &rawpost4_initial.repl);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
rawpost4_ptable = &rawpost4_itable;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ret = nf_register_hook(&rawpost4_hook_ops);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
out:
|
||||||
|
ipt_unregister_table(rawpost4_ptable);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit rawpost4_table_exit(void)
|
||||||
|
{
|
||||||
|
nf_unregister_hook(&rawpost4_hook_ops);
|
||||||
|
ipt_unregister_table(rawpost4_ptable);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(rawpost4_table_init);
|
||||||
|
module_exit(rawpost4_table_exit);
|
||||||
|
MODULE_DESCRIPTION("Xtables: rawpost table for use with RAWNAT");
|
||||||
|
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
|
||||||
|
MODULE_LICENSE("GPL");
|
187
extensions/libxt_RAWDNAT.c
Normal file
187
extensions/libxt_RAWDNAT.c
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* "RAWNAT" target extension for iptables
|
||||||
|
* Copyright © Jan Engelhardt, 2008 - 2009
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License; either
|
||||||
|
* version 2 of the License, or any later version, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*/
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <xtables.h>
|
||||||
|
#include <linux/netfilter.h>
|
||||||
|
#include "xt_RAWNAT.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FLAGS_TO = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct option rawdnat_tg_opts[] = {
|
||||||
|
{.name = "to-destination", .has_arg = true, .val = 't'},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rawdnat_tg_help(void)
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"RAWDNAT target options:\n"
|
||||||
|
" --to-destination addr[/mask] Address or network to map to\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rawdnat_tg4_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||||
|
const void *entry, struct xt_entry_target **target)
|
||||||
|
{
|
||||||
|
struct xt_rawnat_tginfo *info = (void *)(*target)->data;
|
||||||
|
struct in_addr *a;
|
||||||
|
unsigned int mask;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 't':
|
||||||
|
info->mask = 32;
|
||||||
|
end = strchr(optarg, '/');
|
||||||
|
if (end != NULL) {
|
||||||
|
*end++ = '\0';
|
||||||
|
if (!xtables_strtoui(end, NULL, &mask, 0, 32))
|
||||||
|
xtables_param_act(XTF_BAD_VALUE, "RAWDNAT",
|
||||||
|
"--to-destination", optarg);
|
||||||
|
info->mask = mask;
|
||||||
|
}
|
||||||
|
a = xtables_numeric_to_ipaddr(optarg);
|
||||||
|
if (a == NULL)
|
||||||
|
xtables_param_act(XTF_BAD_VALUE, "RAWDNAT",
|
||||||
|
"--to-destination", optarg);
|
||||||
|
memcpy(&info->addr.in, a, sizeof(*a));
|
||||||
|
*flags |= FLAGS_TO;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rawdnat_tg6_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||||
|
const void *entry, struct xt_entry_target **target)
|
||||||
|
{
|
||||||
|
struct xt_rawnat_tginfo *info = (void *)(*target)->data;
|
||||||
|
struct in6_addr *a;
|
||||||
|
unsigned int mask;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 't':
|
||||||
|
info->mask = 128;
|
||||||
|
end = strchr(optarg, '/');
|
||||||
|
if (end != NULL) {
|
||||||
|
*end++ = '\0';
|
||||||
|
if (!xtables_strtoui(end, NULL, &mask, 0, 32))
|
||||||
|
xtables_param_act(XTF_BAD_VALUE, "RAWDNAT",
|
||||||
|
"--to-destination", optarg);
|
||||||
|
info->mask = mask;
|
||||||
|
}
|
||||||
|
a = xtables_numeric_to_ip6addr(optarg);
|
||||||
|
if (a == NULL)
|
||||||
|
xtables_param_act(XTF_BAD_VALUE, "RAWDNAT",
|
||||||
|
"--to-destination", optarg);
|
||||||
|
memcpy(&info->addr.in6, a, sizeof(*a));
|
||||||
|
*flags |= FLAGS_TO;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rawdnat_tg_check(unsigned int flags)
|
||||||
|
{
|
||||||
|
if (!(flags & FLAGS_TO))
|
||||||
|
xtables_error(PARAMETER_PROBLEM, "RAWDNAT: "
|
||||||
|
"\"--to-destination\" is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rawdnat_tg4_print(const void *entry, const struct xt_entry_target *target,
|
||||||
|
int numeric)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
|
if (!numeric && info->mask == 32)
|
||||||
|
printf("to-destination %s ",
|
||||||
|
xtables_ipaddr_to_anyname(&info->addr.in));
|
||||||
|
else
|
||||||
|
printf("to-destination %s/%u ",
|
||||||
|
xtables_ipaddr_to_numeric(&info->addr.in), info->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rawdnat_tg6_print(const void *entry, const struct xt_entry_target *target,
|
||||||
|
int numeric)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
|
if (!numeric && info->mask == 128)
|
||||||
|
printf("to-destination %s ",
|
||||||
|
xtables_ip6addr_to_anyname(&info->addr.in6));
|
||||||
|
else
|
||||||
|
printf("to-destination %s/%u ",
|
||||||
|
xtables_ip6addr_to_numeric(&info->addr.in6), info->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rawdnat_tg4_save(const void *entry, const struct xt_entry_target *target)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
|
printf("--to-destination %s/%u ",
|
||||||
|
xtables_ipaddr_to_numeric(&info->addr.in),
|
||||||
|
info->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rawdnat_tg6_save(const void *entry, const struct xt_entry_target *target)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
|
printf("--to-destination %s/%u ",
|
||||||
|
xtables_ip6addr_to_numeric(&info->addr.in6),
|
||||||
|
info->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct xtables_target rawdnat_tg4_reg = {
|
||||||
|
.version = XTABLES_VERSION,
|
||||||
|
.name = "RAWDNAT",
|
||||||
|
.revision = 0,
|
||||||
|
.family = PF_INET,
|
||||||
|
.size = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
|
||||||
|
.userspacesize = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
|
||||||
|
.help = rawdnat_tg_help,
|
||||||
|
.parse = rawdnat_tg4_parse,
|
||||||
|
.final_check = rawdnat_tg_check,
|
||||||
|
.print = rawdnat_tg4_print,
|
||||||
|
.save = rawdnat_tg4_save,
|
||||||
|
.extra_opts = rawdnat_tg_opts,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct xtables_target rawdnat_tg6_reg = {
|
||||||
|
.version = XTABLES_VERSION,
|
||||||
|
.name = "RAWDNAT",
|
||||||
|
.revision = 0,
|
||||||
|
.family = PF_INET6,
|
||||||
|
.size = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
|
||||||
|
.userspacesize = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
|
||||||
|
.help = rawdnat_tg_help,
|
||||||
|
.parse = rawdnat_tg6_parse,
|
||||||
|
.final_check = rawdnat_tg_check,
|
||||||
|
.print = rawdnat_tg6_print,
|
||||||
|
.save = rawdnat_tg6_save,
|
||||||
|
.extra_opts = rawdnat_tg_opts,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _init(void)
|
||||||
|
{
|
||||||
|
xtables_register_target(&rawdnat_tg4_reg);
|
||||||
|
xtables_register_target(&rawdnat_tg6_reg);
|
||||||
|
}
|
10
extensions/libxt_RAWDNAT.man
Normal file
10
extensions/libxt_RAWDNAT.man
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
The \fBRAWDNAT\fR target will rewrite the destination address in the IP header,
|
||||||
|
much like the \fBNETMAP\fR target.
|
||||||
|
.TP
|
||||||
|
\fB--to-destination\fR \fIaddr\fR[\fB/\fR\fImask\fR]
|
||||||
|
Network address to map to. The resulting address will be constructed the
|
||||||
|
following way: All 'one' bits in the \fImask\fR are filled in from the new
|
||||||
|
\fIaddress\fR. All bits that are zero in the mask are filled in from the
|
||||||
|
original address.
|
||||||
|
.PP
|
||||||
|
See the \fBRAWSNAT\fR help entry for examples and constraints.
|
187
extensions/libxt_RAWSNAT.c
Normal file
187
extensions/libxt_RAWSNAT.c
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* "RAWNAT" target extension for iptables
|
||||||
|
* Copyright © Jan Engelhardt, 2008 - 2009
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License; either
|
||||||
|
* version 2 of the License, or any later version, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*/
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <xtables.h>
|
||||||
|
#include <linux/netfilter.h>
|
||||||
|
#include "xt_RAWNAT.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FLAGS_TO = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct option rawsnat_tg_opts[] = {
|
||||||
|
{.name = "to-source", .has_arg = true, .val = 't'},
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rawsnat_tg_help(void)
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"RAWSNAT target options:\n"
|
||||||
|
" --to-source addr[/mask] Address or network to map to\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rawsnat_tg4_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||||
|
const void *entry, struct xt_entry_target **target)
|
||||||
|
{
|
||||||
|
struct xt_rawnat_tginfo *info = (void *)(*target)->data;
|
||||||
|
struct in_addr *a;
|
||||||
|
unsigned int mask;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 't':
|
||||||
|
info->mask = 32;
|
||||||
|
end = strchr(optarg, '/');
|
||||||
|
if (end != NULL) {
|
||||||
|
*end++ = '\0';
|
||||||
|
if (!xtables_strtoui(end, NULL, &mask, 0, 32))
|
||||||
|
xtables_param_act(XTF_BAD_VALUE, "RAWSNAT",
|
||||||
|
"--to-source", optarg);
|
||||||
|
info->mask = mask;
|
||||||
|
}
|
||||||
|
a = xtables_numeric_to_ipaddr(optarg);
|
||||||
|
if (a == NULL)
|
||||||
|
xtables_param_act(XTF_BAD_VALUE, "RAWSNAT",
|
||||||
|
"--to-source", optarg);
|
||||||
|
memcpy(&info->addr.in, a, sizeof(*a));
|
||||||
|
*flags |= FLAGS_TO;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
rawsnat_tg6_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||||
|
const void *entry, struct xt_entry_target **target)
|
||||||
|
{
|
||||||
|
struct xt_rawnat_tginfo *info = (void *)(*target)->data;
|
||||||
|
struct in6_addr *a;
|
||||||
|
unsigned int mask;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 't':
|
||||||
|
info->mask = 128;
|
||||||
|
end = strchr(optarg, '/');
|
||||||
|
if (end != NULL) {
|
||||||
|
*end++ = '\0';
|
||||||
|
if (!xtables_strtoui(end, NULL, &mask, 0, 32))
|
||||||
|
xtables_param_act(XTF_BAD_VALUE, "RAWSNAT",
|
||||||
|
"--to-source", optarg);
|
||||||
|
info->mask = mask;
|
||||||
|
}
|
||||||
|
a = xtables_numeric_to_ip6addr(optarg);
|
||||||
|
if (a == NULL)
|
||||||
|
xtables_param_act(XTF_BAD_VALUE, "RAWSNAT",
|
||||||
|
"--to-source", optarg);
|
||||||
|
memcpy(&info->addr.in6, a, sizeof(*a));
|
||||||
|
*flags |= FLAGS_TO;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rawsnat_tg_check(unsigned int flags)
|
||||||
|
{
|
||||||
|
if (!(flags & FLAGS_TO))
|
||||||
|
xtables_error(PARAMETER_PROBLEM, "RAWSNAT: "
|
||||||
|
"\"--to-source\" is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rawsnat_tg4_print(const void *entry, const struct xt_entry_target *target,
|
||||||
|
int numeric)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
|
if (!numeric && info->mask == 32)
|
||||||
|
printf("to-source %s ",
|
||||||
|
xtables_ipaddr_to_anyname(&info->addr.in));
|
||||||
|
else
|
||||||
|
printf("to-source %s/%u ",
|
||||||
|
xtables_ipaddr_to_numeric(&info->addr.in), info->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rawsnat_tg6_print(const void *entry, const struct xt_entry_target *target,
|
||||||
|
int numeric)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
|
if (!numeric && info->mask == 128)
|
||||||
|
printf("to-source %s ",
|
||||||
|
xtables_ip6addr_to_anyname(&info->addr.in6));
|
||||||
|
else
|
||||||
|
printf("to-source %s/%u ",
|
||||||
|
xtables_ip6addr_to_numeric(&info->addr.in6), info->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rawsnat_tg4_save(const void *entry, const struct xt_entry_target *target)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
|
printf("--to-source %s/%u ",
|
||||||
|
xtables_ipaddr_to_numeric(&info->addr.in),
|
||||||
|
info->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rawsnat_tg6_save(const void *entry, const struct xt_entry_target *target)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
|
printf("--to-source %s/%u ",
|
||||||
|
xtables_ip6addr_to_numeric(&info->addr.in6),
|
||||||
|
info->mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct xtables_target rawsnat_tg4_reg = {
|
||||||
|
.version = XTABLES_VERSION,
|
||||||
|
.name = "RAWSNAT",
|
||||||
|
.revision = 0,
|
||||||
|
.family = PF_INET,
|
||||||
|
.size = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
|
||||||
|
.userspacesize = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
|
||||||
|
.help = rawsnat_tg_help,
|
||||||
|
.parse = rawsnat_tg4_parse,
|
||||||
|
.final_check = rawsnat_tg_check,
|
||||||
|
.print = rawsnat_tg4_print,
|
||||||
|
.save = rawsnat_tg4_save,
|
||||||
|
.extra_opts = rawsnat_tg_opts,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct xtables_target rawsnat_tg6_reg = {
|
||||||
|
.version = XTABLES_VERSION,
|
||||||
|
.name = "RAWSNAT",
|
||||||
|
.revision = 0,
|
||||||
|
.family = PF_INET6,
|
||||||
|
.size = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
|
||||||
|
.userspacesize = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
|
||||||
|
.help = rawsnat_tg_help,
|
||||||
|
.parse = rawsnat_tg6_parse,
|
||||||
|
.final_check = rawsnat_tg_check,
|
||||||
|
.print = rawsnat_tg6_print,
|
||||||
|
.save = rawsnat_tg6_save,
|
||||||
|
.extra_opts = rawsnat_tg_opts,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _init(void)
|
||||||
|
{
|
||||||
|
xtables_register_target(&rawsnat_tg4_reg);
|
||||||
|
xtables_register_target(&rawsnat_tg6_reg);
|
||||||
|
}
|
38
extensions/libxt_RAWSNAT.man
Normal file
38
extensions/libxt_RAWSNAT.man
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
The \fBRAWSNAT\fR and \fBRAWDNAT\fP targets provide stateless network address
|
||||||
|
translation.
|
||||||
|
.PP
|
||||||
|
The \fBRAWSNAT\fR target will rewrite the source address in the IP header, much
|
||||||
|
like the \fBNETMAP\fP target. \fBRAWSNAT\fP (and \fBRAWDNAT\fP) may only be
|
||||||
|
used in the \fBraw\fP or \fBrawpost\fP tables, but can be used in all chains,
|
||||||
|
which makes it possible to change the source address either when the packet
|
||||||
|
enters the machine or when it leaves it. The reason for this table constraint
|
||||||
|
is that RAWNAT must happen outside of connection tracking.
|
||||||
|
.TP
|
||||||
|
\fB--to-source\fR \fIaddr\fR[\fB/\fR\fImask\fR]
|
||||||
|
Network address to map to. The resulting address will be constructed the
|
||||||
|
following way: All 'one' bits in the \fImask\fR are filled in from the new
|
||||||
|
\fIaddress\fR. All bits that are zero in the mask are filled in from the
|
||||||
|
original address.
|
||||||
|
.PP
|
||||||
|
As an example, changing the destination for packets forwarded from an internal
|
||||||
|
LAN to the internet:
|
||||||
|
.IP
|
||||||
|
-t raw -A PREROUTING -i lan0 -d 212.201.100.135 -j RAWDNAT --to-destination 199.181.132.250
|
||||||
|
-t rawpost -A POSTROUTING -o lan0 -s 199.181.132.250 -j RAWSNAT --to-source 212.201.100.135
|
||||||
|
.PP
|
||||||
|
Note that changing addresses may influence the route selection! Specifically,
|
||||||
|
it statically NATs packets, not connections, like the normal DNAT/SNAT targets
|
||||||
|
would do. Also note that it can transform already-NATed connections -- as said,
|
||||||
|
it is completely external to Netfilter's connection tracking/NAT.
|
||||||
|
.PP
|
||||||
|
If the machine itself generates packets that are to be rawnat'ed, you need a
|
||||||
|
rule in the OUTPUT chain instead, just like you would with the stateful NAT
|
||||||
|
targets.
|
||||||
|
.PP
|
||||||
|
It may be necessary that in doing so, you also need an extra RAWSNAT rule, to
|
||||||
|
override the automatic source address selection that the routing code does
|
||||||
|
before passing packets to iptables. If the connecting socket has not been
|
||||||
|
explicitly bound to an address, as is the common mode of operation, the address
|
||||||
|
that will be chosen is the primary address of the device through which the
|
||||||
|
packet would be routed with its initial destination address - the address as
|
||||||
|
seen before any RAWNAT takes place.
|
8
extensions/xt_RAWNAT.Kconfig
Normal file
8
extensions/xt_RAWNAT.Kconfig
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
config NETFILTER_XT_TARGET_RAWNAT
|
||||||
|
tristate '"RAWNAT" raw address translation w/o conntrack'
|
||||||
|
depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
|
||||||
|
depends on IP_NF_RAW || IP_NF6_RAW
|
||||||
|
---help---
|
||||||
|
This option adds the RAWSNAT and RAWDNAT targets which can do Network
|
||||||
|
Address Translation (no port translation) without requiring Netfilter
|
||||||
|
connection tracking.
|
336
extensions/xt_RAWNAT.c
Normal file
336
extensions/xt_RAWNAT.c
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
/*
|
||||||
|
* "RAWNAT" target extension for Xtables - untracked NAT
|
||||||
|
* Copyright © Jan Engelhardt, 2008 - 2009
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License; either
|
||||||
|
* version 2 of the License, or any later version, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*/
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/ipv6.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/tcp.h>
|
||||||
|
#include <linux/udp.h>
|
||||||
|
#include <linux/netfilter.h>
|
||||||
|
#include <linux/netfilter/nf_conntrack_common.h>
|
||||||
|
#include <linux/netfilter/x_tables.h>
|
||||||
|
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||||
|
#include <net/ip.h>
|
||||||
|
#include <net/ipv6.h>
|
||||||
|
#include "compat_xtables.h"
|
||||||
|
#include "xt_RAWNAT.h"
|
||||||
|
|
||||||
|
static inline __be32
|
||||||
|
remask(__be32 addr, __be32 repl, unsigned int shift)
|
||||||
|
{
|
||||||
|
uint32_t mask = (shift == 32) ? 0 : (~(uint32_t)0 >> shift);
|
||||||
|
return htonl((ntohl(addr) & mask) | (ntohl(repl) & ~mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rawnat_ipv6_mask(__be32 *addr, const __be32 *repl, unsigned int mask)
|
||||||
|
{
|
||||||
|
switch (mask) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1 ... 31:
|
||||||
|
addr[0] = remask(addr[0], repl[0], mask);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
addr[0] = repl[0];
|
||||||
|
break;
|
||||||
|
case 33 ... 63:
|
||||||
|
addr[0] = repl[0];
|
||||||
|
addr[1] = remask(addr[1], repl[1], mask - 64);
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
addr[0] = repl[0];
|
||||||
|
addr[1] = repl[1];
|
||||||
|
break;
|
||||||
|
case 65 ... 95:
|
||||||
|
addr[0] = repl[0];
|
||||||
|
addr[1] = repl[1];
|
||||||
|
addr[2] = remask(addr[2], repl[2], mask - 96);
|
||||||
|
case 96:
|
||||||
|
addr[0] = repl[0];
|
||||||
|
addr[1] = repl[1];
|
||||||
|
addr[2] = repl[2];
|
||||||
|
break;
|
||||||
|
case 97 ... 127:
|
||||||
|
addr[0] = repl[0];
|
||||||
|
addr[1] = repl[1];
|
||||||
|
addr[2] = repl[2];
|
||||||
|
addr[3] = remask(addr[3], repl[3], mask - 128);
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
addr[0] = repl[0];
|
||||||
|
addr[1] = repl[1];
|
||||||
|
addr[2] = repl[2];
|
||||||
|
addr[3] = repl[3];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rawnat4_update_l4(struct sk_buff *skb, __be32 oldip, __be32 newip)
|
||||||
|
{
|
||||||
|
struct iphdr *iph = ip_hdr(skb);
|
||||||
|
void *transport_hdr = (void *)iph + ip_hdrlen(skb);
|
||||||
|
struct tcphdr *tcph;
|
||||||
|
struct udphdr *udph;
|
||||||
|
|
||||||
|
switch (iph->protocol) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
tcph = transport_hdr;
|
||||||
|
inet_proto_csum_replace4(&tcph->check, skb, oldip, newip, true);
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
case IPPROTO_UDPLITE:
|
||||||
|
udph = transport_hdr;
|
||||||
|
if (udph->check != 0 || skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||||
|
inet_proto_csum_replace4(&udph->check, skb,
|
||||||
|
oldip, newip, true);
|
||||||
|
if (udph->check == 0)
|
||||||
|
udph->check = CSUM_MANGLED_0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int rawnat4_writable_part(const struct iphdr *iph)
|
||||||
|
{
|
||||||
|
unsigned int wlen = sizeof(*iph);
|
||||||
|
|
||||||
|
switch (iph->protocol) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
wlen += sizeof(struct tcphdr);
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
wlen += sizeof(struct udphdr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return wlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
rawsnat_tg4(struct sk_buff **pskb, const struct xt_target_param *par)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = par->targinfo;
|
||||||
|
struct iphdr *iph;
|
||||||
|
__be32 new_addr;
|
||||||
|
|
||||||
|
iph = ip_hdr(*pskb);
|
||||||
|
new_addr = remask(iph->saddr, info->addr.ip, info->mask);
|
||||||
|
if (iph->saddr == new_addr)
|
||||||
|
return XT_CONTINUE;
|
||||||
|
|
||||||
|
if (!skb_make_writable(pskb, rawnat4_writable_part(iph)))
|
||||||
|
return NF_DROP;
|
||||||
|
|
||||||
|
iph = ip_hdr(*pskb);
|
||||||
|
csum_replace4(&iph->check, iph->saddr, new_addr);
|
||||||
|
rawnat4_update_l4(*pskb, iph->saddr, new_addr);
|
||||||
|
iph->saddr = new_addr;
|
||||||
|
return XT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
rawdnat_tg4(struct sk_buff **pskb, const struct xt_target_param *par)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = par->targinfo;
|
||||||
|
struct iphdr *iph;
|
||||||
|
__be32 new_addr;
|
||||||
|
|
||||||
|
iph = ip_hdr(*pskb);
|
||||||
|
new_addr = remask(iph->daddr, info->addr.ip, info->mask);
|
||||||
|
if (iph->daddr == new_addr)
|
||||||
|
return XT_CONTINUE;
|
||||||
|
|
||||||
|
if (!skb_make_writable(pskb, rawnat4_writable_part(iph)))
|
||||||
|
return NF_DROP;
|
||||||
|
|
||||||
|
iph = ip_hdr(*pskb);
|
||||||
|
csum_replace4(&iph->check, iph->daddr, new_addr);
|
||||||
|
rawnat4_update_l4(*pskb, iph->daddr, new_addr);
|
||||||
|
iph->daddr = new_addr;
|
||||||
|
return XT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rawnat6_prepare_l4(struct sk_buff **pskb, unsigned int *l4offset,
|
||||||
|
unsigned int *l4proto)
|
||||||
|
{
|
||||||
|
static const unsigned int types[] =
|
||||||
|
{IPPROTO_TCP, IPPROTO_UDP, IPPROTO_UDPLITE};
|
||||||
|
unsigned int i;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
*l4proto = NEXTHDR_MAX;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(types); ++i) {
|
||||||
|
err = ipv6_find_hdr(*pskb, l4offset, types[i], NULL);
|
||||||
|
if (err >= 0) {
|
||||||
|
*l4proto = types[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (err != -ENOENT)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*l4proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
if (!skb_make_writable(pskb, *l4offset + sizeof(struct tcphdr)))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
case IPPROTO_UDPLITE:
|
||||||
|
if (!skb_make_writable(pskb, *l4offset + sizeof(struct udphdr)))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rawnat6_update_l4(struct sk_buff *skb, unsigned int l4proto,
|
||||||
|
unsigned int l4offset, const struct in6_addr *oldip,
|
||||||
|
const struct in6_addr *newip)
|
||||||
|
{
|
||||||
|
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||||
|
struct tcphdr *tcph;
|
||||||
|
struct udphdr *udph;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
switch (l4proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
tcph = (void *)iph + l4offset;
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
inet_proto_csum_replace4(&tcph->check, skb,
|
||||||
|
oldip->s6_addr32[i], newip->s6_addr32[i], true);
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
case IPPROTO_UDPLITE:
|
||||||
|
udph = (void *)iph + l4offset;
|
||||||
|
if (udph->check != 0 || skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||||
|
for (i = 0; i < 4; ++i)
|
||||||
|
inet_proto_csum_replace4(&udph->check, skb,
|
||||||
|
oldip->s6_addr32[i],
|
||||||
|
newip->s6_addr32[i], true);
|
||||||
|
if (udph->check == 0)
|
||||||
|
udph->check = CSUM_MANGLED_0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
rawsnat_tg6(struct sk_buff **pskb, const struct xt_target_param *par)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = par->targinfo;
|
||||||
|
unsigned int l4offset, l4proto;
|
||||||
|
struct ipv6hdr *iph;
|
||||||
|
struct in6_addr new_addr;
|
||||||
|
|
||||||
|
iph = ipv6_hdr(*pskb);
|
||||||
|
memcpy(&new_addr, &iph->saddr, sizeof(new_addr));
|
||||||
|
rawnat_ipv6_mask(new_addr.s6_addr32, info->addr.ip6, info->mask);
|
||||||
|
if (ipv6_addr_cmp(&iph->saddr, &new_addr) == 0)
|
||||||
|
return XT_CONTINUE;
|
||||||
|
if (!rawnat6_prepare_l4(pskb, &l4offset, &l4proto))
|
||||||
|
return NF_DROP;
|
||||||
|
iph = ipv6_hdr(*pskb);
|
||||||
|
rawnat6_update_l4(*pskb, l4proto, l4offset, &iph->saddr, &new_addr);
|
||||||
|
memcpy(&iph->saddr, &new_addr, sizeof(new_addr));
|
||||||
|
return XT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
rawdnat_tg6(struct sk_buff **pskb, const struct xt_target_param *par)
|
||||||
|
{
|
||||||
|
const struct xt_rawnat_tginfo *info = par->targinfo;
|
||||||
|
unsigned int l4offset, l4proto;
|
||||||
|
struct ipv6hdr *iph;
|
||||||
|
struct in6_addr new_addr;
|
||||||
|
|
||||||
|
iph = ipv6_hdr(*pskb);
|
||||||
|
memcpy(&new_addr, &iph->daddr, sizeof(new_addr));
|
||||||
|
rawnat_ipv6_mask(new_addr.s6_addr32, info->addr.ip6, info->mask);
|
||||||
|
if (ipv6_addr_cmp(&iph->daddr, &new_addr) == 0)
|
||||||
|
return XT_CONTINUE;
|
||||||
|
if (!rawnat6_prepare_l4(pskb, &l4offset, &l4proto))
|
||||||
|
return NF_DROP;
|
||||||
|
iph = ipv6_hdr(*pskb);
|
||||||
|
rawnat6_update_l4(*pskb, l4proto, l4offset, &iph->daddr, &new_addr);
|
||||||
|
memcpy(&iph->daddr, &new_addr, sizeof(new_addr));
|
||||||
|
return XT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool rawnat_tg_check(const struct xt_tgchk_param *par)
|
||||||
|
{
|
||||||
|
if (strcmp(par->table, "raw") == 0 ||
|
||||||
|
strcmp(par->table, "rawpost") == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
printk(KERN_ERR KBUILD_MODNAME " may only be used in the \"raw\" or "
|
||||||
|
"\"rawpost\" table.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct xt_target rawnat_tg_reg[] __read_mostly = {
|
||||||
|
{
|
||||||
|
.name = "RAWSNAT",
|
||||||
|
.revision = 0,
|
||||||
|
.family = NFPROTO_IPV4,
|
||||||
|
.target = rawsnat_tg4,
|
||||||
|
.targetsize = sizeof(struct xt_rawnat_tginfo),
|
||||||
|
.checkentry = rawnat_tg_check,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "RAWSNAT",
|
||||||
|
.revision = 0,
|
||||||
|
.family = NFPROTO_IPV6,
|
||||||
|
.target = rawsnat_tg6,
|
||||||
|
.targetsize = sizeof(struct xt_rawnat_tginfo),
|
||||||
|
.checkentry = rawnat_tg_check,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "RAWDNAT",
|
||||||
|
.revision = 0,
|
||||||
|
.family = NFPROTO_IPV4,
|
||||||
|
.target = rawdnat_tg4,
|
||||||
|
.targetsize = sizeof(struct xt_rawnat_tginfo),
|
||||||
|
.checkentry = rawnat_tg_check,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "RAWDNAT",
|
||||||
|
.revision = 0,
|
||||||
|
.family = NFPROTO_IPV6,
|
||||||
|
.target = rawdnat_tg6,
|
||||||
|
.targetsize = sizeof(struct xt_rawnat_tginfo),
|
||||||
|
.checkentry = rawnat_tg_check,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init rawnat_tg_init(void)
|
||||||
|
{
|
||||||
|
return xt_register_targets(rawnat_tg_reg, ARRAY_SIZE(rawnat_tg_reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit rawnat_tg_exit(void)
|
||||||
|
{
|
||||||
|
xt_unregister_targets(rawnat_tg_reg, ARRAY_SIZE(rawnat_tg_reg));
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(rawnat_tg_init);
|
||||||
|
module_exit(rawnat_tg_exit);
|
||||||
|
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
|
||||||
|
MODULE_DESCRIPTION("Xtables: conntrack-less raw NAT");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("ipt_RAWSNAT");
|
||||||
|
MODULE_ALIAS("ipt_RAWDNAT");
|
||||||
|
MODULE_ALIAS("ip6t_RAWSNAT");
|
||||||
|
MODULE_ALIAS("ip6t_RAWDNAT");
|
9
extensions/xt_RAWNAT.h
Normal file
9
extensions/xt_RAWNAT.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _LINUX_NETFILTER_XT_TARGET_RAWNAT
|
||||||
|
#define _LINUX_NETFILTER_XT_TARGET_RAWNAT 1
|
||||||
|
|
||||||
|
struct xt_rawnat_tginfo {
|
||||||
|
union nf_inet_addr addr;
|
||||||
|
__u8 mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _LINUX_NETFILTER_XT_TARGET_RAWNAT */
|
Reference in New Issue
Block a user