[PATCH] add PPP filtering

From: Paul Mackerras (paulus@linuxcare.com.au)
Date: Fri Sep 01 2000 - 23:23:42 EST


Linus,

The patch below adds the ability to filter packets going through a PPP
interface. This allows users to specify that certain types of packets
are not to count as activity, i.e. they don't reset the idle timer or
bring up a demand-dialled link. This is something I have been getting
a lot of requests for.

It also allows users to specify that certain types of packets are to
be dropped - this isn't a substitute for the netfilter stuff of
course, but it comes virtually for free and it can sometimes be
useful.

(Users will need to use ppp-2.4.0 and compile pppd with the line in
pppd/Makefile.linux that says "FILTER=y" uncommented.)

I hope this can go into 2.4. It is a relatively small and
self-contained set of changes. The only change to things outside the
PPP generic module is a small change to make sure that sk_chk_filter
is exported from the socket filtering code. There is also a small
change where I have removed an unnecessary #include from
ppp_channel.h.

The files affected are:

Documentation/Configure.help
drivers/net/ppp_generic.c
include/linux/filter.h
include/linux/if_ppp.h
include/linux/ppp_channel.h
net/netsyms.c

Regards,
Paul.

diff -urN linux/Documentation/Configure.help pmac/Documentation/Configure.help
--- linux/Documentation/Configure.help Sat Sep 2 15:08:58 2000
+++ pmac/Documentation/Configure.help Sat Sep 2 14:58:22 2000
@@ -1748,6 +1748,10 @@
   certain types of data to get through the socket. Linux Socket
   Filtering works on all socket types except TCP for now. See the text
   file Documentation/networking/filter.txt for more information.
+
+ You need to say Y here if you want to use PPP packet filtering
+ (see the CONFIG_PPP_FILTER option below).
+
   If unsure, say N.
 
 Network packet filtering
@@ -6719,6 +6723,17 @@
 
   This has to be supported at the other end as well and you need a
   version of the pppd daemon which understands the multilink protocol.
+
+ If unsure, say N.
+
+PPP filtering (EXPERIMENTAL)
+CONFIG_PPP_FILTER
+ Say Y here if you want to be able to filter the packets passing over
+ PPP interfaces. This allows you to control which packets count as
+ activity (i.e. which packets will reset the idle timer or bring up
+ a demand-dialled link) and which packets are to be dropped entirely.
+ You need to say Y here if you wish to use the pass-filter and
+ active-filter options to pppd.
 
   If unsure, say N.
 
diff -urN linux/drivers/net/ppp_generic.c pmac/drivers/net/ppp_generic.c
--- linux/drivers/net/ppp_generic.c Fri Jul 14 14:41:43 2000
+++ pmac/drivers/net/ppp_generic.c Sat Sep 2 15:14:02 2000
@@ -19,7 +19,7 @@
  * PPP driver, written by Michael Callahan and Al Longyear, and
  * subsequently hacked by Paul Mackerras.
  *
- * ==FILEVERSION 20000417==
+ * ==FILEVERSION 20000902==
  */
 
 #include <linux/config.h>
@@ -32,6 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/poll.h>
 #include <linux/ppp_defs.h>
+#include <linux/filter.h>
 #include <linux/if_ppp.h>
 #include <linux/ppp_channel.h>
 #include <linux/ppp-comp.h>
@@ -121,6 +122,10 @@
         struct sk_buff_head mrq; /* MP: receive reconstruction queue */
 #endif /* CONFIG_PPP_MULTILINK */
         struct net_device_stats stats; /* statistics */
+#ifdef CONFIG_PPP_FILTER
+ struct sock_fprog pass_filter; /* filter for packets to pass */
+ struct sock_fprog active_filter;/* filter for pkts to reset idle */
+#endif /* CONFIG_PPP_FILTER */
 };
 
 /*
@@ -621,6 +626,43 @@
                 err = 0;
                 break;
 
+#ifdef CONFIG_PPP_FILTER
+ case PPPIOCSPASS:
+ case PPPIOCSACTIVE:
+ {
+ struct sock_fprog uprog, *filtp;
+ struct sock_filter *code = NULL;
+ int len;
+
+ if (copy_from_user(&uprog, (void *) arg, sizeof(uprog)))
+ break;
+ if (uprog.len > 0) {
+ err = -ENOMEM;
+ len = uprog.len * sizeof(struct sock_filter);
+ code = kmalloc(len, GFP_KERNEL);
+ if (code == 0)
+ break;
+ err = -EFAULT;
+ if (copy_from_user(code, uprog.filter, len))
+ break;
+ err = sk_chk_filter(code, uprog.len);
+ if (err) {
+ kfree(code);
+ break;
+ }
+ }
+ filtp = (cmd == PPPIOCSPASS)? &ppp->pass_filter: &ppp->active_filter;
+ ppp_lock(ppp);
+ if (filtp->filter)
+ kfree(filtp->filter);
+ filtp->filter = code;
+ filtp->len = uprog.len;
+ ppp_unlock(ppp);
+ err = 0;
+ break;
+ }
+#endif /* CONFIG_PPP_FILTER */
+
 #ifdef CONFIG_PPP_MULTILINK
         case PPPIOCSMRRU:
                 if (get_user(val, (int *) arg))
@@ -892,6 +934,33 @@
         int len;
         unsigned char *cp;
 
+ if (proto < 0x8000) {
+#ifdef CONFIG_PPP_FILTER
+ /* check if we should pass this packet */
+ /* the filter instructions are constructed assuming
+ a four-byte PPP header on each packet */
+ *skb_push(skb, 2) = 1;
+ if (ppp->pass_filter.filter
+ && sk_run_filter(skb, ppp->pass_filter.filter,
+ ppp->pass_filter.len) == 0) {
+ if (ppp->debug & 1) {
+ printk(KERN_DEBUG "PPP: outbound frame not passed\n");
+ kfree_skb(skb);
+ return;
+ }
+ }
+ /* if this packet passes the active filter, record the time */
+ if (!(ppp->active_filter.filter
+ && sk_run_filter(skb, ppp->active_filter.filter,
+ ppp->active_filter.len) == 0))
+ ppp->last_xmit = jiffies;
+ skb_pull(skb, 2);
+#else
+ /* for data packets, record the time */
+ ppp->last_xmit = jiffies;
+#endif /* CONFIG_PPP_FILTER */
+ }
+
         ++ppp->stats.tx_packets;
         ppp->stats.tx_bytes += skb->len - 2;
 
@@ -964,10 +1033,6 @@
                 }
         }
 
- /* for data packets, record the time */
- if (proto < 0x8000)
- ppp->last_xmit = jiffies;
-
         /*
          * If we are waiting for traffic (demand dialling),
          * queue it up for pppd to receive.
@@ -1402,7 +1467,29 @@
 
         } else {
                 /* network protocol frame - give it to the kernel */
+
+#ifdef CONFIG_PPP_FILTER
+ /* check if the packet passes the pass and active filters */
+ /* the filter instructions are constructed assuming
+ a four-byte PPP header on each packet */
+ *skb_push(skb, 2) = 0;
+ if (ppp->pass_filter.filter
+ && sk_run_filter(skb, ppp->pass_filter.filter,
+ ppp->pass_filter.len) == 0) {
+ if (ppp->debug & 1)
+ printk(KERN_DEBUG "PPP: inbound frame not passed\n");
+ kfree_skb(skb);
+ return;
+ }
+ if (!(ppp->active_filter.filter
+ && sk_run_filter(skb, ppp->active_filter.filter,
+ ppp->active_filter.len) == 0))
+ ppp->last_recv = jiffies;
+ skb_pull(skb, 2);
+#else
                 ppp->last_recv = jiffies;
