From f71d418315f9efac495af5dcec0e750d195486ea Mon Sep 17 00:00:00 2001
From: nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Sat, 18 Mar 2006 17:27:20 +0000
Subject: [PATCH] precompile ppp active filter (reduces libpcap overhead to
 only a few k), enable by default to support proper demand dialling, fixes
 #307

git-svn-id: svn://svn.openwrt.org/openwrt/trunk/openwrt@3401 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 package/ppp/Config.in                         |   5 +-
 package/ppp/Makefile                          |   8 +-
 package/ppp/files/etc/ppp/filter              |  23 ++
 package/ppp/files/ifup.pppoa                  |   1 +
 package/ppp/files/ifup.pppoe                  |   1 +
 .../ppp/patches/310-precompiled_filter.patch  | 231 ++++++++++++++++++
 package/ppp/utils/pfc.c                       |  51 ++++
 package/pptp/files/ifup.pptp                  |   1 +
 8 files changed, 316 insertions(+), 5 deletions(-)
 create mode 100644 package/ppp/files/etc/ppp/filter
 create mode 100644 package/ppp/patches/310-precompiled_filter.patch
 create mode 100644 package/ppp/utils/pfc.c

diff --git a/package/ppp/Config.in b/package/ppp/Config.in
index 0dda3cc83..21139adf7 100644
--- a/package/ppp/Config.in
+++ b/package/ppp/Config.in
@@ -8,10 +8,9 @@ config BR2_PACKAGE_PPP
 	select BR2_PACKAGE_KMOD_PPP
 
 config BR2_PACKAGE_PPP_WITH_FILTER
-        prompt "Enable filter support"
+	prompt "Enable filter support"
 	bool
-	default n
-	depends BR2_PACKAGE_LIBPCAP
+	default y
 
 config BR2_PACKAGE_PPP_MOD_PPPOA
 	prompt   "ppp-mod-pppoa................... PPPoA (PPP over ATM) plugin"
diff --git a/package/ppp/Makefile b/package/ppp/Makefile
index d98d7e5cb..e63fa4cf5 100644
--- a/package/ppp/Makefile
+++ b/package/ppp/Makefile
@@ -41,8 +41,7 @@ $(eval $(call PKG_mod_template,PPP_MOD_RADIUS,radius))
 
 PKG_DEPEND:="kmod-ppp"
 ifeq ($(BR2_PACKAGE_PPP_WITH_FILTER),y)
-ENABLE_FILTER:="FILTER=1"
-PKG_DEPEND += ", libpcap"
+ENABLE_FILTER:="PRECOMPILED_FILTER=1"
 endif
 
 $(PKG_BUILD_DIR)/.configured:
@@ -85,11 +84,16 @@ $(PKG_BUILD_DIR)/.built:
 		all install
 	touch $@
 
+ifeq ($(BR2_PACKAGE_PPP_WITH_FILTER),y)
+INSTALL_FILTER=install -m0644 ./files/etc/ppp/filter $(IDIR_PPP)/etc/ppp/
+endif
+
 $(IPKG_PPP):
 	install -d -m0755 $(IDIR_PPP)/etc/ppp
 	ln -sf /tmp/resolv.conf $(IDIR_PPP)/etc/ppp/resolv.conf
 	install -m0600 ./files/etc/ppp/chap-secrets $(IDIR_PPP)/etc/ppp/
 	install -m0644 ./files/etc/ppp/options $(IDIR_PPP)/etc/ppp/
+	$(INSTALL_FILTER)
 	install -m0755 ./files/etc/ppp/ip-up $(IDIR_PPP)/etc/ppp/
 	install -m0755 ./files/etc/ppp/ip-down $(IDIR_PPP)/etc/ppp/
 	install -d -m0755 $(IDIR_PPP)/usr/sbin
