All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] xt_LOG
@ 2006-11-14 20:13 Jozsef Kadlecsik
  2006-11-23 13:13 ` Patrick McHardy
  0 siblings, 1 reply; 2+ messages in thread
From: Jozsef Kadlecsik @ 2006-11-14 20:13 UTC (permalink / raw)
  To: netfilter-devel

[-- Attachment #1: Type: TEXT/PLAIN, Size: 754 bytes --]

Hi,

Attached is the xt_LOG module with a few IPv6 related fixes compared to 
the original ip6t_LOG.c:

- paren could be left unclosed at printing IPv6 extension headers
- MAC header printing of sit tunnels was wrong

Because IPv6 has got extension headers and not options, the string
"OPT" was changed to "EXT", which implies backward-incompatibility.
But the fixed extension header printing is already incompatible with 
ip6t_LOG ;-). (If you disagree, it can be reverted back to "OPT" of 
course.)

Best regards,
Jozsef
-
E-mail  : kadlec@blackhole.kfki.hu, kadlec@sunserv.kfki.hu
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

[-- Attachment #2: LOG.patch --]
[-- Type: TEXT/PLAIN, Size: 29793 bytes --]

[NETFILTER]: xt_LOG target

Unified ipt_LOG and ip6t_LOG with a few IPv6 related fixes:

- paren could be left unclosed at printing IPv6 extension headers
- MAC header printing of sit tunnels was wrong

Because IPv6 has got extension headers and not options, the string
"OPT" was changed to "EXT".

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.18-orig/include/linux/netfilter/xt_LOG.h linux-2.6.18-log/include/linux/netfilter/xt_LOG.h
--- linux-2.6.18-orig/include/linux/netfilter/xt_LOG.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18-log/include/linux/netfilter/xt_LOG.h	2006-11-07 16:45:01.000000000 +0100
@@ -0,0 +1,20 @@
+#ifndef _XT_LOG_H
+#define _XT_LOG_H
+
+/* make sure not to change this without changing netfilter.h:NF_LOG_* (!) */
+#define XT_LOG_TCPSEQ		0x01	/* Log TCP sequence numbers */
+#define XT_LOG_TCPOPT		0x02	/* Log TCP options */
+#define XT_LOG_IPOPT		0x04	/* Log IP options */
+#define XT_LOG_UID		0x08	/* Log UID owning local socket */
+#define XT_LOG_NFLOG		0x10	/* Log using nf_log backend */
+#define XT_LOG_MASK		0x1f
+
+#define XT_LOG_PREFIXLEN	30
+
+struct xt_log_info {
+	unsigned char level;
+	unsigned char logflags;
+	char prefix[XT_LOG_PREFIXLEN];
+};
+
+#endif /*_XT_LOG_H*/
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.18-orig/net/netfilter/Kconfig linux-2.6.18-log/net/netfilter/Kconfig
--- linux-2.6.18-orig/net/netfilter/Kconfig	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18-log/net/netfilter/Kconfig	2006-11-09 12:46:22.000000000 +0100
@@ -148,6 +148,15 @@
 	  <file:Documentation/modules.txt>.  The module will be called
 	  ipt_CONNMARK.o.  If unsure, say `N'.
 
