diff options
8 files changed, 0 insertions, 11617 deletions
diff --git a/target/linux/linux-2.4/patches/generic/101-netfilter_ipp2p.patch b/target/linux/linux-2.4/patches/generic/101-netfilter_ipp2p.patch deleted file mode 100644 index 1314ae4fe..000000000 --- a/target/linux/linux-2.4/patches/generic/101-netfilter_ipp2p.patch +++ /dev/null @@ -1,720 +0,0 @@ -diff -urN linux-2.4.29.old/include/linux/netfilter_ipv4/ipt_ipp2p.h linux-2.4.29/include/linux/netfilter_ipv4/ipt_ipp2p.h ---- linux-2.4.29.old/include/linux/netfilter_ipv4/ipt_ipp2p.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29/include/linux/netfilter_ipv4/ipt_ipp2p.h 2005-03-12 00:44:17.000000000 +0100 -@@ -0,0 +1,29 @@ -+#ifndef __IPT_IPP2P_H -+#define __IPT_IPP2P_H -+#define IPP2P_VERSION "0.7.4" -+ -+struct ipt_p2p_info { -+ int cmd; -+ int debug; -+}; -+ -+#endif //__IPT_IPP2P_H -+ -+#define SHORT_HAND_IPP2P 1 /* --ipp2p switch*/ -+#define SHORT_HAND_DATA 4 /* --ipp2p-data switch*/ -+#define SHORT_HAND_NONE 5 /* no short hand*/ -+ -+#define IPP2P_EDK 2 -+#define IPP2P_DATA_KAZAA 8 -+#define IPP2P_DATA_EDK 16 -+#define IPP2P_DATA_DC 32 -+#define IPP2P_DC 64 -+#define IPP2P_DATA_GNU 128 -+#define IPP2P_GNU 256 -+#define IPP2P_KAZAA 512 -+#define IPP2P_BIT 1024 -+#define IPP2P_APPLE 2048 -+#define IPP2P_SOUL 4096 -+#define IPP2P_WINMX 8192 -+#define IPP2P_ARES 16384 -+ -diff -urN linux-2.4.29.old/net/ipv4/netfilter/Config.in linux-2.4.29/net/ipv4/netfilter/Config.in ---- linux-2.4.29.old/net/ipv4/netfilter/Config.in 2005-03-12 00:40:38.000000000 +0100 -+++ linux-2.4.29/net/ipv4/netfilter/Config.in 2005-03-12 00:42:57.000000000 +0100 -@@ -26,6 +26,7 @@ - dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES - dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES - dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES -+ dep_tristate ' peer to peer traffic match support' CONFIG_IP_NF_MATCH_IPP2P $CONFIG_IP_NF_IPTABLES - - dep_tristate ' DSCP match support' CONFIG_IP_NF_MATCH_DSCP $CONFIG_IP_NF_IPTABLES - -diff -urN linux-2.4.29.old/net/ipv4/netfilter/ipt_ipp2p.c linux-2.4.29/net/ipv4/netfilter/ipt_ipp2p.c ---- linux-2.4.29.old/net/ipv4/netfilter/ipt_ipp2p.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29/net/ipv4/netfilter/ipt_ipp2p.c 2005-03-12 00:44:02.000000000 +0100 -@@ -0,0 +1,661 @@ -+#if defined(MODVERSIONS) -+#include <linux/modversions.h> -+#endif -+#include <linux/module.h> -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/version.h> -+#include <linux/netfilter_ipv4/ipt_ipp2p.h> -+//#include "ipt_ipp2p.h" -+#include <net/tcp.h> -+#include <net/udp.h> -+ -+#define get_u8(X,O) (*(__u8 *)(X + O)) -+#define get_u16(X,O) (*(__u16 *)(X + O)) -+#define get_u32(X,O) (*(__u32 *)(X + O)) -+ -+MODULE_AUTHOR("Eicke Friedrich <ipp2p@ipp2p.org>"); -+MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic."); -+MODULE_LICENSE("GPL"); -+ -+ -+/*Search for UDP eDonkey/eMule/Kad commands*/ -+int -+udp_search_edk (unsigned char *haystack, int packet_len) -+{ -+ unsigned char *t = haystack; -+ t += 8; -+ -+ switch (t[0]) { -+ case 0xe3: { /*edonkey*/ -+ switch (t[1]) { -+ /* e3 9a + 16Bytes Hash | size == 26 */ -+ case 0x9a: if (packet_len == 26) return ((IPP2P_EDK * 100) + 1); -+ /* e3 96 xx yy zz kk | size == 14 | server status request */ -+ case 0x96: if (packet_len == 14) return ((IPP2P_EDK * 100) + 2); -+ /* e3 a2 | size == 10 or 14 <-- recheck*/ -+ } -+ } -+ -+ case 0xc5: { /*emule*/ -+ switch (t[1]) { -+ /* c5 91 xx yy | size == 12 (8+4) | xx != 0x00 -- xx yy queue rating */ -+ case 0x91: if ((packet_len == 12) && (t[2] != 0x00)) return ((IPP2P_EDK * 100) + 3); -+ /* c5 90 xx .. yy | size == 26 (8+2+16) | xx .. yy == hash -- file ping */ -+ case 0x90: if ((packet_len == 26) && (t[2] != 0x00)) return ((IPP2P_EDK * 100) + 4); -+ /* c5 92 | size == 10 (8+2) -- file not found */ -+ case 0x92: if (packet_len == 10) return ((IPP2P_EDK * 100) + 5); -+ /* c5 93 | size == 10 (8+2) -- queue full */ -+ case 0x93: if (packet_len == 10) return ((IPP2P_EDK * 100) + 6); -+ } -+ } -+ -+ case 0xe4: { /*kad*/ -+ switch (t[1]) { -+ /* e4 50 | size == 12 */ -+ case 0x50: if (packet_len == 12) return ((IPP2P_EDK * 100) + 7); -+ /* e4 58 | size == 14 */ -+ case 0x58: if ((packet_len == 14) && (t[2] != 0x00)) return ((IPP2P_EDK * 100) + 8); -+ /* e4 59 | size == 10 */ -+ case 0x59: if (packet_len == 10) return ((IPP2P_EDK * 100) + 9); -+ /* e4 30 .. | t[18] == 0x01 | size > 26 | --> search */ -+ case 0x30: if ((packet_len > 26) && (t[18] == 0x01)) return ((IPP2P_EDK * 100) + 10); -+ /* e4 28 .. 00 | t[68] == 0x00 | size > 76 */ -+ case 0x28: if ((packet_len > 76) && (t[68] == 0x00)) return ((IPP2P_EDK * 100) + 11); -+ /* e4 20 .. | size == 43 */ -+ case 0x20: if ((packet_len == 43) && (t[2] != 0x00) && (t[34] != 0x00)) return ((IPP2P_EDK * 100) + 12); -+ /* e4 00 .. 00 | size == 35 ? */ -+ case 0x00: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 13); -+ /* e4 10 .. 00 | size == 35 ? */ -+ case 0x10: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 14); -+ /* e4 18 .. 00 | size == 35 ? */ -+ case 0x18: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 15); -+ /* e4 40 .. | t[18] == 0x01 | t[19] == 0x00 | size > 40 */ -+ case 0x40: if ((packet_len > 40) && (t[18] == 0x01) && (t[19] == 0x00)) return ((IPP2P_EDK * 100) + 16); -+ } -+ } -+ -+ default: return 0; -+ } /* end of switch (t[0]) */ -+}/*udp_search_edk*/ -+ -+ -+/*Search for UDP Gnutella commands*/ -+int -+udp_search_gnu (unsigned char *haystack, int packet_len) -+{ -+ unsigned char *t = haystack; -+ t += 8; -+ -+ if (memcmp(t, "GND", 3) == 0) return ((IPP2P_GNU * 100) + 1); -+ if (memcmp(t, "GNUTELLA ", 9) == 0) return ((IPP2P_GNU * 100) + 2); -+ return 0; -+}/*udp_search_gnu*/ -+ -+ -+/*Search for UDP KaZaA commands*/ -+int -+udp_search_kazaa (unsigned char *haystack, int packet_len) -+{ -+ unsigned char *t = haystack; -+ -+ if (t[packet_len-1] == 0x00){ -+ t += (packet_len - 6); -+ if (memcmp(t, "KaZaA", 5) == 0) return (IPP2P_KAZAA * 100); -+ } -+ return 0; -+}/*udp_search_kazaa*/ -+ -+ -+/*Search for UDP BitTorrent commands*/ -+int -+udp_search_bit (unsigned char *haystack, int packet_len) -+{ -+ unsigned char *t = haystack; -+ -+ /* packet_len has to be 24 */ -+ if (packet_len != 24) return 0; -+ -+ t += 8; -+ -+ /* ^ 00 00 04 17 27 10 19 80 */ -+ if ((ntohl(get_u32(t, 0)) == 0x00000417) && (ntohl(get_u32(t, 4)) == 0x27101980)) return (IPP2P_BIT * 100); -+ -+ return 0; -+}/*udp_search_bit*/ -+ -+ -+ -+/*Search for Ares commands*/ -+int -+search_ares (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ t += head_len; -+ -+ if ((packet_len - head_len) == 6){ /* possible connect command*/ -+ if ((t[0] == 0x03) && (t[1] == 0x00) && (t[2] == 0x5a) && (t[3] == 0x04) && (t[4] == 0x03) && (t[5] == 0x05)) -+ return ((IPP2P_ARES * 100) + 1); /* found connect packet: 03 00 5a 04 03 05 */ -+ } -+ if ((packet_len - head_len) == 60){ /* possible download command*/ -+ if ((t[59] == 0x0a) && (t[58] == 0x0a)){ -+ if (memcmp(t, "PUSH SHA1:", 10) == 0) /* found download command */ -+ return ((IPP2P_ARES * 100) + 2); -+ } -+ } -+ return 0; -+} /*search_ares*/ -+ -+ -+/*Search for SoulSeek commands*/ -+int -+search_soul (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ t += head_len; -+ -+ if (get_u16(t, 0) == (packet_len - head_len - 4)){ -+ /* xx xx 00 00 yy zz 00 00 .. | xx = sizeof(payload) - 4 */ -+ if ((get_u16(t,2) == 0x0000) &&(t[4] != 0x00) && (get_u16(t,6) == 0x0000)) -+ return ((IPP2P_SOUL * 100) + 1); -+ } else { -+ /* 00 00 00 00 00 00 00 00 + sizeof(payload) == 8*/ -+ if (((packet_len - head_len) == 8) && (get_u32(t, 0) == 0x00000000) && (get_u32(t, 4) == 0x00000000)) -+ return ((IPP2P_SOUL * 100) + 2); -+ } -+ -+ /* 01 xx 00 00 00 yy .. zz 00 00 00 .. | xx == sizeof(nick) | yy .. zz == nick */ -+ if ((t[0] == 0x01) && (t[2] == 0x00) && (get_u16(t,3) == 0x0000) && ((packet_len - head_len) > ((get_u8(t,1))+6)) && -+ (t[(get_u8(t,1))+4] != 0x00) && (t[(get_u8(t,1))+5] == 0x01) && (t[(get_u8(t,1))+6] == 0x00)) -+ return ((IPP2P_SOUL * 100) + 3); -+ return 0; -+} -+ -+ -+/*Search for WinMX commands*/ -+int -+search_winmx (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ int c; -+ t += head_len; -+ -+ if (((packet_len - head_len) == 4) && (memcmp(t, "SEND", 4) == 0)) return ((IPP2P_WINMX * 100) + 1); -+ if (((packet_len - head_len) == 3) && (memcmp(t, "GET", 3) == 0)) return ((IPP2P_WINMX * 100) + 2); -+ if (packet_len < (head_len + 10)) return 0; -+ -+ if ((memcmp(t, "SEND", 4) == 0) || (memcmp(t, "GET", 3) == 0)){ -+ c = head_len + 4; -+ t += 4; -+ while (c < packet_len - 5) { -+ if ((t[0] == 0x20) && (t[1] == 0x22)){ -+ c += 2; -+ t += 2; -+ while (c < packet_len - 2) { -+ if ((t[0] == 0x22) && (t[1] == 0x20)) return ((IPP2P_WINMX * 100) + 3); -+ t++; -+ c++; -+ } -+ } -+ t++; -+ c++; -+ } -+ } -+ return 0; -+} /*search_winmx*/ -+ -+ -+/*Search for appleJuice commands*/ -+int -+search_apple (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ t += head_len; -+ -+ if ((memcmp(t, "ajprot", 6) == 0) && (t[6] == 0x0d) && (t[7] == 0x0a)) return (IPP2P_APPLE * 100); -+ -+ return 0; -+} -+ -+ -+/*Search for BitTorrent commands*/ -+int -+search_bittorrent (unsigned char *haystack, int packet_len, int head_len) -+{ -+ -+ unsigned char *t = haystack; -+ if (*(haystack+head_len) != 0x13) return 0; /*Bail out of first byte != 0x13*/ -+ -+ t += head_len + 1; -+ -+ if (memcmp(t, "BitTorrent protocol", 19) == 0) return (IPP2P_BIT * 100); -+ return 0; -+} -+ -+ -+ -+/*check for Kazaa get command*/ -+int -+search_kazaa (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ -+ if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0; -+ -+ t += head_len; -+ if (memcmp(t, "GET /.hash=", 11) == 0) -+ return (IPP2P_DATA_KAZAA * 100); -+ else -+ return 0; -+} -+ -+ -+/*check for gnutella get command*/ -+int -+search_gnu (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ -+ if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0; -+ -+ t += head_len; -+ if (memcmp(t, "GET /get/", 9) == 0) return ((IPP2P_DATA_GNU * 100) + 1); -+ if (memcmp(t, "GET /uri-res/", 13) == 0) return ((IPP2P_DATA_GNU * 100) + 2); -+ -+ return 0; -+} -+ -+ -+/*check for gnutella get commands and other typical data*/ -+int -+search_all_gnu (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ int c; -+ -+ if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0; -+ -+ t += head_len; -+ -+ if (memcmp(t, "GNUTELLA CONNECT/", 17) == 0) return ((IPP2P_GNU * 100) + 1); -+ if (memcmp(t, "GNUTELLA/", 9) == 0) return ((IPP2P_GNU * 100) + 2); -+ -+ if ((memcmp(t, "GET /get/", 9) == 0) || (memcmp(t, "GET /uri-res/", 13) == 0)) -+ { -+ c = head_len + 8; -+ t += 8; -+ while (c < packet_len - 22) { -+ if ((t[0] == 0x0d) && (t[1] == 0x0a)) { -+ t += 2; -+ c += 2; -+ if ((memcmp(t, "X-Gnutella-", 11) == 0) || (memcmp(t, "X-Queue:", 8) == 0)) return ((IPP2P_GNU * 100) + 3); -+ } else { -+ t++; -+ c++; -+ } -+ } -+ } -+ return 0; -+} -+ -+ -+/*check for KaZaA download commands and other typical data*/ -+int -+search_all_kazaa (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ int c; -+ -+ if (!((*(haystack + packet_len - 2) == 0x0d) && (*(haystack + packet_len - 1) == 0x0a))) return 0; -+ -+ t += head_len; -+ if (memcmp(t, "GIVE ", 5) == 0) return ((IPP2P_KAZAA * 100) + 1); -+ -+ if (memcmp(t, "GET /", 5) == 0) { -+ c = head_len + 8; -+ t += 8; -+ while (c < packet_len - 22) { -+ if ((t[0] == 0x0d) && (t[1] == 0x0a)) { -+ t += 2; -+ c += 2; -+ if ( memcmp(t, "X-Kazaa-Username: ", 18) == 0 ) return ((IPP2P_KAZAA * 100) + 2); -+ if ( memcmp(t, "User-Agent: PeerEnabler/", 24) == 0 ) return ((IPP2P_KAZAA * 100) + 3); -+ } else { -+ t++; -+ c++; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+/*fast check for edonkey file segment transfer command*/ -+int -+search_edk (unsigned char *haystack, int packet_len, int head_len) -+{ -+ if (*(haystack+head_len) != 0xe3) -+ return 0; -+ else { -+ if (*(haystack+head_len+5) == 0x47) -+ return (IPP2P_DATA_EDK * 100); -+ else -+ return 0; -+ } -+} -+ -+ -+ -+/*intensive but slower search for some edonkey packets including size-check*/ -+int -+search_all_edk (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ int cmd; -+ -+ if (*(haystack+head_len) == 0xd4) { -+ t += head_len; -+ cmd = get_u16(t, 1); -+ if (cmd == (packet_len - head_len - 5)) { -+ switch (t[5]) { -+ case 0x82: return ((IPP2P_EDK * 100) + 42); -+ case 0x15: return ((IPP2P_EDK * 100) + 43); -+ default: return 0; -+ } -+ } -+ return 0; -+ } -+ -+ -+ if (*(haystack+head_len) == 0xc5) { /*search for additional eMule packets*/ -+ t += head_len; -+ cmd = get_u16(t, 1); -+ -+ if (cmd == (packet_len - head_len - 5)) { -+ switch (t[5]) { -+ case 0x01: return ((IPP2P_EDK * 100) + 30); -+ case 0x02: return ((IPP2P_EDK * 100) + 31); -+ case 0x60: return ((IPP2P_EDK * 100) + 32); -+ case 0x81: return ((IPP2P_EDK * 100) + 33); -+ case 0x82: return ((IPP2P_EDK * 100) + 34); -+ case 0x85: return ((IPP2P_EDK * 100) + 35); -+ case 0x86: return ((IPP2P_EDK * 100) + 36); -+ case 0x87: return ((IPP2P_EDK * 100) + 37); -+ case 0x40: return ((IPP2P_EDK * 100) + 38); -+ case 0x92: return ((IPP2P_EDK * 100) + 39); -+ case 0x93: return ((IPP2P_EDK * 100) + 40); -+ case 0x12: return ((IPP2P_EDK * 100) + 41); -+ default: return 0; -+ } -+ } -+ -+ return 0; -+ } -+ -+ -+ if (*(haystack+head_len) != 0xe3) -+ return 0; -+ else { -+ t += head_len; -+ cmd = get_u16(t, 1); -+ if (cmd == (packet_len - head_len - 5)) { -+ switch (t[5]) { -+ case 0x01: return ((IPP2P_EDK * 100) + 1); /*Client: hello or Server:hello*/ -+ case 0x50: return ((IPP2P_EDK * 100) + 2); /*Client: file status*/ -+ case 0x16: return ((IPP2P_EDK * 100) + 3); /*Client: search*/ -+ case 0x58: return ((IPP2P_EDK * 100) + 4); /*Client: file request*/ -+ case 0x48: return ((IPP2P_EDK * 100) + 5); /*???*/ -+ case 0x54: return ((IPP2P_EDK * 100) + 6); /*???*/ -+ case 0x47: return ((IPP2P_EDK * 100) + 7); /*Client: file segment request*/ -+ case 0x46: return ((IPP2P_EDK * 100) + 8); /*Client: download segment*/ -+ case 0x4c: return ((IPP2P_EDK * 100) + 9); /*Client: Hello-Answer*/ -+ case 0x4f: return ((IPP2P_EDK * 100) + 10); /*Client: file status request*/ -+ case 0x59: return ((IPP2P_EDK * 100) + 11); /*Client: file request answer*/ -+ case 0x65: return ((IPP2P_EDK * 100) + 12); /*Client: ???*/ -+ case 0x66: return ((IPP2P_EDK * 100) + 13); /*Client: ???*/ -+ case 0x51: return ((IPP2P_EDK * 100) + 14); /*Client: ???*/ -+ case 0x52: return ((IPP2P_EDK * 100) + 15); /*Client: ???*/ -+ case 0x4d: return ((IPP2P_EDK * 100) + 16); /*Client: ???*/ -+ case 0x5c: return ((IPP2P_EDK * 100) + 17); /*Client: ???*/ -+ case 0x38: return ((IPP2P_EDK * 100) + 18); /*Client: ???*/ -+ case 0x69: return ((IPP2P_EDK * 100) + 19); /*Client: ???*/ -+ case 0x19: return ((IPP2P_EDK * 100) + 20); /*Client: ???*/ -+ case 0x42: return ((IPP2P_EDK * 100) + 21); /*Client: ???*/ -+ case 0x34: return ((IPP2P_EDK * 100) + 22); /*Client: ???*/ -+ case 0x94: return ((IPP2P_EDK * 100) + 23); /*Client: ???*/ -+ case 0x1c: return ((IPP2P_EDK * 100) + 24); /*Client: ???*/ -+ case 0x6a: return ((IPP2P_EDK * 100) + 25); /*Client: ???*/ -+ default: return 0; -+ } -+ } else { -+ if (cmd > packet_len - head_len - 5) { -+ if ((t[3] == 0x00) && (t[4] == 0x00)) { -+ if (t[5] == 0x01) return ((IPP2P_EDK * 100) + 26); -+ if (t[5] == 0x4c) return ((IPP2P_EDK * 100) + 27); -+ } -+ return 0; -+ -+ } /*non edk packet*/ -+ if (t[cmd+5] == 0xe3) return ((IPP2P_EDK * 100) + 28);/*found another edk-command*/ -+ if (t[cmd+5] == 0xc5) return ((IPP2P_EDK * 100) + 29);/*found an emule-command*/ -+ return 0; -+ } -+ } -+} -+ -+ -+/*fast check for Direct Connect send command*/ -+int -+search_dc (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ -+ if (*(haystack+head_len) != 0x24 ) -+ return 0; -+ else { -+ t += head_len + 1; -+ if (memcmp(t, "Send|", 5) == 0) -+ return (IPP2P_DATA_DC * 100); -+ else -+ return 0; -+ } -+ -+} -+ -+ -+/*intensive but slower check for all direct connect packets*/ -+int -+search_all_dc (unsigned char *haystack, int packet_len, int head_len) -+{ -+ unsigned char *t = haystack; -+ -+ if ((*(haystack + head_len) == 0x24) && (*(haystack + packet_len - 1) == 0x7c)) { -+ t += head_len + 1; -+ if (memcmp(t, "Lock ", 5) == 0) return ((IPP2P_DC * 100) + 1); /*hub: hello*/ -+ if (memcmp(t, "Key ", 4) == 0) return ((IPP2P_DC * 100) + 2); /*client: hello*/ -+ if (memcmp(t, "Hello ", 6) == 0) return ((IPP2P_DC * 100) + 3); /*hub:connected*/ -+ if (memcmp(t, "MyNick ", 7) == 0) return ((IPP2P_DC * 100) + 4); /*client-client: hello*/ -+ if (memcmp(t, "Search ", 7) == 0) return ((IPP2P_DC * 100) + 5); /*client: search*/ -+ if (memcmp(t, "Send", 4) == 0) return ((IPP2P_DC * 100) + 6); /*client: start download*/ -+ return 0; -+ } else -+ return 0; -+} -+ -+ -+static struct { -+ int command; -+ __u8 short_hand; /*for fucntions included in short hands*/ -+ int packet_len; -+ int (*function_name) (unsigned char *, int, int); -+} matchlist[] = { -+ {IPP2P_EDK,SHORT_HAND_IPP2P,40, &search_all_edk}, -+ {IPP2P_DATA_KAZAA,SHORT_HAND_DATA,200, &search_kazaa}, -+ {IPP2P_DATA_EDK,SHORT_HAND_DATA,60, &search_edk}, -+ {IPP2P_DATA_DC,SHORT_HAND_DATA,26, &search_dc}, -+ {IPP2P_DC,SHORT_HAND_IPP2P,25, search_all_dc}, -+ {IPP2P_DATA_GNU,SHORT_HAND_DATA,40, &search_gnu}, -+ {IPP2P_GNU,SHORT_HAND_IPP2P,35, &search_all_gnu}, -+ {IPP2P_KAZAA,SHORT_HAND_IPP2P,35, &search_all_kazaa}, -+ {IPP2P_BIT,SHORT_HAND_NONE,40, &search_bittorrent}, -+ {IPP2P_APPLE,SHORT_HAND_NONE,20, &search_apple}, -+ {IPP2P_SOUL,SHORT_HAND_NONE,25, &search_soul}, -+ {IPP2P_WINMX,SHORT_HAND_NONE,20, &search_winmx}, -+ {IPP2P_ARES,SHORT_HAND_NONE,25, &search_ares}, -+ {0,0,0,NULL} -+}; -+ -+ -+static struct { -+ int command; -+ __u8 short_hand; /*for fucntions included in short hands*/ -+ int packet_len; -+ int (*function_name) (unsigned char *, int); -+} udp_list[] = { -+ {IPP2P_KAZAA,SHORT_HAND_IPP2P,14, &udp_search_kazaa}, -+ {IPP2P_BIT,SHORT_HAND_NONE,23, &udp_search_bit}, -+ {IPP2P_GNU,SHORT_HAND_IPP2P,11, &udp_search_gnu}, -+ {IPP2P_EDK,SHORT_HAND_IPP2P,9, &udp_search_edk}, -+ {0,0,0,NULL} -+}; -+ -+ -+static int -+match(const struct sk_buff *skb, -+ const struct net_device *in, -+ const struct net_device *out, -+ const void *matchinfo, -+ int offset, -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -+ const void *hdr, -+ u_int16_t datalen, -+#endif -+ -+ int *hotdrop) -+{ -+ const struct ipt_p2p_info *info = matchinfo; -+ unsigned char *haystack; -+ struct iphdr *ip = skb->nh.iph; -+ int p2p_result = 0, i = 0; -+ int head_len; -+ int hlen = ntohs(ip->tot_len)-(ip->ihl*4); /*hlen = packet-data length*/ -+ -+ /*must not be a fragment*/ -+ if (offset) { -+ if (info->debug) printk("IPP2P.match: offset found %i \n",offset); -+ return 0; -+ } -+ -+ /*make sure that skb is linear*/ -+ if(skb_is_nonlinear(skb)){ -+ if (info->debug) printk("IPP2P.match: nonlinear skb found\n"); -+ return 0; -+ } -+ -+ -+ haystack=(char *)ip+(ip->ihl*4); /*haystack = packet data*/ -+ -+ switch (ip->protocol){ -+ case IPPROTO_TCP: /*what to do with a TCP packet*/ -+ { -+ struct tcphdr *tcph = (void *) ip + ip->ihl * 4; -+ -+ if (tcph->fin) return 0; /*if FIN bit is set bail out*/ -+ if (tcph->syn) return 0; /*if SYN bit is set bail out*/ -+ if (tcph->rst) return 0; /*if RST bit is set bail out*/ -+ head_len = tcph->doff * 4; /*get TCP-Header-Size*/ -+ while (matchlist[i].command) { -+ if ((((info->cmd & matchlist[i].command) == matchlist[i].command) || -+ ((info->cmd & matchlist[i].short_hand) == matchlist[i].short_hand)) && -+ (hlen > matchlist[i].packet_len)) { -+ p2p_result = matchlist[i].function_name(haystack, hlen, head_len); -+ if (p2p_result) -+ { -+ if (info->debug) printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n", -+ p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen); -+ return p2p_result; -+ } -+ } -+ i++; -+ } -+ return p2p_result; -+ } -+ -+ case IPPROTO_UDP: /*what to do with an UDP packet*/ -+ { -+ struct udphdr *udph = (void *) ip + ip->ihl * 4; -+ -+ while (udp_list[i].command){ -+ if ((((info->cmd & udp_list[i].command) == udp_list[i].command) || -+ ((info->cmd & udp_list[i].short_hand) == udp_list[i].short_hand)) && -+ (hlen > udp_list[i].packet_len)) { -+ p2p_result = udp_list[i].function_name(haystack, hlen); -+ if (p2p_result){ -+ if (info->debug) printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n", -+ p2p_result, NIPQUAD(ip->saddr),ntohs(udph->source), NIPQUAD(ip->daddr),ntohs(udph->dest),hlen); -+ return p2p_result; -+ } -+ } -+ i++; -+ } -+ return p2p_result; -+ } -+ -+ default: return 0; -+ } -+} -+ -+ -+ -+static int -+checkentry(const char *tablename, -+ const struct ipt_ip *ip, -+ void *matchinfo, -+ unsigned int matchsize, -+ unsigned int hook_mask) -+{ -+ /* Must specify -p tcp */ -+/* if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) { -+ * printk("ipp2p: Only works on TCP packets, use -p tcp\n"); -+ * return 0; -+ * }*/ -+ return 1; -+} -+ -+ -+ -+ -+static struct ipt_match ipp2p_match = { -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -+ { NULL, NULL }, -+ "ipp2p", -+ &match, -+ &checkentry, -+ NULL, -+ THIS_MODULE -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -+ .name = "ipp2p", -+ .match = &match, -+ .checkentry = &checkentry, -+ .me = THIS_MODULE, -+#endif -+}; -+ -+ -+static int __init init(void) -+{ -+ printk(KERN_INFO "IPP2P v%s loading\n", IPP2P_VERSION); -+ return ipt_register_match(&ipp2p_match); -+} -+ -+static void __exit fini(void) -+{ -+ ipt_unregister_match(&ipp2p_match); -+ printk(KERN_INFO "IPP2P v%s unloaded\n", IPP2P_VERSION); -+} -+ -+module_init(init); -+module_exit(fini); -+ -+ -diff -urN linux-2.4.29.old/net/ipv4/netfilter/Makefile linux-2.4.29/net/ipv4/netfilter/Makefile ---- linux-2.4.29.old/net/ipv4/netfilter/Makefile 2005-03-12 00:40:38.000000000 +0100 -+++ linux-2.4.29/net/ipv4/netfilter/Makefile 2005-03-12 00:42:57.000000000 +0100 -@@ -67,6 +67,7 @@ - obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o - obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o - obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o -+obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o - - obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o - obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o diff --git a/target/linux/linux-2.4/patches/generic/102-netfilter_layer7.patch b/target/linux/linux-2.4/patches/generic/102-netfilter_layer7.patch deleted file mode 100644 index 55e817aa4..000000000 --- a/target/linux/linux-2.4/patches/generic/102-netfilter_layer7.patch +++ /dev/null @@ -1,2050 +0,0 @@ -diff -Nurp linux-2.4.30/Documentation/Configure.help linux-2.4.30-layer7/Documentation/Configure.help ---- linux-2.4.30/Documentation/Configure.help 2005-04-03 20:42:19.000000000 -0500 -+++ linux-2.4.30-layer7/Documentation/Configure.help 2005-05-03 18:37:03.000000000 -0500 -@@ -29056,6 +29056,23 @@ CONFIG_SOUND_WM97XX - - If unsure, say N. - -+CONFIG_IP_NF_MATCH_LAYER7 -+ Say Y if you want to be able to classify connections (and their -+ packets) based on regular expression matching of their application -+ layer data. This is one way to classify applications such as -+ peer-to-peer filesharing systems that do not always use the same -+ port. -+ -+ To compile it as a module, choose M here. If unsure, say N. -+ -+CONFIG_IP_NF_MATCH_LAYER7_DEBUG -+ Say Y to get lots of debugging output. -+ -+CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN -+ Size of the buffer that the application layer data is stored in. -+ Unless you know what you're doing, leave it at the default of 2048 -+ Bytes. -+ - # - # A couple of things I keep forgetting: - # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, -diff -Nurp linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.30-layer7/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h 2005-04-03 20:42:20.000000000 -0500 -+++ linux-2.4.30-layer7/include/linux/netfilter_ipv4/ip_conntrack.h 2005-05-03 18:37:03.000000000 -0500 -@@ -207,6 +207,17 @@ struct ip_conntrack - } nat; - #endif /* CONFIG_IP_NF_NAT_NEEDED */ - -+#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) -+ struct { -+ unsigned int numpackets; /* surely this is kept track of somewhere else, right? I can't find it... */ -+ char * app_proto; /* "http", "ftp", etc. NULL if unclassifed */ -+ -+ /* the application layer data so far. NULL if ->numpackets > numpackets */ -+ char * app_data; -+ -+ unsigned int app_data_len; -+ } layer7; -+#endif - }; - - /* get master conntrack via master expectation */ -diff -Nurp linux-2.4.30/include/linux/netfilter_ipv4/ipt_layer7.h linux-2.4.30-layer7/include/linux/netfilter_ipv4/ipt_layer7.h ---- linux-2.4.30/include/linux/netfilter_ipv4/ipt_layer7.h 1969-12-31 18:00:00.000000000 -0600 -+++ linux-2.4.30-layer7/include/linux/netfilter_ipv4/ipt_layer7.h 2005-05-03 18:37:03.000000000 -0500 -@@ -0,0 +1,26 @@ -+/* -+ By Matthew Strait <quadong@users.sf.net>, Dec 2003. -+ http://l7-filter.sf.net -+ -+ This program is free software; you can redistribute it and/or -+ modify it under the terms of the GNU General Public License -+ as published by the Free Software Foundation; either version -+ 2 of the License, or (at your option) any later version. -+ http://www.gnu.org/licenses/gpl.txt -+*/ -+ -+#ifndef _IPT_LAYER7_H -+#define _IPT_LAYER7_H -+ -+#define MAX_PATTERN_LEN 8192 -+#define MAX_PROTOCOL_LEN 256 -+ -+typedef char *(*proc_ipt_search) (char *, char, char *); -+ -+struct ipt_layer7_info { -+ char protocol[MAX_PROTOCOL_LEN]; -+ char invert:1; -+ char pattern[MAX_PATTERN_LEN]; -+}; -+ -+#endif /* _IPT_LAYER7_H */ -diff -Nurp linux-2.4.30/net/ipv4/netfilter/Config.in linux-2.4.30-layer7/net/ipv4/netfilter/Config.in ---- linux-2.4.30/net/ipv4/netfilter/Config.in 2005-01-19 08:10:13.000000000 -0600 -+++ linux-2.4.30-layer7/net/ipv4/netfilter/Config.in 2005-05-03 18:37:03.000000000 -0500 -@@ -43,6 +43,10 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES - dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES -+ dep_tristate ' Layer 7 match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_LAYER7 $CONFIG_IP_NF_CONNTRACK -+ dep_mbool ' Layer 7 debugging output (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_LAYER7_DEBUG $CONFIG_IP_NF_MATCH_LAYER7 -+ int ' Buffer size for application layer data (256-65536)' CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN 2048 -+ - fi - # The targets - dep_tristate ' Packet filtering' CONFIG_IP_NF_FILTER $CONFIG_IP_NF_IPTABLES -diff -Nurp linux-2.4.30/net/ipv4/netfilter/Makefile linux-2.4.30-layer7/net/ipv4/netfilter/Makefile ---- linux-2.4.30/net/ipv4/netfilter/Makefile 2003-08-25 06:44:44.000000000 -0500 -+++ linux-2.4.30-layer7/net/ipv4/netfilter/Makefile 2005-05-03 18:44:12.000000000 -0500 -@@ -86,6 +86,7 @@ obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_s - obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o - obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o - obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o -+obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o - - # targets - obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o -diff -Nurp linux-2.4.30/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.30-layer7/net/ipv4/netfilter/ip_conntrack_core.c ---- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_core.c 2005-04-03 20:42:20.000000000 -0500 -+++ linux-2.4.30-layer7/net/ipv4/netfilter/ip_conntrack_core.c 2005-05-03 18:37:03.000000000 -0500 -@@ -346,6 +346,14 @@ destroy_conntrack(struct nf_conntrack *n - } - kfree(ct->master); - } -+ -+ #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) -+ if(ct->layer7.app_proto) -+ kfree(ct->layer7.app_proto); -+ if(ct->layer7.app_data) -+ kfree(ct->layer7.app_data); -+ #endif -+ - WRITE_UNLOCK(&ip_conntrack_lock); - - if (master) -diff -Nurp linux-2.4.30/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.30-layer7/net/ipv4/netfilter/ip_conntrack_standalone.c ---- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-04-03 20:42:20.000000000 -0500 -+++ linux-2.4.30-layer7/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-05-03 18:37:03.000000000 -0500 -@@ -107,6 +107,13 @@ print_conntrack(char *buffer, struct ip_ - len += sprintf(buffer + len, "[ASSURED] "); - len += sprintf(buffer + len, "use=%u ", - atomic_read(&conntrack->ct_general.use)); -+ -+ #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) -+ if(conntrack->layer7.app_proto) -+ len += sprintf(buffer + len, "l7proto=%s ", -+ conntrack->layer7.app_proto); -+ #endif -+ - len += sprintf(buffer + len, "\n"); - - return len; -diff -Nurp linux-2.4.30/net/ipv4/netfilter/ipt_layer7.c linux-2.4.30-layer7/net/ipv4/netfilter/ipt_layer7.c ---- linux-2.4.30/net/ipv4/netfilter/ipt_layer7.c 1969-12-31 18:00:00.000000000 -0600 -+++ linux-2.4.30-layer7/net/ipv4/netfilter/ipt_layer7.c 2005-05-03 18:37:03.000000000 -0500 -@@ -0,0 +1,557 @@ -+/* -+ Kernel module to match application layer (OSI layer 7) -+ data in connections. -+ -+ http://l7-filter.sf.net -+ -+ By Matthew Strait and Ethan Sommer, 2003-2005. -+ -+ This program is free software; you can redistribute it and/or -+ modify it under the terms of the GNU General Public License -+ as published by the Free Software Foundation; either version -+ 2 of the License, or (at your option) any later version. -+ http://www.gnu.org/licenses/gpl.txt -+ -+ Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be> -+ and cls_layer7.c (C) 2003 Matthew Strait, Ethan Sommer, Justin Levandoski -+*/ -+ -+#include <linux/module.h> -+#include <linux/skbuff.h> -+#include <linux/netfilter_ipv4/ip_conntrack.h> -+#include <linux/proc_fs.h> -+#include <linux/ctype.h> -+#include <net/ip.h> -+#include <net/tcp.h> -+#include <linux/netfilter_ipv4/lockhelp.h> -+ -+#include "regexp/regexp.c" -+ -+#include <linux/netfilter_ipv4/ipt_layer7.h> -+#include <linux/netfilter_ipv4/ip_tables.h> -+ -+MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("iptables application layer match module"); -+ -+#if defined(CONFIG_IP_NF_MATCH_LAYER7_DEBUG) -+ #define DPRINTK(format,args...) printk(format,##args) -+#else -+ #define DPRINTK(format,args...) -+#endif -+ -+#define TOTAL_PACKETS master_conntrack->layer7.numpackets -+ -+/* Number of packets whose data we look at. -+This can be modified through /proc/net/layer7_numpackets */ -+static int num_packets = 8; -+ -+static struct pattern_cache { -+ char * regex_string; -+ regexp * pattern; -+ struct pattern_cache * next; -+} * first_pattern_cache = NULL; -+ -+/* I'm new to locking. Here are my assumptions: -+ -+- No one will write to /proc/net/layer7_numpackets over and over very fast; -+ if they did, nothing awful would happen. -+ -+- This code will never be processing the same packet twice at the same time, -+ because iptables rules are traversed in order. -+ -+- It doesn't matter if two packets from different connections are in here at -+ the same time, because they don't share any data. -+ -+- It _does_ matter if two packets from the same connection are here at the same -+ time. In this case, we have to protect the conntracks and the list of -+ compiled patterns. -+*/ -+DECLARE_RWLOCK(ct_lock); -+DECLARE_LOCK(list_lock); -+ -+#if CONFIG_IP_NF_MATCH_LAYER7_DEBUG -+/* Converts an unfriendly string into a friendly one by -+replacing unprintables with periods and all whitespace with " ". */ -+static char * friendly_print(unsigned char * s) -+{ -+ char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC); -+ int i; -+ -+ if(!f) { -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: out of memory in friendly_print, bailing.\n"); -+ return NULL; -+ } -+ -+ for(i = 0; i < strlen(s); i++){ -+ if(isprint(s[i]) && s[i] < 128) f[i] = s[i]; -+ else if(isspace(s[i])) f[i] = ' '; -+ else f[i] = '.'; -+ } -+ f[i] = '\0'; -+ return f; -+} -+ -+static char dec2hex(int i) -+{ -+ switch (i) { -+ case 0 ... 9: -+ return (char)(i + '0'); -+ break; -+ case 10 ... 15: -+ return (char)(i - 10 + 'a'); -+ break; -+ default: -+ if (net_ratelimit()) -+ printk("Problem in dec2hex\n"); -+ return '\0'; -+ } -+} -+ -+static char * hex_print(unsigned char * s) -+{ -+ char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC); -+ int i; -+ -+ if(!g) { -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: out of memory in hex_print, bailing.\n"); -+ return NULL; -+ } -+ -+ for(i = 0; i < strlen(s); i++) { -+ g[i*3 ] = dec2hex(s[i]/16); -+ g[i*3 + 1] = dec2hex(s[i]%16); -+ g[i*3 + 2] = ' '; -+ } -+ g[i*3] = '\0'; -+ -+ return g; -+} -+#endif // DEBUG -+ -+/* Use instead of regcomp. As we expect to be seeing the same regexps over and -+over again, it make sense to cache the results. */ -+static regexp * compile_and_cache(char * regex_string, char * protocol) -+{ -+ struct pattern_cache * node = first_pattern_cache; -+ struct pattern_cache * last_pattern_cache = first_pattern_cache; -+ struct pattern_cache * tmp; -+ unsigned int len; -+ -+ while (node != NULL) { -+ if (!strcmp(node->regex_string, regex_string)) -+ return node->pattern; -+ -+ last_pattern_cache = node;/* points at the last non-NULL node */ -+ node = node->next; -+ } -+ -+ /* If we reach the end of the list, then we have not yet cached -+ the pattern for this regex. Let's do that now. -+ Be paranoid about running out of memory to avoid list corruption. */ -+ tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC); -+ -+ if(!tmp) { -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); -+ return NULL; -+ } -+ -+ tmp->regex_string = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC); -+ tmp->pattern = kmalloc(sizeof(struct regexp), GFP_ATOMIC); -+ tmp->next = NULL; -+ -+ if(!tmp->regex_string || !tmp->pattern) { -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n"); -+ kfree(tmp->regex_string); -+ kfree(tmp->pattern); -+ kfree(tmp); -+ return NULL; -+ } -+ -+ /* Ok. The new node is all ready now. */ -+ node = tmp; -+ -+ if(first_pattern_cache == NULL) /* list is empty */ -+ first_pattern_cache = node; /* make node the beginning */ -+ else -+ last_pattern_cache->next = node; /* attach node to the end */ -+ -+ /* copy the string and compile the regex */ -+ len = strlen(regex_string); -+ DPRINTK("About to compile this: \"%s\"\n", regex_string); -+ node->pattern = regcomp(regex_string, &len); -+ if ( !node->pattern ) { -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: Error compiling regexp \"%s\" (%s)\n", regex_string, protocol); -+ /* pattern is now cached as NULL, so we won't try again. */ -+ } -+ -+ strcpy(node->regex_string, regex_string); -+ return node->pattern; -+} -+ -+static int can_handle(const struct sk_buff *skb) -+{ -+ if(!skb->nh.iph) /* not IP */ -+ return 0; -+ if(skb->nh.iph->protocol != IPPROTO_TCP && -+ skb->nh.iph->protocol != IPPROTO_UDP && -+ skb->nh.iph->protocol != IPPROTO_ICMP) -+ return 0; -+ return 1; -+} -+ -+/* Returns offset the into the skb->data that the application data starts */ -+static int app_data_offset(const struct sk_buff *skb) -+{ -+ /* In case we are ported somewhere (ebtables?) where skb->nh.iph -+ isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */ -+ int ip_hl = 4*skb->nh.iph->ihl; -+ -+ if( skb->nh.iph->protocol == IPPROTO_TCP ) { -+ /* 12 == offset into TCP header for the header length field. -+ Can't get this with skb->h.th->doff because the tcphdr -+ struct doesn't get set when routing (this is confirmed to be -+ true in Netfilter as well as QoS.) */ -+ int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4); -+ -+ return ip_hl + tcp_hl; -+ } else if( skb->nh.iph->protocol == IPPROTO_UDP ) { -+ return ip_hl + 8; /* UDP header is always 8 bytes */ -+ } else if( skb->nh.iph->protocol == IPPROTO_ICMP ) { -+ return ip_hl + 8; /* ICMP header is 8 bytes */ -+ } else { -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: tried to handle unknown protocol!\n"); -+ return ip_hl + 8; /* something reasonable */ -+ } -+} -+ -+/* handles whether there's a match when we aren't appending data anymore */ -+static int match_no_append(struct ip_conntrack * conntrack, struct ip_conntrack * master_conntrack, -+ enum ip_conntrack_info ctinfo, enum ip_conntrack_info master_ctinfo, -+ struct ipt_layer7_info * info) -+{ -+ /* If we're in here, throw the app data away */ -+ WRITE_LOCK(&ct_lock); -+ if(master_conntrack->layer7.app_data != NULL) { -+ -+ #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG -+ if(!master_conntrack->layer7.app_proto) { -+ char * f = friendly_print(master_conntrack->layer7.app_data); -+ char * g = hex_print(master_conntrack->layer7.app_data); -+ DPRINTK("\nl7-filter gave up after %d bytes (%d packets):\n%s\n", -+ strlen(f), -+ TOTAL_PACKETS, f); -+ kfree(f); -+ DPRINTK("In hex: %s\n", g); -+ kfree(g); -+ } -+ #endif -+ -+ kfree(master_conntrack->layer7.app_data); -+ master_conntrack->layer7.app_data = NULL; /* don't free again */ -+ } -+ WRITE_UNLOCK(&ct_lock); -+ -+ if(master_conntrack->layer7.app_proto){ -+ /* Here child connections set their .app_proto (for /proc/net/ip_conntrack) */ -+ WRITE_LOCK(&ct_lock); -+ if(!conntrack->layer7.app_proto) { -+ conntrack->layer7.app_proto = kmalloc(strlen(master_conntrack->layer7.app_proto)+1, GFP_ATOMIC); -+ if(!conntrack->layer7.app_proto){ -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); -+ WRITE_UNLOCK(&ct_lock); -+ return 1; -+ } -+ strcpy(conntrack->layer7.app_proto, master_conntrack->layer7.app_proto); -+ } -+ WRITE_UNLOCK(&ct_lock); -+ -+ return (!strcmp(master_conntrack->layer7.app_proto, info->protocol)); -+ } -+ else { -+ /* If not classified, set to "unknown" to distinguish from -+ connections that are still being tested. */ -+ WRITE_LOCK(&ct_lock); -+ master_conntrack->layer7.app_proto = kmalloc(strlen("unknown")+1, GFP_ATOMIC); -+ if(!master_conntrack->layer7.app_proto){ -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n"); -+ WRITE_UNLOCK(&ct_lock); -+ return 1; -+ } -+ strcpy(master_conntrack->layer7.app_proto, "unknown"); -+ WRITE_UNLOCK(&ct_lock); -+ return 0; -+ } -+} -+ -+/* add the new app data to the conntrack. Return number of bytes added. */ -+static int add_data(struct ip_conntrack * master_conntrack, -+ char * app_data, int appdatalen) -+{ -+ int length = 0, i; -+ int oldlength = master_conntrack->layer7.app_data_len; -+ -+ /* Strip nulls. Make everything lower case (our regex lib doesn't -+ do case insensitivity). Add it to the end of the current data. */ -+ for(i = 0; i < CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN-oldlength-1 && -+ i < appdatalen; i++) { -+ if(app_data[i] != '\0') { -+ master_conntrack->layer7.app_data[length+oldlength] = -+ /* the kernel version of tolower mungs 'upper ascii' */ -+ isascii(app_data[i])? tolower(app_data[i]) : app_data[i]; -+ length++; -+ } -+ } -+ -+ master_conntrack->layer7.app_data[length+oldlength] = '\0'; -+ master_conntrack->layer7.app_data_len = length + oldlength; -+ -+ return length; -+} -+ -+/* Returns true on match and false otherwise. */ -+static int match(/* const */struct sk_buff *skb, const struct net_device *in, -+ const struct net_device *out, const void *matchinfo, -+ int offset, int *hotdrop) -+{ -+ struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo; -+ enum ip_conntrack_info master_ctinfo, ctinfo; -+ struct ip_conntrack *master_conntrack, *conntrack; -+ unsigned char * app_data; -+ unsigned int pattern_result, appdatalen; -+ regexp * comppattern; -+ -+ if(!can_handle(skb)){ -+ DPRINTK("layer7: This is some protocol I can't handle.\n"); -+ return info->invert; -+ } -+ -+ /* Treat the parent and all its children together as one connection, -+ except for the purpose of setting conntrack->layer7.app_proto in the -+ actual connection. This makes /proc/net/ip_conntrack somewhat more -+ satisfying. */ -+ if(!(conntrack = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) || -+ !(master_conntrack = ip_conntrack_get((struct sk_buff *)skb, &master_ctinfo))) { -+ DPRINTK("layer7: packet is not from a known connection, giving up.\n"); -+ return info->invert; -+ } -+ -+ /* Try to get a master conntrack (and its master etc) for FTP, etc. */ -+ while (master_ct(master_conntrack) != NULL) -+ master_conntrack = master_ct(master_conntrack); -+ -+ if(!skb->cb[0]){ -+ WRITE_LOCK(&ct_lock); -+ master_conntrack->layer7.numpackets++;/*starts at 0 via memset*/ -+ WRITE_UNLOCK(&ct_lock); -+ } -+ -+ /* if we've classified it or seen too many packets */ -+ if(TOTAL_PACKETS > num_packets || -+ master_conntrack->layer7.app_proto) { -+ -+ pattern_result = match_no_append(conntrack, master_conntrack, ctinfo, master_ctinfo, info); -+ -+ /* skb->cb[0] == seen. Avoid doing things twice if there are two l7 -+ rules. I'm not sure that using cb for this purpose is correct, although -+ it says "put your private variables there". But it doesn't look like it -+ is being used for anything else in the skbs that make it here. How can -+ I write to cb without making the compiler angry? */ -+ skb->cb[0] = 1; /* marking it seen here is probably irrelevant, but consistant */ -+ -+ return (pattern_result ^ info->invert); -+ } -+ -+ if(skb_is_nonlinear(skb)){ -+ if(skb_linearize(skb, GFP_ATOMIC) != 0){ -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: failed to linearize packet, bailing.\n"); -+ return info->invert; -+ } -+ } -+ -+ /* now that the skb is linearized, it's safe to set these. */ -+ app_data = skb->data + app_data_offset(skb); -+ appdatalen = skb->tail - app_data; -+ -+ LOCK_BH(&list_lock); -+ /* the return value gets checked later, when we're ready to use it */ -+ comppattern = compile_and_cache(info->pattern, info->protocol); -+ UNLOCK_BH(&list_lock); -+ -+ /* On the first packet of a connection, allocate space for app data */ -+ WRITE_LOCK(&ct_lock); -+ if(TOTAL_PACKETS == 1 && !skb->cb[0] && !master_conntrack->layer7.app_data) { -+ master_conntrack->layer7.app_data = kmalloc(CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN, GFP_ATOMIC); -+ if(!master_conntrack->layer7.app_data){ -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); -+ WRITE_UNLOCK(&ct_lock); -+ return info->invert; -+ } -+ -+ master_conntrack->layer7.app_data[0] = '\0'; -+ } -+ WRITE_UNLOCK(&ct_lock); -+ -+ /* Can be here, but unallocated, if numpackets is increased near -+ the beginning of a connection */ -+ if(master_conntrack->layer7.app_data == NULL) -+ return (info->invert); /* unmatched */ -+ -+ if(!skb->cb[0]){ -+ int newbytes; -+ WRITE_LOCK(&ct_lock); -+ newbytes = add_data(master_conntrack, app_data, appdatalen); -+ WRITE_UNLOCK(&ct_lock); -+ -+ if(newbytes == 0) { /* didn't add any data */ -+ skb->cb[0] = 1; -+ /* Didn't match before, not going to match now */ -+ return info->invert; -+ } -+ } -+ -+ /* If looking for "unknown", then never match. "Unknown" means that -+ we've given up; we're still trying with these packets. */ -+ if(!strcmp(info->protocol, "unknown")) { -+ pattern_result = 0; -+ /* If the regexp failed to compile, don't bother running it */ -+ } else if(comppattern && regexec(comppattern, master_conntrack->layer7.app_data)) { -+ DPRINTK("layer7: regexec positive: %s!\n", info->protocol); -+ pattern_result = 1; -+ } else pattern_result = 0; -+ -+ if(pattern_result) { -+ WRITE_LOCK(&ct_lock); -+ master_conntrack->layer7.app_proto = kmalloc(strlen(info->protocol)+1, GFP_ATOMIC); -+ if(!master_conntrack->layer7.app_proto){ -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); -+ WRITE_UNLOCK(&ct_lock); -+ return (pattern_result ^ info->invert); -+ } -+ strcpy(master_conntrack->layer7.app_proto, info->protocol); -+ WRITE_UNLOCK(&ct_lock); -+ } -+ -+ /* mark the packet seen */ -+ skb->cb[0] = 1; -+ -+ return (pattern_result ^ info->invert); -+} -+ -+static int checkentry(const char *tablename, const struct ipt_ip *ip, -+ void *matchinfo, unsigned int matchsize, unsigned int hook_mask) -+{ -+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_layer7_info))) -+ return 0; -+ return 1; -+} -+ -+static struct ipt_match layer7_match = { -+ .name = "layer7", -+ .match = &match, -+ .checkentry = &checkentry, -+ .me = THIS_MODULE -+}; -+ -+/* taken from drivers/video/modedb.c */ -+static int my_atoi(const char *s) -+{ -+ int val = 0; -+ -+ for (;; s++) { -+ switch (*s) { -+ case '0'...'9': -+ val = 10*val+(*s-'0'); -+ break; -+ default: -+ return val; -+ } -+ } -+} -+ -+/* write out num_packets to userland. */ -+static int layer7_read_proc(char* page, char ** start, off_t off, int count, -+ int* eof, void * data) -+{ -+ if(num_packets > 99 && net_ratelimit()) -+ printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n"); -+ -+ page[0] = num_packets/10 + '0'; -+ page[1] = num_packets%10 + '0'; -+ page[2] = '\n'; -+ page[3] = '\0'; -+ -+ *eof=1; -+ -+ return 3; -+} -+ -+/* Read in num_packets from userland */ -+static int layer7_write_proc(struct file* file, const char* buffer, -+ unsigned long count, void *data) -+{ -+ char * foo = kmalloc(count, GFP_ATOMIC); -+ -+ if(!foo){ -+ if (net_ratelimit()) -+ printk(KERN_ERR "layer7: out of memory, bailing. num_packets unchanged.\n"); -+ return count; -+ } -+ -+ copy_from_user(foo, buffer, count); -+ -+ num_packets = my_atoi(foo); -+ kfree (foo); -+ -+ /* This has an arbitrary limit to make the math easier. I'm lazy. -+ But anyway, 99 is a LOT! If you want more, you're doing it wrong! */ -+ if(num_packets > 99) { -+ printk(KERN_WARNING "layer7: num_packets can't be > 99.\n"); -+ num_packets = 99; -+ } else if(num_packets < 1) { -+ printk(KERN_WARNING "layer7: num_packets can't be < 1.\n"); -+ num_packets = 1; -+ } -+ -+ return count; -+} -+ -+/* register the proc file */ -+static void layer7_init_proc(void) -+{ -+ struct proc_dir_entry* entry; -+ entry = create_proc_entry("layer7_numpackets", 0644, proc_net); -+ entry->read_proc = layer7_read_proc; -+ entry->write_proc = layer7_write_proc; -+} -+ -+static void layer7_cleanup_proc(void) -+{ -+ remove_proc_entry("layer7_numpackets", proc_net); -+} -+ -+static int __init init(void) -+{ -+ layer7_init_proc(); -+ return ipt_register_match(&layer7_match); -+} -+ -+static void __exit fini(void) -+{ -+ layer7_cleanup_proc(); -+ ipt_unregister_match(&layer7_match); -+} -+ -+module_init(init); -+module_exit(fini); -diff -Nurp linux-2.4.30/net/ipv4/netfilter/regexp/regexp.c linux-2.4.30-layer7/net/ipv4/netfilter/regexp/regexp.c ---- linux-2.4.30/net/ipv4/netfilter/regexp/regexp.c 1969-12-31 18:00:00.000000000 -0600 -+++ linux-2.4.30-layer7/net/ipv4/netfilter/regexp/regexp.c 2005-05-03 18:37:03.000000000 -0500 -@@ -0,0 +1,1195 @@ -+/* -+ * regcomp and regexec -- regsub and regerror are elsewhere -+ * @(#)regexp.c 1.3 of 18 April 87 -+ * -+ * Copyright (c) 1986 by University of Toronto. -+ * Written by Henry Spencer. Not derived from licensed software. -+ * -+ * Permission is granted to anyone to use this software for any -+ * purpose on any computer system, and to redistribute it freely, -+ * subject to the following restrictions: -+ * -+ * 1. The author is not responsible for the consequences of use of -+ * this software, no matter how awful, even if they arise -+ * from defects in it. -+ * -+ * 2. The origin of this software must not be misrepresented, either -+ * by explicit claim or by omission. -+ * -+ * 3. Altered versions must be plainly marked as such, and must not -+ * be misrepresented as being the original software. -+ * -+ * Beware that some of this code is subtly aware of the way operator -+ * precedence is structured in regular expressions. Serious changes in -+ * regular-expression syntax might require a total rethink. -+ * -+ * This code was modified by Ethan Sommer to work within the kernel -+ * (it now uses kmalloc etc..) -+ * -+ * Modified slightly by Matthew Strait to use more modern C. -+ */ -+ -+#include "regexp.h" -+#include "regmagic.h" -+ -+/* added by ethan and matt. Lets it work in both kernel and user space. -+(So iptables can use it, for instance.) Yea, it goes both ways... */ -+#if __KERNEL__ -+ #define malloc(foo) kmalloc(foo,GFP_ATOMIC) -+#else -+ #define printk(format,args...) printf(format,##args) -+#endif -+ -+void regerror(char * s) -+{ -+ printk("<3>Regexp: %s\n", s); -+ /* NOTREACHED */ -+} -+ -+/* -+ * The "internal use only" fields in regexp.h are present to pass info from -+ * compile to execute that permits the execute phase to run lots faster on -+ * simple cases. They are: -+ * -+ * regstart char that must begin a match; '\0' if none obvious -+ * reganch is the match anchored (at beginning-of-line only)? -+ * regmust string (pointer into program) that match must include, or NULL -+ * regmlen length of regmust string -+ * -+ * Regstart and reganch permit very fast decisions on suitable starting points -+ * for a match, cutting down the work a lot. Regmust permits fast rejection -+ * of lines that cannot possibly match. The regmust tests are costly enough -+ * that regcomp() supplies a regmust only if the r.e. contains something -+ * potentially expensive (at present, the only such thing detected is * or + -+ * at the start of the r.e., which can involve a lot of backup). Regmlen is -+ * supplied because the test in regexec() needs it and regcomp() is computing -+ * it anyway. -+ */ -+ -+/* -+ * Structure for regexp "program". This is essentially a linear encoding -+ * of a nondeterministic finite-state machine (aka syntax charts or -+ * "railroad normal form" in parsing technology). Each node is an opcode -+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of -+ * all nodes except BRANCH implement concatenation; a "next" pointer with -+ * a BRANCH on both ends of it is connecting two alternatives. (Here we -+ * have one of the subtle syntax dependencies: an individual BRANCH (as -+ * opposed to a collection of them) is never concatenated with anything -+ * because of operator precedence.) The operand of some types of node is -+ * a literal string; for others, it is a node leading into a sub-FSM. In -+ * particular, the operand of a BRANCH node is the first node of the branch. -+ * (NB this is *not* a tree structure: the tail of the branch connects -+ * to the thing following the set of BRANCHes.) The opcodes are: -+ */ -+ -+/* definition number opnd? meaning */ -+#define END 0 /* no End of program. */ -+#define BOL 1 /* no Match "" at beginning of line. */ -+#define EOL 2 /* no Match "" at end of line. */ -+#define ANY 3 /* no Match any one character. */ -+#define ANYOF 4 /* str Match any character in this string. */ -+#define ANYBUT 5 /* str Match any character not in this string. */ -+#define BRANCH 6 /* node Match this alternative, or the next... */ -+#define BACK 7 /* no Match "", "next" ptr points backward. */ -+#define EXACTLY 8 /* str Match this string. */ -+#define NOTHING 9 /* no Match empty string. */ -+#define STAR 10 /* node Match this (simple) thing 0 or more times. */ -+#define PLUS 11 /* node Match this (simple) thing 1 or more times. */ -+#define OPEN 20 /* no Mark this point in input as start of #n. */ -+ /* OPEN+1 is number 1, etc. */ -+#define CLOSE 30 /* no Analogous to OPEN. */ -+ -+/* -+ * Opcode notes: -+ * -+ * BRANCH The set of branches constituting a single choice are hooked -+ * together with their "next" pointers, since precedence prevents -+ * anything being concatenated to any individual branch. The -+ * "next" pointer of the last BRANCH in a choice points to the -+ * thing following the whole choice. This is also where the -+ * final "next" pointer of each individual branch points; each -+ * branch starts with the operand node of a BRANCH node. -+ * -+ * BACK Normal "next" pointers all implicitly point forward; BACK -+ * exists to make loop structures possible. -+ * -+ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular -+ * BRANCH structures using BACK. Simple cases (one character -+ * per match) are implemented with STAR and PLUS for speed -+ * and to minimize recursive plunges. -+ * -+ * OPEN,CLOSE ...are numbered at compile time. -+ */ -+ -+/* -+ * A node is one char of opcode followed by two chars of "next" pointer. -+ * "Next" pointers are stored as two 8-bit pieces, high order first. The -+ * value is a positive offset from the opcode of the node containing it. -+ * An operand, if any, simply follows the node. (Note that much of the -+ * code generation knows about this implicit relationship.) -+ * -+ * Using two bytes for the "next" pointer is vast overkill for most things, -+ * but allows patterns to get big without disasters. -+ */ -+#define OP(p) (*(p)) -+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) -+#define OPERAND(p) ((p) + 3) -+ -+/* -+ * See regmagic.h for one further detail of program structure. -+ */ -+ -+ -+/* -+ * Utility definitions. -+ */ -+#ifndef CHARBITS -+#define UCHARAT(p) ((int)*(unsigned char *)(p)) -+#else -+#define UCHARAT(p) ((int)*(p)&CHARBITS) -+#endif -+ -+#define FAIL(m) { regerror(m); return(NULL); } -+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') -+#define META "^$.[()|?+*\\" -+ -+/* -+ * Flags to be passed up and down. -+ */ -+#define HASWIDTH 01 /* Known never to match null string. */ -+#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ -+#define SPSTART 04 /* Starts with * or +. */ -+#define WORST 0 /* Worst case. */ -+ -+/* -+ * Global work variables for regcomp(). -+ */ -+static char *regparse; /* Input-scan pointer. */ -+static int regnpar; /* () count. */ -+static char regdummy; -+static char *regcode; /* Code-emit pointer; ®dummy = don't. */ -+static long regsize; /* Code size. */ -+ -+/* -+ * Forward declarations for regcomp()'s friends. -+ */ -+#ifndef STATIC -+#define STATIC static -+#endif -+STATIC char *reg(int paren,int *flagp); -+STATIC char *regbranch(int *flagp); -+STATIC char *regpiece(int *flagp); -+STATIC char *regatom(int *flagp); -+STATIC char *regnode(char op); -+STATIC char *regnext(char *p); -+STATIC void regc(char b); -+STATIC void reginsert(char op, char *opnd); -+STATIC void regtail(char *p, char *val); -+STATIC void regoptail(char *p, char *val); -+ -+ -+__kernel_size_t my_strcspn(const char *s1,const char *s2) -+{ -+ char *scan1; -+ char *scan2; -+ int count; -+ -+ count = 0; -+ for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) { -+ for (scan2 = (char *)s2; *scan2 != '\0';) /* ++ moved down. */ -+ if (*scan1 == *scan2++) -+ return(count); -+ count++; -+ } -+ return(count); -+} -+ -+/* -+ - regcomp - compile a regular expression into internal code -+ * -+ * We can't allocate space until we know how big the compiled form will be, -+ * but we can't compile it (and thus know how big it is) until we've got a -+ * place to put the code. So we cheat: we compile it twice, once with code -+ * generation turned off and size counting turned on, and once "for real". -+ * This also means that we don't allocate space until we are sure that the -+ * thing really will compile successfully, and we never have to move the -+ * code and thus invalidate pointers into it. (Note that it has to be in -+ * one piece because free() must be able to free it all.) -+ * -+ * Beware that the optimization-preparation code in here knows about some -+ * of the structure of the compiled regexp. -+ */ -+regexp * -+regcomp(char *exp,int *patternsize) -+{ -+ register regexp *r; -+ register char *scan; -+ register char *longest; -+ register int len; -+ int flags; -+ /* commented out by ethan -+ extern char *malloc(); -+ */ -+ -+ if (exp == NULL) -+ FAIL("NULL argument"); -+ -+ /* First pass: determine size, legality. */ -+ regparse = exp; -+ regnpar = 1; -+ regsize = 0L; -+ regcode = ®dummy; -+ regc(MAGIC); -+ if (reg(0, &flags) == NULL) -+ return(NULL); -+ -+ /* Small enough for pointer-storage convention? */ -+ if (regsize >= 32767L) /* Probably could be 65535L. */ -+ FAIL("regexp too big"); -+ -+ /* Allocate space. */ -+ *patternsize=sizeof(regexp) + (unsigned)regsize; -+ r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); -+ if (r == NULL) -+ FAIL("out of space"); -+ -+ /* Second pass: emit code. */ -+ regparse = exp; -+ regnpar = 1; -+ regcode = r->program; -+ regc(MAGIC); -+ if (reg(0, &flags) == NULL) -+ return(NULL); -+ -+ /* Dig out information for optimizations. */ -+ r->regstart = '\0'; /* Worst-case defaults. */ -+ r->reganch = 0; -+ r->regmust = NULL; -+ r->regmlen = 0; -+ scan = r->program+1; /* First BRANCH. */ -+ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ -+ scan = OPERAND(scan); -+ -+ /* Starting-point info. */ -+ if (OP(scan) == EXACTLY) -+ r->regstart = *OPERAND(scan); -+ else if (OP(scan) == BOL) -+ r->reganch++; -+ -+ /* -+ * If there's something expensive in the r.e., find the -+ * longest literal string that must appear and make it the -+ * regmust. Resolve ties in favor of later strings, since -+ * the regstart check works with the beginning of the r.e. -+ * and avoiding duplication strengthens checking. Not a -+ * strong reason, but sufficient in the absence of others. -+ */ -+ if (flags&SPSTART) { -+ longest = NULL; -+ len = 0; -+ for (; scan != NULL; scan = regnext(scan)) -+ if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) { -+ longest = OPERAND(scan); -+ len = strlen(OPERAND(scan)); -+ } -+ r->regmust = longest; -+ r->regmlen = len; -+ } -+ } -+ -+ return(r); -+} -+ -+/* -+ - reg - regular expression, i.e. main body or parenthesized thing -+ * -+ * Caller must absorb opening parenthesis. -+ * -+ * Combining parenthesis handling with the base level of regular expression -+ * is a trifle forced, but the need to tie the tails of the branches to what -+ * follows makes it hard to avoid. -+ */ -+static char * -+reg(int paren, int *flagp /* Parenthesized? */ ) -+{ -+ register char *ret; -+ register char *br; -+ register char *ender; -+ register int parno = 0; /* 0 makes gcc happy */ -+ int flags; -+ -+ *flagp = HASWIDTH; /* Tentatively. */ -+ -+ /* Make an OPEN node, if parenthesized. */ -+ if (paren) { -+ if (regnpar >= NSUBEXP) -+ FAIL("too many ()"); -+ parno = regnpar; -+ regnpar++; -+ ret = regnode(OPEN+parno); -+ } else -+ ret = NULL; -+ -+ /* Pick up the branches, linking them together. */ -+ br = regbranch(&flags); -+ if (br == NULL) -+ return(NULL); -+ if (ret != NULL) -+ regtail(ret, br); /* OPEN -> first. */ -+ else -+ ret = br; -+ if (!(flags&HASWIDTH)) -+ *flagp &= ~HASWIDTH; -+ *flagp |= flags&SPSTART; -+ while (*regparse == '|') { -+ regparse++; -+ br = regbranch(&flags); -+ if (br == NULL) -+ return(NULL); -+ regtail(ret, br); /* BRANCH -> BRANCH. */ -+ if (!(flags&HASWIDTH)) -+ *flagp &= ~HASWIDTH; -+ *flagp |= flags&SPSTART; -+ } -+ -+ /* Make a closing node, and hook it on the end. */ -+ ender = regnode((paren) ? CLOSE+parno : END); -+ regtail(ret, ender); -+ -+ /* Hook the tails of the branches to the closing node. */ -+ for (br = ret; br != NULL; br = regnext(br)) -+ regoptail(br, ender); -+ -+ /* Check for proper termination. */ -+ if (paren && *regparse++ != ')') { -+ FAIL("unmatched ()"); -+ } else if (!paren && *regparse != '\0') { -+ if (*regparse == ')') { -+ FAIL("unmatched ()"); -+ } else -+ FAIL("junk on end"); /* "Can't happen". */ -+ /* NOTREACHED */ -+ } -+ -+ return(ret); -+} -+ -+/* -+ - regbranch - one alternative of an | operator -+ * -+ * Implements the concatenation operator. -+ */ -+static char * -+regbranch(int *flagp) -+{ -+ register char *ret; -+ register char *chain; -+ register char *latest; -+ int flags; -+ -+ *flagp = WORST; /* Tentatively. */ -+ -+ ret = regnode(BRANCH); -+ chain = NULL; -+ while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { -+ latest = regpiece(&flags); -+ if (latest == NULL) -+ return(NULL); -+ *flagp |= flags&HASWIDTH; -+ if (chain == NULL) /* First piece. */ -+ *flagp |= flags&SPSTART; -+ else -+ regtail(chain, latest); -+ chain = latest; -+ } -+ if (chain == NULL) /* Loop ran zero times. */ -+ (void) regnode(NOTHING); -+ -+ return(ret); -+} -+ -+/* -+ - regpiece - something followed by possible [*+?] -+ * -+ * Note that the branching code sequences used for ? and the general cases -+ * of * and + are somewhat optimized: they use the same NOTHING node as -+ * both the endmarker for their branch list and the body of the last branch. -+ * It might seem that this node could be dispensed with entirely, but the -+ * endmarker role is not redundant. -+ */ -+static char * -+regpiece(int *flagp) -+{ -+ register char *ret; -+ register char op; -+ register char *next; -+ int flags; -+ -+ ret = regatom(&flags); -+ if (ret == NULL) -+ return(NULL); -+ -+ op = *regparse; -+ if (!ISMULT(op)) { -+ *flagp = flags; -+ return(ret); -+ } -+ -+ if (!(flags&HASWIDTH) && op != '?') -+ FAIL("*+ operand could be empty"); -+ *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); -+ -+ if (op == '*' && (flags&SIMPLE)) -+ reginsert(STAR, ret); -+ else if (op == '*') { -+ /* Emit x* as (x&|), where & means "self". */ -+ reginsert(BRANCH, ret); /* Either x */ -+ regoptail(ret, regnode(BACK)); /* and loop */ -+ regoptail(ret, ret); /* back */ -+ regtail(ret, regnode(BRANCH)); /* or */ -+ regtail(ret, regnode(NOTHING)); /* null. */ -+ } else if (op == '+' && (flags&SIMPLE)) -+ reginsert(PLUS, ret); -+ else if (op == '+') { -+ /* Emit x+ as x(&|), where & means "self". */ -+ next = regnode(BRANCH); /* Either */ -+ regtail(ret, next); -+ regtail(regnode(BACK), ret); /* loop back */ -+ regtail(next, regnode(BRANCH)); /* or */ -+ regtail(ret, regnode(NOTHING)); /* null. */ -+ } else if (op == '?') { -+ /* Emit x? as (x|) */ -+ reginsert(BRANCH, ret); /* Either x */ -+ regtail(ret, regnode(BRANCH)); /* or */ -+ next = regnode(NOTHING); /* null. */ -+ regtail(ret, next); -+ regoptail(ret, next); -+ } -+ regparse++; -+ if (ISMULT(*regparse)) -+ FAIL("nested *?+"); -+ -+ return(ret); -+} -+ -+/* -+ - regatom - the lowest level -+ * -+ * Optimization: gobbles an entire sequence of ordinary characters so that -+ * it can turn them into a single node, which is smaller to store and -+ * faster to run. Backslashed characters are exceptions, each becoming a -+ * separate node; the code is simpler that way and it's not worth fixing. -+ */ -+static char * -+regatom(int *flagp) -+{ -+ register char *ret; -+ int flags; -+ -+ *flagp = WORST; /* Tentatively. */ -+ -+ switch (*regparse++) { -+ case '^': -+ ret = regnode(BOL); -+ break; -+ case '$': -+ ret = regnode(EOL); -+ break; -+ case '.': -+ ret = regnode(ANY); -+ *flagp |= HASWIDTH|SIMPLE; -+ break; -+ case '[': { -+ register int class; -+ register int classend; -+ -+ if (*regparse == '^') { /* Complement of range. */ -+ ret = regnode(ANYBUT); -+ regparse++; -+ } else -+ ret = regnode(ANYOF); -+ if (*regparse == ']' || *regparse == '-') -+ regc(*regparse++); -+ while (*regparse != '\0' && *regparse != ']') { -+ if (*regparse == '-') { -+ regparse++; -+ if (*regparse == ']' || *regparse == '\0') -+ regc('-'); -+ else { -+ class = UCHARAT(regparse-2)+1; -+ classend = UCHARAT(regparse); -+ if (class > classend+1) -+ FAIL("invalid [] range"); -+ for (; class <= classend; class++) -+ regc(class); -+ regparse++; -+ } -+ } else -+ regc(*regparse++); -+ } -+ regc('\0'); -+ if (*regparse != ']') -+ FAIL("unmatched []"); -+ regparse++; -+ *flagp |= HASWIDTH|SIMPLE; -+ } -+ break; -+ case '(': -+ ret = reg(1, &flags); -+ if (ret == NULL) -+ return(NULL); -+ *flagp |= flags&(HASWIDTH|SPSTART); -+ break; -+ case '\0': -+ case '|': -+ case ')': -+ FAIL("internal urp"); /* Supposed to be caught earlier. */ -+ break; -+ case '?': -+ case '+': -+ case '*': -+ FAIL("?+* follows nothing"); -+ break; -+ case '\\': -+ if (*regparse == '\0') -+ FAIL("trailing \\"); -+ ret = regnode(EXACTLY); -+ regc(*regparse++); -+ regc('\0'); -+ *flagp |= HASWIDTH|SIMPLE; -+ break; -+ default: { -+ register int len; -+ register char ender; -+ -+ regparse--; -+ len = my_strcspn((const char *)regparse, (const char *)META); -+ if (len <= 0) -+ FAIL("internal disaster"); -+ ender = *(regparse+len); -+ if (len > 1 && ISMULT(ender)) -+ len--; /* Back off clear of ?+* operand. */ -+ *flagp |= HASWIDTH; -+ if (len == 1) -+ *flagp |= SIMPLE; -+ ret = regnode(EXACTLY); -+ while (len > 0) { -+ regc(*regparse++); -+ len--; -+ } -+ regc('\0'); -+ } -+ break; -+ } -+ -+ return(ret); -+} -+ -+/* -+ - regnode - emit a node -+ */ -+static char * /* Location. */ -+regnode(char op) -+{ -+ register char *ret; -+ register char *ptr; -+ -+ ret = regcode; -+ if (ret == ®dummy) { -+ regsize += 3; -+ return(ret); -+ } -+ -+ ptr = ret; -+ *ptr++ = op; -+ *ptr++ = '\0'; /* Null "next" pointer. */ -+ *ptr++ = '\0'; -+ regcode = ptr; -+ -+ return(ret); -+} -+ -+/* -+ - regc - emit (if appropriate) a byte of code -+ */ -+static void -+regc(char b) -+{ -+ if (regcode != ®dummy) -+ *regcode++ = b; -+ else -+ regsize++; -+} -+ -+/* -+ - reginsert - insert an operator in front of already-emitted operand -+ * -+ * Means relocating the operand. -+ */ -+static void -+reginsert(char op, char* opnd) -+{ -+ register char *src; -+ register char *dst; -+ register char *place; -+ -+ if (regcode == ®dummy) { -+ regsize += 3; -+ return; -+ } -+ -+ src = regcode; -+ regcode += 3; -+ dst = regcode; -+ while (src > opnd) -+ *--dst = *--src; -+ -+ place = opnd; /* Op node, where operand used to be. */ -+ *place++ = op; -+ *place++ = '\0'; -+ *place++ = '\0'; -+} -+ -+/* -+ - regtail - set the next-pointer at the end of a node chain -+ */ -+static void -+regtail(char *p, char *val) -+{ -+ register char *scan; -+ register char *temp; -+ register int offset; -+ -+ if (p == ®dummy) -+ return; -+ -+ /* Find last node. */ -+ scan = p; -+ for (;;) { -+ temp = regnext(scan); -+ if (temp == NULL) -+ break; -+ scan = temp; -+ } -+ -+ if (OP(scan) == BACK) -+ offset = scan - val; -+ else -+ offset = val - scan; -+ *(scan+1) = (offset>>8)&0377; -+ *(scan+2) = offset&0377; -+} -+ -+/* -+ - regoptail - regtail on operand of first argument; nop if operandless -+ */ -+static void -+regoptail(char *p, char *val) -+{ -+ /* "Operandless" and "op != BRANCH" are synonymous in practice. */ -+ if (p == NULL || p == ®dummy || OP(p) != BRANCH) -+ return; -+ regtail(OPERAND(p), val); -+} -+ -+/* -+ * regexec and friends -+ */ -+ -+/* -+ * Global work variables for regexec(). -+ */ -+static char *reginput; /* String-input pointer. */ -+static char *regbol; /* Beginning of input, for ^ check. */ -+static char **regstartp; /* Pointer to startp array. */ -+static char **regendp; /* Ditto for endp. */ -+ -+/* -+ * Forwards. -+ */ -+STATIC int regtry(regexp *prog, char *string); -+STATIC int regmatch(char *prog); -+STATIC int regrepeat(char *p); -+ -+#ifdef DEBUG -+int regnarrate = 0; -+void regdump(); -+STATIC char *regprop(char *op); -+#endif -+ -+/* -+ - regexec - match a regexp against a string -+ */ -+int -+regexec(regexp *prog, char *string) -+{ -+ register char *s; -+ -+ /* Be paranoid... */ -+ if (prog == NULL || string == NULL) { -+ printk("<3>Regexp: NULL parameter\n"); -+ return(0); -+ } -+ -+ /* Check validity of program. */ -+ if (UCHARAT(prog->program) != MAGIC) { -+ printk("<3>Regexp: corrupted program\n"); -+ return(0); -+ } -+ -+ /* If there is a "must appear" string, look for it. */ -+ if (prog->regmust != NULL) { -+ s = string; -+ while ((s = strchr(s, prog->regmust[0])) != NULL) { -+ if (strncmp(s, prog->regmust, prog->regmlen) == 0) -+ break; /* Found it. */ -+ s++; -+ } -+ if (s == NULL) /* Not present. */ -+ return(0); -+ } -+ -+ /* Mark beginning of line for ^ . */ -+ regbol = string; -+ -+ /* Simplest case: anchored match need be tried only once. */ -+ if (prog->reganch) -+ return(regtry(prog, string)); -+ -+ /* Messy cases: unanchored match. */ -+ s = string; -+ if (prog->regstart != '\0') -+ /* We know what char it must start with. */ -+ while ((s = strchr(s, prog->regstart)) != NULL) { -+ if (regtry(prog, s)) -+ return(1); -+ s++; -+ } -+ else -+ /* We don't -- general case. */ -+ do { -+ if (regtry(prog, s)) -+ return(1); -+ } while (*s++ != '\0'); -+ -+ /* Failure. */ -+ return(0); -+} -+ -+/* -+ - regtry - try match at specific point -+ */ -+static int /* 0 failure, 1 success */ -+regtry(regexp *prog, char *string) -+{ -+ register int i; -+ register char **sp; -+ register char **ep; -+ -+ reginput = string; -+ regstartp = prog->startp; -+ regendp = prog->endp; -+ -+ sp = prog->startp; -+ ep = prog->endp; -+ for (i = NSUBEXP; i > 0; i--) { -+ *sp++ = NULL; -+ *ep++ = NULL; -+ } -+ if (regmatch(prog->program + 1)) { -+ prog->startp[0] = string; -+ prog->endp[0] = reginput; -+ return(1); -+ } else -+ return(0); -+} -+ -+/* -+ - regmatch - main matching routine -+ * -+ * Conceptually the strategy is simple: check to see whether the current -+ * node matches, call self recursively to see whether the rest matches, -+ * and then act accordingly. In practice we make some effort to avoid -+ * recursion, in particular by going through "ordinary" nodes (that don't -+ * need to know whether the rest of the match failed) by a loop instead of -+ * by recursion. -+ */ -+static int /* 0 failure, 1 success */ -+regmatch(char *prog) -+{ -+ register char *scan = prog; /* Current node. */ -+ char *next; /* Next node. */ -+ -+#ifdef DEBUG -+ if (scan != NULL && regnarrate) -+ fprintf(stderr, "%s(\n", regprop(scan)); -+#endif -+ while (scan != NULL) { -+#ifdef DEBUG -+ if (regnarrate) -+ fprintf(stderr, "%s...\n", regprop(scan)); -+#endif -+ next = regnext(scan); -+ -+ switch (OP(scan)) { -+ case BOL: -+ if (reginput != regbol) -+ return(0); -+ break; -+ case EOL: -+ if (*reginput != '\0') -+ return(0); -+ break; -+ case ANY: -+ if (*reginput == '\0') -+ return(0); -+ reginput++; -+ break; -+ case EXACTLY: { -+ register int len; -+ register char *opnd; -+ -+ opnd = OPERAND(scan); -+ /* Inline the first character, for speed. */ -+ if (*opnd != *reginput) -+ return(0); -+ len = strlen(opnd); -+ if (len > 1 && strncmp(opnd, reginput, len) != 0) -+ return(0); -+ reginput += len; -+ } -+ break; -+ case ANYOF: -+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) -+ return(0); -+ reginput++; -+ break; -+ case ANYBUT: -+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) -+ return(0); -+ reginput++; -+ break; -+ case NOTHING: -+ case BACK: -+ break; -+ case OPEN+1: -+ case OPEN+2: -+ case OPEN+3: -+ case OPEN+4: -+ case OPEN+5: -+ case OPEN+6: -+ case OPEN+7: -+ case OPEN+8: -+ case OPEN+9: { -+ register int no; -+ register char *save; -+ -+ no = OP(scan) - OPEN; -+ save = reginput; -+ -+ if (regmatch(next)) { -+ /* -+ * Don't set startp if some later -+ * invocation of the same parentheses -+ * already has. -+ */ -+ if (regstartp[no] == NULL) -+ regstartp[no] = save; -+ return(1); -+ } else -+ return(0); -+ } -+ break; -+ case CLOSE+1: -+ case CLOSE+2: -+ case CLOSE+3: -+ case CLOSE+4: -+ case CLOSE+5: -+ case CLOSE+6: -+ case CLOSE+7: -+ case CLOSE+8: -+ case CLOSE+9: -+ { -+ register int no; -+ register char *save; -+ -+ no = OP(scan) - CLOSE; -+ save = reginput; -+ -+ if (regmatch(next)) { -+ /* -+ * Don't set endp if some later -+ * invocation of the same parentheses -+ * already has. -+ */ -+ if (regendp[no] == NULL) -+ regendp[no] = save; -+ return(1); -+ } else -+ return(0); -+ } -+ break; -+ case BRANCH: { -+ register char *save; -+ -+ if (OP(next) != BRANCH) /* No choice. */ -+ next = OPERAND(scan); /* Avoid recursion. */ -+ else { -+ do { -+ save = reginput; -+ if (regmatch(OPERAND(scan))) -+ return(1); -+ reginput = save; -+ scan = regnext(scan); -+ } while (scan != NULL && OP(scan) == BRANCH); -+ return(0); -+ /* NOTREACHED */ -+ } -+ } -+ break; -+ case STAR: -+ case PLUS: { -+ register char nextch; -+ register int no; -+ register char *save; -+ register int min; -+ -+ /* -+ * Lookahead to avoid useless match attempts -+ * when we know what character comes next. -+ */ -+ nextch = '\0'; -+ if (OP(next) == EXACTLY) -+ nextch = *OPERAND(next); -+ min = (OP(scan) == STAR) ? 0 : 1; -+ save = reginput; -+ no = regrepeat(OPERAND(scan)); -+ while (no >= min) { -+ /* If it could work, try it. */ -+ if (nextch == '\0' || *reginput == nextch) -+ if (regmatch(next)) -+ return(1); -+ /* Couldn't or didn't -- back up. */ -+ no--; -+ reginput = save + no; -+ } -+ return(0); -+ } -+ break; -+ case END: -+ return(1); /* Success! */ -+ break; -+ default: -+ printk("<3>Regexp: memory corruption\n"); -+ return(0); -+ break; -+ } -+ -+ scan = next; -+ } -+ -+ /* -+ * We get here only if there's trouble -- normally "case END" is -+ * the terminating point. -+ */ -+ printk("<3>Regexp: corrupted pointers\n"); -+ return(0); -+} -+ -+/* -+ - regrepeat - repeatedly match something simple, report how many -+ */ -+static int -+regrepeat(char *p) -+{ -+ register int count = 0; -+ register char *scan; -+ register char *opnd; -+ -+ scan = reginput; -+ opnd = OPERAND(p); -+ switch (OP(p)) { -+ case ANY: -+ count = strlen(scan); -+ scan += count; -+ break; -+ case EXACTLY: -+ while (*opnd == *scan) { -+ count++; -+ scan++; -+ } -+ break; -+ case ANYOF: -+ while (*scan != '\0' && strchr(opnd, *scan) != NULL) { -+ count++; -+ scan++; -+ } -+ break; -+ case ANYBUT: -+ while (*scan != '\0' && strchr(opnd, *scan) == NULL) { -+ count++; -+ scan++; -+ } -+ break; -+ default: /* Oh dear. Called inappropriately. */ -+ printk("<3>Regexp: internal foulup\n"); -+ count = 0; /* Best compromise. */ -+ break; -+ } -+ reginput = scan; -+ -+ return(count); -+} -+ -+/* -+ - regnext - dig the "next" pointer out of a node -+ */ -+static char* -+regnext(char *p) -+{ -+ register int offset; -+ -+ if (p == ®dummy) -+ return(NULL); -+ -+ offset = NEXT(p); -+ if (offset == 0) -+ return(NULL); -+ -+ if (OP(p) == BACK) -+ return(p-offset); -+ else -+ return(p+offset); -+} -+ -+#ifdef DEBUG -+ -+STATIC char *regprop(); -+ -+/* -+ - regdump - dump a regexp onto stdout in vaguely comprehensible form -+ */ -+void -+regdump(regexp *r) -+{ -+ register char *s; -+ register char op = EXACTLY; /* Arbitrary non-END op. */ -+ register char *next; -+ /* extern char *strchr(); */ -+ -+ -+ s = r->program + 1; -+ while (op != END) { /* While that wasn't END last time... */ -+ op = OP(s); -+ printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ -+ next = regnext(s); -+ if (next == NULL) /* Next ptr. */ -+ printf("(0)"); -+ else -+ printf("(%d)", (s-r->program)+(next-s)); -+ s += 3; -+ if (op == ANYOF || op == ANYBUT || op == EXACTLY) { -+ /* Literal string, where present. */ -+ while (*s != '\0') { -+ putchar(*s); -+ s++; -+ } -+ s++; -+ } -+ putchar('\n'); -+ } -+ -+ /* Header fields of interest. */ -+ if (r->regstart != '\0') -+ printf("start `%c' ", r->regstart); -+ if (r->reganch) -+ printf("anchored "); -+ if (r->regmust != NULL) -+ printf("must have \"%s\"", r->regmust); -+ printf("\n"); -+} -+ -+/* -+ - regprop - printable representation of opcode -+ */ -+static char * -+regprop(char *op) -+{ -+#define BUFLEN 50 -+ register char *p; -+ static char buf[BUFLEN]; -+ -+ strcpy(buf, ":"); -+ -+ switch (OP(op)) { -+ case BOL: -+ p = "BOL"; -+ break; -+ case EOL: -+ p = "EOL"; -+ break; -+ case ANY: -+ p = "ANY"; -+ break; -+ case ANYOF: -+ p = "ANYOF"; -+ break; -+ case ANYBUT: -+ p = "ANYBUT"; -+ break; -+ case BRANCH: -+ p = "BRANCH"; -+ break; -+ case EXACTLY: -+ p = "EXACTLY"; -+ break; -+ case NOTHING: -+ p = "NOTHING"; -+ break; -+ case BACK: -+ p = "BACK"; -+ break; -+ case END: -+ p = "END"; -+ break; -+ case OPEN+1: -+ case OPEN+2: -+ case OPEN+3: -+ case OPEN+4: -+ case OPEN+5: -+ case OPEN+6: -+ case OPEN+7: -+ case OPEN+8: -+ case OPEN+9: -+ snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN); -+ p = NULL; -+ break; -+ case CLOSE+1: -+ case CLOSE+2: -+ case CLOSE+3: -+ case CLOSE+4: -+ case CLOSE+5: -+ case CLOSE+6: -+ case CLOSE+7: -+ case CLOSE+8: -+ case CLOSE+9: -+ snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE); -+ p = NULL; -+ break; -+ case STAR: -+ p = "STAR"; -+ break; -+ case PLUS: -+ p = "PLUS"; -+ break; -+ default: -+ printk("<3>Regexp: corrupted opcode\n"); -+ break; -+ } -+ if (p != NULL) -+ strncat(buf, p, BUFLEN-strlen(buf)); -+ return(buf); -+} -+#endif -+ -+ -diff -Nurp linux-2.4.30/net/ipv4/netfilter/regexp/regexp.h linux-2.4.30-layer7/net/ipv4/netfilter/regexp/regexp.h ---- linux-2.4.30/net/ipv4/netfilter/regexp/regexp.h 1969-12-31 18:00:00.000000000 -0600 -+++ linux-2.4.30-layer7/net/ipv4/netfilter/regexp/regexp.h 2005-05-03 18:37:03.000000000 -0500 -@@ -0,0 +1,40 @@ -+/* -+ * Definitions etc. for regexp(3) routines. -+ * -+ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], -+ * not the System V one. -+ */ -+ -+#ifndef REGEXP_H -+#define REGEXP_H -+ -+/* -+http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h , -+which contains a version of this library, says: -+ -+ * -+ * NSUBEXP must be at least 10, and no greater than 117 or the parser -+ * will not work properly. -+ * -+ -+However, it looks rather like this library is limited to 10. If you think -+otherwise, let us know. -+*/ -+ -+#define NSUBEXP 10 -+typedef struct regexp { -+ char *startp[NSUBEXP]; -+ char *endp[NSUBEXP]; -+ char regstart; /* Internal use only. */ -+ char reganch; /* Internal use only. */ -+ char *regmust; /* Internal use only. */ -+ int regmlen; /* Internal use only. */ -+ char program[1]; /* Unwarranted chumminess with compiler. */ -+} regexp; -+ -+regexp * regcomp(char *exp, int *patternsize); -+int regexec(regexp *prog, char *string); -+void regsub(regexp *prog, char *source, char *dest); -+void regerror(char *s); -+ -+#endif -diff -Nurp linux-2.4.30/net/ipv4/netfilter/regexp/regmagic.h linux-2.4.30-layer7/net/ipv4/netfilter/regexp/regmagic.h ---- linux-2.4.30/net/ipv4/netfilter/regexp/regmagic.h 1969-12-31 18:00:00.000000000 -0600 -+++ linux-2.4.30-layer7/net/ipv4/netfilter/regexp/regmagic.h 2005-05-03 18:37:03.000000000 -0500 -@@ -0,0 +1,5 @@ -+/* -+ * The first byte of the regexp internal "program" is actually this magic -+ * number; the start node begins in the second byte. -+ */ -+#define MAGIC 0234 -diff -Nurp linux-2.4.30/net/ipv4/netfilter/regexp/regsub.c linux-2.4.30-layer7/net/ipv4/netfilter/regexp/regsub.c ---- linux-2.4.30/net/ipv4/netfilter/regexp/regsub.c 1969-12-31 18:00:00.000000000 -0600 -+++ linux-2.4.30-layer7/net/ipv4/netfilter/regexp/regsub.c 2005-05-03 18:37:03.000000000 -0500 -@@ -0,0 +1,95 @@ -+/* -+ * regsub -+ * @(#)regsub.c 1.3 of 2 April 86 -+ * -+ * Copyright (c) 1986 by University of Toronto. -+ * Written by Henry Spencer. Not derived from licensed software. -+ * -+ * Permission is granted to anyone to use this software for any -+ * purpose on any computer system, and to redistribute it freely, -+ * subject to the following restrictions: -+ * -+ * 1. The author is not responsible for the consequences of use of -+ * this software, no matter how awful, even if they arise -+ * from defects in it. -+ * -+ * 2. The origin of this software must not be misrepresented, either -+ * by explicit claim or by omission. -+ * -+ * 3. Altered versions must be plainly marked as such, and must not -+ * be misrepresented as being the original software. -+ * -+ * -+ * This code was modified by Ethan Sommer to work within the kernel -+ * (it now uses kmalloc etc..) -+ * -+ */ -+#include "regexp.h" -+#include "regmagic.h" -+#include <linux/string.h> -+ -+ -+#ifndef CHARBITS -+#define UCHARAT(p) ((int)*(unsigned char *)(p)) -+#else -+#define UCHARAT(p) ((int)*(p)&CHARBITS) -+#endif -+ -+#if 0 -+//void regerror(char * s) -+//{ -+// printk("regexp(3): %s", s); -+// /* NOTREACHED */ -+//} -+#endif -+ -+/* -+ - regsub - perform substitutions after a regexp match -+ */ -+void -+regsub(regexp * prog, char * source, char * dest) -+{ -+ register char *src; -+ register char *dst; -+ register char c; -+ register int no; -+ register int len; -+ -+ /* Not necessary and gcc doesn't like it -MLS */ -+ /*extern char *strncpy();*/ -+ -+ if (prog == NULL || source == NULL || dest == NULL) { -+ regerror("NULL parm to regsub"); -+ return; -+ } -+ if (UCHARAT(prog->program) != MAGIC) { -+ regerror("damaged regexp fed to regsub"); -+ return; -+ } -+ -+ src = source; -+ dst = dest; -+ while ((c = *src++) != '\0') { -+ if (c == '&') -+ no = 0; -+ else if (c == '\\' && '0' <= *src && *src <= '9') -+ no = *src++ - '0'; -+ else -+ no = -1; -+ -+ if (no < 0) { /* Ordinary character. */ -+ if (c == '\\' && (*src == '\\' || *src == '&')) -+ c = *src++; -+ *dst++ = c; -+ } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { -+ len = prog->endp[no] - prog->startp[no]; -+ (void) strncpy(dst, prog->startp[no], len); -+ dst += len; -+ if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */ -+ regerror("damaged match string"); -+ return; -+ } -+ } -+ } -+ *dst++ = '\0'; -+} diff --git a/target/linux/linux-2.4/patches/generic/103-netfilter_nat_pptp.patch b/target/linux/linux-2.4/patches/generic/103-netfilter_nat_pptp.patch deleted file mode 100644 index 6c7d6e6f2..000000000 --- a/target/linux/linux-2.4/patches/generic/103-netfilter_nat_pptp.patch +++ /dev/null @@ -1,2412 +0,0 @@ -diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack.h 2005-04-02 19:04:11.000000000 +0200 -+++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack.h 2005-04-02 19:41:05.000000000 +0200 -@@ -50,16 +50,19 @@ - - #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> - #include <linux/netfilter_ipv4/ip_conntrack_icmp.h> -+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> - - /* per conntrack: protocol private data */ - union ip_conntrack_proto { - /* insert conntrack proto private data here */ - struct ip_ct_tcp tcp; - struct ip_ct_icmp icmp; -+ struct ip_ct_gre gre; - }; - - union ip_conntrack_expect_proto { - /* insert expect proto private data here */ -+ struct ip_ct_gre_expect gre; - }; - - /* Add protocol helper include file here */ -@@ -67,6 +70,7 @@ - - #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> - #include <linux/netfilter_ipv4/ip_conntrack_irc.h> -+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> - - /* per expectation: application helper private data */ - union ip_conntrack_expect_help { -@@ -74,6 +78,7 @@ - struct ip_ct_amanda_expect exp_amanda_info; - struct ip_ct_ftp_expect exp_ftp_info; - struct ip_ct_irc_expect exp_irc_info; -+ struct ip_ct_pptp_expect exp_pptp_info; - - #ifdef CONFIG_IP_NF_NAT_NEEDED - union { -@@ -87,14 +92,17 @@ - /* insert conntrack helper private data (master) here */ - struct ip_ct_ftp_master ct_ftp_info; - struct ip_ct_irc_master ct_irc_info; -+ struct ip_ct_pptp_master ct_pptp_info; - }; - - #ifdef CONFIG_IP_NF_NAT_NEEDED - #include <linux/netfilter_ipv4/ip_nat.h> -+#include <linux/netfilter_ipv4/ip_nat_pptp.h> - - /* per conntrack: nat application helper private data */ - union ip_conntrack_nat_help { - /* insert nat helper private data here */ -+ struct ip_nat_pptp nat_pptp_info; - }; - #endif - -diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_pptp.h ---- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 2005-04-02 19:09:07.000000000 +0200 -@@ -0,0 +1,313 @@ -+/* PPTP constants and structs */ -+#ifndef _CONNTRACK_PPTP_H -+#define _CONNTRACK_PPTP_H -+ -+/* state of the control session */ -+enum pptp_ctrlsess_state { -+ PPTP_SESSION_NONE, /* no session present */ -+ PPTP_SESSION_ERROR, /* some session error */ -+ PPTP_SESSION_STOPREQ, /* stop_sess request seen */ -+ PPTP_SESSION_REQUESTED, /* start_sess request seen */ -+ PPTP_SESSION_CONFIRMED, /* session established */ -+}; -+ -+/* state of the call inside the control session */ -+enum pptp_ctrlcall_state { -+ PPTP_CALL_NONE, -+ PPTP_CALL_ERROR, -+ PPTP_CALL_OUT_REQ, -+ PPTP_CALL_OUT_CONF, -+ PPTP_CALL_IN_REQ, -+ PPTP_CALL_IN_REP, -+ PPTP_CALL_IN_CONF, -+ PPTP_CALL_CLEAR_REQ, -+}; -+ -+ -+/* conntrack private data */ -+struct ip_ct_pptp_master { -+ enum pptp_ctrlsess_state sstate; /* session state */ -+ -+ /* everything below is going to be per-expectation in newnat, -+ * since there could be more than one call within one session */ -+ enum pptp_ctrlcall_state cstate; /* call state */ -+ u_int16_t pac_call_id; /* call id of PAC, host byte order */ -+ u_int16_t pns_call_id; /* call id of PNS, host byte order */ -+}; -+ -+/* conntrack_expect private member */ -+struct ip_ct_pptp_expect { -+ enum pptp_ctrlcall_state cstate; /* call state */ -+ u_int16_t pac_call_id; /* call id of PAC */ -+ u_int16_t pns_call_id; /* call id of PNS */ -+}; -+ -+ -+#ifdef __KERNEL__ -+ -+#include <linux/netfilter_ipv4/lockhelp.h> -+DECLARE_LOCK_EXTERN(ip_pptp_lock); -+ -+#define IP_CONNTR_PPTP PPTP_CONTROL_PORT -+ -+union pptp_ctrl_union { -+ void *rawreq; -+ struct PptpStartSessionRequest *sreq; -+ struct PptpStartSessionReply *srep; -+ struct PptpStopSessionRequest *streq; -+ struct PptpStopSessionReply *strep; -+ struct PptpOutCallRequest *ocreq; -+ struct PptpOutCallReply *ocack; -+ struct PptpInCallRequest *icreq; -+ struct PptpInCallReply *icack; -+ struct PptpInCallConnected *iccon; -+ struct PptpClearCallRequest *clrreq; -+ struct PptpCallDisconnectNotify *disc; -+ struct PptpWanErrorNotify *wanerr; -+ struct PptpSetLinkInfo *setlink; -+}; -+ -+ -+ -+#define PPTP_CONTROL_PORT 1723 -+ -+#define PPTP_PACKET_CONTROL 1 -+#define PPTP_PACKET_MGMT 2 -+ -+#define PPTP_MAGIC_COOKIE 0x1a2b3c4d -+ -+struct pptp_pkt_hdr { -+ __u16 packetLength; -+ __u16 packetType; -+ __u32 magicCookie; -+}; -+ -+/* PptpControlMessageType values */ -+#define PPTP_START_SESSION_REQUEST 1 -+#define PPTP_START_SESSION_REPLY 2 -+#define PPTP_STOP_SESSION_REQUEST 3 -+#define PPTP_STOP_SESSION_REPLY 4 -+#define PPTP_ECHO_REQUEST 5 -+#define PPTP_ECHO_REPLY 6 -+#define PPTP_OUT_CALL_REQUEST 7 -+#define PPTP_OUT_CALL_REPLY 8 -+#define PPTP_IN_CALL_REQUEST 9 -+#define PPTP_IN_CALL_REPLY 10 -+#define PPTP_IN_CALL_CONNECT 11 -+#define PPTP_CALL_CLEAR_REQUEST 12 -+#define PPTP_CALL_DISCONNECT_NOTIFY 13 -+#define PPTP_WAN_ERROR_NOTIFY 14 -+#define PPTP_SET_LINK_INFO 15 -+ -+#define PPTP_MSG_MAX 15 -+ -+/* PptpGeneralError values */ -+#define PPTP_ERROR_CODE_NONE 0 -+#define PPTP_NOT_CONNECTED 1 -+#define PPTP_BAD_FORMAT 2 -+#define PPTP_BAD_VALUE 3 -+#define PPTP_NO_RESOURCE 4 -+#define PPTP_BAD_CALLID 5 -+#define PPTP_REMOVE_DEVICE_ERROR 6 -+ -+struct PptpControlHeader { -+ __u16 messageType; -+ __u16 reserved; -+}; -+ -+/* FramingCapability Bitmap Values */ -+#define PPTP_FRAME_CAP_ASYNC 0x1 -+#define PPTP_FRAME_CAP_SYNC 0x2 -+ -+/* BearerCapability Bitmap Values */ -+#define PPTP_BEARER_CAP_ANALOG 0x1 -+#define PPTP_BEARER_CAP_DIGITAL 0x2 -+ -+struct PptpStartSessionRequest { -+ __u16 protocolVersion; -+ __u8 reserved1; -+ __u8 reserved2; -+ __u32 framingCapability; -+ __u32 bearerCapability; -+ __u16 maxChannels; -+ __u16 firmwareRevision; -+ __u8 hostName[64]; -+ __u8 vendorString[64]; -+}; -+ -+/* PptpStartSessionResultCode Values */ -+#define PPTP_START_OK 1 -+#define PPTP_START_GENERAL_ERROR 2 -+#define PPTP_START_ALREADY_CONNECTED 3 -+#define PPTP_START_NOT_AUTHORIZED 4 -+#define PPTP_START_UNKNOWN_PROTOCOL 5 -+ -+struct PptpStartSessionReply { -+ __u16 protocolVersion; -+ __u8 resultCode; -+ __u8 generalErrorCode; -+ __u32 framingCapability; -+ __u32 bearerCapability; -+ __u16 maxChannels; -+ __u16 firmwareRevision; -+ __u8 hostName[64]; -+ __u8 vendorString[64]; -+}; -+ -+/* PptpStopReasons */ -+#define PPTP_STOP_NONE 1 -+#define PPTP_STOP_PROTOCOL 2 -+#define PPTP_STOP_LOCAL_SHUTDOWN 3 -+ -+struct PptpStopSessionRequest { -+ __u8 reason; -+}; -+ -+/* PptpStopSessionResultCode */ -+#define PPTP_STOP_OK 1 -+#define PPTP_STOP_GENERAL_ERROR 2 -+ -+struct PptpStopSessionReply { -+ __u8 resultCode; -+ __u8 generalErrorCode; -+}; -+ -+struct PptpEchoRequest { -+ __u32 identNumber; -+}; -+ -+/* PptpEchoReplyResultCode */ -+#define PPTP_ECHO_OK 1 -+#define PPTP_ECHO_GENERAL_ERROR 2 -+ -+struct PptpEchoReply { -+ __u32 identNumber; -+ __u8 resultCode; -+ __u8 generalErrorCode; -+ __u16 reserved; -+}; -+ -+/* PptpFramingType */ -+#define PPTP_ASYNC_FRAMING 1 -+#define PPTP_SYNC_FRAMING 2 -+#define PPTP_DONT_CARE_FRAMING 3 -+ -+/* PptpCallBearerType */ -+#define PPTP_ANALOG_TYPE 1 -+#define PPTP_DIGITAL_TYPE 2 -+#define PPTP_DONT_CARE_BEARER_TYPE 3 -+ -+struct PptpOutCallRequest { -+ __u16 callID; -+ __u16 callSerialNumber; -+ __u32 minBPS; -+ __u32 maxBPS; -+ __u32 bearerType; -+ __u32 framingType; -+ __u16 packetWindow; -+ __u16 packetProcDelay; -+ __u16 reserved1; -+ __u16 phoneNumberLength; -+ __u16 reserved2; -+ __u8 phoneNumber[64]; -+ __u8 subAddress[64]; -+}; -+ -+/* PptpCallResultCode */ -+#define PPTP_OUTCALL_CONNECT 1 -+#define PPTP_OUTCALL_GENERAL_ERROR 2 -+#define PPTP_OUTCALL_NO_CARRIER 3 -+#define PPTP_OUTCALL_BUSY 4 -+#define PPTP_OUTCALL_NO_DIAL_TONE 5 -+#define PPTP_OUTCALL_TIMEOUT 6 -+#define PPTP_OUTCALL_DONT_ACCEPT 7 -+ -+struct PptpOutCallReply { -+ __u16 callID; -+ __u16 peersCallID; -+ __u8 resultCode; -+ __u8 generalErrorCode; -+ __u16 causeCode; -+ __u32 connectSpeed; -+ __u16 packetWindow; -+ __u16 packetProcDelay; -+ __u32 physChannelID; -+}; -+ -+struct PptpInCallRequest { -+ __u16 callID; -+ __u16 callSerialNumber; -+ __u32 callBearerType; -+ __u32 physChannelID; -+ __u16 dialedNumberLength; -+ __u16 dialingNumberLength; -+ __u8 dialedNumber[64]; -+ __u8 dialingNumber[64]; -+ __u8 subAddress[64]; -+}; -+ -+/* PptpInCallResultCode */ -+#define PPTP_INCALL_ACCEPT 1 -+#define PPTP_INCALL_GENERAL_ERROR 2 -+#define PPTP_INCALL_DONT_ACCEPT 3 -+ -+struct PptpInCallReply { -+ __u16 callID; -+ __u16 peersCallID; -+ __u8 resultCode; -+ __u8 generalErrorCode; -+ __u16 packetWindow; -+ __u16 packetProcDelay; -+ __u16 reserved; -+}; -+ -+struct PptpInCallConnected { -+ __u16 peersCallID; -+ __u16 reserved; -+ __u32 connectSpeed; -+ __u16 packetWindow; -+ __u16 packetProcDelay; -+ __u32 callFramingType; -+}; -+ -+struct PptpClearCallRequest { -+ __u16 callID; -+ __u16 reserved; -+}; -+ -+struct PptpCallDisconnectNotify { -+ __u16 callID; -+ __u8 resultCode; -+ __u8 generalErrorCode; -+ __u16 causeCode; -+ __u16 reserved; -+ __u8 callStatistics[128]; -+}; -+ -+struct PptpWanErrorNotify { -+ __u16 peersCallID; -+ __u16 reserved; -+ __u32 crcErrors; -+ __u32 framingErrors; -+ __u32 hardwareOverRuns; -+ __u32 bufferOverRuns; -+ __u32 timeoutErrors; -+ __u32 alignmentErrors; -+}; -+ -+struct PptpSetLinkInfo { -+ __u16 peersCallID; -+ __u16 reserved; -+ __u32 sendAccm; -+ __u32 recvAccm; -+}; -+ -+ -+struct pptp_priv_data { -+ __u16 call_id; -+ __u16 mcall_id; -+ __u16 pcall_id; -+}; -+ -+#endif /* __KERNEL__ */ -+#endif /* _CONNTRACK_PPTP_H */ -diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h ---- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2005-04-02 19:10:45.000000000 +0200 -@@ -0,0 +1,123 @@ -+#ifndef _CONNTRACK_PROTO_GRE_H -+#define _CONNTRACK_PROTO_GRE_H -+#include <asm/byteorder.h> -+ -+/* GRE PROTOCOL HEADER */ -+ -+/* GRE Version field */ -+#define GRE_VERSION_1701 0x0 -+#define GRE_VERSION_PPTP 0x1 -+ -+/* GRE Protocol field */ -+#define GRE_PROTOCOL_PPTP 0x880B -+ -+/* GRE Flags */ -+#define GRE_FLAG_C 0x80 -+#define GRE_FLAG_R 0x40 -+#define GRE_FLAG_K 0x20 -+#define GRE_FLAG_S 0x10 -+#define GRE_FLAG_A 0x80 -+ -+#define GRE_IS_C(f) ((f)&GRE_FLAG_C) -+#define GRE_IS_R(f) ((f)&GRE_FLAG_R) -+#define GRE_IS_K(f) ((f)&GRE_FLAG_K) -+#define GRE_IS_S(f) ((f)&GRE_FLAG_S) -+#define GRE_IS_A(f) ((f)&GRE_FLAG_A) -+ -+/* GRE is a mess: Four different standards */ -+struct gre_hdr { -+#if defined(__LITTLE_ENDIAN_BITFIELD) -+ __u16 rec:3, -+ srr:1, -+ seq:1, -+ key:1, -+ routing:1, -+ csum:1, -+ version:3, -+ reserved:4, -+ ack:1; -+#elif defined(__BIG_ENDIAN_BITFIELD) -+ __u16 csum:1, -+ routing:1, -+ key:1, -+ seq:1, -+ srr:1, -+ rec:3, -+ ack:1, -+ reserved:4, -+ version:3; -+#else -+#error "Adjust your <asm/byteorder.h> defines" -+#endif -+ __u16 protocol; -+}; -+ -+/* modified GRE header for PPTP */ -+struct gre_hdr_pptp { -+ __u8 flags; /* bitfield */ -+ __u8 version; /* should be GRE_VERSION_PPTP */ -+ __u16 protocol; /* should be GRE_PROTOCOL_PPTP */ -+ __u16 payload_len; /* size of ppp payload, not inc. gre header */ -+ __u16 call_id; /* peer's call_id for this session */ -+ __u32 seq; /* sequence number. Present if S==1 */ -+ __u32 ack; /* seq number of highest packet recieved by */ -+ /* sender in this session */ -+}; -+ -+ -+/* this is part of ip_conntrack */ -+struct ip_ct_gre { -+ unsigned int stream_timeout; -+ unsigned int timeout; -+}; -+ -+/* this is part of ip_conntrack_expect */ -+struct ip_ct_gre_expect { -+ struct ip_ct_gre_keymap *keymap_orig, *keymap_reply; -+}; -+ -+#ifdef __KERNEL__ -+struct ip_conntrack_expect; -+ -+/* structure for original <-> reply keymap */ -+struct ip_ct_gre_keymap { -+ struct list_head list; -+ -+ struct ip_conntrack_tuple tuple; -+}; -+ -+ -+/* add new tuple->key_reply pair to keymap */ -+int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, -+ struct ip_conntrack_tuple *t, -+ int reply); -+ -+/* change an existing keymap entry */ -+void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, -+ struct ip_conntrack_tuple *t); -+ -+/* delete keymap entries */ -+void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp); -+ -+ -+/* get pointer to gre key, if present */ -+static inline u_int32_t *gre_key(struct gre_hdr *greh) -+{ -+ if (!greh->key) -+ return NULL; -+ if (greh->csum || greh->routing) -+ return (u_int32_t *) (greh+sizeof(*greh)+4); -+ return (u_int32_t *) (greh+sizeof(*greh)); -+} -+ -+/* get pointer ot gre csum, if present */ -+static inline u_int16_t *gre_csum(struct gre_hdr *greh) -+{ -+ if (!greh->csum) -+ return NULL; -+ return (u_int16_t *) (greh+sizeof(*greh)); -+} -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _CONNTRACK_PROTO_GRE_H */ -diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_tuple.h ---- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-11-28 19:26:21.000000000 +0100 -+++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2005-04-02 19:07:18.000000000 +0200 -@@ -14,7 +14,7 @@ - union ip_conntrack_manip_proto - { - /* Add other protocols here. */ -- u_int16_t all; -+ u_int32_t all; - - struct { - u_int16_t port; -@@ -25,6 +25,9 @@ - struct { - u_int16_t id; - } icmp; -+ struct { -+ u_int32_t key; -+ } gre; - }; - - /* The manipulable part of the tuple. */ -@@ -44,7 +47,7 @@ - u_int32_t ip; - union { - /* Add other protocols here. */ -- u_int16_t all; -+ u_int32_t all; - - struct { - u_int16_t port; -@@ -55,6 +58,9 @@ - struct { - u_int8_t type, code; - } icmp; -+ struct { -+ u_int32_t key; -+ } gre; - } u; - - /* The protocol. */ -@@ -80,10 +86,16 @@ - #ifdef __KERNEL__ - - #define DUMP_TUPLE(tp) \ --DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \ -+DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \ - (tp), (tp)->dst.protonum, \ -- NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \ -- NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all)) -+ NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \ -+ NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all)) -+ -+#define DUMP_TUPLE_RAW(x) \ -+ DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\ -+ (x), (x)->dst.protonum, \ -+ NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \ -+ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all)) - - #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL) - -diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_nat_pptp.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_nat_pptp.h ---- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_nat_pptp.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_nat_pptp.h 2005-04-02 19:07:18.000000000 +0200 -@@ -0,0 +1,11 @@ -+/* PPTP constants and structs */ -+#ifndef _NAT_PPTP_H -+#define _NAT_PPTP_H -+ -+/* conntrack private data */ -+struct ip_nat_pptp { -+ u_int16_t pns_call_id; /* NAT'ed PNS call id */ -+ u_int16_t pac_call_id; /* NAT'ed PAC call id */ -+}; -+ -+#endif /* _NAT_PPTP_H */ -diff -urN linux-2.4.29-old/net/ipv4/netfilter/Config.in linux-2.4.29-dev/net/ipv4/netfilter/Config.in ---- linux-2.4.29-old/net/ipv4/netfilter/Config.in 2005-04-02 19:04:11.000000000 +0200 -+++ linux-2.4.29-dev/net/ipv4/netfilter/Config.in 2005-04-02 19:07:18.000000000 +0200 -@@ -10,6 +10,8 @@ - dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK - dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK - dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK -+ dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK -+ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE - fi - - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then -@@ -67,6 +69,20 @@ - define_bool CONFIG_IP_NF_NAT_NEEDED y - dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT - dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT -+ if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then -+ define_tristate CONFIG_IP_NF_NAT_PPTP m -+ else -+ if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then -+ define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT -+ fi -+ fi -+ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then -+ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m -+ else -+ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then -+ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT -+ fi -+ fi - if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then - define_tristate CONFIG_IP_NF_NAT_AMANDA m - else -diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_core.c ---- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_core.c 2005-04-02 19:04:11.000000000 +0200 -+++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_core.c 2005-04-02 19:07:18.000000000 +0200 -@@ -142,6 +142,8 @@ - tuple->dst.ip = iph->daddr; - tuple->dst.protonum = iph->protocol; - -+ tuple->src.u.all = tuple->dst.u.all = 0; -+ - ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl, - len - 4*iph->ihl, - tuple); -@@ -157,6 +159,8 @@ - inverse->dst.ip = orig->src.ip; - inverse->dst.protonum = orig->dst.protonum; - -+ inverse->src.u.all = inverse->dst.u.all = 0; -+ - return protocol->invert_tuple(inverse, orig); - } - -@@ -954,8 +958,8 @@ - * so there is no need to use the tuple lock too */ - - DEBUGP("ip_conntrack_expect_related %p\n", related_to); -- DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple); -- DEBUGP("mask: "); DUMP_TUPLE(&expect->mask); -+ DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple); -+ DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask); - - old = LIST_FIND(&ip_conntrack_expect_list, resent_expect, - struct ip_conntrack_expect *, &expect->tuple, -@@ -1072,15 +1076,14 @@ - - MUST_BE_READ_LOCKED(&ip_conntrack_lock); - WRITE_LOCK(&ip_conntrack_expect_tuple_lock); -- - DEBUGP("change_expect:\n"); -- DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple); -- DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask); -- DEBUGP("newtuple: "); DUMP_TUPLE(newtuple); -+ DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple); -+ DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask); -+ DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple); - if (expect->ct_tuple.dst.protonum == 0) { - /* Never seen before */ - DEBUGP("change expect: never seen before\n"); -- if (!ip_ct_tuple_equal(&expect->tuple, newtuple) -+ if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask) - && LIST_FIND(&ip_conntrack_expect_list, expect_clash, - struct ip_conntrack_expect *, newtuple, &expect->mask)) { - /* Force NAT to find an unused tuple */ -diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp.c ---- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp.c 2005-04-02 19:13:21.000000000 +0200 -@@ -0,0 +1,633 @@ -+/* -+ * ip_conntrack_pptp.c - Version 1.9 -+ * -+ * Connection tracking support for PPTP (Point to Point Tunneling Protocol). -+ * PPTP is a a protocol for creating virtual private networks. -+ * It is a specification defined by Microsoft and some vendors -+ * working with Microsoft. PPTP is built on top of a modified -+ * version of the Internet Generic Routing Encapsulation Protocol. -+ * GRE is defined in RFC 1701 and RFC 1702. Documentation of -+ * PPTP can be found in RFC 2637 -+ * -+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> -+ * -+ * Development of this code funded by Astaro AG (http://www.astaro.com/) -+ * -+ * Limitations: -+ * - We blindly assume that control connections are always -+ * established in PNS->PAC direction. This is a violation -+ * of RFFC2673 -+ * -+ * TODO: - finish support for multiple calls within one session -+ * (needs expect reservations in newnat) -+ * - testing of incoming PPTP calls -+ * -+ * Changes: -+ * 2002-02-05 - Version 1.3 -+ * - Call ip_conntrack_unexpect_related() from -+ * pptp_timeout_related() to destroy expectations in case -+ * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen -+ * (Philip Craig <philipc@snapgear.com>) -+ * - Add Version information at module loadtime -+ * 2002-02-10 - Version 1.6 -+ * - move to C99 style initializers -+ * - remove second expectation if first arrives -+ * -+ */ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/netfilter.h> -+#include <linux/ip.h> -+#include <net/checksum.h> -+#include <net/tcp.h> -+ -+#include <linux/netfilter_ipv4/lockhelp.h> -+#include <linux/netfilter_ipv4/ip_conntrack_helper.h> -+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> -+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> -+ -+#define IP_CT_PPTP_VERSION "1.9" -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); -+MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); -+ -+DECLARE_LOCK(ip_pptp_lock); -+ -+#if 0 -+#include "ip_conntrack_pptp_priv.h" -+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ -+ ": " format, ## args) -+#else -+#define DEBUGP(format, args...) -+#endif -+ -+#define SECS *HZ -+#define MINS * 60 SECS -+#define HOURS * 60 MINS -+#define DAYS * 24 HOURS -+ -+#define PPTP_GRE_TIMEOUT (10 MINS) -+#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS) -+ -+static int pptp_expectfn(struct ip_conntrack *ct) -+{ -+ struct ip_conntrack *master; -+ struct ip_conntrack_expect *exp; -+ -+ DEBUGP("increasing timeouts\n"); -+ /* increase timeout of GRE data channel conntrack entry */ -+ ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; -+ ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; -+ -+ master = master_ct(ct); -+ if (!master) { -+ DEBUGP(" no master!!!\n"); -+ return 0; -+ } -+ -+ exp = ct->master; -+ if (!exp) { -+ DEBUGP("no expectation!!\n"); -+ return 0; -+ } -+ -+ DEBUGP("completing tuples with ct info\n"); -+ /* we can do this, since we're unconfirmed */ -+ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == -+ htonl(master->help.ct_pptp_info.pac_call_id)) { -+ /* assume PNS->PAC */ -+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = -+ htonl(master->help.ct_pptp_info.pns_call_id); -+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = -+ htonl(master->help.ct_pptp_info.pns_call_id); -+ } else { -+ /* assume PAC->PNS */ -+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = -+ htonl(master->help.ct_pptp_info.pac_call_id); -+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = -+ htonl(master->help.ct_pptp_info.pac_call_id); -+ } -+ -+ /* delete other expectation */ -+ if (exp->expected_list.next != &exp->expected_list) { -+ struct ip_conntrack_expect *other_exp; -+ struct list_head *cur_item, *next; -+ -+ for (cur_item = master->sibling_list.next; -+ cur_item != &master->sibling_list; cur_item = next) { -+ next = cur_item->next; -+ other_exp = list_entry(cur_item, -+ struct ip_conntrack_expect, -+ expected_list); -+ /* remove only if occurred at same sequence number */ -+ if (other_exp != exp && other_exp->seq == exp->seq) { -+ DEBUGP("unexpecting other direction\n"); -+ ip_ct_gre_keymap_destroy(other_exp); -+ ip_conntrack_unexpect_related(other_exp); -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+/* timeout GRE data connections */ -+static int pptp_timeout_related(struct ip_conntrack *ct) -+{ -+ struct list_head *cur_item, *next; -+ struct ip_conntrack_expect *exp; -+ -+ /* FIXME: do we have to lock something ? */ -+ for (cur_item = ct->sibling_list.next; -+ cur_item != &ct->sibling_list; cur_item = next) { -+ next = cur_item->next; -+ exp = list_entry(cur_item, struct ip_conntrack_expect, -+ expected_list); -+ -+ ip_ct_gre_keymap_destroy(exp); -+ if (!exp->sibling) { -+ ip_conntrack_unexpect_related(exp); -+ continue; -+ } -+ -+ DEBUGP("setting timeout of conntrack %p to 0\n", -+ exp->sibling); -+ exp->sibling->proto.gre.timeout = 0; -+ exp->sibling->proto.gre.stream_timeout = 0; -+ ip_ct_refresh(exp->sibling, 0); -+ } -+ -+ return 0; -+} -+ -+/* expect GRE connections (PNS->PAC and PAC->PNS direction) */ -+static inline int -+exp_gre(struct ip_conntrack *master, -+ u_int32_t seq, -+ u_int16_t callid, -+ u_int16_t peer_callid) -+{ -+ struct ip_conntrack_expect exp; -+ struct ip_conntrack_tuple inv_tuple; -+ -+ memset(&exp, 0, sizeof(exp)); -+ /* tuple in original direction, PNS->PAC */ -+ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid)); -+ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; -+ exp.tuple.dst.u.gre.key = htonl(ntohs(callid)); -+ exp.tuple.dst.protonum = IPPROTO_GRE; -+ -+ exp.mask.src.ip = 0xffffffff; -+ exp.mask.src.u.all = 0; -+ exp.mask.dst.u.all = 0; -+ exp.mask.dst.u.gre.key = 0xffffffff; -+ exp.mask.dst.ip = 0xffffffff; -+ exp.mask.dst.protonum = 0xffff; -+ -+ exp.seq = seq; -+ exp.expectfn = pptp_expectfn; -+ -+ exp.help.exp_pptp_info.pac_call_id = ntohs(callid); -+ exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid); -+ -+ DEBUGP("calling expect_related "); -+ DUMP_TUPLE_RAW(&exp.tuple); -+ -+ /* Add GRE keymap entries */ -+ if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0) -+ return 1; -+ -+ invert_tuplepr(&inv_tuple, &exp.tuple); -+ if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) { -+ ip_ct_gre_keymap_destroy(&exp); -+ return 1; -+ } -+ -+ if (ip_conntrack_expect_related(master, &exp) != 0) { -+ ip_ct_gre_keymap_destroy(&exp); -+ DEBUGP("cannot expect_related()\n"); -+ return 1; -+ } -+ -+ /* tuple in reply direction, PAC->PNS */ -+ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; -+ exp.tuple.src.u.gre.key = htonl(ntohs(callid)); -+ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; -+ exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid)); -+ -+ DEBUGP("calling expect_related "); -+ DUMP_TUPLE_RAW(&exp.tuple); -+ -+ /* Add GRE keymap entries */ -+ ip_ct_gre_keymap_add(&exp, &exp.tuple, 0); -+ invert_tuplepr(&inv_tuple, &exp.tuple); -+ ip_ct_gre_keymap_add(&exp, &inv_tuple, 1); -+ /* FIXME: cannot handle error correctly, since we need to free -+ * the above keymap :( */ -+ -+ if (ip_conntrack_expect_related(master, &exp) != 0) { -+ /* free the second pair of keypmaps */ -+ ip_ct_gre_keymap_destroy(&exp); -+ DEBUGP("cannot expect_related():\n"); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static inline int -+pptp_inbound_pkt(struct tcphdr *tcph, -+ struct pptp_pkt_hdr *pptph, -+ size_t datalen, -+ struct ip_conntrack *ct, -+ enum ip_conntrack_info ctinfo) -+{ -+ struct PptpControlHeader *ctlh; -+ union pptp_ctrl_union pptpReq; -+ -+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; -+ u_int16_t msg, *cid, *pcid; -+ u_int32_t seq; -+ -+ ctlh = (struct PptpControlHeader *) -+ ((char *) pptph + sizeof(struct pptp_pkt_hdr)); -+ pptpReq.rawreq = (void *) -+ ((char *) ctlh + sizeof(struct PptpControlHeader)); -+ -+ msg = ntohs(ctlh->messageType); -+ DEBUGP("inbound control message %s\n", strMName[msg]); -+ -+ switch (msg) { -+ case PPTP_START_SESSION_REPLY: -+ /* server confirms new control session */ -+ if (info->sstate < PPTP_SESSION_REQUESTED) { -+ DEBUGP("%s without START_SESS_REQUEST\n", -+ strMName[msg]); -+ break; -+ } -+ if (pptpReq.srep->resultCode == PPTP_START_OK) -+ info->sstate = PPTP_SESSION_CONFIRMED; -+ else -+ info->sstate = PPTP_SESSION_ERROR; -+ break; -+ -+ case PPTP_STOP_SESSION_REPLY: -+ /* server confirms end of control session */ -+ if (info->sstate > PPTP_SESSION_STOPREQ) { -+ DEBUGP("%s without STOP_SESS_REQUEST\n", -+ strMName[msg]); -+ break; -+ } -+ if (pptpReq.strep->resultCode == PPTP_STOP_OK) -+ info->sstate = PPTP_SESSION_NONE; -+ else -+ info->sstate = PPTP_SESSION_ERROR; -+ break; -+ -+ case PPTP_OUT_CALL_REPLY: -+ /* server accepted call, we now expect GRE frames */ -+ if (info->sstate != PPTP_SESSION_CONFIRMED) { -+ DEBUGP("%s but no session\n", strMName[msg]); -+ break; -+ } -+ if (info->cstate != PPTP_CALL_OUT_REQ && -+ info->cstate != PPTP_CALL_OUT_CONF) { -+ DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]); -+ break; -+ } -+ if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) { -+ info->cstate = PPTP_CALL_NONE; -+ break; -+ } -+ -+ cid = &pptpReq.ocack->callID; -+ pcid = &pptpReq.ocack->peersCallID; -+ -+ info->pac_call_id = ntohs(*cid); -+ -+ if (htons(info->pns_call_id) != *pcid) { -+ DEBUGP("%s for unknown callid %u\n", -+ strMName[msg], ntohs(*pcid)); -+ break; -+ } -+ -+ DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg], -+ ntohs(*cid), ntohs(*pcid)); -+ -+ info->cstate = PPTP_CALL_OUT_CONF; -+ -+ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); -+ if (exp_gre(ct, seq, *cid, *pcid) != 0) -+ printk("ip_conntrack_pptp: error during exp_gre\n"); -+ break; -+ -+ case PPTP_IN_CALL_REQUEST: -+ /* server tells us about incoming call request */ -+ if (info->sstate != PPTP_SESSION_CONFIRMED) { -+ DEBUGP("%s but no session\n", strMName[msg]); -+ break; -+ } -+ pcid = &pptpReq.icack->peersCallID; -+ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); -+ info->cstate = PPTP_CALL_IN_REQ; -+ info->pac_call_id= ntohs(*pcid); -+ break; -+ -+ case PPTP_IN_CALL_CONNECT: -+ /* server tells us about incoming call established */ -+ if (info->sstate != PPTP_SESSION_CONFIRMED) { -+ DEBUGP("%s but no session\n", strMName[msg]); -+ break; -+ } -+ if (info->sstate != PPTP_CALL_IN_REP -+ && info->sstate != PPTP_CALL_IN_CONF) { -+ DEBUGP("%s but never sent IN_CALL_REPLY\n", -+ strMName[msg]); -+ break; -+ } -+ -+ pcid = &pptpReq.iccon->peersCallID; -+ cid = &info->pac_call_id; -+ -+ if (info->pns_call_id != ntohs(*pcid)) { -+ DEBUGP("%s for unknown CallID %u\n", -+ strMName[msg], ntohs(*cid)); -+ break; -+ } -+ -+ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid)); -+ info->cstate = PPTP_CALL_IN_CONF; -+ -+ /* we expect a GRE connection from PAC to PNS */ -+ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph); -+ if (exp_gre(ct, seq, *cid, *pcid) != 0) -+ printk("ip_conntrack_pptp: error during exp_gre\n"); -+ -+ break; -+ -+ case PPTP_CALL_DISCONNECT_NOTIFY: -+ /* server confirms disconnect */ -+ cid = &pptpReq.disc->callID; -+ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); -+ info->cstate = PPTP_CALL_NONE; -+ -+ /* untrack this call id, unexpect GRE packets */ -+ pptp_timeout_related(ct); -+ break; -+ -+ case PPTP_WAN_ERROR_NOTIFY: -+ break; -+ -+ case PPTP_ECHO_REQUEST: -+ case PPTP_ECHO_REPLY: -+ /* I don't have to explain these ;) */ -+ break; -+ default: -+ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX) -+ ? strMName[msg]:strMName[0], msg); -+ break; -+ } -+ -+ return NF_ACCEPT; -+ -+} -+ -+static inline int -+pptp_outbound_pkt(struct tcphdr *tcph, -+ struct pptp_pkt_hdr *pptph, -+ size_t datalen, -+ struct ip_conntrack *ct, -+ enum ip_conntrack_info ctinfo) -+{ -+ struct PptpControlHeader *ctlh; -+ union pptp_ctrl_union pptpReq; -+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; -+ u_int16_t msg, *cid, *pcid; -+ -+ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); -+ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); -+ -+ msg = ntohs(ctlh->messageType); -+ DEBUGP("outbound control message %s\n", strMName[msg]); -+ -+ switch (msg) { -+ case PPTP_START_SESSION_REQUEST: -+ /* client requests for new control session */ -+ if (info->sstate != PPTP_SESSION_NONE) { -+ DEBUGP("%s but we already have one", -+ strMName[msg]); -+ } -+ info->sstate = PPTP_SESSION_REQUESTED; -+ break; -+ case PPTP_STOP_SESSION_REQUEST: -+ /* client requests end of control session */ -+ info->sstate = PPTP_SESSION_STOPREQ; -+ break; -+ -+ case PPTP_OUT_CALL_REQUEST: -+ /* client initiating connection to server */ -+ if (info->sstate != PPTP_SESSION_CONFIRMED) { -+ DEBUGP("%s but no session\n", -+ strMName[msg]); -+ break; -+ } -+ info->cstate = PPTP_CALL_OUT_REQ; -+ /* track PNS call id */ -+ cid = &pptpReq.ocreq->callID; -+ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid)); -+ info->pns_call_id = ntohs(*cid); -+ break; -+ case PPTP_IN_CALL_REPLY: -+ /* client answers incoming call */ -+ if (info->cstate != PPTP_CALL_IN_REQ -+ && info->cstate != PPTP_CALL_IN_REP) { -+ DEBUGP("%s without incall_req\n", -+ strMName[msg]); -+ break; -+ } -+ if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) { -+ info->cstate = PPTP_CALL_NONE; -+ break; -+ } -+ pcid = &pptpReq.icack->peersCallID; -+ if (info->pac_call_id != ntohs(*pcid)) { -+ DEBUGP("%s for unknown call %u\n", -+ strMName[msg], ntohs(*pcid)); -+ break; -+ } -+ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid)); -+ /* part two of the three-way handshake */ -+ info->cstate = PPTP_CALL_IN_REP; -+ info->pns_call_id = ntohs(pptpReq.icack->callID); -+ break; -+ -+ case PPTP_CALL_CLEAR_REQUEST: -+ /* client requests hangup of call */ -+ if (info->sstate != PPTP_SESSION_CONFIRMED) { -+ DEBUGP("CLEAR_CALL but no session\n"); -+ break; -+ } -+ /* FUTURE: iterate over all calls and check if -+ * call ID is valid. We don't do this without newnat, -+ * because we only know about last call */ -+ info->cstate = PPTP_CALL_CLEAR_REQ; -+ break; -+ case PPTP_SET_LINK_INFO: -+ break; -+ case PPTP_ECHO_REQUEST: -+ case PPTP_ECHO_REPLY: -+ /* I don't have to explain these ;) */ -+ break; -+ default: -+ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? -+ strMName[msg]:strMName[0], msg); -+ /* unknown: no need to create GRE masq table entry */ -+ break; -+ } -+ -+ return NF_ACCEPT; -+} -+ -+ -+/* track caller id inside control connection, call expect_related */ -+static int -+conntrack_pptp_help(const struct iphdr *iph, size_t len, -+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) -+ -+{ -+ struct pptp_pkt_hdr *pptph; -+ -+ struct tcphdr *tcph = (void *) iph + iph->ihl * 4; -+ u_int32_t tcplen = len - iph->ihl * 4; -+ u_int32_t datalen = tcplen - tcph->doff * 4; -+ void *datalimit; -+ int dir = CTINFO2DIR(ctinfo); -+ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; -+ -+ int oldsstate, oldcstate; -+ int ret; -+ -+ /* don't do any tracking before tcp handshake complete */ -+ if (ctinfo != IP_CT_ESTABLISHED -+ && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { -+ DEBUGP("ctinfo = %u, skipping\n", ctinfo); -+ return NF_ACCEPT; -+ } -+ -+ /* not a complete TCP header? */ -+ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) { -+ DEBUGP("tcplen = %u\n", tcplen); -+ return NF_ACCEPT; -+ } -+ -+ /* checksum invalid? */ -+ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, -+ csum_partial((char *) tcph, tcplen, 0))) { -+ printk(KERN_NOTICE __FILE__ ": bad csum\n"); -+ /* W2K PPTP server sends TCP packets with wrong checksum :(( */ -+ //return NF_ACCEPT; -+ } -+ -+ if (tcph->fin || tcph->rst) { -+ DEBUGP("RST/FIN received, timeouting GRE\n"); -+ /* can't do this after real newnat */ -+ info->cstate = PPTP_CALL_NONE; -+ -+ /* untrack this call id, unexpect GRE packets */ -+ pptp_timeout_related(ct); -+ } -+ -+ -+ pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4); -+ datalimit = (void *) pptph + datalen; -+ -+ /* not a full pptp packet header? */ -+ if ((void *) pptph+sizeof(*pptph) >= datalimit) { -+ DEBUGP("no full PPTP header, can't track\n"); -+ return NF_ACCEPT; -+ } -+ -+ /* if it's not a control message we can't do anything with it */ -+ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || -+ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { -+ DEBUGP("not a control packet\n"); -+ return NF_ACCEPT; -+ } -+ -+ oldsstate = info->sstate; -+ oldcstate = info->cstate; -+ -+ LOCK_BH(&ip_pptp_lock); -+ -+ /* FIXME: We just blindly assume that the control connection is always -+ * established from PNS->PAC. However, RFC makes no guarantee */ -+ if (dir == IP_CT_DIR_ORIGINAL) -+ /* client -> server (PNS -> PAC) */ -+ ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo); -+ else -+ /* server -> client (PAC -> PNS) */ -+ ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo); -+ DEBUGP("sstate: %d->%d, cstate: %d->%d\n", -+ oldsstate, info->sstate, oldcstate, info->cstate); -+ UNLOCK_BH(&ip_pptp_lock); -+ -+ return ret; -+} -+ -+/* control protocol helper */ -+static struct ip_conntrack_helper pptp = { -+ .list = { NULL, NULL }, -+ .name = "pptp", -+ .flags = IP_CT_HELPER_F_REUSE_EXPECT, -+ .me = THIS_MODULE, -+ .max_expected = 2, -+ .timeout = 0, -+ .tuple = { .src = { .ip = 0, -+ .u = { .tcp = { .port = -+ __constant_htons(PPTP_CONTROL_PORT) } } -+ }, -+ .dst = { .ip = 0, -+ .u = { .all = 0 }, -+ .protonum = IPPROTO_TCP -+ } -+ }, -+ .mask = { .src = { .ip = 0, -+ .u = { .tcp = { .port = 0xffff } } -+ }, -+ .dst = { .ip = 0, -+ .u = { .all = 0 }, -+ .protonum = 0xffff -+ } -+ }, -+ .help = conntrack_pptp_help -+}; -+ -+/* ip_conntrack_pptp initialization */ -+static int __init init(void) -+{ -+ int retcode; -+ -+ DEBUGP(__FILE__ ": registering helper\n"); -+ if ((retcode = ip_conntrack_helper_register(&pptp))) { -+ printk(KERN_ERR "Unable to register conntrack application " -+ "helper for pptp: %d\n", retcode); -+ return -EIO; -+ } -+ -+ printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION); -+ return 0; -+} -+ -+static void __exit fini(void) -+{ -+ ip_conntrack_helper_unregister(&pptp); -+ printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION); -+} -+ -+module_init(init); -+module_exit(fini); -+ -+EXPORT_SYMBOL(ip_pptp_lock); -diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp_priv.h ---- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 2005-04-02 19:14:10.000000000 +0200 -@@ -0,0 +1,24 @@ -+#ifndef _IP_CT_PPTP_PRIV_H -+#define _IP_CT_PPTP_PRIV_H -+ -+/* PptpControlMessageType names */ -+static const char *strMName[] = { -+ "UNKNOWN_MESSAGE", -+ "START_SESSION_REQUEST", -+ "START_SESSION_REPLY", -+ "STOP_SESSION_REQUEST", -+ "STOP_SESSION_REPLY", -+ "ECHO_REQUEST", -+ "ECHO_REPLY", -+ "OUT_CALL_REQUEST", -+ "OUT_CALL_REPLY", -+ "IN_CALL_REQUEST", -+ "IN_CALL_REPLY", -+ "IN_CALL_CONNECT", -+ "CALL_CLEAR_REQUEST", -+ "CALL_DISCONNECT_NOTIFY", -+ "WAN_ERROR_NOTIFY", -+ "SET_LINK_INFO" -+}; -+ -+#endif -diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_proto_gre.c ---- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_proto_gre.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2005-04-02 19:14:31.000000000 +0200 -@@ -0,0 +1,333 @@ -+/* -+ * ip_conntrack_proto_gre.c - Version 1.2 -+ * -+ * Connection tracking protocol helper module for GRE. -+ * -+ * GRE is a generic encapsulation protocol, which is generally not very -+ * suited for NAT, as it has no protocol-specific part as port numbers. -+ * -+ * It has an optional key field, which may help us distinguishing two -+ * connections between the same two hosts. -+ * -+ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 -+ * -+ * PPTP is built on top of a modified version of GRE, and has a mandatory -+ * field called "CallID", which serves us for the same purpose as the key -+ * field in plain GRE. -+ * -+ * Documentation about PPTP can be found in RFC 2637 -+ * -+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> -+ * -+ * Development of this code funded by Astaro AG (http://www.astaro.com/) -+ * -+ */ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/timer.h> -+#include <linux/netfilter.h> -+#include <linux/ip.h> -+#include <linux/in.h> -+#include <linux/list.h> -+ -+#include <linux/netfilter_ipv4/lockhelp.h> -+ -+DECLARE_RWLOCK(ip_ct_gre_lock); -+#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock) -+#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock) -+ -+#include <linux/netfilter_ipv4/listhelp.h> -+#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> -+#include <linux/netfilter_ipv4/ip_conntrack_helper.h> -+#include <linux/netfilter_ipv4/ip_conntrack_core.h> -+ -+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> -+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); -+MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); -+ -+/* shamelessly stolen from ip_conntrack_proto_udp.c */ -+#define GRE_TIMEOUT (30*HZ) -+#define GRE_STREAM_TIMEOUT (180*HZ) -+ -+#if 0 -+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ -+ ": " format, ## args) -+#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \ -+ NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \ -+ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key)) -+#else -+#define DEBUGP(x, args...) -+#define DUMP_TUPLE_GRE(x) -+#endif -+ -+/* GRE KEYMAP HANDLING FUNCTIONS */ -+static LIST_HEAD(gre_keymap_list); -+ -+static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km, -+ const struct ip_conntrack_tuple *t) -+{ -+ return ((km->tuple.src.ip == t->src.ip) && -+ (km->tuple.dst.ip == t->dst.ip) && -+ (km->tuple.dst.protonum == t->dst.protonum) && -+ (km->tuple.dst.u.all == t->dst.u.all)); -+} -+ -+/* look up the source key for a given tuple */ -+static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t) -+{ -+ struct ip_ct_gre_keymap *km; -+ u_int32_t key; -+ -+ READ_LOCK(&ip_ct_gre_lock); -+ km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, -+ struct ip_ct_gre_keymap *, t); -+ if (!km) { -+ READ_UNLOCK(&ip_ct_gre_lock); -+ return 0; -+ } -+ -+ key = km->tuple.src.u.gre.key; -+ READ_UNLOCK(&ip_ct_gre_lock); -+ -+ return key; -+} -+ -+/* add a single keymap entry, associate with specified expect */ -+int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp, -+ struct ip_conntrack_tuple *t, int reply) -+{ -+ struct ip_ct_gre_keymap *km; -+ -+ km = kmalloc(sizeof(*km), GFP_ATOMIC); -+ if (!km) -+ return -1; -+ -+ /* initializing list head should be sufficient */ -+ memset(km, 0, sizeof(*km)); -+ -+ memcpy(&km->tuple, t, sizeof(*t)); -+ -+ if (!reply) -+ exp->proto.gre.keymap_orig = km; -+ else -+ exp->proto.gre.keymap_reply = km; -+ -+ DEBUGP("adding new entry %p: ", km); -+ DUMP_TUPLE_GRE(&km->tuple); -+ -+ WRITE_LOCK(&ip_ct_gre_lock); -+ list_append(&gre_keymap_list, km); -+ WRITE_UNLOCK(&ip_ct_gre_lock); -+ -+ return 0; -+} -+ -+/* change the tuple of a keymap entry (used by nat helper) */ -+void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km, -+ struct ip_conntrack_tuple *t) -+{ -+ DEBUGP("changing entry %p to: ", km); -+ DUMP_TUPLE_GRE(t); -+ -+ WRITE_LOCK(&ip_ct_gre_lock); -+ memcpy(&km->tuple, t, sizeof(km->tuple)); -+ WRITE_UNLOCK(&ip_ct_gre_lock); -+} -+ -+/* destroy the keymap entries associated with specified expect */ -+void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp) -+{ -+ DEBUGP("entering for exp %p\n", exp); -+ WRITE_LOCK(&ip_ct_gre_lock); -+ if (exp->proto.gre.keymap_orig) { -+ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig); -+ list_del(&exp->proto.gre.keymap_orig->list); -+ kfree(exp->proto.gre.keymap_orig); -+ exp->proto.gre.keymap_orig = NULL; -+ } -+ if (exp->proto.gre.keymap_reply) { -+ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply); -+ list_del(&exp->proto.gre.keymap_reply->list); -+ kfree(exp->proto.gre.keymap_reply); -+ exp->proto.gre.keymap_reply = NULL; -+ } -+ WRITE_UNLOCK(&ip_ct_gre_lock); -+} -+ -+ -+/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ -+ -+/* invert gre part of tuple */ -+static int gre_invert_tuple(struct ip_conntrack_tuple *tuple, -+ const struct ip_conntrack_tuple *orig) -+{ -+ tuple->dst.u.gre.key = orig->src.u.gre.key; -+ tuple->src.u.gre.key = orig->dst.u.gre.key; -+ -+ return 1; -+} -+ -+/* gre hdr info to tuple */ -+static int gre_pkt_to_tuple(const void *datah, size_t datalen, -+ struct ip_conntrack_tuple *tuple) -+{ -+ struct gre_hdr *grehdr = (struct gre_hdr *) datah; -+ struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah; -+ u_int32_t srckey; -+ -+ /* core guarantees 8 protocol bytes, no need for size check */ -+ -+ switch (grehdr->version) { -+ case GRE_VERSION_1701: -+ if (!grehdr->key) { -+ DEBUGP("Can't track GRE without key\n"); -+ return 0; -+ } -+ tuple->dst.u.gre.key = *(gre_key(grehdr)); -+ break; -+ -+ case GRE_VERSION_PPTP: -+ if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { -+ DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); -+ return 0; -+ } -+ tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id)); -+ break; -+ -+ default: -+ printk(KERN_WARNING "unknown GRE version %hu\n", -+ grehdr->version); -+ return 0; -+ } -+ -+ srckey = gre_keymap_lookup(tuple); -+ -+#if 0 -+ DEBUGP("found src key %x for tuple ", ntohl(srckey)); -+ DUMP_TUPLE_GRE(tuple); -+#endif -+ tuple->src.u.gre.key = srckey; -+ -+ return 1; -+} -+ -+/* print gre part of tuple */ -+static unsigned int gre_print_tuple(char *buffer, -+ const struct ip_conntrack_tuple *tuple) -+{ -+ return sprintf(buffer, "srckey=0x%x dstkey=0x%x ", -+ ntohl(tuple->src.u.gre.key), -+ ntohl(tuple->dst.u.gre.key)); -+} -+ -+/* print private data for conntrack */ -+static unsigned int gre_print_conntrack(char *buffer, -+ const struct ip_conntrack *ct) -+{ -+ return sprintf(buffer, "timeout=%u, stream_timeout=%u ", -+ (ct->proto.gre.timeout / HZ), -+ (ct->proto.gre.stream_timeout / HZ)); -+} -+ -+/* Returns verdict for packet, and may modify conntrack */ -+static int gre_packet(struct ip_conntrack *ct, -+ struct iphdr *iph, size_t len, -+ enum ip_conntrack_info conntrackinfo) -+{ -+ /* If we've seen traffic both ways, this is a GRE connection. -+ * Extend timeout. */ -+ if (ct->status & IPS_SEEN_REPLY) { -+ ip_ct_refresh(ct, ct->proto.gre.stream_timeout); -+ /* Also, more likely to be important, and not a probe. */ -+ set_bit(IPS_ASSURED_BIT, &ct->status); -+ } else -+ ip_ct_refresh(ct, ct->proto.gre.timeout); -+ -+ return NF_ACCEPT; -+} -+ -+/* Called when a new connection for this protocol found. */ -+static int gre_new(struct ip_conntrack *ct, -+ struct iphdr *iph, size_t len) -+{ -+ DEBUGP(": "); -+ DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); -+ -+ /* initialize to sane value. Ideally a conntrack helper -+ * (e.g. in case of pptp) is increasing them */ -+ ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; -+ ct->proto.gre.timeout = GRE_TIMEOUT; -+ -+ return 1; -+} -+ -+/* Called when a conntrack entry has already been removed from the hashes -+ * and is about to be deleted from memory */ -+static void gre_destroy(struct ip_conntrack *ct) -+{ -+ struct ip_conntrack_expect *master = ct->master; -+ -+ DEBUGP(" entering\n"); -+ -+ if (!master) { -+ DEBUGP("no master exp for ct %p\n", ct); -+ return; -+ } -+ -+ ip_ct_gre_keymap_destroy(master); -+} -+ -+/* protocol helper struct */ -+static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE, -+ "gre", -+ gre_pkt_to_tuple, -+ gre_invert_tuple, -+ gre_print_tuple, -+ gre_print_conntrack, -+ gre_packet, -+ gre_new, -+ gre_destroy, -+ NULL, -+ THIS_MODULE }; -+ -+/* ip_conntrack_proto_gre initialization */ -+static int __init init(void) -+{ -+ int retcode; -+ -+ if ((retcode = ip_conntrack_protocol_register(&gre))) { -+ printk(KERN_ERR "Unable to register conntrack protocol " -+ "helper for gre: %d\n", retcode); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static void __exit fini(void) -+{ -+ struct list_head *pos, *n; -+ -+ /* delete all keymap entries */ -+ WRITE_LOCK(&ip_ct_gre_lock); -+ list_for_each_safe(pos, n, &gre_keymap_list) { -+ DEBUGP("deleting keymap %p at module unload time\n", pos); -+ list_del(pos); -+ kfree(pos); -+ } -+ WRITE_UNLOCK(&ip_ct_gre_lock); -+ -+ ip_conntrack_protocol_unregister(&gre); -+} -+ -+EXPORT_SYMBOL(ip_ct_gre_keymap_add); -+EXPORT_SYMBOL(ip_ct_gre_keymap_change); -+EXPORT_SYMBOL(ip_ct_gre_keymap_destroy); -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_core.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_core.c ---- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_core.c 2005-01-19 15:10:13.000000000 +0100 -+++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_core.c 2005-04-02 19:07:18.000000000 +0200 -@@ -424,7 +424,7 @@ - *tuple = *orig_tuple; - while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum)) - != NULL) { -- DEBUGP("Found best for "); DUMP_TUPLE(tuple); -+ DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple); - /* 3) The per-protocol part of the manip is made to - map into the range to make a unique tuple. */ - -@@ -564,9 +564,9 @@ - HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST", - conntrack); - DEBUGP("Original: "); -- DUMP_TUPLE(&orig_tp); -+ DUMP_TUPLE_RAW(&orig_tp); - DEBUGP("New: "); -- DUMP_TUPLE(&new_tuple); -+ DUMP_TUPLE_RAW(&new_tuple); - #endif - - /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT): -diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_pptp.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_pptp.c ---- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_pptp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_pptp.c 2005-04-02 19:14:52.000000000 +0200 -@@ -0,0 +1,475 @@ -+/* -+ * ip_nat_pptp.c - Version 1.5 -+ * -+ * NAT support for PPTP (Point to Point Tunneling Protocol). -+ * PPTP is a a protocol for creating virtual private networks. -+ * It is a specification defined by Microsoft and some vendors -+ * working with Microsoft. PPTP is built on top of a modified -+ * version of the Internet Generic Routing Encapsulation Protocol. -+ * GRE is defined in RFC 1701 and RFC 1702. Documentation of -+ * PPTP can be found in RFC 2637 -+ * -+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> -+ * -+ * Development of this code funded by Astaro AG (http://www.astaro.com/) -+ * -+ * TODO: - Support for multiple calls within one session -+ * (needs netfilter newnat code) -+ * - NAT to a unique tuple, not to TCP source port -+ * (needs netfilter tuple reservation) -+ * -+ * Changes: -+ * 2002-02-10 - Version 1.3 -+ * - Use ip_nat_mangle_tcp_packet() because of cloned skb's -+ * in local connections (Philip Craig <philipc@snapgear.com>) -+ * - add checks for magicCookie and pptp version -+ * - make argument list of pptp_{out,in}bound_packet() shorter -+ * - move to C99 style initializers -+ * - print version number at module loadtime -+ * 2003-09-22 - Version 1.5 -+ * - use SNATed tcp sourceport as callid, since we get called before -+ * TCP header is mangled (Philip Craig <philipc@snapgear.com>) -+ * -+ */ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/ip.h> -+#include <linux/tcp.h> -+#include <net/tcp.h> -+#include <linux/netfilter_ipv4/ip_nat.h> -+#include <linux/netfilter_ipv4/ip_nat_rule.h> -+#include <linux/netfilter_ipv4/ip_nat_helper.h> -+#include <linux/netfilter_ipv4/ip_nat_pptp.h> -+#include <linux/netfilter_ipv4/ip_conntrack_helper.h> -+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> -+#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> -+ -+#define IP_NAT_PPTP_VERSION "1.5" -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); -+MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); -+ -+ -+#if 0 -+#include "ip_conntrack_pptp_priv.h" -+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ -+ ": " format, ## args) -+#else -+#define DEBUGP(format, args...) -+#endif -+ -+static unsigned int -+pptp_nat_expected(struct sk_buff **pskb, -+ unsigned int hooknum, -+ struct ip_conntrack *ct, -+ struct ip_nat_info *info) -+{ -+ struct ip_conntrack *master = master_ct(ct); -+ struct ip_nat_multi_range mr; -+ struct ip_ct_pptp_master *ct_pptp_info; -+ struct ip_nat_pptp *nat_pptp_info; -+ u_int32_t newip, newcid; -+ int ret; -+ -+ IP_NF_ASSERT(info); -+ IP_NF_ASSERT(master); -+ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); -+ -+ DEBUGP("we have a connection!\n"); -+ -+ LOCK_BH(&ip_pptp_lock); -+ ct_pptp_info = &master->help.ct_pptp_info; -+ nat_pptp_info = &master->nat.help.nat_pptp_info; -+ -+ /* need to alter GRE tuple because conntrack expectfn() used 'wrong' -+ * (unmanipulated) values */ -+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { -+ DEBUGP("completing tuples with NAT info \n"); -+ /* we can do this, since we're unconfirmed */ -+ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == -+ htonl(ct_pptp_info->pac_call_id)) { -+ /* assume PNS->PAC */ -+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = -+ htonl(nat_pptp_info->pns_call_id); -+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = -+ htonl(nat_pptp_info->pns_call_id); -+ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; -+ newcid = htonl(nat_pptp_info->pac_call_id); -+ } else { -+ /* assume PAC->PNS */ -+ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key = -+ htonl(nat_pptp_info->pac_call_id); -+ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key = -+ htonl(nat_pptp_info->pac_call_id); -+ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ newcid = htonl(nat_pptp_info->pns_call_id); -+ } -+ } else { -+ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key == -+ htonl(ct_pptp_info->pac_call_id)) { -+ /* assume PNS->PAC */ -+ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; -+ newcid = htonl(ct_pptp_info->pns_call_id); -+ } -+ else { -+ /* assume PAC->PNS */ -+ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; -+ newcid = htonl(ct_pptp_info->pac_call_id); -+ } -+ } -+ -+ mr.rangesize = 1; -+ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED; -+ mr.range[0].min_ip = mr.range[0].max_ip = newip; -+ mr.range[0].min = mr.range[0].max = -+ ((union ip_conntrack_manip_proto ) { newcid }); -+ DEBUGP("change ip to %u.%u.%u.%u\n", -+ NIPQUAD(newip)); -+ DEBUGP("change key to 0x%x\n", ntohl(newcid)); -+ ret = ip_nat_setup_info(ct, &mr, hooknum); -+ -+ UNLOCK_BH(&ip_pptp_lock); -+ -+ return ret; -+ -+} -+ -+/* outbound packets == from PNS to PAC */ -+static inline unsigned int -+pptp_outbound_pkt(struct sk_buff **pskb, -+ struct ip_conntrack *ct, -+ enum ip_conntrack_info ctinfo, -+ struct ip_conntrack_expect *exp) -+ -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct tcphdr *tcph = (void *) iph + iph->ihl*4; -+ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) -+ ((void *)tcph + tcph->doff*4); -+ -+ struct PptpControlHeader *ctlh; -+ union pptp_ctrl_union pptpReq; -+ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; -+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; -+ -+ u_int16_t msg, *cid = NULL, new_callid; -+ -+ /* FIXME: size checks !!! */ -+ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); -+ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); -+ -+ new_callid = htons(ct_pptp_info->pns_call_id); -+ -+ switch (msg = ntohs(ctlh->messageType)) { -+ case PPTP_OUT_CALL_REQUEST: -+ cid = &pptpReq.ocreq->callID; -+ /* FIXME: ideally we would want to reserve a call ID -+ * here. current netfilter NAT core is not able to do -+ * this :( For now we use TCP source port. This breaks -+ * multiple calls within one control session */ -+ -+ /* save original call ID in nat_info */ -+ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; -+ -+ /* don't use tcph->source since we are at a DSTmanip -+ * hook (e.g. PREROUTING) and pkt is not mangled yet */ -+ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; -+ -+ /* save new call ID in ct info */ -+ ct_pptp_info->pns_call_id = ntohs(new_callid); -+ break; -+ case PPTP_IN_CALL_REPLY: -+ cid = &pptpReq.icreq->callID; -+ break; -+ case PPTP_CALL_CLEAR_REQUEST: -+ cid = &pptpReq.clrreq->callID; -+ break; -+ default: -+ DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, -+ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); -+ /* fall through */ -+ -+ case PPTP_SET_LINK_INFO: -+ /* only need to NAT in case PAC is behind NAT box */ -+ case PPTP_START_SESSION_REQUEST: -+ case PPTP_START_SESSION_REPLY: -+ case PPTP_STOP_SESSION_REQUEST: -+ case PPTP_STOP_SESSION_REPLY: -+ case PPTP_ECHO_REQUEST: -+ case PPTP_ECHO_REPLY: -+ /* no need to alter packet */ -+ return NF_ACCEPT; -+ } -+ -+ IP_NF_ASSERT(cid); -+ -+ DEBUGP("altering call id from 0x%04x to 0x%04x\n", -+ ntohs(*cid), ntohs(new_callid)); -+ -+ /* mangle packet */ -+ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph, -+ sizeof(new_callid), (char *)&new_callid, -+ sizeof(new_callid)); -+ -+ return NF_ACCEPT; -+} -+ -+/* inbound packets == from PAC to PNS */ -+static inline unsigned int -+pptp_inbound_pkt(struct sk_buff **pskb, -+ struct ip_conntrack *ct, -+ enum ip_conntrack_info ctinfo, -+ struct ip_conntrack_expect *oldexp) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct tcphdr *tcph = (void *) iph + iph->ihl*4; -+ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *) -+ ((void *)tcph + tcph->doff*4); -+ -+ struct PptpControlHeader *ctlh; -+ union pptp_ctrl_union pptpReq; -+ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; -+ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; -+ -+ u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL; -+ u_int32_t old_dst_ip; -+ -+ struct ip_conntrack_tuple t, inv_t; -+ struct ip_conntrack_tuple *orig_t, *reply_t; -+ -+ /* FIXME: size checks !!! */ -+ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph)); -+ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh)); -+ -+ new_pcid = htons(nat_pptp_info->pns_call_id); -+ -+ switch (msg = ntohs(ctlh->messageType)) { -+ case PPTP_OUT_CALL_REPLY: -+ pcid = &pptpReq.ocack->peersCallID; -+ cid = &pptpReq.ocack->callID; -+ if (!oldexp) { -+ DEBUGP("outcall but no expectation\n"); -+ break; -+ } -+ old_dst_ip = oldexp->tuple.dst.ip; -+ t = oldexp->tuple; -+ invert_tuplepr(&inv_t, &t); -+ -+ /* save original PAC call ID in nat_info */ -+ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; -+ -+ /* alter expectation */ -+ orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; -+ reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; -+ if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) { -+ /* expectation for PNS->PAC direction */ -+ t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); -+ t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); -+ inv_t.src.ip = reply_t->src.ip; -+ inv_t.dst.ip = reply_t->dst.ip; -+ inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); -+ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); -+ } else { -+ /* expectation for PAC->PNS direction */ -+ t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id); -+ t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id); -+ inv_t.src.ip = orig_t->src.ip; -+ inv_t.dst.ip = orig_t->dst.ip; -+ inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id); -+ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id); -+ } -+ -+ if (!ip_conntrack_change_expect(oldexp, &t)) { -+ DEBUGP("successfully changed expect\n"); -+ } else { -+ DEBUGP("can't change expect\n"); -+ } -+ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t); -+ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t); -+ break; -+ case PPTP_IN_CALL_CONNECT: -+ pcid = &pptpReq.iccon->peersCallID; -+ if (!oldexp) -+ break; -+ old_dst_ip = oldexp->tuple.dst.ip; -+ t = oldexp->tuple; -+ -+ /* alter expectation, no need for callID */ -+ if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) { -+ /* expectation for PNS->PAC direction */ -+ t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; -+ } else { -+ /* expectation for PAC->PNS direction */ -+ t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; -+ } -+ -+ if (!ip_conntrack_change_expect(oldexp, &t)) { -+ DEBUGP("successfully changed expect\n"); -+ } else { -+ DEBUGP("can't change expect\n"); -+ } -+ break; -+ case PPTP_IN_CALL_REQUEST: -+ /* only need to nat in case PAC is behind NAT box */ -+ break; -+ case PPTP_WAN_ERROR_NOTIFY: -+ pcid = &pptpReq.wanerr->peersCallID; -+ break; -+ case PPTP_CALL_DISCONNECT_NOTIFY: -+ pcid = &pptpReq.disc->callID; -+ break; -+ -+ default: -+ DEBUGP("unknown inbound packet %s\n", -+ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]); -+ /* fall through */ -+ -+ case PPTP_START_SESSION_REQUEST: -+ case PPTP_START_SESSION_REPLY: -+ case PPTP_STOP_SESSION_REQUEST: -+ case PPTP_STOP_SESSION_REPLY: -+ case PPTP_ECHO_REQUEST: -+ case PPTP_ECHO_REPLY: -+ /* no need to alter packet */ -+ return NF_ACCEPT; -+ } -+ -+ /* mangle packet */ -+ IP_NF_ASSERT(pcid); -+ DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", -+ ntohs(*pcid), ntohs(new_pcid)); -+ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph, -+ sizeof(new_pcid), (char *)&new_pcid, -+ sizeof(new_pcid)); -+ -+ if (new_cid) { -+ IP_NF_ASSERT(cid); -+ DEBUGP("altering call id from 0x%04x to 0x%04x\n", -+ ntohs(*cid), ntohs(new_cid)); -+ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, -+ (void *)cid - (void *)pptph, -+ sizeof(new_cid), (char *)&new_cid, -+ sizeof(new_cid)); -+ } -+ -+ /* great, at least we don't need to resize packets */ -+ return NF_ACCEPT; -+} -+ -+ -+static unsigned int tcp_help(struct ip_conntrack *ct, -+ struct ip_conntrack_expect *exp, -+ struct ip_nat_info *info, -+ enum ip_conntrack_info ctinfo, -+ unsigned int hooknum, struct sk_buff **pskb) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct tcphdr *tcph = (void *) iph + iph->ihl*4; -+ unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4; -+ struct pptp_pkt_hdr *pptph; -+ -+ int dir; -+ -+ DEBUGP("entering\n"); -+ -+ /* Only mangle things once: DST for original direction -+ and SRC for reply direction. */ -+ dir = CTINFO2DIR(ctinfo); -+ if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC -+ && dir == IP_CT_DIR_ORIGINAL) -+ || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST -+ && dir == IP_CT_DIR_REPLY))) { -+ DEBUGP("Not touching dir %s at hook %s\n", -+ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", -+ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" -+ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" -+ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" -+ : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???"); -+ return NF_ACCEPT; -+ } -+ -+ /* if packet is too small, just skip it */ -+ if (datalen < sizeof(struct pptp_pkt_hdr)+ -+ sizeof(struct PptpControlHeader)) { -+ DEBUGP("pptp packet too short\n"); -+ return NF_ACCEPT; -+ } -+ -+ pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4); -+ -+ /* if it's not a control message, we can't handle it */ -+ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || -+ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { -+ DEBUGP("not a pptp control packet\n"); -+ return NF_ACCEPT; -+ } -+ -+ LOCK_BH(&ip_pptp_lock); -+ -+ if (dir == IP_CT_DIR_ORIGINAL) { -+ /* reuqests sent by client to server (PNS->PAC) */ -+ pptp_outbound_pkt(pskb, ct, ctinfo, exp); -+ } else { -+ /* response from the server to the client (PAC->PNS) */ -+ pptp_inbound_pkt(pskb, ct, ctinfo, exp); -+ } -+ -+ UNLOCK_BH(&ip_pptp_lock); -+ -+ return NF_ACCEPT; -+} -+ -+/* nat helper struct for control connection */ -+static struct ip_nat_helper pptp_tcp_helper = { -+ .list = { NULL, NULL }, -+ .name = "pptp", -+ .flags = IP_NAT_HELPER_F_ALWAYS, -+ .me = THIS_MODULE, -+ .tuple = { .src = { .ip = 0, -+ .u = { .tcp = { .port = -+ __constant_htons(PPTP_CONTROL_PORT) } -+ } -+ }, -+ .dst = { .ip = 0, -+ .u = { .all = 0 }, -+ .protonum = IPPROTO_TCP -+ } -+ }, -+ -+ .mask = { .src = { .ip = 0, -+ .u = { .tcp = { .port = 0xFFFF } } -+ }, -+ .dst = { .ip = 0, -+ .u = { .all = 0 }, -+ .protonum = 0xFFFF -+ } -+ }, -+ .help = tcp_help, -+ .expect = pptp_nat_expected -+}; -+ -+ -+static int __init init(void) -+{ -+ DEBUGP("%s: registering NAT helper\n", __FILE__); -+ if (ip_nat_helper_register(&pptp_tcp_helper)) { -+ printk(KERN_ERR "Unable to register NAT application helper " -+ "for pptp\n"); -+ return -EIO; -+ } -+ -+ printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); -+ return 0; -+} -+ -+static void __exit fini(void) -+{ -+ DEBUGP("cleanup_module\n" ); -+ ip_nat_helper_unregister(&pptp_tcp_helper); -+ printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); -+} -+ -+module_init(init); -+module_exit(fini); -Binary files linux-2.4.29-old/net/ipv4/netfilter/.ip_nat_pptp.c.swp and linux-2.4.29-dev/net/ipv4/netfilter/.ip_nat_pptp.c.swp differ -diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_proto_gre.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_proto_gre.c ---- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_proto_gre.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_proto_gre.c 2005-04-02 19:15:10.000000000 +0200 -@@ -0,0 +1,202 @@ -+/* -+ * ip_nat_proto_gre.c - Version 1.2 -+ * -+ * NAT protocol helper module for GRE. -+ * -+ * GRE is a generic encapsulation protocol, which is generally not very -+ * suited for NAT, as it has no protocol-specific part as port numbers. -+ * -+ * It has an optional key field, which may help us distinguishing two -+ * connections between the same two hosts. -+ * -+ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 -+ * -+ * PPTP is built on top of a modified version of GRE, and has a mandatory -+ * field called "CallID", which serves us for the same purpose as the key -+ * field in plain GRE. -+ * -+ * Documentation about PPTP can be found in RFC 2637 -+ * -+ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org> -+ * -+ * Development of this code funded by Astaro AG (http://www.astaro.com/) -+ * -+ */ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/ip.h> -+#include <linux/netfilter_ipv4/ip_nat.h> -+#include <linux/netfilter_ipv4/ip_nat_rule.h> -+#include <linux/netfilter_ipv4/ip_nat_protocol.h> -+#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); -+MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); -+ -+#if 0 -+#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \ -+ ": " format, ## args) -+#else -+#define DEBUGP(x, args...) -+#endif -+ -+/* is key in given range between min and max */ -+static int -+gre_in_range(const struct ip_conntrack_tuple *tuple, -+ enum ip_nat_manip_type maniptype, -+ const union ip_conntrack_manip_proto *min, -+ const union ip_conntrack_manip_proto *max) -+{ -+ u_int32_t key; -+ -+ if (maniptype == IP_NAT_MANIP_SRC) -+ key = tuple->src.u.gre.key; -+ else -+ key = tuple->dst.u.gre.key; -+ -+ return ntohl(key) >= ntohl(min->gre.key) -+ && ntohl(key) <= ntohl(max->gre.key); -+} -+ -+/* generate unique tuple ... */ -+static int -+gre_unique_tuple(struct ip_conntrack_tuple *tuple, -+ const struct ip_nat_range *range, -+ enum ip_nat_manip_type maniptype, -+ const struct ip_conntrack *conntrack) -+{ -+ u_int32_t min, i, range_size; -+ u_int32_t key = 0, *keyptr; -+ -+ if (maniptype == IP_NAT_MANIP_SRC) -+ keyptr = &tuple->src.u.gre.key; -+ else -+ keyptr = &tuple->dst.u.gre.key; -+ -+ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { -+ -+ DEBUGP("%p: NATing GRE PPTP\n", conntrack); -+ min = 1; -+ range_size = 0xffff; -+ -+ } else { -+ min = ntohl(range->min.gre.key); -+ range_size = ntohl(range->max.gre.key) - min + 1; -+ } -+ -+ DEBUGP("min = %u, range_size = %u\n", min, range_size); -+ -+ for (i = 0; i < range_size; i++, key++) { -+ *keyptr = htonl(min + key % range_size); -+ if (!ip_nat_used_tuple(tuple, conntrack)) -+ return 1; -+ } -+ -+ DEBUGP("%p: no NAT mapping\n", conntrack); -+ -+ return 0; -+} -+ -+/* manipulate a GRE packet according to maniptype */ -+static void -+gre_manip_pkt(struct iphdr *iph, size_t len, -+ const struct ip_conntrack_manip *manip, -+ enum ip_nat_manip_type maniptype) -+{ -+ struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl); -+ struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh; -+ -+ /* we only have destination manip of a packet, since 'source key' -+ * is not present in the packet itself */ -+ if (maniptype == IP_NAT_MANIP_DST) { -+ /* key manipulation is always dest */ -+ switch (greh->version) { -+ case 0: -+ if (!greh->key) { -+ DEBUGP("can't nat GRE w/o key\n"); -+ break; -+ } -+ if (greh->csum) { -+ /* FIXME: Never tested this code... */ -+ *(gre_csum(greh)) = -+ ip_nat_cheat_check(~*(gre_key(greh)), -+ manip->u.gre.key, -+ *(gre_csum(greh))); -+ } -+ *(gre_key(greh)) = manip->u.gre.key; -+ break; -+ case GRE_VERSION_PPTP: -+ DEBUGP("call_id -> 0x%04x\n", -+ ntohl(manip->u.gre.key)); -+ pgreh->call_id = htons(ntohl(manip->u.gre.key)); -+ break; -+ default: -+ DEBUGP("can't nat unknown GRE version\n"); -+ break; -+ } -+ } -+} -+ -+/* print out a nat tuple */ -+static unsigned int -+gre_print(char *buffer, -+ const struct ip_conntrack_tuple *match, -+ const struct ip_conntrack_tuple *mask) -+{ -+ unsigned int len = 0; -+ -+ if (mask->src.u.gre.key) -+ len += sprintf(buffer + len, "srckey=0x%x ", -+ ntohl(match->src.u.gre.key)); -+ -+ if (mask->dst.u.gre.key) -+ len += sprintf(buffer + len, "dstkey=0x%x ", -+ ntohl(match->src.u.gre.key)); -+ -+ return len; -+} -+ -+/* print a range of keys */ -+static unsigned int -+gre_print_range(char *buffer, const struct ip_nat_range *range) -+{ -+ if (range->min.gre.key != 0 -+ || range->max.gre.key != 0xFFFF) { -+ if (range->min.gre.key == range->max.gre.key) -+ return sprintf(buffer, "key 0x%x ", -+ ntohl(range->min.gre.key)); -+ else -+ return sprintf(buffer, "keys 0x%u-0x%u ", -+ ntohl(range->min.gre.key), -+ ntohl(range->max.gre.key)); -+ } else -+ return 0; -+} -+ -+/* nat helper struct */ -+static struct ip_nat_protocol gre = -+ { { NULL, NULL }, "GRE", IPPROTO_GRE, -+ gre_manip_pkt, -+ gre_in_range, -+ gre_unique_tuple, -+ gre_print, -+ gre_print_range -+ }; -+ -+static int __init init(void) -+{ -+ if (ip_nat_protocol_register(&gre)) -+ return -EIO; -+ -+ return 0; -+} -+ -+static void __exit fini(void) -+{ -+ ip_nat_protocol_unregister(&gre); -+} -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.29-old/net/ipv4/netfilter/Makefile linux-2.4.29-dev/net/ipv4/netfilter/Makefile ---- linux-2.4.29-old/net/ipv4/netfilter/Makefile 2005-04-02 19:04:11.000000000 +0200 -+++ linux-2.4.29-dev/net/ipv4/netfilter/Makefile 2005-04-02 19:07:18.000000000 +0200 -@@ -36,23 +36,32 @@ - ifdef CONFIG_IP_NF_AMANDA - export-objs += ip_conntrack_amanda.o - endif -- - obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o - obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o - ifdef CONFIG_IP_NF_FTP - export-objs += ip_conntrack_ftp.o - endif -- - obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o - ifdef CONFIG_IP_NF_IRC - export-objs += ip_conntrack_irc.o - endif -+obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o -+ifdef CONFIG_IP_NF_CT_PROTO_GRE -+ export-objs += ip_conntrack_proto_gre.o -+endif -+obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o -+ifdef CONFIG_IP_NF_NAT_PPTP -+ export-objs += ip_conntrack_pptp.o -+endif -+ - - # NAT helpers - obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o - obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o - obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o - obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o -+obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o -+obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o - - # generic IP tables - obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/target/linux/linux-2.4/patches/generic/104-netfilter_maxconn.patch b/target/linux/linux-2.4/patches/generic/104-netfilter_maxconn.patch deleted file mode 100644 index 001ed67b8..000000000 --- a/target/linux/linux-2.4/patches/generic/104-netfilter_maxconn.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- ../../buildroot-unpacked/build_mipsel/linux/net/ipv4/netfilter/ip_conntrack_core.c 2004-11-28 22:59:36.000000000 -0500 -+++ linux/net/ipv4/netfilter/ip_conntrack_core.c 2004-11-30 05:05:32.000000000 -0500 -@@ -1386,7 +1386,7 @@ - nf_unregister_sockopt(&so_getorigdst); - } - --static int hashsize = 0; -+static int hashsize = 5953; - MODULE_PARM(hashsize, "i"); - - int __init ip_conntrack_init(void) -@@ -1407,7 +1407,7 @@ - if (ip_conntrack_htable_size < 16) - ip_conntrack_htable_size = 16; - } -- ip_conntrack_max = 8 * ip_conntrack_htable_size; -+ ip_conntrack_max = ip_conntrack_htable_size; - - printk("ip_conntrack version %s (%u buckets, %d max)" - " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION, diff --git a/target/linux/linux-2.4/patches/generic/105-netfilter_TTL.patch b/target/linux/linux-2.4/patches/generic/105-netfilter_TTL.patch deleted file mode 100644 index 0aa3c8043..000000000 --- a/target/linux/linux-2.4/patches/generic/105-netfilter_TTL.patch +++ /dev/null @@ -1,180 +0,0 @@ -diff -urN linux-2.4.30.old/Documentation/Configure.help linux-2.4.30.dev/Documentation/Configure.help ---- linux-2.4.30.old/Documentation/Configure.help 2005-04-27 11:35:46.000000000 +0200 -+++ linux-2.4.30.dev/Documentation/Configure.help 2005-04-27 11:43:49.000000000 +0200 -@@ -3209,6 +3209,15 @@ - If you want to compile it as a module, say M here and read - <file:Documentation/modules.txt>. If unsure, say `N'. - -+TTL target support -+CONFIG_IP_NF_TARGET_TTL -+ This option adds a `TTL' target, which enables the user to set -+ the TTL value or increment / decrement the TTL value by a given -+ amount. -+ -+ If you want to compile it as a module, say M here and read -+ Documentation/modules.txt. If unsure, say `N'. -+ - ipchains (2.2-style) support - CONFIG_IP_NF_COMPAT_IPCHAINS - This option places ipchains (with masquerading and redirection -diff -urN linux-2.4.30.old/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.4.30.dev/include/linux/netfilter_ipv4/ipt_TTL.h ---- linux-2.4.30.old/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.dev/include/linux/netfilter_ipv4/ipt_TTL.h 2005-04-27 11:43:49.000000000 +0200 -@@ -0,0 +1,21 @@ -+/* TTL modification module for IP tables -+ * (C) 2000 by Harald Welte <laforge@gnumonks.org> */ -+ -+#ifndef _IPT_TTL_H -+#define _IPT_TTL_H -+ -+enum { -+ IPT_TTL_SET = 0, -+ IPT_TTL_INC, -+ IPT_TTL_DEC -+}; -+ -+#define IPT_TTL_MAXMODE IPT_TTL_DEC -+ -+struct ipt_TTL_info { -+ u_int8_t mode; -+ u_int8_t ttl; -+}; -+ -+ -+#endif -diff -urN linux-2.4.30.old/net/ipv4/netfilter/Config.in linux-2.4.30.dev/net/ipv4/netfilter/Config.in ---- linux-2.4.30.old/net/ipv4/netfilter/Config.in 2005-04-27 11:35:45.000000000 +0200 -+++ linux-2.4.30.dev/net/ipv4/netfilter/Config.in 2005-04-27 11:43:49.000000000 +0200 -@@ -129,6 +129,7 @@ - dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE - fi - dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES -+ dep_tristate ' TTL target support' CONFIG_IP_NF_TARGET_TTL $CONFIG_IP_NF_IPTABLES - dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES - dep_tristate ' TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES - fi -diff -urN linux-2.4.30.old/net/ipv4/netfilter/ipt_TTL.c linux-2.4.30.dev/net/ipv4/netfilter/ipt_TTL.c ---- linux-2.4.30.old/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.dev/net/ipv4/netfilter/ipt_TTL.c 2005-04-27 11:43:49.000000000 +0200 -@@ -0,0 +1,110 @@ -+/* TTL modification target for IP tables -+ * (C) 2000 by Harald Welte <laforge@gnumonks.org> -+ * -+ * Version: $Revision: 1.1 $ -+ * -+ * This software is distributed under the terms of GNU GPL -+ */ -+ -+#include <linux/module.h> -+#include <linux/skbuff.h> -+#include <linux/ip.h> -+#include <net/checksum.h> -+ -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ipt_TTL.h> -+ -+MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); -+MODULE_DESCRIPTION("IP tables TTL modification module"); -+MODULE_LICENSE("GPL"); -+ -+static unsigned int ipt_ttl_target(struct sk_buff **pskb, unsigned int hooknum, -+ const struct net_device *in, const struct net_device *out, -+ const void *targinfo, void *userinfo) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ const struct ipt_TTL_info *info = targinfo; -+ u_int16_t diffs[2]; -+ int new_ttl; -+ -+ switch (info->mode) { -+ case IPT_TTL_SET: -+ new_ttl = info->ttl; -+ break; -+ case IPT_TTL_INC: -+ new_ttl = iph->ttl + info->ttl; -+ if (new_ttl > 255) -+ new_ttl = 255; -+ break; -+ case IPT_TTL_DEC: -+ new_ttl = iph->ttl - info->ttl; -+ if (new_ttl < 0) -+ new_ttl = 0; -+ break; -+ default: -+ new_ttl = iph->ttl; -+ break; -+ } -+ -+ if (new_ttl != iph->ttl) { -+ diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF; -+ iph->ttl = new_ttl; -+ diffs[1] = htons(((unsigned)iph->ttl) << 8); -+ iph->check = csum_fold(csum_partial((char *)diffs, -+ sizeof(diffs), -+ iph->check^0xFFFF)); -+ (*pskb)->nfcache |= NFC_ALTERED; -+ } -+ -+ return IPT_CONTINUE; -+} -+ -+static int ipt_ttl_checkentry(const char *tablename, -+ const struct ipt_entry *e, -+ void *targinfo, -+ unsigned int targinfosize, -+ unsigned int hook_mask) -+{ -+ struct ipt_TTL_info *info = targinfo; -+ -+ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) { -+ printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n", -+ targinfosize, -+ IPT_ALIGN(sizeof(struct ipt_TTL_info))); -+ return 0; -+ } -+ -+ if (strcmp(tablename, "mangle")) { -+ printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename); -+ return 0; -+ } -+ -+ if (info->mode > IPT_TTL_MAXMODE) { -+ printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n", -+ info->mode); -+ return 0; -+ } -+ -+ if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) { -+ printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n"); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+static struct ipt_target ipt_TTL = { { NULL, NULL }, "TTL", -+ ipt_ttl_target, ipt_ttl_checkentry, NULL, THIS_MODULE }; -+ -+static int __init init(void) -+{ -+ return ipt_register_target(&ipt_TTL); -+} -+ -+static void __exit fini(void) -+{ -+ ipt_unregister_target(&ipt_TTL); -+} -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.30.old/net/ipv4/netfilter/Makefile linux-2.4.30.dev/net/ipv4/netfilter/Makefile ---- linux-2.4.30.old/net/ipv4/netfilter/Makefile 2005-04-27 11:35:45.000000000 +0200 -+++ linux-2.4.30.dev/net/ipv4/netfilter/Makefile 2005-04-27 11:43:49.000000000 +0200 -@@ -112,6 +112,7 @@ - obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o - obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o - obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o -+obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o - obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o - obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o - diff --git a/target/linux/linux-2.4/patches/generic/111-netfilter_NETMAP.patch b/target/linux/linux-2.4/patches/generic/111-netfilter_NETMAP.patch deleted file mode 100644 index ccd639181..000000000 --- a/target/linux/linux-2.4/patches/generic/111-netfilter_NETMAP.patch +++ /dev/null @@ -1,159 +0,0 @@ -diff -urN linux-2.4.30.orig/Documentation/Configure.help linux-2.4.30/Documentation/Configure.help ---- linux-2.4.30.orig/Documentation/Configure.help 2005-07-01 02:06:36.000000000 +0200 -+++ linux-2.4.30/Documentation/Configure.help 2005-07-01 00:41:09.000000000 +0200 -@@ -3086,6 +3086,17 @@ - If you want to compile it as a module, say M here and read - <file:Documentation/modules.txt>. If unsure, say `N'. - -+NETMAP target support -+CONFIG_IP_NF_TARGET_NETMAP -+ NETMAP is an implementation of static 1:1 NAT mapping of network -+ addresses. It maps the network address part, while keeping the -+ host address part intact. It is similar to Fast NAT, except that -+ Netfilter's connection tracking doesn't work well with Fast NAT. -+ -+ If you want to compile it as a module, say M here and read -+ Documentation/modules.txt. The module will be called -+ ipt_NETMAP.o. If unsure, say `N'. -+ - Packet mangling - CONFIG_IP_NF_MANGLE - This option adds a `mangle' table to iptables: see the man page for -diff -urN linux-2.4.30.orig/net/ipv4/netfilter/Config.in linux-2.4.30/net/ipv4/netfilter/Config.in ---- linux-2.4.30.orig/net/ipv4/netfilter/Config.in 2005-07-01 02:06:35.000000000 +0200 -+++ linux-2.4.30/net/ipv4/netfilter/Config.in 2005-07-01 00:41:09.000000000 +0200 -@@ -69,6 +69,7 @@ - define_bool CONFIG_IP_NF_NAT_NEEDED y - dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT - dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT -+ dep_tristate ' NETMAP target support' CONFIG_IP_NF_TARGET_NETMAP $CONFIG_IP_NF_NAT - if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then - define_tristate CONFIG_IP_NF_NAT_PPTP m - else -diff -urN linux-2.4.30.orig/net/ipv4/netfilter/ipt_NETMAP.c linux-2.4.30/net/ipv4/netfilter/ipt_NETMAP.c ---- linux-2.4.30.orig/net/ipv4/netfilter/ipt_NETMAP.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30/net/ipv4/netfilter/ipt_NETMAP.c 2005-07-01 00:41:09.000000000 +0200 -@@ -0,0 +1,112 @@ -+/* NETMAP - static NAT mapping of IP network addresses (1:1). -+ The mapping can be applied to source (POSTROUTING), -+ destination (PREROUTING), or both (with separate rules). -+ -+ Author: Svenning Soerensen <svenning@post5.tele.dk> -+*/ -+ -+#include <linux/config.h> -+#include <linux/ip.h> -+#include <linux/module.h> -+#include <linux/netdevice.h> -+#include <linux/netfilter.h> -+#include <linux/netfilter_ipv4.h> -+#include <linux/netfilter_ipv4/ip_nat_rule.h> -+ -+#define MODULENAME "NETMAP" -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>"); -+MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target"); -+ -+#if 0 -+#define DEBUGP printk -+#else -+#define DEBUGP(format, args...) -+#endif -+ -+static int -+check(const char *tablename, -+ const struct ipt_entry *e, -+ void *targinfo, -+ unsigned int targinfosize, -+ unsigned int hook_mask) -+{ -+ const struct ip_nat_multi_range *mr = targinfo; -+ -+ if (strcmp(tablename, "nat") != 0) { -+ DEBUGP(MODULENAME":check: bad table `%s'.\n", tablename); -+ return 0; -+ } -+ if (targinfosize != IPT_ALIGN(sizeof(*mr))) { -+ DEBUGP(MODULENAME":check: size %u.\n", targinfosize); -+ return 0; -+ } -+ if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING))) { -+ DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask); -+ return 0; -+ } -+ if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) { -+ DEBUGP(MODULENAME":check: bad MAP_IPS.\n"); -+ return 0; -+ } -+ if (mr->rangesize != 1) { -+ DEBUGP(MODULENAME":check: bad rangesize %u.\n", mr->rangesize); -+ return 0; -+ } -+ return 1; -+} -+ -+static unsigned int -+target(struct sk_buff **pskb, -+ unsigned int hooknum, -+ const struct net_device *in, -+ const struct net_device *out, -+ const void *targinfo, -+ void *userinfo) -+{ -+ struct ip_conntrack *ct; -+ enum ip_conntrack_info ctinfo; -+ u_int32_t new_ip, netmask; -+ const struct ip_nat_multi_range *mr = targinfo; -+ struct ip_nat_multi_range newrange; -+ -+ IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING -+ || hooknum == NF_IP_POST_ROUTING); -+ ct = ip_conntrack_get(*pskb, &ctinfo); -+ -+ netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip); -+ -+ if (hooknum == NF_IP_PRE_ROUTING) -+ new_ip = (*pskb)->nh.iph->daddr & ~netmask; -+ else -+ new_ip = (*pskb)->nh.iph->saddr & ~netmask; -+ new_ip |= mr->range[0].min_ip & netmask; -+ -+ newrange = ((struct ip_nat_multi_range) -+ { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, -+ new_ip, new_ip, -+ mr->range[0].min, mr->range[0].max } } }); -+ -+ /* Hand modified range to generic setup. */ -+ return ip_nat_setup_info(ct, &newrange, hooknum); -+} -+ -+static struct ipt_target target_module = { -+ .name = MODULENAME, -+ .target = target, -+ .checkentry = check, -+ .me = THIS_MODULE -+}; -+ -+static int __init init(void) -+{ -+ return ipt_register_target(&target_module); -+} -+ -+static void __exit fini(void) -+{ -+ ipt_unregister_target(&target_module); -+} -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.30.orig/net/ipv4/netfilter/Makefile linux-2.4.30/net/ipv4/netfilter/Makefile ---- linux-2.4.30.orig/net/ipv4/netfilter/Makefile 2005-07-01 02:06:35.000000000 +0200 -+++ linux-2.4.30/net/ipv4/netfilter/Makefile 2005-07-01 00:41:09.000000000 +0200 -@@ -110,6 +110,7 @@ - obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o - obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o - obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o -+obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o - obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o - obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o - obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o diff --git a/target/linux/linux-2.4/patches/generic/113-netfilter_connmark.patch b/target/linux/linux-2.4/patches/generic/113-netfilter_connmark.patch deleted file mode 100644 index 154314dc4..000000000 --- a/target/linux/linux-2.4/patches/generic/113-netfilter_connmark.patch +++ /dev/null @@ -1,351 +0,0 @@ -diff -urN linux.old/include/linux/netfilter_ipv4/ip_conntrack.h linux.dev/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux.old/include/linux/netfilter_ipv4/ip_conntrack.h 2005-08-20 20:02:06.619827000 +0200 -+++ linux.dev/include/linux/netfilter_ipv4/ip_conntrack.h 2005-08-20 20:19:23.302029232 +0200 -@@ -226,6 +226,9 @@ - unsigned int app_data_len; - } layer7; - #endif -+#if defined(CONFIG_IP_NF_CONNTRACK_MARK) -+ unsigned long mark; -+#endif - }; - - /* get master conntrack via master expectation */ -diff -urN linux.old/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux.dev/include/linux/netfilter_ipv4/ipt_CONNMARK.h ---- linux.old/include/linux/netfilter_ipv4/ipt_CONNMARK.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/include/linux/netfilter_ipv4/ipt_CONNMARK.h 2005-08-20 20:19:41.058329864 +0200 -@@ -0,0 +1,25 @@ -+#ifndef _IPT_CONNMARK_H_target -+#define _IPT_CONNMARK_H_target -+ -+/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> -+ * by Henrik Nordstrom <hno@marasystems.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+enum { -+ IPT_CONNMARK_SET = 0, -+ IPT_CONNMARK_SAVE, -+ IPT_CONNMARK_RESTORE -+}; -+ -+struct ipt_connmark_target_info { -+ unsigned long mark; -+ unsigned long mask; -+ u_int8_t mode; -+}; -+ -+#endif /*_IPT_CONNMARK_H_target*/ -diff -urN linux.old/include/linux/netfilter_ipv4/ipt_connmark.h linux.dev/include/linux/netfilter_ipv4/ipt_connmark.h ---- linux.old/include/linux/netfilter_ipv4/ipt_connmark.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/include/linux/netfilter_ipv4/ipt_connmark.h 2005-08-20 20:19:41.058329864 +0200 -@@ -0,0 +1,18 @@ -+#ifndef _IPT_CONNMARK_H -+#define _IPT_CONNMARK_H -+ -+/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> -+ * by Henrik Nordstrom <hno@marasystems.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+struct ipt_connmark_info { -+ unsigned long mark, mask; -+ u_int8_t invert; -+}; -+ -+#endif /*_IPT_CONNMARK_H*/ -diff -urN linux.old/net/ipv4/netfilter/Config.in linux.dev/net/ipv4/netfilter/Config.in ---- linux.old/net/ipv4/netfilter/Config.in 2005-08-20 20:02:09.325416000 +0200 -+++ linux.dev/net/ipv4/netfilter/Config.in 2005-08-20 20:29:11.546602464 +0200 -@@ -6,7 +6,8 @@ - - tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK - if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then -- dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK -+ bool ' Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK -+ dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACKa - dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK - dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK - dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK -@@ -42,6 +43,9 @@ - if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then - dep_tristate ' Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES - dep_tristate ' Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES -+ if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then -+ dep_tristate ' Connection mark match support' CONFIG_IP_NF_MATCH_CONNMARK $CONFIG_IP_NF_IPTABLES -+ fi - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES -@@ -125,6 +129,9 @@ - - dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE - fi -+ if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then -+ dep_tristate ' CONNMARK target support' CONFIG_IP_NF_TARGET_CONNMARK $CONFIG_IP_NF_IPTABLES -+ fi - dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES - dep_tristate ' TTL target support' CONFIG_IP_NF_TARGET_TTL $CONFIG_IP_NF_IPTABLES - dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES -diff -urN linux.old/net/ipv4/netfilter/Makefile linux.dev/net/ipv4/netfilter/Makefile ---- linux.old/net/ipv4/netfilter/Makefile 2005-08-20 20:02:09.326416000 +0200 -+++ linux.dev/net/ipv4/netfilter/Makefile 2005-08-20 20:29:54.081136232 +0200 -@@ -93,6 +93,7 @@ - - obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o - obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o -+obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o - obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o - obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o - obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o -@@ -110,6 +111,7 @@ - obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o - obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o - obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o -+obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o - obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o - obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o - obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o -diff -urN linux.old/net/ipv4/netfilter/ip_conntrack_core.c linux.dev/net/ipv4/netfilter/ip_conntrack_core.c ---- linux.old/net/ipv4/netfilter/ip_conntrack_core.c 2005-08-20 20:02:06.828795000 +0200 -+++ linux.dev/net/ipv4/netfilter/ip_conntrack_core.c 2005-08-20 20:33:23.308328864 +0200 -@@ -755,6 +755,9 @@ - __set_bit(IPS_EXPECTED_BIT, &conntrack->status); - conntrack->master = expected; - expected->sibling = conntrack; -+#ifdef CONFIG_IP_NF_CONNTRACK_MARK -+ conntrack->mark = expected->expectant->mark; -+#endif - LIST_DELETE(&ip_conntrack_expect_list, expected); - expected->expectant->expecting--; - nf_conntrack_get(&master_ct(conntrack)->infos[0]); -diff -urN linux.old/net/ipv4/netfilter/ip_conntrack_standalone.c linux.dev/net/ipv4/netfilter/ip_conntrack_standalone.c ---- linux.old/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-08-20 20:02:06.583833000 +0200 -+++ linux.dev/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-08-20 20:32:15.364657872 +0200 -@@ -107,6 +107,9 @@ - len += sprintf(buffer + len, "[ASSURED] "); - len += sprintf(buffer + len, "use=%u ", - atomic_read(&conntrack->ct_general.use)); -+ #if defined(CONFIG_IP_NF_CONNTRACK_MARK) -+ len += sprintf(buffer + len, "mark=%ld ", conntrack->mark); -+ #endif - - #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) - if(conntrack->layer7.app_proto) -diff -urN linux.old/net/ipv4/netfilter/ipt_CONNMARK.c linux.dev/net/ipv4/netfilter/ipt_CONNMARK.c ---- linux.old/net/ipv4/netfilter/ipt_CONNMARK.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/net/ipv4/netfilter/ipt_CONNMARK.c 2005-08-20 20:21:28.666970864 +0200 -@@ -0,0 +1,118 @@ -+/* This kernel module is used to modify the connection mark values, or -+ * to optionally restore the skb nfmark from the connection mark -+ * -+ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> -+ * by Henrik Nordstrom <hno@marasystems.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+#include <linux/module.h> -+#include <linux/skbuff.h> -+#include <linux/ip.h> -+#include <net/checksum.h> -+ -+MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>"); -+MODULE_DESCRIPTION("IP tables CONNMARK matching module"); -+MODULE_LICENSE("GPL"); -+ -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ipt_CONNMARK.h> -+#include <linux/netfilter_ipv4/ip_conntrack.h> -+ -+static unsigned int -+target(struct sk_buff **pskb, -+ unsigned int hooknum, -+ const struct net_device *in, -+ const struct net_device *out, -+ const void *targinfo, -+ void *userinfo) -+{ -+ const struct ipt_connmark_target_info *markinfo = targinfo; -+ unsigned long diff; -+ unsigned long nfmark; -+ unsigned long newmark; -+ -+ enum ip_conntrack_info ctinfo; -+ struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo); -+ if (ct) { -+ switch(markinfo->mode) { -+ case IPT_CONNMARK_SET: -+ newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; -+ if (newmark != ct->mark) -+ ct->mark = newmark; -+ break; -+ case IPT_CONNMARK_SAVE: -+ newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask); -+ if (ct->mark != newmark) -+ ct->mark = newmark; -+ break; -+ case IPT_CONNMARK_RESTORE: -+ nfmark = (*pskb)->nfmark; -+ diff = (ct->mark ^ nfmark & markinfo->mask); -+ if (diff != 0) { -+ (*pskb)->nfmark = nfmark ^ diff; -+ (*pskb)->nfcache |= NFC_ALTERED; -+ } -+ break; -+ } -+ } -+ -+ return IPT_CONTINUE; -+} -+ -+static int -+checkentry(const char *tablename, -+ const struct ipt_entry *e, -+ void *targinfo, -+ unsigned int targinfosize, -+ unsigned int hook_mask) -+{ -+ struct ipt_connmark_target_info *matchinfo = targinfo; -+ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) { -+ printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n", -+ targinfosize, -+ IPT_ALIGN(sizeof(struct ipt_connmark_target_info))); -+ return 0; -+ } -+ -+ if (matchinfo->mode == IPT_CONNMARK_RESTORE) { -+ if (strcmp(tablename, "mangle") != 0) { -+ printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename); -+ return 0; -+ } -+ } -+ -+ return 1; -+} -+ -+static struct ipt_target ipt_connmark_reg = { -+ .name = "CONNMARK", -+ .target = &target, -+ .checkentry = &checkentry, -+ .me = THIS_MODULE -+}; -+ -+static int __init init(void) -+{ -+ return ipt_register_target(&ipt_connmark_reg); -+} -+ -+static void __exit fini(void) -+{ -+ ipt_unregister_target(&ipt_connmark_reg); -+} -+ -+module_init(init); -+module_exit(fini); -diff -urN linux.old/net/ipv4/netfilter/ipt_connmark.c linux.dev/net/ipv4/netfilter/ipt_connmark.c ---- linux.old/net/ipv4/netfilter/ipt_connmark.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux.dev/net/ipv4/netfilter/ipt_connmark.c 2005-08-20 20:21:28.666970864 +0200 -@@ -0,0 +1,83 @@ -+/* This kernel module matches connection mark values set by the -+ * CONNMARK target -+ * -+ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> -+ * by Henrik Nordstrom <hno@marasystems.com> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/module.h> -+#include <linux/skbuff.h> -+ -+MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>"); -+MODULE_DESCRIPTION("IP tables connmark match module"); -+MODULE_LICENSE("GPL"); -+ -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ipt_connmark.h> -+#include <linux/netfilter_ipv4/ip_conntrack.h> -+ -+static int -+match(const struct sk_buff *skb, -+ const struct net_device *in, -+ const struct net_device *out, -+ const void *matchinfo, -+ int offset, -+ const void *hdr, -+ u_int16_t datalen, -+ int *hotdrop) -+{ -+ const struct ipt_connmark_info *info = matchinfo; -+ enum ip_conntrack_info ctinfo; -+ struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); -+ if (!ct) -+ return 0; -+ -+ return ((ct->mark & info->mask) == info->mark) ^ info->invert; -+} -+ -+static int -+checkentry(const char *tablename, -+ const struct ipt_ip *ip, -+ void *matchinfo, -+ unsigned int matchsize, -+ unsigned int hook_mask) -+{ -+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info))) -+ return 0; -+ -+ return 1; -+} -+ -+static struct ipt_match connmark_match = { -+ .name = "connmark", -+ .match = &match, -+ .checkentry = &checkentry, -+ .me = THIS_MODULE -+}; -+ -+static int __init init(void) -+{ -+ return ipt_register_match(&connmark_match); -+} -+ -+static void __exit fini(void) -+{ -+ ipt_unregister_match(&connmark_match); -+} -+ -+module_init(init); -+module_exit(fini); diff --git a/target/linux/linux-2.4/patches/generic/600-netfilter_ipset.patch b/target/linux/linux-2.4/patches/generic/600-netfilter_ipset.patch deleted file mode 100644 index 8cf5c694d..000000000 --- a/target/linux/linux-2.4/patches/generic/600-netfilter_ipset.patch +++ /dev/null @@ -1,5725 +0,0 @@ -diff -Naur linux-old/Documentation/Configure.help linux-new/Documentation/Configure.help ---- linux-old/Documentation/Configure.help 2005-07-23 23:34:46.000000000 +0200 -+++ linux-new/Documentation/Configure.help 2005-08-10 22:13:01.000000000 +0200 -@@ -3209,6 +3209,75 @@ - If you want to compile it as a module, say M here and read - <file:Documentation/modules.txt>. If unsure, say `N'. - -+IP set support -+CONFIG_IP_NF_SET -+ This option adds IP set support to the kernel. -+ -+ In order to define and use sets, you need userlevel utilities: an -+ iptables binary which knows about IP sets and the program ipset(8), -+ by which you can define and setup the sets themselves. -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/modules.txt>. If unsure, say `N'. -+ -+set match support -+CONFIG_IP_NF_MATCH_SET -+ This option adds IP set match support. -+ You need the ipset utility to create and set up the sets. -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/modules.txt>. If unsure, say `N'. -+ -+SET target support -+CONFIG_IP_NF_TARGET_SET -+ This option adds IP set target support. -+ You need the ipset utility to create and set up the sets. -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/modules.txt>. If unsure, say `N'. -+ -+ipmap set type support -+CONFIG_IP_NF_SET_IPMAP -+ This option adds the ipmap set type support. -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/modules.txt>. If unsure, say `N'. -+ -+macipmap set type support -+CONFIG_IP_NF_SET_MACIPMAP -+ This option adds the macipmap set type support. -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/modules.txt>. If unsure, say `N'. -+ -+portmap set type support -+CONFIG_IP_NF_SET_PORTMAP -+ This option adds the portmap set type support. -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/modules.txt>. If unsure, say `N'. -+ -+iphash set type support -+CONFIG_IP_NF_SET_IPHASH -+ This option adds the iphash set type support. -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/modules.txt>. If unsure, say `N'. -+ -+nethash set type support -+CONFIG_IP_NF_SET_NETHASH -+ This option adds the nethash set type support. -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/modules.txt>. If unsure, say `N'. -+ -+iptree set type support -+CONFIG_IP_NF_SET_IPTREE -+ This option adds the iptree set type support. -+ -+ If you want to compile it as a module, say M here and read -+ <file:Documentation/modules.txt>. If unsure, say `N'. -+ - TTL target support - CONFIG_IP_NF_TARGET_TTL - This option adds a `TTL' target, which enables the user to set -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set.h linux-new/include/linux/netfilter_ipv4/ip_set.h ---- linux-old/include/linux/netfilter_ipv4/ip_set.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,489 @@ -+#ifndef _IP_SET_H -+#define _IP_SET_H -+ -+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> -+ * Patrick Schaaf <bof@bof.de> -+ * Martin Josefsson <gandalf@wlug.westbo.se> -+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* -+ * A sockopt of such quality has hardly ever been seen before on the open -+ * market! This little beauty, hardly ever used: above 64, so it's -+ * traditionally used for firewalling, not touched (even once!) by the -+ * 2.0, 2.2 and 2.4 kernels! -+ * -+ * Comes with its own certificate of authenticity, valid anywhere in the -+ * Free world! -+ * -+ * Rusty, 19.4.2000 -+ */ -+#define SO_IP_SET 83 -+ -+/* -+ * Heavily modify by Joakim Axelsson 08.03.2002 -+ * - Made it more modulebased -+ * -+ * Additional heavy modifications by Jozsef Kadlecsik 22.02.2004 -+ * - bindings added -+ * - in order to "deal with" backward compatibility, renamed to ipset -+ */ -+ -+/* -+ * Used so that the kernel module and ipset-binary can match their versions -+ */ -+#define IP_SET_PROTOCOL_VERSION 2 -+ -+#define IP_SET_MAXNAMELEN 32 /* set names and set typenames */ -+ -+/* Lets work with our own typedef for representing an IP address. -+ * We hope to make the code more portable, possibly to IPv6... -+ * -+ * The representation works in HOST byte order, because most set types -+ * will perform arithmetic operations and compare operations. -+ * -+ * For now the type is an uint32_t. -+ * -+ * Make sure to ONLY use the functions when translating and parsing -+ * in order to keep the host byte order and make it more portable: -+ * parse_ip() -+ * parse_mask() -+ * parse_ipandmask() -+ * ip_tostring() -+ * (Joakim: where are they???) -+ */ -+ -+typedef uint32_t ip_set_ip_t; -+ -+/* Sets are identified by an id in kernel space. Tweak with ip_set_id_t -+ * and IP_SET_INVALID_ID if you want to increase the max number of sets. -+ */ -+typedef uint16_t ip_set_id_t; -+ -+#define IP_SET_INVALID_ID 65535 -+ -+/* How deep we follow bindings */ -+#define IP_SET_MAX_BINDINGS 6 -+ -+/* -+ * Option flags for kernel operations (ipt_set_info) -+ */ -+#define IPSET_SRC 0x01 /* Source match/add */ -+#define IPSET_DST 0x02 /* Destination match/add */ -+#define IPSET_MATCH_INV 0x04 /* Inverse matching */ -+ -+/* -+ * Set types (flavours) -+ */ -+#define IPSET_TYPE_IP 0 /* IP address type of set */ -+#define IPSET_TYPE_PORT 1 /* Port type of set */ -+ -+/* Reserved keywords */ -+#define IPSET_TOKEN_DEFAULT ":default:" -+#define IPSET_TOKEN_ALL ":all:" -+ -+/* SO_IP_SET operation constants, and their request struct types. -+ * -+ * Operation ids: -+ * 0-99: commands with version checking -+ * 100-199: add/del/test/bind/unbind -+ * 200-299: list, save, restore -+ */ -+ -+/* Single shot operations: -+ * version, create, destroy, flush, rename and swap -+ * -+ * Sets are identified by name. -+ */ -+ -+#define IP_SET_REQ_STD \ -+ unsigned op; \ -+ unsigned version; \ -+ char name[IP_SET_MAXNAMELEN] -+ -+#define IP_SET_OP_CREATE 0x00000001 /* Create a new (empty) set */ -+struct ip_set_req_create { -+ IP_SET_REQ_STD; -+ char typename[IP_SET_MAXNAMELEN]; -+}; -+ -+#define IP_SET_OP_DESTROY 0x00000002 /* Remove a (empty) set */ -+struct ip_set_req_std { -+ IP_SET_REQ_STD; -+}; -+ -+#define IP_SET_OP_FLUSH 0x00000003 /* Remove all IPs in a set */ -+/* Uses ip_set_req_std */ -+ -+#define IP_SET_OP_RENAME 0x00000004 /* Rename a set */ -+/* Uses ip_set_req_create */ -+ -+#define IP_SET_OP_SWAP 0x00000005 /* Swap two sets */ -+/* Uses ip_set_req_create */ -+ -+union ip_set_name_index { -+ char name[IP_SET_MAXNAMELEN]; -+ ip_set_id_t index; -+}; -+ -+#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */ -+struct ip_set_req_get_set { -+ unsigned op; -+ unsigned version; -+ union ip_set_name_index set; -+}; -+ -+#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */ -+/* Uses ip_set_req_get_set */ -+ -+#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ -+struct ip_set_req_version { -+ unsigned op; -+ unsigned version; -+}; -+ -+/* Double shots operations: -+ * add, del, test, bind and unbind. -+ * -+ * First we query the kernel to get the index and type of the target set, -+ * then issue the command. Validity of IP is checked in kernel in order -+ * to minimalize sockopt operations. -+ */ -+ -+/* Get minimal set data for add/del/test/bind/unbind IP */ -+#define IP_SET_OP_ADT_GET 0x00000010 /* Get set and type */ -+struct ip_set_req_adt_get { -+ unsigned op; -+ unsigned version; -+ union ip_set_name_index set; -+ char typename[IP_SET_MAXNAMELEN]; -+}; -+ -+#define IP_SET_REQ_BYINDEX \ -+ unsigned op; \ -+ ip_set_id_t index; -+ -+struct ip_set_req_adt { -+ IP_SET_REQ_BYINDEX; -+}; -+ -+#define IP_SET_OP_ADD_IP 0x00000101 /* Add an IP to a set */ -+/* Uses ip_set_req_adt, with type specific addage */ -+ -+#define IP_SET_OP_DEL_IP 0x00000102 /* Remove an IP from a set */ -+/* Uses ip_set_req_adt, with type specific addage */ -+ -+#define IP_SET_OP_TEST_IP 0x00000103 /* Test an IP in a set */ -+/* Uses ip_set_req_adt, with type specific addage */ -+ -+#define IP_SET_OP_BIND_SET 0x00000104 /* Bind an IP to a set */ -+/* Uses ip_set_req_bind, with type specific addage */ -+struct ip_set_req_bind { -+ IP_SET_REQ_BYINDEX; -+ char binding[IP_SET_MAXNAMELEN]; -+}; -+ -+#define IP_SET_OP_UNBIND_SET 0x00000105 /* Unbind an IP from a set */ -+/* Uses ip_set_req_bind, with type speficic addage -+ * index = 0 means unbinding for all sets */ -+ -+#define IP_SET_OP_TEST_BIND_SET 0x00000106 /* Test binding an IP to a set */ -+/* Uses ip_set_req_bind, with type specific addage */ -+ -+/* Multiple shots operations: list, save, restore. -+ * -+ * - check kernel version and query the max number of sets -+ * - get the basic information on all sets -+ * and size required for the next step -+ * - get actual set data: header, data, bindings -+ */ -+ -+/* Get max_sets and the index of a queried set -+ */ -+#define IP_SET_OP_MAX_SETS 0x00000020 -+struct ip_set_req_max_sets { -+ unsigned op; -+ unsigned version; -+ ip_set_id_t max_sets; /* max_sets */ -+ ip_set_id_t sets; /* real number of sets */ -+ union ip_set_name_index set; /* index of set if name used */ -+}; -+ -+/* Get the id and name of the sets plus size for next step */ -+#define IP_SET_OP_LIST_SIZE 0x00000201 -+#define IP_SET_OP_SAVE_SIZE 0x00000202 -+struct ip_set_req_setnames { -+ unsigned op; -+ ip_set_id_t index; /* set to list/save */ -+ size_t size; /* size to get setdata/bindings */ -+ /* followed by sets number of struct ip_set_name_list */ -+}; -+ -+struct ip_set_name_list { -+ char name[IP_SET_MAXNAMELEN]; -+ char typename[IP_SET_MAXNAMELEN]; -+ ip_set_id_t index; -+ ip_set_id_t id; -+}; -+ -+/* The actual list operation */ -+#define IP_SET_OP_LIST 0x00000203 -+struct ip_set_req_list { -+ IP_SET_REQ_BYINDEX; -+ /* sets number of struct ip_set_list in reply */ -+}; -+ -+struct ip_set_list { -+ ip_set_id_t index; -+ ip_set_id_t binding; -+ u_int32_t ref; -+ size_t header_size; /* Set header data of header_size */ -+ size_t members_size; /* Set members data of members_size */ -+ size_t bindings_size; /* Set bindings data of bindings_size */ -+}; -+ -+struct ip_set_hash_list { -+ ip_set_ip_t ip; -+ ip_set_id_t binding; -+}; -+ -+/* The save operation */ -+#define IP_SET_OP_SAVE 0x00000204 -+/* Uses ip_set_req_list, in the reply replaced by -+ * sets number of struct ip_set_save plus a marker -+ * ip_set_save followed by ip_set_hash_save structures. -+ */ -+struct ip_set_save { -+ ip_set_id_t index; -+ ip_set_id_t binding; -+ size_t header_size; /* Set header data of header_size */ -+ size_t members_size; /* Set members data of members_size */ -+}; -+ -+/* At restoring, ip == 0 means default binding for the given set: */ -+struct ip_set_hash_save { -+ ip_set_ip_t ip; -+ ip_set_id_t id; -+ ip_set_id_t binding; -+}; -+ -+/* The restore operation */ -+#define IP_SET_OP_RESTORE 0x00000205 -+/* Uses ip_set_req_setnames followed by ip_set_restore structures -+ * plus a marker ip_set_restore, followed by ip_set_hash_save -+ * structures. -+ */ -+struct ip_set_restore { -+ char name[IP_SET_MAXNAMELEN]; -+ char typename[IP_SET_MAXNAMELEN]; -+ ip_set_id_t index; -+ size_t header_size; /* Create data of header_size */ -+ size_t members_size; /* Set members data of members_size */ -+}; -+ -+static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b) -+{ -+ return 4 * ((((b - a + 8) / 8) + 3) / 4); -+} -+ -+#ifdef __KERNEL__ -+ -+#define ip_set_printk(format, args...) \ -+ do { \ -+ printk("%s: %s: ", __FILE__, __FUNCTION__); \ -+ printk(format "\n" , ## args); \ -+ } while (0) -+ -+#if defined(IP_SET_DEBUG) -+#define DP(format, args...) \ -+ do { \ -+ printk("%s: %s (DBG): ", __FILE__, __FUNCTION__);\ -+ printk(format "\n" , ## args); \ -+ } while (0) -+#define IP_SET_ASSERT(x) \ -+ do { \ -+ if (!(x)) \ -+ printk("IP_SET_ASSERT: %s:%i(%s)\n", \ -+ __FILE__, __LINE__, __FUNCTION__); \ -+ } while (0) -+#else -+#define DP(format, args...) -+#define IP_SET_ASSERT(x) -+#endif -+ -+struct ip_set; -+ -+/* -+ * The ip_set_type definition - one per set type, e.g. "ipmap". -+ * -+ * Each individual set has a pointer, set->type, going to one -+ * of these structures. Function pointers inside the structure implement -+ * the real behaviour of the sets. -+ * -+ * If not mentioned differently, the implementation behind the function -+ * pointers of a set_type, is expected to return 0 if ok, and a negative -+ * errno (e.g. -EINVAL) on error. -+ */ -+struct ip_set_type { -+ struct list_head list; /* next in list of set types */ -+ -+ /* test for IP in set (kernel: iptables -m set src|dst) -+ * return 0 if not in set, 1 if in set. -+ */ -+ int (*testip_kernel) (struct ip_set *set, -+ const struct sk_buff * skb, -+ u_int32_t flags, -+ ip_set_ip_t *ip); -+ -+ /* test for IP in set (userspace: ipset -T set IP) -+ * return 0 if not in set, 1 if in set. -+ */ -+ int (*testip) (struct ip_set *set, -+ const void *data, size_t size, -+ ip_set_ip_t *ip); -+ -+ /* -+ * Size of the data structure passed by when -+ * adding/deletin/testing an entry. -+ */ -+ size_t reqsize; -+ -+ /* Add IP into set (userspace: ipset -A set IP) -+ * Return -EEXIST if the address is already in the set, -+ * and -ERANGE if the address lies outside the set bounds. -+ * If the address was not already in the set, 0 is returned. -+ */ -+ int (*addip) (struct ip_set *set, -+ const void *data, size_t size, -+ ip_set_ip_t *ip); -+ -+ /* Add IP into set (kernel: iptables ... -j SET set src|dst) -+ * Return -EEXIST if the address is already in the set, -+ * and -ERANGE if the address lies outside the set bounds. -+ * If the address was not already in the set, 0 is returned. -+ */ -+ int (*addip_kernel) (struct ip_set *set, -+ const struct sk_buff * skb, -+ u_int32_t flags, -+ ip_set_ip_t *ip); -+ -+ /* remove IP from set (userspace: ipset -D set --entry x) -+ * Return -EEXIST if the address is NOT in the set, -+ * and -ERANGE if the address lies outside the set bounds. -+ * If the address really was in the set, 0 is returned. -+ */ -+ int (*delip) (struct ip_set *set, -+ const void *data, size_t size, -+ ip_set_ip_t *ip); -+ -+ /* remove IP from set (kernel: iptables ... -j SET --entry x) -+ * Return -EEXIST if the address is NOT in the set, -+ * and -ERANGE if the address lies outside the set bounds. -+ * If the address really was in the set, 0 is returned. -+ */ -+ int (*delip_kernel) (struct ip_set *set, -+ const struct sk_buff * skb, -+ u_int32_t flags, -+ ip_set_ip_t *ip); -+ -+ /* new set creation - allocated type specific items -+ */ -+ int (*create) (struct ip_set *set, -+ const void *data, size_t size); -+ -+ /* retry the operation after successfully tweaking the set -+ */ -+ int (*retry) (struct ip_set *set); -+ -+ /* set destruction - free type specific items -+ * There is no return value. -+ * Can be called only when child sets are destroyed. -+ */ -+ void (*destroy) (struct ip_set *set); -+ -+ /* set flushing - reset all bits in the set, or something similar. -+ * There is no return value. -+ */ -+ void (*flush) (struct ip_set *set); -+ -+ /* Listing: size needed for header -+ */ -+ size_t header_size; -+ -+ /* Listing: Get the header -+ * -+ * Fill in the information in "data". -+ * This function is always run after list_header_size() under a -+ * writelock on the set. Therefor is the length of "data" always -+ * correct. -+ */ -+ void (*list_header) (const struct ip_set *set, -+ void *data); -+ -+ /* Listing: Get the size for the set members -+ */ -+ int (*list_members_size) (const struct ip_set *set); -+ -+ /* Listing: Get the set members -+ * -+ * Fill in the information in "data". -+ * This function is always run after list_member_size() under a -+ * writelock on the set. Therefor is the length of "data" always -+ * correct. -+ */ -+ void (*list_members) (const struct ip_set *set, -+ void *data); -+ -+ char typename[IP_SET_MAXNAMELEN]; -+ char typecode; -+ int protocol_version; -+ -+ /* Set this to THIS_MODULE if you are a module, otherwise NULL */ -+ struct module *me; -+}; -+ -+extern int ip_set_register_set_type(struct ip_set_type *set_type); -+extern void ip_set_unregister_set_type(struct ip_set_type *set_type); -+ -+/* A generic ipset */ -+struct ip_set { -+ char name[IP_SET_MAXNAMELEN]; /* the name of the set */ -+ rwlock_t lock; /* lock for concurrency control */ -+ ip_set_id_t id; /* set id for swapping */ -+ ip_set_id_t binding; /* default binding for the set */ -+ atomic_t ref; /* in kernel and in hash references */ -+ struct ip_set_type *type; /* the set types */ -+ void *data; /* pooltype specific data */ -+}; -+ -+/* Structure to bind set elements to sets */ -+struct ip_set_hash { -+ struct list_head list; /* list of clashing entries in hash */ -+ ip_set_ip_t ip; /* ip from set */ -+ ip_set_id_t id; /* set id */ -+ ip_set_id_t binding; /* set we bind the element to */ -+}; -+ -+/* register and unregister set references */ -+extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]); -+extern ip_set_id_t ip_set_get_byindex(ip_set_id_t id); -+extern void ip_set_put(ip_set_id_t id); -+ -+/* API for iptables set match, and SET target */ -+extern void ip_set_addip_kernel(ip_set_id_t id, -+ const struct sk_buff *skb, -+ const u_int32_t *flags); -+extern void ip_set_delip_kernel(ip_set_id_t id, -+ const struct sk_buff *skb, -+ const u_int32_t *flags); -+extern int ip_set_testip_kernel(ip_set_id_t id, -+ const struct sk_buff *skb, -+ const u_int32_t *flags); -+ -+#endif /* __KERNEL__ */ -+ -+#endif /*_IP_SET_H*/ -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_iphash.h linux-new/include/linux/netfilter_ipv4/ip_set_iphash.h ---- linux-old/include/linux/netfilter_ipv4/ip_set_iphash.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set_iphash.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,30 @@ -+#ifndef __IP_SET_IPHASH_H -+#define __IP_SET_IPHASH_H -+ -+#include <linux/netfilter_ipv4/ip_set.h> -+ -+#define SETTYPE_NAME "iphash" -+#define MAX_RANGE 0x0000FFFF -+ -+struct ip_set_iphash { -+ ip_set_ip_t *members; /* the iphash proper */ -+ uint32_t initval; /* initval for jhash_1word */ -+ uint32_t prime; /* prime for double hashing */ -+ uint32_t hashsize; /* hash size */ -+ uint16_t probes; /* max number of probes */ -+ uint16_t resize; /* resize factor in percent */ -+ ip_set_ip_t netmask; /* netmask */ -+}; -+ -+struct ip_set_req_iphash_create { -+ uint32_t hashsize; -+ uint16_t probes; -+ uint16_t resize; -+ ip_set_ip_t netmask; -+}; -+ -+struct ip_set_req_iphash { -+ ip_set_ip_t ip; -+}; -+ -+#endif /* __IP_SET_IPHASH_H */ -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_ipmap.h linux-new/include/linux/netfilter_ipv4/ip_set_ipmap.h ---- linux-old/include/linux/netfilter_ipv4/ip_set_ipmap.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set_ipmap.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,56 @@ -+#ifndef __IP_SET_IPMAP_H -+#define __IP_SET_IPMAP_H -+ -+#include <linux/netfilter_ipv4/ip_set.h> -+ -+#define SETTYPE_NAME "ipmap" -+#define MAX_RANGE 0x0000FFFF -+ -+struct ip_set_ipmap { -+ void *members; /* the ipmap proper */ -+ ip_set_ip_t first_ip; /* host byte order, included in range */ -+ ip_set_ip_t last_ip; /* host byte order, included in range */ -+ ip_set_ip_t netmask; /* subnet netmask */ -+ ip_set_ip_t sizeid; /* size of set in IPs */ -+ u_int16_t hosts; /* number of hosts in a subnet */ -+}; -+ -+struct ip_set_req_ipmap_create { -+ ip_set_ip_t from; -+ ip_set_ip_t to; -+ ip_set_ip_t netmask; -+}; -+ -+struct ip_set_req_ipmap { -+ ip_set_ip_t ip; -+}; -+ -+unsigned int -+mask_to_bits(ip_set_ip_t mask) -+{ -+ unsigned int bits = 32; -+ ip_set_ip_t maskaddr; -+ -+ if (mask == 0xFFFFFFFF) -+ return bits; -+ -+ maskaddr = 0xFFFFFFFE; -+ while (--bits >= 0 && maskaddr != mask) -+ maskaddr <<= 1; -+ -+ return bits; -+} -+ -+ip_set_ip_t -+range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits) -+{ -+ ip_set_ip_t mask = 0xFFFFFFFE; -+ -+ *bits = 32; -+ while (--(*bits) >= 0 && mask && (to & mask) != from) -+ mask <<= 1; -+ -+ return mask; -+} -+ -+#endif /* __IP_SET_IPMAP_H */ -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_iptree.h linux-new/include/linux/netfilter_ipv4/ip_set_iptree.h ---- linux-old/include/linux/netfilter_ipv4/ip_set_iptree.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set_iptree.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,39 @@ -+#ifndef __IP_SET_IPTREE_H -+#define __IP_SET_IPTREE_H -+ -+#include <linux/netfilter_ipv4/ip_set.h> -+ -+#define SETTYPE_NAME "iptree" -+#define MAX_RANGE 0x0000FFFF -+ -+struct ip_set_iptreed { -+ unsigned long expires[255]; /* x.x.x.ADDR */ -+}; -+ -+struct ip_set_iptreec { -+ struct ip_set_iptreed *tree[255]; /* x.x.ADDR.* */ -+}; -+ -+struct ip_set_iptreeb { -+ struct ip_set_iptreec *tree[255]; /* x.ADDR.*.* */ -+}; -+ -+struct ip_set_iptree { -+ unsigned int timeout; -+ unsigned int gc_interval; -+#ifdef __KERNEL__ -+ struct timer_list gc; -+ struct ip_set_iptreeb *tree[255]; /* ADDR.*.*.* */ -+#endif -+}; -+ -+struct ip_set_req_iptree_create { -+ unsigned int timeout; -+}; -+ -+struct ip_set_req_iptree { -+ ip_set_ip_t ip; -+ unsigned int timeout; -+}; -+ -+#endif /* __IP_SET_IPTREE_H */ -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_jhash.h linux-new/include/linux/netfilter_ipv4/ip_set_jhash.h ---- linux-old/include/linux/netfilter_ipv4/ip_set_jhash.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set_jhash.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,148 @@ -+#ifndef _LINUX_IPSET_JHASH_H -+#define _LINUX_IPSET_JHASH_H -+ -+/* This is a copy of linux/jhash.h but the types u32/u8 are changed -+ * to __u32/__u8 so that the header file can be included into -+ * userspace code as well. Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) -+ */ -+ -+/* jhash.h: Jenkins hash support. -+ * -+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) -+ * -+ * http://burtleburtle.net/bob/hash/ -+ * -+ * These are the credits from Bob's sources: -+ * -+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain. -+ * hash(), hash2(), hash3, and mix() are externally useful functions. -+ * Routines to test the hash are included if SELF_TEST is defined. -+ * You can use this free for any purpose. It has no warranty. -+ * -+ * Copyright (C) 2003 David S. Miller (davem@redhat.com) -+ * -+ * I've modified Bob's hash to be useful in the Linux kernel, and -+ * any bugs present are surely my fault. -DaveM -+ */ -+ -+/* NOTE: Arguments are modified. */ -+#define __jhash_mix(a, b, c) \ -+{ \ -+ a -= b; a -= c; a ^= (c>>13); \ -+ b -= c; b -= a; b ^= (a<<8); \ -+ c -= a; c -= b; c ^= (b>>13); \ -+ a -= b; a -= c; a ^= (c>>12); \ -+ b -= c; b -= a; b ^= (a<<16); \ -+ c -= a; c -= b; c ^= (b>>5); \ -+ a -= b; a -= c; a ^= (c>>3); \ -+ b -= c; b -= a; b ^= (a<<10); \ -+ c -= a; c -= b; c ^= (b>>15); \ -+} -+ -+/* The golden ration: an arbitrary value */ -+#define JHASH_GOLDEN_RATIO 0x9e3779b9 -+ -+/* The most generic version, hashes an arbitrary sequence -+ * of bytes. No alignment or length assumptions are made about -+ * the input key. -+ */ -+static inline __u32 jhash(void *key, __u32 length, __u32 initval) -+{ -+ __u32 a, b, c, len; -+ __u8 *k = key; -+ -+ len = length; -+ a = b = JHASH_GOLDEN_RATIO; -+ c = initval; -+ -+ while (len >= 12) { -+ a += (k[0] +((__u32)k[1]<<8) +((__u32)k[2]<<16) +((__u32)k[3]<<24)); -+ b += (k[4] +((__u32)k[5]<<8) +((__u32)k[6]<<16) +((__u32)k[7]<<24)); -+ c += (k[8] +((__u32)k[9]<<8) +((__u32)k[10]<<16)+((__u32)k[11]<<24)); -+ -+ __jhash_mix(a,b,c); -+ -+ k += 12; -+ len -= 12; -+ } -+ -+ c += length; -+ switch (len) { -+ case 11: c += ((__u32)k[10]<<24); -+ case 10: c += ((__u32)k[9]<<16); -+ case 9 : c += ((__u32)k[8]<<8); -+ case 8 : b += ((__u32)k[7]<<24); -+ case 7 : b += ((__u32)k[6]<<16); -+ case 6 : b += ((__u32)k[5]<<8); -+ case 5 : b += k[4]; -+ case 4 : a += ((__u32)k[3]<<24); -+ case 3 : a += ((__u32)k[2]<<16); -+ case 2 : a += ((__u32)k[1]<<8); -+ case 1 : a += k[0]; -+ }; -+ -+ __jhash_mix(a,b,c); -+ -+ return c; -+} -+ -+/* A special optimized version that handles 1 or more of __u32s. -+ * The length parameter here is the number of __u32s in the key. -+ */ -+static inline __u32 jhash2(__u32 *k, __u32 length, __u32 initval) -+{ -+ __u32 a, b, c, len; -+ -+ a = b = JHASH_GOLDEN_RATIO; -+ c = initval; -+ len = length; -+ -+ while (len >= 3) { -+ a += k[0]; -+ b += k[1]; -+ c += k[2]; -+ __jhash_mix(a, b, c); -+ k += 3; len -= 3; -+ } -+ -+ c += length * 4; -+ -+ switch (len) { -+ case 2 : b += k[1]; -+ case 1 : a += k[0]; -+ }; -+ -+ __jhash_mix(a,b,c); -+ -+ return c; -+} -+ -+ -+/* A special ultra-optimized versions that knows they are hashing exactly -+ * 3, 2 or 1 word(s). -+ * -+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally -+ * done at the end is not done here. -+ */ -+static inline __u32 jhash_3words(__u32 a, __u32 b, __u32 c, __u32 initval) -+{ -+ a += JHASH_GOLDEN_RATIO; -+ b += JHASH_GOLDEN_RATIO; -+ c += initval; -+ -+ __jhash_mix(a, b, c); -+ -+ return c; -+} -+ -+static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval) -+{ -+ return jhash_3words(a, b, 0, initval); -+} -+ -+static inline __u32 jhash_1word(__u32 a, __u32 initval) -+{ -+ return jhash_3words(a, 0, 0, initval); -+} -+ -+#endif /* _LINUX_IPSET_JHASH_H */ -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_macipmap.h linux-new/include/linux/netfilter_ipv4/ip_set_macipmap.h ---- linux-old/include/linux/netfilter_ipv4/ip_set_macipmap.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set_macipmap.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,38 @@ -+#ifndef __IP_SET_MACIPMAP_H -+#define __IP_SET_MACIPMAP_H -+ -+#include <linux/netfilter_ipv4/ip_set.h> -+ -+#define SETTYPE_NAME "macipmap" -+#define MAX_RANGE 0x0000FFFF -+ -+/* general flags */ -+#define IPSET_MACIP_MATCHUNSET 1 -+ -+/* per ip flags */ -+#define IPSET_MACIP_ISSET 1 -+ -+struct ip_set_macipmap { -+ void *members; /* the macipmap proper */ -+ ip_set_ip_t first_ip; /* host byte order, included in range */ -+ ip_set_ip_t last_ip; /* host byte order, included in range */ -+ u_int32_t flags; -+}; -+ -+struct ip_set_req_macipmap_create { -+ ip_set_ip_t from; -+ ip_set_ip_t to; -+ u_int32_t flags; -+}; -+ -+struct ip_set_req_macipmap { -+ ip_set_ip_t ip; -+ unsigned char ethernet[ETH_ALEN]; -+}; -+ -+struct ip_set_macip { -+ unsigned short flags; -+ unsigned char ethernet[ETH_ALEN]; -+}; -+ -+#endif /* __IP_SET_MACIPMAP_H */ -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_malloc.h linux-new/include/linux/netfilter_ipv4/ip_set_malloc.h ---- linux-old/include/linux/netfilter_ipv4/ip_set_malloc.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set_malloc.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,27 @@ -+#ifndef _IP_SET_MALLOC_H -+#define _IP_SET_MALLOC_H -+ -+#ifdef __KERNEL__ -+ -+/* Memory allocation and deallocation */ -+static size_t max_malloc_size = 131072; /* Guaranteed: slab.c */ -+ -+static inline void * ip_set_malloc(size_t bytes) -+{ -+ if (bytes > max_malloc_size) -+ return vmalloc(bytes); -+ else -+ return kmalloc(bytes, GFP_KERNEL); -+} -+ -+static inline void ip_set_free(void * data, size_t bytes) -+{ -+ if (bytes > max_malloc_size) -+ vfree(data); -+ else -+ kfree(data); -+} -+ -+#endif /* __KERNEL__ */ -+ -+#endif /*_IP_SET_MALLOC_H*/ -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_nethash.h linux-new/include/linux/netfilter_ipv4/ip_set_nethash.h ---- linux-old/include/linux/netfilter_ipv4/ip_set_nethash.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set_nethash.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,55 @@ -+#ifndef __IP_SET_NETHASH_H -+#define __IP_SET_NETHASH_H -+ -+#include <linux/netfilter_ipv4/ip_set.h> -+ -+#define SETTYPE_NAME "nethash" -+#define MAX_RANGE 0x0000FFFF -+ -+struct ip_set_nethash { -+ ip_set_ip_t *members; /* the nethash proper */ -+ uint32_t initval; /* initval for jhash_1word */ -+ uint32_t prime; /* prime for double hashing */ -+ uint32_t hashsize; /* hash size */ -+ uint16_t probes; /* max number of probes */ -+ uint16_t resize; /* resize factor in percent */ -+ unsigned char cidr[30]; /* CIDR sizes */ -+}; -+ -+struct ip_set_req_nethash_create { -+ uint32_t hashsize; -+ uint16_t probes; -+ uint16_t resize; -+}; -+ -+struct ip_set_req_nethash { -+ ip_set_ip_t ip; -+ unsigned char cidr; -+}; -+ -+static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1}; -+ -+static inline ip_set_ip_t -+pack(ip_set_ip_t ip, unsigned char cidr) -+{ -+ ip_set_ip_t addr, *paddr = &addr; -+ unsigned char n, t, *a; -+ -+ addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr)))); -+#ifdef __KERNEL__ -+ DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr); -+#endif -+ n = cidr / 8; -+ t = cidr % 8; -+ a = &((unsigned char *)paddr)[n]; -+ *a = *a /(1 << (8 - t)) + shifts[t]; -+#ifdef __KERNEL__ -+ DP("n: %u, t: %u, a: %u", n, t, *a); -+ DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u", -+ HIPQUAD(ip), cidr, NIPQUAD(addr)); -+#endif -+ -+ return ntohl(addr); -+} -+ -+#endif /* __IP_SET_NETHASH_H */ -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_portmap.h linux-new/include/linux/netfilter_ipv4/ip_set_portmap.h ---- linux-old/include/linux/netfilter_ipv4/ip_set_portmap.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set_portmap.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,25 @@ -+#ifndef __IP_SET_PORTMAP_H -+#define __IP_SET_PORTMAP_H -+ -+#include <linux/netfilter_ipv4/ip_set.h> -+ -+#define SETTYPE_NAME "portmap" -+#define MAX_RANGE 0x0000FFFF -+#define INVALID_PORT (MAX_RANGE + 1) -+ -+struct ip_set_portmap { -+ void *members; /* the portmap proper */ -+ ip_set_ip_t first_port; /* host byte order, included in range */ -+ ip_set_ip_t last_port; /* host byte order, included in range */ -+}; -+ -+struct ip_set_req_portmap_create { -+ ip_set_ip_t from; -+ ip_set_ip_t to; -+}; -+ -+struct ip_set_req_portmap { -+ ip_set_ip_t port; -+}; -+ -+#endif /* __IP_SET_PORTMAP_H */ -diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_prime.h linux-new/include/linux/netfilter_ipv4/ip_set_prime.h ---- linux-old/include/linux/netfilter_ipv4/ip_set_prime.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ip_set_prime.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,34 @@ -+#ifndef __IP_SET_PRIME_H -+#define __IP_SET_PRIME_H -+ -+static inline unsigned make_prime_bound(unsigned nr) -+{ -+ unsigned long long nr64 = nr; -+ unsigned long long x = 1; -+ nr = 1; -+ while (x <= nr64) { x <<= 2; nr <<= 1; } -+ return nr; -+} -+ -+static inline int make_prime_check(unsigned nr) -+{ -+ unsigned x = 3; -+ unsigned b = make_prime_bound(nr); -+ while (x <= b) { -+ if (0 == (nr % x)) return 0; -+ x += 2; -+ } -+ return 1; -+} -+ -+static unsigned make_prime(unsigned nr) -+{ -+ if (0 == (nr & 1)) nr--; -+ while (nr > 1) { -+ if (make_prime_check(nr)) return nr; -+ nr -= 2; -+ } -+ return 2; -+} -+ -+#endif /* __IP_SET_PRIME_H */ -diff -Naur linux-old/include/linux/netfilter_ipv4/ipt_set.h linux-new/include/linux/netfilter_ipv4/ipt_set.h ---- linux-old/include/linux/netfilter_ipv4/ipt_set.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/include/linux/netfilter_ipv4/ipt_set.h 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,21 @@ -+#ifndef _IPT_SET_H -+#define _IPT_SET_H -+ -+#include <linux/netfilter_ipv4/ip_set.h> -+ -+struct ipt_set_info { -+ ip_set_id_t index; -+ u_int32_t flags[IP_SET_MAX_BINDINGS + 1]; -+}; -+ -+/* match info */ -+struct ipt_set_info_match { -+ struct ipt_set_info match_set; -+}; -+ -+struct ipt_set_info_target { -+ struct ipt_set_info add_set; -+ struct ipt_set_info del_set; -+}; -+ -+#endif /*_IPT_SET_H*/ -diff -Naur linux-old/net/ipv4/netfilter/Config.in linux-new/net/ipv4/netfilter/Config.in ---- linux-old/net/ipv4/netfilter/Config.in 2005-07-23 23:34:46.000000000 +0200 -+++ linux-new/net/ipv4/netfilter/Config.in 2005-08-10 22:13:01.000000000 +0200 -@@ -21,6 +21,20 @@ - if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then - # The simple matches. - dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES -+ -+ dep_tristate ' IP set support' CONFIG_IP_NF_SET $CONFIG_IP_NF_IPTABLES -+ if [ "$CONFIG_IP_NF_SET" != "n" ]; then -+ int ' Maximum number of sets' CONFIG_IP_NF_SET_MAX 256 -+ int ' Hash size for bindings of IP sets' CONFIG_IP_NF_SET_HASHSIZE 1024 -+ dep_tristate ' set match support' CONFIG_IP_NF_MATCH_SET $CONFIG_IP_NF_SET -+ dep_tristate ' SET target support' CONFIG_IP_NF_TARGET_SET $CONFIG_IP_NF_SET -+ dep_tristate ' ipmap set type support' CONFIG_IP_NF_SET_IPMAP $CONFIG_IP_NF_SET -+ dep_tristate ' portmap set type support' CONFIG_IP_NF_SET_PORTMAP $CONFIG_IP_NF_SET -+ dep_tristate ' macipmap set type support' CONFIG_IP_NF_SET_MACIPMAP $CONFIG_IP_NF_SET -+ dep_tristate ' iphash set type support' CONFIG_IP_NF_SET_IPHASH $CONFIG_IP_NF_SET -+ dep_tristate ' nethash set type support' CONFIG_IP_NF_SET_NETHASH $CONFIG_IP_NF_SET -+ dep_tristate ' iptree set type support' CONFIG_IP_NF_SET_IPTREE $CONFIG_IP_NF_SET -+ fi - dep_tristate ' MAC address match support' CONFIG_IP_NF_MATCH_MAC $CONFIG_IP_NF_IPTABLES - dep_tristate ' Packet type match support' CONFIG_IP_NF_MATCH_PKTTYPE $CONFIG_IP_NF_IPTABLES - dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES -diff -Naur linux-old/net/ipv4/netfilter/ip_set.c linux-new/net/ipv4/netfilter/ip_set.c ---- linux-old/net/ipv4/netfilter/ip_set.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/net/ipv4/netfilter/ip_set.c 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,2002 @@ -+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> -+ * Patrick Schaaf <bof@bof.de> -+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* Kernel module for IP set management */ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/kmod.h> -+#include <linux/ip.h> -+#include <linux/skbuff.h> -+#include <linux/random.h> -+#include <linux/jhash.h> -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/errno.h> -+#include <asm/uaccess.h> -+#include <asm/bitops.h> -+#include <asm/softirq.h> -+#include <asm/semaphore.h> -+#include <linux/spinlock.h> -+#include <linux/vmalloc.h> -+ -+#define ASSERT_READ_LOCK(x) /* dont use that */ -+#define ASSERT_WRITE_LOCK(x) -+#include <linux/netfilter_ipv4/listhelp.h> -+#include <linux/netfilter_ipv4/ip_set.h> -+ -+static struct list_head set_type_list; /* all registered sets */ -+static struct ip_set **ip_set_list; /* all individual sets */ -+static DECLARE_RWLOCK(ip_set_lock); /* protects the lists and the hash */ -+static DECLARE_MUTEX(ip_set_app_mutex); /* serializes user access */ -+static ip_set_id_t ip_set_max = CONFIG_IP_NF_SET_MAX; -+static ip_set_id_t ip_set_bindings_hash_size = CONFIG_IP_NF_SET_HASHSIZE; -+static struct list_head *ip_set_hash; /* hash of bindings */ -+static unsigned int ip_set_hash_random; /* random seed */ -+ -+/* Arrgh */ -+#ifdef MODULE -+#define __MOD_INC(foo) __MOD_INC_USE_COUNT(foo) -+#define __MOD_DEC(foo) __MOD_DEC_USE_COUNT(foo) -+#define __MOD_INC_SELF MOD_INC_USE_COUNT -+#define __MOD_DEC_SELF MOD_DEC_USE_COUNT -+#else -+#define __MOD_INC(foo) -+#define __MOD_DEC(foo) -+#define __MOD_INC_SELF -+#define __MOD_DEC_SELF -+#endif -+ -+/* -+ * Sets are identified either by the index in ip_set_list or by id. -+ * The id never changes and is used to find a key in the hash. -+ * The index may change by swapping and used at all other places -+ * (set/SET netfilter modules, binding value, etc.) -+ * -+ * Userspace requests are serialized by ip_set_mutex and sets can -+ * be deleted only from userspace. Therefore ip_set_list locking -+ * must obey the following rules: -+ * -+ * - kernel requests: read and write locking mandatory -+ * - user requests: read locking optional, write locking mandatory -+ */ -+ -+static inline void -+__ip_set_get(ip_set_id_t index) -+{ -+ atomic_inc(&ip_set_list[index]->ref); -+} -+ -+static inline void -+__ip_set_put(ip_set_id_t index) -+{ -+ atomic_dec(&ip_set_list[index]->ref); -+} -+ -+/* -+ * Binding routines -+ */ -+ -+static inline int -+ip_hash_cmp(const struct ip_set_hash *set_hash, -+ ip_set_id_t id, ip_set_ip_t ip) -+{ -+ return set_hash->id == id && set_hash->ip == ip; -+} -+ -+static ip_set_id_t -+ip_set_find_in_hash(ip_set_id_t id, ip_set_ip_t ip) -+{ -+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random) -+ % ip_set_bindings_hash_size; -+ struct ip_set_hash *set_hash; -+ -+ MUST_BE_READ_LOCKED(&ip_set_lock); -+ IP_SET_ASSERT(ip_set_list[id]); -+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip)); -+ -+ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp, -+ struct ip_set_hash *, id, ip); -+ -+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name, -+ HIPQUAD(ip), -+ set_hash != NULL ? ip_set_list[set_hash->binding]->name : ""); -+ -+ return (set_hash != NULL ? set_hash->binding : IP_SET_INVALID_ID); -+} -+ -+static inline void -+__set_hash_del(struct ip_set_hash *set_hash) -+{ -+ MUST_BE_WRITE_LOCKED(&ip_set_lock); -+ IP_SET_ASSERT(ip_set_list[set_hash->binding]); -+ -+ __ip_set_put(set_hash->binding); -+ list_del(&set_hash->list); -+ kfree(set_hash); -+} -+ -+static int -+ip_set_hash_del(ip_set_id_t id, ip_set_ip_t ip) -+{ -+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random) -+ % ip_set_bindings_hash_size; -+ struct ip_set_hash *set_hash; -+ -+ IP_SET_ASSERT(ip_set_list[id]); -+ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip)); -+ WRITE_LOCK(&ip_set_lock); -+ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp, -+ struct ip_set_hash *, id, ip); -+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name, -+ HIPQUAD(ip), -+ set_hash != NULL ? ip_set_list[set_hash->binding]->name : ""); -+ -+ if (set_hash != NULL) -+ __set_hash_del(set_hash); -+ WRITE_UNLOCK(&ip_set_lock); -+ return 0; -+} -+ -+static int -+ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding) -+{ -+ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random) -+ % ip_set_bindings_hash_size; -+ struct ip_set_hash *set_hash; -+ int ret = 0; -+ -+ IP_SET_ASSERT(ip_set_list[id]); -+ IP_SET_ASSERT(ip_set_list[binding]); -+ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name, -+ HIPQUAD(ip), ip_set_list[binding]->name); -+ WRITE_LOCK(&ip_set_lock); -+ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp, -+ struct ip_set_hash *, id, ip); -+ if (!set_hash) { -+ set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_KERNEL); -+ if (!set_hash) { -+ ret = -ENOMEM; -+ goto unlock; -+ } -+ INIT_LIST_HEAD(&set_hash->list); -+ set_hash->id = id; -+ set_hash->ip = ip; -+ list_add(&ip_set_hash[key], &set_hash->list); -+ } else { -+ IP_SET_ASSERT(ip_set_list[set_hash->binding]); -+ DP("overwrite binding: %s", -+ ip_set_list[set_hash->binding]->name); -+ __ip_set_put(set_hash->binding); -+ } -+ set_hash->binding = binding; -+ __ip_set_get(set_hash->binding); -+ unlock: -+ WRITE_UNLOCK(&ip_set_lock); -+ return ret; -+} -+ -+#define FOREACH_HASH_DO(fn, args...) \ -+({ \ -+ ip_set_id_t __key; \ -+ struct ip_set_hash *__set_hash; \ -+ \ -+ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \ -+ list_for_each_entry(__set_hash, &ip_set_hash[__key], list) \ -+ fn(__set_hash , ## args); \ -+ } \ -+}) -+ -+#define FOREACH_HASH_RW_DO(fn, args...) \ -+({ \ -+ ip_set_id_t __key; \ -+ struct ip_set_hash *__set_hash, *__n; \ -+ \ -+ MUST_BE_WRITE_LOCKED(&ip_set_lock); \ -+ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \ -+ list_for_each_entry_safe(__set_hash, __n, &ip_set_hash[__key], list)\ -+ fn(__set_hash , ## args); \ -+ } \ -+}) -+ -+/* Add, del and test set entries from kernel */ -+ -+#define follow_bindings(index, set, ip) \ -+((index = ip_set_find_in_hash((set)->id, ip)) != IP_SET_INVALID_ID \ -+ || (index = (set)->binding) != IP_SET_INVALID_ID) -+ -+int -+ip_set_testip_kernel(ip_set_id_t index, -+ const struct sk_buff *skb, -+ const u_int32_t *flags) -+{ -+ struct ip_set *set; -+ ip_set_ip_t ip; -+ int res, i = 0; -+ -+ IP_SET_ASSERT(flags[i]); -+ READ_LOCK(&ip_set_lock); -+ do { -+ set = ip_set_list[index]; -+ IP_SET_ASSERT(set); -+ DP("set %s, index %u", set->name, index); -+ read_lock_bh(&set->lock); -+ res = set->type->testip_kernel(set, skb, flags[i], &ip); -+ read_unlock_bh(&set->lock); -+ } while (res > 0 -+ && flags[++i] -+ && follow_bindings(index, set, ip)); -+ READ_UNLOCK(&ip_set_lock); -+ -+ return res; -+} -+ -+void -+ip_set_addip_kernel(ip_set_id_t index, -+ const struct sk_buff *skb, -+ const u_int32_t *flags) -+{ -+ struct ip_set *set; -+ ip_set_ip_t ip; -+ int res, i= 0; -+ -+ IP_SET_ASSERT(flags[i]); -+ retry: -+ READ_LOCK(&ip_set_lock); -+ do { -+ set = ip_set_list[index]; -+ IP_SET_ASSERT(set); -+ DP("set %s, index %u", set->name, index); -+ write_lock_bh(&set->lock); -+ res = set->type->addip_kernel(set, skb, flags[i], &ip); -+ write_unlock_bh(&set->lock); -+ } while ((res == 0 || res == -EEXIST) -+ && flags[++i] -+ && follow_bindings(index, set, ip)); -+ READ_UNLOCK(&ip_set_lock); -+ -+ if (res == -EAGAIN -+ && set->type->retry -+ && (res = set->type->retry(set)) == 0) -+ goto retry; -+} -+ -+void -+ip_set_delip_kernel(ip_set_id_t index, -+ const struct sk_buff *skb, -+ const u_int32_t *flags) -+{ -+ struct ip_set *set; -+ ip_set_ip_t ip; -+ int res, i = 0; -+ -+ IP_SET_ASSERT(flags[i]); -+ READ_LOCK(&ip_set_lock); -+ do { -+ set = ip_set_list[index]; -+ IP_SET_ASSERT(set); -+ DP("set %s, index %u", set->name, index); -+ write_lock_bh(&set->lock); -+ res = set->type->delip_kernel(set, skb, flags[i], &ip); -+ write_unlock_bh(&set->lock); -+ } while ((res == 0 || res == -EEXIST) -+ && flags[++i] -+ && follow_bindings(index, set, ip)); -+ READ_UNLOCK(&ip_set_lock); -+} -+ -+/* Register and deregister settype */ -+ -+static inline int -+set_type_equal(const struct ip_set_type *set_type, const char *str2) -+{ -+ return !strncmp(set_type->typename, str2, IP_SET_MAXNAMELEN - 1); -+} -+ -+static inline struct ip_set_type * -+find_set_type(const char *name) -+{ -+ return LIST_FIND(&set_type_list, -+ set_type_equal, -+ struct ip_set_type *, -+ name); -+} -+ -+int -+ip_set_register_set_type(struct ip_set_type *set_type) -+{ -+ int ret = 0; -+ -+ if (set_type->protocol_version != IP_SET_PROTOCOL_VERSION) { -+ ip_set_printk("'%s' uses wrong protocol version %u (want %u)", -+ set_type->typename, -+ set_type->protocol_version, -+ IP_SET_PROTOCOL_VERSION); -+ return -EINVAL; -+ } -+ -+ WRITE_LOCK(&ip_set_lock); -+ if (find_set_type(set_type->typename)) { -+ /* Duplicate! */ -+ ip_set_printk("'%s' already registered!", -+ set_type->typename); -+ ret = -EINVAL; -+ goto unlock; -+ } -+ __MOD_INC_SELF; -+ list_append(&set_type_list, set_type); -+ DP("'%s' registered.", set_type->typename); -+ unlock: -+ WRITE_UNLOCK(&ip_set_lock); -+ return ret; -+} -+ -+void -+ip_set_unregister_set_type(struct ip_set_type *set_type) -+{ -+ WRITE_LOCK(&ip_set_lock); -+ if (!find_set_type(set_type->typename)) { -+ ip_set_printk("'%s' not registered?", -+ set_type->typename); -+ goto unlock; -+ } -+ LIST_DELETE(&set_type_list, set_type); -+ __MOD_DEC_SELF; -+ DP("'%s' unregistered.", set_type->typename); -+ unlock: -+ WRITE_UNLOCK(&ip_set_lock); -+ -+} -+ -+/* -+ * Userspace routines -+ */ -+ -+/* -+ * Find set by name, reference it once. The reference makes sure the -+ * thing pointed to, does not go away under our feet. Drop the reference -+ * later, using ip_set_put(). -+ */ -+ip_set_id_t -+ip_set_get_byname(const char *name) -+{ -+ ip_set_id_t i, index = IP_SET_INVALID_ID; -+ -+ down(&ip_set_app_mutex); -+ for (i = 0; i < ip_set_max; i++) { -+ if (ip_set_list[i] != NULL -+ && strcmp(ip_set_list[i]->name, name) == 0) { -+ __ip_set_get(i); -+ index = i; -+ break; -+ } -+ } -+ up(&ip_set_app_mutex); -+ return index; -+} -+ -+/* -+ * Find set by index, reference it once. The reference makes sure the -+ * thing pointed to, does not go away under our feet. Drop the reference -+ * later, using ip_set_put(). -+ */ -+ip_set_id_t -+ip_set_get_byindex(ip_set_id_t index) -+{ -+ down(&ip_set_app_mutex); -+ -+ if (index >= ip_set_max) -+ return IP_SET_INVALID_ID; -+ -+ if (ip_set_list[index]) -+ __ip_set_get(index); -+ else -+ index = IP_SET_INVALID_ID; -+ -+ up(&ip_set_app_mutex); -+ return index; -+} -+ -+/* -+ * If the given set pointer points to a valid set, decrement -+ * reference count by 1. The caller shall not assume the index -+ * to be valid, after calling this function. -+ */ -+void ip_set_put(ip_set_id_t index) -+{ -+ down(&ip_set_app_mutex); -+ if (ip_set_list[index]) -+ __ip_set_put(index); -+ up(&ip_set_app_mutex); -+} -+ -+/* Find a set by name or index */ -+static ip_set_id_t -+ip_set_find_byname(const char *name) -+{ -+ ip_set_id_t i, index = IP_SET_INVALID_ID; -+ -+ for (i = 0; i < ip_set_max; i++) { -+ if (ip_set_list[i] != NULL -+ && strcmp(ip_set_list[i]->name, name) == 0) { -+ index = i; -+ break; -+ } -+ } -+ return index; -+} -+ -+static ip_set_id_t -+ip_set_find_byindex(ip_set_id_t index) -+{ -+ if (index >= ip_set_max || ip_set_list[index] == NULL) -+ index = IP_SET_INVALID_ID; -+ -+ return index; -+} -+ -+/* -+ * Add, del, test, bind and unbind -+ */ -+ -+static inline int -+__ip_set_testip(struct ip_set *set, -+ const void *data, -+ size_t size, -+ ip_set_ip_t *ip) -+{ -+ int res; -+ -+ read_lock_bh(&set->lock); -+ res = set->type->testip(set, data, size, ip); -+ read_unlock_bh(&set->lock); -+ -+ return res; -+} -+ -+static int -+__ip_set_addip(ip_set_id_t index, -+ const void *data, -+ size_t size) -+{ -+ struct ip_set *set = ip_set_list[index]; -+ ip_set_ip_t ip; -+ int res; -+ -+ IP_SET_ASSERT(set); -+ do { -+ write_lock_bh(&set->lock); -+ res = set->type->addip(set, data, size, &ip); -+ write_unlock_bh(&set->lock); -+ } while (res == -EAGAIN -+ && set->type->retry -+ && (res = set->type->retry(set)) == 0); -+ -+ return res; -+} -+ -+static int -+ip_set_addip(ip_set_id_t index, -+ const void *data, -+ size_t size) -+{ -+ -+ return __ip_set_addip(index, -+ data + sizeof(struct ip_set_req_adt), -+ size - sizeof(struct ip_set_req_adt)); -+} -+ -+static int -+ip_set_delip(ip_set_id_t index, -+ const void *data, -+ size_t size) -+{ -+ struct ip_set *set = ip_set_list[index]; -+ ip_set_ip_t ip; -+ int res; -+ -+ IP_SET_ASSERT(set); -+ write_lock_bh(&set->lock); -+ res = set->type->delip(set, -+ data + sizeof(struct ip_set_req_adt), -+ size - sizeof(struct ip_set_req_adt), -+ &ip); -+ write_unlock_bh(&set->lock); -+ -+ return res; -+} -+ -+static int -+ip_set_testip(ip_set_id_t index, -+ const void *data, -+ size_t size) -+{ -+ struct ip_set *set = ip_set_list[index]; -+ ip_set_ip_t ip; -+ int res; -+ -+ IP_SET_ASSERT(set); -+ res = __ip_set_testip(set, -+ data + sizeof(struct ip_set_req_adt), -+ size - sizeof(struct ip_set_req_adt), -+ &ip); -+ -+ return (res > 0 ? -EEXIST : res); -+} -+ -+static int -+ip_set_bindip(ip_set_id_t index, -+ const void *data, -+ size_t size) -+{ -+ struct ip_set *set = ip_set_list[index]; -+ struct ip_set_req_bind *req_bind; -+ ip_set_id_t binding; -+ ip_set_ip_t ip; -+ int res; -+ -+ IP_SET_ASSERT(set); -+ if (size < sizeof(struct ip_set_req_bind)) -+ return -EINVAL; -+ -+ req_bind = (struct ip_set_req_bind *) data; -+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0'; -+ -+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) { -+ /* Default binding of a set */ -+ char *binding_name; -+ -+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN) -+ return -EINVAL; -+ -+ binding_name = (char *)(data + sizeof(struct ip_set_req_bind)); -+ binding_name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ -+ binding = ip_set_find_byname(binding_name); -+ if (binding == IP_SET_INVALID_ID) -+ return -ENOENT; -+ -+ WRITE_LOCK(&ip_set_lock); -+ /* Sets as binding values are referenced */ -+ if (set->binding != IP_SET_INVALID_ID) -+ __ip_set_put(set->binding); -+ set->binding = binding; -+ __ip_set_get(set->binding); -+ WRITE_UNLOCK(&ip_set_lock); -+ -+ return 0; -+ } -+ binding = ip_set_find_byname(req_bind->binding); -+ if (binding == IP_SET_INVALID_ID) -+ return -ENOENT; -+ -+ res = __ip_set_testip(set, -+ data + sizeof(struct ip_set_req_bind), -+ size - sizeof(struct ip_set_req_bind), -+ &ip); -+ DP("set %s, ip: %u.%u.%u.%u, binding %s", -+ set->name, HIPQUAD(ip), ip_set_list[binding]->name); -+ -+ if (res >= 0) -+ res = ip_set_hash_add(set->id, ip, binding); -+ -+ return res; -+} -+ -+#define FOREACH_SET_DO(fn, args...) \ -+({ \ -+ ip_set_id_t __i; \ -+ struct ip_set *__set; \ -+ \ -+ for (__i = 0; __i < ip_set_max; __i++) { \ -+ __set = ip_set_list[__i]; \ -+ if (__set != NULL) \ -+ fn(__set , ##args); \ -+ } \ -+}) -+ -+static inline void -+__set_hash_del_byid(struct ip_set_hash *set_hash, ip_set_id_t id) -+{ -+ if (set_hash->id == id) -+ __set_hash_del(set_hash); -+} -+ -+static inline void -+__unbind_default(struct ip_set *set) -+{ -+ if (set->binding != IP_SET_INVALID_ID) { -+ /* Sets as binding values are referenced */ -+ __ip_set_put(set->binding); -+ set->binding = IP_SET_INVALID_ID; -+ } -+} -+ -+static int -+ip_set_unbindip(ip_set_id_t index, -+ const void *data, -+ size_t size) -+{ -+ struct ip_set *set; -+ struct ip_set_req_bind *req_bind; -+ ip_set_ip_t ip; -+ int res; -+ -+ DP(""); -+ if (size < sizeof(struct ip_set_req_bind)) -+ return -EINVAL; -+ -+ req_bind = (struct ip_set_req_bind *) data; -+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0'; -+ -+ DP("%u %s", index, req_bind->binding); -+ if (index == IP_SET_INVALID_ID) { -+ /* unbind :all: */ -+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) { -+ /* Default binding of sets */ -+ WRITE_LOCK(&ip_set_lock); -+ FOREACH_SET_DO(__unbind_default); -+ WRITE_UNLOCK(&ip_set_lock); -+ return 0; -+ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) { -+ /* Flush all bindings of all sets*/ -+ WRITE_LOCK(&ip_set_lock); -+ FOREACH_HASH_RW_DO(__set_hash_del); -+ WRITE_UNLOCK(&ip_set_lock); -+ return 0; -+ } -+ DP("unreachable reached!"); -+ return -EINVAL; -+ } -+ -+ set = ip_set_list[index]; -+ IP_SET_ASSERT(set); -+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) { -+ /* Default binding of set */ -+ ip_set_id_t binding = ip_set_find_byindex(set->binding); -+ -+ if (binding == IP_SET_INVALID_ID) -+ return -ENOENT; -+ -+ WRITE_LOCK(&ip_set_lock); -+ /* Sets in hash values are referenced */ -+ __ip_set_put(set->binding); -+ set->binding = IP_SET_INVALID_ID; -+ WRITE_UNLOCK(&ip_set_lock); -+ -+ return 0; -+ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) { -+ /* Flush all bindings */ -+ -+ WRITE_LOCK(&ip_set_lock); -+ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id); -+ WRITE_UNLOCK(&ip_set_lock); -+ return 0; -+ } -+ -+ res = __ip_set_testip(set, -+ data + sizeof(struct ip_set_req_bind), -+ size - sizeof(struct ip_set_req_bind), -+ &ip); -+ -+ DP("set %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip)); -+ if (res >= 0) -+ res = ip_set_hash_del(set->id, ip); -+ -+ return res; -+} -+ -+static int -+ip_set_testbind(ip_set_id_t index, -+ const void *data, -+ size_t size) -+{ -+ struct ip_set *set = ip_set_list[index]; -+ struct ip_set_req_bind *req_bind; -+ ip_set_id_t binding; -+ ip_set_ip_t ip; -+ int res; -+ -+ IP_SET_ASSERT(set); -+ if (size < sizeof(struct ip_set_req_bind)) -+ return -EINVAL; -+ -+ req_bind = (struct ip_set_req_bind *) data; -+ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0'; -+ -+ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) { -+ /* Default binding of set */ -+ char *binding_name; -+ -+ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN) -+ return -EINVAL; -+ -+ binding_name = (char *)(data + sizeof(struct ip_set_req_bind)); -+ binding_name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ -+ binding = ip_set_find_byname(binding_name); -+ if (binding == IP_SET_INVALID_ID) -+ return -ENOENT; -+ -+ res = (set->binding == binding) ? -EEXIST : 0; -+ -+ return res; -+ } -+ binding = ip_set_find_byname(req_bind->binding); -+ if (binding == IP_SET_INVALID_ID) -+ return -ENOENT; -+ -+ -+ res = __ip_set_testip(set, -+ data + sizeof(struct ip_set_req_bind), -+ size - sizeof(struct ip_set_req_bind), -+ &ip); -+ DP("set %s, ip: %u.%u.%u.%u, binding %s", -+ set->name, HIPQUAD(ip), ip_set_list[binding]->name); -+ -+ if (res >= 0) -+ res = (ip_set_find_in_hash(set->id, ip) == binding) -+ ? -EEXIST : 0; -+ -+ return res; -+} -+ -+static struct ip_set_type * -+find_set_type_rlock(const char *typename) -+{ -+ struct ip_set_type *type; -+ -+ READ_LOCK(&ip_set_lock); -+ type = find_set_type(typename); -+ if (type == NULL) -+ READ_UNLOCK(&ip_set_lock); -+ -+ return type; -+} -+ -+static int -+find_free_id(const char *name, -+ ip_set_id_t *index, -+ ip_set_id_t *id) -+{ -+ ip_set_id_t i; -+ -+ *id = IP_SET_INVALID_ID; -+ for (i = 0; i < ip_set_max; i++) { -+ if (ip_set_list[i] == NULL) { -+ if (*id == IP_SET_INVALID_ID) -+ *id = *index = i; -+ } else if (strcmp(name, ip_set_list[i]->name) == 0) -+ /* Name clash */ -+ return -EEXIST; -+ } -+ if (*id == IP_SET_INVALID_ID) -+ /* No free slot remained */ -+ return -ERANGE; -+ /* Check that index is usable as id (swapping) */ -+ check: -+ for (i = 0; i < ip_set_max; i++) { -+ if (ip_set_list[i] != NULL -+ && ip_set_list[i]->id == *id) { -+ *id = i; -+ goto check; -+ } -+ } -+ return 0; -+} -+ -+/* -+ * Create a set -+ */ -+static int -+ip_set_create(const char *name, -+ const char *typename, -+ ip_set_id_t restore, -+ const void *data, -+ size_t size) -+{ -+ struct ip_set *set; -+ ip_set_id_t index, id; -+ int res = 0; -+ -+ DP("setname: %s, typename: %s, id: %u", name, typename, restore); -+ /* -+ * First, and without any locks, allocate and initialize -+ * a normal base set structure. -+ */ -+ set = kmalloc(sizeof(struct ip_set), GFP_KERNEL); -+ if (!set) -+ return -ENOMEM; -+ set->lock = RW_LOCK_UNLOCKED; -+ strncpy(set->name, name, IP_SET_MAXNAMELEN); -+ set->binding = IP_SET_INVALID_ID; -+ atomic_set(&set->ref, 0); -+ -+ /* -+ * Next, take the &ip_set_lock, check that we know the type, -+ * and take a reference on the type, to make sure it -+ * stays available while constructing our new set. -+ * -+ * After referencing the type, we drop the &ip_set_lock, -+ * and let the new set construction run without locks. -+ */ -+ set->type = find_set_type_rlock(typename); -+ if (set->type == NULL) { -+ /* Try loading the module */ -+ char modulename[IP_SET_MAXNAMELEN + strlen("ip_set_") + 1]; -+ strcpy(modulename, "ip_set_"); -+ strcat(modulename, typename); -+ DP("try to load %s", modulename); -+ request_module(modulename); -+ set->type = find_set_type_rlock(typename); -+ } -+ if (set->type == NULL) { -+ ip_set_printk("no set type '%s', set '%s' not created", -+ typename, name); -+ kfree(set); -+ return -ENOENT; -+ } -+ __MOD_INC(set->type->me); -+ READ_UNLOCK(&ip_set_lock); -+ -+ /* -+ * Without holding any locks, create private part. -+ */ -+ res = set->type->create(set, data, size); -+ if (res != 0) { -+ __MOD_DEC(set->type->me); -+ kfree(set); -+ return res; -+ } -+ -+ /* BTW, res==0 here. */ -+ -+ /* -+ * Here, we have a valid, constructed set. &ip_set_lock again, -+ * find free id/index and check that it is not already in -+ * ip_set_list. -+ */ -+ WRITE_LOCK(&ip_set_lock); -+ if ((res = find_free_id(set->name, &index, &id)) != 0) { -+ DP("no free id!"); -+ goto cleanup; -+ } -+ -+ /* Make sure restore gets the same index */ -+ if (restore != IP_SET_INVALID_ID && index != restore) { -+ DP("Can't restore, sets are screwed up"); -+ res = -ERANGE; -+ goto cleanup; -+ } -+ -+ /* -+ * Finally! Add our shiny new set to the list, and be done. -+ */ -+ DP("create: '%s' created with index %u, id %u!", set->name, index, id); -+ set->id = id; -+ ip_set_list[index] = set; -+ WRITE_UNLOCK(&ip_set_lock); -+ return res; -+ -+ cleanup: -+ WRITE_UNLOCK(&ip_set_lock); -+ set->type->destroy(set); -+ __MOD_DEC(set->type->me); -+ kfree(set); -+ return res; -+} -+ -+/* -+ * Destroy a given existing set -+ */ -+static void -+ip_set_destroy_set(ip_set_id_t index) -+{ -+ struct ip_set *set = ip_set_list[index]; -+ -+ IP_SET_ASSERT(set); -+ DP("set: %s", set->name); -+ WRITE_LOCK(&ip_set_lock); -+ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id); -+ if (set->binding != IP_SET_INVALID_ID) -+ __ip_set_put(set->binding); -+ ip_set_list[index] = NULL; -+ WRITE_UNLOCK(&ip_set_lock); -+ -+ /* Must call it without holding any lock */ -+ set->type->destroy(set); -+ __MOD_DEC(set->type->me); -+ kfree(set); -+} -+ -+/* -+ * Destroy a set - or all sets -+ * Sets must not be referenced/used. -+ */ -+static int -+ip_set_destroy(ip_set_id_t index) -+{ -+ ip_set_id_t i; -+ -+ /* ref modification always protected by the mutex */ -+ if (index != IP_SET_INVALID_ID) { -+ if (atomic_read(&ip_set_list[index]->ref)) -+ return -EBUSY; -+ ip_set_destroy_set(index); -+ } else { -+ for (i = 0; i < ip_set_max; i++) { -+ if (ip_set_list[i] != NULL -+ && (atomic_read(&ip_set_list[i]->ref))) -+ return -EBUSY; -+ } -+ -+ for (i = 0; i < ip_set_max; i++) { -+ if (ip_set_list[i] != NULL) -+ ip_set_destroy_set(i); -+ } -+ } -+ return 0; -+} -+ -+static void -+ip_set_flush_set(struct ip_set *set) -+{ -+ DP("set: %s %u", set->name, set->id); -+ -+ write_lock_bh(&set->lock); -+ set->type->flush(set); -+ write_unlock_bh(&set->lock); -+} -+ -+/* -+ * Flush data in a set - or in all sets -+ */ -+static int -+ip_set_flush(ip_set_id_t index) -+{ -+ if (index != IP_SET_INVALID_ID) { -+ IP_SET_ASSERT(ip_set_list[index]); -+ ip_set_flush_set(ip_set_list[index]); -+ } else -+ FOREACH_SET_DO(ip_set_flush_set); -+ -+ return 0; -+} -+ -+/* Rename a set */ -+static int -+ip_set_rename(ip_set_id_t index, const char *name) -+{ -+ struct ip_set *set = ip_set_list[index]; -+ ip_set_id_t i; -+ int res = 0; -+ -+ DP("set: %s to %s", set->name, name); -+ WRITE_LOCK(&ip_set_lock); -+ for (i = 0; i < ip_set_max; i++) { -+ if (ip_set_list[i] != NULL -+ && strncmp(ip_set_list[i]->name, -+ name, -+ IP_SET_MAXNAMELEN - 1) == 0) { -+ res = -EEXIST; -+ goto unlock; -+ } -+ } -+ strncpy(set->name, name, IP_SET_MAXNAMELEN); -+ unlock: -+ WRITE_UNLOCK(&ip_set_lock); -+ return res; -+} -+ -+/* -+ * Swap two sets so that name/index points to the other. -+ * References are also swapped. -+ */ -+static int -+ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index) -+{ -+ struct ip_set *from = ip_set_list[from_index]; -+ struct ip_set *to = ip_set_list[to_index]; -+ char from_name[IP_SET_MAXNAMELEN]; -+ u_int32_t from_ref; -+ -+ DP("set: %s to %s", from->name, to->name); -+ /* Type can't be changed. Artifical restriction. */ -+ if (from->type->typecode != to->type->typecode) -+ return -ENOEXEC; -+ -+ /* No magic here: ref munging protected by the mutex */ -+ WRITE_LOCK(&ip_set_lock); -+ strncpy(from_name, from->name, IP_SET_MAXNAMELEN); -+ from_ref = atomic_read(&from->ref); -+ -+ strncpy(from->name, to->name, IP_SET_MAXNAMELEN); -+ atomic_set(&from->ref, atomic_read(&to->ref)); -+ strncpy(to->name, from_name, IP_SET_MAXNAMELEN); -+ atomic_set(&to->ref, from_ref); -+ -+ ip_set_list[from_index] = to; -+ ip_set_list[to_index] = from; -+ -+ WRITE_UNLOCK(&ip_set_lock); -+ return 0; -+} -+ -+/* -+ * List set data -+ */ -+ -+static inline void -+__set_hash_bindings_size_list(struct ip_set_hash *set_hash, -+ ip_set_id_t id, size_t *size) -+{ -+ if (set_hash->id == id) -+ *size += sizeof(struct ip_set_hash_list); -+} -+ -+static inline void -+__set_hash_bindings_size_save(struct ip_set_hash *set_hash, -+ ip_set_id_t id, size_t *size) -+{ -+ if (set_hash->id == id) -+ *size += sizeof(struct ip_set_hash_save); -+} -+ -+static inline void -+__set_hash_bindings(struct ip_set_hash *set_hash, -+ ip_set_id_t id, void *data, int *used) -+{ -+ if (set_hash->id == id) { -+ struct ip_set_hash_list *hash_list = -+ (struct ip_set_hash_list *)(data + *used); -+ -+ hash_list->ip = set_hash->ip; -+ hash_list->binding = set_hash->binding; -+ *used += sizeof(struct ip_set_hash_list); -+ } -+} -+ -+static int ip_set_list_set(ip_set_id_t index, -+ void *data, -+ int *used, -+ int len) -+{ -+ struct ip_set *set = ip_set_list[index]; -+ struct ip_set_list *set_list; -+ -+ /* Pointer to our header */ -+ set_list = (struct ip_set_list *) (data + *used); -+ -+ DP("set: %s, used: %d %p %p", set->name, *used, data, data + *used); -+ -+ /* Get and ensure header size */ -+ if (*used + sizeof(struct ip_set_list) > len) -+ goto not_enough_mem; -+ *used += sizeof(struct ip_set_list); -+ -+ read_lock_bh(&set->lock); -+ /* Get and ensure set specific header size */ -+ set_list->header_size = set->type->header_size; -+ if (*used + set_list->header_size > len) -+ goto unlock_set; -+ -+ /* Fill in the header */ -+ set_list->index = index; -+ set_list->binding = set->binding; -+ set_list->ref = atomic_read(&set->ref); -+ -+ /* Fill in set spefific header data */ -+ DP("call list_header"); -+ set->type->list_header(set, data + *used); -+ DP("call list_header, done"); -+ *used += set_list->header_size; -+ -+ /* Get and ensure set specific members size */ -+ DP("call list_members_size"); -+ set_list->members_size = set->type->list_members_size(set); -+ DP("call list_members_size, done"); -+ if (*used + set_list->members_size > len) -+ goto unlock_set; -+ -+ /* Fill in set spefific members data */ -+ DP("call list_members"); -+ set->type->list_members(set, data + *used); -+ DP("call list_members, done"); -+ *used += set_list->members_size; -+ read_unlock_bh(&set->lock); -+ -+ /* Bindings */ -+ -+ /* Get and ensure set specific bindings size */ -+ set_list->bindings_size = 0; -+ FOREACH_HASH_DO(__set_hash_bindings_size_list, -+ set->id, &set_list->bindings_size); -+ if (*used + set_list->bindings_size > len) -+ goto not_enough_mem; -+ -+ /* Fill in set spefific bindings data */ -+ FOREACH_HASH_DO(__set_hash_bindings, set->id, data, used); -+ -+ return 0; -+ -+ unlock_set: -+ read_unlock_bh(&set->lock); -+ not_enough_mem: -+ DP("not enough mem, try again"); -+ return -EAGAIN; -+} -+ -+/* -+ * Save sets -+ */ -+static int ip_set_save_set(ip_set_id_t index, -+ void *data, -+ int *used, -+ int len) -+{ -+ struct ip_set *set; -+ struct ip_set_save *set_save; -+ -+ /* Pointer to our header */ -+ set_save = (struct ip_set_save *) (data + *used); -+ -+ /* Get and ensure header size */ -+ if (*used + sizeof(struct ip_set_save) > len) -+ goto not_enough_mem; -+ *used += sizeof(struct ip_set_save); -+ -+ set = ip_set_list[index]; -+ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len, -+ data, data + *used); -+ -+ read_lock_bh(&set->lock); -+ /* Get and ensure set specific header size */ -+ set_save->header_size = set->type->header_size; -+ if (*used + set_save->header_size > len) -+ goto unlock_set; -+ -+ /* Fill in the header */ -+ set_save->index = index; -+ set_save->binding = set->binding; -+ -+ /* Fill in set spefific header data */ -+ set->type->list_header(set, data + *used); -+ *used += set_save->header_size; -+ -+ DP("set header filled: %s, used: %u %p %p", set->name, *used, -+ data, data + *used); -+ /* Get and ensure set specific members size */ -+ set_save->members_size = set->type->list_members_size(set); -+ if (*used + set_save->members_size > len) -+ goto unlock_set; -+ -+ /* Fill in set spefific members data */ -+ set->type->list_members(set, data + *used); -+ *used += set_save->members_size; -+ read_unlock_bh(&set->lock); -+ DP("set members filled: %s, used: %u %p %p", set->name, *used, -+ data, data + *used); -+ return 0; -+ -+ unlock_set: -+ read_unlock_bh(&set->lock); -+ not_enough_mem: -+ DP("not enough mem, try again"); -+ return -EAGAIN; -+} -+ -+static inline void -+__set_hash_save_bindings(struct ip_set_hash *set_hash, -+ ip_set_id_t id, -+ void *data, -+ int *used, -+ int len, -+ int *res) -+{ -+ if (*res == 0 -+ && (id == IP_SET_INVALID_ID || set_hash->id == id)) { -+ struct ip_set_hash_save *hash_save = -+ (struct ip_set_hash_save *)(data + *used); -+ /* Ensure bindings size */ -+ if (*used + sizeof(struct ip_set_hash_save) > len) { -+ *res = -ENOMEM; -+ return; -+ } -+ hash_save->id = set_hash->id; -+ hash_save->ip = set_hash->ip; -+ hash_save->binding = set_hash->binding; -+ *used += sizeof(struct ip_set_hash_save); -+ } -+} -+ -+static int ip_set_save_bindings(ip_set_id_t index, -+ void *data, -+ int *used, -+ int len) -+{ -+ int res = 0; -+ struct ip_set_save *set_save; -+ -+ DP("used %u, len %u", *used, len); -+ /* Get and ensure header size */ -+ if (*used + sizeof(struct ip_set_save) > len) -+ return -ENOMEM; -+ -+ /* Marker */ -+ set_save = (struct ip_set_save *) (data + *used); -+ set_save->index = IP_SET_INVALID_ID; -+ *used += sizeof(struct ip_set_save); -+ -+ DP("marker added used %u, len %u", *used, len); -+ /* Fill in bindings data */ -+ if (index != IP_SET_INVALID_ID) -+ /* Sets are identified by id in hash */ -+ index = ip_set_list[index]->id; -+ FOREACH_HASH_DO(__set_hash_save_bindings, index, data, used, len, &res); -+ -+ return res; -+} -+ -+/* -+ * Restore sets -+ */ -+static int ip_set_restore(void *data, -+ int len) -+{ -+ int res = 0; -+ int line = 0, used = 0, members_size; -+ struct ip_set *set; -+ struct ip_set_hash_save *hash_save; -+ struct ip_set_restore *set_restore; -+ ip_set_id_t index; -+ -+ /* Loop to restore sets */ -+ while (1) { -+ line++; -+ -+ DP("%u %u %u", used, sizeof(struct ip_set_restore), len); -+ /* Get and ensure header size */ -+ if (used + sizeof(struct ip_set_restore) > len) -+ return line; -+ set_restore = (struct ip_set_restore *) (data + used); -+ used += sizeof(struct ip_set_restore); -+ -+ /* Ensure data size */ -+ if (used -+ + set_restore->header_size -+ + set_restore->members_size > len) -+ return line; -+ -+ /* Check marker */ -+ if (set_restore->index == IP_SET_INVALID_ID) { -+ line--; -+ goto bindings; -+ } -+ -+ /* Try to create the set */ -+ DP("restore %s %s", set_restore->name, set_restore->typename); -+ res = ip_set_create(set_restore->name, -+ set_restore->typename, -+ set_restore->index, -+ data + used, -+ set_restore->header_size); -+ -+ if (res != 0) -+ return line; -+ used += set_restore->header_size; -+ -+ index = ip_set_find_byindex(set_restore->index); -+ DP("index %u, restore_index %u", index, set_restore->index); -+ if (index != set_restore->index) -+ return line; -+ /* Try to restore members data */ -+ set = ip_set_list[index]; -+ members_size = 0; -+ DP("members_size %u reqsize %u", -+ set_restore->members_size, set->type->reqsize); -+ while (members_size + set->type->reqsize <= -+ set_restore->members_size) { -+ line++; -+ DP("members: %u, line %u", members_size, line); -+ res = __ip_set_addip(index, -+ data + used + members_size, -+ set->type->reqsize); -+ if (!(res == 0 || res == -EEXIST)) -+ return line; -+ members_size += set->type->reqsize; -+ } -+ -+ DP("members_size %u %u", -+ set_restore->members_size, members_size); -+ if (members_size != set_restore->members_size) -+ return line++; -+ used += set_restore->members_size; -+ } -+ -+ bindings: -+ /* Loop to restore bindings */ -+ while (used < len) { -+ line++; -+ -+ DP("restore binding, line %u", line); -+ /* Get and ensure size */ -+ if (used + sizeof(struct ip_set_hash_save) > len) -+ return line; -+ hash_save = (struct ip_set_hash_save *) (data + used); -+ used += sizeof(struct ip_set_hash_save); -+ -+ /* hash_save->id is used to store the index */ -+ index = ip_set_find_byindex(hash_save->id); -+ DP("restore binding index %u, id %u, %u -> %u", -+ index, hash_save->id, hash_save->ip, hash_save->binding); -+ if (index != hash_save->id) -+ return line; -+ -+ set = ip_set_list[hash_save->id]; -+ /* Null valued IP means default binding */ -+ if (hash_save->ip) -+ res = ip_set_hash_add(set->id, -+ hash_save->ip, -+ hash_save->binding); -+ else { -+ IP_SET_ASSERT(set->binding == IP_SET_INVALID_ID); -+ WRITE_LOCK(&ip_set_lock); -+ set->binding = hash_save->binding; -+ __ip_set_get(set->binding); -+ WRITE_UNLOCK(&ip_set_lock); -+ DP("default binding: %u", set->binding); -+ } -+ if (res != 0) -+ return line; -+ } -+ if (used != len) -+ return line; -+ -+ return 0; -+} -+ -+static int -+ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len) -+{ -+ void *data; -+ int res = 0; /* Assume OK */ -+ unsigned *op; -+ struct ip_set_req_adt *req_adt; -+ ip_set_id_t index = IP_SET_INVALID_ID; -+ int (*adtfn)(ip_set_id_t index, -+ const void *data, size_t size); -+ struct fn_table { -+ int (*fn)(ip_set_id_t index, -+ const void *data, size_t size); -+ } adtfn_table[] = -+ { { ip_set_addip }, { ip_set_delip }, { ip_set_testip}, -+ { ip_set_bindip}, { ip_set_unbindip }, { ip_set_testbind }, -+ }; -+ -+ DP("optval=%d, user=%p, len=%d", optval, user, len); -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ if (optval != SO_IP_SET) -+ return -EBADF; -+ if (len <= sizeof(unsigned)) { -+ ip_set_printk("short userdata (want >%zu, got %u)", -+ sizeof(unsigned), len); -+ return -EINVAL; -+ } -+ data = vmalloc(len); -+ if (!data) { -+ DP("out of mem for %u bytes", len); -+ return -ENOMEM; -+ } -+ if (copy_from_user(data, user, len) != 0) { -+ res = -EFAULT; -+ goto done; -+ } -+ if (down_interruptible(&ip_set_app_mutex)) { -+ res = -EINTR; -+ goto done; -+ } -+ -+ op = (unsigned *)data; -+ DP("op=%x", *op); -+ -+ if (*op < IP_SET_OP_VERSION) { -+ /* Check the version at the beginning of operations */ -+ struct ip_set_req_version *req_version = -+ (struct ip_set_req_version *) data; -+ if (req_version->version != IP_SET_PROTOCOL_VERSION) { -+ res = -EPROTO; -+ goto done; -+ } -+ } -+ -+ switch (*op) { -+ case IP_SET_OP_CREATE:{ -+ struct ip_set_req_create *req_create -+ = (struct ip_set_req_create *) data; -+ -+ if (len <= sizeof(struct ip_set_req_create)) { -+ ip_set_printk("short CREATE data (want >%zu, got %u)", -+ sizeof(struct ip_set_req_create), len); -+ res = -EINVAL; -+ goto done; -+ } -+ req_create->name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ req_create->typename[IP_SET_MAXNAMELEN - 1] = '\0'; -+ res = ip_set_create(req_create->name, -+ req_create->typename, -+ IP_SET_INVALID_ID, -+ data + sizeof(struct ip_set_req_create), -+ len - sizeof(struct ip_set_req_create)); -+ goto done; -+ } -+ case IP_SET_OP_DESTROY:{ -+ struct ip_set_req_std *req_destroy -+ = (struct ip_set_req_std *) data; -+ -+ if (len != sizeof(struct ip_set_req_std)) { -+ ip_set_printk("invalid DESTROY data (want %zu, got %u)", -+ sizeof(struct ip_set_req_std), len); -+ res = -EINVAL; -+ goto done; -+ } -+ if (strcmp(req_destroy->name, IPSET_TOKEN_ALL) == 0) { -+ /* Destroy all sets */ -+ index = IP_SET_INVALID_ID; -+ } else { -+ req_destroy->name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ index = ip_set_find_byname(req_destroy->name); -+ -+ if (index == IP_SET_INVALID_ID) { -+ res = -ENOENT; -+ goto done; -+ } -+ } -+ -+ res = ip_set_destroy(index); -+ goto done; -+ } -+ case IP_SET_OP_FLUSH:{ -+ struct ip_set_req_std *req_flush = -+ (struct ip_set_req_std *) data; -+ -+ if (len != sizeof(struct ip_set_req_std)) { -+ ip_set_printk("invalid FLUSH data (want %zu, got %u)", -+ sizeof(struct ip_set_req_std), len); -+ res = -EINVAL; -+ goto done; -+ } -+ if (strcmp(req_flush->name, IPSET_TOKEN_ALL) == 0) { -+ /* Flush all sets */ -+ index = IP_SET_INVALID_ID; -+ } else { -+ req_flush->name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ index = ip_set_find_byname(req_flush->name); -+ -+ if (index == IP_SET_INVALID_ID) { -+ res = -ENOENT; -+ goto done; -+ } -+ } -+ res = ip_set_flush(index); -+ goto done; -+ } -+ case IP_SET_OP_RENAME:{ -+ struct ip_set_req_create *req_rename -+ = (struct ip_set_req_create *) data; -+ -+ if (len != sizeof(struct ip_set_req_create)) { -+ ip_set_printk("invalid RENAME data (want %zu, got %u)", -+ sizeof(struct ip_set_req_create), len); -+ res = -EINVAL; -+ goto done; -+ } -+ -+ req_rename->name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ req_rename->typename[IP_SET_MAXNAMELEN - 1] = '\0'; -+ -+ index = ip_set_find_byname(req_rename->name); -+ if (index == IP_SET_INVALID_ID) { -+ res = -ENOENT; -+ goto done; -+ } -+ res = ip_set_rename(index, req_rename->typename); -+ goto done; -+ } -+ case IP_SET_OP_SWAP:{ -+ struct ip_set_req_create *req_swap -+ = (struct ip_set_req_create *) data; -+ ip_set_id_t to_index; -+ -+ if (len != sizeof(struct ip_set_req_create)) { -+ ip_set_printk("invalid SWAP data (want %zu, got %u)", -+ sizeof(struct ip_set_req_create), len); -+ res = -EINVAL; -+ goto done; -+ } -+ -+ req_swap->name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ req_swap->typename[IP_SET_MAXNAMELEN - 1] = '\0'; -+ -+ index = ip_set_find_byname(req_swap->name); -+ if (index == IP_SET_INVALID_ID) { -+ res = -ENOENT; -+ goto done; -+ } -+ to_index = ip_set_find_byname(req_swap->typename); -+ if (to_index == IP_SET_INVALID_ID) { -+ res = -ENOENT; -+ goto done; -+ } -+ res = ip_set_swap(index, to_index); -+ goto done; -+ } -+ default: -+ break; /* Set identified by id */ -+ } -+ -+ /* There we may have add/del/test/bind/unbind/test_bind operations */ -+ if (*op < IP_SET_OP_ADD_IP || *op > IP_SET_OP_TEST_BIND_SET) { -+ res = -EBADMSG; -+ goto done; -+ } -+ adtfn = adtfn_table[*op - IP_SET_OP_ADD_IP].fn; -+ -+ if (len < sizeof(struct ip_set_req_adt)) { -+ ip_set_printk("short data in adt request (want >=%zu, got %u)", -+ sizeof(struct ip_set_req_adt), len); -+ res = -EINVAL; -+ goto done; -+ } -+ req_adt = (struct ip_set_req_adt *) data; -+ -+ /* -U :all: :all:|:default: uses IP_SET_INVALID_ID */ -+ if (!(*op == IP_SET_OP_UNBIND_SET -+ && req_adt->index == IP_SET_INVALID_ID)) { -+ index = ip_set_find_byindex(req_adt->index); -+ if (index == IP_SET_INVALID_ID) { -+ res = -ENOENT; -+ goto done; -+ } -+ } -+ res = adtfn(index, data, len); -+ -+ done: -+ up(&ip_set_app_mutex); -+ vfree(data); -+ if (res > 0) -+ res = 0; -+ DP("final result %d", res); -+ return res; -+} -+ -+static int -+ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len) -+{ -+ int res = 0; -+ unsigned *op; -+ ip_set_id_t index = IP_SET_INVALID_ID; -+ void *data; -+ int copylen = *len; -+ -+ DP("optval=%d, user=%p, len=%d", optval, user, *len); -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ if (optval != SO_IP_SET) -+ return -EBADF; -+ if (*len < sizeof(unsigned)) { -+ ip_set_printk("short userdata (want >=%zu, got %d)", -+ sizeof(unsigned), *len); -+ return -EINVAL; -+ } -+ data = vmalloc(*len); -+ if (!data) { -+ DP("out of mem for %d bytes", *len); -+ return -ENOMEM; -+ } -+ if (copy_from_user(data, user, *len) != 0) { -+ res = -EFAULT; -+ goto done; -+ } -+ if (down_interruptible(&ip_set_app_mutex)) { -+ res = -EINTR; -+ goto done; -+ } -+ -+ op = (unsigned *) data; -+ DP("op=%x", *op); -+ -+ if (*op < IP_SET_OP_VERSION) { -+ /* Check the version at the beginning of operations */ -+ struct ip_set_req_version *req_version = -+ (struct ip_set_req_version *) data; -+ if (req_version->version != IP_SET_PROTOCOL_VERSION) { -+ res = -EPROTO; -+ goto done; -+ } -+ } -+ -+ switch (*op) { -+ case IP_SET_OP_VERSION: { -+ struct ip_set_req_version *req_version = -+ (struct ip_set_req_version *) data; -+ -+ if (*len != sizeof(struct ip_set_req_version)) { -+ ip_set_printk("invalid VERSION (want %zu, got %d)", -+ sizeof(struct ip_set_req_version), -+ *len); -+ res = -EINVAL; -+ goto done; -+ } -+ -+ req_version->version = IP_SET_PROTOCOL_VERSION; -+ res = copy_to_user(user, req_version, -+ sizeof(struct ip_set_req_version)); -+ goto done; -+ } -+ case IP_SET_OP_GET_BYNAME: { -+ struct ip_set_req_get_set *req_get -+ = (struct ip_set_req_get_set *) data; -+ -+ if (*len != sizeof(struct ip_set_req_get_set)) { -+ ip_set_printk("invalid GET_BYNAME (want %zu, got %d)", -+ sizeof(struct ip_set_req_get_set), *len); -+ res = -EINVAL; -+ goto done; -+ } -+ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ index = ip_set_find_byname(req_get->set.name); -+ req_get->set.index = index; -+ goto copy; -+ } -+ case IP_SET_OP_GET_BYINDEX: { -+ struct ip_set_req_get_set *req_get -+ = (struct ip_set_req_get_set *) data; -+ -+ if (*len != sizeof(struct ip_set_req_get_set)) { -+ ip_set_printk("invalid GET_BYINDEX (want %zu, got %d)", -+ sizeof(struct ip_set_req_get_set), *len); -+ res = -EINVAL; -+ goto done; -+ } -+ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ index = ip_set_find_byindex(req_get->set.index); -+ strncpy(req_get->set.name, -+ index == IP_SET_INVALID_ID ? "" -+ : ip_set_list[index]->name, IP_SET_MAXNAMELEN); -+ goto copy; -+ } -+ case IP_SET_OP_ADT_GET: { -+ struct ip_set_req_adt_get *req_get -+ = (struct ip_set_req_adt_get *) data; -+ -+ if (*len != sizeof(struct ip_set_req_adt_get)) { -+ ip_set_printk("invalid ADT_GET (want %zu, got %d)", -+ sizeof(struct ip_set_req_adt_get), *len); -+ res = -EINVAL; -+ goto done; -+ } -+ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ index = ip_set_find_byname(req_get->set.name); -+ if (index != IP_SET_INVALID_ID) { -+ req_get->set.index = index; -+ strncpy(req_get->typename, -+ ip_set_list[index]->type->typename, -+ IP_SET_MAXNAMELEN - 1); -+ } else { -+ res = -ENOENT; -+ goto done; -+ } -+ goto copy; -+ } -+ case IP_SET_OP_MAX_SETS: { -+ struct ip_set_req_max_sets *req_max_sets -+ = (struct ip_set_req_max_sets *) data; -+ ip_set_id_t i; -+ -+ if (*len != sizeof(struct ip_set_req_max_sets)) { -+ ip_set_printk("invalid MAX_SETS (want %zu, got %d)", -+ sizeof(struct ip_set_req_max_sets), *len); -+ res = -EINVAL; -+ goto done; -+ } -+ -+ if (strcmp(req_max_sets->set.name, IPSET_TOKEN_ALL) == 0) { -+ req_max_sets->set.index = IP_SET_INVALID_ID; -+ } else { -+ req_max_sets->set.name[IP_SET_MAXNAMELEN - 1] = '\0'; -+ req_max_sets->set.index = -+ ip_set_find_byname(req_max_sets->set.name); -+ if (req_max_sets->set.index == IP_SET_INVALID_ID) { -+ res = -ENOENT; -+ goto done; -+ } -+ } -+ req_max_sets->max_sets = ip_set_max; -+ req_max_sets->sets = 0; -+ for (i = 0; i < ip_set_max; i++) { -+ if (ip_set_list[i] != NULL) -+ req_max_sets->sets++; -+ } -+ goto copy; -+ } -+ case IP_SET_OP_LIST_SIZE: -+ case IP_SET_OP_SAVE_SIZE: { -+ struct ip_set_req_setnames *req_setnames -+ = (struct ip_set_req_setnames *) data; -+ struct ip_set_name_list *name_list; -+ struct ip_set *set; -+ ip_set_id_t i; -+ int used; -+ -+ if (*len < sizeof(struct ip_set_req_setnames)) { -+ ip_set_printk("short LIST_SIZE (want >=%zu, got %d)", -+ sizeof(struct ip_set_req_setnames), *len); -+ res = -EINVAL; -+ goto done; -+ } -+ -+ req_setnames->size = 0; -+ used = sizeof(struct ip_set_req_setnames); -+ for (i = 0; i < ip_set_max; i++) { -+ if (ip_set_list[i] == NULL) -+ continue; -+ name_list = (struct ip_set_name_list *) -+ (data + used); -+ used += sizeof(struct ip_set_name_list); -+ if (used > copylen) { -+ res = -EAGAIN; -+ goto done; -+ } -+ set = ip_set_list[i]; -+ /* Fill in index, name, etc. */ -+ name_list->index = i; -+ name_list->id = set->id; -+ strncpy(name_list->name, -+ set->name, -+ IP_SET_MAXNAMELEN - 1); -+ strncpy(name_list->typename, -+ set->type->typename, -+ IP_SET_MAXNAMELEN - 1); -+ DP("filled %s of type %s, index %u\n", -+ name_list->name, name_list->typename, -+ name_list->index); -+ if (!(req_setnames->index == IP_SET_INVALID_ID -+ || req_setnames->index == i)) -+ continue; -+ /* Update size */ -+ switch (*op) { -+ case IP_SET_OP_LIST_SIZE: { -+ req_setnames->size += sizeof(struct ip_set_list) -+ + set->type->header_size -+ + set->type->list_members_size(set); -+ FOREACH_HASH_DO(__set_hash_bindings_size_list, -+ i, &req_setnames->size); -+ break; -+ } -+ case IP_SET_OP_SAVE_SIZE: { -+ req_setnames->size += sizeof(struct ip_set_save) -+ + set->type->header_size -+ + set->type->list_members_size(set); -+ FOREACH_HASH_DO(__set_hash_bindings_size_save, -+ i, &req_setnames->size); -+ break; -+ } -+ default: -+ break; -+ } -+ } -+ if (copylen != used) { -+ res = -EAGAIN; -+ goto done; -+ } -+ goto copy; -+ } -+ case IP_SET_OP_LIST: { -+ struct ip_set_req_list *req_list -+ = (struct ip_set_req_list *) data; -+ ip_set_id_t i; -+ int used; -+ -+ if (*len < sizeof(struct ip_set_req_list)) { -+ ip_set_printk("short LIST (want >=%zu, got %d)", -+ sizeof(struct ip_set_req_list), *len); -+ res = -EINVAL; -+ goto done; -+ } -+ index = req_list->index; -+ if (index != IP_SET_INVALID_ID -+ && ip_set_find_byindex(index) != index) { -+ res = -ENOENT; -+ goto done; -+ } -+ used = 0; -+ if (index == IP_SET_INVALID_ID) { -+ /* List all sets */ -+ for (i = 0; i < ip_set_max && res == 0; i++) { -+ if (ip_set_list[i] != NULL) -+ res = ip_set_list_set(i, data, &used, *len); -+ } -+ } else { -+ /* List an individual set */ -+ res = ip_set_list_set(index, data, &used, *len); -+ } -+ if (res != 0) -+ goto done; -+ else if (copylen != used) { -+ res = -EAGAIN; -+ goto done; -+ } -+ goto copy; -+ } -+ case IP_SET_OP_SAVE: { -+ struct ip_set_req_list *req_save -+ = (struct ip_set_req_list *) data; -+ ip_set_id_t i; -+ int used; -+ -+ if (*len < sizeof(struct ip_set_req_list)) { -+ ip_set_printk("short SAVE (want >=%zu, got %d)", -+ sizeof(struct ip_set_req_list), *len); -+ res = -EINVAL; -+ goto done; -+ } -+ index = req_save->index; -+ if (index != IP_SET_INVALID_ID -+ && ip_set_find_byindex(index) != index) { -+ res = -ENOENT; -+ goto done; -+ } -+ used = 0; -+ if (index == IP_SET_INVALID_ID) { -+ /* Save all sets */ -+ for (i = 0; i < ip_set_max && res == 0; i++) { -+ if (ip_set_list[i] != NULL) -+ res = ip_set_save_set(i, data, &used, *len); -+ } -+ } else { -+ /* Save an individual set */ -+ res = ip_set_save_set(index, data, &used, *len); -+ } -+ if (res == 0) -+ res = ip_set_save_bindings(index, data, &used, *len); -+ -+ if (res != 0) -+ goto done; -+ else if (copylen != used) { -+ res = -EAGAIN; -+ goto done; -+ } -+ goto copy; -+ } -+ case IP_SET_OP_RESTORE: { -+ struct ip_set_req_setnames *req_restore -+ = (struct ip_set_req_setnames *) data; -+ int line; -+ -+ if (*len < sizeof(struct ip_set_req_setnames) -+ || *len != req_restore->size) { -+ ip_set_printk("invalid RESTORE (want =%zu, got %d)", -+ req_restore->size, *len); -+ res = -EINVAL; -+ goto done; -+ } -+ line = ip_set_restore(data + sizeof(struct ip_set_req_setnames), -+ req_restore->size - sizeof(struct ip_set_req_setnames)); -+ DP("ip_set_restore: %u", line); -+ if (line != 0) { -+ res = -EAGAIN; -+ req_restore->size = line; -+ copylen = sizeof(struct ip_set_req_setnames); -+ goto copy; -+ } -+ goto done; -+ } -+ default: -+ res = -EBADMSG; -+ goto done; -+ } /* end of switch(op) */ -+ -+ copy: -+ DP("set %s, copylen %u", index != IP_SET_INVALID_ID -+ && ip_set_list[index] -+ ? ip_set_list[index]->name -+ : ":all:", copylen); -+ if (res == 0) -+ res = copy_to_user(user, data, copylen); -+ else -+ copy_to_user(user, data, copylen); -+ -+ done: -+ up(&ip_set_app_mutex); -+ vfree(data); -+ if (res > 0) -+ res = 0; -+ DP("final result %d", res); -+ return res; -+} -+ -+static struct nf_sockopt_ops so_set = { -+ .pf = PF_INET, -+ .set_optmin = SO_IP_SET, -+ .set_optmax = SO_IP_SET + 1, -+ .set = &ip_set_sockfn_set, -+ .get_optmin = SO_IP_SET, -+ .get_optmax = SO_IP_SET + 1, -+ .get = &ip_set_sockfn_get, -+ .use = 0 -+}; -+ -+static int max_sets, hash_size; -+MODULE_PARM(max_sets, "i"); -+MODULE_PARM_DESC(max_sets, "maximal number of sets"); -+MODULE_PARM(hash_size, "i"); -+MODULE_PARM_DESC(hash_size, "hash size for bindings"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -+MODULE_DESCRIPTION("module implementing core IP set support"); -+ -+static int __init init(void) -+{ -+ int res; -+ ip_set_id_t i; -+ -+ get_random_bytes(&ip_set_hash_random, 4); -+ if (max_sets) -+ ip_set_max = max_sets; -+ ip_set_list = vmalloc(sizeof(struct ip_set *) * ip_set_max); -+ if (!ip_set_list) { -+ printk(KERN_ERR "Unable to create ip_set_list\n"); -+ return -ENOMEM; -+ } -+ memset(ip_set_list, 0, sizeof(struct ip_set *) * ip_set_max); -+ if (hash_size) -+ ip_set_bindings_hash_size = hash_size; -+ ip_set_hash = vmalloc(sizeof(struct list_head) * ip_set_bindings_hash_size); -+ if (!ip_set_hash) { -+ printk(KERN_ERR "Unable to create ip_set_hash\n"); -+ vfree(ip_set_list); -+ return -ENOMEM; -+ } -+ for (i = 0; i < ip_set_bindings_hash_size; i++) -+ INIT_LIST_HEAD(&ip_set_hash[i]); -+ -+ INIT_LIST_HEAD(&set_type_list); -+ -+ res = nf_register_sockopt(&so_set); -+ if (res != 0) { -+ ip_set_printk("SO_SET registry failed: %d", res); -+ vfree(ip_set_list); -+ vfree(ip_set_hash); -+ return res; -+ } -+ return 0; -+} -+ -+static void __exit fini(void) -+{ -+ /* There can't be any existing set or binding. Racy. */ -+ nf_unregister_sockopt(&so_set); -+ vfree(ip_set_list); -+ vfree(ip_set_hash); -+ DP("these are the famous last words"); -+} -+ -+EXPORT_SYMBOL(ip_set_register_set_type); -+EXPORT_SYMBOL(ip_set_unregister_set_type); -+ -+EXPORT_SYMBOL(ip_set_get_byname); -+EXPORT_SYMBOL(ip_set_get_byindex); -+EXPORT_SYMBOL(ip_set_put); -+ -+EXPORT_SYMBOL(ip_set_addip_kernel); -+EXPORT_SYMBOL(ip_set_delip_kernel); -+EXPORT_SYMBOL(ip_set_testip_kernel); -+ -+module_init(init); -+module_exit(fini); -diff -Naur linux-old/net/ipv4/netfilter/ip_set_iphash.c linux-new/net/ipv4/netfilter/ip_set_iphash.c ---- linux-old/net/ipv4/netfilter/ip_set_iphash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/net/ipv4/netfilter/ip_set_iphash.c 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,379 @@ -+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* Kernel module implementing an ip hash set */ -+ -+#include <linux/module.h> -+#include <linux/ip.h> -+#include <linux/skbuff.h> -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ip_set.h> -+#include <linux/errno.h> -+#include <asm/uaccess.h> -+#include <asm/bitops.h> -+#include <asm/softirq.h> -+#include <linux/spinlock.h> -+#include <linux/vmalloc.h> -+#include <linux/random.h> -+ -+#include <net/ip.h> -+ -+#include <linux/netfilter_ipv4/ip_set_malloc.h> -+#include <linux/netfilter_ipv4/ip_set_iphash.h> -+#include <linux/netfilter_ipv4/ip_set_jhash.h> -+#include <linux/netfilter_ipv4/ip_set_prime.h> -+ -+static inline __u32 -+jhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip) -+{ -+ return jhash_1word(ip, map->initval); -+} -+ -+static inline __u32 -+randhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip) -+{ -+ return (1 + ip % map->prime); -+} -+ -+static inline __u32 -+hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data; -+ __u32 jhash, randhash, id; -+ u_int16_t i; -+ -+ *hash_ip = ip & map->netmask; -+ jhash = jhash_ip(map, *hash_ip); -+ randhash = randhash_ip(map, *hash_ip); -+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u", -+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask)); -+ -+ for (i = 0; i < map->probes; i++) { -+ id = (jhash + i * randhash) % map->hashsize; -+ DP("hash key: %u", id); -+ if (map->members[id] == *hash_ip) -+ return id; -+ /* No shortcut at testing - there can be deleted -+ * entries. */ -+ } -+ return UINT_MAX; -+} -+ -+static inline int -+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ return (hash_id(set, ip, hash_ip) != UINT_MAX); -+} -+ -+static int -+testip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_iphash *req = -+ (struct ip_set_req_iphash *) data; -+ -+ if (size != sizeof(struct ip_set_req_iphash)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_iphash), -+ size); -+ return -EINVAL; -+ } -+ return __testip(set, req->ip, hash_ip); -+} -+ -+static int -+testip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ return __testip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+} -+ -+static inline int -+__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ __u32 jhash, randhash, probe; -+ u_int16_t i; -+ -+ *hash_ip = ip & map->netmask; -+ jhash = jhash_ip(map, *hash_ip); -+ randhash = randhash_ip(map, *hash_ip); -+ -+ for (i = 0; i < map->probes; i++) { -+ probe = (jhash + i * randhash) % map->hashsize; -+ if (map->members[probe] == *hash_ip) -+ return -EEXIST; -+ if (!map->members[probe]) { -+ map->members[probe] = *hash_ip; -+ return 0; -+ } -+ } -+ /* Trigger rehashing */ -+ return -EAGAIN; -+} -+ -+static int -+addip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_iphash *req = -+ (struct ip_set_req_iphash *) data; -+ -+ if (size != sizeof(struct ip_set_req_iphash)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_iphash), -+ size); -+ return -EINVAL; -+ } -+ return __addip((struct ip_set_iphash *) set->data, req->ip, hash_ip); -+} -+ -+static int -+addip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ return __addip((struct ip_set_iphash *) set->data, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+} -+ -+static int retry(struct ip_set *set) -+{ -+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data; -+ ip_set_ip_t hash_ip, *members; -+ u_int32_t i, hashsize; -+ unsigned newbytes; -+ int res; -+ struct ip_set_iphash tmp = { -+ .hashsize = map->hashsize, -+ .probes = map->probes, -+ .resize = map->resize, -+ .netmask = map->netmask, -+ }; -+ -+ if (map->resize == 0) -+ return -ERANGE; -+ -+ again: -+ res = 0; -+ -+ /* Calculate new parameters */ -+ get_random_bytes(&tmp.initval, 4); -+ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100; -+ if (hashsize == tmp.hashsize) -+ hashsize++; -+ tmp.prime = make_prime(hashsize); -+ -+ ip_set_printk("rehashing of set %s triggered: " -+ "hashsize grows from %u to %u", -+ set->name, tmp.hashsize, hashsize); -+ tmp.hashsize = hashsize; -+ -+ newbytes = hashsize * sizeof(ip_set_ip_t); -+ tmp.members = ip_set_malloc(newbytes); -+ if (!tmp.members) { -+ DP("out of memory for %d bytes", newbytes); -+ return -ENOMEM; -+ } -+ memset(tmp.members, 0, newbytes); -+ -+ write_lock_bh(&set->lock); -+ map = (struct ip_set_iphash *) set->data; /* Play safe */ -+ for (i = 0; i < map->hashsize && res == 0; i++) { -+ if (map->members[i]) -+ res = __addip(&tmp, map->members[i], &hash_ip); -+ } -+ if (res) { -+ /* Failure, try again */ -+ write_unlock_bh(&set->lock); -+ ip_set_free(tmp.members, newbytes); -+ goto again; -+ } -+ -+ /* Success at resizing! */ -+ members = map->members; -+ hashsize = map->hashsize; -+ -+ map->initval = tmp.initval; -+ map->prime = tmp.prime; -+ map->hashsize = tmp.hashsize; -+ map->members = tmp.members; -+ write_unlock_bh(&set->lock); -+ -+ ip_set_free(members, hashsize * sizeof(ip_set_ip_t)); -+ -+ return 0; -+} -+ -+static inline int -+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data; -+ ip_set_ip_t id = hash_id(set, ip, hash_ip); -+ -+ if (id == UINT_MAX) -+ return -EEXIST; -+ -+ map->members[id] = 0; -+ return 0; -+} -+ -+static int -+delip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_iphash *req = -+ (struct ip_set_req_iphash *) data; -+ -+ if (size != sizeof(struct ip_set_req_iphash)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_iphash), -+ size); -+ return -EINVAL; -+ } -+ return __delip(set, req->ip, hash_ip); -+} -+ -+static int -+delip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ return __delip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+} -+ -+static int create(struct ip_set *set, const void *data, size_t size) -+{ -+ unsigned newbytes; -+ struct ip_set_req_iphash_create *req = -+ (struct ip_set_req_iphash_create *) data; -+ struct ip_set_iphash *map; -+ -+ if (size != sizeof(struct ip_set_req_iphash_create)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_iphash_create), -+ size); -+ return -EINVAL; -+ } -+ -+ if (req->hashsize < 1) { -+ ip_set_printk("hashsize too small"); -+ return -ENOEXEC; -+ } -+ -+ map = kmalloc(sizeof(struct ip_set_iphash), GFP_KERNEL); -+ if (!map) { -+ DP("out of memory for %d bytes", -+ sizeof(struct ip_set_iphash)); -+ return -ENOMEM; -+ } -+ get_random_bytes(&map->initval, 4); -+ map->prime = make_prime(req->hashsize); -+ map->hashsize = req->hashsize; -+ map->probes = req->probes; -+ map->resize = req->resize; -+ map->netmask = req->netmask; -+ newbytes = map->hashsize * sizeof(ip_set_ip_t); -+ map->members = ip_set_malloc(newbytes); -+ if (!map->members) { -+ DP("out of memory for %d bytes", newbytes); -+ kfree(map); -+ return -ENOMEM; -+ } -+ memset(map->members, 0, newbytes); -+ -+ set->data = map; -+ return 0; -+} -+ -+static void destroy(struct ip_set *set) -+{ -+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data; -+ -+ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t)); -+ kfree(map); -+ -+ set->data = NULL; -+} -+ -+static void flush(struct ip_set *set) -+{ -+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data; -+ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t)); -+} -+ -+static void list_header(const struct ip_set *set, void *data) -+{ -+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data; -+ struct ip_set_req_iphash_create *header = -+ (struct ip_set_req_iphash_create *) data; -+ -+ header->hashsize = map->hashsize; -+ header->probes = map->probes; -+ header->resize = map->resize; -+ header->netmask = map->netmask; -+} -+ -+static int list_members_size(const struct ip_set *set) -+{ -+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data; -+ -+ return (map->hashsize * sizeof(ip_set_ip_t)); -+} -+ -+static void list_members(const struct ip_set *set, void *data) -+{ -+ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data; -+ int bytes = map->hashsize * sizeof(ip_set_ip_t); -+ -+ memcpy(data, map->members, bytes); -+} -+ -+static struct ip_set_type ip_set_iphash = { -+ .typename = SETTYPE_NAME, -+ .typecode = IPSET_TYPE_IP, -+ .protocol_version = IP_SET_PROTOCOL_VERSION, -+ .create = &create, -+ .destroy = &destroy, -+ .flush = &flush, -+ .reqsize = sizeof(struct ip_set_req_iphash), -+ .addip = &addip, -+ .addip_kernel = &addip_kernel, -+ .retry = &retry, -+ .delip = &delip, -+ .delip_kernel = &delip_kernel, -+ .testip = &testip, -+ .testip_kernel = &testip_kernel, -+ .header_size = sizeof(struct ip_set_req_iphash_create), -+ .list_header = &list_header, -+ .list_members_size = &list_members_size, -+ .list_members = &list_members, -+ .me = THIS_MODULE, -+}; -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -+MODULE_DESCRIPTION("iphash type of IP sets"); -+ -+static int __init init(void) -+{ -+ return ip_set_register_set_type(&ip_set_iphash); -+} -+ -+static void __exit fini(void) -+{ -+ /* FIXME: possible race with ip_set_create() */ -+ ip_set_unregister_set_type(&ip_set_iphash); -+} -+ -+module_init(init); -+module_exit(fini); -diff -Naur linux-old/net/ipv4/netfilter/ip_set_ipmap.c linux-new/net/ipv4/netfilter/ip_set_ipmap.c ---- linux-old/net/ipv4/netfilter/ip_set_ipmap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/net/ipv4/netfilter/ip_set_ipmap.c 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,314 @@ -+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> -+ * Patrick Schaaf <bof@bof.de> -+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* Kernel module implementing an IP set type: the single bitmap type */ -+ -+#include <linux/module.h> -+#include <linux/ip.h> -+#include <linux/skbuff.h> -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ip_set.h> -+#include <linux/errno.h> -+#include <asm/uaccess.h> -+#include <asm/bitops.h> -+#include <asm/softirq.h> -+#include <linux/spinlock.h> -+ -+#include <linux/netfilter_ipv4/ip_set_ipmap.h> -+ -+static inline ip_set_ip_t -+ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip) -+{ -+ return (ip - map->first_ip)/map->hosts; -+} -+ -+static inline int -+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data; -+ -+ if (ip < map->first_ip || ip > map->last_ip) -+ return -ERANGE; -+ -+ *hash_ip = ip & map->netmask; -+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u", -+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip)); -+ return !!test_bit(ip_to_id(map, *hash_ip), map->members); -+} -+ -+static int -+testip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_ipmap *req = -+ (struct ip_set_req_ipmap *) data; -+ -+ if (size != sizeof(struct ip_set_req_ipmap)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_ipmap), -+ size); -+ return -EINVAL; -+ } -+ return __testip(set, req->ip, hash_ip); -+} -+ -+static int -+testip_kernel(struct ip_set *set, -+ const struct sk_buff *skb, -+ u_int32_t flags, -+ ip_set_ip_t *hash_ip) -+{ -+ int res; -+ -+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u", -+ flags & IPSET_SRC ? "SRC" : "DST", -+ NIPQUAD(skb->nh.iph->saddr), -+ NIPQUAD(skb->nh.iph->daddr)); -+ -+ res = __testip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+ return (res < 0 ? 0 : res); -+} -+ -+static inline int -+__addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data; -+ -+ if (ip < map->first_ip || ip > map->last_ip) -+ return -ERANGE; -+ -+ *hash_ip = ip & map->netmask; -+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); -+ if (test_and_set_bit(ip_to_id(map, *hash_ip), map->members)) -+ return -EEXIST; -+ -+ return 0; -+} -+ -+static int -+addip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_ipmap *req = -+ (struct ip_set_req_ipmap *) data; -+ -+ if (size != sizeof(struct ip_set_req_ipmap)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_ipmap), -+ size); -+ return -EINVAL; -+ } -+ DP("%u.%u.%u.%u", HIPQUAD(req->ip)); -+ return __addip(set, req->ip, hash_ip); -+} -+ -+static int -+addip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ return __addip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+} -+ -+static inline int -+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data; -+ -+ if (ip < map->first_ip || ip > map->last_ip) -+ return -ERANGE; -+ -+ *hash_ip = ip & map->netmask; -+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); -+ if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members)) -+ return -EEXIST; -+ -+ return 0; -+} -+ -+static int -+delip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_ipmap *req = -+ (struct ip_set_req_ipmap *) data; -+ -+ if (size != sizeof(struct ip_set_req_ipmap)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_ipmap), -+ size); -+ return -EINVAL; -+ } -+ return __delip(set, req->ip, hash_ip); -+} -+ -+static int -+delip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ return __delip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+} -+ -+static int create(struct ip_set *set, const void *data, size_t size) -+{ -+ int newbytes; -+ struct ip_set_req_ipmap_create *req = -+ (struct ip_set_req_ipmap_create *) data; -+ struct ip_set_ipmap *map; -+ -+ if (size != sizeof(struct ip_set_req_ipmap_create)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_ipmap_create), -+ size); -+ return -EINVAL; -+ } -+ -+ DP("from %u.%u.%u.%u to %u.%u.%u.%u", -+ HIPQUAD(req->from), HIPQUAD(req->to)); -+ -+ if (req->from > req->to) { -+ DP("bad ip range"); -+ return -ENOEXEC; -+ } -+ -+ if (req->to - req->from > MAX_RANGE) { -+ ip_set_printk("range too big (max %d addresses)", -+ MAX_RANGE); -+ return -ENOEXEC; -+ } -+ -+ map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL); -+ if (!map) { -+ DP("out of memory for %d bytes", -+ sizeof(struct ip_set_ipmap)); -+ return -ENOMEM; -+ } -+ map->first_ip = req->from; -+ map->last_ip = req->to; -+ map->netmask = req->netmask; -+ -+ if (req->netmask == 0xFFFFFFFF) { -+ map->hosts = 1; -+ map->sizeid = map->last_ip - map->first_ip + 1; -+ } else { -+ unsigned int mask_bits, netmask_bits; -+ ip_set_ip_t mask; -+ -+ map->first_ip &= map->netmask; /* Should we better bark? */ -+ -+ mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits); -+ netmask_bits = mask_to_bits(map->netmask); -+ -+ if (!mask || netmask_bits <= mask_bits) -+ return -ENOEXEC; -+ -+ map->hosts = 2 << (32 - netmask_bits - 1); -+ map->sizeid = 2 << (netmask_bits - mask_bits - 1); -+ } -+ newbytes = bitmap_bytes(0, map->sizeid - 1); -+ map->members = kmalloc(newbytes, GFP_KERNEL); -+ if (!map->members) { -+ DP("out of memory for %d bytes", newbytes); -+ kfree(map); -+ return -ENOMEM; -+ } -+ memset(map->members, 0, newbytes); -+ -+ set->data = map; -+ return 0; -+} -+ -+static void destroy(struct ip_set *set) -+{ -+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data; -+ -+ kfree(map->members); -+ kfree(map); -+ -+ set->data = NULL; -+} -+ -+static void flush(struct ip_set *set) -+{ -+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data; -+ memset(map->members, 0, bitmap_bytes(0, map->sizeid - 1)); -+} -+ -+static void list_header(const struct ip_set *set, void *data) -+{ -+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data; -+ struct ip_set_req_ipmap_create *header = -+ (struct ip_set_req_ipmap_create *) data; -+ -+ header->from = map->first_ip; -+ header->to = map->last_ip; -+ header->netmask = map->netmask; -+} -+ -+static int list_members_size(const struct ip_set *set) -+{ -+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data; -+ -+ return bitmap_bytes(0, map->sizeid - 1); -+} -+ -+static void list_members(const struct ip_set *set, void *data) -+{ -+ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data; -+ int bytes = bitmap_bytes(0, map->sizeid - 1); -+ -+ memcpy(data, map->members, bytes); -+} -+ -+static struct ip_set_type ip_set_ipmap = { -+ .typename = SETTYPE_NAME, -+ .typecode = IPSET_TYPE_IP, -+ .protocol_version = IP_SET_PROTOCOL_VERSION, -+ .create = &create, -+ .destroy = &destroy, -+ .flush = &flush, -+ .reqsize = sizeof(struct ip_set_req_ipmap), -+ .addip = &addip, -+ .addip_kernel = &addip_kernel, -+ .delip = &delip, -+ .delip_kernel = &delip_kernel, -+ .testip = &testip, -+ .testip_kernel = &testip_kernel, -+ .header_size = sizeof(struct ip_set_req_ipmap_create), -+ .list_header = &list_header, -+ .list_members_size = &list_members_size, -+ .list_members = &list_members, -+ .me = THIS_MODULE, -+}; -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -+MODULE_DESCRIPTION("ipmap type of IP sets"); -+ -+static int __init init(void) -+{ -+ return ip_set_register_set_type(&ip_set_ipmap); -+} -+ -+static void __exit fini(void) -+{ -+ /* FIXME: possible race with ip_set_create() */ -+ ip_set_unregister_set_type(&ip_set_ipmap); -+} -+ -+module_init(init); -+module_exit(fini); -diff -Naur linux-old/net/ipv4/netfilter/ip_set_iptree.c linux-new/net/ipv4/netfilter/ip_set_iptree.c ---- linux-old/net/ipv4/netfilter/ip_set_iptree.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/net/ipv4/netfilter/ip_set_iptree.c 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,511 @@ -+/* Copyright (C) 2005 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* Kernel module implementing an IP set type: the iptree type */ -+ -+#include <linux/module.h> -+#include <linux/ip.h> -+#include <linux/skbuff.h> -+#include <linux/slab.h> -+#include <linux/delay.h> -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ip_set.h> -+#include <linux/errno.h> -+#include <asm/uaccess.h> -+#include <asm/bitops.h> -+#include <linux/interrupt.h> -+#include <linux/spinlock.h> -+ -+#include <linux/netfilter_ipv4/ip_set_iptree.h> -+ -+/* Garbage collection interval in seconds: */ -+#define IPTREE_GC_TIME 5*60 -+/* Sleep so many milliseconds before trying again -+ * to delete the gc timer at destroying a set */ -+#define IPTREE_DESTROY_SLEEP 100 -+ -+static kmem_cache_t *branch_cachep; -+static kmem_cache_t *leaf_cachep; -+ -+#define ABCD(a,b,c,d,addrp) do { \ -+ a = ((unsigned char *)addrp)[3]; \ -+ b = ((unsigned char *)addrp)[2]; \ -+ c = ((unsigned char *)addrp)[1]; \ -+ d = ((unsigned char *)addrp)[0]; \ -+} while (0) -+ -+#define TESTIP_WALK(map, elem, branch) do { \ -+ if ((map)->tree[elem]) { \ -+ branch = (map)->tree[elem]; \ -+ } else \ -+ return 0; \ -+} while (0) -+ -+static inline int -+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ struct ip_set_iptreeb *btree; -+ struct ip_set_iptreec *ctree; -+ struct ip_set_iptreed *dtree; -+ unsigned char a,b,c,d; -+ -+ *hash_ip = ip; -+ ABCD(a, b, c, d, hash_ip); -+ DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout); -+ TESTIP_WALK(map, a, btree); -+ TESTIP_WALK(btree, b, ctree); -+ TESTIP_WALK(ctree, c, dtree); -+ DP("%lu %lu", dtree->expires[d], jiffies); -+ return !!(map->timeout ? (time_after(dtree->expires[d], jiffies)) -+ : dtree->expires[d]); -+} -+ -+static int -+testip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_iptree *req = -+ (struct ip_set_req_iptree *) data; -+ -+ if (size != sizeof(struct ip_set_req_iptree)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_iptree), -+ size); -+ return -EINVAL; -+ } -+ return __testip(set, req->ip, hash_ip); -+} -+ -+static int -+testip_kernel(struct ip_set *set, -+ const struct sk_buff *skb, -+ u_int32_t flags, -+ ip_set_ip_t *hash_ip) -+{ -+ int res; -+ -+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u", -+ flags & IPSET_SRC ? "SRC" : "DST", -+ NIPQUAD(skb->nh.iph->saddr), -+ NIPQUAD(skb->nh.iph->daddr)); -+ -+ res = __testip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+ return (res < 0 ? 0 : res); -+} -+ -+#define ADDIP_WALK(map, elem, branch, type, cachep) do { \ -+ if ((map)->tree[elem]) { \ -+ DP("found %u", elem); \ -+ branch = (map)->tree[elem]; \ -+ } else { \ -+ branch = (type *) \ -+ kmem_cache_alloc(cachep, GFP_KERNEL); \ -+ if (branch == NULL) \ -+ return -ENOMEM; \ -+ memset(branch, 0, sizeof(*branch)); \ -+ (map)->tree[elem] = branch; \ -+ DP("alloc %u", elem); \ -+ } \ -+} while (0) -+ -+static inline int -+__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ struct ip_set_iptreeb *btree; -+ struct ip_set_iptreec *ctree; -+ struct ip_set_iptreed *dtree; -+ unsigned char a,b,c,d; -+ int ret = 0; -+ -+ *hash_ip = ip; -+ ABCD(a, b, c, d, hash_ip); -+ DP("%u %u %u %u timeout %u", a, b, c, d, timeout); -+ ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep); -+ ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep); -+ ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreed, leaf_cachep); -+ if (dtree->expires[d] -+ && (!map->timeout || time_after(dtree->expires[d], jiffies))) -+ ret = -EEXIST; -+ dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1; -+ DP("%u %lu", d, dtree->expires[d]); -+ return ret; -+} -+ -+static int -+addip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ struct ip_set_req_iptree *req = -+ (struct ip_set_req_iptree *) data; -+ -+ if (size != sizeof(struct ip_set_req_iptree)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_iptree), -+ size); -+ return -EINVAL; -+ } -+ DP("%u.%u.%u.%u %u", HIPQUAD(req->ip), req->timeout); -+ return __addip(set, req->ip, -+ req->timeout ? req->timeout : map->timeout, -+ hash_ip); -+} -+ -+static int -+addip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ -+ return __addip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ map->timeout, -+ hash_ip); -+} -+ -+#define DELIP_WALK(map, elem, branch) do { \ -+ if ((map)->tree[elem]) { \ -+ branch = (map)->tree[elem]; \ -+ } else \ -+ return -EEXIST; \ -+} while (0) -+ -+static inline int -+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ struct ip_set_iptreeb *btree; -+ struct ip_set_iptreec *ctree; -+ struct ip_set_iptreed *dtree; -+ unsigned char a,b,c,d; -+ -+ *hash_ip = ip; -+ ABCD(a, b, c, d, hash_ip); -+ DELIP_WALK(map, a, btree); -+ DELIP_WALK(btree, b, ctree); -+ DELIP_WALK(ctree, c, dtree); -+ -+ if (dtree->expires[d]) { -+ dtree->expires[d] = 0; -+ return 0; -+ } -+ return -EEXIST; -+} -+ -+static int -+delip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_iptree *req = -+ (struct ip_set_req_iptree *) data; -+ -+ if (size != sizeof(struct ip_set_req_iptree)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_iptree), -+ size); -+ return -EINVAL; -+ } -+ return __delip(set, req->ip, hash_ip); -+} -+ -+static int -+delip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ return __delip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+} -+ -+#define LOOP_WALK_BEGIN(map, i, branch) \ -+ for (i = 0; i < 255; i++) { \ -+ if (!(map)->tree[i]) \ -+ continue; \ -+ branch = (map)->tree[i] -+ -+#define LOOP_WALK_END } -+ -+static void ip_tree_gc(unsigned long ul_set) -+{ -+ struct ip_set *set = (void *) ul_set; -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ struct ip_set_iptreeb *btree; -+ struct ip_set_iptreec *ctree; -+ struct ip_set_iptreed *dtree; -+ unsigned char a,b,c,d; -+ unsigned char i,j,k; -+ -+ i = j = k = 0; -+ DP("gc: %s", set->name); -+ write_lock_bh(&set->lock); -+ LOOP_WALK_BEGIN(map, a, btree); -+ LOOP_WALK_BEGIN(btree, b, ctree); -+ LOOP_WALK_BEGIN(ctree, c, dtree); -+ for (d = 0; d < 255; d++) { -+ if (dtree->expires[d]) { -+ DP("gc: %u %u %u %u: expires %lu jiffies %lu", -+ a, b, c, d, -+ dtree->expires[d], jiffies); -+ if (map->timeout -+ && time_before(dtree->expires[d], jiffies)) -+ dtree->expires[d] = 0; -+ else -+ k = 1; -+ } -+ } -+ if (k == 0) { -+ DP("gc: %s: leaf %u %u %u empty", -+ set->name, a, b, c); -+ kmem_cache_free(leaf_cachep, dtree); -+ ctree->tree[c] = NULL; -+ } else { -+ DP("gc: %s: leaf %u %u %u not empty", -+ set->name, a, b, c); -+ j = 1; -+ k = 0; -+ } -+ LOOP_WALK_END; -+ if (j == 0) { -+ DP("gc: %s: branch %u %u empty", -+ set->name, a, b); -+ kmem_cache_free(branch_cachep, ctree); -+ btree->tree[b] = NULL; -+ } else { -+ DP("gc: %s: branch %u %u not empty", -+ set->name, a, b); -+ i = 1; -+ j = k = 0; -+ } -+ LOOP_WALK_END; -+ if (i == 0) { -+ DP("gc: %s: branch %u empty", -+ set->name, a); -+ kmem_cache_free(branch_cachep, btree); -+ map->tree[a] = NULL; -+ } else { -+ DP("gc: %s: branch %u not empty", -+ set->name, a); -+ i = j = k = 0; -+ } -+ LOOP_WALK_END; -+ write_unlock_bh(&set->lock); -+ -+ map->gc.expires = jiffies + map->gc_interval * HZ; -+ add_timer(&map->gc); -+} -+ -+static int create(struct ip_set *set, const void *data, size_t size) -+{ -+ struct ip_set_req_iptree_create *req = -+ (struct ip_set_req_iptree_create *) data; -+ struct ip_set_iptree *map; -+ -+ if (size != sizeof(struct ip_set_req_iptree_create)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_iptree_create), -+ size); -+ return -EINVAL; -+ } -+ -+ map = kmalloc(sizeof(struct ip_set_iptree), GFP_KERNEL); -+ if (!map) { -+ DP("out of memory for %d bytes", -+ sizeof(struct ip_set_iptree)); -+ return -ENOMEM; -+ } -+ memset(map, 0, sizeof(*map)); -+ map->timeout = req->timeout; -+ set->data = map; -+ -+ /* If there is no timeout for the entries, -+ * we still have to call gc because delete -+ * do not clean up empty branches */ -+ map->gc_interval = IPTREE_GC_TIME; -+ init_timer(&map->gc); -+ map->gc.data = (unsigned long) set; -+ map->gc.function = ip_tree_gc; -+ map->gc.expires = jiffies + map->gc_interval * HZ; -+ add_timer(&map->gc); -+ -+ return 0; -+} -+ -+static void __flush(struct ip_set_iptree *map) -+{ -+ struct ip_set_iptreeb *btree; -+ struct ip_set_iptreec *ctree; -+ struct ip_set_iptreed *dtree; -+ unsigned int a,b,c; -+ -+ LOOP_WALK_BEGIN(map, a, btree); -+ LOOP_WALK_BEGIN(btree, b, ctree); -+ LOOP_WALK_BEGIN(ctree, c, dtree); -+ kmem_cache_free(leaf_cachep, dtree); -+ LOOP_WALK_END; -+ kmem_cache_free(branch_cachep, ctree); -+ LOOP_WALK_END; -+ kmem_cache_free(branch_cachep, btree); -+ LOOP_WALK_END; -+} -+ -+static void destroy(struct ip_set *set) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ -+ while (!del_timer(&map->gc)) -+ msleep(IPTREE_DESTROY_SLEEP); -+ __flush(map); -+ kfree(map); -+ set->data = NULL; -+} -+ -+static void flush(struct ip_set *set) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ unsigned int timeout = map->timeout; -+ -+ __flush(map); -+ memset(map, 0, sizeof(*map)); -+ map->timeout = timeout; -+} -+ -+static void list_header(const struct ip_set *set, void *data) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ struct ip_set_req_iptree_create *header = -+ (struct ip_set_req_iptree_create *) data; -+ -+ header->timeout = map->timeout; -+} -+ -+static int list_members_size(const struct ip_set *set) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ struct ip_set_iptreeb *btree; -+ struct ip_set_iptreec *ctree; -+ struct ip_set_iptreed *dtree; -+ unsigned char a,b,c,d; -+ unsigned int count = 0; -+ -+ LOOP_WALK_BEGIN(map, a, btree); -+ LOOP_WALK_BEGIN(btree, b, ctree); -+ LOOP_WALK_BEGIN(ctree, c, dtree); -+ for (d = 0; d < 255; d++) { -+ if (dtree->expires[d] -+ && (!map->timeout || time_after(dtree->expires[d], jiffies))) -+ count++; -+ } -+ LOOP_WALK_END; -+ LOOP_WALK_END; -+ LOOP_WALK_END; -+ -+ DP("members %u", count); -+ return (count * sizeof(struct ip_set_req_iptree)); -+} -+ -+static void list_members(const struct ip_set *set, void *data) -+{ -+ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data; -+ struct ip_set_iptreeb *btree; -+ struct ip_set_iptreec *ctree; -+ struct ip_set_iptreed *dtree; -+ unsigned char a,b,c,d; -+ size_t offset = 0; -+ struct ip_set_req_iptree *entry; -+ -+ LOOP_WALK_BEGIN(map, a, btree); -+ LOOP_WALK_BEGIN(btree, b, ctree); -+ LOOP_WALK_BEGIN(ctree, c, dtree); -+ for (d = 0; d < 255; d++) { -+ if (dtree->expires[d] -+ && (!map->timeout || time_after(dtree->expires[d], jiffies))) { -+ entry = (struct ip_set_req_iptree *)(data + offset); -+ entry->ip = ((a << 24) | (b << 16) | (c << 8) | d); -+ entry->timeout = !map->timeout ? 0 -+ : (dtree->expires[d] - jiffies)/HZ; -+ offset += sizeof(struct ip_set_req_iptree); -+ } -+ } -+ LOOP_WALK_END; -+ LOOP_WALK_END; -+ LOOP_WALK_END; -+} -+ -+static struct ip_set_type ip_set_iptree = { -+ .typename = SETTYPE_NAME, -+ .typecode = IPSET_TYPE_IP, -+ .protocol_version = IP_SET_PROTOCOL_VERSION, -+ .create = &create, -+ .destroy = &destroy, -+ .flush = &flush, -+ .reqsize = sizeof(struct ip_set_req_iptree), -+ .addip = &addip, -+ .addip_kernel = &addip_kernel, -+ .delip = &delip, -+ .delip_kernel = &delip_kernel, -+ .testip = &testip, -+ .testip_kernel = &testip_kernel, -+ .header_size = sizeof(struct ip_set_req_iptree_create), -+ .list_header = &list_header, -+ .list_members_size = &list_members_size, -+ .list_members = &list_members, -+ .me = THIS_MODULE, -+}; -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -+MODULE_DESCRIPTION("iptree type of IP sets"); -+ -+static int __init init(void) -+{ -+ int ret; -+ -+ branch_cachep = kmem_cache_create("ip_set_iptreeb", -+ sizeof(struct ip_set_iptreeb), -+ 0, 0, NULL, NULL); -+ if (!branch_cachep) { -+ printk(KERN_ERR "Unable to create ip_set_iptreeb slab cache\n"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ leaf_cachep = kmem_cache_create("ip_set_iptreed", -+ sizeof(struct ip_set_iptreed), -+ 0, 0, NULL, NULL); -+ if (!leaf_cachep) { -+ printk(KERN_ERR "Unable to create ip_set_iptreed slab cache\n"); -+ ret = -ENOMEM; -+ goto free_branch; -+ } -+ ret = ip_set_register_set_type(&ip_set_iptree); -+ if (ret == 0) -+ goto out; -+ -+ kmem_cache_destroy(leaf_cachep); -+ free_branch: -+ kmem_cache_destroy(branch_cachep); -+ out: -+ return ret; -+} -+ -+static void __exit fini(void) -+{ -+ /* FIXME: possible race with ip_set_create() */ -+ ip_set_unregister_set_type(&ip_set_iptree); -+ kmem_cache_destroy(leaf_cachep); -+ kmem_cache_destroy(branch_cachep); -+} -+ -+module_init(init); -+module_exit(fini); -diff -Naur linux-old/net/ipv4/netfilter/ip_set_macipmap.c linux-new/net/ipv4/netfilter/ip_set_macipmap.c ---- linux-old/net/ipv4/netfilter/ip_set_macipmap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/net/ipv4/netfilter/ip_set_macipmap.c 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,340 @@ -+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> -+ * Patrick Schaaf <bof@bof.de> -+ * Martin Josefsson <gandalf@wlug.westbo.se> -+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* Kernel module implementing an IP set type: the macipmap type */ -+ -+#include <linux/module.h> -+#include <linux/ip.h> -+#include <linux/skbuff.h> -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ip_set.h> -+#include <linux/errno.h> -+#include <asm/uaccess.h> -+#include <asm/bitops.h> -+#include <asm/softirq.h> -+#include <linux/spinlock.h> -+#include <linux/if_ether.h> -+#include <linux/vmalloc.h> -+ -+#include <linux/netfilter_ipv4/ip_set_malloc.h> -+#include <linux/netfilter_ipv4/ip_set_macipmap.h> -+ -+static int -+testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_macipmap *map = (struct ip_set_macipmap *) set->data; -+ struct ip_set_macip *table = (struct ip_set_macip *) map->members; -+ struct ip_set_req_macipmap *req = (struct ip_set_req_macipmap *) data; -+ -+ if (size != sizeof(struct ip_set_req_macipmap)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_macipmap), -+ size); -+ return -EINVAL; -+ } -+ -+ if (req->ip < map->first_ip || req->ip > map->last_ip) -+ return -ERANGE; -+ -+ *hash_ip = req->ip; -+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u", -+ set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip)); -+ if (test_bit(IPSET_MACIP_ISSET, -+ &table[req->ip - map->first_ip].flags)) { -+ return (memcmp(req->ethernet, -+ &table[req->ip - map->first_ip].ethernet, -+ ETH_ALEN) == 0); -+ } else { -+ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0); -+ } -+} -+ -+static int -+testip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_macipmap *map = -+ (struct ip_set_macipmap *) set->data; -+ struct ip_set_macip *table = -+ (struct ip_set_macip *) map->members; -+ ip_set_ip_t ip; -+ -+ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr); -+ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u", -+ flags & IPSET_SRC ? "SRC" : "DST", -+ NIPQUAD(skb->nh.iph->saddr), -+ NIPQUAD(skb->nh.iph->daddr)); -+ -+ if (ip < map->first_ip || ip > map->last_ip) -+ return 0; -+ -+ *hash_ip = ip; -+ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u", -+ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip)); -+ if (test_bit(IPSET_MACIP_ISSET, &table[ip - map->first_ip].flags)) { -+ /* Is mac pointer valid? -+ * If so, compare... */ -+ return (skb->mac.raw >= skb->head -+ && (skb->mac.raw + ETH_HLEN) <= skb->data -+ && (memcmp(skb->mac.ethernet->h_source, -+ &table[ip - map->first_ip].ethernet, -+ ETH_ALEN) == 0)); -+ } else { -+ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0); -+ } -+} -+ -+/* returns 0 on success */ -+static inline int -+__addip(struct ip_set *set, -+ ip_set_ip_t ip, unsigned char *ethernet, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_macipmap *map = -+ (struct ip_set_macipmap *) set->data; -+ struct ip_set_macip *table = -+ (struct ip_set_macip *) map->members; -+ -+ if (ip < map->first_ip || ip > map->last_ip) -+ return -ERANGE; -+ if (test_and_set_bit(IPSET_MACIP_ISSET, -+ &table[ip - map->first_ip].flags)) -+ return -EEXIST; -+ -+ *hash_ip = ip; -+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); -+ memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN); -+ return 0; -+} -+ -+static int -+addip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_macipmap *req = -+ (struct ip_set_req_macipmap *) data; -+ -+ if (size != sizeof(struct ip_set_req_macipmap)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_macipmap), -+ size); -+ return -EINVAL; -+ } -+ return __addip(set, req->ip, req->ethernet, hash_ip); -+} -+ -+static int -+addip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ ip_set_ip_t ip; -+ -+ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr); -+ -+ if (!(skb->mac.raw >= skb->head -+ && (skb->mac.raw + ETH_HLEN) <= skb->data)) -+ return -EINVAL; -+ -+ return __addip(set, ip, skb->mac.ethernet->h_source, hash_ip); -+} -+ -+static inline int -+__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_macipmap *map = -+ (struct ip_set_macipmap *) set->data; -+ struct ip_set_macip *table = -+ (struct ip_set_macip *) map->members; -+ -+ if (ip < map->first_ip || ip > map->last_ip) -+ return -ERANGE; -+ if (!test_and_clear_bit(IPSET_MACIP_ISSET, -+ &table[ip - map->first_ip].flags)) -+ return -EEXIST; -+ -+ *hash_ip = ip; -+ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); -+ return 0; -+} -+ -+static int -+delip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_macipmap *req = -+ (struct ip_set_req_macipmap *) data; -+ -+ if (size != sizeof(struct ip_set_req_macipmap)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_macipmap), -+ size); -+ return -EINVAL; -+ } -+ return __delip(set, req->ip, hash_ip); -+} -+ -+static int -+delip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ return __delip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+} -+ -+static inline size_t members_size(ip_set_id_t from, ip_set_id_t to) -+{ -+ return (size_t)((to - from + 1) * sizeof(struct ip_set_macip)); -+} -+ -+static int create(struct ip_set *set, const void *data, size_t size) -+{ -+ int newbytes; -+ struct ip_set_req_macipmap_create *req = -+ (struct ip_set_req_macipmap_create *) data; -+ struct ip_set_macipmap *map; -+ -+ if (size != sizeof(struct ip_set_req_macipmap_create)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_macipmap_create), -+ size); -+ return -EINVAL; -+ } -+ -+ DP("from %u.%u.%u.%u to %u.%u.%u.%u", -+ HIPQUAD(req->from), HIPQUAD(req->to)); -+ -+ if (req->from > req->to) { -+ DP("bad ip range"); -+ return -ENOEXEC; -+ } -+ -+ if (req->to - req->from > MAX_RANGE) { -+ ip_set_printk("range too big (max %d addresses)", -+ MAX_RANGE); -+ return -ENOEXEC; -+ } -+ -+ map = kmalloc(sizeof(struct ip_set_macipmap), GFP_KERNEL); -+ if (!map) { -+ DP("out of memory for %d bytes", -+ sizeof(struct ip_set_macipmap)); -+ return -ENOMEM; -+ } -+ map->flags = req->flags; -+ map->first_ip = req->from; -+ map->last_ip = req->to; -+ newbytes = members_size(map->first_ip, map->last_ip); -+ map->members = ip_set_malloc(newbytes); -+ DP("members: %u %p", newbytes, map->members); -+ if (!map->members) { -+ DP("out of memory for %d bytes", newbytes); -+ kfree(map); -+ return -ENOMEM; -+ } -+ memset(map->members, 0, newbytes); -+ -+ set->data = map; -+ return 0; -+} -+ -+static void destroy(struct ip_set *set) -+{ -+ struct ip_set_macipmap *map = -+ (struct ip_set_macipmap *) set->data; -+ -+ ip_set_free(map->members, members_size(map->first_ip, map->last_ip)); -+ kfree(map); -+ -+ set->data = NULL; -+} -+ -+static void flush(struct ip_set *set) -+{ -+ struct ip_set_macipmap *map = -+ (struct ip_set_macipmap *) set->data; -+ memset(map->members, 0, members_size(map->first_ip, map->last_ip)); -+} -+ -+static void list_header(const struct ip_set *set, void *data) -+{ -+ struct ip_set_macipmap *map = -+ (struct ip_set_macipmap *) set->data; -+ struct ip_set_req_macipmap_create *header = -+ (struct ip_set_req_macipmap_create *) data; -+ -+ DP("list_header %x %x %u", map->first_ip, map->last_ip, -+ map->flags); -+ -+ header->from = map->first_ip; -+ header->to = map->last_ip; -+ header->flags = map->flags; -+} -+ -+static int list_members_size(const struct ip_set *set) -+{ -+ struct ip_set_macipmap *map = -+ (struct ip_set_macipmap *) set->data; -+ -+ DP("%u", members_size(map->first_ip, map->last_ip)); -+ return members_size(map->first_ip, map->last_ip); -+} -+ -+static void list_members(const struct ip_set *set, void *data) -+{ -+ struct ip_set_macipmap *map = -+ (struct ip_set_macipmap *) set->data; -+ -+ int bytes = members_size(map->first_ip, map->last_ip); -+ -+ DP("members: %u %p", bytes, map->members); -+ memcpy(data, map->members, bytes); -+} -+ -+static struct ip_set_type ip_set_macipmap = { -+ .typename = SETTYPE_NAME, -+ .typecode = IPSET_TYPE_IP, -+ .protocol_version = IP_SET_PROTOCOL_VERSION, -+ .create = &create, -+ .destroy = &destroy, -+ .flush = &flush, -+ .reqsize = sizeof(struct ip_set_req_macipmap), -+ .addip = &addip, -+ .addip_kernel = &addip_kernel, -+ .delip = &delip, -+ .delip_kernel = &delip_kernel, -+ .testip = &testip, -+ .testip_kernel = &testip_kernel, -+ .header_size = sizeof(struct ip_set_req_macipmap_create), -+ .list_header = &list_header, -+ .list_members_size = &list_members_size, -+ .list_members = &list_members, -+ .me = THIS_MODULE, -+}; -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -+MODULE_DESCRIPTION("macipmap type of IP sets"); -+ -+static int __init init(void) -+{ -+ return ip_set_register_set_type(&ip_set_macipmap); -+} -+ -+static void __exit fini(void) -+{ -+ /* FIXME: possible race with ip_set_create() */ -+ ip_set_unregister_set_type(&ip_set_macipmap); -+} -+ -+module_init(init); -+module_exit(fini); -diff -Naur linux-old/net/ipv4/netfilter/ip_set_nethash.c linux-new/net/ipv4/netfilter/ip_set_nethash.c ---- linux-old/net/ipv4/netfilter/ip_set_nethash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/net/ipv4/netfilter/ip_set_nethash.c 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,450 @@ -+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* Kernel module implementing a cidr nethash set */ -+ -+#include <linux/module.h> -+#include <linux/ip.h> -+#include <linux/skbuff.h> -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ip_set.h> -+#include <linux/errno.h> -+#include <asm/uaccess.h> -+#include <asm/bitops.h> -+#include <asm/softirq.h> -+#include <linux/spinlock.h> -+#include <linux/vmalloc.h> -+#include <linux/random.h> -+ -+#include <net/ip.h> -+ -+#include <linux/netfilter_ipv4/ip_set_malloc.h> -+#include <linux/netfilter_ipv4/ip_set_nethash.h> -+#include <linux/netfilter_ipv4/ip_set_jhash.h> -+#include <linux/netfilter_ipv4/ip_set_prime.h> -+ -+static inline __u32 -+jhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip) -+{ -+ return jhash_1word(ip, map->initval); -+} -+ -+static inline __u32 -+randhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip) -+{ -+ return (1 + ip % map->prime); -+} -+ -+static inline __u32 -+hash_id_cidr(struct ip_set_nethash *map, -+ ip_set_ip_t ip, -+ unsigned char cidr, -+ ip_set_ip_t *hash_ip) -+{ -+ __u32 jhash, randhash, id; -+ u_int16_t i; -+ -+ *hash_ip = pack(ip, cidr); -+ jhash = jhash_ip(map, *hash_ip); -+ randhash = randhash_ip(map, *hash_ip); -+ -+ for (i = 0; i < map->probes; i++) { -+ id = (jhash + i * randhash) % map->hashsize; -+ DP("hash key: %u", id); -+ if (map->members[id] == *hash_ip) -+ return id; -+ } -+ return UINT_MAX; -+} -+ -+static inline __u32 -+hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ __u32 id = UINT_MAX; -+ int i; -+ -+ for (i = 0; i < 30 && map->cidr[i]; i++) { -+ id = hash_id_cidr(map, ip, map->cidr[i], hash_ip); -+ if (id != UINT_MAX) -+ break; -+ } -+ return id; -+} -+ -+static inline int -+__testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ -+ return (hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX); -+} -+ -+static inline int -+__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) -+{ -+ return (hash_id(set, ip, hash_ip) != UINT_MAX); -+} -+ -+static int -+testip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_nethash *req = -+ (struct ip_set_req_nethash *) data; -+ -+ if (size != sizeof(struct ip_set_req_nethash)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_nethash), -+ size); -+ return -EINVAL; -+ } -+ return (req->cidr == 32 ? __testip(set, req->ip, hash_ip) -+ : __testip_cidr(set, req->ip, req->cidr, hash_ip)); -+} -+ -+static int -+testip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ return __testip(set, -+ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr), -+ hash_ip); -+} -+ -+static inline int -+__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip) -+{ -+ __u32 jhash, randhash, probe; -+ u_int16_t i; -+ -+ jhash = jhash_ip(map, ip); -+ randhash = randhash_ip(map, ip); -+ -+ for (i = 0; i < map->probes; i++) { -+ probe = (jhash + i * randhash) % map->hashsize; -+ if (map->members[probe] == ip) -+ return -EEXIST; -+ if (!map->members[probe]) { -+ map->members[probe] = ip; -+ return 0; -+ } -+ } -+ /* Trigger rehashing */ -+ return -EAGAIN; -+} -+ -+static inline int -+__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr, -+ ip_set_ip_t *hash_ip) -+{ -+ *hash_ip = pack(ip, cidr); -+ DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip)); -+ -+ return __addip_base(map, *hash_ip); -+} -+ -+static void -+update_cidr_sizes(struct ip_set_nethash *map, unsigned char cidr) -+{ -+ unsigned char next; -+ int i; -+ -+ for (i = 0; i < 30 && map->cidr[i]; i++) { -+ if (map->cidr[i] == cidr) { -+ return; -+ } else if (map->cidr[i] < cidr) { -+ next = map->cidr[i]; -+ map->cidr[i] = cidr; -+ cidr = next; -+ } -+ } -+ if (i < 30) -+ map->cidr[i] = cidr; -+} -+ -+static int -+addip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_nethash *req = -+ (struct ip_set_req_nethash *) data; -+ int ret; -+ -+ if (size != sizeof(struct ip_set_req_nethash)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_nethash), -+ size); -+ return -EINVAL; -+ } -+ ret = __addip((struct ip_set_nethash *) set->data, -+ req->ip, req->cidr, hash_ip); -+ -+ if (ret == 0) -+ update_cidr_sizes((struct ip_set_nethash *) set->data, -+ req->cidr); -+ -+ return ret; -+} -+ -+static int -+addip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ int ret = -ERANGE; -+ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr); -+ -+ if (map->cidr[0]) -+ ret = __addip(map, ip, map->cidr[0], hash_ip); -+ -+ return ret; -+} -+ -+static int retry(struct ip_set *set) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ ip_set_ip_t *members; -+ u_int32_t i, hashsize; -+ unsigned newbytes; -+ int res; -+ struct ip_set_nethash tmp = { -+ .hashsize = map->hashsize, -+ .probes = map->probes, -+ .resize = map->resize -+ }; -+ -+ if (map->resize == 0) -+ return -ERANGE; -+ -+ memcpy(tmp.cidr, map->cidr, 30 * sizeof(unsigned char)); -+ again: -+ res = 0; -+ -+ /* Calculate new parameters */ -+ get_random_bytes(&tmp.initval, 4); -+ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100; -+ if (hashsize == tmp.hashsize) -+ hashsize++; -+ tmp.prime = make_prime(hashsize); -+ -+ ip_set_printk("rehashing of set %s triggered: " -+ "hashsize grows from %u to %u", -+ set->name, tmp.hashsize, hashsize); -+ tmp.hashsize = hashsize; -+ -+ newbytes = hashsize * sizeof(ip_set_ip_t); -+ tmp.members = ip_set_malloc(newbytes); -+ if (!tmp.members) { -+ DP("out of memory for %d bytes", newbytes); -+ return -ENOMEM; -+ } -+ memset(tmp.members, 0, newbytes); -+ -+ write_lock_bh(&set->lock); -+ map = (struct ip_set_nethash *) set->data; /* Play safe */ -+ for (i = 0; i < map->hashsize && res == 0; i++) { -+ if (map->members[i]) -+ res = __addip_base(&tmp, map->members[i]); -+ } -+ if (res) { -+ /* Failure, try again */ -+ write_unlock_bh(&set->lock); -+ ip_set_free(tmp.members, newbytes); -+ goto again; -+ } -+ -+ /* Success at resizing! */ -+ members = map->members; -+ hashsize = map->hashsize; -+ -+ map->initval = tmp.initval; -+ map->prime = tmp.prime; -+ map->hashsize = tmp.hashsize; -+ map->members = tmp.members; -+ write_unlock_bh(&set->lock); -+ -+ ip_set_free(members, hashsize * sizeof(ip_set_ip_t)); -+ -+ return 0; -+} -+ -+static inline int -+__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr, -+ ip_set_ip_t *hash_ip) -+{ -+ ip_set_ip_t id = hash_id_cidr(map, ip, cidr, hash_ip); -+ -+ if (id == UINT_MAX) -+ return -EEXIST; -+ -+ map->members[id] = 0; -+ return 0; -+} -+ -+static int -+delip(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_req_nethash *req = -+ (struct ip_set_req_nethash *) data; -+ -+ if (size != sizeof(struct ip_set_req_nethash)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_nethash), -+ size); -+ return -EINVAL; -+ } -+ /* TODO: no garbage collection in map->cidr */ -+ return __delip((struct ip_set_nethash *) set->data, -+ req->ip, req->cidr, hash_ip); -+} -+ -+static int -+delip_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_ip) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ int ret = -ERANGE; -+ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr -+ : skb->nh.iph->daddr); -+ -+ if (map->cidr[0]) -+ ret = __delip(map, ip, map->cidr[0], hash_ip); -+ -+ return ret; -+} -+ -+static int create(struct ip_set *set, const void *data, size_t size) -+{ -+ unsigned newbytes; -+ struct ip_set_req_nethash_create *req = -+ (struct ip_set_req_nethash_create *) data; -+ struct ip_set_nethash *map; -+ -+ if (size != sizeof(struct ip_set_req_nethash_create)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_nethash_create), -+ size); -+ return -EINVAL; -+ } -+ -+ if (req->hashsize < 1) { -+ ip_set_printk("hashsize too small"); -+ return -ENOEXEC; -+ } -+ -+ map = kmalloc(sizeof(struct ip_set_nethash), GFP_KERNEL); -+ if (!map) { -+ DP("out of memory for %d bytes", -+ sizeof(struct ip_set_nethash)); -+ return -ENOMEM; -+ } -+ get_random_bytes(&map->initval, 4); -+ map->prime = make_prime(req->hashsize); -+ map->hashsize = req->hashsize; -+ map->probes = req->probes; -+ map->resize = req->resize; -+ memset(map->cidr, 0, 30 * sizeof(unsigned char)); -+ newbytes = map->hashsize * sizeof(ip_set_ip_t); -+ map->members = ip_set_malloc(newbytes); -+ if (!map->members) { -+ DP("out of memory for %d bytes", newbytes); -+ kfree(map); -+ return -ENOMEM; -+ } -+ memset(map->members, 0, newbytes); -+ -+ set->data = map; -+ return 0; -+} -+ -+static void destroy(struct ip_set *set) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ -+ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t)); -+ kfree(map); -+ -+ set->data = NULL; -+} -+ -+static void flush(struct ip_set *set) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t)); -+ memset(map->cidr, 0, 30 * sizeof(unsigned char)); -+} -+ -+static void list_header(const struct ip_set *set, void *data) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ struct ip_set_req_nethash_create *header = -+ (struct ip_set_req_nethash_create *) data; -+ -+ header->hashsize = map->hashsize; -+ header->probes = map->probes; -+ header->resize = map->resize; -+} -+ -+static int list_members_size(const struct ip_set *set) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ -+ return (map->hashsize * sizeof(ip_set_ip_t)); -+} -+ -+static void list_members(const struct ip_set *set, void *data) -+{ -+ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data; -+ int bytes = map->hashsize * sizeof(ip_set_ip_t); -+ -+ memcpy(data, map->members, bytes); -+} -+ -+static struct ip_set_type ip_set_nethash = { -+ .typename = SETTYPE_NAME, -+ .typecode = IPSET_TYPE_IP, -+ .protocol_version = IP_SET_PROTOCOL_VERSION, -+ .create = &create, -+ .destroy = &destroy, -+ .flush = &flush, -+ .reqsize = sizeof(struct ip_set_req_nethash), -+ .addip = &addip, -+ .addip_kernel = &addip_kernel, -+ .retry = &retry, -+ .delip = &delip, -+ .delip_kernel = &delip_kernel, -+ .testip = &testip, -+ .testip_kernel = &testip_kernel, -+ .header_size = sizeof(struct ip_set_req_nethash_create), -+ .list_header = &list_header, -+ .list_members_size = &list_members_size, -+ .list_members = &list_members, -+ .me = THIS_MODULE, -+}; -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -+MODULE_DESCRIPTION("nethash type of IP sets"); -+ -+static int __init init(void) -+{ -+ return ip_set_register_set_type(&ip_set_nethash); -+} -+ -+static void __exit fini(void) -+{ -+ /* FIXME: possible race with ip_set_create() */ -+ ip_set_unregister_set_type(&ip_set_nethash); -+} -+ -+module_init(init); -+module_exit(fini); -diff -Naur linux-old/net/ipv4/netfilter/ip_set_portmap.c linux-new/net/ipv4/netfilter/ip_set_portmap.c ---- linux-old/net/ipv4/netfilter/ip_set_portmap.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/net/ipv4/netfilter/ip_set_portmap.c 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,321 @@ -+/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* Kernel module implementing a port set type as a bitmap */ -+ -+#include <linux/module.h> -+#include <linux/ip.h> -+#include <linux/tcp.h> -+#include <linux/udp.h> -+#include <linux/skbuff.h> -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ip_set.h> -+#include <linux/errno.h> -+#include <asm/uaccess.h> -+#include <asm/bitops.h> -+#include <asm/softirq.h> -+#include <linux/spinlock.h> -+ -+#include <net/ip.h> -+ -+#include <linux/netfilter_ipv4/ip_set_portmap.h> -+ -+static inline ip_set_ip_t -+get_port(const struct sk_buff *skb, u_int32_t flags) -+{ -+ struct iphdr *iph = skb->nh.iph; -+ u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET; -+ -+ switch (iph->protocol) { -+ case IPPROTO_TCP: { -+ struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl); -+ -+ /* See comments at tcp_match in ip_tables.c */ -+ if (offset != 0 -+ || (offset == 0 -+ && (skb->len - iph->ihl * 4) < sizeof(struct tcphdr))) -+ return INVALID_PORT; -+ -+ return ntohs(flags & IPSET_SRC ? -+ tcph->source : tcph->dest); -+ } -+ case IPPROTO_UDP: { -+ struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl); -+ -+ if (offset != 0 -+ || (offset == 0 -+ && (skb->len - iph->ihl * 4) < sizeof(struct udphdr))) -+ return INVALID_PORT; -+ -+ return ntohs(flags & IPSET_SRC ? -+ udph->source : udph->dest); -+ } -+ default: -+ return INVALID_PORT; -+ } -+} -+ -+static inline int -+__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) -+{ -+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data; -+ -+ if (port < map->first_port || port > map->last_port) -+ return -ERANGE; -+ -+ *hash_port = port; -+ DP("set: %s, port:%u, %u", set->name, port, *hash_port); -+ return !!test_bit(port - map->first_port, map->members); -+} -+ -+static int -+testport(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_port) -+{ -+ struct ip_set_req_portmap *req = -+ (struct ip_set_req_portmap *) data; -+ -+ if (size != sizeof(struct ip_set_req_portmap)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_portmap), -+ size); -+ return -EINVAL; -+ } -+ return __testport(set, req->port, hash_port); -+} -+ -+static int -+testport_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_port) -+{ -+ int res; -+ ip_set_ip_t port = get_port(skb, flags); -+ -+ DP("flag %s port %u", flags & IPSET_SRC ? "SRC" : "DST", port); -+ if (port == INVALID_PORT) -+ return 0; -+ -+ res = __testport(set, port, hash_port); -+ -+ return (res < 0 ? 0 : res); -+} -+ -+static inline int -+__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) -+{ -+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data; -+ -+ if (port < map->first_port || port > map->last_port) -+ return -ERANGE; -+ if (test_and_set_bit(port - map->first_port, map->members)) -+ return -EEXIST; -+ -+ *hash_port = port; -+ DP("port %u", port); -+ return 0; -+} -+ -+static int -+addport(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_port) -+{ -+ struct ip_set_req_portmap *req = -+ (struct ip_set_req_portmap *) data; -+ -+ if (size != sizeof(struct ip_set_req_portmap)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_portmap), -+ size); -+ return -EINVAL; -+ } -+ return __addport(set, req->port, hash_port); -+} -+ -+static int -+addport_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_port) -+{ -+ ip_set_ip_t port = get_port(skb, flags); -+ -+ if (port == INVALID_PORT) -+ return -EINVAL; -+ -+ return __addport(set, port, hash_port); -+} -+ -+static inline int -+__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) -+{ -+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data; -+ -+ if (port < map->first_port || port > map->last_port) -+ return -ERANGE; -+ if (!test_and_clear_bit(port - map->first_port, map->members)) -+ return -EEXIST; -+ -+ *hash_port = port; -+ DP("port %u", port); -+ return 0; -+} -+ -+static int -+delport(struct ip_set *set, const void *data, size_t size, -+ ip_set_ip_t *hash_port) -+{ -+ struct ip_set_req_portmap *req = -+ (struct ip_set_req_portmap *) data; -+ -+ if (size != sizeof(struct ip_set_req_portmap)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_portmap), -+ size); -+ return -EINVAL; -+ } -+ return __delport(set, req->port, hash_port); -+} -+ -+static int -+delport_kernel(struct ip_set *set, const struct sk_buff *skb, -+ u_int32_t flags, ip_set_ip_t *hash_port) -+{ -+ ip_set_ip_t port = get_port(skb, flags); -+ -+ if (port == INVALID_PORT) -+ return -EINVAL; -+ -+ return __delport(set, port, hash_port); -+} -+ -+static int create(struct ip_set *set, const void *data, size_t size) -+{ -+ int newbytes; -+ struct ip_set_req_portmap_create *req = -+ (struct ip_set_req_portmap_create *) data; -+ struct ip_set_portmap *map; -+ -+ if (size != sizeof(struct ip_set_req_portmap_create)) { -+ ip_set_printk("data length wrong (want %zu, have %zu)", -+ sizeof(struct ip_set_req_portmap_create), -+ size); -+ return -EINVAL; -+ } -+ -+ DP("from %u to %u", req->from, req->to); -+ -+ if (req->from > req->to) { -+ DP("bad port range"); -+ return -ENOEXEC; -+ } -+ -+ if (req->to - req->from > MAX_RANGE) { -+ ip_set_printk("range too big (max %d ports)", -+ MAX_RANGE); -+ return -ENOEXEC; -+ } -+ -+ map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL); -+ if (!map) { -+ DP("out of memory for %d bytes", -+ sizeof(struct ip_set_portmap)); -+ return -ENOMEM; -+ } -+ map->first_port = req->from; -+ map->last_port = req->to; -+ newbytes = bitmap_bytes(req->from, req->to); -+ map->members = kmalloc(newbytes, GFP_KERNEL); -+ if (!map->members) { -+ DP("out of memory for %d bytes", newbytes); -+ kfree(map); -+ return -ENOMEM; -+ } -+ memset(map->members, 0, newbytes); -+ -+ set->data = map; -+ return 0; -+} -+ -+static void destroy(struct ip_set *set) -+{ -+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data; -+ -+ kfree(map->members); -+ kfree(map); -+ -+ set->data = NULL; -+} -+ -+static void flush(struct ip_set *set) -+{ -+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data; -+ memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port)); -+} -+ -+static void list_header(const struct ip_set *set, void *data) -+{ -+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data; -+ struct ip_set_req_portmap_create *header = -+ (struct ip_set_req_portmap_create *) data; -+ -+ DP("list_header %u %u", map->first_port, map->last_port); -+ -+ header->from = map->first_port; -+ header->to = map->last_port; -+} -+ -+static int list_members_size(const struct ip_set *set) -+{ -+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data; -+ -+ return bitmap_bytes(map->first_port, map->last_port); -+} -+ -+static void list_members(const struct ip_set *set, void *data) -+{ -+ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data; -+ int bytes = bitmap_bytes(map->first_port, map->last_port); -+ -+ memcpy(data, map->members, bytes); -+} -+ -+static struct ip_set_type ip_set_portmap = { -+ .typename = SETTYPE_NAME, -+ .typecode = IPSET_TYPE_PORT, -+ .protocol_version = IP_SET_PROTOCOL_VERSION, -+ .create = &create, -+ .destroy = &destroy, -+ .flush = &flush, -+ .reqsize = sizeof(struct ip_set_req_portmap), -+ .addip = &addport, -+ .addip_kernel = &addport_kernel, -+ .delip = &delport, -+ .delip_kernel = &delport_kernel, -+ .testip = &testport, -+ .testip_kernel = &testport_kernel, -+ .header_size = sizeof(struct ip_set_req_portmap_create), -+ .list_header = &list_header, -+ .list_members_size = &list_members_size, -+ .list_members = &list_members, -+ .me = THIS_MODULE, -+}; -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -+MODULE_DESCRIPTION("portmap type of IP sets"); -+ -+static int __init init(void) -+{ -+ return ip_set_register_set_type(&ip_set_portmap); -+} -+ -+static void __exit fini(void) -+{ -+ /* FIXME: possible race with ip_set_create() */ -+ ip_set_unregister_set_type(&ip_set_portmap); -+} -+ -+module_init(init); -+module_exit(fini); -diff -Naur linux-old/net/ipv4/netfilter/ipt_set.c linux-new/net/ipv4/netfilter/ipt_set.c ---- linux-old/net/ipv4/netfilter/ipt_set.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/net/ipv4/netfilter/ipt_set.c 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,114 @@ -+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> -+ * Patrick Schaaf <bof@bof.de> -+ * Martin Josefsson <gandalf@wlug.westbo.se> -+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* Kernel module to match an IP set. */ -+ -+#include <linux/module.h> -+#include <linux/ip.h> -+#include <linux/skbuff.h> -+ -+#include <linux/netfilter_ipv4/ip_tables.h> -+#include <linux/netfilter_ipv4/ip_set.h> -+#include <linux/netfilter_ipv4/ipt_set.h> -+ -+static inline int -+match_set(const struct ipt_set_info *info, -+ const struct sk_buff *skb, -+ int inv) -+{ -+ if (ip_set_testip_kernel(info->index, skb, info->flags)) -+ inv = !inv; -+ return inv; -+} -+ -+static int -+match(const struct sk_buff *skb, -+ const struct net_device *in, -+ const struct net_device *out, -+ const void *matchinfo, -+ int offset, -+ const void *hdr, -+ u_int16_t datalen, -+ int *hotdrop) -+{ -+ const struct ipt_set_info_match *info = matchinfo; -+ -+ return match_set(&info->match_set, -+ skb, -+ info->match_set.flags[0] & IPSET_MATCH_INV); -+} -+ -+static int -+checkentry(const char *tablename, -+ const struct ipt_ip *ip, -+ void *matchinfo, -+ unsigned int matchsize, -+ unsigned int hook_mask) -+{ -+ struct ipt_set_info_match *info = -+ (struct ipt_set_info_match *) matchinfo; -+ ip_set_id_t index; -+ -+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) { -+ ip_set_printk("invalid matchsize %d", matchsize); -+ return 0; -+ } -+ -+ index = ip_set_get_byindex(info->match_set.index); -+ -+ if (index == IP_SET_INVALID_ID) { -+ ip_set_printk("Cannot find set indentified by id %u to match", -+ info->match_set.index); -+ return 0; /* error */ -+ } -+ if (info->match_set.flags[IP_SET_MAX_BINDINGS] != 0) { -+ ip_set_printk("That's nasty!"); -+ return 0; /* error */ -+ } -+ -+ return 1; -+} -+ -+static void destroy(void *matchinfo, unsigned int matchsize) -+{ -+ struct ipt_set_info_match *info = matchinfo; -+ -+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) { -+ ip_set_printk("invalid matchsize %d", matchsize); -+ return; -+ } -+ -+ ip_set_put(info->match_set.index); -+} -+ -+static struct ipt_match set_match = { -+ .name = "set", -+ .match = &match, -+ .checkentry = &checkentry, -+ .destroy = &destroy, -+ .me = THIS_MODULE -+}; -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -+MODULE_DESCRIPTION("iptables IP set match module"); -+ -+static int __init init(void) -+{ -+ return ipt_register_match(&set_match); -+} -+ -+static void __exit fini(void) -+{ -+ ipt_unregister_match(&set_match); -+} -+ -+module_init(init); -+module_exit(fini); -diff -Naur linux-old/net/ipv4/netfilter/ipt_SET.c linux-new/net/ipv4/netfilter/ipt_SET.c ---- linux-old/net/ipv4/netfilter/ipt_SET.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-new/net/ipv4/netfilter/ipt_SET.c 2005-08-10 22:13:00.000000000 +0200 -@@ -0,0 +1,127 @@ -+/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> -+ * Patrick Schaaf <bof@bof.de> -+ * Martin Josefsson <gandalf@wlug.westbo.se> -+ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> -+ * -+ * 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. -+ */ -+ -+/* ipt_SET.c - netfilter target to manipulate IP sets */ -+ -+#include <linux/types.h> -+#include <linux/ip.h> -+#include <linux/timer.h> -+#include <linux/module.h> -+#include <linux/netfilter.h> -+#include <linux/netdevice.h> -+#include <linux/if.h> -+#include <linux/inetdevice.h> -+#include <net/protocol.h> -+#include <net/checksum.h> -+#include <linux/netfilter_ipv4.h> -+#include <linux/netfilter_ipv4/ip_nat_rule.h> -+#include <linux/netfilter_ipv4/ipt_set.h> -+ -+static unsigned int -+target(struct sk_buff **pskb, -+ unsigned int hooknum, -+ const struct net_device *in, -+ const struct net_device *out, -+ const void *targinfo, -+ void *userinfo) -+{ -+ const struct ipt_set_info_target *info = targinfo; -+ -+ if (info->add_set.index != IP_SET_INVALID_ID) -+ ip_set_addip_kernel(info->add_set.index, -+ *pskb, -+ info->add_set.flags); -+ if (info->del_set.index != IP_SET_INVALID_ID) -+ ip_set_delip_kernel(info->del_set.index, -+ *pskb, -+ info->del_set.flags); -+ -+ return IPT_CONTINUE; -+} -+ -+static int -+checkentry(const char *tablename, -+ const struct ipt_entry *e, -+ void *targinfo, -+ unsigned int targinfosize, unsigned int hook_mask) -+{ -+ struct ipt_set_info_target *info = -+ (struct ipt_set_info_target *) targinfo; -+ ip_set_id_t index; -+ -+ if (targinfosize != IPT_ALIGN(sizeof(*info))) { -+ DP("bad target info size %u", targinfosize); -+ return 0; -+ } -+ -+ if (info->add_set.index != IP_SET_INVALID_ID) { -+ index = ip_set_get_byindex(info->add_set.index); -+ if (index == IP_SET_INVALID_ID) { -+ ip_set_printk("cannot find add_set index %u as target", -+ info->add_set.index); -+ return 0; /* error */ -+ } -+ } -+ -+ if (info->del_set.index != IP_SET_INVALID_ID) { -+ index = ip_set_get_byindex(info->del_set.index); -+ if (index == IP_SET_INVALID_ID) { -+ ip_set_printk("cannot find del_set index %u as target", -+ info->del_set.index); -+ return 0; /* error */ -+ } -+ } -+ if (info->add_set.flags[IP_SET_MAX_BINDINGS] != 0 -+ || info->del_set.flags[IP_SET_MAX_BINDINGS] != 0) { -+ ip_set_printk("That's nasty!"); -+ return 0; /* error */ -+ } -+ return 1; -+} -+ -+static void destroy(void *targetinfo, unsigned int targetsize) -+{ -+ struct ipt_set_info_target *info = targetinfo; -+ -+ if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) { -+ ip_set_printk("invalid targetsize %d", targetsize); -+ return; -+ } -+ -+ if (info->add_set.index != IP_SET_INVALID_ID) -+ ip_set_put(info->add_set.index); -+ if (info->del_set.index != IP_SET_INVALID_ID) -+ ip_set_put(info->del_set.index); -+} -+ -+static struct ipt_target SET_target = { -+ .name = "SET", -+ .target = target, -+ .checkentry = checkentry, -+ .destroy = destroy, -+ .me = THIS_MODULE -+}; -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); -+MODULE_DESCRIPTION("iptables IP set target module"); -+ -+static int __init init(void) -+{ -+ return ipt_register_target(&SET_target); -+} -+ -+static void __exit fini(void) -+{ -+ ipt_unregister_target(&SET_target); -+} -+ -+module_init(init); -+module_exit(fini); -diff -Naur linux-old/net/ipv4/netfilter/Makefile linux-new/net/ipv4/netfilter/Makefile ---- linux-old/net/ipv4/netfilter/Makefile 2005-07-23 23:34:46.000000000 +0200 -+++ linux-new/net/ipv4/netfilter/Makefile 2005-08-10 22:13:01.000000000 +0200 -@@ -75,6 +75,18 @@ - obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o - obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o - obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o -+obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o -+obj-$(CONFIG_IP_NF_TARGET_SET) += ipt_SET.o -+ifdef CONFIG_IP_NF_SET -+ obj-$(CONFIG_IP_NF_SET) += ip_set.o -+ export-objs += ip_set.o -+endif -+obj-$(CONFIG_IP_NF_SET_IPMAP) += ip_set_ipmap.o -+obj-$(CONFIG_IP_NF_SET_PORTMAP) += ip_set_portmap.o -+obj-$(CONFIG_IP_NF_SET_MACIPMAP) += ip_set_macipmap.o -+obj-$(CONFIG_IP_NF_SET_IPHASH) += ip_set_iphash.o -+obj-$(CONFIG_IP_NF_SET_NETHASH) += ip_set_nethash.o -+obj-$(CONFIG_IP_NF_SET_IPTREE) += ip_set_iptree.o - obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o - obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o - |