linux/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
<<
>>
Prefs
   1/* (C) 1999-2001 Paul `Rusty' Russell
   2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
   3 * (C) 2006-2010 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/timer.h>
  12#include <linux/netfilter.h>
  13#include <linux/in.h>
  14#include <linux/icmp.h>
  15#include <linux/seq_file.h>
  16#include <net/ip.h>
  17#include <net/checksum.h>
  18#include <linux/netfilter_ipv4.h>
  19#include <net/netfilter/nf_conntrack_tuple.h>
  20#include <net/netfilter/nf_conntrack_l4proto.h>
  21#include <net/netfilter/nf_conntrack_core.h>
  22#include <net/netfilter/nf_conntrack_zones.h>
  23#include <net/netfilter/nf_log.h>
  24
  25static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ;
  26
  27static inline struct nf_icmp_net *icmp_pernet(struct net *net)
  28{
  29        return &net->ct.nf_ct_proto.icmp;
  30}
  31
  32static bool icmp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
  33                              struct nf_conntrack_tuple *tuple)
  34{
  35        const struct icmphdr *hp;
  36        struct icmphdr _hdr;
  37
  38        hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
  39        if (hp == NULL)
  40                return false;
  41
  42        tuple->dst.u.icmp.type = hp->type;
  43        tuple->src.u.icmp.id = hp->un.echo.id;
  44        tuple->dst.u.icmp.code = hp->code;
  45
  46        return true;
  47}
  48
  49/* Add 1; spaces filled with 0. */
  50static const u_int8_t invmap[] = {
  51        [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
  52        [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
  53        [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
  54        [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
  55        [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
  56        [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
  57        [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
  58        [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1
  59};
  60
  61static bool icmp_invert_tuple(struct nf_conntrack_tuple *tuple,
  62                              const struct nf_conntrack_tuple *orig)
  63{
  64        if (orig->dst.u.icmp.type >= sizeof(invmap) ||
  65            !invmap[orig->dst.u.icmp.type])
  66                return false;
  67
  68        tuple->src.u.icmp.id = orig->src.u.icmp.id;
  69        tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1;
  70        tuple->dst.u.icmp.code = orig->dst.u.icmp.code;
  71        return true;
  72}
  73
  74/* Print out the per-protocol part of the tuple. */
  75static int icmp_print_tuple(struct seq_file *s,
  76                            const struct nf_conntrack_tuple *tuple)
  77{
  78        return seq_printf(s, "type=%u code=%u id=%u ",
  79                          tuple->dst.u.icmp.type,
  80                          tuple->dst.u.icmp.code,
  81                          ntohs(tuple->src.u.icmp.id));
  82}
  83
  84static unsigned int *icmp_get_timeouts(struct net *net)
  85{
  86        return &icmp_pernet(net)->timeout;
  87}
  88
  89/* Returns verdict for packet, or -1 for invalid. */
  90static int icmp_packet(struct nf_conn *ct,
  91                       const struct sk_buff *skb,
  92                       unsigned int dataoff,
  93                       enum ip_conntrack_info ctinfo,
  94                       u_int8_t pf,
  95                       unsigned int hooknum,
  96                       unsigned int *timeout)
  97{
  98        /* Do not immediately delete the connection after the first
  99           successful reply to avoid excessive conntrackd traffic
 100           and also to handle correctly ICMP echo reply duplicates. */
 101        nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
 102
 103        return NF_ACCEPT;
 104}
 105
 106/* Called when a new connection for this protocol found. */
 107static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb,
 108                     unsigned int dataoff, unsigned int *timeouts)
 109{
 110        static const u_int8_t valid_new[] = {
 111                [ICMP_ECHO] = 1,
 112                [ICMP_TIMESTAMP] = 1,
 113                [ICMP_INFO_REQUEST] = 1,
 114                [ICMP_ADDRESS] = 1
 115        };
 116
 117        if (ct->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) ||
 118            !valid_new[ct->tuplehash[0].tuple.dst.u.icmp.type]) {
 119                /* Can't create a new ICMP `conn' with this. */
 120                pr_debug("icmp: can't create new conn with type %u\n",
 121                         ct->tuplehash[0].tuple.dst.u.icmp.type);
 122                nf_ct_dump_tuple_ip(&ct->tuplehash[0].tuple);
 123                return false;
 124        }
 125        return true;
 126}
 127
 128/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
 129static int
 130icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
 131                 enum ip_conntrack_info *ctinfo,
 132                 unsigned int hooknum)
 133{
 134        struct nf_conntrack_tuple innertuple, origtuple;
 135        const struct nf_conntrack_l4proto *innerproto;
 136        const struct nf_conntrack_tuple_hash *h;
 137        u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
 138
 139        NF_CT_ASSERT(skb->nfct == NULL);
 140
 141        /* Are they talking about one of our connections? */
 142        if (!nf_ct_get_tuplepr(skb,
 143                               skb_network_offset(skb) + ip_hdrlen(skb)
 144                                                       + sizeof(struct icmphdr),
 145                               PF_INET, &origtuple)) {
 146                pr_debug("icmp_error_message: failed to get tuple\n");
 147                return -NF_ACCEPT;
 148        }
 149
 150        /* rcu_read_lock()ed by nf_hook_slow */
 151        innerproto = __nf_ct_l4proto_find(PF_INET, origtuple.dst.protonum);
 152
 153        /* Ordinarily, we'd expect the inverted tupleproto, but it's
 154           been preserved inside the ICMP. */
 155        if (!nf_ct_invert_tuple(&innertuple, &origtuple,
 156                                &nf_conntrack_l3proto_ipv4, innerproto)) {
 157                pr_debug("icmp_error_message: no match\n");
 158                return -NF_ACCEPT;
 159        }
 160
 161        *ctinfo = IP_CT_RELATED;
 162
 163        h = nf_conntrack_find_get(net, zone, &innertuple);
 164        if (!h) {
 165                pr_debug("icmp_error_message: no match\n");
 166                return -NF_ACCEPT;
 167        }
 168
 169        if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
 170                *ctinfo += IP_CT_IS_REPLY;
 171
 172        /* Update skb to refer to this connection */
 173        skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
 174        skb->nfctinfo = *ctinfo;
 175        return NF_ACCEPT;
 176}
 177
 178/* Small and modified version of icmp_rcv */
 179static int
 180icmp_error(struct net *net, struct nf_conn *tmpl,
 181           struct sk_buff *skb, unsigned int dataoff,
 182           enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum)
 183{
 184        const struct icmphdr *icmph;
 185        struct icmphdr _ih;
 186
 187        /* Not enough header? */
 188        icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih);
 189        if (icmph == NULL) {
 190                if (LOG_INVALID(net, IPPROTO_ICMP))
 191                        nf_log_packet(net, PF_INET, 0, skb, NULL, NULL,
 192                                      NULL, "nf_ct_icmp: short packet ");
 193                return -NF_ACCEPT;
 194        }
 195
 196        /* See ip_conntrack_proto_tcp.c */
 197        if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 198            nf_ip_checksum(skb, hooknum, dataoff, 0)) {
 199                if (LOG_INVALID(net, IPPROTO_ICMP))
 200                        nf_log_packet(net, PF_INET, 0, skb, NULL, NULL, NULL,
 201                                      "nf_ct_icmp: bad HW ICMP checksum ");
 202                return -NF_ACCEPT;
 203        }
 204
 205        /*
 206         *      18 is the highest 'known' ICMP type. Anything else is a mystery
 207         *
 208         *      RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently
 209         *                discarded.
 210         */
 211        if (icmph->type > NR_ICMP_TYPES) {
 212                if (LOG_INVALID(net, IPPROTO_ICMP))
 213                        nf_log_packet(net, PF_INET, 0, skb, NULL, NULL, NULL,
 214                                      "nf_ct_icmp: invalid ICMP type ");
 215                return -NF_ACCEPT;
 216        }
 217
 218        /* Need to track icmp error message? */
 219        if (icmph->type != ICMP_DEST_UNREACH &&
 220            icmph->type != ICMP_SOURCE_QUENCH &&
 221            icmph->type != ICMP_TIME_EXCEEDED &&
 222            icmph->type != ICMP_PARAMETERPROB &&
 223            icmph->type != ICMP_REDIRECT)
 224                return NF_ACCEPT;
 225
 226        return icmp_error_message(net, tmpl, skb, ctinfo, hooknum);
 227}
 228
 229#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
 230
 231#include <linux/netfilter/nfnetlink.h>
 232#include <linux/netfilter/nfnetlink_conntrack.h>
 233
 234static int icmp_tuple_to_nlattr(struct sk_buff *skb,
 235                                const struct nf_conntrack_tuple *t)
 236{
 237        if (nla_put_be16(skb, CTA_PROTO_ICMP_ID, t->src.u.icmp.id) ||
 238            nla_put_u8(skb, CTA_PROTO_ICMP_TYPE, t->dst.u.icmp.type) ||
 239            nla_put_u8(skb, CTA_PROTO_ICMP_CODE, t->dst.u.icmp.code))
 240                goto nla_put_failure;
 241        return 0;
 242
 243nla_put_failure:
 244        return -1;
 245}
 246
 247static const struct nla_policy icmp_nla_policy[CTA_PROTO_MAX+1] = {
 248        [CTA_PROTO_ICMP_TYPE]   = { .type = NLA_U8 },
 249        [CTA_PROTO_ICMP_CODE]   = { .type = NLA_U8 },
 250        [CTA_PROTO_ICMP_ID]     = { .type = NLA_U16 },
 251};
 252
 253static int icmp_nlattr_to_tuple(struct nlattr *tb[],
 254                                struct nf_conntrack_tuple *tuple)
 255{
 256        if (!tb[CTA_PROTO_ICMP_TYPE] ||
 257            !tb[CTA_PROTO_ICMP_CODE] ||
 258            !tb[CTA_PROTO_ICMP_ID])
 259                return -EINVAL;
 260
 261        tuple->dst.u.icmp.type = nla_get_u8(tb[CTA_PROTO_ICMP_TYPE]);
 262        tuple->dst.u.icmp.code = nla_get_u8(tb[CTA_PROTO_ICMP_CODE]);
 263        tuple->src.u.icmp.id = nla_get_be16(tb[CTA_PROTO_ICMP_ID]);
 264
 265        if (tuple->dst.u.icmp.type >= sizeof(invmap) ||
 266            !invmap[tuple->dst.u.icmp.type])
 267                return -EINVAL;
 268
 269        return 0;
 270}
 271
 272static int icmp_nlattr_tuple_size(void)
 273{
 274        return nla_policy_len(icmp_nla_policy, CTA_PROTO_MAX + 1);
 275}
 276#endif
 277
 278#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 279
 280#include <linux/netfilter/nfnetlink.h>
 281#include <linux/netfilter/nfnetlink_cttimeout.h>
 282
 283static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[],
 284                                      struct net *net, void *data)
 285{
 286        unsigned int *timeout = data;
 287        struct nf_icmp_net *in = icmp_pernet(net);
 288
 289        if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) {
 290                *timeout =
 291                        ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ;
 292        } else {
 293                /* Set default ICMP timeout. */
 294                *timeout = in->timeout;
 295        }
 296        return 0;
 297}
 298
 299static int
 300icmp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
 301{
 302        const unsigned int *timeout = data;
 303
 304        if (nla_put_be32(skb, CTA_TIMEOUT_ICMP_TIMEOUT, htonl(*timeout / HZ)))
 305                goto nla_put_failure;
 306        return 0;
 307
 308nla_put_failure:
 309        return -ENOSPC;
 310}
 311
 312static const struct nla_policy
 313icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = {
 314        [CTA_TIMEOUT_ICMP_TIMEOUT]      = { .type = NLA_U32 },
 315};
 316#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 317
 318#ifdef CONFIG_SYSCTL
 319static struct ctl_table icmp_sysctl_table[] = {
 320        {
 321                .procname       = "nf_conntrack_icmp_timeout",
 322                .maxlen         = sizeof(unsigned int),
 323                .mode           = 0644,
 324                .proc_handler   = proc_dointvec_jiffies,
 325        },
 326        { }
 327};
 328#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 329static struct ctl_table icmp_compat_sysctl_table[] = {
 330        {
 331                .procname       = "ip_conntrack_icmp_timeout",
 332                .maxlen         = sizeof(unsigned int),
 333                .mode           = 0644,
 334                .proc_handler   = proc_dointvec_jiffies,
 335        },
 336        { }
 337};
 338#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 339#endif /* CONFIG_SYSCTL */
 340
 341static int icmp_kmemdup_sysctl_table(struct nf_proto_net *pn,
 342                                     struct nf_icmp_net *in)
 343{
 344#ifdef CONFIG_SYSCTL
 345        pn->ctl_table = kmemdup(icmp_sysctl_table,
 346                                sizeof(icmp_sysctl_table),
 347                                GFP_KERNEL);
 348        if (!pn->ctl_table)
 349                return -ENOMEM;
 350
 351        pn->ctl_table[0].data = &in->timeout;
 352#endif
 353        return 0;
 354}
 355
 356static int icmp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
 357                                            struct nf_icmp_net *in)
 358{
 359#ifdef CONFIG_SYSCTL
 360#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 361        pn->ctl_compat_table = kmemdup(icmp_compat_sysctl_table,
 362                                       sizeof(icmp_compat_sysctl_table),
 363                                       GFP_KERNEL);
 364        if (!pn->ctl_compat_table)
 365                return -ENOMEM;
 366
 367        pn->ctl_compat_table[0].data = &in->timeout;
 368#endif
 369#endif
 370        return 0;
 371}
 372
 373static int icmp_init_net(struct net *net, u_int16_t proto)
 374{
 375        int ret;
 376        struct nf_icmp_net *in = icmp_pernet(net);
 377        struct nf_proto_net *pn = &in->pn;
 378
 379        in->timeout = nf_ct_icmp_timeout;
 380
 381        ret = icmp_kmemdup_compat_sysctl_table(pn, in);
 382        if (ret < 0)
 383                return ret;
 384
 385        ret = icmp_kmemdup_sysctl_table(pn, in);
 386        if (ret < 0)
 387                nf_ct_kfree_compat_sysctl_table(pn);
 388
 389        return ret;
 390}
 391
 392static struct nf_proto_net *icmp_get_net_proto(struct net *net)
 393{
 394        return &net->ct.nf_ct_proto.icmp.pn;
 395}
 396
 397struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
 398{
 399        .l3proto                = PF_INET,
 400        .l4proto                = IPPROTO_ICMP,
 401        .name                   = "icmp",
 402        .pkt_to_tuple           = icmp_pkt_to_tuple,
 403        .invert_tuple           = icmp_invert_tuple,
 404        .print_tuple            = icmp_print_tuple,
 405        .packet                 = icmp_packet,
 406        .get_timeouts           = icmp_get_timeouts,
 407        .new                    = icmp_new,
 408        .error                  = icmp_error,
 409        .destroy                = NULL,
 410        .me                     = NULL,
 411#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
 412        .tuple_to_nlattr        = icmp_tuple_to_nlattr,
 413        .nlattr_tuple_size      = icmp_nlattr_tuple_size,
 414        .nlattr_to_tuple        = icmp_nlattr_to_tuple,
 415        .nla_policy             = icmp_nla_policy,
 416#endif
 417#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 418        .ctnl_timeout           = {
 419                .nlattr_to_obj  = icmp_timeout_nlattr_to_obj,
 420                .obj_to_nlattr  = icmp_timeout_obj_to_nlattr,
 421                .nlattr_max     = CTA_TIMEOUT_ICMP_MAX,
 422                .obj_size       = sizeof(unsigned int),
 423                .nla_policy     = icmp_timeout_nla_policy,
 424        },
 425#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 426        .init_net               = icmp_init_net,
 427        .get_net_proto          = icmp_get_net_proto,
 428};
 429