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/bitops.h> 6#include <linux/skbuff.h> 7#include <linux/math64.h> 8#include <linux/netfilter/x_tables.h> 9#include <linux/netfilter/xt_connbytes.h> 10#include <net/netfilter/nf_conntrack.h> 11#include <net/netfilter/nf_conntrack_acct.h> 12 13MODULE_LICENSE("GPL"); 14MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 15MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching"); 16MODULE_ALIAS("ipt_connbytes"); 17MODULE_ALIAS("ip6t_connbytes"); 18 19static bool 20connbytes_mt(const struct sk_buff *skb, const struct net_device *in, 21 const struct net_device *out, const struct xt_match *match, 22 const void *matchinfo, int offset, unsigned int protoff, 23 bool *hotdrop) 24{ 25 const struct xt_connbytes_info *sinfo = matchinfo; 26 const struct nf_conn *ct; 27 enum ip_conntrack_info ctinfo; 28 u_int64_t what = 0; /* initialize to make gcc happy */ 29 u_int64_t bytes = 0; 30 u_int64_t pkts = 0; 31 const struct nf_conn_counter *counters; 32 33 ct = nf_ct_get(skb, &ctinfo); 34 if (!ct) 35 return false; 36 37 counters = nf_conn_acct_find(ct); 38 if (!counters) 39 return false; 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_u64(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 bool 99connbytes_mt_check(const char *tablename, const void *ip, 100 const struct xt_match *match, void *matchinfo, 101 unsigned int hook_mask) 102{ 103 const struct xt_connbytes_info *sinfo = matchinfo; 104 105 if (sinfo->what != XT_CONNBYTES_PKTS && 106 sinfo->what != XT_CONNBYTES_BYTES && 107 sinfo->what != XT_CONNBYTES_AVGPKT) 108 return false; 109 110 if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL && 111 sinfo->direction != XT_CONNBYTES_DIR_REPLY && 112 sinfo->direction != XT_CONNBYTES_DIR_BOTH) 113 return false; 114 115 if (nf_ct_l3proto_try_module_get(match->family) < 0) { 116 printk(KERN_WARNING "can't load conntrack support for " 117 "proto=%u\n", match->family); 118 return false; 119 } 120 121 return true; 122} 123 124static void 125connbytes_mt_destroy(const struct xt_match *match, void *matchinfo) 126{ 127 nf_ct_l3proto_module_put(match->family); 128} 129 130static struct xt_match connbytes_mt_reg[] __read_mostly = { 131 { 132 .name = "connbytes", 133 .family = AF_INET, 134 .checkentry = connbytes_mt_check, 135 .match = connbytes_mt, 136 .destroy = connbytes_mt_destroy, 137 .matchsize = sizeof(struct xt_connbytes_info), 138 .me = THIS_MODULE 139 }, 140 { 141 .name = "connbytes", 142 .family = AF_INET6, 143 .checkentry = connbytes_mt_check, 144 .match = connbytes_mt, 145 .destroy = connbytes_mt_destroy, 146 .matchsize = sizeof(struct xt_connbytes_info), 147 .me = THIS_MODULE 148 }, 149}; 150 151static int __init connbytes_mt_init(void) 152{ 153 return xt_register_matches(connbytes_mt_reg, 154 ARRAY_SIZE(connbytes_mt_reg)); 155} 156 157static void __exit connbytes_mt_exit(void) 158{ 159 xt_unregister_matches(connbytes_mt_reg, ARRAY_SIZE(connbytes_mt_reg)); 160} 161 162module_init(connbytes_mt_init); 163module_exit(connbytes_mt_exit);