+config NETFILTER_XT_TARGET_LOG
+	tristate '"LOG" target support'
+	depends on NETFILTER_XTABLES
+	help
+	  This option adds a `LOG' target, which allows you to create rules
+	  in any table which records the packet header to the syslog.
+
+	  To compile it as a module, choose M here.  If unsure, say N.
+
 config NETFILTER_XT_TARGET_MARK
 	tristate '"MARK" target support'
 	depends on NETFILTER_XTABLES
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.18-orig/net/netfilter/Makefile linux-2.6.18-log/net/netfilter/Makefile
--- linux-2.6.18-orig/net/netfilter/Makefile	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18-log/net/netfilter/Makefile	2006-11-09 12:44:27.000000000 +0100
@@ -30,6 +30,7 @@
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o
 
 # matches
 obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
diff -urN --exclude-from=/usr/src/diff.exclude linux-2.6.18-orig/net/netfilter/xt_LOG.c linux-2.6.18-log/net/netfilter/xt_LOG.c
--- linux-2.6.18-orig/net/netfilter/xt_LOG.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18-log/net/netfilter/xt_LOG.c	2006-11-13 13:16:16.000000000 +0100
@@ -0,0 +1,973 @@
+/* 
+ * x_tables module for logging IPv4/IPv6 packets.
+ */
+
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2001 Jan Rekorajski <baggins@pld.org.pl>
+ * (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/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ip.h>
+#include <linux/icmpv6.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/tcp.h>
+#include <net/ipv6.h>
+#include <net/route.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_LOG.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
+MODULE_DESCRIPTION("x_tables syslog logging module");
+MODULE_ALIAS("ipt_LOG");
+MODULE_ALIAS("ip6t_LOG");
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Lock which protects our buffer */
+static DEFINE_SPINLOCK(log_lock);
+static char *log_buffer;
+static int log_offset  = 0;
+
+#define LOG_BUFFER_SIZE	1024
+
+#define PRINTF(fmt, args...) \
+	log_offset += scnprintf(log_buffer + log_offset,	\
+				LOG_BUFFER_SIZE - log_offset, 	\
+				fmt , ## args)
+
+static struct nf_loginfo default_loginfo = {
+	.type	= NF_LOG_TYPE_LOG,
+	.u = {
+		.log = {
+			.level    = 0,
+			.logflags = NF_LOG_MASK,
+		},
+	},
+};
+
+/* Common routines */
+static void dump_tcp(unsigned int logflags,
+		     const struct sk_buff *skb,
+		     unsigned int offset,
+		     int fragment)
+{
+	struct tcphdr _tcph, *th;
+
+	/* Max length: 10 "PROTO=TCP " */
+	PRINTF("PROTO=TCP ");
+
+	if (fragment)
+		return;
+
+	/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+	th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
+	if (th == NULL) {
+		PRINTF("INCOMPLETE [%u bytes] ", skb->len - offset);
+		return;
+	}
+
+	/* Max length: 20 "SPT=65535 DPT=65535 " */
+	PRINTF("SPT=%u DPT=%u ",
+	       ntohs(th->source), ntohs(th->dest));
+	/* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
+	if (logflags & XT_LOG_TCPSEQ)
+		PRINTF("SEQ=%u ACK=%u ",
+		       ntohl(th->seq), ntohl(th->ack_seq));
+	/* Max length: 13 "WINDOW=65535 " */
+	PRINTF("WINDOW=%u ", ntohs(th->window));
+	/* Max length: 9 "RES=0x3F " */
+	PRINTF("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
+	/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
+	if (th->cwr)
+		PRINTF("CWR ");
+	if (th->ece)
+		PRINTF("ECE ");
+	if (th->urg)
+		PRINTF("URG ");
+	if (th->ack)
+		PRINTF("ACK ");
+	if (th->psh)
+		PRINTF("PSH ");
+	if (th->rst)
+		PRINTF("RST ");
+	if (th->syn)
+		PRINTF("SYN ");
+	if (th->fin)
+		PRINTF("FIN ");
+	/* Max length: 11 "URGP=65535 " */
+	PRINTF("URGP=%u ", ntohs(th->urg_ptr));
+
+	if ((logflags & XT_LOG_TCPOPT)
+	    && th->doff * 4 > sizeof(struct tcphdr)) {
+	    	unsigned char _opt[4 * 15 - sizeof(struct tcphdr)];
+	    	unsigned char *op;
+	    	unsigned int i, optsize;
+
+	    	optsize = th->doff * 4 - sizeof(struct tcphdr);
+	    	op = skb_header_pointer(skb,
+					offset+sizeof(_tcph),
+					optsize, _opt);
+		if (op == NULL) {
+			PRINTF("TRUNCATED");
+			return;
+		}
+
+		/* Max length: 127 "OPT (" 15*4*2chars ") " */
+		PRINTF("OPT (");
+		for (i = 0; i < optsize; i++)
+			PRINTF("%02X", op[i]);
+		PRINTF(") ");
+	}
+	/* TCP max length: 252 */
+}
+
+static void dump_udp(unsigned int logflags,
+		     const struct sk_buff *skb,
+		     unsigned int offset,
+		     int fragment)
+{
+	struct udphdr _udph, *uh;
+
+	/* Max length: 10 "PROTO=UDP " */
+	PRINTF("PROTO=UDP ");
+
+	if (fragment)
+		return;
+
+	/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+	uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
+	if (uh == NULL) {
+		PRINTF("INCOMPLETE [%u bytes] ", skb->len - offset);
+		return;
+	}
+
+	/* Max length: 20 "SPT=65535 DPT=65535 " */
+	PRINTF("SPT=%u DPT=%u LEN=%u ",
+	       ntohs(uh->source), ntohs(uh->dest),
+	       ntohs(uh->len));
+	/* UDP max length: 35 */
+}
+
+static void dump_ah(unsigned int logflags,
+		    const char *str,
+		    const struct sk_buff *skb,
+		    unsigned int offset,
+		    int fragment)
+{
+	struct ip_auth_hdr _ahdr, *ah;
+
+	/* Max length: 9 "PROTO=AH " */
+	PRINTF("%sAH ", str);
+
+	if (fragment)
+		return;
+		
+	/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+	ah = skb_header_pointer(skb, offset, sizeof(_ahdr), &_ahdr);
+	if (ah == NULL) {
+		PRINTF("INCOMPLETE [%u bytes] ", skb->len - offset);
+		return;
+	}
+
+	/* Length: 15 "SPI=0xF1234567 " */
+	PRINTF("SPI=0x%x ", ntohl(ah->spi));
+	/* AH proto max length: 49 */
+	/* AH header max length: 42 (space deleted) */
+}
+
+static void dump_esp(unsigned int logflags,
+		     const char *str,
+		     const struct sk_buff *skb,
+		     unsigned int offset,
+		     int fragment)
+{
+	struct ip_esp_hdr _esph, *eh;
+
+	/* Max length: 10 "PROTO=ESP " */
+	PRINTF("%sESP ", str);
+
+	if (fragment)
+		return;
+
+	/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+	eh = skb_header_pointer(skb, offset, sizeof(_esph), &_esph);
+	if (eh == NULL) {
+		PRINTF("INCOMPLETE [%u bytes] ", skb->len - offset);
+		return;
+	}
+
+	/* Length: 15 "SPI=0xF1234567 " */
+	PRINTF("SPI=0x%x ", ntohl(eh->spi));
+	/* ESP proto max length: 50 */
+	/* ESP header max length: 43 (space deleted) */
+}
+
+/* One level of recursion won't kill us */
+static void dump_ipv4_packet(const struct nf_loginfo *info,
+			     const struct sk_buff *skb,
+			     unsigned int iphoff)
+{
+	struct iphdr _iph, *ih;
+	unsigned int logflags;
+
+	if (info->type == NF_LOG_TYPE_LOG)
+		logflags = info->u.log.logflags;
+	else
+		logflags = NF_LOG_MASK;
+
+	ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
+	if (ih == NULL) {
+		PRINTF("TRUNCATED");
+		return;
+	}
+
+	/* Important fields:
+	 * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
+	/* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
+	PRINTF("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ",
+	       NIPQUAD(ih->saddr), NIPQUAD(ih->daddr));
+
+	/* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
+	PRINTF("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
+	       ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK,
+	       ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id));
+
+	/* Max length: 9 "CE DF MF " */
+	if (ntohs(ih->frag_off) & IP_CE)
+		PRINTF("CE ");
+	if (ntohs(ih->frag_off) & IP_DF)
+		PRINTF("DF ");
+	if (ntohs(ih->frag_off) & IP_MF)
+		PRINTF("MF ");
+
+	/* Max length: 11 "FRAG:65535 " */
+	if (ntohs(ih->frag_off) & IP_OFFSET)
+		PRINTF("FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
+
+	if ((logflags & XT_LOG_IPOPT)
+	    && ih->ihl * 4 > sizeof(struct iphdr)) {
+		unsigned char _opt[4 * 15 - sizeof(struct iphdr)], *op;
+		unsigned int i, optsize;
+
+		optsize = ih->ihl * 4 - sizeof(struct iphdr);
+		op = skb_header_pointer(skb, iphoff+sizeof(_iph),
+					optsize, _opt);
+		if (op == NULL) {
+			PRINTF("TRUNCATED");
+			return;
+		}
+
+		/* Max length: 127 "OPT (" 15*4*2chars ") " */
+		PRINTF("OPT (");
+		for (i = 0; i < optsize; i++)
+			PRINTF("%02X", op[i]);
+		PRINTF(") ");
+	}
+
+	switch (ih->protocol) {
+	case IPPROTO_TCP:
+		dump_tcp(logflags, skb,
+			 iphoff + ih->ihl * 4,
+			 ntohs(ih->frag_off) & IP_OFFSET);
+		break;
+	case IPPROTO_UDP:
+		dump_udp(logflags, skb,
+			 iphoff + ih->ihl * 4,
+			 ntohs(ih->frag_off) & IP_OFFSET);
+		break;
+	case IPPROTO_ICMP: {
+		struct icmphdr _icmph, *ich;
+		static const size_t required_len[NR_ICMP_TYPES+1]
+			= { [ICMP_ECHOREPLY] = 4,
+			    [ICMP_DEST_UNREACH]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_SOURCE_QUENCH]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_REDIRECT]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_ECHO] = 4,
+			    [ICMP_TIME_EXCEEDED]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_PARAMETERPROB]
+			    = 8 + sizeof(struct iphdr),
+			    [ICMP_TIMESTAMP] = 20,
+			    [ICMP_TIMESTAMPREPLY] = 20,
+			    [ICMP_ADDRESS] = 12,
+			    [ICMP_ADDRESSREPLY] = 12 };
+
+		/* Max length: 11 "PROTO=ICMP " */
+		PRINTF("PROTO=ICMP ");
+
+		if (ntohs(ih->frag_off) & IP_OFFSET)
+			break;
+
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		ich = skb_header_pointer(skb, iphoff + ih->ihl * 4,
+					 sizeof(_icmph), &_icmph);
+		if (ich == NULL) {
+			PRINTF("INCOMPLETE [%u bytes] ",
+			       skb->len - iphoff - ih->ihl*4);
+			break;
+		}
+
+		/* Max length: 18 "TYPE=255 CODE=255 " */
+		PRINTF("TYPE=%u CODE=%u ", ich->type, ich->code);
+
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		if (ich->type <= NR_ICMP_TYPES
+		    && required_len[ich->type]
+		    && skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) {
+			PRINTF("INCOMPLETE [%u bytes] ",
+			       skb->len - iphoff - ih->ihl*4);
+			break;
+		}
+
+		switch (ich->type) {
+		case ICMP_ECHOREPLY:
+		case ICMP_ECHO:
+			/* Max length: 19 "ID=65535 SEQ=65535 " */
+			PRINTF("ID=%u SEQ=%u ",
+			       ntohs(ich->un.echo.id),
+			       ntohs(ich->un.echo.sequence));
+			break;
+
+		case ICMP_PARAMETERPROB:
+			/* Max length: 14 "PARAMETER=255 " */
+			PRINTF("PARAMETER=%u ",
+			       ntohl(ich->un.gateway) >> 24);
+			break;
+		case ICMP_REDIRECT:
+			/* Max length: 24 "GATEWAY=255.255.255.255 " */
+			PRINTF("GATEWAY=%u.%u.%u.%u ",
+			       NIPQUAD(ich->un.gateway));
+			/* Fall through */
+		case ICMP_DEST_UNREACH:
+		case ICMP_SOURCE_QUENCH:
+		case ICMP_TIME_EXCEEDED:
+			/* Max length: 3+maxlen */
+			if (!iphoff) { /* Only recurse once. */
+				PRINTF("[");
+				dump_ipv4_packet(info, skb,
+					    	 iphoff + ih->ihl*4+sizeof(_icmph));
+				PRINTF("] ");
+			}
+
+			/* Max length: 10 "MTU=65535 " */
+			if (ich->type == ICMP_DEST_UNREACH
+			    && ich->code == ICMP_FRAG_NEEDED)
+				PRINTF("MTU=%u ", ntohs(ich->un.frag.mtu));
+		}
+		break;
+	}
+	case IPPROTO_AH:
+		dump_ah(logflags, "PROTO=", skb,
+			iphoff + ih->ihl * 4,
+			ntohs(ih->frag_off) & IP_OFFSET);
+		break;
+	case IPPROTO_ESP:
+		dump_esp(logflags, "PROTO=", skb,
+			 iphoff + ih->ihl * 4,
+			 ntohs(ih->frag_off) & IP_OFFSET);
+		break;
+	/* Max length: 10 "PROTO 255 " */
+	default:
+		PRINTF("PROTO=%u ", ih->protocol);
+	}
+
+	/* Max length: 15 "UID=4294967295 " */
+ 	if ((logflags & XT_LOG_UID) && !iphoff && skb->sk) {
+		read_lock_bh(&skb->sk->sk_callback_lock);
+		if (skb->sk->sk_socket && skb->sk->sk_socket->file)
+ 			PRINTF("UID=%u ", skb->sk->sk_socket->file->f_uid);
+		read_unlock_bh(&skb->sk->sk_callback_lock);
+	}
+
+	/* Proto    Max log string length */
+	/* IP:      40+46+9+11+127 = 233 */
+	/* TCP:     10+max(25,20+30+13+9+32+11+127) = 252 */
+	/* UDP:     10+max(25,20) = 35 */
+	/* ICMP:    11+max(25,18+max(25,max(19,14,24+3+n+10,3+n+10))) = 66+n */
+	/* ESP:     10+max(25,15) = 35 */
+	/* AH:      9+max(25,15) = 34 */
+	/* unknown: 10 */
+	/* UID:	    15 */
+
+	/* (ICMP allows recursion one level deep) */
+	/* maxlen =  IP + ICMP +  IP + max(TCP,UDP,ICMP,ESP,AH,unknown) + UID */
+	/* maxlen = 233 +   66 + 233 + 252 + 15 = 799 */
+}
+
+/* Skip/dump IPv6 extension headers
+ * return values:
+ *	-1:	truncated packet
+ *	 0:	success
+ *	 1:	encrypted (ESP)
+ */
+static int skip_ext_hdr(const struct sk_buff *skb,
+			u_int8_t *currenthdr,
+		     	unsigned int *ptr,
+		     	int *fragment)
+{
+	unsigned int hdrlen;
+
+	while (*currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(*currenthdr)) {
+		struct ipv6_opt_hdr _hdr, *hp;
+
+		hp = skb_header_pointer(skb, *ptr, sizeof(_hdr), &_hdr);
+		if (hp == NULL)
+			return -1;
+
+		switch (*currenthdr) {
+		case IPPROTO_FRAGMENT: {
+			struct frag_hdr _fhdr, *fh;
+
+			fh = skb_header_pointer(skb, *ptr, sizeof(_fhdr),
+						&_fhdr);
+			if (fh == NULL)
+				return -1;
+
+			if (ntohs(fh->frag_off) & 0xFFF8)
+				*fragment = 1;
+
+			hdrlen = 8;
+
+			break;
+		}
+		case IPPROTO_DSTOPTS:
+		case IPPROTO_ROUTING:
+		case IPPROTO_HOPOPTS:
+			hdrlen = ipv6_optlen(hp);
+			break;
+		case IPPROTO_AH:
+			hdrlen = (hp->hdrlen+2)<<2;
+			break;
+		case IPPROTO_ESP:
+			return 1;
+		default:
+			return 0;
+		}
+
+		*currenthdr = hp->nexthdr;
+		*ptr += hdrlen;
+	}
+	return 0;
+}
+
+static int dump_ext_hdr(const struct sk_buff *skb,
+			unsigned int logflags,
+			u_int8_t *currenthdr,
+		     	unsigned int *ptr,
+		     	int *fragment)
+{
+	char seen[IPPROTO_MAX] = {0};
+	int next = 0;
+	unsigned int hdrlen;
+	
+	while (*currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(*currenthdr)) {
+		struct ipv6_opt_hdr _hdr, *hp;
+
+		if (next)
+			PRINTF(", ");
+
+		hp = skb_header_pointer(skb, *ptr, sizeof(_hdr), &_hdr);
+		if (hp == NULL) {
+			PRINTF("TRUNCATED");
+			return -1;
+		}
+
+		switch (*currenthdr) {
+		case IPPROTO_FRAGMENT: {
+			struct frag_hdr _fhdr, *fh;
+
+			if (seen[*currenthdr]) {
+				PRINTF("FRAG:IGNORED");
+				return skip_ext_hdr(skb, currenthdr, 
+						    ptr, fragment);
+			}
+			
+			/* Max length: 33 "FRAG:65535 INCOMPLETE ID:ffffffff" */
+			/*            +12 "FRAG:IGNORED" */
+			
+			PRINTF("FRAG:");
+			fh = skb_header_pointer(skb, *ptr, sizeof(_fhdr),
+						&_fhdr);
+			if (fh == NULL) {
+				PRINTF("TRUNCATED");
+				return -1;
+			}
+
+			/* Max length: 6 "65535 " */
+			PRINTF("%u ", ntohs(fh->frag_off) & 0xFFF8);
+
+			/* Max length: 11 "INCOMPLETE " */
+			if (fh->frag_off & htons(0x0001))
+				PRINTF("INCOMPLETE ");
+
+			PRINTF("ID:%08x", ntohl(fh->identification));
+
+			if (ntohs(fh->frag_off) & 0xFFF8)
+				*fragment = 1;
+
+			hdrlen = 8;
+			seen[*currenthdr]++;
+
+			break;
+		}
+		case IPPROTO_DSTOPTS:
+			if (seen[*currenthdr] > 1) {
+				PRINTF("DSTOPTS:IGNORED");
+				return skip_ext_hdr(skb, currenthdr, 
+						    ptr, fragment);
+			}
+			/* Max length:  7 "DSTOPTS" */
+			/*            + 7 "DSTOPTS" */
+			/*            +15 "DSTOPTS:IGNORED" */
+			PRINTF("DSTOPTS");
+			hdrlen = ipv6_optlen(hp);
+			seen[*currenthdr]++;
+			break;
+		case IPPROTO_ROUTING:
+			if (seen[*currenthdr]) {
+				PRINTF("ROUTING:IGNORED");
+				return skip_ext_hdr(skb, currenthdr, 
+						    ptr, fragment);
+			}
+			/* Max length:  7 "ROUTING" */
+			/*            +15 "ROUTING:IGNORED" */
+			PRINTF("ROUTING");
+			hdrlen = ipv6_optlen(hp);
+			seen[*currenthdr]++;
+			break;
+		case IPPROTO_HOPOPTS:
+			if (seen[*currenthdr]) {
+				PRINTF("HOPOPTS:IGNORED");
+				return skip_ext_hdr(skb, currenthdr, 
+						    ptr, fragment);
+			}
+			/* Max length:  7 "HOPOPTS" */
+			/*            +15 "HOPOPTS:IGNORED" */
+			PRINTF("HOPOPTS");
+			hdrlen = ipv6_optlen(hp);
+			seen[*currenthdr]++;
+			break;
+		/* Max Length */
+		case IPPROTO_AH:
+			if (seen[*currenthdr]) {
+				PRINTF("AH:IGNORED");
+				return skip_ext_hdr(skb, currenthdr, 
+						    ptr, fragment);
+			}
+			/* Max length: 43 "AH INCOMPLETE [65535 bytes]" */
+			/*            +10 "AH:IGNORED" */
+			dump_ah(logflags, "", skb, *ptr, *fragment);
+			log_offset--;	/* erase space */
+			hdrlen = (hp->hdrlen+2)<<2;
+			seen[*currenthdr]++;
+			break;
+		case IPPROTO_ESP:
+			/* Can't see twice as extension header */
+			/* Max length: 44 "ESP INCOMPLETE [65535 bytes]" */
+			dump_esp(logflags, "", skb, *ptr, *fragment);
+			log_offset--;	/* erase space */
+			return 1;
+		default:
+			/* Max length: 11 "UNKNOWN:255" */
+			PRINTF("UNKNOWN:%u", *currenthdr);
+			return 0;
+		}
+		*currenthdr = hp->nexthdr;
+		*ptr += hdrlen;
+		next = 1;
+	}
+	/* Max length: HOP + DST + ROUT + FRAG + AH + DST + max(ESP,UNK,IGN) + 6*2 */
+	/*               7 +   7 +    7 +   33 + 43 +   7 + max(44,11,max(10,15,12)) + 6*2 */
+	/* Max length: 160 */
+	return 0;
+}
+
+static void dump_ipv6_packet(const struct nf_loginfo *info,
+			     const struct sk_buff *skb,
+			     unsigned int ip6hoff,
+			     int recurse)
+{
+	u_int8_t currenthdr;
+	int fragment, ext_hdr;
+	struct ipv6hdr _ip6h, *ih;
+	unsigned int ptr;
+	unsigned int logflags;
+
+	if (info->type == NF_LOG_TYPE_LOG)
+		logflags = info->u.log.logflags;
+	else
+		logflags = NF_LOG_MASK;
+
+	ih = skb_header_pointer(skb, ip6hoff, sizeof(_ip6h), &_ip6h);
+	if (ih == NULL) {
+		PRINTF("TRUNCATED ");
+		return;
+	}
+
+	/* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */
+	PRINTF("SRC=" NIP6_FMT " DST=" NIP6_FMT " ", NIP6(ih->saddr), NIP6(ih->daddr));
+
+	/* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */
+	PRINTF("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ",
+	       ntohs(ih->payload_len) + sizeof(struct ipv6hdr),
+	       (ntohl(*(u_int32_t *)ih) & 0x0ff00000) >> 20,
+	       ih->hop_limit,
+	       (ntohl(*(u_int32_t *)ih) & 0x000fffff));
+
+	fragment = 0;
+	ptr = ip6hoff + sizeof(struct ipv6hdr);
+	currenthdr = ih->nexthdr;
+	if (logflags & XT_LOG_IPOPT) {
+		/* Max length: 167 "EXT (" <160 char> ") " */
+		PRINTF("EXT (");
+		ext_hdr = dump_ext_hdr(skb, logflags, &currenthdr, &ptr, &fragment);
+		PRINTF(") ");
+	} else {
+		ext_hdr = skip_ext_hdr(skb, &currenthdr, &ptr, &fragment);
+		
+		if (ext_hdr < 0)
+			PRINTF("TRUNCATED ");
+	}
+	if (ext_hdr)
+		return;
+	
+	switch (currenthdr) {
+	case IPPROTO_TCP:
+		dump_tcp(logflags, skb, ptr, fragment);
+		break;
+	case IPPROTO_UDP:
+		dump_udp(logflags, skb, ptr, fragment);
+		break;
+	case IPPROTO_ICMPV6: {
+		struct icmp6hdr _icmp6h, *ic;
+
+		/* Max length: 13 "PROTO=ICMPv6 " */
+		PRINTF("PROTO=ICMPv6 ");
+
+		if (fragment)
+			break;
+
+		/* Max length: 25 "INCOMPLETE [65535 bytes] " */
+		ic = skb_header_pointer(skb, ptr, sizeof(_icmp6h), &_icmp6h);
+		if (ic == NULL) {
+			PRINTF("INCOMPLETE [%u bytes] ", skb->len - ptr);
+			return;
+		}
+
+		/* Max length: 18 "TYPE=255 CODE=255 " */
+		PRINTF("TYPE=%u CODE=%u ", ic->icmp6_type, ic->icmp6_code);
+
+		switch (ic->icmp6_type) {
+		case ICMPV6_ECHO_REQUEST:
+		case ICMPV6_ECHO_REPLY:
+			/* Max length: 19 "ID=65535 SEQ=65535 " */
+			PRINTF("ID=%u SEQ=%u ",
+				ntohs(ic->icmp6_identifier),
+				ntohs(ic->icmp6_sequence));
+			break;
+		case ICMPV6_MGM_QUERY:
+		case ICMPV6_MGM_REPORT:
+		case ICMPV6_MGM_REDUCTION:
+			break;
+
+		case ICMPV6_PARAMPROB:
+			/* Max length: 17 "POINTER=ffffffff " */
+			PRINTF("POINTER=%08x ", ntohl(ic->icmp6_pointer));
+			/* Fall through */
+		case ICMPV6_DEST_UNREACH:
+		case ICMPV6_PKT_TOOBIG:
+		case ICMPV6_TIME_EXCEED:
+			/* Max length: 3+maxlen */
+			if (recurse) {
+				PRINTF("[");
+				dump_ipv6_packet(info, skb, 
+						 ptr + sizeof(_icmp6h),
+						 0);
+				PRINTF("] ");
+			}
+
+			/* Max length: 10 "MTU=65535 " */
+			if (ic->icmp6_type == ICMPV6_PKT_TOOBIG)
+				PRINTF("MTU=%u ", ntohl(ic->icmp6_mtu));
+		}
+		break;
+	}
+	/* Max length: 10 "PROTO=255 " */
+	default:
+		PRINTF("PROTO=%u ", currenthdr);
+	}
+
+	/* Max length: 15 "UID=4294967295 " */
+	if ((logflags & XT_LOG_UID) && recurse && skb->sk) {
+		read_lock_bh(&skb->sk->sk_callback_lock);
+		if (skb->sk->sk_socket && skb->sk->sk_socket->file)
+			PRINTF("UID=%u ", skb->sk->sk_socket->file->f_uid);
+		read_unlock_bh(&skb->sk->sk_callback_lock);
+	}
+	/* Proto    Max log string length */
+	/* IPv6:    88+44+48 = 180 */
+	/* TCP:     10+max(25,20+30+13+9+32+11+127) = 252 */
+	/* UDP:     10+max(25,20) = 35 */
+	/* ICMPv6:  13+max(25,18+max(19,17,3+n+10))) = 44+n */
+	/* ESP:     10+max(25,15) = 35 */
+	/* AH:      9+max(25,15) = 34 */
+	/* unknown: 10 */
+	/* UID:	    15 */
+
+	/* (ICMPv6 allows recursion one level deep) */
+	/* maxlen =  IPv6 + ICMPv6 +  IPv6 + max(TCP,UDP,ICMP,ESP,AH,unknown) + UID */
+	/* maxlen =   180 +     44 +   180 + 252 + 15 = 671 */
+}
+
+static void
+xt_log_packet(unsigned int pf,
+	      unsigned int hooknum,
+	      const struct sk_buff *skb,
+	      const struct net_device *in,
+	      const struct net_device *out,
+	      const struct nf_loginfo *loginfo,
+	      const char *prefix)
+{
+	if (!loginfo)
+		loginfo = &default_loginfo;
+
+	spin_lock_bh(&log_lock);
+	log_buffer[0] = '\0';
+	log_offset = 0;
+	/* loglevel + interfaces
+	 * Max length: 36 + XT_LOG_PREFIXLEN
+	 *	      "<7>prefixIN=abcdefghijkl OUT=abcdefghijkl " */
+	PRINTF("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
+	       prefix,
+	       in ? in->name : "",
+	       out ? out->name : "");
+#ifdef CONFIG_BRIDGE_NETFILTER
+	if (skb->nf_bridge) {
+		struct net_device *physindev = skb->nf_bridge->physindev;
+		struct net_device *physoutdev = skb->nf_bridge->physoutdev;
+		/* Max length: 41 "PHYSIN=abcdefghijkl PHYSOUT=abcdefghijkl " */
+		if (physindev && in != physindev)
+			PRINTF("PHYSIN=%s ", physindev->name);
+		if (physoutdev && out != physoutdev)
+			PRINTF("PHYSOUT=%s ", physoutdev->name);
+	}
+#endif
+	if (in && !out) {
+		unsigned int len;
+		/* MAC logging for input chain only. */
+		/* Max length: 46 "MAC=00:01:02:03:04:05:06:07:08:09:10:11:12:13 " */
+		/* Max length: 40 "TUNNEL=255.255.255.255->255.255.255.255 " */
+		PRINTF("MAC=");
+		if (skb->dev && (len = skb->dev->hard_header_len) &&
+		    skb->mac.raw != skb->nh.raw) {
+		    	unsigned char *p = skb->mac.raw;
+		    	int i;
+
+		    	if (skb->dev->type == ARPHRD_SIT) {
+		    		if ((p -= ETH_HLEN) < skb->head)
+			    		p = NULL;
+				else
+					len = ETH_HLEN;
+			}
+
+			if (p != NULL) {
+				for (i = 0; i < len; i++)
+					PRINTF("%02x%s", p[i],
+					       i == len - 1 ? "" : ":");
+			}
+			PRINTF(" ");
+
+			if (skb->dev->type == ARPHRD_SIT) {
+				struct iphdr *iph = (struct iphdr *)skb->mac.raw;
+				PRINTF("TUNNEL=%u.%u.%u.%u->%u.%u.%u.%u ",
+				       NIPQUAD(iph->saddr),
+				       NIPQUAD(iph->daddr));
+			}
+		} else
+			PRINTF(" ");
+	}
+
+	switch (pf) {
+	case PF_INET:			
+		dump_ipv4_packet(loginfo, skb, 0);
+		break;
+	case PF_INET6:	
+		dump_ipv6_packet(loginfo, skb, 0, 1);
+		break;
+	default:
+		;
+	}
+	/* Total lenght for IPv4:
+	 *
+	 * 	header + bridge + mac + packet + newline
+	 *          66 +     41 +  46 +    799 +       1 = 953
+	 *
+	 * Total length for IPv6: 
+	 *
+	 * 	header + bridge + mac + tunnel + packet + newline
+	 *          66 +     41 +  46 +     40 +    671 +       1 = 865
+	 */
+	PRINTF("\n");
+	printk(log_buffer);
+	spin_unlock_bh(&log_lock);
+}
+
+static unsigned int
+xt_log_ipv4_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,
+		   void *userinfo)
+{
+	const struct xt_log_info *loginfo = targinfo;
+	struct nf_loginfo li;
+
+	li.type = NF_LOG_TYPE_LOG;
+	li.u.log.level = loginfo->level;
+	li.u.log.logflags = loginfo->logflags;
+
+	if (loginfo->logflags & XT_LOG_NFLOG)
+		nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
+		              "%s", loginfo->prefix);
+	else
+		xt_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
+			      loginfo->prefix);
+
+	return XT_CONTINUE;
+}
+
+static unsigned int
+xt_log_ipv6_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,
+		void *userinfo)
+{
+	const struct xt_log_info *loginfo = targinfo;
+	struct nf_loginfo li;
+
+	li.type = NF_LOG_TYPE_LOG;
+	li.u.log.level = loginfo->level;
+	li.u.log.logflags = loginfo->logflags;
+
+	if (loginfo->logflags & XT_LOG_NFLOG)
+		nf_log_packet(PF_INET6, hooknum, *pskb, in, out, &li,
+		              "%s", loginfo->prefix);
+	else
+		xt_log_packet(PF_INET6, hooknum, *pskb, in, out, &li,
+			      loginfo->prefix);
+
+	return XT_CONTINUE;
+}
+
+static int xt_log_checkentry(const char *tablename,
+			     const void *e,
+			     const struct xt_target *target,
+			     void *targinfo,
+			     unsigned int targinfosize,
+			     unsigned int hook_mask)
+{
+	const struct xt_log_info *loginfo = targinfo;
+
+	if (loginfo->level >= 8) {
+		DEBUGP("LOG: level %u >= 8\n", loginfo->level);
+		return 0;
+	}
+	if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
+		DEBUGP("LOG: prefix term %i\n",
+		       loginfo->prefix[sizeof(loginfo->prefix)-1]);
+		return 0;
+	}
+	return 1;
+}
+
+static struct xt_target xt_log_reg = {
+	.name		= "LOG",
+	.target		= xt_log_ipv4_target,
+	.targetsize	= sizeof(struct xt_log_info),
+	.checkentry	= xt_log_checkentry,
+	.family		= AF_INET,
+	.me		= THIS_MODULE,
+};
+
+static struct xt_target xt_log6_reg = {
+	.name		= "LOG",
+	.target		= xt_log_ipv6_target,
+	.targetsize	= sizeof(struct xt_log_info),
+	.checkentry	= xt_log_checkentry,
+	.family		= AF_INET6,
+	.me		= THIS_MODULE,
+};
+
+static struct nf_logger xt_log_logger ={
+	.name		= "LOG",
+	.logfn		= &xt_log_packet,
+	.me		= THIS_MODULE,
+};
+
+static int __init xt_log_init(void)
+{
+	int ret;
+	
+	log_buffer = kmalloc(LOG_BUFFER_SIZE, GFP_KERNEL);
+	if (!log_buffer)
+		return -ENOMEM;
+	ret = xt_register_target(&xt_log_reg);
+	if (ret)
+		goto REG_FAIL;
+	ret = xt_register_target(&xt_log6_reg);
+	if (ret)
+		goto REG6_FAIL;
+	/* we cannot make module load fail below, since otherwise
+	 * iptables userspace would abort */
+	if (nf_log_register(PF_INET, &xt_log_logger) < 0) {
+		printk(KERN_WARNING "xt_LOG: not logging via system console "
+		       "since somebody else already registered for PF_INET\n");
+	}
+	if (nf_log_register(PF_INET6, &xt_log_logger) < 0) {
+		printk(KERN_WARNING "xt_LOG: not logging via system console "
+		       "since somebody else already registered for PF_INET6\n");
+	}
+	
+	return 0;
+
+   REG6_FAIL:
+   	xt_unregister_target(&xt_log_reg);
+   REG_FAIL:
+   	kfree(log_buffer);
+   	return ret;
+}
+
+static void __exit xt_log_fini(void)
+{
+	nf_log_unregister_logger(&xt_log_logger);
+	xt_unregister_target(&xt_log6_reg);
+	xt_unregister_target(&xt_log_reg);
+	kfree(log_buffer);
+}
+
+module_init(xt_log_init);
+module_exit(xt_log_fini);

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2006-11-23 13:13 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-14 20:13 [PATCH] xt_LOG Jozsef Kadlecsik
2006-11-23 13:13 ` Patrick McHardy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.