linux/net/netfilter/nf_conntrack_standalone.c
<<
>>
Prefs
   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
  10#include <linux/types.h>
  11#include <linux/netfilter.h>
  12#include <linux/slab.h>
  13#include <linux/module.h>
  14#include <linux/skbuff.h>
  15#include <linux/proc_fs.h>
  16#include <linux/seq_file.h>
  17#include <linux/percpu.h>
  18#include <linux/netdevice.h>
  19#include <linux/security.h>
  20#include <net/net_namespace.h>
  21#ifdef CONFIG_SYSCTL
  22#include <linux/sysctl.h>
  23#endif
  24
  25#include <net/netfilter/nf_conntrack.h>
  26#include <net/netfilter/nf_conntrack_core.h>
  27#include <net/netfilter/nf_conntrack_l3proto.h>
  28#include <net/netfilter/nf_conntrack_l4proto.h>
  29#include <net/netfilter/nf_conntrack_expect.h>
  30#include <net/netfilter/nf_conntrack_helper.h>
  31#include <net/netfilter/nf_conntrack_acct.h>
  32#include <net/netfilter/nf_conntrack_zones.h>
  33#include <net/netfilter/nf_conntrack_timestamp.h>
  34#include <linux/rculist_nulls.h>
  35
  36MODULE_LICENSE("GPL");
  37
  38#ifdef CONFIG_NF_CONNTRACK_PROCFS
  39void
  40print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
  41            const struct nf_conntrack_l3proto *l3proto,
  42            const struct nf_conntrack_l4proto *l4proto)
  43{
  44        l3proto->print_tuple(s, tuple);
  45        l4proto->print_tuple(s, tuple);
  46}
  47EXPORT_SYMBOL_GPL(print_tuple);
  48
  49struct ct_iter_state {
  50        struct seq_net_private p;
  51        struct hlist_nulls_head *hash;
  52        unsigned int htable_size;
  53        unsigned int bucket;
  54        u_int64_t time_now;
  55};
  56
  57static struct hlist_nulls_node *ct_get_first(struct seq_file *seq)
  58{
  59        struct ct_iter_state *st = seq->private;
  60        struct hlist_nulls_node *n;
  61
  62        for (st->bucket = 0;
  63             st->bucket < st->htable_size;
  64             st->bucket++) {
  65                n = rcu_dereference(
  66                        hlist_nulls_first_rcu(&st->hash[st->bucket]));
  67                if (!is_a_nulls(n))
  68                        return n;
  69        }
  70        return NULL;
  71}
  72
  73static struct hlist_nulls_node *ct_get_next(struct seq_file *seq,
  74                                      struct hlist_nulls_node *head)
  75{
  76        struct ct_iter_state *st = seq->private;
  77
  78        head = rcu_dereference(hlist_nulls_next_rcu(head));
  79        while (is_a_nulls(head)) {
  80                if (likely(get_nulls_value(head) == st->bucket)) {
  81                        if (++st->bucket >= st->htable_size)
  82                                return NULL;
  83                }
  84                head = rcu_dereference(
  85                        hlist_nulls_first_rcu(&st->hash[st->bucket]));
  86        }
  87        return head;
  88}
  89
  90static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos)
  91{
  92        struct hlist_nulls_node *head = ct_get_first(seq);
  93
  94        if (head)
  95                while (pos && (head = ct_get_next(seq, head)))
  96                        pos--;
  97        return pos ? NULL : head;
  98}
  99
 100static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
 101        __acquires(RCU)
 102{
 103        struct ct_iter_state *st = seq->private;
 104
 105        st->time_now = ktime_get_real_ns();
 106        rcu_read_lock();
 107
 108        nf_conntrack_get_ht(&st->hash, &st->htable_size);
 109        return ct_get_idx(seq, *pos);
 110}
 111
 112static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
 113{
 114        (*pos)++;
 115        return ct_get_next(s, v);
 116}
 117
 118static void ct_seq_stop(struct seq_file *s, void *v)
 119        __releases(RCU)
 120{
 121        rcu_read_unlock();
 122}
 123
 124#ifdef CONFIG_NF_CONNTRACK_SECMARK
 125static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
 126{
 127        int ret;
 128        u32 len;
 129        char *secctx;
 130
 131        ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
 132        if (ret)
 133                return;
 134
 135        seq_printf(s, "secctx=%s ", secctx);
 136
 137        security_release_secctx(secctx, len);
 138}
 139#else
 140static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
 141{
 142}
 143#endif
 144
 145#ifdef CONFIG_NF_CONNTRACK_ZONES
 146static void ct_show_zone(struct seq_file *s, const struct nf_conn *ct,
 147                         int dir)
 148{
 149        const struct nf_conntrack_zone *zone = nf_ct_zone(ct);
 150
 151        if (zone->dir != dir)
 152                return;
 153        switch (zone->dir) {
 154        case NF_CT_DEFAULT_ZONE_DIR:
 155                seq_printf(s, "zone=%u ", zone->id);
 156                break;
 157        case NF_CT_ZONE_DIR_ORIG:
 158                seq_printf(s, "zone-orig=%u ", zone->id);
 159                break;
 160        case NF_CT_ZONE_DIR_REPL:
 161                seq_printf(s, "zone-reply=%u ", zone->id);
 162                break;
 163        default:
 164                break;
 165        }
 166}
 167#else
 168static inline void ct_show_zone(struct seq_file *s, const struct nf_conn *ct,
 169                                int dir)
 170{
 171}
 172#endif
 173
 174#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
 175static void ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
 176{
 177        struct ct_iter_state *st = s->private;
 178        struct nf_conn_tstamp *tstamp;
 179        s64 delta_time;
 180
 181        tstamp = nf_conn_tstamp_find(ct);
 182        if (tstamp) {
 183                delta_time = st->time_now - tstamp->start;
 184                if (delta_time > 0)
 185                        delta_time = div_s64(delta_time, NSEC_PER_SEC);
 186                else
 187                        delta_time = 0;
 188
 189                seq_printf(s, "delta-time=%llu ",
 190                           (unsigned long long)delta_time);
 191        }
 192        return;
 193}
 194#else
 195static inline void
 196ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
 197{
 198}
 199#endif
 200
 201/* return 0 on success, 1 in case of error */
 202static int ct_seq_show(struct seq_file *s, void *v)
 203{
 204        struct nf_conntrack_tuple_hash *hash = v;
 205        struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
 206        const struct nf_conntrack_l3proto *l3proto;
 207        const struct nf_conntrack_l4proto *l4proto;
 208        struct net *net = seq_file_net(s);
 209        int ret = 0;
 210
 211        NF_CT_ASSERT(ct);
 212        if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
 213                return 0;
 214
 215        if (nf_ct_should_gc(ct)) {
 216                nf_ct_kill(ct);
 217                goto release;
 218        }
 219
 220        /* we only want to print DIR_ORIGINAL */
 221        if (NF_CT_DIRECTION(hash))
 222                goto release;
 223
 224        if (!net_eq(nf_ct_net(ct), net))
 225                goto release;
 226
 227        l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));
 228        NF_CT_ASSERT(l3proto);
 229        l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
 230        NF_CT_ASSERT(l4proto);
 231
 232        ret = -ENOSPC;
 233        seq_printf(s, "%-8s %u %-8s %u %ld ",
 234                   l3proto->name, nf_ct_l3num(ct),
 235                   l4proto->name, nf_ct_protonum(ct),
 236                   nf_ct_expires(ct)  / HZ);
 237
 238        if (l4proto->print_conntrack)
 239                l4proto->print_conntrack(s, ct);
 240
 241        print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
 242                    l3proto, l4proto);
 243
 244        ct_show_zone(s, ct, NF_CT_ZONE_DIR_ORIG);
 245
 246        if (seq_has_overflowed(s))
 247                goto release;
 248
 249        if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL))
 250                goto release;
 251
 252        if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
 253                seq_puts(s, "[UNREPLIED] ");
 254
 255        print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
 256                    l3proto, l4proto);
 257
 258        ct_show_zone(s, ct, NF_CT_ZONE_DIR_REPL);
 259
 260        if (seq_print_acct(s, ct, IP_CT_DIR_REPLY))
 261                goto release;
 262
 263        if (test_bit(IPS_ASSURED_BIT, &ct->status))
 264                seq_puts(s, "[ASSURED] ");
 265
 266        if (seq_has_overflowed(s))
 267                goto release;
 268
 269#if defined(CONFIG_NF_CONNTRACK_MARK)
 270        seq_printf(s, "mark=%u ", ct->mark);
 271#endif
 272
 273        ct_show_secctx(s, ct);
 274        ct_show_zone(s, ct, NF_CT_DEFAULT_ZONE_DIR);
 275        ct_show_delta_time(s, ct);
 276
 277        seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use));
 278
 279        if (seq_has_overflowed(s))
 280                goto release;
 281
 282        ret = 0;
 283release:
 284        nf_ct_put(ct);
 285        return ret;
 286}
 287
 288static const struct seq_operations ct_seq_ops = {
 289        .start = ct_seq_start,
 290        .next  = ct_seq_next,
 291        .stop  = ct_seq_stop,
 292        .show  = ct_seq_show
 293};
 294
 295static int ct_open(struct inode *inode, struct file *file)
 296{
 297        return seq_open_net(inode, file, &ct_seq_ops,
 298                        sizeof(struct ct_iter_state));
 299}
 300
 301static const struct file_operations ct_file_ops = {
 302        .owner   = THIS_MODULE,
 303        .open    = ct_open,
 304        .read    = seq_read,
 305        .llseek  = seq_lseek,
 306        .release = seq_release_net,
 307};
 308
 309static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
 310{
 311        struct net *net = seq_file_net(seq);
 312        int cpu;
 313
 314        if (*pos == 0)
 315                return SEQ_START_TOKEN;
 316
 317        for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
 318                if (!cpu_possible(cpu))
 319                        continue;
 320                *pos = cpu + 1;
 321                return per_cpu_ptr(net->ct.stat, cpu);
 322        }
 323
 324        return NULL;
 325}
 326
 327static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 328{
 329        struct net *net = seq_file_net(seq);
 330        int cpu;
 331
 332        for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
 333                if (!cpu_possible(cpu))
 334                        continue;
 335                *pos = cpu + 1;
 336                return per_cpu_ptr(net->ct.stat, cpu);
 337        }
 338
 339        return NULL;
 340}
 341
 342static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
 343{
 344}
 345
 346static int ct_cpu_seq_show(struct seq_file *seq, void *v)
 347{
 348        struct net *net = seq_file_net(seq);
 349        unsigned int nr_conntracks = atomic_read(&net->ct.count);
 350        const struct ip_conntrack_stat *st = v;
 351
 352        if (v == SEQ_START_TOKEN) {
 353                seq_puts(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");
 354                return 0;
 355        }
 356
 357        seq_printf(seq, "%08x  %08x %08x %08x %08x %08x %08x %08x "
 358                        "%08x %08x %08x %08x %08x  %08x %08x %08x %08x\n",
 359                   nr_conntracks,
 360                   0,
 361                   st->found,
 362                   0,
 363                   st->invalid,
 364                   st->ignore,
 365                   0,
 366                   0,
 367                   st->insert,
 368                   st->insert_failed,
 369                   st->drop,
 370                   st->early_drop,
 371                   st->error,
 372
 373                   st->expect_new,
 374                   st->expect_create,
 375                   st->expect_delete,
 376                   st->search_restart
 377                );
 378        return 0;
 379}
 380
 381static const struct seq_operations ct_cpu_seq_ops = {
 382        .start  = ct_cpu_seq_start,
 383        .next   = ct_cpu_seq_next,
 384        .stop   = ct_cpu_seq_stop,
 385        .show   = ct_cpu_seq_show,
 386};
 387
 388static int ct_cpu_seq_open(struct inode *inode, struct file *file)
 389{
 390        return seq_open_net(inode, file, &ct_cpu_seq_ops,
 391                            sizeof(struct seq_net_private));
 392}
 393
 394static const struct file_operations ct_cpu_seq_fops = {
 395        .owner   = THIS_MODULE,
 396        .open    = ct_cpu_seq_open,
 397        .read    = seq_read,
 398        .llseek  = seq_lseek,
 399        .release = seq_release_net,
 400};
 401
 402static int nf_conntrack_standalone_init_proc(struct net *net)
 403{
 404        struct proc_dir_entry *pde;
 405        kuid_t root_uid;
 406        kgid_t root_gid;
 407
 408        pde = proc_create("nf_conntrack", 0440, net->proc_net, &ct_file_ops);
 409        if (!pde)
 410                goto out_nf_conntrack;
 411
 412        root_uid = make_kuid(net->user_ns, 0);
 413        root_gid = make_kgid(net->user_ns, 0);
 414        if (uid_valid(root_uid) && gid_valid(root_gid))
 415                proc_set_user(pde, root_uid, root_gid);
 416
 417        pde = proc_create("nf_conntrack", S_IRUGO, net->proc_net_stat,
 418                          &ct_cpu_seq_fops);
 419        if (!pde)
 420                goto out_stat_nf_conntrack;
 421        return 0;
 422
 423out_stat_nf_conntrack:
 424        remove_proc_entry("nf_conntrack", net->proc_net);
 425out_nf_conntrack:
 426        return -ENOMEM;
 427}
 428
 429static void nf_conntrack_standalone_fini_proc(struct net *net)
 430{
 431        remove_proc_entry("nf_conntrack", net->proc_net_stat);
 432        remove_proc_entry("nf_conntrack", net->proc_net);
 433}
 434#else
 435static int nf_conntrack_standalone_init_proc(struct net *net)
 436{
 437        return 0;
 438}
 439
 440static void nf_conntrack_standalone_fini_proc(struct net *net)
 441{
 442}
 443#endif /* CONFIG_NF_CONNTRACK_PROCFS */
 444
 445/* Sysctl support */
 446
 447#ifdef CONFIG_SYSCTL
 448/* Log invalid packets of a given protocol */
 449static int log_invalid_proto_min __read_mostly;
 450static int log_invalid_proto_max __read_mostly = 255;
 451
 452/* size the user *wants to set */
 453static unsigned int nf_conntrack_htable_size_user __read_mostly;
 454
 455extern unsigned int nf_conntrack_default_on;
 456unsigned int nf_conntrack_default_on __read_mostly = 1;
 457
 458static int
 459nf_conntrack_hash_sysctl(struct ctl_table *table, int write,
 460                         void __user *buffer, size_t *lenp, loff_t *ppos)
 461{
 462        int ret;
 463
 464        ret = proc_dointvec(table, write, buffer, lenp, ppos);
 465        if (ret < 0 || !write)
 466                return ret;
 467
 468        /* update ret, we might not be able to satisfy request */
 469        ret = nf_conntrack_hash_resize(nf_conntrack_htable_size_user);
 470
 471        /* update it to the actual value used by conntrack */
 472        nf_conntrack_htable_size_user = nf_conntrack_htable_size;
 473        return ret;
 474}
 475
 476static struct ctl_table_header *nf_ct_netfilter_header;
 477
 478static struct ctl_table nf_ct_sysctl_table[] = {
 479        {
 480                .procname       = "nf_conntrack_max",
 481                .data           = &nf_conntrack_max,
 482                .maxlen         = sizeof(int),
 483                .mode           = 0644,
 484                .proc_handler   = proc_dointvec,
 485        },
 486        {
 487                .procname       = "nf_conntrack_count",
 488                .data           = &init_net.ct.count,
 489                .maxlen         = sizeof(int),
 490                .mode           = 0444,
 491                .proc_handler   = proc_dointvec,
 492        },
 493        {
 494                .procname       = "nf_conntrack_buckets",
 495                .data           = &nf_conntrack_htable_size_user,
 496                .maxlen         = sizeof(unsigned int),
 497                .mode           = 0644,
 498                .proc_handler   = nf_conntrack_hash_sysctl,
 499        },
 500        {
 501                .procname       = "nf_conntrack_checksum",
 502                .data           = &init_net.ct.sysctl_checksum,
 503                .maxlen         = sizeof(unsigned int),
 504                .mode           = 0644,
 505                .proc_handler   = proc_dointvec,
 506        },
 507        {
 508                .procname       = "nf_conntrack_log_invalid",
 509                .data           = &init_net.ct.sysctl_log_invalid,
 510                .maxlen         = sizeof(unsigned int),
 511                .mode           = 0644,
 512                .proc_handler   = proc_dointvec_minmax,
 513                .extra1         = &log_invalid_proto_min,
 514                .extra2         = &log_invalid_proto_max,
 515        },
 516        {
 517                .procname       = "nf_conntrack_expect_max",
 518                .data           = &nf_ct_expect_max,
 519                .maxlen         = sizeof(int),
 520                .mode           = 0644,
 521                .proc_handler   = proc_dointvec,
 522        },
 523        {
 524                .procname       = "nf_conntrack_default_on",
 525                .data           = &nf_conntrack_default_on,
 526                .maxlen         = sizeof(unsigned int),
 527                .mode           = 0644,
 528                .proc_handler   = proc_dointvec,
 529        },
 530        { }
 531};
 532
 533static struct ctl_table nf_ct_netfilter_table[] = {
 534        {
 535                .procname       = "nf_conntrack_max",
 536                .data           = &nf_conntrack_max,
 537                .maxlen         = sizeof(int),
 538                .mode           = 0644,
 539                .proc_handler   = proc_dointvec,
 540        },
 541        { }
 542};
 543
 544static int nf_conntrack_standalone_init_sysctl(struct net *net)
 545{
 546        struct ctl_table *table;
 547
 548        table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table),
 549                        GFP_KERNEL);
 550        if (!table)
 551                goto out_kmemdup;
 552
 553        table[1].data = &net->ct.count;
 554        table[3].data = &net->ct.sysctl_checksum;
 555        table[4].data = &net->ct.sysctl_log_invalid;
 556
 557        /* Don't export sysctls to unprivileged users */
 558        if (net->user_ns != &init_user_ns)
 559                table[0].procname = NULL;
 560
 561        if (!net_eq(&init_net, net))
 562                table[2].mode = 0444;
 563
 564        net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table);
 565        if (!net->ct.sysctl_header)
 566                goto out_unregister_netfilter;
 567
 568        return 0;
 569
 570out_unregister_netfilter:
 571        kfree(table);
 572out_kmemdup:
 573        return -ENOMEM;
 574}
 575
 576static void nf_conntrack_standalone_fini_sysctl(struct net *net)
 577{
 578        struct ctl_table *table;
 579
 580        table = net->ct.sysctl_header->ctl_table_arg;
 581        unregister_net_sysctl_table(net->ct.sysctl_header);
 582        kfree(table);
 583}
 584#else
 585static int nf_conntrack_standalone_init_sysctl(struct net *net)
 586{
 587        return 0;
 588}
 589
 590static void nf_conntrack_standalone_fini_sysctl(struct net *net)
 591{
 592}
 593#endif /* CONFIG_SYSCTL */
 594
 595static int nf_conntrack_pernet_init(struct net *net)
 596{
 597        int ret;
 598
 599        ret = nf_conntrack_init_net(net);
 600        if (ret < 0)
 601                goto out_init;
 602
 603        ret = nf_conntrack_standalone_init_proc(net);
 604        if (ret < 0)
 605                goto out_proc;
 606
 607        net->ct.sysctl_checksum = 1;
 608        net->ct.sysctl_log_invalid = 0;
 609        ret = nf_conntrack_standalone_init_sysctl(net);
 610        if (ret < 0)
 611                goto out_sysctl;
 612
 613        return 0;
 614
 615out_sysctl:
 616        nf_conntrack_standalone_fini_proc(net);
 617out_proc:
 618        nf_conntrack_cleanup_net(net);
 619out_init:
 620        return ret;
 621}
 622
 623static void nf_conntrack_pernet_exit(struct list_head *net_exit_list)
 624{
 625        struct net *net;
 626
 627        list_for_each_entry(net, net_exit_list, exit_list) {
 628                nf_conntrack_standalone_fini_sysctl(net);
 629                nf_conntrack_standalone_fini_proc(net);
 630        }
 631        nf_conntrack_cleanup_net_list(net_exit_list);
 632}
 633
 634static struct pernet_operations nf_conntrack_net_ops = {
 635        .init           = nf_conntrack_pernet_init,
 636        .exit_batch     = nf_conntrack_pernet_exit,
 637};
 638
 639static int __init nf_conntrack_standalone_init(void)
 640{
 641        int ret = nf_conntrack_init_start();
 642        if (ret < 0)
 643                goto out_start;
 644
 645        BUILD_BUG_ON(SKB_NFCT_PTRMASK != NFCT_PTRMASK);
 646        BUILD_BUG_ON(NFCT_INFOMASK <= IP_CT_NUMBER);
 647
 648#ifdef CONFIG_SYSCTL
 649        nf_ct_netfilter_header =
 650                register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
 651        if (!nf_ct_netfilter_header) {
 652                pr_err("nf_conntrack: can't register to sysctl.\n");
 653                ret = -ENOMEM;
 654                goto out_sysctl;
 655        }
 656
 657        nf_conntrack_htable_size_user = nf_conntrack_htable_size;
 658#endif
 659
 660        ret = register_pernet_subsys(&nf_conntrack_net_ops);
 661        if (ret < 0)
 662                goto out_pernet;
 663
 664        nf_conntrack_init_end();
 665        return 0;
 666
 667out_pernet:
 668#ifdef CONFIG_SYSCTL
 669        unregister_net_sysctl_table(nf_ct_netfilter_header);
 670out_sysctl:
 671#endif
 672        nf_conntrack_cleanup_end();
 673out_start:
 674        return ret;
 675}
 676
 677static void __exit nf_conntrack_standalone_fini(void)
 678{
 679        nf_conntrack_cleanup_start();
 680        unregister_pernet_subsys(&nf_conntrack_net_ops);
 681#ifdef CONFIG_SYSCTL
 682        unregister_net_sysctl_table(nf_ct_netfilter_header);
 683#endif
 684        nf_conntrack_cleanup_end();
 685}
 686
 687module_init(nf_conntrack_standalone_init);
 688module_exit(nf_conntrack_standalone_fini);
 689
 690/* Some modules need us, but don't depend directly on any symbol.
 691   They should call this. */
 692void need_conntrack(void)
 693{
 694}
 695EXPORT_SYMBOL_GPL(need_conntrack);
 696