add layer7 to iptables/kernel
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 1 Apr 2005 21:05:15 +0000 (21:05 +0000)
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 1 Apr 2005 21:05:15 +0000 (21:05 +0000)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@511 3c298f89-4303-0410-b956-a3cf2f4a3e73

openwrt/package/iptables/kernelconfig.mk
openwrt/package/iptables/patches/01-ipp2p-0.7.4.patch [new file with mode: 0644]
openwrt/package/iptables/patches/02-layer7-1.1.patch [new file with mode: 0644]
openwrt/package/iptables/patches/ipp2p-0.7.4.patch [deleted file]
openwrt/package/linux/kernel-patches/306-netfilter-layer7-0.9.1 [new file with mode: 0644]
openwrt/package/linux/linux.config

index 319cea8..00d2349 100644 (file)
@@ -22,6 +22,7 @@ ext-$(CONFIG_IP_NF_MATCH_CONNTRACK) += conntrack
 ext-$(CONFIG_IP_NF_MATCH_UNCLEAN) += unclean
 ext-$(CONFIG_IP_NF_MATCH_OWNER) += owner
 ext-$(CONFIG_IP_NF_MATCH_PHYSDEV) += physdev
 ext-$(CONFIG_IP_NF_MATCH_UNCLEAN) += unclean
 ext-$(CONFIG_IP_NF_MATCH_OWNER) += owner
 ext-$(CONFIG_IP_NF_MATCH_PHYSDEV) += physdev
+ext-$(CONFIG_IP_NF_MATCH_LAYER7) += layer7
 ext-$(CONFIG_IP_NF_TARGET_MASQUERADE) += MASQUERADE
 ext-$(CONFIG_IP_NF_TARGET_REDIRECT) += REDIRECT
 ext-$(CONFIG_IP_NF_TARGET_REJECT) += REJECT
 ext-$(CONFIG_IP_NF_TARGET_MASQUERADE) += MASQUERADE
 ext-$(CONFIG_IP_NF_TARGET_REDIRECT) += REDIRECT
 ext-$(CONFIG_IP_NF_TARGET_REJECT) += REJECT
