[linux-l] iptables Problem: Einfuegen nicht moeglich wenn Referenz > 0

Benjamin Schieder blindcoder at scavenger.homeip.net
Fr Sep 1 16:12:38 CEST 2006


Hi Liste.

Ich habe gerade ein seeehr merkwuerdiges Problem mit iptables.
Folgende Situation:
Ich moechte mein Traffic Accounting Tool (UTA Dragon) mit aktuellem Kernel
2.6.17.7 zum Laufen bringen. Dazu ist ein Kernel Patch vonnoeten, damit
ich Traffic einem User zuordnen kann. Dies ist eine neue Version des
ipt_ownersocketlookup.patch aus iptables patch-o-matic:

---
diff -pruN linux-2.6.17.7-rock/net/ipv4/netfilter/ipt_owner.c linux-2.6.17.7-rock-dragon/net/ipv4/netfilter/ipt_owner.c
--- linux-2.6.17.7-rock/net/ipv4/netfilter/ipt_owner.c	2006-09-01 15:48:39.000000000 +0200
+++ linux-2.6.17.7-rock-dragon/net/ipv4/netfilter/ipt_owner.c	2006-08-30 09:58:15.000000000 +0200
@@ -12,7 +12,13 @@
 #include <linux/skbuff.h>
 #include <linux/file.h>
 #include <linux/rcupdate.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
 #include <net/sock.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/inet_hashtables.h>
 
 #include <linux/netfilter_ipv4/ipt_owner.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
