1/* Kernel module to match connection tracking byte counter. 2 * GPL (C) 2002 Martin Devera (devik@cdi.cz). 3 */ 4#include <linux/module.h> 5#include <linux/skbuff.h> 6#include <linux/netfilter/x_tables.h> 7#include <linux/netfilter/xt_connbytes.h> 8#include <net/netfilter/nf_conntrack.h> 9 10#include <asm/div64.h> 11#include <asm/bitops.h> 12 13MODULE_LICENSE("GPL"); 14MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 15MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection"); 16MODULE_ALIAS("ipt_connbytes"); 17 18static int 19match(const struct sk_buff *skb, 20 const struct net_device *in, 21 const struct net_device *out, 22 const struct xt_match *match, 23 const void *matchinfo, 24 int offset, 25 unsigned int protoff, 26 int *hotdrop) 27{ 28 const struct xt_connbytes_info *sinfo = matchinfo; 29 struct nf_conn *ct; 30 enum ip_conntrack_info ctinfo; 31 u_int64_t what = 0; /* initialize to make gcc happy */ 32 u_int64_t bytes = 0; 33 u_int64_t pkts = 0; 34 const struct ip_conntrack_counter *counters; 35 36 ct = nf_ct_get(skb, &ctinfo); 37 if (!ct) 38 return 0; 39 counters = ct->counters; 40 41 switch (sinfo->what) { 42 case XT_CONNBYTES_PKTS: 43 switch (sinfo->direction) { 44 case XT_CONNBYTES_DIR_ORIGINAL: 45 what = counters[IP_CT_DIR_ORIGINAL].packets; 46 break; 47 case XT_CONNBYTES_DIR_REPLY: 48 what = counters[IP_CT_DIR_REPLY].packets; 49 break; 50 case XT_CONNBYTES_DIR_BOTH: 51 what = counters[IP_CT_DIR_ORIGINAL].packets; 52 what += counters[IP_CT_DIR_REPLY].packets; 53 break; 54 } 55 break; 56 case XT_CONNBYTES_BYTES: 57 switch (sinfo->direction) { 58 case XT_CONNBYTES_DIR_ORIGINAL: 59 what = counters[IP_CT_DIR_ORIGINAL].bytes; 60 break; 61 case XT_CONNBYTES_DIR_REPLY: 62 what = counters[IP_CT_DIR_REPLY].bytes; 63 break; 64 case XT_CONNBYTES_DIR_BOTH: 65 what = counters[IP_CT_DIR_ORIGINAL].bytes; 66 what += counters[IP_CT_DIR_REPLY].bytes; 67 break; 68 } 69 break; 70 case XT_CONNBYTES_AVGPKT: 71 switch (sinfo->direction) { 72 case XT_CONNBYTES_DIR_ORIGINAL: 73 bytes = counters[IP_CT_DIR_ORIGINAL].bytes; 74 pkts = counters[IP_CT_DIR_ORIGINAL].packets; 75 break; 76 case XT_CONNBYTES_DIR_REPLY: 77 bytes = counters[IP_CT_DIR_REPLY].bytes; 78 pkts = counters[IP_CT_DIR_REPLY].packets; 79 break; 80 case XT_CONNBYTES_DIR_BOTH: 81 bytes = counters[IP_CT_DIR_ORIGINAL].bytes + 82 counters[IP_CT_DIR_REPLY].bytes; 83 pkts = counters[IP_CT_DIR_ORIGINAL].packets + 84 counters[IP_CT_DIR_REPLY].packets; 85 break; 86 } 87 if (pkts != 0) 88 what = div64_64(bytes, pkts); 89 break; 90 } 91 92 if (sinfo->count.to) 93 return (what <= sinfo->count.to && what >= sinfo->count.from); 94 else 95 return (what >= sinfo->count.from); 96} 97 98static int check(const char *tablename, 99 const void *ip, 100 const struct xt_match *match, 101 void *matchinfo, 102 unsigned int hook_mask) 103{ 104 const struct xt_connbytes_info *sinfo = matchinfo; 105 106 if (sinfo->what != XT_CONNBYTES_PKTS && 107 sinfo->what != XT_CONNBYTES_BYTES && 108 sinfo->what != XT_CONNBYTES_AVGPKT) 109 return 0; 110 111 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL && 112 sinfo->direction != XT_CONNBYTES_DIR_REPLY && 113 sinfo->direction != XT_CONNBYTES_DIR_BOTH) 114 return 0; 115 116 if (nf_ct_l3proto_try_module_get(match->family) < 0) { 117 printk(KERN_WARNING "can't load conntrack support for " 118 "proto=%d\n", match->family); 119 return 0; 120 } 121 122 return 1; 123} 124 125static void 126destroy(const struct xt_match *match, void *matchinfo) 127{ 128 nf_ct_l3proto_module_put(match->family); 129} 130 131static struct xt_match xt_connbytes_match[] = { 132 { 133 .name = "connbytes", 134 .family = AF_INET, 135 .checkentry = check, 136 .match = match, 137 .destroy = destroy, 138 .matchsize = sizeof(struct xt_connbytes_info), 139 .me = THIS_MODULE 140 }, 141 { 142 .name = "connbytes", 143 .family = AF_INET6, 144 .checkentry = check, 145 .match = match, 146 .destroy = destroy, 147 .matchsize = sizeof(struct xt_connbytes_info), 148 .me = THIS_MODULE 149 }, 150}; 151 152static int __init xt_connbytes_init(void) 153{ 154 return xt_register_matches(xt_connbytes_match, 155 ARRAY_SIZE(xt_connbytes_match)); 156} 157 158static void __exit xt_connbytes_fini(void) 159{ 160 xt_unregister_matches(xt_connbytes_match, 161 ARRAY_SIZE(xt_connbytes_match)); 162} 163 164module_init(xt_connbytes_init); 165module_exit(xt_connbytes_fini); 166