diff --git a/package/ppp/files/etc/ppp/filter b/package/ppp/files/etc/ppp/filter
new file mode 100644
index 000000000..ec72a81a0
--- /dev/null
+++ b/package/ppp/files/etc/ppp/filter
@@ -0,0 +1,23 @@
+#
+# Expression: outbound and not icmp[0] != 8 and not tcp[13] & 4 != 0
+#
+19
+48 0 0 0
+21 0 16 1
+40 0 0 2
+21 0 13 33
+48 0 0 13
+21 0 5 1
+40 0 0 10
+69 9 0 8191
+177 0 0 4
+80 0 0 4
+21 6 7 8
+21 0 5 6
+40 0 0 10
+69 3 0 8191
+177 0 0 4
+80 0 0 17
+69 1 0 4
+6 0 0 4
+6 0 0 0
diff --git a/package/ppp/files/ifup.pppoa b/package/ppp/files/ifup.pppoa
index 2ae6019c5..baea25ebf 100644
--- a/package/ppp/files/ifup.pppoa
+++ b/package/ppp/files/ifup.pppoa
@@ -25,6 +25,7 @@ case "$DEMAND" in
 	on|1|enabled)
 		DEMAND=$(nvram get ppp_idletime)
 		DEMAND=${IDLETIME:+demand idle $IDLETIME}
+		[ -f /etc/ppp/filter ] && DEMAND=${DEMAND:+precompiled-active-filter /etc/ppp/filter $DEMAND}
 	;;
 	*) DEMAND="persist";;
 esac
diff --git a/package/ppp/files/ifup.pppoe b/package/ppp/files/ifup.pppoe
index d4a79aedd..1f9cd739c 100644
--- a/package/ppp/files/ifup.pppoe
+++ b/package/ppp/files/ifup.pppoe
@@ -24,6 +24,7 @@ case "$DEMAND" in
 	on|1|enabled)
 		DEMAND=$(nvram get ppp_idletime)
 		DEMAND=${IDLETIME:+demand idle $IDLETIME}
+		[ -f /etc/ppp/filter ] && DEMAND=${DEMAND:+precompiled-active-filter /etc/ppp/filter $DEMAND}
 	;;
 	*) DEMAND="persist";;
 esac