+#endif /* CONFIG_PPP_FILTER */
+
                 if ((ppp->dev->flags & IFF_UP) == 0
                     || ppp->npmode[npi] != NPMODE_PASS) {
                         kfree_skb(skb);
@@ -2193,6 +2280,7 @@
         ppp->file.index = unit;
         ppp->mru = PPP_MRU;
         init_ppp_file(&ppp->file, INTERFACE);
+ ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */
         for (i = 0; i < NUM_NP; ++i)
                 ppp->npmode[i] = NPMODE_PASS;
         INIT_LIST_HEAD(&ppp->channels);
@@ -2264,6 +2352,16 @@
 #ifdef CONFIG_PPP_MULTILINK
         skb_queue_purge(&ppp->mrq);
 #endif /* CONFIG_PPP_MULTILINK */
+#ifdef CONFIG_PPP_FILTER
+ if (ppp->pass_filter.filter) {
+ kfree(ppp->pass_filter.filter);
+ ppp->pass_filter.filter = NULL;
+ }
+ if (ppp->active_filter.filter) {
+ kfree(ppp->active_filter.filter);
+ ppp->active_filter.filter = 0;
+ }
+#endif /* CONFIG_PPP_FILTER */
         dev = ppp->dev;
         ppp->dev = 0;
         ppp_unlock(ppp);
diff -urN linux/include/linux/filter.h pmac/include/linux/filter.h
--- linux/include/linux/filter.h Fri Apr 28 08:55:09 2000
+++ pmac/include/linux/filter.h Mon Aug 7 11:29:07 2000
@@ -135,6 +135,7 @@
 #ifdef __KERNEL__
 extern int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen);
 extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
+extern int sk_chk_filter(struct sock_filter *filter, int flen);
 #endif /* __KERNEL__ */
 
 #endif /* __LINUX_FILTER_H__ */
diff -urN linux/include/linux/if_ppp.h pmac/include/linux/if_ppp.h
--- linux/include/linux/if_ppp.h Tue Mar 28 04:28:55 2000
+++ pmac/include/linux/if_ppp.h Tue Jul 25 12:17:07 2000
@@ -1,4 +1,4 @@
-/* $Id: if_ppp.h,v 1.19 1999/03/31 06:07:57 paulus Exp $ */
+/* $Id: if_ppp.h,v 1.21 2000/03/27 06:03:36 paulus Exp $ */
 
 /*
  * if_ppp.h - Point-to-Point Protocol definitions.
@@ -21,7 +21,7 @@
  */
 
 /*
- * ==FILEVERSION 20000324==
+ * ==FILEVERSION 20000724==
  *
  * NOTE TO MAINTAINERS:
  * If you modify this file at all, please set the above date.
@@ -130,6 +130,8 @@
 #define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data)
 #define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */
 #define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */
+#define PPPIOCSPASS _IOW('t', 71, struct sock_fprog) /* set pass filter */
+#define PPPIOCSACTIVE _IOW('t', 70, struct sock_fprog) /* set active filt */
 #define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */
 #define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */
 #define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */
diff -urN linux/include/linux/ppp_channel.h pmac/include/linux/ppp_channel.h
--- linux/include/linux/ppp_channel.h Thu May 25 12:53:48 2000
+++ pmac/include/linux/ppp_channel.h Wed Aug 30 14:48:06 2000
@@ -22,7 +22,6 @@
 #include <linux/list.h>
 #include <linux/skbuff.h>
 #include <linux/poll.h>
-#include <asm/atomic.h>
 
 struct ppp_channel;
 
@@ -32,7 +31,6 @@
         int (*start_xmit)(struct ppp_channel *, struct sk_buff *);
         /* Handle an ioctl call that has come in via /dev/ppp. */
         int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long);
-
 };
 
 struct ppp_channel {
diff -urN linux/net/netsyms.c pmac/net/netsyms.c
--- linux/net/netsyms.c Thu Aug 24 17:52:19 2000
+++ pmac/net/netsyms.c Fri Aug 25 11:20:12 2000
@@ -141,6 +141,7 @@
 EXPORT_SYMBOL(sock_kfree_s);
 
 #ifdef CONFIG_FILTER
+EXPORT_SYMBOL(sk_chk_filter);
 EXPORT_SYMBOL(sk_run_filter);
 #endif
 

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Sep 07 2000 - 21:00:12 EST