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 [EMAIL PROTECTED]
Please read the FAQ at http://www.tux.org/lkml/

Reply via email to