nf_conntrack_standalone.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. /* (C) 1999-2001 Paul `Rusty' Russell
  2. * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
  3. * (C) 2005-2012 Patrick McHardy <kaber@trash.net>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. */
  9. #include <linux/types.h>
  10. #include <linux/netfilter.h>
  11. #include <linux/slab.h>
  12. #include <linux/module.h>
  13. #include <linux/skbuff.h>
  14. #include <linux/proc_fs.h>
  15. #include <linux/seq_file.h>
  16. #include <linux/percpu.h>
  17. #include <linux/netdevice.h>
  18. #include <linux/security.h>
  19. #include <net/net_namespace.h>
  20. #ifdef CONFIG_SYSCTL
  21. #include <linux/sysctl.h>
  22. #endif
  23. #include <net/netfilter/nf_conntrack.h>
  24. #include <net/netfilter/nf_conntrack_core.h>
  25. #include <net/netfilter/nf_conntrack_l3proto.h>
  26. #include <net/netfilter/nf_conntrack_l4proto.h>
  27. #include <net/netfilter/nf_conntrack_expect.h>
  28. #include <net/netfilter/nf_conntrack_helper.h>
  29. #include <net/netfilter/nf_conntrack_acct.h>
  30. #include <net/netfilter/nf_conntrack_zones.h>
  31. #include <net/netfilter/nf_conntrack_timestamp.h>
  32. #include <linux/rculist_nulls.h>
  33. MODULE_LICENSE("GPL");
  34. #ifdef CONFIG_NF_CONNTRACK_PROCFS
  35. void
  36. print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
  37. const struct nf_conntrack_l3proto *l3proto,
  38. const struct nf_conntrack_l4proto *l4proto)
  39. {
  40. l3proto->print_tuple(s, tuple);
  41. l4proto->print_tuple(s, tuple);
  42. }
  43. EXPORT_SYMBOL_GPL(print_tuple);
  44. struct ct_iter_state {
  45. struct seq_net_private p;
  46. unsigned int bucket;
  47. u_int64_t time_now;
  48. };
  49. static struct hlist_nulls_node *ct_get_first(struct seq_file *seq)
  50. {
  51. struct net *net = seq_file_net(seq);
  52. struct ct_iter_state *st = seq->private;
  53. struct hlist_nulls_node *n;
  54. for (st->bucket = 0;
  55. st->bucket < net->ct.htable_size;
  56. st->bucket++) {
  57. n = rcu_dereference(hlist_nulls_first_rcu(&net->ct.hash[st->bucket]));
  58. if (!is_a_nulls(n))
  59. return n;
  60. }
  61. return NULL;
  62. }
  63. static struct hlist_nulls_node *ct_get_next(struct seq_file *seq,
  64. struct hlist_nulls_node *head)
  65. {
  66. struct net *net = seq_file_net(seq);
  67. struct ct_iter_state *st = seq->private;
  68. head = rcu_dereference(hlist_nulls_next_rcu(head));
  69. while (is_a_nulls(head)) {
  70. if (likely(get_nulls_value(head) == st->bucket)) {
  71. if (++st->bucket >= net->ct.htable_size)
  72. return NULL;
  73. }
  74. head = rcu_dereference(
  75. hlist_nulls_first_rcu(
  76. &net->ct.hash[st->bucket]));
  77. }
  78. return head;
  79. }
  80. static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos)
  81. {
  82. struct hlist_nulls_node *head = ct_get_first(seq);
  83. if (head)
  84. while (pos && (head = ct_get_next(seq, head)))
  85. pos--;
  86. return pos ? NULL : head;
  87. }
  88. static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
  89. __acquires(RCU)
  90. {
  91. struct ct_iter_state *st = seq->private;
  92. st->time_now = ktime_get_real_ns();
  93. rcu_read_lock();
  94. return ct_get_idx(seq, *pos);
  95. }
  96. static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
  97. {
  98. (*pos)++;
  99. return ct_get_next(s, v);
  100. }
  101. static void ct_seq_stop(struct seq_file *s, void *v)
  102. __releases(RCU)
  103. {
  104. rcu_read_unlock();
  105. }
  106. #ifdef CONFIG_NF_CONNTRACK_SECMARK
  107. static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
  108. {
  109. int ret;
  110. u32 len;
  111. char *secctx;
  112. ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
  113. if (ret)
  114. return;
  115. seq_printf(s, "secctx=%s ", secctx);
  116. security_release_secctx(secctx, len);
  117. }
  118. #else
  119. static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
  120. {
  121. }
  122. #endif
  123. #ifdef CONFIG_NF_CONNTRACK_ZONES
  124. static void ct_show_zone(struct seq_file *s, const struct nf_conn *ct,
  125. int dir)
  126. {
  127. const struct nf_conntrack_zone *zone = nf_ct_zone(ct);
  128. if (zone->dir != dir)
  129. return;
  130. switch (zone->dir) {
  131. case NF_CT_DEFAULT_ZONE_DIR:
  132. seq_printf(s, "zone=%u ", zone->id);
  133. break;
  134. case NF_CT_ZONE_DIR_ORIG:
  135. seq_printf(s, "zone-orig=%u ", zone->id);
  136. break;
  137. case NF_CT_ZONE_DIR_REPL:
  138. seq_printf(s, "zone-reply=%u ", zone->id);
  139. break;
  140. default:
  141. break;
  142. }
  143. }
  144. #else
  145. static inline void ct_show_zone(struct seq_file *s, const struct nf_conn *ct,
  146. int dir)
  147. {
  148. }
  149. #endif
  150. #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
  151. static void ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
  152. {
  153. struct ct_iter_state *st = s->private;
  154. struct nf_conn_tstamp *tstamp;
  155. s64 delta_time;
  156. tstamp = nf_conn_tstamp_find(ct);
  157. if (tstamp) {
  158. delta_time = st->time_now - tstamp->start;
  159. if (delta_time > 0)
  160. delta_time = div_s64(delta_time, NSEC_PER_SEC);
  161. else
  162. delta_time = 0;
  163. seq_printf(s, "delta-time=%llu ",
  164. (unsigned long long)delta_time);
  165. }
  166. return;
  167. }
  168. #else
  169. static inline void
  170. ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
  171. {
  172. }
  173. #endif
  174. /* return 0 on success, 1 in case of error */
  175. static int ct_seq_show(struct seq_file *s, void *v)
  176. {
  177. struct nf_conntrack_tuple_hash *hash = v;
  178. struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
  179. const struct nf_conntrack_l3proto *l3proto;
  180. const struct nf_conntrack_l4proto *l4proto;
  181. int ret = 0;
  182. NF_CT_ASSERT(ct);
  183. if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
  184. return 0;
  185. /* we only want to print DIR_ORIGINAL */
  186. if (NF_CT_DIRECTION(hash))
  187. goto release;
  188. l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));
  189. NF_CT_ASSERT(l3proto);
  190. l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
  191. NF_CT_ASSERT(l4proto);
  192. ret = -ENOSPC;
  193. seq_printf(s, "%-8s %u %-8s %u %ld ",
  194. l3proto->name, nf_ct_l3num(ct),
  195. l4proto->name, nf_ct_protonum(ct),
  196. timer_pending(&ct->timeout)
  197. ? (long)(ct->timeout.expires - jiffies)/HZ : 0);
  198. if (l4proto->print_conntrack)
  199. l4proto->print_conntrack(s, ct);
  200. print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
  201. l3proto, l4proto);
  202. ct_show_zone(s, ct, NF_CT_ZONE_DIR_ORIG);
  203. if (seq_has_overflowed(s))
  204. goto release;
  205. if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL))
  206. goto release;
  207. if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
  208. seq_printf(s, "[UNREPLIED] ");
  209. print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
  210. l3proto, l4proto);
  211. ct_show_zone(s, ct, NF_CT_ZONE_DIR_REPL);
  212. if (seq_print_acct(s, ct, IP_CT_DIR_REPLY))
  213. goto release;
  214. if (test_bit(IPS_ASSURED_BIT, &ct->status))
  215. seq_printf(s, "[ASSURED] ");
  216. if (seq_has_overflowed(s))
  217. goto release;
  218. #if defined(CONFIG_NF_CONNTRACK_MARK)
  219. seq_printf(s, "mark=%u ", ct->mark);
  220. #endif
  221. ct_show_secctx(s, ct);
  222. ct_show_zone(s, ct, NF_CT_DEFAULT_ZONE_DIR);
  223. ct_show_delta_time(s, ct);
  224. seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use));
  225. if (seq_has_overflowed(s))
  226. goto release;
  227. ret = 0;
  228. release:
  229. nf_ct_put(ct);
  230. return ret;
  231. }
  232. static const struct seq_operations ct_seq_ops = {
  233. .start = ct_seq_start,
  234. .next = ct_seq_next,
  235. .stop = ct_seq_stop,
  236. .show = ct_seq_show
  237. };
  238. static int ct_open(struct inode *inode, struct file *file)
  239. {
  240. return seq_open_net(inode, file, &ct_seq_ops,
  241. sizeof(struct ct_iter_state));
  242. }
  243. static const struct file_operations ct_file_ops = {
  244. .owner = THIS_MODULE,
  245. .open = ct_open,
  246. .read = seq_read,
  247. .llseek = seq_lseek,
  248. .release = seq_release_net,
  249. };
  250. static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
  251. {
  252. struct net *net = seq_file_net(seq);
  253. int cpu;
  254. if (*pos == 0)
  255. return SEQ_START_TOKEN;
  256. for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
  257. if (!cpu_possible(cpu))
  258. continue;
  259. *pos = cpu + 1;
  260. return per_cpu_ptr(net->ct.stat, cpu);
  261. }
  262. return NULL;
  263. }
  264. static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
  265. {
  266. struct net *net = seq_file_net(seq);
  267. int cpu;
  268. for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
  269. if (!cpu_possible(cpu))
  270. continue;
  271. *pos = cpu + 1;
  272. return per_cpu_ptr(net->ct.stat, cpu);
  273. }
  274. return NULL;
  275. }
  276. static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
  277. {
  278. }
  279. static int ct_cpu_seq_show(struct seq_file *seq, void *v)
  280. {
  281. struct net *net = seq_file_net(seq);
  282. unsigned int nr_conntracks = atomic_read(&net->ct.count);
  283. const struct ip_conntrack_stat *st = v;
  284. if (v == SEQ_START_TOKEN) {
  285. seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart\n");
  286. return 0;
  287. }
  288. seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x "
  289. "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
  290. nr_conntracks,
  291. st->searched,
  292. st->found,
  293. st->new,
  294. st->invalid,
  295. st->ignore,
  296. st->delete,
  297. st->delete_list,
  298. st->insert,
  299. st->insert_failed,
  300. st->drop,
  301. st->early_drop,
  302. st->error,
  303. st->expect_new,
  304. st->expect_create,
  305. st->expect_delete,
  306. st->search_restart
  307. );
  308. return 0;
  309. }
  310. static const struct seq_operations ct_cpu_seq_ops = {
  311. .start = ct_cpu_seq_start,
  312. .next = ct_cpu_seq_next,
  313. .stop = ct_cpu_seq_stop,
  314. .show = ct_cpu_seq_show,
  315. };
  316. static int ct_cpu_seq_open(struct inode *inode, struct file *file)
  317. {
  318. return seq_open_net(inode, file, &ct_cpu_seq_ops,
  319. sizeof(struct seq_net_private));
  320. }
  321. static const struct file_operations ct_cpu_seq_fops = {
  322. .owner = THIS_MODULE,
  323. .open = ct_cpu_seq_open,
  324. .read = seq_read,
  325. .llseek = seq_lseek,
  326. .release = seq_release_net,
  327. };
  328. static int nf_conntrack_standalone_init_proc(struct net *net)
  329. {
  330. struct proc_dir_entry *pde;
  331. pde = proc_create("nf_conntrack", 0440, net->proc_net, &ct_file_ops);
  332. if (!pde)
  333. goto out_nf_conntrack;
  334. pde = proc_create("nf_conntrack", S_IRUGO, net->proc_net_stat,
  335. &ct_cpu_seq_fops);
  336. if (!pde)
  337. goto out_stat_nf_conntrack;
  338. return 0;
  339. out_stat_nf_conntrack:
  340. remove_proc_entry("nf_conntrack", net->proc_net);
  341. out_nf_conntrack:
  342. return -ENOMEM;
  343. }
  344. static void nf_conntrack_standalone_fini_proc(struct net *net)
  345. {
  346. remove_proc_entry("nf_conntrack", net->proc_net_stat);
  347. remove_proc_entry("nf_conntrack", net->proc_net);
  348. }
  349. #else
  350. static int nf_conntrack_standalone_init_proc(struct net *net)
  351. {
  352. return 0;
  353. }
  354. static void nf_conntrack_standalone_fini_proc(struct net *net)
  355. {
  356. }
  357. #endif /* CONFIG_NF_CONNTRACK_PROCFS */
  358. /* Sysctl support */
  359. #ifdef CONFIG_SYSCTL
  360. /* Log invalid packets of a given protocol */
  361. static int log_invalid_proto_min = 0;
  362. static int log_invalid_proto_max = 255;
  363. static struct ctl_table_header *nf_ct_netfilter_header;
  364. static struct ctl_table nf_ct_sysctl_table[] = {
  365. {
  366. .procname = "nf_conntrack_max",
  367. .data = &nf_conntrack_max,
  368. .maxlen = sizeof(int),
  369. .mode = 0644,
  370. .proc_handler = proc_dointvec,
  371. },
  372. {
  373. .procname = "nf_conntrack_count",
  374. .data = &init_net.ct.count,
  375. .maxlen = sizeof(int),
  376. .mode = 0444,
  377. .proc_handler = proc_dointvec,
  378. },
  379. {
  380. .procname = "nf_conntrack_buckets",
  381. .data = &init_net.ct.htable_size,
  382. .maxlen = sizeof(unsigned int),
  383. .mode = 0444,
  384. .proc_handler = proc_dointvec,
  385. },
  386. {
  387. .procname = "nf_conntrack_checksum",
  388. .data = &init_net.ct.sysctl_checksum,
  389. .maxlen = sizeof(unsigned int),
  390. .mode = 0644,
  391. .proc_handler = proc_dointvec,
  392. },
  393. {
  394. .procname = "nf_conntrack_log_invalid",
  395. .data = &init_net.ct.sysctl_log_invalid,
  396. .maxlen = sizeof(unsigned int),
  397. .mode = 0644,
  398. .proc_handler = proc_dointvec_minmax,
  399. .extra1 = &log_invalid_proto_min,
  400. .extra2 = &log_invalid_proto_max,
  401. },
  402. {
  403. .procname = "nf_conntrack_expect_max",
  404. .data = &nf_ct_expect_max,
  405. .maxlen = sizeof(int),
  406. .mode = 0644,
  407. .proc_handler = proc_dointvec,
  408. },
  409. { }
  410. };
  411. #define NET_NF_CONNTRACK_MAX 2089
  412. static struct ctl_table nf_ct_netfilter_table[] = {
  413. {
  414. .procname = "nf_conntrack_max",
  415. .data = &nf_conntrack_max,
  416. .maxlen = sizeof(int),
  417. .mode = 0644,
  418. .proc_handler = proc_dointvec,
  419. },
  420. { }
  421. };
  422. static int nf_conntrack_standalone_init_sysctl(struct net *net)
  423. {
  424. struct ctl_table *table;
  425. table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table),
  426. GFP_KERNEL);
  427. if (!table)
  428. goto out_kmemdup;
  429. table[1].data = &net->ct.count;
  430. table[2].data = &net->ct.htable_size;
  431. table[3].data = &net->ct.sysctl_checksum;
  432. table[4].data = &net->ct.sysctl_log_invalid;
  433. /* Don't export sysctls to unprivileged users */
  434. if (net->user_ns != &init_user_ns)
  435. table[0].procname = NULL;
  436. net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table);
  437. if (!net->ct.sysctl_header)
  438. goto out_unregister_netfilter;
  439. return 0;
  440. out_unregister_netfilter:
  441. kfree(table);
  442. out_kmemdup:
  443. return -ENOMEM;
  444. }
  445. static void nf_conntrack_standalone_fini_sysctl(struct net *net)
  446. {
  447. struct ctl_table *table;
  448. table = net->ct.sysctl_header->ctl_table_arg;
  449. unregister_net_sysctl_table(net->ct.sysctl_header);
  450. kfree(table);
  451. }
  452. #else
  453. static int nf_conntrack_standalone_init_sysctl(struct net *net)
  454. {
  455. return 0;
  456. }
  457. static void nf_conntrack_standalone_fini_sysctl(struct net *net)
  458. {
  459. }
  460. #endif /* CONFIG_SYSCTL */
  461. static int nf_conntrack_pernet_init(struct net *net)
  462. {
  463. int ret;
  464. ret = nf_conntrack_init_net(net);
  465. if (ret < 0)
  466. goto out_init;
  467. ret = nf_conntrack_standalone_init_proc(net);
  468. if (ret < 0)
  469. goto out_proc;
  470. net->ct.sysctl_checksum = 1;
  471. net->ct.sysctl_log_invalid = 0;
  472. ret = nf_conntrack_standalone_init_sysctl(net);
  473. if (ret < 0)
  474. goto out_sysctl;
  475. return 0;
  476. out_sysctl:
  477. nf_conntrack_standalone_fini_proc(net);
  478. out_proc:
  479. nf_conntrack_cleanup_net(net);
  480. out_init:
  481. return ret;
  482. }
  483. static void nf_conntrack_pernet_exit(struct list_head *net_exit_list)
  484. {
  485. struct net *net;
  486. list_for_each_entry(net, net_exit_list, exit_list) {
  487. nf_conntrack_standalone_fini_sysctl(net);
  488. nf_conntrack_standalone_fini_proc(net);
  489. }
  490. nf_conntrack_cleanup_net_list(net_exit_list);
  491. }
  492. static struct pernet_operations nf_conntrack_net_ops = {
  493. .init = nf_conntrack_pernet_init,
  494. .exit_batch = nf_conntrack_pernet_exit,
  495. };
  496. static int __init nf_conntrack_standalone_init(void)
  497. {
  498. int ret = nf_conntrack_init_start();
  499. if (ret < 0)
  500. goto out_start;
  501. #ifdef CONFIG_SYSCTL
  502. nf_ct_netfilter_header =
  503. register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
  504. if (!nf_ct_netfilter_header) {
  505. pr_err("nf_conntrack: can't register to sysctl.\n");
  506. ret = -ENOMEM;
  507. goto out_sysctl;
  508. }
  509. #endif
  510. ret = register_pernet_subsys(&nf_conntrack_net_ops);
  511. if (ret < 0)
  512. goto out_pernet;
  513. nf_conntrack_init_end();
  514. return 0;
  515. out_pernet:
  516. #ifdef CONFIG_SYSCTL
  517. unregister_net_sysctl_table(nf_ct_netfilter_header);
  518. out_sysctl:
  519. #endif
  520. nf_conntrack_cleanup_end();
  521. out_start:
  522. return ret;
  523. }
  524. static void __exit nf_conntrack_standalone_fini(void)
  525. {
  526. nf_conntrack_cleanup_start();
  527. unregister_pernet_subsys(&nf_conntrack_net_ops);
  528. #ifdef CONFIG_SYSCTL
  529. unregister_net_sysctl_table(nf_ct_netfilter_header);
  530. #endif
  531. nf_conntrack_cleanup_end();
  532. }
  533. module_init(nf_conntrack_standalone_init);
  534. module_exit(nf_conntrack_standalone_fini);
  535. /* Some modules need us, but don't depend directly on any symbol.
  536. They should call this. */
  537. void need_conntrack(void)
  538. {
  539. }
  540. EXPORT_SYMBOL_GPL(need_conntrack);