Hi,
Attached you can find patches for netfilter and iptabes to support the
logging of the original and NAT-ed IP addresses together.
Currently there's no way to do it by netfilter/iptables. If we log in the
filter table, there we can record the original src IP address only.
However, we cannot log the src IP address after NAT at all: SNAT happens
in the nat table at POSTROUTING, and there's no other table to which the
logging rule could be added (and the NAT targets return ACCEPT, so we
cannot add the loggin rule to the nat table either).
The only way to log src/dst IP before/after NAT presently is to run
'conntrack' in event mode like this:
conntrack -E -e NEW | logger -p kernel.info
which is a little bit cumbersome and requires the libnfnetlink,
libnetfilter_conntrack libraries too.
The attached netfilter patch is questionable/incomplete in the sense that:
- it adds the POST_ROUTING hook to the raw table and in the IPv4 case
only: but there's no much point to add the hook to IPv6
- for the sake of completeness the LOCAL_IN hook should be added too,
in order to make possilbe the logging of local SNAT-ed addresses
- the original src/dst ports could be logged as well: in practice the
original src IP address matters only when one wants to hunt down
an infected machine on a NATed network
Comments are welcomed.
Best regards,
Jozsef
-
E-mail : kadlec@xxxxxxxxxxxxxxxxx, kadlec@xxxxxxxxxxxx
PGP key : http://www.kfki.hu/~kadlec/pgp_public_key.txt
Address : KFKI Research Institute for Particle and Nuclear Physics
H-1525 Budapest 114, POB. 49, Hungary
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index 29c7727..2e6dad5 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -63,6 +63,7 @@ enum nf_ip_hook_priorities {
NF_IP_PRI_SECURITY = 50,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_SELINUX_LAST = 225,
+ NF_IP_PRI_RAW_LOG = 300,
NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
NF_IP_PRI_LAST = INT_MAX,
};
diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h
index 90fa652..a63c0cd 100644
--- a/include/linux/netfilter_ipv4/ipt_LOG.h
+++ b/include/linux/netfilter_ipv4/ipt_LOG.h
@@ -7,7 +7,8 @@
#define IPT_LOG_IPOPT 0x04 /* Log IP options */
#define IPT_LOG_UID 0x08 /* Log UID owning local socket */
#define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */
-#define IPT_LOG_MASK 0x1f
+#define IPT_LOG_ORIG 0x20 /* Log original src/dst from ct */
+#define IPT_LOG_MASK 0x3f
struct ipt_log_info {
unsigned char level;
diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h
index 7182c06..60def34 100644
--- a/include/net/netfilter/nf_log.h
+++ b/include/net/netfilter/nf_log.h
@@ -8,7 +8,8 @@
#define NF_LOG_TCPOPT 0x02 /* Log TCP options */
#define NF_LOG_IPOPT 0x04 /* Log IP options */
#define NF_LOG_UID 0x08 /* Log UID owning local socket */
-#define NF_LOG_MASK 0x0f
+#define NF_LOG_ORIG 0x20 /* Log original src/dst from ct */
+#define NF_LOG_MASK 0x2f
#define NF_LOG_TYPE_LOG 0x01
#define NF_LOG_TYPE_ULOG 0x02
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 3816e1d..98c4ad3 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -132,6 +132,16 @@ config IP_NF_TARGET_LOG
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_TARGET_LOG_ORIG
+ bool "LOG target support for logging of original src/dst IP"
+ depends on NF_NAT
+ default y
+ help
+ This option enables logging of the original src/dst IP besides
+ the ones which can be found in the packet. The feature makes
+ possible to log the source/destination IP addresses before and
+ after NAT.
+
config IP_NF_TARGET_ULOG
tristate "ULOG target support"
default m if NETFILTER_ADVANCED=n
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index 27a78fb..076db8e 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -23,6 +23,9 @@
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_LOG.h>
#include <net/netfilter/nf_log.h>
+#ifdef CONFIG_IP_NF_TARGET_LOG_ORIG
+#include <net/netfilter/nf_conntrack.h>
+#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@xxxxxxxxxxxxx>");
@@ -348,8 +351,28 @@ static void dump_packet(const struct nf_loginfo *info,
if (!iphoff && skb->mark)
printk("MARK=0x%x ", skb->mark);
+#ifdef CONFIG_IP_NF_TARGET_LOG_ORIG
+ /* Original src/dst from ct */
+ if ((logflags & IPT_LOG_ORIG) && !iphoff) {
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ /* Max length: 48 "ORIGSRC=255.255.255.255 ORIGDST=255.255.255.255 " */
+ if (!ct || ct == &nf_conntrack_untracked)
+ printk("ORIGSRC=%u.%u.%u.%u ORIGDST=%u.%u.%u.%u ",
+ NIPQUAD(ih->saddr), NIPQUAD(ih->daddr));
+ else {
+ enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ printk("ORIGSRC=%u.%u.%u.%u ORIGDST=%u.%u.%u.%u ",
+ NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip),
+ NIPQUAD(ct->tuplehash[dir].tuple.dst.u3.ip));
+ }
+ }
+#endif
+
/* Proto Max log string length */
- /* IP: 40+46+6+11+127 = 230 */
+ /* IP: 40+46+6+11+127+48 = 278 */
/* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */
/* UDP: 10+max(25,20) = 35 */
/* UDPLITE: 14+max(25,20) = 39 */
@@ -360,7 +383,7 @@ static void dump_packet(const struct nf_loginfo *info,
/* (ICMP allows recursion one level deep) */
/* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */
- /* maxlen = 230+ 91 + 230 + 252 = 803 */
+ /* maxlen = 278+ 91 + 230 + 252 = 851 */
}
static struct nf_loginfo default_loginfo = {
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 7f65d18..466c8bc 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -1,5 +1,6 @@
/*
* 'raw' table, which is the very first hooked in at PRE_ROUTING and LOCAL_OUT .
+ * - POST_ROUTING is added to support logging after NAT (2009).
*
* Copyright (C) 2003 Jozsef Kadlecsik <kadlec@xxxxxxxxxxxxxxxxx>
*/
@@ -7,31 +8,36 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <net/ip.h>
-#define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT))
+#define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
+ (1 << NF_INET_LOCAL_OUT) |\
+ (1 << NF_INET_POST_ROUTING))
static struct
{
struct ipt_replace repl;
- struct ipt_standard entries[2];
+ struct ipt_standard entries[3];
struct ipt_error term;
} initial_table __net_initdata = {
.repl = {
.name = "raw",
.valid_hooks = RAW_VALID_HOOKS,
- .num_entries = 3,
- .size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
+ .num_entries = 4,
+ .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
.hook_entry = {
[NF_INET_PRE_ROUTING] = 0,
- [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard)
+ [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard),
+ [NF_INET_POST_ROUTING] = sizeof(struct ipt_standard) * 2,
},
.underflow = {
[NF_INET_PRE_ROUTING] = 0,
- [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard)
+ [NF_INET_LOCAL_OUT] = sizeof(struct ipt_standard),
+ [NF_INET_POST_ROUTING] = sizeof(struct ipt_standard) * 2,
},
},
.entries = {
IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
},
.term = IPT_ERROR_INIT, /* ERROR */
};
@@ -71,6 +77,17 @@ ipt_local_hook(unsigned int hook,
dev_net(out)->ipv4.iptable_raw);
}
+static unsigned int
+ipt_log_hook(unsigned int hook,
+ struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return ipt_do_table(skb, hook, in, out,
+ dev_net(out)->ipv4.iptable_raw);
+}
+
/* 'raw' is the very first table. */
static struct nf_hook_ops ipt_ops[] __read_mostly = {
{
@@ -87,6 +104,13 @@ static struct nf_hook_ops ipt_ops[] __read_mostly = {
.priority = NF_IP_PRI_RAW,
.owner = THIS_MODULE,
},
+ {
+ .hook = ipt_log_hook,
+ .pf = PF_INET,
+ .hooknum = NF_INET_POST_ROUTING,
+ .priority = NF_IP_PRI_RAW_LOG,
+ .owner = THIS_MODULE,
+ },
};
static int __net_init iptable_raw_net_init(struct net *net)
diff --git a/extensions/libipt_LOG.c b/extensions/libipt_LOG.c
index 50b1130..6f0b38b 100644
--- a/extensions/libipt_LOG.c
+++ b/extensions/libipt_LOG.c
@@ -14,7 +14,7 @@
#ifndef IPT_LOG_UID /* Old kernel */
#define IPT_LOG_UID 0x08 /* Log UID owning local socket */
#undef IPT_LOG_MASK
-#define IPT_LOG_MASK 0x0f
+#define IPT_LOG_MASK 0x2f
#endif
/* Function which prints out usage message. */
@@ -27,7 +27,8 @@ static void LOG_help(void)
" --log-tcp-sequence Log TCP sequence numbers.\n\n"
" --log-tcp-options Log TCP options.\n\n"
" --log-ip-options Log IP options.\n\n"
-" --log-uid Log UID owning the local socket.\n\n");
+" --log-uid Log UID owning the local socket.\n\n"
+" --log-orig Log original src/dst IP.\n\n");
}
static const struct option LOG_opts[] = {
@@ -37,6 +38,7 @@ static const struct option LOG_opts[] = {
{ .name = "log-tcp-options", .has_arg = 0, .val = '2' },
{ .name = "log-ip-options", .has_arg = 0, .val = '3' },
{ .name = "log-uid", .has_arg = 0, .val = '4' },
+ { .name = "log-orig", .has_arg = 0, .val = '5' },
{ .name = NULL }
};
@@ -102,6 +104,7 @@ parse_level(const char *level)
#define IPT_LOG_OPT_TCPOPT 0x08
#define IPT_LOG_OPT_IPOPT 0x10
#define IPT_LOG_OPT_UID 0x20
+#define IPT_LOG_OPT_ORIG 0x40
/* Function which parses command options; returns true if it
ate an option */
@@ -168,7 +171,6 @@ static int LOG_parse(int c, char **argv, int invert, unsigned int *flags,
loginfo->logflags |= IPT_LOG_TCPOPT;
*flags |= IPT_LOG_OPT_TCPOPT;
break;
-
case '3':
if (*flags & IPT_LOG_OPT_IPOPT)
exit_error(PARAMETER_PROBLEM,
@@ -187,6 +189,15 @@ static int LOG_parse(int c, char **argv, int invert, unsigned int *flags,
*flags |= IPT_LOG_OPT_UID;
break;
+ case '5':
+ if (*flags & IPT_LOG_OPT_ORIG)
+ exit_error(PARAMETER_PROBLEM,
+ "Can't specify --log-orig twice");
+
+ loginfo->logflags |= IPT_LOG_ORIG;
+ *flags |= IPT_LOG_OPT_ORIG;
+ break;
+
default:
return 0;
}
@@ -225,6 +236,8 @@ static void LOG_print(const void *ip, const struct xt_entry_target *target,
printf("ip-options ");
if (loginfo->logflags & IPT_LOG_UID)
printf("uid ");
+ if (loginfo->logflags & IPT_LOG_ORIG)
+ printf("orig ");
if (loginfo->logflags & ~(IPT_LOG_MASK))
printf("unknown-flags ");
}
@@ -255,6 +268,8 @@ static void LOG_save(const void *ip, const struct xt_entry_target *target)
printf("--log-ip-options ");
if (loginfo->logflags & IPT_LOG_UID)
printf("--log-uid ");
+ if (loginfo->logflags & IPT_LOG_ORIG)
+ printf("--log-orig ");
}
static struct xtables_target log_tg_reg = {
diff --git a/include/linux/netfilter_ipv4/ipt_LOG.h b/include/linux/netfilter_ipv4/ipt_LOG.h
index 90fa652..a63c0cd 100644
--- a/include/linux/netfilter_ipv4/ipt_LOG.h
+++ b/include/linux/netfilter_ipv4/ipt_LOG.h
@@ -7,7 +7,8 @@
#define IPT_LOG_IPOPT 0x04 /* Log IP options */
#define IPT_LOG_UID 0x08 /* Log UID owning local socket */
#define IPT_LOG_NFLOG 0x10 /* Unsupported, don't reuse */
-#define IPT_LOG_MASK 0x1f
+#define IPT_LOG_ORIG 0x20 /* Log original src/dst from ct */
+#define IPT_LOG_MASK 0x3f
struct ipt_log_info {
unsigned char level;