nf_log.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  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. #include "nf_internals.h"
  11. /* Internal logging interface, which relies on the real
  12. LOG target modules */
  13. #define NF_LOG_PREFIXLEN 128
  14. #define NFLOGGER_NAME_LEN 64
  15. static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
  16. static DEFINE_MUTEX(nf_log_mutex);
  17. #define nft_log_dereference(logger) \
  18. rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex))
  19. static struct nf_logger *__find_logger(int pf, const char *str_logger)
  20. {
  21. struct nf_logger *log;
  22. int i;
  23. for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
  24. if (loggers[pf][i] == NULL)
  25. continue;
  26. log = nft_log_dereference(loggers[pf][i]);
  27. if (!strncasecmp(str_logger, log->name, strlen(log->name)))
  28. return log;
  29. }
  30. return NULL;
  31. }
  32. void nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
  33. {
  34. const struct nf_logger *log;
  35. if (pf == NFPROTO_UNSPEC)
  36. return;
  37. mutex_lock(&nf_log_mutex);
  38. log = nft_log_dereference(net->nf.nf_loggers[pf]);
  39. if (log == NULL)
  40. rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
  41. mutex_unlock(&nf_log_mutex);
  42. }
  43. EXPORT_SYMBOL(nf_log_set);
  44. void nf_log_unset(struct net *net, const struct nf_logger *logger)
  45. {
  46. int i;
  47. const struct nf_logger *log;
  48. mutex_lock(&nf_log_mutex);
  49. for (i = 0; i < NFPROTO_NUMPROTO; i++) {
  50. log = nft_log_dereference(net->nf.nf_loggers[i]);
  51. if (log == logger)
  52. RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL);
  53. }
  54. mutex_unlock(&nf_log_mutex);
  55. synchronize_rcu();
  56. }
  57. EXPORT_SYMBOL(nf_log_unset);
  58. /* return EEXIST if the same logger is registered, 0 on success. */
  59. int nf_log_register(u_int8_t pf, struct nf_logger *logger)
  60. {
  61. int i;
  62. int ret = 0;
  63. if (pf >= ARRAY_SIZE(init_net.nf.nf_loggers))
  64. return -EINVAL;
  65. mutex_lock(&nf_log_mutex);
  66. if (pf == NFPROTO_UNSPEC) {
  67. for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
  68. if (rcu_access_pointer(loggers[i][logger->type])) {
  69. ret = -EEXIST;
  70. goto unlock;
  71. }
  72. }
  73. for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
  74. rcu_assign_pointer(loggers[i][logger->type], logger);
  75. } else {
  76. if (rcu_access_pointer(loggers[pf][logger->type])) {
  77. ret = -EEXIST;
  78. goto unlock;
  79. }
  80. rcu_assign_pointer(loggers[pf][logger->type], logger);
  81. }
  82. unlock:
  83. mutex_unlock(&nf_log_mutex);
  84. return ret;
  85. }
  86. EXPORT_SYMBOL(nf_log_register);
  87. void nf_log_unregister(struct nf_logger *logger)
  88. {
  89. const struct nf_logger *log;
  90. int i;
  91. mutex_lock(&nf_log_mutex);
  92. for (i = 0; i < NFPROTO_NUMPROTO; i++) {
  93. log = nft_log_dereference(loggers[i][logger->type]);
  94. if (log == logger)
  95. RCU_INIT_POINTER(loggers[i][logger->type], NULL);
  96. }
  97. mutex_unlock(&nf_log_mutex);
  98. synchronize_rcu();
  99. }
  100. EXPORT_SYMBOL(nf_log_unregister);
  101. int nf_log_bind_pf(struct net *net, u_int8_t pf,
  102. const struct nf_logger *logger)
  103. {
  104. if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
  105. return -EINVAL;
  106. mutex_lock(&nf_log_mutex);
  107. if (__find_logger(pf, logger->name) == NULL) {
  108. mutex_unlock(&nf_log_mutex);
  109. return -ENOENT;
  110. }
  111. rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
  112. mutex_unlock(&nf_log_mutex);
  113. return 0;
  114. }
  115. EXPORT_SYMBOL(nf_log_bind_pf);
  116. void nf_log_unbind_pf(struct net *net, u_int8_t pf)
  117. {
  118. if (pf >= ARRAY_SIZE(net->nf.nf_loggers))
  119. return;
  120. mutex_lock(&nf_log_mutex);
  121. RCU_INIT_POINTER(net->nf.nf_loggers[pf], NULL);
  122. mutex_unlock(&nf_log_mutex);
  123. }
  124. EXPORT_SYMBOL(nf_log_unbind_pf);
  125. void nf_logger_request_module(int pf, enum nf_log_type type)
  126. {
  127. if (loggers[pf][type] == NULL)
  128. request_module("nf-logger-%u-%u", pf, type);
  129. }
  130. EXPORT_SYMBOL_GPL(nf_logger_request_module);
  131. int nf_logger_find_get(int pf, enum nf_log_type type)
  132. {
  133. struct nf_logger *logger;
  134. int ret = -ENOENT;
  135. if (rcu_access_pointer(loggers[pf][type]) == NULL)
  136. request_module("nf-logger-%u-%u", pf, type);
  137. rcu_read_lock();
  138. logger = rcu_dereference(loggers[pf][type]);
  139. if (logger == NULL)
  140. goto out;
  141. if (logger && try_module_get(logger->me))
  142. ret = 0;
  143. out:
  144. rcu_read_unlock();
  145. return ret;
  146. }
  147. EXPORT_SYMBOL_GPL(nf_logger_find_get);
  148. void nf_logger_put(int pf, enum nf_log_type type)
  149. {
  150. struct nf_logger *logger;
  151. BUG_ON(loggers[pf][type] == NULL);
  152. rcu_read_lock();
  153. logger = rcu_dereference(loggers[pf][type]);
  154. module_put(logger->me);
  155. rcu_read_unlock();
  156. }
  157. EXPORT_SYMBOL_GPL(nf_logger_put);
  158. void nf_log_packet(struct net *net,
  159. u_int8_t pf,
  160. unsigned int hooknum,
  161. const struct sk_buff *skb,
  162. const struct net_device *in,
  163. const struct net_device *out,
  164. const struct nf_loginfo *loginfo,
  165. const char *fmt, ...)
  166. {
  167. va_list args;
  168. char prefix[NF_LOG_PREFIXLEN];
  169. const struct nf_logger *logger;
  170. rcu_read_lock();
  171. if (loginfo != NULL)
  172. logger = rcu_dereference(loggers[pf][loginfo->type]);
  173. else
  174. logger = rcu_dereference(net->nf.nf_loggers[pf]);
  175. if (logger) {
  176. va_start(args, fmt);
  177. vsnprintf(prefix, sizeof(prefix), fmt, args);
  178. va_end(args);
  179. logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
  180. }
  181. rcu_read_unlock();
  182. }
  183. EXPORT_SYMBOL(nf_log_packet);
  184. void nf_log_trace(struct net *net,
  185. u_int8_t pf,
  186. unsigned int hooknum,
  187. const struct sk_buff *skb,
  188. const struct net_device *in,
  189. const struct net_device *out,
  190. const struct nf_loginfo *loginfo, const char *fmt, ...)
  191. {
  192. va_list args;
  193. char prefix[NF_LOG_PREFIXLEN];
  194. const struct nf_logger *logger;
  195. rcu_read_lock();
  196. logger = rcu_dereference(net->nf.nf_loggers[pf]);
  197. if (logger) {
  198. va_start(args, fmt);
  199. vsnprintf(prefix, sizeof(prefix), fmt, args);
  200. va_end(args);
  201. logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
  202. }
  203. rcu_read_unlock();
  204. }
  205. EXPORT_SYMBOL(nf_log_trace);
  206. #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
  207. struct nf_log_buf {
  208. unsigned int count;
  209. char buf[S_SIZE + 1];
  210. };
  211. static struct nf_log_buf emergency, *emergency_ptr = &emergency;
  212. __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...)
  213. {
  214. va_list args;
  215. int len;
  216. if (likely(m->count < S_SIZE)) {
  217. va_start(args, f);
  218. len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
  219. va_end(args);
  220. if (likely(m->count + len < S_SIZE)) {
  221. m->count += len;
  222. return 0;
  223. }
  224. }
  225. m->count = S_SIZE;
  226. printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n");
  227. return -1;
  228. }
  229. EXPORT_SYMBOL_GPL(nf_log_buf_add);
  230. struct nf_log_buf *nf_log_buf_open(void)
  231. {
  232. struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC);
  233. if (unlikely(!m)) {
  234. local_bh_disable();
  235. do {
  236. m = xchg(&emergency_ptr, NULL);
  237. } while (!m);
  238. }
  239. m->count = 0;
  240. return m;
  241. }
  242. EXPORT_SYMBOL_GPL(nf_log_buf_open);
  243. void nf_log_buf_close(struct nf_log_buf *m)
  244. {
  245. m->buf[m->count] = 0;
  246. printk("%s\n", m->buf);
  247. if (likely(m != &emergency))
  248. kfree(m);
  249. else {
  250. emergency_ptr = m;
  251. local_bh_enable();
  252. }
  253. }
  254. EXPORT_SYMBOL_GPL(nf_log_buf_close);
  255. #ifdef CONFIG_PROC_FS
  256. static void *seq_start(struct seq_file *seq, loff_t *pos)
  257. {
  258. struct net *net = seq_file_net(seq);
  259. mutex_lock(&nf_log_mutex);
  260. if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
  261. return NULL;
  262. return pos;
  263. }
  264. static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
  265. {
  266. struct net *net = seq_file_net(s);
  267. (*pos)++;
  268. if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
  269. return NULL;
  270. return pos;
  271. }
  272. static void seq_stop(struct seq_file *s, void *v)
  273. {
  274. mutex_unlock(&nf_log_mutex);
  275. }
  276. static int seq_show(struct seq_file *s, void *v)
  277. {
  278. loff_t *pos = v;
  279. const struct nf_logger *logger;
  280. int i;
  281. struct net *net = seq_file_net(s);
  282. logger = nft_log_dereference(net->nf.nf_loggers[*pos]);
  283. if (!logger)
  284. seq_printf(s, "%2lld NONE (", *pos);
  285. else
  286. seq_printf(s, "%2lld %s (", *pos, logger->name);
  287. if (seq_has_overflowed(s))
  288. return -ENOSPC;
  289. for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
  290. if (loggers[*pos][i] == NULL)
  291. continue;
  292. logger = nft_log_dereference(loggers[*pos][i]);
  293. seq_printf(s, "%s", logger->name);
  294. if (i == 0 && loggers[*pos][i + 1] != NULL)
  295. seq_printf(s, ",");
  296. if (seq_has_overflowed(s))
  297. return -ENOSPC;
  298. }
  299. seq_printf(s, ")\n");
  300. if (seq_has_overflowed(s))
  301. return -ENOSPC;
  302. return 0;
  303. }
  304. static const struct seq_operations nflog_seq_ops = {
  305. .start = seq_start,
  306. .next = seq_next,
  307. .stop = seq_stop,
  308. .show = seq_show,
  309. };
  310. static int nflog_open(struct inode *inode, struct file *file)
  311. {
  312. return seq_open_net(inode, file, &nflog_seq_ops,
  313. sizeof(struct seq_net_private));
  314. }
  315. static const struct file_operations nflog_file_ops = {
  316. .owner = THIS_MODULE,
  317. .open = nflog_open,
  318. .read = seq_read,
  319. .llseek = seq_lseek,
  320. .release = seq_release_net,
  321. };
  322. #endif /* PROC_FS */
  323. #ifdef CONFIG_SYSCTL
  324. static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
  325. static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
  326. static int nf_log_proc_dostring(struct ctl_table *table, int write,
  327. void __user *buffer, size_t *lenp, loff_t *ppos)
  328. {
  329. const struct nf_logger *logger;
  330. char buf[NFLOGGER_NAME_LEN];
  331. size_t size = *lenp;
  332. int r = 0;
  333. int tindex = (unsigned long)table->extra1;
  334. struct net *net = table->extra2;
  335. if (write) {
  336. if (size > sizeof(buf))
  337. size = sizeof(buf);
  338. if (copy_from_user(buf, buffer, size))
  339. return -EFAULT;
  340. if (!strcmp(buf, "NONE")) {
  341. nf_log_unbind_pf(net, tindex);
  342. return 0;
  343. }
  344. mutex_lock(&nf_log_mutex);
  345. logger = __find_logger(tindex, buf);
  346. if (logger == NULL) {
  347. mutex_unlock(&nf_log_mutex);
  348. return -ENOENT;
  349. }
  350. rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
  351. mutex_unlock(&nf_log_mutex);
  352. } else {
  353. struct ctl_table tmp = *table;
  354. tmp.data = buf;
  355. mutex_lock(&nf_log_mutex);
  356. logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
  357. if (!logger)
  358. strlcpy(buf, "NONE", sizeof(buf));
  359. else
  360. strlcpy(buf, logger->name, sizeof(buf));
  361. mutex_unlock(&nf_log_mutex);
  362. r = proc_dostring(&tmp, write, buffer, lenp, ppos);
  363. }
  364. return r;
  365. }
  366. static int netfilter_log_sysctl_init(struct net *net)
  367. {
  368. int i;
  369. struct ctl_table *table;
  370. table = nf_log_sysctl_table;
  371. if (!net_eq(net, &init_net)) {
  372. table = kmemdup(nf_log_sysctl_table,
  373. sizeof(nf_log_sysctl_table),
  374. GFP_KERNEL);
  375. if (!table)
  376. goto err_alloc;
  377. } else {
  378. for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
  379. snprintf(nf_log_sysctl_fnames[i],
  380. 3, "%d", i);
  381. nf_log_sysctl_table[i].procname =
  382. nf_log_sysctl_fnames[i];
  383. nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN;
  384. nf_log_sysctl_table[i].mode = 0644;
  385. nf_log_sysctl_table[i].proc_handler =
  386. nf_log_proc_dostring;
  387. nf_log_sysctl_table[i].extra1 =
  388. (void *)(unsigned long) i;
  389. }
  390. }
  391. for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
  392. table[i].extra2 = net;
  393. net->nf.nf_log_dir_header = register_net_sysctl(net,
  394. "net/netfilter/nf_log",
  395. table);
  396. if (!net->nf.nf_log_dir_header)
  397. goto err_reg;
  398. return 0;
  399. err_reg:
  400. if (!net_eq(net, &init_net))
  401. kfree(table);
  402. err_alloc:
  403. return -ENOMEM;
  404. }
  405. static void netfilter_log_sysctl_exit(struct net *net)
  406. {
  407. struct ctl_table *table;
  408. table = net->nf.nf_log_dir_header->ctl_table_arg;
  409. unregister_net_sysctl_table(net->nf.nf_log_dir_header);
  410. if (!net_eq(net, &init_net))
  411. kfree(table);
  412. }
  413. #else
  414. static int netfilter_log_sysctl_init(struct net *net)
  415. {
  416. return 0;
  417. }
  418. static void netfilter_log_sysctl_exit(struct net *net)
  419. {
  420. }
  421. #endif /* CONFIG_SYSCTL */
  422. static int __net_init nf_log_net_init(struct net *net)
  423. {
  424. int ret = -ENOMEM;
  425. #ifdef CONFIG_PROC_FS
  426. if (!proc_create("nf_log", S_IRUGO,
  427. net->nf.proc_netfilter, &nflog_file_ops))
  428. return ret;
  429. #endif
  430. ret = netfilter_log_sysctl_init(net);
  431. if (ret < 0)
  432. goto out_sysctl;
  433. return 0;
  434. out_sysctl:
  435. #ifdef CONFIG_PROC_FS
  436. remove_proc_entry("nf_log", net->nf.proc_netfilter);
  437. #endif
  438. return ret;
  439. }
  440. static void __net_exit nf_log_net_exit(struct net *net)
  441. {
  442. netfilter_log_sysctl_exit(net);
  443. #ifdef CONFIG_PROC_FS
  444. remove_proc_entry("nf_log", net->nf.proc_netfilter);
  445. #endif
  446. }
  447. static struct pernet_operations nf_log_net_ops = {
  448. .init = nf_log_net_init,
  449. .exit = nf_log_net_exit,
  450. };
  451. int __init netfilter_log_init(void)
  452. {
  453. return register_pernet_subsys(&nf_log_net_ops);
  454. }