nf_log.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  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 NFLOGGER_NAME_LEN 64
  14. static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
  15. static DEFINE_MUTEX(nf_log_mutex);
  16. #define nft_log_dereference(logger) \
  17. rcu_dereference_protected(logger, lockdep_is_held(&nf_log_mutex))
  18. static struct nf_logger *__find_logger(int pf, const char *str_logger)
  19. {
  20. struct nf_logger *log;
  21. int i;
  22. for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
  23. if (loggers[pf][i] == NULL)
  24. continue;
  25. log = nft_log_dereference(loggers[pf][i]);
  26. if (!strncasecmp(str_logger, log->name, strlen(log->name)))
  27. return log;
  28. }
  29. return NULL;
  30. }
  31. int nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger)
  32. {
  33. const struct nf_logger *log;
  34. if (pf == NFPROTO_UNSPEC || pf >= ARRAY_SIZE(net->nf.nf_loggers))
  35. return -EOPNOTSUPP;
  36. mutex_lock(&nf_log_mutex);
  37. log = nft_log_dereference(net->nf.nf_loggers[pf]);
  38. if (log == NULL)
  39. rcu_assign_pointer(net->nf.nf_loggers[pf], logger);
  40. mutex_unlock(&nf_log_mutex);
  41. return 0;
  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 (pf == NFPROTO_INET) {
  136. ret = nf_logger_find_get(NFPROTO_IPV4, type);
  137. if (ret < 0)
  138. return ret;
  139. ret = nf_logger_find_get(NFPROTO_IPV6, type);
  140. if (ret < 0) {
  141. nf_logger_put(NFPROTO_IPV4, type);
  142. return ret;
  143. }
  144. return 0;
  145. }
  146. if (rcu_access_pointer(loggers[pf][type]) == NULL)
  147. request_module("nf-logger-%u-%u", pf, type);
  148. rcu_read_lock();
  149. logger = rcu_dereference(loggers[pf][type]);
  150. if (logger == NULL)
  151. goto out;
  152. if (try_module_get(logger->me))
  153. ret = 0;
  154. out:
  155. rcu_read_unlock();
  156. return ret;
  157. }
  158. EXPORT_SYMBOL_GPL(nf_logger_find_get);
  159. void nf_logger_put(int pf, enum nf_log_type type)
  160. {
  161. struct nf_logger *logger;
  162. if (pf == NFPROTO_INET) {
  163. nf_logger_put(NFPROTO_IPV4, type);
  164. nf_logger_put(NFPROTO_IPV6, type);
  165. return;
  166. }
  167. BUG_ON(loggers[pf][type] == NULL);
  168. rcu_read_lock();
  169. logger = rcu_dereference(loggers[pf][type]);
  170. module_put(logger->me);
  171. rcu_read_unlock();
  172. }
  173. EXPORT_SYMBOL_GPL(nf_logger_put);
  174. void nf_log_packet(struct net *net,
  175. u_int8_t pf,
  176. unsigned int hooknum,
  177. const struct sk_buff *skb,
  178. const struct net_device *in,
  179. const struct net_device *out,
  180. const struct nf_loginfo *loginfo,
  181. const char *fmt, ...)
  182. {
  183. va_list args;
  184. char prefix[NF_LOG_PREFIXLEN];
  185. const struct nf_logger *logger;
  186. rcu_read_lock();
  187. if (loginfo != NULL)
  188. logger = rcu_dereference(loggers[pf][loginfo->type]);
  189. else
  190. logger = rcu_dereference(net->nf.nf_loggers[pf]);
  191. if (logger) {
  192. va_start(args, fmt);
  193. vsnprintf(prefix, sizeof(prefix), fmt, args);
  194. va_end(args);
  195. logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
  196. }
  197. rcu_read_unlock();
  198. }
  199. EXPORT_SYMBOL(nf_log_packet);
  200. void nf_log_trace(struct net *net,
  201. u_int8_t pf,
  202. unsigned int hooknum,
  203. const struct sk_buff *skb,
  204. const struct net_device *in,
  205. const struct net_device *out,
  206. const struct nf_loginfo *loginfo, const char *fmt, ...)
  207. {
  208. va_list args;
  209. char prefix[NF_LOG_PREFIXLEN];
  210. const struct nf_logger *logger;
  211. rcu_read_lock();
  212. logger = rcu_dereference(net->nf.nf_loggers[pf]);
  213. if (logger) {
  214. va_start(args, fmt);
  215. vsnprintf(prefix, sizeof(prefix), fmt, args);
  216. va_end(args);
  217. logger->logfn(net, pf, hooknum, skb, in, out, loginfo, prefix);
  218. }
  219. rcu_read_unlock();
  220. }
  221. EXPORT_SYMBOL(nf_log_trace);
  222. #define S_SIZE (1024 - (sizeof(unsigned int) + 1))
  223. struct nf_log_buf {
  224. unsigned int count;
  225. char buf[S_SIZE + 1];
  226. };
  227. static struct nf_log_buf emergency, *emergency_ptr = &emergency;
  228. __printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...)
  229. {
  230. va_list args;
  231. int len;
  232. if (likely(m->count < S_SIZE)) {
  233. va_start(args, f);
  234. len = vsnprintf(m->buf + m->count, S_SIZE - m->count, f, args);
  235. va_end(args);
  236. if (likely(m->count + len < S_SIZE)) {
  237. m->count += len;
  238. return 0;
  239. }
  240. }
  241. m->count = S_SIZE;
  242. printk_once(KERN_ERR KBUILD_MODNAME " please increase S_SIZE\n");
  243. return -1;
  244. }
  245. EXPORT_SYMBOL_GPL(nf_log_buf_add);
  246. struct nf_log_buf *nf_log_buf_open(void)
  247. {
  248. struct nf_log_buf *m = kmalloc(sizeof(*m), GFP_ATOMIC);
  249. if (unlikely(!m)) {
  250. local_bh_disable();
  251. do {
  252. m = xchg(&emergency_ptr, NULL);
  253. } while (!m);
  254. }
  255. m->count = 0;
  256. return m;
  257. }
  258. EXPORT_SYMBOL_GPL(nf_log_buf_open);
  259. void nf_log_buf_close(struct nf_log_buf *m)
  260. {
  261. m->buf[m->count] = 0;
  262. printk("%s\n", m->buf);
  263. if (likely(m != &emergency))
  264. kfree(m);
  265. else {
  266. emergency_ptr = m;
  267. local_bh_enable();
  268. }
  269. }
  270. EXPORT_SYMBOL_GPL(nf_log_buf_close);
  271. #ifdef CONFIG_PROC_FS
  272. static void *seq_start(struct seq_file *seq, loff_t *pos)
  273. {
  274. struct net *net = seq_file_net(seq);
  275. mutex_lock(&nf_log_mutex);
  276. if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
  277. return NULL;
  278. return pos;
  279. }
  280. static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
  281. {
  282. struct net *net = seq_file_net(s);
  283. (*pos)++;
  284. if (*pos >= ARRAY_SIZE(net->nf.nf_loggers))
  285. return NULL;
  286. return pos;
  287. }
  288. static void seq_stop(struct seq_file *s, void *v)
  289. {
  290. mutex_unlock(&nf_log_mutex);
  291. }
  292. static int seq_show(struct seq_file *s, void *v)
  293. {
  294. loff_t *pos = v;
  295. const struct nf_logger *logger;
  296. int i;
  297. struct net *net = seq_file_net(s);
  298. logger = nft_log_dereference(net->nf.nf_loggers[*pos]);
  299. if (!logger)
  300. seq_printf(s, "%2lld NONE (", *pos);
  301. else
  302. seq_printf(s, "%2lld %s (", *pos, logger->name);
  303. if (seq_has_overflowed(s))
  304. return -ENOSPC;
  305. for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
  306. if (loggers[*pos][i] == NULL)
  307. continue;
  308. logger = nft_log_dereference(loggers[*pos][i]);
  309. seq_printf(s, "%s", logger->name);
  310. if (i == 0 && loggers[*pos][i + 1] != NULL)
  311. seq_printf(s, ",");
  312. if (seq_has_overflowed(s))
  313. return -ENOSPC;
  314. }
  315. seq_printf(s, ")\n");
  316. if (seq_has_overflowed(s))
  317. return -ENOSPC;
  318. return 0;
  319. }
  320. static const struct seq_operations nflog_seq_ops = {
  321. .start = seq_start,
  322. .next = seq_next,
  323. .stop = seq_stop,
  324. .show = seq_show,
  325. };
  326. static int nflog_open(struct inode *inode, struct file *file)
  327. {
  328. return seq_open_net(inode, file, &nflog_seq_ops,
  329. sizeof(struct seq_net_private));
  330. }
  331. static const struct file_operations nflog_file_ops = {
  332. .owner = THIS_MODULE,
  333. .open = nflog_open,
  334. .read = seq_read,
  335. .llseek = seq_lseek,
  336. .release = seq_release_net,
  337. };
  338. #endif /* PROC_FS */
  339. #ifdef CONFIG_SYSCTL
  340. static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
  341. static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
  342. static int nf_log_proc_dostring(struct ctl_table *table, int write,
  343. void __user *buffer, size_t *lenp, loff_t *ppos)
  344. {
  345. const struct nf_logger *logger;
  346. char buf[NFLOGGER_NAME_LEN];
  347. int r = 0;
  348. int tindex = (unsigned long)table->extra1;
  349. struct net *net = table->extra2;
  350. if (write) {
  351. struct ctl_table tmp = *table;
  352. /* proc_dostring() can append to existing strings, so we need to
  353. * initialize it as an empty string.
  354. */
  355. buf[0] = '\0';
  356. tmp.data = buf;
  357. r = proc_dostring(&tmp, write, buffer, lenp, ppos);
  358. if (r)
  359. return r;
  360. if (!strcmp(buf, "NONE")) {
  361. nf_log_unbind_pf(net, tindex);
  362. return 0;
  363. }
  364. mutex_lock(&nf_log_mutex);
  365. logger = __find_logger(tindex, buf);
  366. if (logger == NULL) {
  367. mutex_unlock(&nf_log_mutex);
  368. return -ENOENT;
  369. }
  370. rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
  371. mutex_unlock(&nf_log_mutex);
  372. } else {
  373. struct ctl_table tmp = *table;
  374. tmp.data = buf;
  375. mutex_lock(&nf_log_mutex);
  376. logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
  377. if (!logger)
  378. strlcpy(buf, "NONE", sizeof(buf));
  379. else
  380. strlcpy(buf, logger->name, sizeof(buf));
  381. mutex_unlock(&nf_log_mutex);
  382. r = proc_dostring(&tmp, write, buffer, lenp, ppos);
  383. }
  384. return r;
  385. }
  386. static int netfilter_log_sysctl_init(struct net *net)
  387. {
  388. int i;
  389. struct ctl_table *table;
  390. table = nf_log_sysctl_table;
  391. if (!net_eq(net, &init_net)) {
  392. table = kmemdup(nf_log_sysctl_table,
  393. sizeof(nf_log_sysctl_table),
  394. GFP_KERNEL);
  395. if (!table)
  396. goto err_alloc;
  397. } else {
  398. for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
  399. snprintf(nf_log_sysctl_fnames[i],
  400. 3, "%d", i);
  401. nf_log_sysctl_table[i].procname =
  402. nf_log_sysctl_fnames[i];
  403. nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN;
  404. nf_log_sysctl_table[i].mode = 0644;
  405. nf_log_sysctl_table[i].proc_handler =
  406. nf_log_proc_dostring;
  407. nf_log_sysctl_table[i].extra1 =
  408. (void *)(unsigned long) i;
  409. }
  410. }
  411. for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
  412. table[i].extra2 = net;
  413. net->nf.nf_log_dir_header = register_net_sysctl(net,
  414. "net/netfilter/nf_log",
  415. table);
  416. if (!net->nf.nf_log_dir_header)
  417. goto err_reg;
  418. return 0;
  419. err_reg:
  420. if (!net_eq(net, &init_net))
  421. kfree(table);
  422. err_alloc:
  423. return -ENOMEM;
  424. }
  425. static void netfilter_log_sysctl_exit(struct net *net)
  426. {
  427. struct ctl_table *table;
  428. table = net->nf.nf_log_dir_header->ctl_table_arg;
  429. unregister_net_sysctl_table(net->nf.nf_log_dir_header);
  430. if (!net_eq(net, &init_net))
  431. kfree(table);
  432. }
  433. #else
  434. static int netfilter_log_sysctl_init(struct net *net)
  435. {
  436. return 0;
  437. }
  438. static void netfilter_log_sysctl_exit(struct net *net)
  439. {
  440. }
  441. #endif /* CONFIG_SYSCTL */
  442. static int __net_init nf_log_net_init(struct net *net)
  443. {
  444. int ret = -ENOMEM;
  445. #ifdef CONFIG_PROC_FS
  446. if (!proc_create("nf_log", S_IRUGO,
  447. net->nf.proc_netfilter, &nflog_file_ops))
  448. return ret;
  449. #endif
  450. ret = netfilter_log_sysctl_init(net);
  451. if (ret < 0)
  452. goto out_sysctl;
  453. return 0;
  454. out_sysctl:
  455. #ifdef CONFIG_PROC_FS
  456. remove_proc_entry("nf_log", net->nf.proc_netfilter);
  457. #endif
  458. return ret;
  459. }
  460. static void __net_exit nf_log_net_exit(struct net *net)
  461. {
  462. netfilter_log_sysctl_exit(net);
  463. #ifdef CONFIG_PROC_FS
  464. remove_proc_entry("nf_log", net->nf.proc_netfilter);
  465. #endif
  466. }
  467. static struct pernet_operations nf_log_net_ops = {
  468. .init = nf_log_net_init,
  469. .exit = nf_log_net_exit,
  470. };
  471. int __init netfilter_log_init(void)
  472. {
  473. return register_pernet_subsys(&nf_log_net_ops);
  474. }