1 /* Accouting handling for netfilter. */ 2 3 /* 4 * (C) 2008 Krzysztof Piotr Oledzki <ole@ans.pl> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11 #include <linux/netfilter.h> 12 #include <linux/slab.h> 13 #include <linux/kernel.h> 14 #include <linux/moduleparam.h> 15 #include <linux/export.h> 16 17 #include <net/netfilter/nf_conntrack.h> 18 #include <net/netfilter/nf_conntrack_extend.h> 19 #include <net/netfilter/nf_conntrack_acct.h> 20 21 static bool nf_ct_acct __read_mostly; 22 23 module_param_named(acct, nf_ct_acct, bool, 0644); 24 MODULE_PARM_DESC(acct, "Enable connection tracking flow accounting."); 25 26 #ifdef CONFIG_SYSCTL 27 static struct ctl_table acct_sysctl_table[] = { 28 { 29 .procname = "nf_conntrack_acct", 30 .data = &init_net.ct.sysctl_acct, 31 .maxlen = sizeof(unsigned int), 32 .mode = 0644, 33 .proc_handler = proc_dointvec, 34 }, 35 {} 36 }; 37 #endif /* CONFIG_SYSCTL */ 38 39 unsigned int 40 seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir) 41 { 42 struct nf_conn_acct *acct; 43 struct nf_conn_counter *counter; 44 45 acct = nf_conn_acct_find(ct); 46 if (!acct) 47 return 0; 48 49 counter = acct->counter; 50 seq_printf(s, "packets=%llu bytes=%llu ", 51 (unsigned long long)atomic64_read(&counter[dir].packets), 52 (unsigned long long)atomic64_read(&counter[dir].bytes)); 53 54 return 0; 55 }; 56 EXPORT_SYMBOL_GPL(seq_print_acct); 57 58 static const struct nf_ct_ext_type acct_extend = { 59 .len = sizeof(struct nf_conn_acct), 60 .align = __alignof__(struct nf_conn_acct), 61 .id = NF_CT_EXT_ACCT, 62 }; 63 64 #ifdef CONFIG_SYSCTL 65 static int nf_conntrack_acct_init_sysctl(struct net *net) 66 { 67 struct ctl_table *table; 68 69 table = kmemdup(acct_sysctl_table, sizeof(acct_sysctl_table), 70 GFP_KERNEL); 71 if (!table) 72 goto out; 73 74 table[0].data = &net->ct.sysctl_acct; 75 76 /* Don't export sysctls to unprivileged users */ 77 if (net->user_ns != &init_user_ns) 78 table[0].procname = NULL; 79 80 net->ct.acct_sysctl_header = register_net_sysctl(net, "net/netfilter", 81 table); 82 if (!net->ct.acct_sysctl_header) { 83 printk(KERN_ERR "nf_conntrack_acct: can't register to sysctl.\n"); 84 goto out_register; 85 } 86 return 0; 87 88 out_register: 89 kfree(table); 90 out: 91 return -ENOMEM; 92 } 93 94 static void nf_conntrack_acct_fini_sysctl(struct net *net) 95 { 96 struct ctl_table *table; 97 98 table = net->ct.acct_sysctl_header->ctl_table_arg; 99 unregister_net_sysctl_table(net->ct.acct_sysctl_header); 100 kfree(table); 101 } 102 #else 103 static int nf_conntrack_acct_init_sysctl(struct net *net) 104 { 105 return 0; 106 } 107 108 static void nf_conntrack_acct_fini_sysctl(struct net *net) 109 { 110 } 111 #endif 112 113 int nf_conntrack_acct_pernet_init(struct net *net) 114 { 115 net->ct.sysctl_acct = nf_ct_acct; 116 return nf_conntrack_acct_init_sysctl(net); 117 } 118 119 void nf_conntrack_acct_pernet_fini(struct net *net) 120 { 121 nf_conntrack_acct_fini_sysctl(net); 122 } 123 124 int nf_conntrack_acct_init(void) 125 { 126 int ret = nf_ct_extend_register(&acct_extend); 127 if (ret < 0) 128 pr_err("nf_conntrack_acct: Unable to register extension\n"); 129 return ret; 130 } 131 132 void nf_conntrack_acct_fini(void) 133 { 134 nf_ct_extend_unregister(&acct_extend); 135 } 136