PageRenderTime 39ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c

https://gitlab.com/oyvholm/linux
C | 459 lines | 377 code | 63 blank | 19 comment | 45 complexity | 3e550dbb6cffb8388f2d43dad367ab7a MD5 | raw file
  1. /*
  2. * Copyright (C)2004 USAGI/WIDE Project
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * Author:
  9. * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
  10. */
  11. #include <linux/types.h>
  12. #include <linux/ipv6.h>
  13. #include <linux/in6.h>
  14. #include <linux/netfilter.h>
  15. #include <linux/module.h>
  16. #include <linux/skbuff.h>
  17. #include <linux/icmp.h>
  18. #include <net/ipv6.h>
  19. #include <net/inet_frag.h>
  20. #include <linux/netfilter_bridge.h>
  21. #include <linux/netfilter_ipv6.h>
  22. #include <linux/netfilter_ipv6/ip6_tables.h>
  23. #include <net/netfilter/nf_conntrack.h>
  24. #include <net/netfilter/nf_conntrack_helper.h>
  25. #include <net/netfilter/nf_conntrack_l4proto.h>
  26. #include <net/netfilter/nf_conntrack_l3proto.h>
  27. #include <net/netfilter/nf_conntrack_core.h>
  28. #include <net/netfilter/nf_conntrack_zones.h>
  29. #include <net/netfilter/nf_conntrack_seqadj.h>
  30. #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
  31. #include <net/netfilter/nf_nat_helper.h>
  32. #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
  33. #include <net/netfilter/nf_log.h>
  34. static int conntrack6_net_id;
  35. static DEFINE_MUTEX(register_ipv6_hooks);
  36. struct conntrack6_net {
  37. unsigned int users;
  38. };
  39. static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
  40. struct nf_conntrack_tuple *tuple)
  41. {
  42. const u_int32_t *ap;
  43. u_int32_t _addrs[8];
  44. ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr),
  45. sizeof(_addrs), _addrs);
  46. if (ap == NULL)
  47. return false;
  48. memcpy(tuple->src.u3.ip6, ap, sizeof(tuple->src.u3.ip6));
  49. memcpy(tuple->dst.u3.ip6, ap + 4, sizeof(tuple->dst.u3.ip6));
  50. return true;
  51. }
  52. static bool ipv6_invert_tuple(struct nf_conntrack_tuple *tuple,
  53. const struct nf_conntrack_tuple *orig)
  54. {
  55. memcpy(tuple->src.u3.ip6, orig->dst.u3.ip6, sizeof(tuple->src.u3.ip6));
  56. memcpy(tuple->dst.u3.ip6, orig->src.u3.ip6, sizeof(tuple->dst.u3.ip6));
  57. return true;
  58. }
  59. static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
  60. unsigned int *dataoff, u_int8_t *protonum)
  61. {
  62. unsigned int extoff = nhoff + sizeof(struct ipv6hdr);
  63. __be16 frag_off;
  64. int protoff;
  65. u8 nexthdr;
  66. if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr),
  67. &nexthdr, sizeof(nexthdr)) != 0) {
  68. pr_debug("ip6_conntrack_core: can't get nexthdr\n");
  69. return -NF_ACCEPT;
  70. }
  71. protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off);
  72. /*
  73. * (protoff == skb->len) means the packet has not data, just
  74. * IPv6 and possibly extensions headers, but it is tracked anyway
  75. */
  76. if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
  77. pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
  78. return -NF_ACCEPT;
  79. }
  80. *dataoff = protoff;
  81. *protonum = nexthdr;
  82. return NF_ACCEPT;
  83. }
  84. static unsigned int ipv6_helper(void *priv,
  85. struct sk_buff *skb,
  86. const struct nf_hook_state *state)
  87. {
  88. struct nf_conn *ct;
  89. const struct nf_conn_help *help;
  90. const struct nf_conntrack_helper *helper;
  91. enum ip_conntrack_info ctinfo;
  92. __be16 frag_off;
  93. int protoff;
  94. u8 nexthdr;
  95. /* This is where we call the helper: as the packet goes out. */
  96. ct = nf_ct_get(skb, &ctinfo);
  97. if (!ct || ctinfo == IP_CT_RELATED_REPLY)
  98. return NF_ACCEPT;
  99. help = nfct_help(ct);
  100. if (!help)
  101. return NF_ACCEPT;
  102. /* rcu_read_lock()ed by nf_hook_thresh */
  103. helper = rcu_dereference(help->helper);
  104. if (!helper)
  105. return NF_ACCEPT;
  106. nexthdr = ipv6_hdr(skb)->nexthdr;
  107. protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
  108. &frag_off);
  109. if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
  110. pr_debug("proto header not found\n");
  111. return NF_ACCEPT;
  112. }
  113. return helper->help(skb, protoff, ct, ctinfo);
  114. }
  115. static unsigned int ipv6_confirm(void *priv,
  116. struct sk_buff *skb,
  117. const struct nf_hook_state *state)
  118. {
  119. struct nf_conn *ct;
  120. enum ip_conntrack_info ctinfo;
  121. unsigned char pnum = ipv6_hdr(skb)->nexthdr;
  122. int protoff;
  123. __be16 frag_off;
  124. ct = nf_ct_get(skb, &ctinfo);
  125. if (!ct || ctinfo == IP_CT_RELATED_REPLY)
  126. goto out;
  127. protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
  128. &frag_off);
  129. if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
  130. pr_debug("proto header not found\n");
  131. goto out;
  132. }
  133. /* adjust seqs for loopback traffic only in outgoing direction */
  134. if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
  135. !nf_is_loopback_packet(skb)) {
  136. if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
  137. NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
  138. return NF_DROP;
  139. }
  140. }
  141. out:
  142. /* We've seen it coming out the other side: confirm it */
  143. return nf_conntrack_confirm(skb);
  144. }
  145. static unsigned int ipv6_conntrack_in(void *priv,
  146. struct sk_buff *skb,
  147. const struct nf_hook_state *state)
  148. {
  149. return nf_conntrack_in(state->net, PF_INET6, state->hook, skb);
  150. }
  151. static unsigned int ipv6_conntrack_local(void *priv,
  152. struct sk_buff *skb,
  153. const struct nf_hook_state *state)
  154. {
  155. /* root is playing with raw sockets. */
  156. if (skb->len < sizeof(struct ipv6hdr)) {
  157. net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
  158. return NF_ACCEPT;
  159. }
  160. return nf_conntrack_in(state->net, PF_INET6, state->hook, skb);
  161. }
  162. static const struct nf_hook_ops ipv6_conntrack_ops[] = {
  163. {
  164. .hook = ipv6_conntrack_in,
  165. .pf = NFPROTO_IPV6,
  166. .hooknum = NF_INET_PRE_ROUTING,
  167. .priority = NF_IP6_PRI_CONNTRACK,
  168. },
  169. {
  170. .hook = ipv6_conntrack_local,
  171. .pf = NFPROTO_IPV6,
  172. .hooknum = NF_INET_LOCAL_OUT,
  173. .priority = NF_IP6_PRI_CONNTRACK,
  174. },
  175. {
  176. .hook = ipv6_helper,
  177. .pf = NFPROTO_IPV6,
  178. .hooknum = NF_INET_POST_ROUTING,
  179. .priority = NF_IP6_PRI_CONNTRACK_HELPER,
  180. },
  181. {
  182. .hook = ipv6_confirm,
  183. .pf = NFPROTO_IPV6,
  184. .hooknum = NF_INET_POST_ROUTING,
  185. .priority = NF_IP6_PRI_LAST,
  186. },
  187. {
  188. .hook = ipv6_helper,
  189. .pf = NFPROTO_IPV6,
  190. .hooknum = NF_INET_LOCAL_IN,
  191. .priority = NF_IP6_PRI_CONNTRACK_HELPER,
  192. },
  193. {
  194. .hook = ipv6_confirm,
  195. .pf = NFPROTO_IPV6,
  196. .hooknum = NF_INET_LOCAL_IN,
  197. .priority = NF_IP6_PRI_LAST-1,
  198. },
  199. };
  200. static int
  201. ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
  202. {
  203. const struct inet_sock *inet = inet_sk(sk);
  204. const struct ipv6_pinfo *inet6 = inet6_sk(sk);
  205. const struct nf_conntrack_tuple_hash *h;
  206. struct sockaddr_in6 sin6;
  207. struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
  208. struct nf_conn *ct;
  209. tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
  210. tuple.src.u.tcp.port = inet->inet_sport;
  211. tuple.dst.u3.in6 = sk->sk_v6_daddr;
  212. tuple.dst.u.tcp.port = inet->inet_dport;
  213. tuple.dst.protonum = sk->sk_protocol;
  214. if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP)
  215. return -ENOPROTOOPT;
  216. if (*len < 0 || (unsigned int) *len < sizeof(sin6))
  217. return -EINVAL;
  218. h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
  219. if (!h) {
  220. pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n",
  221. &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port),
  222. &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port));
  223. return -ENOENT;
  224. }
  225. ct = nf_ct_tuplehash_to_ctrack(h);
  226. sin6.sin6_family = AF_INET6;
  227. sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
  228. sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK;
  229. memcpy(&sin6.sin6_addr,
  230. &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
  231. sizeof(sin6.sin6_addr));
  232. nf_ct_put(ct);
  233. sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr,
  234. sk->sk_bound_dev_if);
  235. return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
  236. }
  237. #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  238. #include <linux/netfilter/nfnetlink.h>
  239. #include <linux/netfilter/nfnetlink_conntrack.h>
  240. static int ipv6_tuple_to_nlattr(struct sk_buff *skb,
  241. const struct nf_conntrack_tuple *tuple)
  242. {
  243. if (nla_put_in6_addr(skb, CTA_IP_V6_SRC, &tuple->src.u3.in6) ||
  244. nla_put_in6_addr(skb, CTA_IP_V6_DST, &tuple->dst.u3.in6))
  245. goto nla_put_failure;
  246. return 0;
  247. nla_put_failure:
  248. return -1;
  249. }
  250. static const struct nla_policy ipv6_nla_policy[CTA_IP_MAX+1] = {
  251. [CTA_IP_V6_SRC] = { .len = sizeof(u_int32_t)*4 },
  252. [CTA_IP_V6_DST] = { .len = sizeof(u_int32_t)*4 },
  253. };
  254. static int ipv6_nlattr_to_tuple(struct nlattr *tb[],
  255. struct nf_conntrack_tuple *t)
  256. {
  257. if (!tb[CTA_IP_V6_SRC] || !tb[CTA_IP_V6_DST])
  258. return -EINVAL;
  259. t->src.u3.in6 = nla_get_in6_addr(tb[CTA_IP_V6_SRC]);
  260. t->dst.u3.in6 = nla_get_in6_addr(tb[CTA_IP_V6_DST]);
  261. return 0;
  262. }
  263. #endif
  264. static int ipv6_hooks_register(struct net *net)
  265. {
  266. struct conntrack6_net *cnet = net_generic(net, conntrack6_net_id);
  267. int err = 0;
  268. mutex_lock(&register_ipv6_hooks);
  269. cnet->users++;
  270. if (cnet->users > 1)
  271. goto out_unlock;
  272. err = nf_defrag_ipv6_enable(net);
  273. if (err < 0) {
  274. cnet->users = 0;
  275. goto out_unlock;
  276. }
  277. err = nf_register_net_hooks(net, ipv6_conntrack_ops,
  278. ARRAY_SIZE(ipv6_conntrack_ops));
  279. if (err)
  280. cnet->users = 0;
  281. out_unlock:
  282. mutex_unlock(&register_ipv6_hooks);
  283. return err;
  284. }
  285. static void ipv6_hooks_unregister(struct net *net)
  286. {
  287. struct conntrack6_net *cnet = net_generic(net, conntrack6_net_id);
  288. mutex_lock(&register_ipv6_hooks);
  289. if (cnet->users && (--cnet->users == 0))
  290. nf_unregister_net_hooks(net, ipv6_conntrack_ops,
  291. ARRAY_SIZE(ipv6_conntrack_ops));
  292. mutex_unlock(&register_ipv6_hooks);
  293. }
  294. const struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
  295. .l3proto = PF_INET6,
  296. .pkt_to_tuple = ipv6_pkt_to_tuple,
  297. .invert_tuple = ipv6_invert_tuple,
  298. .get_l4proto = ipv6_get_l4proto,
  299. #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  300. .tuple_to_nlattr = ipv6_tuple_to_nlattr,
  301. .nlattr_to_tuple = ipv6_nlattr_to_tuple,
  302. .nla_policy = ipv6_nla_policy,
  303. .nla_size = NLA_ALIGN(NLA_HDRLEN + sizeof(u32[4])) +
  304. NLA_ALIGN(NLA_HDRLEN + sizeof(u32[4])),
  305. #endif
  306. .net_ns_get = ipv6_hooks_register,
  307. .net_ns_put = ipv6_hooks_unregister,
  308. .me = THIS_MODULE,
  309. };
  310. MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
  311. MODULE_LICENSE("GPL");
  312. MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
  313. static struct nf_sockopt_ops so_getorigdst6 = {
  314. .pf = NFPROTO_IPV6,
  315. .get_optmin = IP6T_SO_ORIGINAL_DST,
  316. .get_optmax = IP6T_SO_ORIGINAL_DST + 1,
  317. .get = ipv6_getorigdst,
  318. .owner = THIS_MODULE,
  319. };
  320. static struct nf_conntrack_l4proto *builtin_l4proto6[] = {
  321. &nf_conntrack_l4proto_tcp6,
  322. &nf_conntrack_l4proto_udp6,
  323. &nf_conntrack_l4proto_icmpv6,
  324. #ifdef CONFIG_NF_CT_PROTO_DCCP
  325. &nf_conntrack_l4proto_dccp6,
  326. #endif
  327. #ifdef CONFIG_NF_CT_PROTO_SCTP
  328. &nf_conntrack_l4proto_sctp6,
  329. #endif
  330. #ifdef CONFIG_NF_CT_PROTO_UDPLITE
  331. &nf_conntrack_l4proto_udplite6,
  332. #endif
  333. };
  334. static int ipv6_net_init(struct net *net)
  335. {
  336. return nf_ct_l4proto_pernet_register(net, builtin_l4proto6,
  337. ARRAY_SIZE(builtin_l4proto6));
  338. }
  339. static void ipv6_net_exit(struct net *net)
  340. {
  341. nf_ct_l4proto_pernet_unregister(net, builtin_l4proto6,
  342. ARRAY_SIZE(builtin_l4proto6));
  343. }
  344. static struct pernet_operations ipv6_net_ops = {
  345. .init = ipv6_net_init,
  346. .exit = ipv6_net_exit,
  347. .id = &conntrack6_net_id,
  348. .size = sizeof(struct conntrack6_net),
  349. };
  350. static int __init nf_conntrack_l3proto_ipv6_init(void)
  351. {
  352. int ret = 0;
  353. need_conntrack();
  354. #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  355. if (WARN_ON(nla_policy_len(ipv6_nla_policy, CTA_IP_MAX + 1) !=
  356. nf_conntrack_l3proto_ipv6.nla_size))
  357. return -EINVAL;
  358. #endif
  359. ret = nf_register_sockopt(&so_getorigdst6);
  360. if (ret < 0) {
  361. pr_err("Unable to register netfilter socket option\n");
  362. return ret;
  363. }
  364. ret = register_pernet_subsys(&ipv6_net_ops);
  365. if (ret < 0)
  366. goto cleanup_sockopt;
  367. ret = nf_ct_l4proto_register(builtin_l4proto6,
  368. ARRAY_SIZE(builtin_l4proto6));
  369. if (ret < 0)
  370. goto cleanup_pernet;
  371. ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv6);
  372. if (ret < 0) {
  373. pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n");
  374. goto cleanup_l4proto;
  375. }
  376. return ret;
  377. cleanup_l4proto:
  378. nf_ct_l4proto_unregister(builtin_l4proto6,
  379. ARRAY_SIZE(builtin_l4proto6));
  380. cleanup_pernet:
  381. unregister_pernet_subsys(&ipv6_net_ops);
  382. cleanup_sockopt:
  383. nf_unregister_sockopt(&so_getorigdst6);
  384. return ret;
  385. }
  386. static void __exit nf_conntrack_l3proto_ipv6_fini(void)
  387. {
  388. synchronize_net();
  389. nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
  390. nf_ct_l4proto_unregister(builtin_l4proto6,
  391. ARRAY_SIZE(builtin_l4proto6));
  392. unregister_pernet_subsys(&ipv6_net_ops);
  393. nf_unregister_sockopt(&so_getorigdst6);
  394. }
  395. module_init(nf_conntrack_l3proto_ipv6_init);
  396. module_exit(nf_conntrack_l3proto_ipv6_fini);