diff --git a/package/ppp/patches/310-precompiled_filter.patch b/package/ppp/patches/310-precompiled_filter.patch
new file mode 100644
index 000000000..df9452c37
--- /dev/null
+++ b/package/ppp/patches/310-precompiled_filter.patch
@@ -0,0 +1,231 @@
+diff -urN ppp.old/pppd/Makefile.linux ppp.dev/pppd/Makefile.linux
+--- ppp.old/pppd/Makefile.linux	2006-03-18 15:58:00.000000000 +0100
++++ ppp.dev/pppd/Makefile.linux	2006-03-18 16:52:01.000000000 +0100
+@@ -50,6 +50,9 @@
+ # and that the kernel driver support PPP packet filtering.
+ #FILTER=y
+ 
++# Support for precompiled filters
++PRECOMPILED_FILTER=y
++
+ # Uncomment the next line to enable multilink PPP (enabled by default)
+ # Linux distributions: Please leave multilink ENABLED in your builds
+ # of pppd!
+@@ -177,6 +180,14 @@
+ endif
+ endif
+ 
++ifdef PRECOMPILED_FILTER
++PPPDSRCS += pcap_pcc.c
++HEADERS  += pcap_pcc.h
++PPPDOBJS += pcap_pcc.o
++LIBS	+= $(STAGING_DIR)/usr/lib/libpcap.a
++CFLAGS	+= -DPPP_FILTER -DPPP_PRECOMPILED_FILTER -I$(STAGING_DIR)/usr/include
++endif
++
+ ifdef HAVE_INET6
+      PPPDSRCS += ipv6cp.c eui64.c
+      HEADERS  += ipv6cp.h eui64.h
+diff -urN ppp.old/pppd/demand.c ppp.dev/pppd/demand.c
+--- ppp.old/pppd/demand.c	2006-03-18 15:58:00.000000000 +0100
++++ ppp.dev/pppd/demand.c	2006-03-18 18:09:16.000000000 +0100
+@@ -438,12 +438,14 @@
+ 	return 0;
+     proto = PPP_PROTOCOL(p);
+ #ifdef PPP_FILTER
++	*p = 1; /* set outbound for the filter rule */
+     if (pass_filter.bf_len != 0
+ 	&& bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
+ 	return 0;
+     if (active_filter.bf_len != 0
+ 	&& bpf_filter(active_filter.bf_insns, p, len, len) == 0)
+ 	return 0;
++	*p = 0xff; /* restore original ppp header */
+ #endif
+     for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+ 	if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
+diff -urN ppp.old/pppd/options.c ppp.dev/pppd/options.c
+--- ppp.old/pppd/options.c	2006-03-18 15:58:00.000000000 +0100
++++ ppp.dev/pppd/options.c	2006-03-18 18:05:58.000000000 +0100
+@@ -57,14 +57,7 @@
+ 
+ #ifdef PPP_FILTER
+ #include <pcap.h>
+-/*
+- * DLT_PPP_WITH_DIRECTION is in current libpcap cvs, and should be in
+- * libpcap-0.8.4.  Until that is released, use DLT_PPP - but that means
+- * we lose the inbound and outbound qualifiers.
+- */
+-#ifndef DLT_PPP_WITH_DIRECTION
+-#define DLT_PPP_WITH_DIRECTION	DLT_PPP
+-#endif
++#include <pcap-bpf.h>
+ #endif
+ 
+ #include "pppd.h"
+@@ -155,6 +148,13 @@
+ static int loadplugin __P((char **));
+ #endif
+ 
++#ifdef PPP_PRECOMPILED_FILTER
++#include "pcap_pcc.h"
++static int setprecompiledpassfilter __P((char **));
++static int setprecompiledactivefilter __P((char **));
++#undef PPP_FILTER
++#endif
++
+ #ifdef PPP_FILTER
+ static int setpassfilter __P((char **));
+ static int setactivefilter __P((char **));
+@@ -312,6 +312,14 @@
+       "set filter for active pkts", OPT_PRIO },
+ #endif
+ 
++#ifdef PPP_PRECOMPILED_FILTER
++    { "precompiled-pass-filter", 1, setprecompiledpassfilter,
++      "set precompiled filter for packets to pass", OPT_PRIO },
++
++    { "precompiled-active-filter", 1, setprecompiledactivefilter,
++      "set precompiled filter for active pkts", OPT_PRIO },
++#endif
++
+ #ifdef MAXOCTETS
+     { "maxoctets", o_int, &maxoctets,
+       "Set connection traffic limit",
+@@ -1447,6 +1455,29 @@
+     return ok;
+ }
+ 
++#ifdef PPP_PRECOMPILED_FILTER
++/*
++ * setprecompiledpassfilter - Set the pass filter for packets using a
++ * precompiled expression
++ */
++static int
++setprecompiledpassfilter(argv)
++    char **argv;
++{
++    return pcap_pre_compiled (*argv, &pass_filter);
++}
++
++/*
++ * setactivefilter - Set the active filter for packets
++ */
++static int
++setprecompiledactivefilter(argv)
++    char **argv;
++{
++    return pcap_pre_compiled (*argv, &active_filter);
++}
++#endif
++
+ #ifdef PPP_FILTER
+ /*
+  * setpassfilter - Set the pass filter for packets
+@@ -1458,7 +1489,7 @@
+     pcap_t *pc;
+     int ret = 0;
+ 
+-    pc = pcap_open_dead(DLT_PPP_WITH_DIRECTION, 65535);
++    pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
+     if (pcap_compile(pc, &pass_filter, *argv, 1, netmask) == -1) {
+ 	option_error("error in pass-filter expression: %s\n",
+ 		     pcap_geterr(pc));
+@@ -1479,7 +1510,7 @@
+     pcap_t *pc;
+     int ret = 0;
+ 
+-    pc = pcap_open_dead(DLT_PPP_WITH_DIRECTION, 65535);
++    pc = pcap_open_dead(DLT_PPP_PPPD, 65535);
+     if (pcap_compile(pc, &active_filter, *argv, 1, netmask) == -1) {
+ 	option_error("error in active-filter expression: %s\n",
+ 		     pcap_geterr(pc));
+diff -urN ppp.old/pppd/pcap_pcc.c ppp.dev/pppd/pcap_pcc.c
+--- ppp.old/pppd/pcap_pcc.c	1970-01-01 01:00:00.000000000 +0100
++++ ppp.dev/pppd/pcap_pcc.c	2006-03-18 16:51:31.000000000 +0100
+@@ -0,0 +1,74 @@
++#include <pcap.h>
++#include <pcap-bpf.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include "pppd.h"
++
++int pcap_pre_compiled (char * fname, struct bpf_program *p)
++{
++    char buf[128];
++    int line = 0, size = 0, index=0, ret=1;
++    FILE *f = fopen (fname, "r");
++    if (!f)
++    {
++       option_error("error opening precompiled active-filter '%s': %s",
++                    fname, strerror (errno));
++       return 0;
++    }
++    while (fgets (buf, 127, f))
++    {
++       line++;
++       if (*buf == '#')
++           continue;
++       if (size)
++       {
++           /*
++             struct bpf_insn {
++             u_short   code;
++             u_char    jt;
++             u_char    jf;
++             bpf_int32 k;
++             }
++           */
++           struct bpf_insn * insn = & p->bf_insns[index];
++           unsigned code, jt, jf, k;
++           if (sscanf (buf, "%u %u %u %u", &code, &jt, &jf, &k) != 4)
++           {
++               goto err;
++           }
++           insn->code = code;
++           insn->jt = jt;
++           insn->jf = jf;
++           insn->k  = k;
++           index++;
++       }
++       else
++       {
++           if (sscanf (buf, "%u", &size) != 1)
++           {
++               goto err;
++           }
++           p->bf_len = size;
++           p->bf_insns = (struct bpf_insn *) 
++               malloc (size * sizeof (struct bpf_insn));
++       }
++    } 
++    if (size != index)
++    {
++       option_error("error in precompiled active-filter,"
++                    " expected %d expressions, got %dn",
++                    size, index);
++       ret = 0;
++    }
++    fclose(f);
++    return ret;
++
++err:
++  option_error("error in precompiled active-filter"
++              " expression line %s:%d (wrong size)\n", 
++              fname, line);
++  fclose (f);
++  return 0;
++}
+diff -urN ppp.old/pppd/pcap_pcc.h ppp.dev/pppd/pcap_pcc.h
+--- ppp.old/pppd/pcap_pcc.h	1970-01-01 01:00:00.000000000 +0100
++++ ppp.dev/pppd/pcap_pcc.h	2006-03-18 15:59:14.000000000 +0100
+@@ -0,0 +1,7 @@
++#ifndef PCAP_PCC_H
++#define PCAP_PCC_H
++
++#include <pcap.h>
++
++int pcap_pre_compiled (char * fname, struct bpf_program *p);
++#endif /* PCAP_PCC_H */
diff --git a/package/ppp/utils/pfc.c b/package/ppp/utils/pfc.c
new file mode 100644
index 000000000..5476be170
--- /dev/null
+++ b/package/ppp/utils/pfc.c
@@ -0,0 +1,51 @@
+/* 
+ * Taken from fli4l 3.0
+ * Make sure you compile it against the same libpcap version used in OpenWrt
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <string.h>
+
+#include <linux/types.h>
+#include <linux/ppp_defs.h>
+
+#include <pcap.h>
+#include <pcap-bpf.h>
+
+int main (int argc, char ** argv)
+{
+    pcap_t  *pc; /* Fake struct pcap so we can compile expr */
+    struct  bpf_program filter; /* Filter program for link-active pkts */
+    u_int32_t netmask=0;
+
+    int dflag = 3;
+    if (argc == 4)
+    {
+	if (!strcmp (argv[1], "-d"))
+	{
+	    dflag = atoi (argv[2]);
+	    argv += 2;
+	    argc -=2;
+	}
+    }
+    if (argc != 2)
+    {
+	printf ("usage; %s [ -d <debug_level> ] expression\n", argv[0]);
+	return 1;
+    }
+
+    pc = pcap_open_dead(DLT_PPP_PPPD, PPP_HDRLEN);
+    if (pcap_compile(pc, &filter, argv[1], 1, netmask) == 0)
+    {
+	printf ("#\n# Expression: %s\n#\n", argv[1]);
+	bpf_dump (&filter, dflag);
+	return 0;
+    }
+    else
+    {
+	printf("error in active-filter expression: %s\n", pcap_geterr(pc));
+    }
+    return 1;
+}
diff --git a/package/pptp/files/ifup.pptp b/package/pptp/files/ifup.pptp
index fe04d9784..9b1ac07c2 100644
--- a/package/pptp/files/ifup.pptp
+++ b/package/pptp/files/ifup.pptp
@@ -23,6 +23,7 @@ case "$DEMAND" in
 	on|1|enabled)
 		DEMAND=$(nvram get ppp_idletime)
 		DEMAND=${IDLETIME:+demand idle $IDLETIME}
+		[ -f /etc/ppp/filter ] && DEMAND=${DEMAND:+precompiled-active-filter /etc/ppp/filter $DEMAND}
 	;;
 	*) DEMAND="persist";;
 esac
-- 
2.20.1