Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nf_log.c
Go to the documentation of this file.
1 #include <linux/kernel.h>
2 #include <linux/init.h>
3 #include <linux/module.h>
4 #include <linux/proc_fs.h>
5 #include <linux/skbuff.h>
6 #include <linux/netfilter.h>
7 #include <linux/seq_file.h>
8 #include <net/protocol.h>
9 #include <net/netfilter/nf_log.h>
10 
11 #include "nf_internals.h"
12 
13 /* Internal logging interface, which relies on the real
14  LOG target modules */
15 
16 #define NF_LOG_PREFIXLEN 128
17 #define NFLOGGER_NAME_LEN 64
18 
19 static const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO] __read_mostly;
20 static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly;
21 static DEFINE_MUTEX(nf_log_mutex);
22 
23 static struct nf_logger *__find_logger(int pf, const char *str_logger)
24 {
25  struct nf_logger *t;
26 
27  list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) {
28  if (!strnicmp(str_logger, t->name, strlen(t->name)))
29  return t;
30  }
31 
32  return NULL;
33 }
34 
35 /* return EEXIST if the same logger is registred, 0 on success. */
36 int nf_log_register(u_int8_t pf, struct nf_logger *logger)
37 {
38  const struct nf_logger *llog;
39  int i;
40 
41  if (pf >= ARRAY_SIZE(nf_loggers))
42  return -EINVAL;
43 
44  for (i = 0; i < ARRAY_SIZE(logger->list); i++)
45  INIT_LIST_HEAD(&logger->list[i]);
46 
47  mutex_lock(&nf_log_mutex);
48 
49  if (pf == NFPROTO_UNSPEC) {
50  for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
51  list_add_tail(&(logger->list[i]), &(nf_loggers_l[i]));
52  } else {
53  /* register at end of list to honor first register win */
54  list_add_tail(&logger->list[pf], &nf_loggers_l[pf]);
55  llog = rcu_dereference_protected(nf_loggers[pf],
56  lockdep_is_held(&nf_log_mutex));
57  if (llog == NULL)
58  rcu_assign_pointer(nf_loggers[pf], logger);
59  }
60 
61  mutex_unlock(&nf_log_mutex);
62 
63  return 0;
64 }
66 
67 void nf_log_unregister(struct nf_logger *logger)
68 {
69  const struct nf_logger *c_logger;
70  int i;
71 
72  mutex_lock(&nf_log_mutex);
73  for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) {
74  c_logger = rcu_dereference_protected(nf_loggers[i],
75  lockdep_is_held(&nf_log_mutex));
76  if (c_logger == logger)
77  RCU_INIT_POINTER(nf_loggers[i], NULL);
78  list_del(&logger->list[i]);
79  }
80  mutex_unlock(&nf_log_mutex);
81 
82  synchronize_rcu();
83 }
85 
86 int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
87 {
88  if (pf >= ARRAY_SIZE(nf_loggers))
89  return -EINVAL;
90  mutex_lock(&nf_log_mutex);
91  if (__find_logger(pf, logger->name) == NULL) {
92  mutex_unlock(&nf_log_mutex);
93  return -ENOENT;
94  }
95  rcu_assign_pointer(nf_loggers[pf], logger);
96  mutex_unlock(&nf_log_mutex);
97  return 0;
98 }
100 
102 {
103  if (pf >= ARRAY_SIZE(nf_loggers))
104  return;
105  mutex_lock(&nf_log_mutex);
106  RCU_INIT_POINTER(nf_loggers[pf], NULL);
107  mutex_unlock(&nf_log_mutex);
108 }
110 
112  unsigned int hooknum,
113  const struct sk_buff *skb,
114  const struct net_device *in,
115  const struct net_device *out,
116  const struct nf_loginfo *loginfo,
117  const char *fmt, ...)
118 {
119  va_list args;
120  char prefix[NF_LOG_PREFIXLEN];
121  const struct nf_logger *logger;
122 
123  rcu_read_lock();
124  logger = rcu_dereference(nf_loggers[pf]);
125  if (logger) {
126  va_start(args, fmt);
127  vsnprintf(prefix, sizeof(prefix), fmt, args);
128  va_end(args);
129  logger->logfn(pf, hooknum, skb, in, out, loginfo, prefix);
130  }
131  rcu_read_unlock();
132 }
134 
135 #ifdef CONFIG_PROC_FS
136 static void *seq_start(struct seq_file *seq, loff_t *pos)
137 {
138  mutex_lock(&nf_log_mutex);
139 
140  if (*pos >= ARRAY_SIZE(nf_loggers))
141  return NULL;
142 
143  return pos;
144 }
145 
146 static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
147 {
148  (*pos)++;
149 
150  if (*pos >= ARRAY_SIZE(nf_loggers))
151  return NULL;
152 
153  return pos;
154 }
155 
156 static void seq_stop(struct seq_file *s, void *v)
157 {
158  mutex_unlock(&nf_log_mutex);
159 }
160 
161 static int seq_show(struct seq_file *s, void *v)
162 {
163  loff_t *pos = v;
164  const struct nf_logger *logger;
165  struct nf_logger *t;
166  int ret;
167 
168  logger = rcu_dereference_protected(nf_loggers[*pos],
169  lockdep_is_held(&nf_log_mutex));
170 
171  if (!logger)
172  ret = seq_printf(s, "%2lld NONE (", *pos);
173  else
174  ret = seq_printf(s, "%2lld %s (", *pos, logger->name);
175 
176  if (ret < 0)
177  return ret;
178 
179  list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) {
180  ret = seq_printf(s, "%s", t->name);
181  if (ret < 0)
182  return ret;
183  if (&t->list[*pos] != nf_loggers_l[*pos].prev) {
184  ret = seq_printf(s, ",");
185  if (ret < 0)
186  return ret;
187  }
188  }
189 
190  return seq_printf(s, ")\n");
191 }
192 
193 static const struct seq_operations nflog_seq_ops = {
194  .start = seq_start,
195  .next = seq_next,
196  .stop = seq_stop,
197  .show = seq_show,
198 };
199 
200 static int nflog_open(struct inode *inode, struct file *file)
201 {
202  return seq_open(file, &nflog_seq_ops);
203 }
204 
205 static const struct file_operations nflog_file_ops = {
206  .owner = THIS_MODULE,
207  .open = nflog_open,
208  .read = seq_read,
209  .llseek = seq_lseek,
210  .release = seq_release,
211 };
212 
213 
214 #endif /* PROC_FS */
215 
216 #ifdef CONFIG_SYSCTL
217 static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
218 static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
219 static struct ctl_table_header *nf_log_dir_header;
220 
221 static int nf_log_proc_dostring(ctl_table *table, int write,
222  void __user *buffer, size_t *lenp, loff_t *ppos)
223 {
224  const struct nf_logger *logger;
225  char buf[NFLOGGER_NAME_LEN];
226  size_t size = *lenp;
227  int r = 0;
228  int tindex = (unsigned long)table->extra1;
229 
230  if (write) {
231  if (size > sizeof(buf))
232  size = sizeof(buf);
233  if (copy_from_user(buf, buffer, size))
234  return -EFAULT;
235 
236  if (!strcmp(buf, "NONE")) {
237  nf_log_unbind_pf(tindex);
238  return 0;
239  }
240  mutex_lock(&nf_log_mutex);
241  logger = __find_logger(tindex, buf);
242  if (logger == NULL) {
243  mutex_unlock(&nf_log_mutex);
244  return -ENOENT;
245  }
246  rcu_assign_pointer(nf_loggers[tindex], logger);
247  mutex_unlock(&nf_log_mutex);
248  } else {
249  mutex_lock(&nf_log_mutex);
250  logger = rcu_dereference_protected(nf_loggers[tindex],
251  lockdep_is_held(&nf_log_mutex));
252  if (!logger)
253  table->data = "NONE";
254  else
255  table->data = logger->name;
256  r = proc_dostring(table, write, buffer, lenp, ppos);
257  mutex_unlock(&nf_log_mutex);
258  }
259 
260  return r;
261 }
262 
263 static __init int netfilter_log_sysctl_init(void)
264 {
265  int i;
266 
267  for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
268  snprintf(nf_log_sysctl_fnames[i-NFPROTO_UNSPEC], 3, "%d", i);
269  nf_log_sysctl_table[i].procname =
270  nf_log_sysctl_fnames[i-NFPROTO_UNSPEC];
271  nf_log_sysctl_table[i].data = NULL;
272  nf_log_sysctl_table[i].maxlen =
273  NFLOGGER_NAME_LEN * sizeof(char);
274  nf_log_sysctl_table[i].mode = 0644;
275  nf_log_sysctl_table[i].proc_handler = nf_log_proc_dostring;
276  nf_log_sysctl_table[i].extra1 = (void *)(unsigned long) i;
277  }
278 
279  nf_log_dir_header = register_net_sysctl(&init_net, "net/netfilter/nf_log",
280  nf_log_sysctl_table);
281  if (!nf_log_dir_header)
282  return -ENOMEM;
283 
284  return 0;
285 }
286 #else
287 static __init int netfilter_log_sysctl_init(void)
288 {
289  return 0;
290 }
291 #endif /* CONFIG_SYSCTL */
292 
294 {
295  int i, r;
296 #ifdef CONFIG_PROC_FS
297  if (!proc_create("nf_log", S_IRUGO,
298  proc_net_netfilter, &nflog_file_ops))
299  return -1;
300 #endif
301 
302  /* Errors will trigger panic, unroll on error is unnecessary. */
303  r = netfilter_log_sysctl_init();
304  if (r < 0)
305  return r;
306 
307  for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
308  INIT_LIST_HEAD(&(nf_loggers_l[i]));
309 
310  return 0;
311 }