Last active
August 29, 2015 14:02
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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