nf_log.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  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. tmp.data = buf;
  353. r = proc_dostring(&tmp, write, buffer, lenp, ppos);
  354. if (r)
  355. return r;
  356. if (!strcmp(buf, "NONE")) {
  357. nf_log_unbind_pf(net, tindex);
  358. return 0;
  359. }
  360. mutex_lock(&nf_log_mutex);
  361. logger = __find_logger(tindex, buf);
  362. if (logger == NULL) {
  363. mutex_unlock(&nf_log_mutex);
  364. return -ENOENT;
  365. }
  366. rcu_assign_pointer(net->nf.nf_loggers[tindex], logger);
  367. mutex_unlock(&nf_log_mutex);
  368. } else {
  369. struct ctl_table tmp = *table;
  370. tmp.data = buf;
  371. mutex_lock(&nf_log_mutex);
  372. logger = nft_log_dereference(net->nf.nf_loggers[tindex]);
  373. if (!logger)
  374. strlcpy(buf, "NONE", sizeof(buf));
  375. else
  376. strlcpy(buf, logger->name, sizeof(buf));
  377. mutex_unlock(&nf_log_mutex);
  378. r = proc_dostring(&tmp, write, buffer, lenp, ppos);
  379. }
  380. return r;
  381. }
  382. static int netfilter_log_sysctl_init(struct net *net)
  383. {
  384. int i;
  385. struct ctl_table *table;
  386. table = nf_log_sysctl_table;
  387. if (!net_eq(net, &init_net)) {
  388. table = kmemdup(nf_log_sysctl_table,
  389. sizeof(nf_log_sysctl_table),
  390. GFP_KERNEL);
  391. if (!table)
  392. goto err_alloc;
  393. } else {
  394. for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
  395. snprintf(nf_log_sysctl_fnames[i],
  396. 3, "%d", i);
  397. nf_log_sysctl_table[i].procname =
  398. nf_log_sysctl_fnames[i];
  399. nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN;
  400. nf_log_sysctl_table[i].mode = 0644;
  401. nf_log_sysctl_table[i].proc_handler =
  402. nf_log_proc_dostring;
  403. nf_log_sysctl_table[i].extra1 =
  404. (void *)(unsigned long) i;
  405. }
  406. }
  407. for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
  408. table[i].extra2 = net;
  409. net->nf.nf_log_dir_header = register_net_sysctl(net,
  410. "net/netfilter/nf_log",
  411. table);
  412. if (!net->nf.nf_log_dir_header)
  413. goto err_reg;
  414. return 0;
  415. err_reg:
  416. if (!net_eq(net, &init_net))
  417. kfree(table);
  418. err_alloc:
  419. return -ENOMEM;
  420. }
  421. static void netfilter_log_sysctl_exit(struct net *net)
  422. {
  423. struct ctl_table *table;
  424. table = net->nf.nf_log_dir_header->ctl_table_arg;
  425. unregister_net_sysctl_table(net->nf.nf_log_dir_header);
  426. if (!net_eq(net, &init_net))
  427. kfree(table);
  428. }
  429. #else
  430. static int netfilter_log_sysctl_init(struct net *net)
  431. {
  432. return 0;
  433. }
  434. static void netfilter_log_sysctl_exit(struct net *net)
  435. {
  436. }
  437. #endif /* CONFIG_SYSCTL */
  438. static int __net_init nf_log_net_init(struct net *net)
  439. {
  440. int ret = -ENOMEM;
  441. #ifdef CONFIG_PROC_FS
  442. if (!proc_create("nf_log", S_IRUGO,
  443. net->nf.proc_netfilter, &nflog_file_ops))
  444. return ret;
  445. #endif
  446. ret = netfilter_log_sysctl_init(net);
  447. if (ret < 0)
  448. goto out_sysctl;
  449. return 0;
  450. out_sysctl:
  451. #ifdef CONFIG_PROC_FS
  452. remove_proc_entry("nf_log", net->nf.proc_netfilter);
  453. #endif
  454. return ret;
  455. }
  456. static void __net_exit nf_log_net_exit(struct net *net)
  457. {
  458. netfilter_log_sysctl_exit(net);
  459. #ifdef CONFIG_PROC_FS
  460. remove_proc_entry("nf_log", net->nf.proc_netfilter);
  461. #endif
  462. }
  463. static struct pernet_operations nf_log_net_ops = {
  464. .init = nf_log_net_init,
  465. .exit = nf_log_net_exit,
  466. };
  467. int __init netfilter_log_init(void)
  468. {
  469. return register_pernet_subsys(&nf_log_net_ops);
  470. }