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

* Re: [PATCH] xt_LOG
  2006-11-14 20:13 [PATCH] xt_LOG Jozsef Kadlecsik
@ 2006-11-23 13:13 ` Patrick McHardy
  0 siblings, 0 replies; 2+ messages in thread
From: Patrick McHardy @ 2006-11-23 13:13 UTC (permalink / raw)
  To: Jozsef Kadlecsik; +Cc: netfilter-devel

Jozsef Kadlecsik wrote:
> 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.)


The unification is a nice thing, but I have some reservations
introducing incompatibilities after so many years, especially
considering it so far is the only option for IPv6 logging so
people probably will notice. Since its obsoleted by nfnetlink_log
anyway I doubt its worth fixing these purely cosmetical bugs.

^ 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.