diff --git a/openwrt/package/iptables/patches/01-ipp2p-0.7.4.patch b/openwrt/package/iptables/patches/01-ipp2p-0.7.4.patch
new file mode 100644 (file)
index 0000000..d39a39d
--- /dev/null
@@ -0,0 +1,506 @@
+diff -urN iptables-1.2.11.old/extensions/libipt_ipp2p.c iptables-1.2.11/extensions/libipt_ipp2p.c
+--- iptables-1.2.11.old/extensions/libipt_ipp2p.c      1970-01-01 01:00:00.000000000 +0100
++++ iptables-1.2.11/extensions/libipt_ipp2p.c  2005-03-12 00:50:27.000000000 +0100
+@@ -0,0 +1,455 @@
++
++#include <stdio.h>
++#include <netdb.h>
++#include <string.h>
++#include <stdlib.h>
++#include <getopt.h>
++#include <ctype.h>
++
++#include <iptables.h>
++
++#include <linux/netfilter_ipv4/ipt_ipp2p.h>
++
++
++
++
++static void
++help(void)
++{
++    printf(
++    "IPP2P v%s options:\n"
++    " --ipp2p Grab all known p2p packets\n"
++    " --ipp2p-data    Identify all known p2p download commands (obsolete)\n\n"
++    " --edk           [TCP&UDP]       All known eDonkey/eMule/Overnet packets\n"
++    " --dc            [TCP]           All known Direct Connect packets\n"
++    " --kazaa [TCP&UDP]       All known KaZaA packets\n"
++    " --gnu           [TCP&UDP]       All known Gnutella packets\n"
++    " --bit           [TCP&UDP]       All known BitTorrent packets\n"
++    " --apple [TCP]           All known AppleJuice packets (beta - just a few tests until now)\n"
++    " --winmx [TCP]           All known WinMX (beta - need feedback)\n"
++    " --soul          [TCP]           All known SoulSeek (beta - need feedback!)\n"
++    " --ares          [TCP]           All known Ares - use with DROP only (beta - need feedback!)\n\n"
++    " --edk-data      [TCP]           eDonkey/eMule/Overnet download commands (obsolete)\n"
++    " --dc-data       [TCP]           Direct Connect download command (obsolete)\n"
++    " --kazaa-data    [TCP]           KaZaA download command (obsolete)\n"
++    " --gnu-data      [TCP]           Gnutella download command (obsolete)\n"
++    "\nNote that the follwing options will have the same meaning:\n"
++    " '--ipp2p' is equal to '--edk --dc --kazaa --gnu'\n"
++    " '--ipp2p-data' is equal to '--edk-data --dc-data --kazaa-data --gnu-data'\n"
++    "\nIPP2P was intended for TCP only. Due to increasing usage of UDP we needed to change this.\n"
++    "You can now use -p udp to search UDP packets only or without -p switch to search UDP and TCP packets.\n"
++    "\nSee README included with this package for more details or visit http://www.ipp2p.org\n"
++    "\nExamples:\n"
++    " iptables -A FORWARD -m ipp2p --ipp2p -j MARK --set-mark 0x01\n"
++    " iptables -A FORWARD -p udp -m ipp2p --kazaa --bit -j DROP\n"
++    " iptables -A FORWARD -p tcp -m ipp2p --edk --soul -j DROP\n\n"
++    , IPP2P_VERSION);
++}
++
++                                                          
++
++static struct option opts[] = {
++        { "ipp2p", 0, 0, '1' },
++        { "edk", 0, 0, '2' }, 
++        { "ipp2p-data", 0, 0, '3' },          
++        { "kazaa-data", 0, 0, '4' },
++        { "edk-data", 0, 0, '5' },    
++        { "dc-data", 0, 0, '6' },
++      { "dc", 0, 0, '7' },
++      { "gnu-data", 0, 0, '8' },      
++      { "gnu", 0, 0, '9' },
++      { "kazaa", 0, 0, 'a' },
++      { "bit", 0, 0, 'b' },
++      { "apple", 0, 0, 'c' }, 
++      { "soul", 0, 0, 'd' },  
++      { "winmx", 0, 0, 'e' }, 
++      { "ares", 0, 0, 'f' },
++      { "debug", 0, 0, 'g' },
++        {0}
++};
++
++      
++
++static void
++init(struct ipt_entry_match *m, unsigned int *nfcache)
++{
++    struct ipt_p2p_info *info = (struct ipt_p2p_info *)m->data;
++
++    *nfcache |= NFC_UNKNOWN;
++
++    /*init the module with default values*/
++    info->cmd = 0;
++    info->debug = 0;
++
++}
++      
++
++static int
++parse(int c, char **argv, int invert, unsigned int *flags,
++      const struct ipt_entry *entry,
++      unsigned int *nfcache,
++      struct ipt_entry_match **match)
++{
++    struct ipt_p2p_info *info = (struct ipt_p2p_info *)(*match)->data;
++    
++    switch (c) {
++      case '1':               /*cmd: ipp2p*/
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified once!");
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++          if ((*flags) != 0)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++          *flags += SHORT_HAND_IPP2P;
++          info->cmd = *flags;
++          break;
++          
++      case '2':               /*cmd: edk*/
++          if ((*flags & IPP2P_EDK) == IPP2P_EDK)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--edk' may only be "
++                              "specified once");
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++            if ((*flags & IPP2P_DATA_EDK) == IPP2P_DATA_EDK)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: use `--edk' OR `--edk-data' but not both of them!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++          *flags += IPP2P_EDK;
++          info->cmd = *flags;     
++          break;
++
++      case '3':               /*cmd: ipp2p-data*/
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified once!");
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++          if ((*flags) != 0)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++          *flags += SHORT_HAND_DATA;
++          info->cmd = *flags;     
++          break;
++
++        case '4':             /*cmd: kazaa-data*/
++            if ((*flags & IPP2P_DATA_KAZAA) == IPP2P_DATA_KAZAA)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--kazaa-data' may only be "
++                                "specified once!");
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++            if ((*flags & IPP2P_KAZAA) == IPP2P_KAZAA)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: use `--kazaa' OR `--kazaa-data' but not both of them!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_DATA_KAZAA;
++          info->cmd = *flags;
++          break;
++
++      case '5':               /*cmd: edk-data*/
++            if ((*flags & IPP2P_DATA_EDK) == IPP2P_DATA_EDK)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--edk-data' may only be "
++                                "specified once!");
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++            if ((*flags & IPP2P_EDK) == IPP2P_EDK)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: use `--edk' OR `--edk-data' but not both of them!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_DATA_EDK;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++      case '6':               /*cmd: dc-data*/
++            if ((*flags & IPP2P_DATA_DC) == IPP2P_DATA_DC)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--dc-data' may only be "
++                                "specified once!");
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++            if ((*flags & IPP2P_DC) == IPP2P_DC)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: use `--dc' OR `--dc-data' but not both of them!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_DATA_DC;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++      case '7':               /*cmd: dc*/
++            if ((*flags & IPP2P_DC) == IPP2P_DC)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--dc' may only be "
++                                "specified once!");
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++            if ((*flags & IPP2P_DATA_DC) == IPP2P_DATA_DC)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: use `--dc' OR `--dc-data' but not both of them!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_DC;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++
++      case '8':               /*cmd: gnu-data*/
++            if ((*flags & IPP2P_DATA_GNU) == IPP2P_DATA_GNU)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--gnu-data' may only be "
++                                "specified once!");
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++            if ((*flags & IPP2P_GNU) == IPP2P_GNU)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: use `--gnu' OR `--gnu-data' but not both of them!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_DATA_GNU;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++      case '9':               /*cmd: gnu*/
++            if ((*flags & IPP2P_GNU) == IPP2P_GNU)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--gnu' may only be "
++                                "specified once!");
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++            if ((*flags & IPP2P_DATA_GNU) == IPP2P_DATA_GNU)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: use `--gnu' OR `--gnu-data' but not both of them!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_GNU;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++      case 'a':               /*cmd: kazaa*/
++            if ((*flags & IPP2P_KAZAA) == IPP2P_KAZAA)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--kazaa' may only be "
++                                "specified once!");
++          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p-data' may only be "
++                              "specified alone!");
++          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
++                  exit_error(PARAMETER_PROBLEM,
++                              "ipp2p: `--ipp2p' may only be "
++                              "specified alone!");
++            if ((*flags & IPP2P_DATA_KAZAA) == IPP2P_DATA_KAZAA)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: use `--kazaa' OR `--kazaa-data' but not both of them!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_KAZAA;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++      case 'b':               /*cmd: bit*/
++            if ((*flags & IPP2P_BIT) == IPP2P_BIT)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--bit' may only be "
++                                "specified once!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_BIT;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++      case 'c':               /*cmd: apple*/
++            if ((*flags & IPP2P_APPLE) == IPP2P_APPLE)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--apple' may only be "
++                                "specified once!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_APPLE;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++
++      case 'd':               /*cmd: soul*/
++            if ((*flags & IPP2P_SOUL) == IPP2P_SOUL)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--soul' may only be "
++                                "specified once!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_SOUL;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++
++      case 'e':               /*cmd: winmx*/
++            if ((*flags & IPP2P_WINMX) == IPP2P_WINMX)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--winmx' may only be "
++                                "specified once!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_WINMX;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++      case 'f':               /*cmd: ares*/
++            if ((*flags & IPP2P_ARES) == IPP2P_ARES)
++            exit_error(PARAMETER_PROBLEM,
++                                "ipp2p: `--ares' may only be "
++                                "specified once!");
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++            *flags += IPP2P_ARES;
++          info->cmd = *flags;
++          break;                                                                                                                                                                                                                      
++
++      case 'g':               /*cmd: debug*/
++          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
++          info->debug = 1;
++          break;                                                                                                                                                                                                                      
++
++      default:
++            exit_error(PARAMETER_PROBLEM,
++          "\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n");
++          return 0;
++    }
++    return 1;
++}
++
++
++static void
++final_check(unsigned int flags)
++{
++    if (!flags)
++            exit_error(PARAMETER_PROBLEM,
++          "\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n");
++}
++
++
++
++static void
++print(const struct ipt_ip *ip,
++        const struct ipt_entry_match *match,
++      int numeric)
++{
++    struct ipt_p2p_info *info = (struct ipt_p2p_info *)match->data;
++    
++    printf("ipp2p v%s", IPP2P_VERSION);
++    if ((info->cmd & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P) printf(" --ipp2p");
++    if ((info->cmd & SHORT_HAND_DATA) == SHORT_HAND_DATA) printf(" --ipp2p-data");
++    if ((info->cmd & IPP2P_KAZAA) == IPP2P_KAZAA) printf(" --kazaa");
++    if ((info->cmd & IPP2P_DATA_KAZAA) == IPP2P_DATA_KAZAA) printf(" --kazaa-data");
++    if ((info->cmd & IPP2P_DATA_GNU) == IPP2P_DATA_GNU) printf(" --gnu-data");
++    if ((info->cmd & IPP2P_GNU) == IPP2P_GNU) printf(" --gnu");
++    if ((info->cmd & IPP2P_EDK) == IPP2P_EDK) printf(" --edk");
++    if ((info->cmd & IPP2P_DATA_EDK) == IPP2P_DATA_EDK) printf(" --edk-data");
++    if ((info->cmd & IPP2P_DATA_DC) == IPP2P_DATA_DC) printf(" --dc-data");
++    if ((info->cmd & IPP2P_DC) == IPP2P_DC) printf(" --dc");
++    if ((info->cmd & IPP2P_BIT) == IPP2P_BIT) printf(" --bit");
++    if ((info->cmd & IPP2P_APPLE) == IPP2P_APPLE) printf(" --apple");
++    if ((info->cmd & IPP2P_SOUL) == IPP2P_SOUL) printf(" --soul");
++    if ((info->cmd & IPP2P_WINMX) == IPP2P_WINMX) printf(" --winmx");
++    if ((info->cmd & IPP2P_ARES) == IPP2P_ARES) printf(" --ares");
++    if (info->debug != 0) printf(" --debug");
++    printf(" ");
++}
++                                                                         
++
++
++static void
++save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
++{
++    struct ipt_p2p_info *info = (struct ipt_p2p_info *)match->data;
++    
++    if ((info->cmd & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P) printf("--ipp2p ");
++    if ((info->cmd & SHORT_HAND_DATA) == SHORT_HAND_DATA) printf("--ipp2p-data ");
++    if ((info->cmd & IPP2P_KAZAA) == IPP2P_KAZAA) printf("--kazaa ");
++    if ((info->cmd & IPP2P_DATA_KAZAA) == IPP2P_DATA_KAZAA) printf("--kazaa-data ");
++    if ((info->cmd & IPP2P_DATA_GNU) == IPP2P_DATA_GNU) printf("--gnu-data ");
++    if ((info->cmd & IPP2P_GNU) == IPP2P_GNU) printf("--gnu ");
++    if ((info->cmd & IPP2P_EDK) == IPP2P_EDK) printf("--edk ");
++    if ((info->cmd & IPP2P_DATA_EDK) == IPP2P_DATA_EDK) printf("--edk-data ");
++    if ((info->cmd & IPP2P_DATA_DC) == IPP2P_DATA_DC) printf("--dc-data ");
++    if ((info->cmd & IPP2P_DC) == IPP2P_DC) printf("--dc ");
++    if ((info->cmd & IPP2P_BIT) == IPP2P_BIT) printf("--bit ");
++    if ((info->cmd & IPP2P_APPLE) == IPP2P_APPLE) printf("--apple ");
++    if ((info->cmd & IPP2P_SOUL) == IPP2P_SOUL) printf("--soul ");
++    if ((info->cmd & IPP2P_WINMX) == IPP2P_WINMX) printf("--winmx ");
++    if ((info->cmd & IPP2P_ARES) == IPP2P_ARES) printf("--ares ");
++    if (info->debug != 0) printf("--debug ");
++}
++
++              
++
++
++static 
++struct iptables_match ipp2p= 
++{ 
++    .next           = NULL,
++    .name           = "ipp2p",
++    .version        = IPTABLES_VERSION,
++    .size           = IPT_ALIGN(sizeof(struct ipt_p2p_info)),
++    .userspacesize  = IPT_ALIGN(sizeof(struct ipt_p2p_info)),
++    .help           = &help,
++    .init           = &init,
++    .parse          = &parse,
++    .final_check    = &final_check,
++    .print          = &print,
++    .save           = &save,
++    .extra_opts     = opts
++};
++                                          
++
++
++void _init(void)
++{
++    register_match(&ipp2p);
++}
++
+diff -urN iptables-1.2.11.old/extensions/Makefile iptables-1.2.11/extensions/Makefile
+--- iptables-1.2.11.old/extensions/Makefile    2004-06-17 12:22:54.000000000 +0200
++++ iptables-1.2.11/extensions/Makefile        2005-03-12 00:50:12.000000000 +0100
+@@ -8,6 +8,10 @@
+ PF_EXT_SLIB:=ah connlimit connmark conntrack dscp ecn esp helper icmp iprange length limit mac mark multiport owner physdev pkttype realm rpc sctp standard state tcp tcpmss tos ttl udp unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE MIRROR NETMAP NOTRACK REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TRACE TTL ULOG
+ PF6_EXT_SLIB:=eui64 hl icmpv6 length limit mac mark multiport owner standard tcp udp HL LOG MARK TRACE
++
++# ipp2p
++PF_EXT_SLIB += ipp2p
++
+ # Optionals
+ PF_EXT_SLIB_OPTS:=$(foreach T,$(wildcard extensions/.*-test),$(shell KERNEL_DIR=$(KERNEL_DIR) $(T)))
+ PF6_EXT_SLIB_OPTS:=$(foreach T,$(wildcard extensions/.*-test6),$(shell KERNEL_DIR=$(KERNEL_DIR) $(T)))
+diff -urN iptables-1.2.11.old/include/linux/netfilter_ipv4/ipt_ipp2p.h iptables-1.2.11/include/linux/netfilter_ipv4/ipt_ipp2p.h
+--- iptables-1.2.11.old/include/linux/netfilter_ipv4/ipt_ipp2p.h       1970-01-01 01:00:00.000000000 +0100
++++ iptables-1.2.11/include/linux/netfilter_ipv4/ipt_ipp2p.h   2005-03-12 00:50:46.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 --git a/openwrt/package/iptables/patches/02-layer7-1.1.patch b/openwrt/package/iptables/patches/02-layer7-1.1.patch
new file mode 100644 (file)
index 0000000..6eee8a1
--- /dev/null
@@ -0,0 +1,756 @@
+diff -Nurp iptables-1.3.0-stock/extensions/.layer7-test iptables-1.3.0-layer7/extensions/.layer7-test
+--- iptables-1.3.0-stock/extensions/.layer7-test       1969-12-31 18:00:00.000000000 -0600
++++ iptables-1.3.0-layer7/extensions/.layer7-test      2005-03-01 22:12:06.000000000 -0600
+@@ -0,0 +1,2 @@
++#! /bin/sh
++[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_layer7.h ] && echo layer7
+diff -Nurp iptables-1.3.0-stock/extensions/libipt_layer7.c iptables-1.3.0-layer7/extensions/libipt_layer7.c
+--- iptables-1.3.0-stock/extensions/libipt_layer7.c    1969-12-31 18:00:00.000000000 -0600
++++ iptables-1.3.0-layer7/extensions/libipt_layer7.c   2005-03-06 22:14:13.000000000 -0600
+@@ -0,0 +1,357 @@
++/* 
++   Shared library add-on to iptables to add layer 7 matching support. 
++  
++   By Matthew Strait <quadong@users.sf.net>, Oct 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
++
++   Based on libipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>
++*/
++
++#define _GNU_SOURCE
++#include <stdio.h>
++#include <netdb.h>
++#include <string.h>
++#include <stdlib.h>
++#include <getopt.h>
++#include <ctype.h>
++#include <dirent.h>
++
++#include <iptables.h>
++#include <linux/netfilter_ipv4/ipt_layer7.h>
++
++#define MAX_FN_LEN 256
++
++static char l7dir[MAX_FN_LEN] = "\0";
++
++/* Function which prints out usage message. */
++static void help(void)
++{
++      printf(
++      "LAYER7 match v%s options:\n"
++      "--l7dir <directory>  : Look for patterns here instead of /etc/l7-protocols/\n"
++      "                       (--l7dir must be specified before --l7proto if used!)\n"
++      "--l7proto [!] <name> : Match the protocol defined in /etc/l7-protocols/name.pat\n",
++      IPTABLES_VERSION);
++      fputc('\n', stdout);
++}
++
++static struct option opts[] = {
++      { .name = "l7proto", .has_arg = 1, .flag = 0, .val = '1' },
++      { .name = "l7dir",   .has_arg = 1, .flag = 0, .val = '2' },
++      { .name = 0 }
++};
++
++/* Initialize the match. */
++static void init(struct ipt_entry_match *m, unsigned int *nfcache)
++{
++      *nfcache |= NFC_UNKNOWN;
++}
++
++/* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */
++int parse_protocol_file(char * filename, const unsigned char * protoname, struct ipt_layer7_info *info)
++{
++      FILE * f;
++      char * line = NULL;
++      size_t len = 0;
++
++      enum { protocol, pattern, done } datatype = protocol;
++
++      f = fopen(filename, "r");
++
++      if(!f)
++              return 0;
++
++      while(getline(&line, &len, f) != -1)
++      {
++              if(strlen(line) < 2 || line[0] == '#')
++                      continue;
++
++              /* strip the pesky newline... */
++              if(line[strlen(line) - 1] == '\n')
++                      line[strlen(line) - 1] = '\0';
++
++              if(datatype == protocol)
++              {
++                      if(strcmp(line, protoname))
++                              exit_error(OTHER_PROBLEM, 
++                                      "Protocol name (%s) doesn't match file name (%s).  Bailing out\n",
++                                      protoname, filename);
++
++                      if(strlen(line) >= MAX_PROTOCOL_LEN)
++                               exit_error(PARAMETER_PROBLEM, 
++                                      "Protocol name in %s too long!", filename);
++                      strncpy(info->protocol, line, MAX_PROTOCOL_LEN);
++
++                      datatype = pattern; 
++              }
++              else if(datatype == pattern)
++              {
++                      if(strlen(line) >= MAX_PATTERN_LEN)
++                               exit_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename);
++                      strncpy(info->pattern, line, MAX_PATTERN_LEN);
++                      
++                      datatype = done;                        
++                      break;
++              }
++              else
++                      exit_error(OTHER_PROBLEM, "Internal error");
++      }
++
++      if(datatype != done)
++              exit_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename);
++
++      if(line) free(line);
++      fclose(f);
++
++      return 1;
++
++/*
++      fprintf(stderr, "protocol: %s\npattern: %s\n\n", 
++                      info->protocol,
++                      info->pattern);
++*/
++}
++
++static int hex2dec(char c)
++{
++        switch (c)
++        {
++                case '0' ... '9':
++                        return c - '0';
++                case 'a' ... 'f':
++                        return c - 'a' + 10;
++                case 'A' ... 'F':
++                        return c - 'A' + 10;
++                default:
++                        exit_error(OTHER_PROBLEM, "hex2dec: bad value!\n");
++                        return 0;
++        }
++}
++
++/* takes a string with \xHH escapes and returns one with the characters 
++they stand for */
++static char * pre_process(char * s)
++{
++      char * result = malloc(strlen(s) + 1);
++      int sindex = 0, rindex = 0;
++        while( sindex < strlen(s) )
++        {
++            if( sindex + 3 < strlen(s) &&
++                s[sindex] == '\\' && s[sindex+1] == 'x' && 
++                isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) 
++                {
++                        /* carefully remember to call tolower here... */
++                        result[rindex] = tolower( hex2dec(s[sindex + 2])*16 +
++                                                  hex2dec(s[sindex + 3] ) );
++                        sindex += 3; /* 4 total */
++                }
++                else
++                        result[rindex] = tolower(s[sindex]);
++
++              sindex++; 
++              rindex++;
++        }
++      result[rindex] = '\0';
++
++      return result;
++}
++
++#define MAX_SUBDIRS 128
++char ** readl7dir(char * dirname)
++{
++        DIR             * scratchdir;
++        struct dirent   ** namelist;
++      char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *));
++
++        int n, d = 1;
++      subdirs[0] = "";
++
++        n = scandir(dirname, &namelist, 0, alphasort);
++
++      if (n < 0)
++      {
++            perror("scandir");
++          exit_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname);
++      }
++        else 
++      {
++              while(n--) 
++              {
++                      char fulldirname[MAX_FN_LEN];
++
++                      snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name);
++
++                      if((scratchdir = opendir(fulldirname)) != NULL)
++                      {
++                              closedir(scratchdir);
++
++                              if(!strcmp(namelist[n]->d_name, ".") || 
++                                 !strcmp(namelist[n]->d_name, ".."))
++                                      /* do nothing */ ;
++                              else
++                              {
++                                      subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1);
++                                      strcpy(subdirs[d], namelist[n]->d_name);
++                                      d++;
++                                      if(d >= MAX_SUBDIRS - 1)
++                                      {
++                                              fprintf(stderr, 
++                                                "Too many subdirectories, skipping the rest!\n");
++                                              break;
++                                      }
++                              }
++                      }
++                      free(namelist[n]);
++              }
++              free(namelist);
++        }
++      
++      subdirs[d] = NULL;
++
++      return subdirs;
++}
++
++static void
++parse_layer7_protocol(const unsigned char *s, struct ipt_layer7_info *info)
++{
++      char filename[MAX_FN_LEN];
++      char * dir = NULL;
++      char ** subdirs;
++      int n = 0, done = 0;
++
++      if(strlen(l7dir) > 0)
++              dir = l7dir;
++      else
++              dir = "/etc/l7-protocols";
++
++      subdirs = readl7dir(dir);
++
++      while(subdirs[n] != NULL)
++      {
++              int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s);
++
++              //fprintf(stderr, "Trying to find pattern in %s ... ", filename);
++
++              if(c > MAX_FN_LEN)
++              {
++                      exit_error(OTHER_PROBLEM, 
++                              "Filename beginning with %s is too long!\n", filename);
++              }
++
++              /* read in the pattern from the file */
++              if(parse_protocol_file(filename, s, info))
++              {
++                      //fprintf(stderr, "found\n");
++                      done = 1;
++                      break;
++              }
++              
++              //fprintf(stderr, "not found\n");
++
++              n++;
++      }
++
++      if(!done)
++              exit_error(OTHER_PROBLEM, 
++                      "Couldn't find a pattern definition file for %s.\n", s);
++
++      /* process \xHH escapes and tolower everything. (our regex lib has no
++      case insensitivity option.) */
++      strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN);
++}
++
++/* Function which parses command options; returns true if it ate an option */
++static int parse(int c, char **argv, int invert, unsigned int *flags,
++      const struct ipt_entry *entry, unsigned int *nfcache,
++      struct ipt_entry_match **match)
++{
++      struct ipt_layer7_info *layer7info = 
++              (struct ipt_layer7_info *)(*match)->data;
++
++      switch (c) {
++      case '1':
++              check_inverse(optarg, &invert, &optind, 0);
++              parse_layer7_protocol(argv[optind-1], layer7info);
++              if (invert)
++                      layer7info->invert = 1;
++              *flags = 1;
++              break;
++
++      case '2':
++              /* not going to use this, but maybe we need to strip a ! anyway (?) */
++              check_inverse(optarg, &invert, &optind, 0);
++
++              if(strlen(argv[optind-1]) >= MAX_FN_LEN)
++                      exit_error(PARAMETER_PROBLEM, "directory name too long\n");
++
++              strncpy(l7dir, argv[optind-1], MAX_FN_LEN);
++
++              *flags = 1;
++              break;
++
++      default:
++              return 0;
++      }
++
++      return 1;
++}
++
++/* Final check; must have specified --pattern. */
++static void final_check(unsigned int flags)
++{
++      if (!flags)
++              exit_error(PARAMETER_PROBLEM,
++                         "LAYER7 match: You must specify `--pattern'");
++}
++
++static void print_protocol(char s[], int invert, int numeric)
++{
++      fputs("l7proto ", stdout);
++      if (invert) fputc('!', stdout);
++      printf("%s ", s);
++}
++
++/* Prints out the matchinfo. */
++static void print(const struct ipt_ip *ip,
++      const struct ipt_entry_match *match,
++      int numeric)
++{
++      printf("LAYER7 ");
++
++      print_protocol(((struct ipt_layer7_info *)match->data)->protocol,
++                ((struct ipt_layer7_info *)match->data)->invert, numeric);
++}
++/* Saves the union ipt_matchinfo in parsable form to stdout. */
++static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
++{
++        const struct ipt_layer7_info *info =
++            (const struct ipt_layer7_info*) match->data;
++
++        printf("--l7proto %s%s ", (info->invert)   ? "! ": "", info->protocol);
++}
++
++static struct iptables_match layer7 = { 
++    .name          = "layer7",
++    .version       = IPTABLES_VERSION,
++    .size          = IPT_ALIGN(sizeof(struct ipt_layer7_info)),
++    .userspacesize = IPT_ALIGN(sizeof(struct ipt_layer7_info)),
++    .help          = &help,
++    .init          = &init,
++    .parse         = &parse,
++    .final_check   = &final_check,
++    .print         = &print,
++    .save          = &save,
++    .extra_opts    = opts
++};
++
++void _init(void)
++{
++      register_match(&layer7);
++}
+diff -Nurp iptables-1.3.0-stock/extensions/libipt_layer7.c.orig iptables-1.3.0-layer7/extensions/libipt_layer7.c.orig
+--- iptables-1.3.0-stock/extensions/libipt_layer7.c.orig       1969-12-31 18:00:00.000000000 -0600
++++ iptables-1.3.0-layer7/extensions/libipt_layer7.c.orig      2005-03-06 22:20:28.000000000 -0600
+@@ -0,0 +1,357 @@
++/* 
++   Shared library add-on to iptables to add layer 7 matching support. 
++  
++   By Matthew Strait <quadong@users.sf.net>, Oct 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
++
++   Based on libipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>
++*/
++
++#define _GNU_SOURCE
++#include <stdio.h>
++#include <netdb.h>
++#include <string.h>
++#include <stdlib.h>
++#include <getopt.h>
++#include <ctype.h>
++#include <dirent.h>
++
++#include <iptables.h>
++#include <linux/netfilter_ipv4/ipt_layer7.h>
++
++#define MAX_FN_LEN 256
++
++static char l7dir[MAX_FN_LEN] = "\0";
++
++/* Function which prints out usage message. */
++static void help(void)
++{
++      printf(
++      "LAYER7 match v%s options:\n"
++      "--l7dir <directory>  : Look for patterns here instead of /etc/l7-protocols/\n"
++      "                       (--l7dir must be specified before --l7proto if used!)\n"
++      "--l7proto [!] <name> : Match the protocol defined in /etc/l7-protocols/name.pat\n",
++      IPTABLES_VERSION);
++      fputc('\n', stdout);
++}
++
++static struct option opts[] = {
++      { .name = "l7proto", .has_arg = 1, .flag = 0, .val = '1' },
++      { .name = "l7dir",   .has_arg = 1, .flag = 0, .val = '2' },
++      { .name = 0 }
++};
++
++/* Initialize the match. */
++static void init(struct ipt_entry_match *m, unsigned int *nfcache)
++{
++      *nfcache |= NFC_UNKNOWN;
++}
++
++/* reads filename, puts protocol info into layer7_protocol_info, number of protocols to numprotos */
++int parse_protocol_file(char * filename, const unsigned char * protoname, struct ipt_layer7_info *info)
++{
++      FILE * f;
++      char * line = NULL;
++      int len = 0;
++
++      enum { protocol, pattern, done } datatype = protocol;
++
++      f = fopen(filename, "r");
++
++      if(!f)
++              return 0;
++
++      while(getline(&line, &len, f) != -1)
++      {
++              if(strlen(line) < 2 || line[0] == '#')
++                      continue;
++
++              /* strip the pesky newline... */
++              if(line[strlen(line) - 1] == '\n')
++                      line[strlen(line) - 1] = '\0';
++
++              if(datatype == protocol)
++              {
++                      if(strcmp(line, protoname))
++                              exit_error(OTHER_PROBLEM, 
++                                      "Protocol name (%s) doesn't match file name (%s).  Bailing out\n",
++                                      protoname, filename);
++
++                      if(strlen(line) >= MAX_PROTOCOL_LEN)
++                               exit_error(PARAMETER_PROBLEM, 
++                                      "Protocol name in %s too long!", filename);
++                      strncpy(info->protocol, line, MAX_PROTOCOL_LEN);
++
++                      datatype = pattern; 
++              }
++              else if(datatype == pattern)
++              {
++                      if(strlen(line) >= MAX_PATTERN_LEN)
++                               exit_error(PARAMETER_PROBLEM, "Pattern in %s too long!", filename);
++                      strncpy(info->pattern, line, MAX_PATTERN_LEN);
++                      
++                      datatype = done;                        
++                      break;
++              }
++              else
++                      exit_error(OTHER_PROBLEM, "Internal error");
++      }
++
++      if(datatype != done)
++              exit_error(OTHER_PROBLEM, "Failed to get all needed data from %s", filename);
++
++      if(line) free(line);
++      fclose(f);
++
++      return 1;
++
++/*
++      fprintf(stderr, "protocol: %s\npattern: %s\n\n", 
++                      info->protocol,
++                      info->pattern);
++*/
++}
++
++static int hex2dec(char c)
++{
++        switch (c)
++        {
++                case '0' ... '9':
++                        return c - '0';
++                case 'a' ... 'f':
++                        return c - 'a' + 10;
++                case 'A' ... 'F':
++                        return c - 'A' + 10;
++                default:
++                        exit_error(OTHER_PROBLEM, "hex2dec: bad value!\n");
++                        return 0;
++        }
++}
++
++/* takes a string with \xHH escapes and returns one with the characters 
++they stand for */
++static char * pre_process(char * s)
++{
++      char * result = malloc(strlen(s) + 1);
++      int sindex = 0, rindex = 0;
++        while( sindex < strlen(s) )
++        {
++            if( sindex + 3 < strlen(s) &&
++                s[sindex] == '\\' && s[sindex+1] == 'x' && 
++                isxdigit(s[sindex + 2]) && isxdigit(s[sindex + 3]) ) 
++                {
++                        /* carefully remember to call tolower here... */
++                        result[rindex] = tolower( hex2dec(s[sindex + 2])*16 +
++                                                  hex2dec(s[sindex + 3] ) );
++                        sindex += 3; /* 4 total */
++                }
++                else
++                        result[rindex] = tolower(s[sindex]);
++
++              sindex++; 
++              rindex++;
++        }
++      result[rindex] = '\0';
++
++      return result;
++}
++
++#define MAX_SUBDIRS 128
++char ** readl7dir(char * dirname)
++{
++        DIR             * scratchdir;
++        struct dirent   ** namelist;
++      char ** subdirs = malloc(MAX_SUBDIRS * sizeof(char *));
++
++        int n, d = 1;
++      subdirs[0] = "";
++
++        n = scandir(dirname, &namelist, 0, alphasort);
++
++      if (n < 0)
++      {
++            perror("scandir");
++          exit_error(OTHER_PROBLEM, "Couldn't open %s\n", dirname);
++      }
++        else 
++      {
++              while(n--) 
++              {
++                      char fulldirname[MAX_FN_LEN];
++
++                      snprintf(fulldirname, MAX_FN_LEN, "%s/%s", dirname, namelist[n]->d_name);
++
++                      if((scratchdir = opendir(fulldirname)) != NULL)
++                      {
++                              closedir(scratchdir);
++
++                              if(!strcmp(namelist[n]->d_name, ".") || 
++                                 !strcmp(namelist[n]->d_name, ".."))
++                                      /* do nothing */ ;
++                              else
++                              {
++                                      subdirs[d] = malloc(strlen(namelist[n]->d_name) + 1);
++                                      strcpy(subdirs[d], namelist[n]->d_name);
++                                      d++;
++                                      if(d >= MAX_SUBDIRS - 1)
++                                      {
++                                              fprintf(stderr, 
++                                                "Too many subdirectories, skipping the rest!\n");
++                                              break;
++                                      }
++                              }
++                      }
++                      free(namelist[n]);
++              }
++              free(namelist);
++        }
++      
++      subdirs[d] = NULL;
++
++      return subdirs;
++}
++
++static void
++parse_layer7_protocol(const unsigned char *s, struct ipt_layer7_info *info)
++{
++      char filename[MAX_FN_LEN];
++      char * dir = NULL;
++      char ** subdirs;
++      int n = 0, done = 0;
++
++      if(strlen(l7dir) > 0)
++              dir = l7dir;
++      else
++              dir = "/etc/l7-protocols";
++
++      subdirs = readl7dir(dir);
++
++      while(subdirs[n] != NULL)
++      {
++              int c = snprintf(filename, MAX_FN_LEN, "%s/%s/%s.pat", dir, subdirs[n], s);
++
++              //fprintf(stderr, "Trying to find pattern in %s ... ", filename);
++
++              if(c > MAX_FN_LEN)
++              {
++                      exit_error(OTHER_PROBLEM, 
++                              "Filename beginning with %s is too long!\n", filename);
++              }
++
++              /* read in the pattern from the file */
++              if(parse_protocol_file(filename, s, info))
++              {
++                      //fprintf(stderr, "found\n");
++                      done = 1;
++                      break;
++              }
++              
++              //fprintf(stderr, "not found\n");
++
++              n++;
++      }
++
++      if(!done)
++              exit_error(OTHER_PROBLEM, 
++                      "Couldn't find a pattern definition file for %s.\n", s);
++
++      /* process \xHH escapes and tolower everything. (our regex lib has no
++      case insensitivity option.) */
++      strncpy(info->pattern, pre_process(info->pattern), MAX_PATTERN_LEN);
++}
++
++/* Function which parses command options; returns true if it ate an option */
++static int parse(int c, char **argv, int invert, unsigned int *flags,
++      const struct ipt_entry *entry, unsigned int *nfcache,
++      struct ipt_entry_match **match)
++{
++      struct ipt_layer7_info *layer7info = 
++              (struct ipt_layer7_info *)(*match)->data;
++
++      switch (c) {
++      case '1':
++              check_inverse(optarg, &invert, &optind, 0);
++              parse_layer7_protocol(argv[optind-1], layer7info);
++              if (invert)
++                      layer7info->invert = 1;
++              *flags = 1;
++              break;
++
++      case '2':
++              /* not going to use this, but maybe we need to strip a ! anyway (?) */
++              check_inverse(optarg, &invert, &optind, 0);
++
++              if(strlen(argv[optind-1]) >= MAX_FN_LEN)
++                      exit_error(PARAMETER_PROBLEM, "directory name too long\n");
++
++              strncpy(l7dir, argv[optind-1], MAX_FN_LEN);
++
++              *flags = 1;
++              break;
++
++      default:
++              return 0;
++      }
++
++      return 1;
++}
++
++/* Final check; must have specified --pattern. */
++static void final_check(unsigned int flags)
++{
++      if (!flags)
++              exit_error(PARAMETER_PROBLEM,
++                         "LAYER7 match: You must specify `--pattern'");
++}
++
++static void print_protocol(char s[], int invert, int numeric)
++{
++      fputs("l7proto ", stdout);
++      if (invert) fputc('!', stdout);
++      printf("%s ", s);
++}
++
++/* Prints out the matchinfo. */
++static void print(const struct ipt_ip *ip,
++      const struct ipt_entry_match *match,
++      int numeric)
++{
++      printf("LAYER7 ");
++
++      print_protocol(((struct ipt_layer7_info *)match->data)->protocol,
++                ((struct ipt_layer7_info *)match->data)->invert, numeric);
++}
++/* Saves the union ipt_matchinfo in parsable form to stdout. */
++static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
++{
++        const struct ipt_layer7_info *info =
++            (const struct ipt_layer7_info*) match->data;
++
++        printf("--l7proto %s%s ", (info->invert)   ? "! ": "", info->protocol);
++}
++
++static struct iptables_match layer7 = { 
++    .name          = "layer7",
++    .version       = IPTABLES_VERSION,
++    .size          = IPT_ALIGN(sizeof(struct ipt_layer7_info)),
++    .userspacesize = IPT_ALIGN(sizeof(struct ipt_layer7_info)),
++    .help          = &help,
++    .init          = &init,
++    .parse         = &parse,
++    .final_check   = &final_check,
++    .print         = &print,
++    .save          = &save,
++    .extra_opts    = opts
++};
++
++void _init(void)
++{
++      register_match(&layer7);
++}
+diff -Nurp iptables-1.3.0-stock/extensions/libipt_layer7.man iptables-1.3.0-layer7/extensions/libipt_layer7.man
+--- iptables-1.3.0-stock/extensions/libipt_layer7.man  1969-12-31 18:00:00.000000000 -0600
++++ iptables-1.3.0-layer7/extensions/libipt_layer7.man 2005-03-01 22:12:06.000000000 -0600
+@@ -0,0 +1,13 @@
++This module matches packets based on the application layer data of 
++their connections.  It uses regular expression matching to compare 
++the application layer data to regular expressions found it the layer7 
++configuration files.  This is an experimental module which can be found at 
++http://l7-filter.sf.net.  It takes two options.
++.TP
++.BI "--l7proto " "\fIprotocol\fP"
++Match the specified protocol.  The protocol name must match a file 
++name in /etc/l7-protocols/
++.TP
++.BI "--l7dir " "\fIdirectory\fP"
++Use \fIdirectory\fP instead of /etc/l7-protocols/
++
+--- iptables-1.3.1/extensions/Makefile.orig    2005-04-01 23:02:50.000000000 +0200
++++ iptables-1.3.1/extensions/Makefile 2005-04-01 23:03:06.000000000 +0200
+@@ -11,6 +11,8 @@
+ # ipp2p
+ PF_EXT_SLIB += ipp2p
++# layer7
++PF_EXT_SLIB += layer7
+ # Optionals
+ PF_EXT_SLIB_OPTS:=$(foreach T,$(wildcard extensions/.*-test),$(shell KERNEL_DIR=$(KERNEL_DIR) $(T)))
diff --git a/openwrt/package/iptables/patches/ipp2p-0.7.4.patch b/openwrt/package/iptables/patches/ipp2p-0.7.4.patch
deleted file mode 100644 (file)
index d39a39d..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-diff -urN iptables-1.2.11.old/extensions/libipt_ipp2p.c iptables-1.2.11/extensions/libipt_ipp2p.c
---- iptables-1.2.11.old/extensions/libipt_ipp2p.c      1970-01-01 01:00:00.000000000 +0100
-+++ iptables-1.2.11/extensions/libipt_ipp2p.c  2005-03-12 00:50:27.000000000 +0100
-@@ -0,0 +1,455 @@
-+
-+#include <stdio.h>
-+#include <netdb.h>
-+#include <string.h>
-+#include <stdlib.h>
-+#include <getopt.h>
-+#include <ctype.h>
-+
-+#include <iptables.h>
-+
-+#include <linux/netfilter_ipv4/ipt_ipp2p.h>
-+
-+
-+
-+
-+static void
-+help(void)
-+{
-+    printf(
-+    "IPP2P v%s options:\n"
-+    " --ipp2p Grab all known p2p packets\n"
-+    " --ipp2p-data    Identify all known p2p download commands (obsolete)\n\n"
-+    " --edk           [TCP&UDP]       All known eDonkey/eMule/Overnet packets\n"
-+    " --dc            [TCP]           All known Direct Connect packets\n"
-+    " --kazaa [TCP&UDP]       All known KaZaA packets\n"
-+    " --gnu           [TCP&UDP]       All known Gnutella packets\n"
-+    " --bit           [TCP&UDP]       All known BitTorrent packets\n"
-+    " --apple [TCP]           All known AppleJuice packets (beta - just a few tests until now)\n"
-+    " --winmx [TCP]           All known WinMX (beta - need feedback)\n"
-+    " --soul          [TCP]           All known SoulSeek (beta - need feedback!)\n"
-+    " --ares          [TCP]           All known Ares - use with DROP only (beta - need feedback!)\n\n"
-+    " --edk-data      [TCP]           eDonkey/eMule/Overnet download commands (obsolete)\n"
-+    " --dc-data       [TCP]           Direct Connect download command (obsolete)\n"
-+    " --kazaa-data    [TCP]           KaZaA download command (obsolete)\n"
-+    " --gnu-data      [TCP]           Gnutella download command (obsolete)\n"
-+    "\nNote that the follwing options will have the same meaning:\n"
-+    " '--ipp2p' is equal to '--edk --dc --kazaa --gnu'\n"
-+    " '--ipp2p-data' is equal to '--edk-data --dc-data --kazaa-data --gnu-data'\n"
-+    "\nIPP2P was intended for TCP only. Due to increasing usage of UDP we needed to change this.\n"
-+    "You can now use -p udp to search UDP packets only or without -p switch to search UDP and TCP packets.\n"
-+    "\nSee README included with this package for more details or visit http://www.ipp2p.org\n"
-+    "\nExamples:\n"
-+    " iptables -A FORWARD -m ipp2p --ipp2p -j MARK --set-mark 0x01\n"
-+    " iptables -A FORWARD -p udp -m ipp2p --kazaa --bit -j DROP\n"
-+    " iptables -A FORWARD -p tcp -m ipp2p --edk --soul -j DROP\n\n"
-+    , IPP2P_VERSION);
-+}
-+
-+                                                          
-+
-+static struct option opts[] = {
-+        { "ipp2p", 0, 0, '1' },
-+        { "edk", 0, 0, '2' }, 
-+        { "ipp2p-data", 0, 0, '3' },          
-+        { "kazaa-data", 0, 0, '4' },
-+        { "edk-data", 0, 0, '5' },    
-+        { "dc-data", 0, 0, '6' },
-+      { "dc", 0, 0, '7' },
-+      { "gnu-data", 0, 0, '8' },      
-+      { "gnu", 0, 0, '9' },
-+      { "kazaa", 0, 0, 'a' },
-+      { "bit", 0, 0, 'b' },
-+      { "apple", 0, 0, 'c' }, 
-+      { "soul", 0, 0, 'd' },  
-+      { "winmx", 0, 0, 'e' }, 
-+      { "ares", 0, 0, 'f' },
-+      { "debug", 0, 0, 'g' },
-+        {0}
-+};
-+
-+      
-+
-+static void
-+init(struct ipt_entry_match *m, unsigned int *nfcache)
-+{
-+    struct ipt_p2p_info *info = (struct ipt_p2p_info *)m->data;
-+
-+    *nfcache |= NFC_UNKNOWN;
-+
-+    /*init the module with default values*/
-+    info->cmd = 0;
-+    info->debug = 0;
-+
-+}
-+      
-+
-+static int
-+parse(int c, char **argv, int invert, unsigned int *flags,
-+      const struct ipt_entry *entry,
-+      unsigned int *nfcache,
-+      struct ipt_entry_match **match)
-+{
-+    struct ipt_p2p_info *info = (struct ipt_p2p_info *)(*match)->data;
-+    
-+    switch (c) {
-+      case '1':               /*cmd: ipp2p*/
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified once!");
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+          if ((*flags) != 0)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+          *flags += SHORT_HAND_IPP2P;
-+          info->cmd = *flags;
-+          break;
-+          
-+      case '2':               /*cmd: edk*/
-+          if ((*flags & IPP2P_EDK) == IPP2P_EDK)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--edk' may only be "
-+                              "specified once");
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+            if ((*flags & IPP2P_DATA_EDK) == IPP2P_DATA_EDK)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: use `--edk' OR `--edk-data' but not both of them!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+          *flags += IPP2P_EDK;
-+          info->cmd = *flags;     
-+          break;
-+
-+      case '3':               /*cmd: ipp2p-data*/
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified once!");
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+          if ((*flags) != 0)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+          *flags += SHORT_HAND_DATA;
-+          info->cmd = *flags;     
-+          break;
-+
-+        case '4':             /*cmd: kazaa-data*/
-+            if ((*flags & IPP2P_DATA_KAZAA) == IPP2P_DATA_KAZAA)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--kazaa-data' may only be "
-+                                "specified once!");
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+            if ((*flags & IPP2P_KAZAA) == IPP2P_KAZAA)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: use `--kazaa' OR `--kazaa-data' but not both of them!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_DATA_KAZAA;
-+          info->cmd = *flags;
-+          break;
-+
-+      case '5':               /*cmd: edk-data*/
-+            if ((*flags & IPP2P_DATA_EDK) == IPP2P_DATA_EDK)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--edk-data' may only be "
-+                                "specified once!");
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+            if ((*flags & IPP2P_EDK) == IPP2P_EDK)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: use `--edk' OR `--edk-data' but not both of them!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_DATA_EDK;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+      case '6':               /*cmd: dc-data*/
-+            if ((*flags & IPP2P_DATA_DC) == IPP2P_DATA_DC)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--dc-data' may only be "
-+                                "specified once!");
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+            if ((*flags & IPP2P_DC) == IPP2P_DC)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: use `--dc' OR `--dc-data' but not both of them!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_DATA_DC;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+      case '7':               /*cmd: dc*/
-+            if ((*flags & IPP2P_DC) == IPP2P_DC)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--dc' may only be "
-+                                "specified once!");
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+            if ((*flags & IPP2P_DATA_DC) == IPP2P_DATA_DC)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: use `--dc' OR `--dc-data' but not both of them!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_DC;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+
-+      case '8':               /*cmd: gnu-data*/
-+            if ((*flags & IPP2P_DATA_GNU) == IPP2P_DATA_GNU)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--gnu-data' may only be "
-+                                "specified once!");
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+            if ((*flags & IPP2P_GNU) == IPP2P_GNU)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: use `--gnu' OR `--gnu-data' but not both of them!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_DATA_GNU;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+      case '9':               /*cmd: gnu*/
-+            if ((*flags & IPP2P_GNU) == IPP2P_GNU)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--gnu' may only be "
-+                                "specified once!");
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+            if ((*flags & IPP2P_DATA_GNU) == IPP2P_DATA_GNU)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: use `--gnu' OR `--gnu-data' but not both of them!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_GNU;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+      case 'a':               /*cmd: kazaa*/
-+            if ((*flags & IPP2P_KAZAA) == IPP2P_KAZAA)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--kazaa' may only be "
-+                                "specified once!");
-+          if ((*flags & SHORT_HAND_DATA) == SHORT_HAND_DATA)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p-data' may only be "
-+                              "specified alone!");
-+          if ((*flags & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P)
-+                  exit_error(PARAMETER_PROBLEM,
-+                              "ipp2p: `--ipp2p' may only be "
-+                              "specified alone!");
-+            if ((*flags & IPP2P_DATA_KAZAA) == IPP2P_DATA_KAZAA)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: use `--kazaa' OR `--kazaa-data' but not both of them!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_KAZAA;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+      case 'b':               /*cmd: bit*/
-+            if ((*flags & IPP2P_BIT) == IPP2P_BIT)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--bit' may only be "
-+                                "specified once!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_BIT;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+      case 'c':               /*cmd: apple*/
-+            if ((*flags & IPP2P_APPLE) == IPP2P_APPLE)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--apple' may only be "
-+                                "specified once!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_APPLE;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+
-+      case 'd':               /*cmd: soul*/
-+            if ((*flags & IPP2P_SOUL) == IPP2P_SOUL)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--soul' may only be "
-+                                "specified once!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_SOUL;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+
-+      case 'e':               /*cmd: winmx*/
-+            if ((*flags & IPP2P_WINMX) == IPP2P_WINMX)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--winmx' may only be "
-+                                "specified once!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_WINMX;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+      case 'f':               /*cmd: ares*/
-+            if ((*flags & IPP2P_ARES) == IPP2P_ARES)
-+            exit_error(PARAMETER_PROBLEM,
-+                                "ipp2p: `--ares' may only be "
-+                                "specified once!");
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+            *flags += IPP2P_ARES;
-+          info->cmd = *flags;
-+          break;                                                                                                                                                                                                                      
-+
-+      case 'g':               /*cmd: debug*/
-+          if (invert) exit_error(PARAMETER_PROBLEM, "ipp2p: invert [!] is not allowed!");
-+          info->debug = 1;
-+          break;                                                                                                                                                                                                                      
-+
-+      default:
-+            exit_error(PARAMETER_PROBLEM,
-+          "\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n");
-+          return 0;
-+    }
-+    return 1;
-+}
-+
-+
-+static void
-+final_check(unsigned int flags)
-+{
-+    if (!flags)
-+            exit_error(PARAMETER_PROBLEM,
-+          "\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n");
-+}
-+
-+
-+
-+static void
-+print(const struct ipt_ip *ip,
-+        const struct ipt_entry_match *match,
-+      int numeric)
-+{
-+    struct ipt_p2p_info *info = (struct ipt_p2p_info *)match->data;
-+    
-+    printf("ipp2p v%s", IPP2P_VERSION);
-+    if ((info->cmd & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P) printf(" --ipp2p");
-+    if ((info->cmd & SHORT_HAND_DATA) == SHORT_HAND_DATA) printf(" --ipp2p-data");
-+    if ((info->cmd & IPP2P_KAZAA) == IPP2P_KAZAA) printf(" --kazaa");
-+    if ((info->cmd & IPP2P_DATA_KAZAA) == IPP2P_DATA_KAZAA) printf(" --kazaa-data");
-+    if ((info->cmd & IPP2P_DATA_GNU) == IPP2P_DATA_GNU) printf(" --gnu-data");
-+    if ((info->cmd & IPP2P_GNU) == IPP2P_GNU) printf(" --gnu");
-+    if ((info->cmd & IPP2P_EDK) == IPP2P_EDK) printf(" --edk");
-+    if ((info->cmd & IPP2P_DATA_EDK) == IPP2P_DATA_EDK) printf(" --edk-data");
-+    if ((info->cmd & IPP2P_DATA_DC) == IPP2P_DATA_DC) printf(" --dc-data");
-+    if ((info->cmd & IPP2P_DC) == IPP2P_DC) printf(" --dc");
-+    if ((info->cmd & IPP2P_BIT) == IPP2P_BIT) printf(" --bit");
-+    if ((info->cmd & IPP2P_APPLE) == IPP2P_APPLE) printf(" --apple");
-+    if ((info->cmd & IPP2P_SOUL) == IPP2P_SOUL) printf(" --soul");
-+    if ((info->cmd & IPP2P_WINMX) == IPP2P_WINMX) printf(" --winmx");
-+    if ((info->cmd & IPP2P_ARES) == IPP2P_ARES) printf(" --ares");
-+    if (info->debug != 0) printf(" --debug");
-+    printf(" ");
-+}
-+                                                                         
-+
-+
-+static void
-+save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
-+{
-+    struct ipt_p2p_info *info = (struct ipt_p2p_info *)match->data;
-+    
-+    if ((info->cmd & SHORT_HAND_IPP2P) == SHORT_HAND_IPP2P) printf("--ipp2p ");
-+    if ((info->cmd & SHORT_HAND_DATA) == SHORT_HAND_DATA) printf("--ipp2p-data ");
-+    if ((info->cmd & IPP2P_KAZAA) == IPP2P_KAZAA) printf("--kazaa ");
-+    if ((info->cmd & IPP2P_DATA_KAZAA) == IPP2P_DATA_KAZAA) printf("--kazaa-data ");
-+    if ((info->cmd & IPP2P_DATA_GNU) == IPP2P_DATA_GNU) printf("--gnu-data ");
-+    if ((info->cmd & IPP2P_GNU) == IPP2P_GNU) printf("--gnu ");
-+    if ((info->cmd & IPP2P_EDK) == IPP2P_EDK) printf("--edk ");
-+    if ((info->cmd & IPP2P_DATA_EDK) == IPP2P_DATA_EDK) printf("--edk-data ");
-+    if ((info->cmd & IPP2P_DATA_DC) == IPP2P_DATA_DC) printf("--dc-data ");
-+    if ((info->cmd & IPP2P_DC) == IPP2P_DC) printf("--dc ");
-+    if ((info->cmd & IPP2P_BIT) == IPP2P_BIT) printf("--bit ");
-+    if ((info->cmd & IPP2P_APPLE) == IPP2P_APPLE) printf("--apple ");
-+    if ((info->cmd & IPP2P_SOUL) == IPP2P_SOUL) printf("--soul ");
-+    if ((info->cmd & IPP2P_WINMX) == IPP2P_WINMX) printf("--winmx ");
-+    if ((info->cmd & IPP2P_ARES) == IPP2P_ARES) printf("--ares ");
-+    if (info->debug != 0) printf("--debug ");
-+}
-+
-+              
-+
-+
-+static 
-+struct iptables_match ipp2p= 
-+{ 
-+    .next           = NULL,
-+    .name           = "ipp2p",
-+    .version        = IPTABLES_VERSION,
-+    .size           = IPT_ALIGN(sizeof(struct ipt_p2p_info)),
-+    .userspacesize  = IPT_ALIGN(sizeof(struct ipt_p2p_info)),
-+    .help           = &help,
-+    .init           = &init,
-+    .parse          = &parse,
-+    .final_check    = &final_check,
-+    .print          = &print,
-+    .save           = &save,
-+    .extra_opts     = opts
-+};
-+                                          
-+
-+
-+void _init(void)
-+{
-+    register_match(&ipp2p);
-+}
-+
-diff -urN iptables-1.2.11.old/extensions/Makefile iptables-1.2.11/extensions/Makefile
---- iptables-1.2.11.old/extensions/Makefile    2004-06-17 12:22:54.000000000 +0200
-+++ iptables-1.2.11/extensions/Makefile        2005-03-12 00:50:12.000000000 +0100
-@@ -8,6 +8,10 @@
- PF_EXT_SLIB:=ah connlimit connmark conntrack dscp ecn esp helper icmp iprange length limit mac mark multiport owner physdev pkttype realm rpc sctp standard state tcp tcpmss tos ttl udp unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE MIRROR NETMAP NOTRACK REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TRACE TTL ULOG
- PF6_EXT_SLIB:=eui64 hl icmpv6 length limit mac mark multiport owner standard tcp udp HL LOG MARK TRACE
-+
-+# ipp2p
-+PF_EXT_SLIB += ipp2p
-+
- # Optionals
- PF_EXT_SLIB_OPTS:=$(foreach T,$(wildcard extensions/.*-test),$(shell KERNEL_DIR=$(KERNEL_DIR) $(T)))
- PF6_EXT_SLIB_OPTS:=$(foreach T,$(wildcard extensions/.*-test6),$(shell KERNEL_DIR=$(KERNEL_DIR) $(T)))
-diff -urN iptables-1.2.11.old/include/linux/netfilter_ipv4/ipt_ipp2p.h iptables-1.2.11/include/linux/netfilter_ipv4/ipt_ipp2p.h
---- iptables-1.2.11.old/include/linux/netfilter_ipv4/ipt_ipp2p.h       1970-01-01 01:00:00.000000000 +0100
-+++ iptables-1.2.11/include/linux/netfilter_ipv4/ipt_ipp2p.h   2005-03-12 00:50:46.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 --git a/openwrt/package/linux/kernel-patches/306-netfilter-layer7-0.9.1 b/openwrt/package/linux/kernel-patches/306-netfilter-layer7-0.9.1
new file mode 100644 (file)
index 0000000..4dd1fce
--- /dev/null
@@ -0,0 +1,2022 @@
+diff -Nurp linux-2.4.26-stock/Documentation/Configure.help linux-2.4.26-layer7-clean/Documentation/Configure.help
+--- linux-2.4.26-stock/Documentation/Configure.help    2004-04-14 08:05:24.000000000 -0500
++++ linux-2.4.26-layer7-clean/Documentation/Configure.help     2004-06-21 00:18:14.000000000 -0500
+@@ -28819,6 +28819,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.26-stock/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.26-layer7-clean/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.4.26-stock/include/linux/netfilter_ipv4/ip_conntrack.h     2004-04-14 08:05:40.000000000 -0500
++++ linux-2.4.26-layer7-clean/include/linux/netfilter_ipv4/ip_conntrack.h      2004-06-21 00:18:28.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.26-stock/include/linux/netfilter_ipv4/ipt_layer7.h linux-2.4.26-layer7-clean/include/linux/netfilter_ipv4/ipt_layer7.h
+--- linux-2.4.26-stock/include/linux/netfilter_ipv4/ipt_layer7.h       1969-12-31 18:00:00.000000000 -0600
++++ linux-2.4.26-layer7-clean/include/linux/netfilter_ipv4/ipt_layer7.h        2004-06-21 00:18:28.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.26-stock/net/ipv4/netfilter/Config.in linux-2.4.26-layer7-clean/net/ipv4/netfilter/Config.in
+--- linux-2.4.26-stock/net/ipv4/netfilter/Config.in    2003-08-25 06:44:44.000000000 -0500
++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/Config.in     2004-06-21 00:15:23.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.26-stock/net/ipv4/netfilter/Makefile linux-2.4.26-layer7-clean/net/ipv4/netfilter/Makefile
+--- linux-2.4.26-stock/net/ipv4/netfilter/Makefile     2003-08-25 06:44:44.000000000 -0500
++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/Makefile      2004-06-21 00:15:22.000000000 -0500
+@@ -87,6 +87,8 @@ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += i
+ 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
+ obj-$(CONFIG_IP_NF_TARGET_MIRROR) += ipt_MIRROR.o
+diff -Nurp linux-2.4.26-stock/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux-2.4.26-stock/net/ipv4/netfilter/ip_conntrack_core.c  2004-02-18 07:36:32.000000000 -0600
++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/ip_conntrack_core.c   2004-06-21 00:15:22.000000000 -0500
+@@ -339,6 +339,15 @@ destroy_conntrack(struct nf_conntrack *n
+               }
+               kfree(ct->master);
+       }
++
++      #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++      /* This ought to get free'd somewhere.  How about here? */
++      if(ct->layer7.app_proto) /* this is sufficient, right? */
++              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.26-stock/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux-2.4.26-stock/net/ipv4/netfilter/ip_conntrack_standalone.c    2004-02-18 07:36:32.000000000 -0600
++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/ip_conntrack_standalone.c     2004-06-21 00:15:22.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.26-stock/net/ipv4/netfilter/ipt_layer7.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/ipt_layer7.c
+--- linux-2.4.26-stock/net/ipv4/netfilter/ipt_layer7.c 1969-12-31 18:00:00.000000000 -0600
++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/ipt_layer7.c  2004-06-27 19:06:51.000000000 -0500
+@@ -0,0 +1,540 @@
++/* 
++  Kernel module to match application layer (OSI layer 7) 
++  data in connections.
++  
++  http://l7-filter.sf.net
++
++  By Matthew Strait and Ethan Sommer, 2003.
++
++  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 "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
++
++/* 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 is going to write to /proc/net/layer7_numpackets over and over
++  within a short period of time, and if they did, nothing awful would happen.
++
++- This code will never be processing the same packet twice at the same time,
++  because iptables rules need to be 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, the things we have to protect are the conntracks and
++  the list of compiled patterns.
++*/
++DECLARE_RWLOCK(ct_lock);
++DECLARE_LOCK(list_lock);
++
++/* 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) {
++              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);
++
++      if(!tmp->regex_string || !tmp->pattern) {
++              printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n");
++              kfree(tmp->regex_string);
++              kfree(tmp->pattern);
++              kfree(tmp);
++              return NULL;
++      }
++
++        tmp->next = 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);
++      node->pattern = regcomp(regex_string, &len);
++        if ( !node->pattern ) {
++                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;
++}
++
++#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) {
++               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:
++                      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) {
++               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
++
++
++/* The following functions are here in case we get ported into an environment
++(ebtables?) where skb->nh.iph->protocol isn't set. They assume that skb->data
++points at the beginning of the IP datagram, which is true for iptables (but in
++QoS it points to the beginning of the Ethernet frame). */
++#if 0
++#define IP_PROTO_OFFSET 9
++static int is_tcp_over_ipv4 (const struct sk_buff *skb){return(skb->data[IP_PROTO_OFFSET]==IPPROTO_TCP );}
++static int is_udp_over_ipv4 (const struct sk_buff *skb){return(skb->data[IP_PROTO_OFFSET]==IPPROTO_UDP );}
++static int is_icmp_over_ipv4(const struct sk_buff *skb){return(skb->data[IP_PROTO_OFFSET]==IPPROTO_ICMP);}
++#endif
++
++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 {
++                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,
++                      struct ipt_layer7_info * info)
++{
++      /* If we're in here, we don't care about the app data anymore */
++      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("\nGave up on the %d length stream: \n%s\n",
++                             master_conntrack->layer7.app_data_len, f);
++                      DPRINTK("\nIn hex: %s\n", g);
++                              kfree(f);
++                      kfree(g);
++                      }
++                      #endif
++
++              kfree(master_conntrack->layer7.app_data);
++              master_conntrack->layer7.app_data = NULL; /* don't free again */
++      }
++      WRITE_UNLOCK(&ct_lock);
++
++      /* Is top-level master (possibly self) classified? */
++      if(master_conntrack->layer7.app_proto) { 
++              if(!strcmp(master_conntrack->layer7.app_proto, info->protocol))
++              {
++                      /* set own .protocol (for /proc/net/ip_conntrack) */
++                      WRITE_LOCK(&ct_lock);
++                      if(!conntrack->layer7.app_proto) {
++                              conntrack->layer7.app_proto = kmalloc(strlen(info->protocol), GFP_ATOMIC);
++                                if(!conntrack->layer7.app_proto){
++                                       printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n");
++                                       WRITE_UNLOCK(&ct_lock);
++                                       return 1;
++                                }
++
++                              strcpy(conntrack->layer7.app_proto, info->protocol);
++                      }
++                      WRITE_UNLOCK(&ct_lock);
++      
++                      return 1;
++              } else return 0;
++      } else return 0; /* no clasification */
++}
++
++/* 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;
++      }
++
++      LOCK_BH(&list_lock);
++      comppattern = compile_and_cache(info->pattern, info->protocol);
++      UNLOCK_BH(&list_lock);
++      /* the return value gets checked later, when we're ready to use it */
++
++      app_data = skb->data + app_data_offset(skb);
++      appdatalen = skb->tail - app_data;
++
++      /* Treat the parent and all its children together as one connection, 
++      except for the purpose of setting conntrack->layer7.pattern 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);
++
++      /* skb->cb[0] == seen. Avoid doing things twice if there are two layer7 
++      rules. I'm not sure that using cb for this purpose is correct, although 
++      it says "put your private variables there" and this seems to qualify.  
++      But it doesn't look like it's being used for anything else in the 
++      sk_buffs that make it here. I'm open to suggestions for how to be able 
++      to write to cb without making the compiler angry.  That I can't figure 
++      this out is an argument against this being correct. */
++      if(!skb->cb[0]){
++              WRITE_LOCK(&ct_lock);
++              master_conntrack->layer7.numpackets++;/*starts at 0 via memset*/
++              WRITE_UNLOCK(&ct_lock);
++      }
++
++      /* On the first packet of a connection, allocate space for app data */
++      WRITE_LOCK(&ct_lock);
++      if(master_conntrack->layer7.numpackets == 1 && !skb->cb[0]) {
++              master_conntrack->layer7.app_data = kmalloc(CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN, GFP_ATOMIC);
++                if(!master_conntrack->layer7.app_data){                                                         
++                        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);
++
++      /* if we've classified it or seen too many packets */
++      if(master_conntrack->layer7.numpackets > num_packets || 
++         master_conntrack->layer7.app_proto) {
++      
++              pattern_result = match_no_append(conntrack, master_conntrack, info);
++      
++              /* mark the packet seen (probably irrelevant, but consistant) */
++              skb->cb[0] = 1;
++
++              return (pattern_result ^ info->invert);
++      }
++      
++      /* Can end up here, but unallocated, if numpackets is increased during 
++      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 the regexp failed to compile, don't bother running it */
++      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);
++              conntrack->layer7.app_proto = kmalloc(strlen(info->protocol), GFP_ATOMIC);
++                if(!conntrack->layer7.app_proto){
++                        printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
++                        WRITE_UNLOCK(&ct_lock);
++                        return (pattern_result ^ info->invert);
++                        }
++ 
++              strcpy(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)
++                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){
++                printk(KERN_ERR "layer7: out of memory, bailing.  num_packets unchanged.\n");
++                return count;
++        }
++
++        /* copy in the data from userland */
++        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;
++
++        /* create the file */
++        entry = create_proc_entry("layer7_numpackets", 0644, proc_net);
++
++        /* set the callback functions */
++      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.26-stock/net/ipv4/netfilter/regexp/regexp.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regexp.c
+--- linux-2.4.26-stock/net/ipv4/netfilter/regexp/regexp.c      1969-12-31 18:00:00.000000000 -0600
++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regexp.c       2004-06-27 19:07:00.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; &regdummy = 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 = &regdummy;
++      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 == &regdummy) {
++              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 != &regdummy)
++              *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 == &regdummy) {
++              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 == &regdummy)
++              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 == &regdummy || 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 == &regdummy)
++              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.26-stock/net/ipv4/netfilter/regexp/regexp.h linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regexp.h
+--- linux-2.4.26-stock/net/ipv4/netfilter/regexp/regexp.h      1969-12-31 18:00:00.000000000 -0600
++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regexp.h       2004-06-27 19:07:00.000000000 -0500
+@@ -0,0 +1,27 @@
++/*
++ * 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
++
++#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.26-stock/net/ipv4/netfilter/regexp/regmagic.h linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regmagic.h
+--- linux-2.4.26-stock/net/ipv4/netfilter/regexp/regmagic.h    1969-12-31 18:00:00.000000000 -0600
++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regmagic.h     2004-06-27 19:07:00.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.26-stock/net/ipv4/netfilter/regexp/regsub.c linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regsub.c
+--- linux-2.4.26-stock/net/ipv4/netfilter/regexp/regsub.c      1969-12-31 18:00:00.000000000 -0600
++++ linux-2.4.26-layer7-clean/net/ipv4/netfilter/regexp/regsub.c       2004-06-27 19:07:00.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';
++}
index fdef565..f636f8c 100644 (file)
@@ -373,6 +373,9 @@ CONFIG_IP_NF_MATCH_STATE=y
 CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_UNCLEAN=m
 # CONFIG_IP_NF_MATCH_OWNER is not set
 CONFIG_IP_NF_MATCH_CONNTRACK=m
 CONFIG_IP_NF_MATCH_UNCLEAN=m
 # CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN=2048
 # CONFIG_IP_NF_MATCH_PHYSDEV is not set
 CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
 # CONFIG_IP_NF_MATCH_PHYSDEV is not set
 CONFIG_IP_NF_FILTER=y
 CONFIG_IP_NF_TARGET_REJECT=y
This page took 0.106692 seconds and 4 git commands to generate.