@@ -32,23 +38,48 @@ match(const struct sk_buff *skb,
       int *hotdrop)
 {
 	const struct ipt_owner_info *info = matchinfo;
+	struct iphdr *iph = skb->nh.iph;
+	struct sock *sk = NULL;
+	int ret = 0;
+
+	if (out) {
+		sk = skb->sk;
+	} else {
+		if (iph->protocol == IPPROTO_TCP) {
+			struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+			sk = inet_lookup(&tcp_hashinfo, iph->saddr, tcph->source, iph->daddr, tcph->dest, skb->dev->ifindex);
+
+			if (sk && sk->sk_state == TCP_TIME_WAIT) {
+				inet_twsk_put((struct inet_timewait_sock *)sk);
+				return ret;
+			}
+		} else if (iph->protocol == IPPROTO_UDP) {
+			struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
+			sk = udp_v4_lookup(iph->saddr, udph->source, iph->daddr, udph->dest, skb->dev->ifindex);
+		}
+	}
 
-	if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file)
-		return 0;
+	if (!sk || !sk->sk_socket || !sk->sk_socket->file)
+		goto out;
 
 	if(info->match & IPT_OWNER_UID) {
-		if ((skb->sk->sk_socket->file->f_uid != info->uid) ^
+		if ((sk->sk_socket->file->f_uid != info->uid) ^
 		    !!(info->invert & IPT_OWNER_UID))
-			return 0;
+			goto out;
 	}
 
 	if(info->match & IPT_OWNER_GID) {
-		if ((skb->sk->sk_socket->file->f_gid != info->gid) ^
+		if ((sk->sk_socket->file->f_gid != info->gid) ^
 		    !!(info->invert & IPT_OWNER_GID))
-			return 0;
+			goto out;
 	}
 
-	return 1;
+	ret = 1;
+
+out:
+	if (in && sk)
+		sock_put(sk);
+	return ret;
 }
 
 static int
diff -pruN linux-2.6.17.7-rock/net/ipv4/udp.c linux-2.6.17.7-rock-dragon/net/ipv4/udp.c
--- linux-2.6.17.7-rock/net/ipv4/udp.c	2006-08-30 08:44:09.000000000 +0200
+++ linux-2.6.17.7-rock-dragon/net/ipv4/udp.c	2006-08-30 15:23:36.000000000 +0200
@@ -1587,6 +1587,7 @@ EXPORT_SYMBOL(udp_port_rover);
 EXPORT_SYMBOL(udp_prot);
 EXPORT_SYMBOL(udp_sendmsg);
 EXPORT_SYMBOL(udp_poll);
+EXPORT_SYMBOL(udp_v4_lookup);
 
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(udp_proc_register);
diff -pruN linux-2.6.17.7-rock/include/net/udp.h linux-2.6.17.7-rock-dragon/include/net/udp.h
--- linux-2.6.17.7-rock/include/net/udp.h	2006-08-30 08:46:19.000000000 +0200
+++ linux-2.6.17.7-rock-dragon/include/net/udp.h	2006-08-30 17:17:26.000000000 +0200
@@ -74,6 +74,8 @@ extern int	udp_disconnect(struct sock *s
 extern unsigned int udp_poll(struct file *file, struct socket *sock,
 			     poll_table *wait);
 
+static struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif);
+
 DECLARE_SNMP_STAT(struct udp_mib, udp_statistics);
 #define UDP_INC_STATS(field)		SNMP_INC_STATS(udp_statistics, field)
 #define UDP_INC_STATS_BH(field)		SNMP_INC_STATS_BH(udp_statistics, field)
---

Wenn ich jetzt das Programm starte und es seine Initialisierung durchfuehrt,
bricht es beim einfuegen der User ab:

iptables -A DRAGONUSER_INPUT -p tcp -d 192.168.1.6 -m owner --uid-owner 0 -j RETURN
iptables: Unknown error 4294967295

dmesg:
ip_tables: owner match: bad hook_mask 2

iptables -L sieht jetzt so aus:

root at ceres:/usr/src/dragon_0.3# iptables -vnxL
root at ceres:/usr/src/dragon_0.3# iptables -vnxL
Chain INPUT (policy ACCEPT 26730 packets, 7854290 bytes)
    pkts      bytes target     prot opt in     out     source               destination
#      95    46248 DRAGON_INPUT  all  --  *      *       0.0.0.0/0            192.168.1.6

Chain FORWARD (policy DROP 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 26123 packets, 9843675 bytes)
    pkts      bytes target     prot opt in     out     source               destination
      90    33282 DRAGON_OUTPUT  all  --  *      *       192.168.1.6          0.0.0.0/0

Chain DRAGONPROGRAM_INPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination

Chain DRAGONPROGRAM_OUTPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination

#Chain DRAGONUSER_INPUT (1 references)
#    pkts      bytes target     prot opt in     out     source               destination

Chain DRAGONUSER_OUTPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination

Chain DRAGON_INPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination
       0        0 RETURN     all  --  *      *       127.0.0.0/8          0.0.0.0/0
      35     2540 RETURN     all  --  *      *       192.168.1.0/24       0.0.0.0/0
#      60    43708 DRAGONUSER_INPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0
      60    43708 DRAGONPROGRAM_INPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0
      50    42425 RETURN     tcp  --  *      *       0.0.0.0/0            192.168.1.6         /* total_in */
      10     1283 RETURN     udp  --  *      *       0.0.0.0/0            192.168.1.6         /* total_in */
       0        0 RETURN     all  --  *      *       0.0.0.0/0            192.168.1.6         /* total_in */

Chain DRAGON_OUTPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination
       0        0 RETURN     all  --  *      *       0.0.0.0/0            127.0.0.0/8
      24     2928 RETURN     all  --  *      *       0.0.0.0/0            192.168.1.0/24
      66    30354 DRAGONUSER_OUTPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0
      66    30354 DRAGONPROGRAM_OUTPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0
      56    28791 RETURN     tcp  --  *      *       192.168.1.6          0.0.0.0/0           /* total_out */
       0        0 RETURN     udp  --  *      *       192.168.1.6          0.0.0.0/0           /* total_out */
      10     1563 RETURN     all  --  *      *       192.168.1.6          0.0.0.0/0           /* total_out */

Die Zeilen mit # am Anfang hab ich markiert, die sind hier wichtig. Traffic
wird von INPUT nach DRAGON_INPUT geschickt, dort wird er gezaehlt. DRAGON_INPUT
schickt ihn nach DRAGONUSER_INPUT, wo er auf die User accounted werden soll.
Wenn ich aus DRAGON_INPUT die entsprechende Zeile loesche, funktioniert
komischerweise das Einfuegen in DRAGONUSER_INPUT:

root at ceres:/usr/src# iptables -D DRAGON_INPUT -j DRAGONUSER_INPUT
root at ceres:/usr/src# iptables -A DRAGONUSER_INPUT -p tcp -d 192.168.1.6 -m owner --uid-owner 0 -j RETURN
root at ceres:/usr/src# iptables -vnxL
Chain INPUT (policy ACCEPT 39814 packets, 13602839 bytes)
    pkts      bytes target     prot opt in     out     source               destination
   12948  5775994 DRAGON_INPUT  all  --  *      *       0.0.0.0/0            192.168.1.6

Chain FORWARD (policy DROP 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 37753 packets, 13783989 bytes)
    pkts      bytes target     prot opt in     out     source               destination
   11489  3954793 DRAGON_OUTPUT  all  --  *      *       192.168.1.6          0.0.0.0/0

Chain DRAGONPROGRAM_INPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination

Chain DRAGONPROGRAM_OUTPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination

Chain DRAGONUSER_INPUT (0 references)
    pkts      bytes target     prot opt in     out     source               destination
#       0        0 RETURN     tcp  --  *      *       0.0.0.0/0            192.168.1.6         OWNER UID match 0

Chain DRAGONUSER_OUTPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination

Chain DRAGON_INPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination
       0        0 RETURN     all  --  *      *       127.0.0.0/8          0.0.0.0/0
    3840   301809 RETURN     all  --  *      *       192.168.1.0/24       0.0.0.0/0
    9108  5474185 DRAGONPROGRAM_INPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    8429  5387893 RETURN     tcp  --  *      *       0.0.0.0/0            192.168.1.6         /* total_in */
     679    86292 RETURN     udp  --  *      *       0.0.0.0/0            192.168.1.6         /* total_in */
       0        0 RETURN     all  --  *      *       0.0.0.0/0            192.168.1.6         /* total_in */

Chain DRAGON_OUTPUT (1 references)
    pkts      bytes target     prot opt in     out     source               destination
       0        0 RETURN     all  --  *      *       0.0.0.0/0            127.0.0.0/8
    2520   485625 RETURN     all  --  *      *       0.0.0.0/0            192.168.1.0/24
    8969  3469168 DRAGONUSER_OUTPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    8969  3469168 DRAGONPROGRAM_OUTPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0
    8290  3363864 RETURN     tcp  --  *      *       192.168.1.6          0.0.0.0/0           /* total_out */
       0        0 RETURN     udp  --  *      *       192.168.1.6          0.0.0.0/0           /* total_out */
     679   105304 RETURN     all  --  *      *       192.168.1.6          0.0.0.0/0           /* total_out */

In DRAGONUSER_OUTPUT kann ich problemlos einfuegen.

Hat jemand von euch eine Idee?


Gruesse,
	Benjamin

-- 
Benjamin 'blindCoder' Schieder
Registered Linux User #289529: http://counter.li.org
finger blindcoder at scavenger.homeip.net | gpg --import
-- 
http://www.rocklinux.org/ The Distribution Build Kit
-------------- nächster Teil --------------
Ein Dateianhang mit Binärdaten wurde abgetrennt...
Dateiname   : nicht verfügbar
Dateityp    : application/pgp-signature
Dateigröße  : 189 bytes
Beschreibung: nicht verfügbar
URL         : <https://mlists.in-berlin.de/pipermail/linux-l-mlists.in-berlin.de/attachments/20060901/b72fae9b/attachment.sig>


Mehr Informationen über die Mailingliste linux-l