Skip to content

Instantly share code, notes, and snippets.

@drdaeman
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drdaeman/f4884077d338efb72ea4 to your computer and use it in GitHub Desktop.
Save drdaeman/f4884077d338efb72ea4 to your computer and use it in GitHub Desktop.
An somewhat ugly hack to make packets to certain IPv4 addresses not increment interface counters. Original patch's not mine.
--- drivers/net/ppp/ppp_generic.c 2014-01-20 06:40:07.000000000 +0400
+++ drivers/net/ppp/ppp_generic.c 2014-06-09 14:48:48.000000000 +0400
@@ -54,6 +54,13 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
+#define CONFIG_PPP_FILTER_COUNTERS 1
+
+#ifdef CONFIG_PPP_FILTER_COUNTERS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#endif
+
#define PPP_VERSION "2.4.2"
/*
@@ -367,6 +374,179 @@
#define ppp_unlock(ppp) do { ppp_recv_unlock(ppp); \
ppp_xmit_unlock(ppp); } while (0)
+
+#ifdef CONFIG_PPP_FILTER_COUNTERS
+#define PPP_FILTER_COUNTERS_MAX 64
+#define PPP_FILTER_COUNTERS_PROCNAME "ppp_filter_counters"
+
+static u32 ppp_filter_counters[PPP_FILTER_COUNTERS_MAX][2];
+static unsigned int ppp_filter_counters_count;
+static bool ppp_filter_counters_debug;
+
+static ssize_t ppp_filter_counters_proc_write(struct file *fp, const char __user *buf, size_t len, loff_t *ppos) {
+ char b[24];
+ char *str;
+ bool insert = false;
+ u32 ip;
+ unsigned int i, j;
+ u32 ip_byte[4], mask = 0, masklen = 0;
+ loff_t pos = *ppos;
+
+ if (pos < 0)
+ return -EINVAL;
+ if (pos != 0) {
+ pr_warn("ppp_filter_counters: write from non-zero offset (%lld) is not supported\n", pos);
+ return -EFAULT;
+ }
+ if (len > 20) {
+ pr_warn("ppp_filter_counters: string is too long (%zu)\n", len);
+ return -EFAULT;
+ }
+ if (copy_from_user(b, buf, len))
+ return -EFAULT;
+
+ if (strncmp(b, "debug", len) == 0) {
+ ppp_filter_counters_debug = ~ppp_filter_counters_debug;
+ pr_notice("ppp_filter_counters: debugging %s\n",
+ ppp_filter_counters_debug ? "enabled" : "disabled");
+ return len;
+ }
+
+ if (b[0] == '+') {
+ if (ppp_filter_counters_count < PPP_FILTER_COUNTERS_MAX) {
+ insert = true;
+ } else {
+ pr_warn("ppp_filter_counters: table is full\n");
+ return -EFAULT;
+ }
+ } else if (b[0] == '-') {
+ insert = false;
+ } else {
+ pr_warn("ppp_filter_counters: syntax error, must be (+|-)<IPv4/mask>\n");
+ return -EFAULT;
+ }
+ str = b;
+ str++;
+ b[len] = '\0';
+
+ sscanf(str, "%d.%d.%d.%d/%d", &ip_byte[3], &ip_byte[2], &ip_byte[1], &ip_byte[0], &masklen);
+ if (ip_byte[3] > 255 || ip_byte[2] > 255 || ip_byte[1] > 255|| ip_byte[0] > 255) {
+ pr_warn("ppp_filter_counters: not a valid IPv4 address\n");
+ return -EFAULT;
+ }
+ ip = (ip_byte[3]<<24) | (ip_byte[2]<<16) | (ip_byte[1]<<8) | (ip_byte[0]);
+ if (masklen > 32 || masklen < 0) {
+ pr_warn("ppp_filter_counters: invalid netmask (%d)\n", masklen);
+ return -EFAULT;
+ }
+ mask = 0xffffffff << (32 - masklen);
+
+ if (ip != 0 && mask) {
+ if (insert) {
+ for (i = 0; i < ppp_filter_counters_count; i++) {
+ if (ip == ppp_filter_counters[i][0] && mask == ppp_filter_counters[i][1])
+ return len; /* already there */
+ }
+ ppp_filter_counters[ppp_filter_counters_count][0] = ip;
+ ppp_filter_counters[ppp_filter_counters_count][1] = mask;
+ ppp_filter_counters_count++;
+ return len;
+ } else {
+ for (i = 0; i < ppp_filter_counters_count; i++) {
+ if (ip == ppp_filter_counters[i][0] && mask == ppp_filter_counters[i][1]) {
+ pr_notice("ppp_filter_counters: removed %d.%d.%d.%d/%d\n",
+ ip_byte[3], ip_byte[2], ip_byte[1], ip_byte[0], masklen);
+ for (j = i; j < ppp_filter_counters_count - 1; j++) {
+ ppp_filter_counters[j][0] = ppp_filter_counters[j+1][0];
+ ppp_filter_counters[j][1] = ppp_filter_counters[j+1][1];
+ }
+ ppp_filter_counters_count--;
+ return len;
+ }
+ }
+ }
+ }
+ return len;
+}
+
+static int ppp_filter_counters_proc_show(struct seq_file *m, void *v) {
+ unsigned int i, j, mask = 0;
+
+ if (ppp_filter_counters_count==0)
+ seq_printf(m, "no entries\n");
+ else for (i = 0; i < ppp_filter_counters_count; i++) {
+ for (j = 0; j < 32; j++){
+ if (((ppp_filter_counters[i][1] >> j) & 1) == 1) {
+ mask = 32 - j;
+ break;
+ }
+ }
+ seq_printf(m, "%d.%d.%d.%d/%d\n",
+ (ppp_filter_counters[i][0] >> 24) & 0x000000ff,
+ (ppp_filter_counters[i][0] >> 16) & 0x000000ff,
+ (ppp_filter_counters[i][0] >> 8) & 0x000000ff,
+ ppp_filter_counters[i][0] & 0x000000ff, mask);
+ }
+ return 0;
+}
+
+static int ppp_filter_counters_proc_open(struct inode *inode, struct file *file) {
+ return single_open(file, ppp_filter_counters_proc_show, NULL);
+}
+
+static const struct file_operations ppp_filter_counters_fops = {
+ .owner = THIS_MODULE,
+ .open = ppp_filter_counters_proc_open,
+ .read = seq_read,
+ .write = ppp_filter_counters_proc_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static bool ppp_filter_counters_allow(struct ppp* sppp, struct sk_buff *skb, bool tx){
+ struct iphdr *iph;
+ unsigned int ip;
+ int i;
+
+ if (ppp_filter_counters_count == 0)
+ return true;
+ if (sppp == NULL || skb == NULL || PPP_PROTO(skb) != PPP_IP)
+ return true;
+
+ iph = (struct iphdr*)skb_network_header(skb);
+ if (iph == NULL || iph->ihl < 5){
+ iph = (struct iphdr*) ((char*)skb->data+2);
+ }
+ if (iph == NULL)
+ return true;
+
+ if (tx)
+ ip = ntohl(iph->saddr);
+ else
+ ip = ntohl(iph->daddr);
+
+ if (ppp_filter_counters_debug)
+ netdev_printk(KERN_DEBUG, sppp->dev, "ppp_filter_counters: src=%pI4h dst=%pI4h\n", ntohl(iph->saddr), ntohl(iph->daddr));
+ for (i=0; i<ppp_filter_counters_count; i++){
+ if (!((ppp_filter_counters[i][0]&ppp_filter_counters[i][1]) ^ (ip&ppp_filter_counters[i][1]))) {
+ if (ppp_filter_counters_debug)
+ netdev_printk(KERN_DEBUG, sppp->dev, "ppp_filter_counters: not counting %pI4h\n", ip);
+ return false; /* do not count */
+ }
+ }
+ return true; /* count */
+}
+
+static bool ppp_filter_counters_init(void) {
+ struct proc_dir_entry *e;
+
+ ppp_filter_counters_count = 0;
+ ppp_filter_counters_debug = false;
+ e = proc_create(PPP_FILTER_COUNTERS_PROCNAME, 0644, NULL, &ppp_filter_counters_fops);
+ return e == NULL; /* return false on success, true on failure */
+}
+#endif /*CONFIG_PPP_FILTER_COUNTERS*/
+
/*
* /dev/ppp device routines.
* The /dev/ppp device is used by pppd to control the ppp unit.
@@ -932,6 +1112,11 @@
goto out_chrdev;
}
+#ifdef CONFIG_PPP_FILTER_COUNTERS
+ if (ppp_filter_counters_init())
+ pr_err( "failed to initialize ppp_filter_counters\n");
+#endif
+
/* not a big deal if we fail here :-) */
device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
@@ -1203,8 +1388,14 @@
#endif /* CONFIG_PPP_FILTER */
}
+#ifdef CONFIG_PPP_FILTER_COUNTERS
+ if (proto != PPP_IP || ppp_filter_counters_allow(ppp, skb, true)) {
+#endif
++ppp->stats64.tx_packets;
ppp->stats64.tx_bytes += skb->len - 2;
+#ifdef CONFIG_PPP_FILTER_COUNTERS
+ }
+#endif
switch (proto) {
case PPP_IP:
@@ -1791,8 +1982,14 @@
break;
}
+#ifdef CONFIG_PPP_FILTER_COUNTERS
+ if (proto != PPP_IP || ppp_filter_counters_allow(ppp, skb, false)) {
+#endif
++ppp->stats64.rx_packets;
ppp->stats64.rx_bytes += skb->len - 2;
+#ifdef CONFIG_PPP_FILTER_COUNTERS
+ }
+#endif
npi = proto_to_npindex(proto);
if (npi < 0) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment