nf_log.c 13 KB

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