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 12#include <linux/types.h> 13#include <linux/ipv6.h> 14#include <linux/in6.h> 15#include <linux/netfilter.h> 16#include <linux/module.h> 17#include <linux/skbuff.h> 18#include <linux/icmp.h> 19#include <net/ipv6.h> 20#include <net/inet_frag.h> 21 22#include <linux/netfilter_bridge.h> 23#include <linux/netfilter_ipv6.h> 24#include <linux/netfilter_ipv6/ip6_tables.h> 25#include <net/netfilter/nf_conntrack.h> 26#include <net/netfilter/nf_conntrack_helper.h> 27#include <net/netfilter/nf_conntrack_l4proto.h> 28#include <net/netfilter/nf_conntrack_l3proto.h> 29#include <net/netfilter/nf_conntrack_core.h> 30#include <net/netfilter/nf_conntrack_zones.h> 31#include <net/netfilter/nf_conntrack_seqadj.h> 32#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 33#include <net/netfilter/nf_nat_helper.h> 34#include <net/netfilter/ipv6/nf_defrag_ipv6.h> 35#include <net/netfilter/nf_log.h> 36 37static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, 38 struct nf_conntrack_tuple *tuple) 39{ 40 const u_int32_t *ap; 41 u_int32_t _addrs[8]; 42 43 ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr), 44 sizeof(_addrs), _addrs); 45 if (ap == NULL) 46 return false; 47 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 51 return true; 52} 53 54static bool ipv6_invert_tuple(struct nf_conntrack_tuple *tuple, 55 const struct nf_conntrack_tuple *orig) 56{ 57 memcpy(tuple->src.u3.ip6, orig->dst.u3.ip6, sizeof(tuple->src.u3.ip6)); 58 memcpy(tuple->dst.u3.ip6, orig->src.u3.ip6, sizeof(tuple->dst.u3.ip6)); 59 60 return true; 61} 62 63static int ipv6_print_tuple(struct seq_file *s, 64 const struct nf_conntrack_tuple *tuple) 65{ 66 return seq_printf(s, "src=%pI6 dst=%pI6 ", 67 tuple->src.u3.ip6, tuple->dst.u3.ip6); 68} 69 70static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, 71 unsigned int *dataoff, u_int8_t *protonum) 72{ 73 unsigned int extoff = nhoff + sizeof(struct ipv6hdr); 74 __be16 frag_off; 75 int protoff; 76 u8 nexthdr; 77 78 if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr), 79 &nexthdr, sizeof(nexthdr)) != 0) { 80 pr_debug("ip6_conntrack_core: can't get nexthdr\n"); 81 return -NF_ACCEPT; 82 } 83 protoff = ipv6_skip_exthdr(skb, extoff, &nexthdr, &frag_off); 84 /* 85 * (protoff == skb->len) means the packet has not data, just 86 * IPv6 and possibly extensions headers, but it is tracked anyway 87 */ 88 if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 89 pr_debug("ip6_conntrack_core: can't find proto in pkt\n"); 90 return -NF_ACCEPT; 91 } 92 93 *dataoff = protoff; 94 *protonum = nexthdr; 95 return NF_ACCEPT; 96} 97 98static unsigned int ipv6_helper(const struct nf_hook_ops *ops, 99 struct sk_buff *skb, 100 const struct net_device *in, 101 const struct net_device *out, 102 int (*okfn)(struct sk_buff *)) 103{ 104 struct nf_conn *ct; 105 const struct nf_conn_help *help; 106 const struct nf_conntrack_helper *helper; 107 enum ip_conntrack_info ctinfo; 108 __be16 frag_off; 109 int protoff; 110 u8 nexthdr; 111 112 /* This is where we call the helper: as the packet goes out. */ 113 ct = nf_ct_get(skb, &ctinfo); 114 if (!ct || ctinfo == IP_CT_RELATED_REPLY) 115 return NF_ACCEPT; 116 117 help = nfct_help(ct); 118 if (!help) 119 return NF_ACCEPT; 120 /* rcu_read_lock()ed by nf_hook_slow */ 121 helper = rcu_dereference(help->helper); 122 if (!helper) 123 return NF_ACCEPT; 124 125 nexthdr = ipv6_hdr(skb)->nexthdr; 126 protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, 127 &frag_off); 128 if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 129 pr_debug("proto header not found\n"); 130 return NF_ACCEPT; 131 } 132 133 return helper->help(skb, protoff, ct, ctinfo); 134} 135 136static unsigned int ipv6_confirm(const struct nf_hook_ops *ops, 137 struct sk_buff *skb, 138 const struct net_device *in, 139 const struct net_device *out, 140 int (*okfn)(struct sk_buff *)) 141{ 142 struct nf_conn *ct; 143 enum ip_conntrack_info ctinfo; 144 unsigned char pnum = ipv6_hdr(skb)->nexthdr; 145 int protoff; 146 __be16 frag_off; 147 148 ct = nf_ct_get(skb, &ctinfo); 149 if (!ct || ctinfo == IP_CT_RELATED_REPLY) 150 goto out; 151 152 protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum, 153 &frag_off); 154 if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { 155 pr_debug("proto header not found\n"); 156 goto out; 157 } 158 159 /* adjust seqs for loopback traffic only in outgoing direction */ 160 if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) && 161 !nf_is_loopback_packet(skb)) { 162 if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) { 163 NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); 164 return NF_DROP; 165 } 166 } 167out: 168 /* We've seen it coming out the other side: confirm it */ 169 return nf_conntrack_confirm(skb); 170} 171 172static unsigned int ipv6_conntrack_in(const struct nf_hook_ops *ops, 173 struct sk_buff *skb, 174 const struct net_device *in, 175 const struct net_device *out, 176 int (*okfn)(struct sk_buff *)) 177{ 178 return nf_conntrack_in(dev_net(in), PF_INET6, ops->hooknum, skb); 179} 180 181static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops, 182 struct sk_buff *skb, 183 const struct net_device *in, 184 const struct net_device *out, 185 int (*okfn)(struct sk_buff *)) 186{ 187 /* root is playing with raw sockets. */ 188 if (skb->len < sizeof(struct ipv6hdr)) { 189 net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); 190 return NF_ACCEPT; 191 } 192 return nf_conntrack_in(dev_net(out), PF_INET6, ops->hooknum, skb); 193} 194 195static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { 196 { 197 .hook = ipv6_conntrack_in, 198 .owner = THIS_MODULE, 199 .pf = NFPROTO_IPV6, 200 .hooknum = NF_INET_PRE_ROUTING, 201 .priority = NF_IP6_PRI_CONNTRACK, 202 }, 203 { 204 .hook = ipv6_conntrack_local, 205 .owner = THIS_MODULE, 206 .pf = NFPROTO_IPV6, 207 .hooknum = NF_INET_LOCAL_OUT, 208 .priority = NF_IP6_PRI_CONNTRACK, 209 }, 210 { 211 .hook = ipv6_helper, 212 .owner = THIS_MODULE, 213 .pf = NFPROTO_IPV6, 214 .hooknum = NF_INET_POST_ROUTING, 215 .priority = NF_IP6_PRI_CONNTRACK_HELPER, 216 }, 217 { 218 .hook = ipv6_confirm, 219 .owner = THIS_MODULE, 220 .pf = NFPROTO_IPV6, 221 .hooknum = NF_INET_POST_ROUTING, 222 .priority = NF_IP6_PRI_LAST, 223 }, 224 { 225 .hook = ipv6_helper, 226 .owner = THIS_MODULE, 227 .pf = NFPROTO_IPV6, 228 .hooknum = NF_INET_LOCAL_IN, 229 .priority = NF_IP6_PRI_CONNTRACK_HELPER, 230 }, 231 { 232 .hook = ipv6_confirm, 233 .owner = THIS_MODULE, 234 .pf = NFPROTO_IPV6, 235 .hooknum = NF_INET_LOCAL_IN, 236 .priority = NF_IP6_PRI_LAST-1, 237 }, 238}; 239 240static int 241ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) 242{ 243 const struct inet_sock *inet = inet_sk(sk); 244 const struct ipv6_pinfo *inet6 = inet6_sk(sk); 245 const struct nf_conntrack_tuple_hash *h; 246 struct sockaddr_in6 sin6; 247 struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; 248 struct nf_conn *ct; 249 250 tuple.src.u3.in6 = sk->sk_v6_rcv_saddr; 251 tuple.src.u.tcp.port = inet->inet_sport; 252 tuple.dst.u3.in6 = sk->sk_v6_daddr; 253 tuple.dst.u.tcp.port = inet->inet_dport; 254 tuple.dst.protonum = sk->sk_protocol; 255 256 if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) 257 return -ENOPROTOOPT; 258 259 if (*len < 0 || (unsigned int) *len < sizeof(sin6)) 260 return -EINVAL; 261 262 h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple); 263 if (!h) { 264 pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n", 265 &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port), 266 &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port)); 267 return -ENOENT; 268 } 269 270 ct = nf_ct_tuplehash_to_ctrack(h); 271 272 sin6.sin6_family = AF_INET6; 273 sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; 274 sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK; 275 memcpy(&sin6.sin6_addr, 276 &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, 277 sizeof(sin6.sin6_addr)); 278 279 nf_ct_put(ct); 280 sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, 281 sk->sk_bound_dev_if); 282 return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; 283} 284 285#if IS_ENABLED(CONFIG_NF_CT_NETLINK) 286 287#include <linux/netfilter/nfnetlink.h> 288#include <linux/netfilter/nfnetlink_conntrack.h> 289 290static int ipv6_tuple_to_nlattr(struct sk_buff *skb, 291 const struct nf_conntrack_tuple *tuple) 292{ 293 if (nla_put(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4, 294 &tuple->src.u3.ip6) || 295 nla_put(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4, 296 &tuple->dst.u3.ip6)) 297 goto nla_put_failure; 298 return 0; 299 300nla_put_failure: 301 return -1; 302} 303 304static const struct nla_policy ipv6_nla_policy[CTA_IP_MAX+1] = { 305 [CTA_IP_V6_SRC] = { .len = sizeof(u_int32_t)*4 }, 306 [CTA_IP_V6_DST] = { .len = sizeof(u_int32_t)*4 }, 307}; 308 309static int ipv6_nlattr_to_tuple(struct nlattr *tb[], 310 struct nf_conntrack_tuple *t) 311{ 312 if (!tb[CTA_IP_V6_SRC] || !tb[CTA_IP_V6_DST]) 313 return -EINVAL; 314 315 memcpy(&t->src.u3.ip6, nla_data(tb[CTA_IP_V6_SRC]), 316 sizeof(u_int32_t) * 4); 317 memcpy(&t->dst.u3.ip6, nla_data(tb[CTA_IP_V6_DST]), 318 sizeof(u_int32_t) * 4); 319 320 return 0; 321} 322 323static int ipv6_nlattr_tuple_size(void) 324{ 325 return nla_policy_len(ipv6_nla_policy, CTA_IP_MAX + 1); 326} 327#endif 328 329struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = { 330 .l3proto = PF_INET6, 331 .name = "ipv6", 332 .pkt_to_tuple = ipv6_pkt_to_tuple, 333 .invert_tuple = ipv6_invert_tuple, 334 .print_tuple = ipv6_print_tuple, 335 .get_l4proto = ipv6_get_l4proto, 336#if IS_ENABLED(CONFIG_NF_CT_NETLINK) 337 .tuple_to_nlattr = ipv6_tuple_to_nlattr, 338 .nlattr_tuple_size = ipv6_nlattr_tuple_size, 339 .nlattr_to_tuple = ipv6_nlattr_to_tuple, 340 .nla_policy = ipv6_nla_policy, 341#endif 342 .me = THIS_MODULE, 343}; 344 345MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); 346MODULE_LICENSE("GPL"); 347MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); 348 349static struct nf_sockopt_ops so_getorigdst6 = { 350 .pf = NFPROTO_IPV6, 351 .get_optmin = IP6T_SO_ORIGINAL_DST, 352 .get_optmax = IP6T_SO_ORIGINAL_DST + 1, 353 .get = ipv6_getorigdst, 354 .owner = THIS_MODULE, 355}; 356 357static int ipv6_net_init(struct net *net) 358{ 359 int ret = 0; 360 361 ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_tcp6); 362 if (ret < 0) { 363 pr_err("nf_conntrack_tcp6: pernet registration failed\n"); 364 goto out; 365 } 366 ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udp6); 367 if (ret < 0) { 368 pr_err("nf_conntrack_udp6: pernet registration failed\n"); 369 goto cleanup_tcp6; 370 } 371 ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_icmpv6); 372 if (ret < 0) { 373 pr_err("nf_conntrack_icmp6: pernet registration failed\n"); 374 goto cleanup_udp6; 375 } 376 ret = nf_ct_l3proto_pernet_register(net, &nf_conntrack_l3proto_ipv6); 377 if (ret < 0) { 378 pr_err("nf_conntrack_ipv6: pernet registration failed.\n"); 379 goto cleanup_icmpv6; 380 } 381 return 0; 382 cleanup_icmpv6: 383 nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6); 384 cleanup_udp6: 385 nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6); 386 cleanup_tcp6: 387 nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6); 388 out: 389 return ret; 390} 391 392static void ipv6_net_exit(struct net *net) 393{ 394 nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv6); 395 nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6); 396 nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6); 397 nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6); 398} 399 400static struct pernet_operations ipv6_net_ops = { 401 .init = ipv6_net_init, 402 .exit = ipv6_net_exit, 403}; 404 405static int __init nf_conntrack_l3proto_ipv6_init(void) 406{ 407 int ret = 0; 408 409 need_conntrack(); 410 nf_defrag_ipv6_enable(); 411 412 ret = nf_register_sockopt(&so_getorigdst6); 413 if (ret < 0) { 414 pr_err("Unable to register netfilter socket option\n"); 415 return ret; 416 } 417 418 ret = register_pernet_subsys(&ipv6_net_ops); 419 if (ret < 0) 420 goto cleanup_sockopt; 421 422 ret = nf_register_hooks(ipv6_conntrack_ops, 423 ARRAY_SIZE(ipv6_conntrack_ops)); 424 if (ret < 0) { 425 pr_err("nf_conntrack_ipv6: can't register pre-routing defrag " 426 "hook.\n"); 427 goto cleanup_pernet; 428 } 429 430 ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp6); 431 if (ret < 0) { 432 pr_err("nf_conntrack_ipv6: can't register tcp6 proto.\n"); 433 goto cleanup_hooks; 434 } 435 436 ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp6); 437 if (ret < 0) { 438 pr_err("nf_conntrack_ipv6: can't register udp6 proto.\n"); 439 goto cleanup_tcp6; 440 } 441 442 ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_icmpv6); 443 if (ret < 0) { 444 pr_err("nf_conntrack_ipv6: can't register icmpv6 proto.\n"); 445 goto cleanup_udp6; 446 } 447 448 ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv6); 449 if (ret < 0) { 450 pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n"); 451 goto cleanup_icmpv6; 452 } 453 return ret; 454 455 cleanup_icmpv6: 456 nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); 457 cleanup_udp6: 458 nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6); 459 cleanup_tcp6: 460 nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6); 461 cleanup_hooks: 462 nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); 463 cleanup_pernet: 464 unregister_pernet_subsys(&ipv6_net_ops); 465 cleanup_sockopt: 466 nf_unregister_sockopt(&so_getorigdst6); 467 return ret; 468} 469 470static void __exit nf_conntrack_l3proto_ipv6_fini(void) 471{ 472 synchronize_net(); 473 nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv6); 474 nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6); 475 nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6); 476 nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); 477 nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); 478 unregister_pernet_subsys(&ipv6_net_ops); 479 nf_unregister_sockopt(&so_getorigdst6); 480} 481 482module_init(nf_conntrack_l3proto_ipv6_init); 483module_exit(nf_conntrack_l3proto_ipv6_fini); 484