nf_conntrack_proto_udplite.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /* (C) 1999-2001 Paul `Rusty' Russell
  2. * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
  3. * (C) 2007 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/timer.h>
  11. #include <linux/module.h>
  12. #include <linux/udp.h>
  13. #include <linux/seq_file.h>
  14. #include <linux/skbuff.h>
  15. #include <linux/ipv6.h>
  16. #include <net/ip6_checksum.h>
  17. #include <net/checksum.h>
  18. #include <linux/netfilter.h>
  19. #include <linux/netfilter_ipv4.h>
  20. #include <linux/netfilter_ipv6.h>
  21. #include <net/netfilter/nf_conntrack_l4proto.h>
  22. #include <net/netfilter/nf_conntrack_ecache.h>
  23. #include <net/netfilter/nf_log.h>
  24. enum udplite_conntrack {
  25. UDPLITE_CT_UNREPLIED,
  26. UDPLITE_CT_REPLIED,
  27. UDPLITE_CT_MAX
  28. };
  29. static unsigned int udplite_timeouts[UDPLITE_CT_MAX] = {
  30. [UDPLITE_CT_UNREPLIED] = 30*HZ,
  31. [UDPLITE_CT_REPLIED] = 180*HZ,
  32. };
  33. static int udplite_net_id __read_mostly;
  34. struct udplite_net {
  35. struct nf_proto_net pn;
  36. unsigned int timeouts[UDPLITE_CT_MAX];
  37. };
  38. static inline struct udplite_net *udplite_pernet(struct net *net)
  39. {
  40. return net_generic(net, udplite_net_id);
  41. }
  42. static bool udplite_pkt_to_tuple(const struct sk_buff *skb,
  43. unsigned int dataoff,
  44. struct net *net,
  45. struct nf_conntrack_tuple *tuple)
  46. {
  47. const struct udphdr *hp;
  48. struct udphdr _hdr;
  49. hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
  50. if (hp == NULL)
  51. return false;
  52. tuple->src.u.udp.port = hp->source;
  53. tuple->dst.u.udp.port = hp->dest;
  54. return true;
  55. }
  56. static bool udplite_invert_tuple(struct nf_conntrack_tuple *tuple,
  57. const struct nf_conntrack_tuple *orig)
  58. {
  59. tuple->src.u.udp.port = orig->dst.u.udp.port;
  60. tuple->dst.u.udp.port = orig->src.u.udp.port;
  61. return true;
  62. }
  63. /* Print out the per-protocol part of the tuple. */
  64. static void udplite_print_tuple(struct seq_file *s,
  65. const struct nf_conntrack_tuple *tuple)
  66. {
  67. seq_printf(s, "sport=%hu dport=%hu ",
  68. ntohs(tuple->src.u.udp.port),
  69. ntohs(tuple->dst.u.udp.port));
  70. }
  71. static unsigned int *udplite_get_timeouts(struct net *net)
  72. {
  73. return udplite_pernet(net)->timeouts;
  74. }
  75. /* Returns verdict for packet, and may modify conntracktype */
  76. static int udplite_packet(struct nf_conn *ct,
  77. const struct sk_buff *skb,
  78. unsigned int dataoff,
  79. enum ip_conntrack_info ctinfo,
  80. u_int8_t pf,
  81. unsigned int hooknum,
  82. unsigned int *timeouts)
  83. {
  84. /* If we've seen traffic both ways, this is some kind of UDP
  85. stream. Extend timeout. */
  86. if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
  87. nf_ct_refresh_acct(ct, ctinfo, skb,
  88. timeouts[UDPLITE_CT_REPLIED]);
  89. /* Also, more likely to be important, and not a probe */
  90. if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
  91. nf_conntrack_event_cache(IPCT_ASSURED, ct);
  92. } else {
  93. nf_ct_refresh_acct(ct, ctinfo, skb,
  94. timeouts[UDPLITE_CT_UNREPLIED]);
  95. }
  96. return NF_ACCEPT;
  97. }
  98. /* Called when a new connection for this protocol found. */
  99. static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb,
  100. unsigned int dataoff, unsigned int *timeouts)
  101. {
  102. return true;
  103. }
  104. static int udplite_error(struct net *net, struct nf_conn *tmpl,
  105. struct sk_buff *skb,
  106. unsigned int dataoff,
  107. enum ip_conntrack_info *ctinfo,
  108. u_int8_t pf,
  109. unsigned int hooknum)
  110. {
  111. unsigned int udplen = skb->len - dataoff;
  112. const struct udphdr *hdr;
  113. struct udphdr _hdr;
  114. unsigned int cscov;
  115. /* Header is too small? */
  116. hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
  117. if (hdr == NULL) {
  118. if (LOG_INVALID(net, IPPROTO_UDPLITE))
  119. nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
  120. "nf_ct_udplite: short packet ");
  121. return -NF_ACCEPT;
  122. }
  123. cscov = ntohs(hdr->len);
  124. if (cscov == 0)
  125. cscov = udplen;
  126. else if (cscov < sizeof(*hdr) || cscov > udplen) {
  127. if (LOG_INVALID(net, IPPROTO_UDPLITE))
  128. nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
  129. "nf_ct_udplite: invalid checksum coverage ");
  130. return -NF_ACCEPT;
  131. }
  132. /* UDPLITE mandates checksums */
  133. if (!hdr->check) {
  134. if (LOG_INVALID(net, IPPROTO_UDPLITE))
  135. nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
  136. "nf_ct_udplite: checksum missing ");
  137. return -NF_ACCEPT;
  138. }
  139. /* Checksum invalid? Ignore. */
  140. if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
  141. nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP,
  142. pf)) {
  143. if (LOG_INVALID(net, IPPROTO_UDPLITE))
  144. nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
  145. "nf_ct_udplite: bad UDPLite checksum ");
  146. return -NF_ACCEPT;
  147. }
  148. return NF_ACCEPT;
  149. }
  150. #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
  151. #include <linux/netfilter/nfnetlink.h>
  152. #include <linux/netfilter/nfnetlink_cttimeout.h>
  153. static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[],
  154. struct net *net, void *data)
  155. {
  156. unsigned int *timeouts = data;
  157. struct udplite_net *un = udplite_pernet(net);
  158. /* set default timeouts for UDPlite. */
  159. timeouts[UDPLITE_CT_UNREPLIED] = un->timeouts[UDPLITE_CT_UNREPLIED];
  160. timeouts[UDPLITE_CT_REPLIED] = un->timeouts[UDPLITE_CT_REPLIED];
  161. if (tb[CTA_TIMEOUT_UDPLITE_UNREPLIED]) {
  162. timeouts[UDPLITE_CT_UNREPLIED] =
  163. ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_UNREPLIED])) * HZ;
  164. }
  165. if (tb[CTA_TIMEOUT_UDPLITE_REPLIED]) {
  166. timeouts[UDPLITE_CT_REPLIED] =
  167. ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_REPLIED])) * HZ;
  168. }
  169. return 0;
  170. }
  171. static int
  172. udplite_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
  173. {
  174. const unsigned int *timeouts = data;
  175. if (nla_put_be32(skb, CTA_TIMEOUT_UDPLITE_UNREPLIED,
  176. htonl(timeouts[UDPLITE_CT_UNREPLIED] / HZ)) ||
  177. nla_put_be32(skb, CTA_TIMEOUT_UDPLITE_REPLIED,
  178. htonl(timeouts[UDPLITE_CT_REPLIED] / HZ)))
  179. goto nla_put_failure;
  180. return 0;
  181. nla_put_failure:
  182. return -ENOSPC;
  183. }
  184. static const struct nla_policy
  185. udplite_timeout_nla_policy[CTA_TIMEOUT_UDPLITE_MAX+1] = {
  186. [CTA_TIMEOUT_UDPLITE_UNREPLIED] = { .type = NLA_U32 },
  187. [CTA_TIMEOUT_UDPLITE_REPLIED] = { .type = NLA_U32 },
  188. };
  189. #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
  190. #ifdef CONFIG_SYSCTL
  191. static struct ctl_table udplite_sysctl_table[] = {
  192. {
  193. .procname = "nf_conntrack_udplite_timeout",
  194. .maxlen = sizeof(unsigned int),
  195. .mode = 0644,
  196. .proc_handler = proc_dointvec_jiffies,
  197. },
  198. {
  199. .procname = "nf_conntrack_udplite_timeout_stream",
  200. .maxlen = sizeof(unsigned int),
  201. .mode = 0644,
  202. .proc_handler = proc_dointvec_jiffies,
  203. },
  204. { }
  205. };
  206. #endif /* CONFIG_SYSCTL */
  207. static int udplite_kmemdup_sysctl_table(struct nf_proto_net *pn,
  208. struct udplite_net *un)
  209. {
  210. #ifdef CONFIG_SYSCTL
  211. if (pn->ctl_table)
  212. return 0;
  213. pn->ctl_table = kmemdup(udplite_sysctl_table,
  214. sizeof(udplite_sysctl_table),
  215. GFP_KERNEL);
  216. if (!pn->ctl_table)
  217. return -ENOMEM;
  218. pn->ctl_table[0].data = &un->timeouts[UDPLITE_CT_UNREPLIED];
  219. pn->ctl_table[1].data = &un->timeouts[UDPLITE_CT_REPLIED];
  220. #endif
  221. return 0;
  222. }
  223. static int udplite_init_net(struct net *net, u_int16_t proto)
  224. {
  225. struct udplite_net *un = udplite_pernet(net);
  226. struct nf_proto_net *pn = &un->pn;
  227. if (!pn->users) {
  228. int i;
  229. for (i = 0 ; i < UDPLITE_CT_MAX; i++)
  230. un->timeouts[i] = udplite_timeouts[i];
  231. }
  232. return udplite_kmemdup_sysctl_table(pn, un);
  233. }
  234. static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
  235. {
  236. .l3proto = PF_INET,
  237. .l4proto = IPPROTO_UDPLITE,
  238. .name = "udplite",
  239. .pkt_to_tuple = udplite_pkt_to_tuple,
  240. .invert_tuple = udplite_invert_tuple,
  241. .print_tuple = udplite_print_tuple,
  242. .packet = udplite_packet,
  243. .get_timeouts = udplite_get_timeouts,
  244. .new = udplite_new,
  245. .error = udplite_error,
  246. #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  247. .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
  248. .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
  249. .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
  250. .nla_policy = nf_ct_port_nla_policy,
  251. #endif
  252. #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
  253. .ctnl_timeout = {
  254. .nlattr_to_obj = udplite_timeout_nlattr_to_obj,
  255. .obj_to_nlattr = udplite_timeout_obj_to_nlattr,
  256. .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX,
  257. .obj_size = sizeof(unsigned int) *
  258. CTA_TIMEOUT_UDPLITE_MAX,
  259. .nla_policy = udplite_timeout_nla_policy,
  260. },
  261. #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
  262. .net_id = &udplite_net_id,
  263. .init_net = udplite_init_net,
  264. };
  265. static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
  266. {
  267. .l3proto = PF_INET6,
  268. .l4proto = IPPROTO_UDPLITE,
  269. .name = "udplite",
  270. .pkt_to_tuple = udplite_pkt_to_tuple,
  271. .invert_tuple = udplite_invert_tuple,
  272. .print_tuple = udplite_print_tuple,
  273. .packet = udplite_packet,
  274. .get_timeouts = udplite_get_timeouts,
  275. .new = udplite_new,
  276. .error = udplite_error,
  277. #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  278. .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
  279. .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
  280. .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
  281. .nla_policy = nf_ct_port_nla_policy,
  282. #endif
  283. #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
  284. .ctnl_timeout = {
  285. .nlattr_to_obj = udplite_timeout_nlattr_to_obj,
  286. .obj_to_nlattr = udplite_timeout_obj_to_nlattr,
  287. .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX,
  288. .obj_size = sizeof(unsigned int) *
  289. CTA_TIMEOUT_UDPLITE_MAX,
  290. .nla_policy = udplite_timeout_nla_policy,
  291. },
  292. #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
  293. .net_id = &udplite_net_id,
  294. .init_net = udplite_init_net,
  295. };
  296. static int udplite_net_init(struct net *net)
  297. {
  298. int ret = 0;
  299. ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udplite4);
  300. if (ret < 0) {
  301. pr_err("nf_conntrack_udplite4: pernet registration failed.\n");
  302. goto out;
  303. }
  304. ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udplite6);
  305. if (ret < 0) {
  306. pr_err("nf_conntrack_udplite6: pernet registration failed.\n");
  307. goto cleanup_udplite4;
  308. }
  309. return 0;
  310. cleanup_udplite4:
  311. nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udplite4);
  312. out:
  313. return ret;
  314. }
  315. static void udplite_net_exit(struct net *net)
  316. {
  317. nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udplite6);
  318. nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udplite4);
  319. }
  320. static struct pernet_operations udplite_net_ops = {
  321. .init = udplite_net_init,
  322. .exit = udplite_net_exit,
  323. .id = &udplite_net_id,
  324. .size = sizeof(struct udplite_net),
  325. };
  326. static int __init nf_conntrack_proto_udplite_init(void)
  327. {
  328. int ret;
  329. ret = register_pernet_subsys(&udplite_net_ops);
  330. if (ret < 0)
  331. goto out_pernet;
  332. ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udplite4);
  333. if (ret < 0)
  334. goto out_udplite4;
  335. ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udplite6);
  336. if (ret < 0)
  337. goto out_udplite6;
  338. return 0;
  339. out_udplite6:
  340. nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
  341. out_udplite4:
  342. unregister_pernet_subsys(&udplite_net_ops);
  343. out_pernet:
  344. return ret;
  345. }
  346. static void __exit nf_conntrack_proto_udplite_exit(void)
  347. {
  348. nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite6);
  349. nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
  350. unregister_pernet_subsys(&udplite_net_ops);
  351. }
  352. module_init(nf_conntrack_proto_udplite_init);
  353. module_exit(nf_conntrack_proto_udplite_exit);
  354. MODULE_LICENSE("GPL");