root/net/netfilter/nf_conntrack_proto.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __printf
  2. __printf
  3. nf_ct_l4proto_find
  4. nf_confirm
  5. ipv4_confirm
  6. ipv4_conntrack_in
  7. ipv4_conntrack_local
  8. getorigdst
  9. ipv6_getorigdst
  10. ipv6_confirm
  11. ipv6_conntrack_in
  12. ipv6_conntrack_local
  13. nf_ct_tcp_fixup
  14. nf_ct_netns_do_get
  15. nf_ct_netns_do_put
  16. nf_ct_netns_inet_get
  17. nf_ct_netns_get
  18. nf_ct_netns_put
  19. nf_ct_bridge_register
  20. nf_ct_bridge_unregister
  21. nf_conntrack_proto_init
  22. nf_conntrack_proto_fini
  23. nf_conntrack_proto_pernet_init
  24. nf_conntrack_proto_pernet_fini

   1 // SPDX-License-Identifier: GPL-2.0
   2 
   3 #include <linux/types.h>
   4 #include <linux/netfilter.h>
   5 #include <linux/module.h>
   6 #include <linux/slab.h>
   7 #include <linux/mutex.h>
   8 #include <linux/vmalloc.h>
   9 #include <linux/stddef.h>
  10 #include <linux/err.h>
  11 #include <linux/percpu.h>
  12 #include <linux/notifier.h>
  13 #include <linux/kernel.h>
  14 #include <linux/netdevice.h>
  15 
  16 #include <net/netfilter/nf_conntrack.h>
  17 #include <net/netfilter/nf_conntrack_l4proto.h>
  18 #include <net/netfilter/nf_conntrack_core.h>
  19 #include <net/netfilter/nf_conntrack_bridge.h>
  20 #include <net/netfilter/nf_log.h>
  21 
  22 #include <linux/ip.h>
  23 #include <linux/icmp.h>
  24 #include <linux/sysctl.h>
  25 #include <net/route.h>
  26 #include <net/ip.h>
  27 
  28 #include <linux/netfilter_ipv4.h>
  29 #include <linux/netfilter_ipv6.h>
  30 #include <linux/netfilter_ipv6/ip6_tables.h>
  31 #include <net/netfilter/nf_conntrack_helper.h>
  32 #include <net/netfilter/nf_conntrack_zones.h>
  33 #include <net/netfilter/nf_conntrack_seqadj.h>
  34 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
  35 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
  36 #include <net/netfilter/nf_nat_helper.h>
  37 #include <net/netfilter/ipv4/nf_defrag_ipv4.h>
  38 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
  39 
  40 #include <linux/ipv6.h>
  41 #include <linux/in6.h>
  42 #include <net/ipv6.h>
  43 #include <net/inet_frag.h>
  44 
  45 extern unsigned int nf_conntrack_net_id;
  46 
  47 static DEFINE_MUTEX(nf_ct_proto_mutex);
  48 
  49 #ifdef CONFIG_SYSCTL
  50 __printf(5, 6)
  51 void nf_l4proto_log_invalid(const struct sk_buff *skb,
  52                             struct net *net,
  53                             u16 pf, u8 protonum,
  54                             const char *fmt, ...)
  55 {
  56         struct va_format vaf;
  57         va_list args;
  58 
  59         if (net->ct.sysctl_log_invalid != protonum &&
  60             net->ct.sysctl_log_invalid != IPPROTO_RAW)
  61                 return;
  62 
  63         va_start(args, fmt);
  64         vaf.fmt = fmt;
  65         vaf.va = &args;
  66 
  67         nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
  68                       "nf_ct_proto_%d: %pV ", protonum, &vaf);
  69         va_end(args);
  70 }
  71 EXPORT_SYMBOL_GPL(nf_l4proto_log_invalid);
  72 
  73 __printf(3, 4)
  74 void nf_ct_l4proto_log_invalid(const struct sk_buff *skb,
  75                                const struct nf_conn *ct,
  76                                const char *fmt, ...)
  77 {
  78         struct va_format vaf;
  79         struct net *net;
  80         va_list args;
  81 
  82         net = nf_ct_net(ct);
  83         if (likely(net->ct.sysctl_log_invalid == 0))
  84                 return;
  85 
  86         va_start(args, fmt);
  87         vaf.fmt = fmt;
  88         vaf.va = &args;
  89 
  90         nf_l4proto_log_invalid(skb, net, nf_ct_l3num(ct),
  91                                nf_ct_protonum(ct), "%pV", &vaf);
  92         va_end(args);
  93 }
  94 EXPORT_SYMBOL_GPL(nf_ct_l4proto_log_invalid);
  95 #endif
  96 
  97 const struct nf_conntrack_l4proto *nf_ct_l4proto_find(u8 l4proto)
  98 {
  99         switch (l4proto) {
 100         case IPPROTO_UDP: return &nf_conntrack_l4proto_udp;
 101         case IPPROTO_TCP: return &nf_conntrack_l4proto_tcp;
 102         case IPPROTO_ICMP: return &nf_conntrack_l4proto_icmp;
 103 #ifdef CONFIG_NF_CT_PROTO_DCCP
 104         case IPPROTO_DCCP: return &nf_conntrack_l4proto_dccp;
 105 #endif
 106 #ifdef CONFIG_NF_CT_PROTO_SCTP
 107         case IPPROTO_SCTP: return &nf_conntrack_l4proto_sctp;
 108 #endif
 109 #ifdef CONFIG_NF_CT_PROTO_UDPLITE
 110         case IPPROTO_UDPLITE: return &nf_conntrack_l4proto_udplite;
 111 #endif
 112 #ifdef CONFIG_NF_CT_PROTO_GRE
 113         case IPPROTO_GRE: return &nf_conntrack_l4proto_gre;
 114 #endif
 115 #if IS_ENABLED(CONFIG_IPV6)
 116         case IPPROTO_ICMPV6: return &nf_conntrack_l4proto_icmpv6;
 117 #endif /* CONFIG_IPV6 */
 118         }
 119 
 120         return &nf_conntrack_l4proto_generic;
 121 };
 122 EXPORT_SYMBOL_GPL(nf_ct_l4proto_find);
 123 
 124 unsigned int nf_confirm(struct sk_buff *skb, unsigned int protoff,
 125                         struct nf_conn *ct, enum ip_conntrack_info ctinfo)
 126 {
 127         const struct nf_conn_help *help;
 128 
 129         help = nfct_help(ct);
 130         if (help) {
 131                 const struct nf_conntrack_helper *helper;
 132                 int ret;
 133 
 134                 /* rcu_read_lock()ed by nf_hook_thresh */
 135                 helper = rcu_dereference(help->helper);
 136                 if (helper) {
 137                         ret = helper->help(skb,
 138                                            protoff,
 139                                            ct, ctinfo);
 140                         if (ret != NF_ACCEPT)
 141                                 return ret;
 142                 }
 143         }
 144 
 145         if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status) &&
 146             !nf_is_loopback_packet(skb)) {
 147                 if (!nf_ct_seq_adjust(skb, ct, ctinfo, protoff)) {
 148                         NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop);
 149                         return NF_DROP;
 150                 }
 151         }
 152 
 153         /* We've seen it coming out the other side: confirm it */
 154         return nf_conntrack_confirm(skb);
 155 }
 156 EXPORT_SYMBOL_GPL(nf_confirm);
 157 
 158 static unsigned int ipv4_confirm(void *priv,
 159                                  struct sk_buff *skb,
 160                                  const struct nf_hook_state *state)
 161 {
 162         enum ip_conntrack_info ctinfo;
 163         struct nf_conn *ct;
 164 
 165         ct = nf_ct_get(skb, &ctinfo);
 166         if (!ct || ctinfo == IP_CT_RELATED_REPLY)
 167                 return nf_conntrack_confirm(skb);
 168 
 169         return nf_confirm(skb,
 170                           skb_network_offset(skb) + ip_hdrlen(skb),
 171                           ct, ctinfo);
 172 }
 173 
 174 static unsigned int ipv4_conntrack_in(void *priv,
 175                                       struct sk_buff *skb,
 176                                       const struct nf_hook_state *state)
 177 {
 178         return nf_conntrack_in(skb, state);
 179 }
 180 
 181 static unsigned int ipv4_conntrack_local(void *priv,
 182                                          struct sk_buff *skb,
 183                                          const struct nf_hook_state *state)
 184 {
 185         if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
 186                 enum ip_conntrack_info ctinfo;
 187                 struct nf_conn *tmpl;
 188 
 189                 tmpl = nf_ct_get(skb, &ctinfo);
 190                 if (tmpl && nf_ct_is_template(tmpl)) {
 191                         /* when skipping ct, clear templates to avoid fooling
 192                          * later targets/matches
 193                          */
 194                         skb->_nfct = 0;
 195                         nf_ct_put(tmpl);
 196                 }
 197                 return NF_ACCEPT;
 198         }
 199 
 200         return nf_conntrack_in(skb, state);
 201 }
 202 
 203 /* Connection tracking may drop packets, but never alters them, so
 204  * make it the first hook.
 205  */
 206 static const struct nf_hook_ops ipv4_conntrack_ops[] = {
 207         {
 208                 .hook           = ipv4_conntrack_in,
 209                 .pf             = NFPROTO_IPV4,
 210                 .hooknum        = NF_INET_PRE_ROUTING,
 211                 .priority       = NF_IP_PRI_CONNTRACK,
 212         },
 213         {
 214                 .hook           = ipv4_conntrack_local,
 215                 .pf             = NFPROTO_IPV4,
 216                 .hooknum        = NF_INET_LOCAL_OUT,
 217                 .priority       = NF_IP_PRI_CONNTRACK,
 218         },
 219         {
 220                 .hook           = ipv4_confirm,
 221                 .pf             = NFPROTO_IPV4,
 222                 .hooknum        = NF_INET_POST_ROUTING,
 223                 .priority       = NF_IP_PRI_CONNTRACK_CONFIRM,
 224         },
 225         {
 226                 .hook           = ipv4_confirm,
 227                 .pf             = NFPROTO_IPV4,
 228                 .hooknum        = NF_INET_LOCAL_IN,
 229                 .priority       = NF_IP_PRI_CONNTRACK_CONFIRM,
 230         },
 231 };
 232 
 233 /* Fast function for those who don't want to parse /proc (and I don't
 234  * blame them).
 235  * Reversing the socket's dst/src point of view gives us the reply
 236  * mapping.
 237  */
 238 static int
 239 getorigdst(struct sock *sk, int optval, void __user *user, int *len)
 240 {
 241         const struct inet_sock *inet = inet_sk(sk);
 242         const struct nf_conntrack_tuple_hash *h;
 243         struct nf_conntrack_tuple tuple;
 244 
 245         memset(&tuple, 0, sizeof(tuple));
 246 
 247         lock_sock(sk);
 248         tuple.src.u3.ip = inet->inet_rcv_saddr;
 249         tuple.src.u.tcp.port = inet->inet_sport;
 250         tuple.dst.u3.ip = inet->inet_daddr;
 251         tuple.dst.u.tcp.port = inet->inet_dport;
 252         tuple.src.l3num = PF_INET;
 253         tuple.dst.protonum = sk->sk_protocol;
 254         release_sock(sk);
 255 
 256         /* We only do TCP and SCTP at the moment: is there a better way? */
 257         if (tuple.dst.protonum != IPPROTO_TCP &&
 258             tuple.dst.protonum != IPPROTO_SCTP) {
 259                 pr_debug("SO_ORIGINAL_DST: Not a TCP/SCTP socket\n");
 260                 return -ENOPROTOOPT;
 261         }
 262 
 263         if ((unsigned int)*len < sizeof(struct sockaddr_in)) {
 264                 pr_debug("SO_ORIGINAL_DST: len %d not %zu\n",
 265                          *len, sizeof(struct sockaddr_in));
 266                 return -EINVAL;
 267         }
 268 
 269         h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
 270         if (h) {
 271                 struct sockaddr_in sin;
 272                 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
 273 
 274                 sin.sin_family = AF_INET;
 275                 sin.sin_port = ct->tuplehash[IP_CT_DIR_ORIGINAL]
 276                         .tuple.dst.u.tcp.port;
 277                 sin.sin_addr.s_addr = ct->tuplehash[IP_CT_DIR_ORIGINAL]
 278                         .tuple.dst.u3.ip;
 279                 memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
 280 
 281                 pr_debug("SO_ORIGINAL_DST: %pI4 %u\n",
 282                          &sin.sin_addr.s_addr, ntohs(sin.sin_port));
 283                 nf_ct_put(ct);
 284                 if (copy_to_user(user, &sin, sizeof(sin)) != 0)
 285                         return -EFAULT;
 286                 else
 287                         return 0;
 288         }
 289         pr_debug("SO_ORIGINAL_DST: Can't find %pI4/%u-%pI4/%u.\n",
 290                  &tuple.src.u3.ip, ntohs(tuple.src.u.tcp.port),
 291                  &tuple.dst.u3.ip, ntohs(tuple.dst.u.tcp.port));
 292         return -ENOENT;
 293 }
 294 
 295 static struct nf_sockopt_ops so_getorigdst = {
 296         .pf             = PF_INET,
 297         .get_optmin     = SO_ORIGINAL_DST,
 298         .get_optmax     = SO_ORIGINAL_DST + 1,
 299         .get            = getorigdst,
 300         .owner          = THIS_MODULE,
 301 };
 302 
 303 #if IS_ENABLED(CONFIG_IPV6)
 304 static int
 305 ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len)
 306 {
 307         struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 };
 308         const struct ipv6_pinfo *inet6 = inet6_sk(sk);
 309         const struct inet_sock *inet = inet_sk(sk);
 310         const struct nf_conntrack_tuple_hash *h;
 311         struct sockaddr_in6 sin6;
 312         struct nf_conn *ct;
 313         __be32 flow_label;
 314         int bound_dev_if;
 315 
 316         lock_sock(sk);
 317         tuple.src.u3.in6 = sk->sk_v6_rcv_saddr;
 318         tuple.src.u.tcp.port = inet->inet_sport;
 319         tuple.dst.u3.in6 = sk->sk_v6_daddr;
 320         tuple.dst.u.tcp.port = inet->inet_dport;
 321         tuple.dst.protonum = sk->sk_protocol;
 322         bound_dev_if = sk->sk_bound_dev_if;
 323         flow_label = inet6->flow_label;
 324         release_sock(sk);
 325 
 326         if (tuple.dst.protonum != IPPROTO_TCP &&
 327             tuple.dst.protonum != IPPROTO_SCTP)
 328                 return -ENOPROTOOPT;
 329 
 330         if (*len < 0 || (unsigned int)*len < sizeof(sin6))
 331                 return -EINVAL;
 332 
 333         h = nf_conntrack_find_get(sock_net(sk), &nf_ct_zone_dflt, &tuple);
 334         if (!h) {
 335                 pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n",
 336                          &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port),
 337                          &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port));
 338                 return -ENOENT;
 339         }
 340 
 341         ct = nf_ct_tuplehash_to_ctrack(h);
 342 
 343         sin6.sin6_family = AF_INET6;
 344         sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port;
 345         sin6.sin6_flowinfo = flow_label & IPV6_FLOWINFO_MASK;
 346         memcpy(&sin6.sin6_addr,
 347                &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6,
 348                sizeof(sin6.sin6_addr));
 349 
 350         nf_ct_put(ct);
 351         sin6.sin6_scope_id = ipv6_iface_scope_id(&sin6.sin6_addr, bound_dev_if);
 352         return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0;
 353 }
 354 
 355 static struct nf_sockopt_ops so_getorigdst6 = {
 356         .pf             = NFPROTO_IPV6,
 357         .get_optmin     = IP6T_SO_ORIGINAL_DST,
 358         .get_optmax     = IP6T_SO_ORIGINAL_DST + 1,
 359         .get            = ipv6_getorigdst,
 360         .owner          = THIS_MODULE,
 361 };
 362 
 363 static unsigned int ipv6_confirm(void *priv,
 364                                  struct sk_buff *skb,
 365                                  const struct nf_hook_state *state)
 366 {
 367         struct nf_conn *ct;
 368         enum ip_conntrack_info ctinfo;
 369         unsigned char pnum = ipv6_hdr(skb)->nexthdr;
 370         __be16 frag_off;
 371         int protoff;
 372 
 373         ct = nf_ct_get(skb, &ctinfo);
 374         if (!ct || ctinfo == IP_CT_RELATED_REPLY)
 375                 return nf_conntrack_confirm(skb);
 376 
 377         protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &pnum,
 378                                    &frag_off);
 379         if (protoff < 0 || (frag_off & htons(~0x7)) != 0) {
 380                 pr_debug("proto header not found\n");
 381                 return nf_conntrack_confirm(skb);
 382         }
 383 
 384         return nf_confirm(skb, protoff, ct, ctinfo);
 385 }
 386 
 387 static unsigned int ipv6_conntrack_in(void *priv,
 388                                       struct sk_buff *skb,
 389                                       const struct nf_hook_state *state)
 390 {
 391         return nf_conntrack_in(skb, state);
 392 }
 393 
 394 static unsigned int ipv6_conntrack_local(void *priv,
 395                                          struct sk_buff *skb,
 396                                          const struct nf_hook_state *state)
 397 {
 398         return nf_conntrack_in(skb, state);
 399 }
 400 
 401 static const struct nf_hook_ops ipv6_conntrack_ops[] = {
 402         {
 403                 .hook           = ipv6_conntrack_in,
 404                 .pf             = NFPROTO_IPV6,
 405                 .hooknum        = NF_INET_PRE_ROUTING,
 406                 .priority       = NF_IP6_PRI_CONNTRACK,
 407         },
 408         {
 409                 .hook           = ipv6_conntrack_local,
 410                 .pf             = NFPROTO_IPV6,
 411                 .hooknum        = NF_INET_LOCAL_OUT,
 412                 .priority       = NF_IP6_PRI_CONNTRACK,
 413         },
 414         {
 415                 .hook           = ipv6_confirm,
 416                 .pf             = NFPROTO_IPV6,
 417                 .hooknum        = NF_INET_POST_ROUTING,
 418                 .priority       = NF_IP6_PRI_LAST,
 419         },
 420         {
 421                 .hook           = ipv6_confirm,
 422                 .pf             = NFPROTO_IPV6,
 423                 .hooknum        = NF_INET_LOCAL_IN,
 424                 .priority       = NF_IP6_PRI_LAST - 1,
 425         },
 426 };
 427 #endif
 428 
 429 static int nf_ct_tcp_fixup(struct nf_conn *ct, void *_nfproto)
 430 {
 431         u8 nfproto = (unsigned long)_nfproto;
 432 
 433         if (nf_ct_l3num(ct) != nfproto)
 434                 return 0;
 435 
 436         if (nf_ct_protonum(ct) == IPPROTO_TCP &&
 437             ct->proto.tcp.state == TCP_CONNTRACK_ESTABLISHED) {
 438                 ct->proto.tcp.seen[0].td_maxwin = 0;
 439                 ct->proto.tcp.seen[1].td_maxwin = 0;
 440         }
 441 
 442         return 0;
 443 }
 444 
 445 static struct nf_ct_bridge_info *nf_ct_bridge_info;
 446 
 447 static int nf_ct_netns_do_get(struct net *net, u8 nfproto)
 448 {
 449         struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
 450         bool fixup_needed = false, retry = true;
 451         int err = 0;
 452 retry:
 453         mutex_lock(&nf_ct_proto_mutex);
 454 
 455         switch (nfproto) {
 456         case NFPROTO_IPV4:
 457                 cnet->users4++;
 458                 if (cnet->users4 > 1)
 459                         goto out_unlock;
 460                 err = nf_defrag_ipv4_enable(net);
 461                 if (err) {
 462                         cnet->users4 = 0;
 463                         goto out_unlock;
 464                 }
 465 
 466                 err = nf_register_net_hooks(net, ipv4_conntrack_ops,
 467                                             ARRAY_SIZE(ipv4_conntrack_ops));
 468                 if (err)
 469                         cnet->users4 = 0;
 470                 else
 471                         fixup_needed = true;
 472                 break;
 473 #if IS_ENABLED(CONFIG_IPV6)
 474         case NFPROTO_IPV6:
 475                 cnet->users6++;
 476                 if (cnet->users6 > 1)
 477                         goto out_unlock;
 478                 err = nf_defrag_ipv6_enable(net);
 479                 if (err < 0) {
 480                         cnet->users6 = 0;
 481                         goto out_unlock;
 482                 }
 483 
 484                 err = nf_register_net_hooks(net, ipv6_conntrack_ops,
 485                                             ARRAY_SIZE(ipv6_conntrack_ops));
 486                 if (err)
 487                         cnet->users6 = 0;
 488                 else
 489                         fixup_needed = true;
 490                 break;
 491 #endif
 492         case NFPROTO_BRIDGE:
 493                 if (!nf_ct_bridge_info) {
 494                         if (!retry) {
 495                                 err = -EPROTO;
 496                                 goto out_unlock;
 497                         }
 498                         mutex_unlock(&nf_ct_proto_mutex);
 499                         request_module("nf_conntrack_bridge");
 500                         retry = false;
 501                         goto retry;
 502                 }
 503                 if (!try_module_get(nf_ct_bridge_info->me)) {
 504                         err = -EPROTO;
 505                         goto out_unlock;
 506                 }
 507                 cnet->users_bridge++;
 508                 if (cnet->users_bridge > 1)
 509                         goto out_unlock;
 510 
 511                 err = nf_register_net_hooks(net, nf_ct_bridge_info->ops,
 512                                             nf_ct_bridge_info->ops_size);
 513                 if (err)
 514                         cnet->users_bridge = 0;
 515                 else
 516                         fixup_needed = true;
 517                 break;
 518         default:
 519                 err = -EPROTO;
 520                 break;
 521         }
 522  out_unlock:
 523         mutex_unlock(&nf_ct_proto_mutex);
 524 
 525         if (fixup_needed)
 526                 nf_ct_iterate_cleanup_net(net, nf_ct_tcp_fixup,
 527                                           (void *)(unsigned long)nfproto, 0, 0);
 528 
 529         return err;
 530 }
 531 
 532 static void nf_ct_netns_do_put(struct net *net, u8 nfproto)
 533 {
 534         struct nf_conntrack_net *cnet = net_generic(net, nf_conntrack_net_id);
 535 
 536         mutex_lock(&nf_ct_proto_mutex);
 537         switch (nfproto) {
 538         case NFPROTO_IPV4:
 539                 if (cnet->users4 && (--cnet->users4 == 0))
 540                         nf_unregister_net_hooks(net, ipv4_conntrack_ops,
 541                                                 ARRAY_SIZE(ipv4_conntrack_ops));
 542                 break;
 543 #if IS_ENABLED(CONFIG_IPV6)
 544         case NFPROTO_IPV6:
 545                 if (cnet->users6 && (--cnet->users6 == 0))
 546                         nf_unregister_net_hooks(net, ipv6_conntrack_ops,
 547                                                 ARRAY_SIZE(ipv6_conntrack_ops));
 548                 break;
 549 #endif
 550         case NFPROTO_BRIDGE:
 551                 if (!nf_ct_bridge_info)
 552                         break;
 553                 if (cnet->users_bridge && (--cnet->users_bridge == 0))
 554                         nf_unregister_net_hooks(net, nf_ct_bridge_info->ops,
 555                                                 nf_ct_bridge_info->ops_size);
 556 
 557                 module_put(nf_ct_bridge_info->me);
 558                 break;
 559         }
 560         mutex_unlock(&nf_ct_proto_mutex);
 561 }
 562 
 563 static int nf_ct_netns_inet_get(struct net *net)
 564 {
 565         int err;
 566 
 567         err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
 568         if (err < 0)
 569                 goto err1;
 570         err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
 571         if (err < 0)
 572                 goto err2;
 573 
 574         return err;
 575 err2:
 576         nf_ct_netns_put(net, NFPROTO_IPV4);
 577 err1:
 578         return err;
 579 }
 580 
 581 int nf_ct_netns_get(struct net *net, u8 nfproto)
 582 {
 583         int err;
 584 
 585         switch (nfproto) {
 586         case NFPROTO_INET:
 587                 err = nf_ct_netns_inet_get(net);
 588                 break;
 589         case NFPROTO_BRIDGE:
 590                 err = nf_ct_netns_do_get(net, NFPROTO_BRIDGE);
 591                 if (err < 0)
 592                         return err;
 593 
 594                 err = nf_ct_netns_inet_get(net);
 595                 if (err < 0) {
 596                         nf_ct_netns_put(net, NFPROTO_BRIDGE);
 597                         return err;
 598                 }
 599                 break;
 600         default:
 601                 err = nf_ct_netns_do_get(net, nfproto);
 602                 break;
 603         }
 604         return err;
 605 }
 606 EXPORT_SYMBOL_GPL(nf_ct_netns_get);
 607 
 608 void nf_ct_netns_put(struct net *net, uint8_t nfproto)
 609 {
 610         switch (nfproto) {
 611         case NFPROTO_BRIDGE:
 612                 nf_ct_netns_do_put(net, NFPROTO_BRIDGE);
 613                 /* fall through */
 614         case NFPROTO_INET:
 615                 nf_ct_netns_do_put(net, NFPROTO_IPV4);
 616                 nf_ct_netns_do_put(net, NFPROTO_IPV6);
 617                 break;
 618         default:
 619                 nf_ct_netns_do_put(net, nfproto);
 620                 break;
 621         }
 622 }
 623 EXPORT_SYMBOL_GPL(nf_ct_netns_put);
 624 
 625 void nf_ct_bridge_register(struct nf_ct_bridge_info *info)
 626 {
 627         WARN_ON(nf_ct_bridge_info);
 628         mutex_lock(&nf_ct_proto_mutex);
 629         nf_ct_bridge_info = info;
 630         mutex_unlock(&nf_ct_proto_mutex);
 631 }
 632 EXPORT_SYMBOL_GPL(nf_ct_bridge_register);
 633 
 634 void nf_ct_bridge_unregister(struct nf_ct_bridge_info *info)
 635 {
 636         WARN_ON(!nf_ct_bridge_info);
 637         mutex_lock(&nf_ct_proto_mutex);
 638         nf_ct_bridge_info = NULL;
 639         mutex_unlock(&nf_ct_proto_mutex);
 640 }
 641 EXPORT_SYMBOL_GPL(nf_ct_bridge_unregister);
 642 
 643 int nf_conntrack_proto_init(void)
 644 {
 645         int ret;
 646 
 647         ret = nf_register_sockopt(&so_getorigdst);
 648         if (ret < 0)
 649                 return ret;
 650 
 651 #if IS_ENABLED(CONFIG_IPV6)
 652         ret = nf_register_sockopt(&so_getorigdst6);
 653         if (ret < 0)
 654                 goto cleanup_sockopt;
 655 #endif
 656 
 657         return ret;
 658 
 659 #if IS_ENABLED(CONFIG_IPV6)
 660 cleanup_sockopt:
 661         nf_unregister_sockopt(&so_getorigdst6);
 662 #endif
 663         return ret;
 664 }
 665 
 666 void nf_conntrack_proto_fini(void)
 667 {
 668         nf_unregister_sockopt(&so_getorigdst);
 669 #if IS_ENABLED(CONFIG_IPV6)
 670         nf_unregister_sockopt(&so_getorigdst6);
 671 #endif
 672 }
 673 
 674 void nf_conntrack_proto_pernet_init(struct net *net)
 675 {
 676         nf_conntrack_generic_init_net(net);
 677         nf_conntrack_udp_init_net(net);
 678         nf_conntrack_tcp_init_net(net);
 679         nf_conntrack_icmp_init_net(net);
 680 #if IS_ENABLED(CONFIG_IPV6)
 681         nf_conntrack_icmpv6_init_net(net);
 682 #endif
 683 #ifdef CONFIG_NF_CT_PROTO_DCCP
 684         nf_conntrack_dccp_init_net(net);
 685 #endif
 686 #ifdef CONFIG_NF_CT_PROTO_SCTP
 687         nf_conntrack_sctp_init_net(net);
 688 #endif
 689 #ifdef CONFIG_NF_CT_PROTO_GRE
 690         nf_conntrack_gre_init_net(net);
 691 #endif
 692 }
 693 
 694 void nf_conntrack_proto_pernet_fini(struct net *net)
 695 {
 696 #ifdef CONFIG_NF_CT_PROTO_GRE
 697         nf_ct_gre_keymap_flush(net);
 698 #endif
 699 }
 700 
 701 module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
 702                   &nf_conntrack_htable_size, 0600);
 703 
 704 MODULE_ALIAS("ip_conntrack");
 705 MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
 706 MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
 707 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */