linux/net/netfilter/nf_conntrack_proto_udp.c
<<
>>
Prefs
   1/* (C) 1999-2001 Paul `Rusty' Russell
   2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
   3 * (C) 2006-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/timer.h>
  12#include <linux/module.h>
  13#include <linux/udp.h>
  14#include <linux/seq_file.h>
  15#include <linux/skbuff.h>
  16#include <linux/ipv6.h>
  17#include <net/ip6_checksum.h>
  18#include <net/checksum.h>
  19
  20#include <linux/netfilter.h>
  21#include <linux/netfilter_ipv4.h>
  22#include <linux/netfilter_ipv6.h>
  23#include <net/netfilter/nf_conntrack_l4proto.h>
  24#include <net/netfilter/nf_conntrack_ecache.h>
  25#include <net/netfilter/nf_log.h>
  26#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
  27#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
  28
  29static unsigned int udp_timeouts[UDP_CT_MAX] = {
  30        [UDP_CT_UNREPLIED]      = 30*HZ,
  31        [UDP_CT_REPLIED]        = 180*HZ,
  32};
  33
  34static inline struct nf_udp_net *udp_pernet(struct net *net)
  35{
  36        return &net->ct.nf_ct_proto.udp;
  37}
  38
  39static bool udp_pkt_to_tuple(const struct sk_buff *skb,
  40                             unsigned int dataoff,
  41                             struct nf_conntrack_tuple *tuple)
  42{
  43        const struct udphdr *hp;
  44        struct udphdr _hdr;
  45
  46        /* Actually only need first 8 bytes. */
  47        hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
  48        if (hp == NULL)
  49                return false;
  50
  51        tuple->src.u.udp.port = hp->source;
  52        tuple->dst.u.udp.port = hp->dest;
  53
  54        return true;
  55}
  56
  57static bool udp_invert_tuple(struct nf_conntrack_tuple *tuple,
  58                             const struct nf_conntrack_tuple *orig)
  59{
  60        tuple->src.u.udp.port = orig->dst.u.udp.port;
  61        tuple->dst.u.udp.port = orig->src.u.udp.port;
  62        return true;
  63}
  64
  65/* Print out the per-protocol part of the tuple. */
  66static int udp_print_tuple(struct seq_file *s,
  67                           const struct nf_conntrack_tuple *tuple)
  68{
  69        return seq_printf(s, "sport=%hu dport=%hu ",
  70                          ntohs(tuple->src.u.udp.port),
  71                          ntohs(tuple->dst.u.udp.port));
  72}
  73
  74static unsigned int *udp_get_timeouts(struct net *net)
  75{
  76        return udp_pernet(net)->timeouts;
  77}
  78
  79/* Returns verdict for packet, and may modify conntracktype */
  80static int udp_packet(struct nf_conn *ct,
  81                      const struct sk_buff *skb,
  82                      unsigned int dataoff,
  83                      enum ip_conntrack_info ctinfo,
  84                      u_int8_t pf,
  85                      unsigned int hooknum,
  86                      unsigned int *timeouts)
  87{
  88        /* If we've seen traffic both ways, this is some kind of UDP
  89           stream.  Extend timeout. */
  90        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
  91                nf_ct_refresh_acct(ct, ctinfo, skb,
  92                                   timeouts[UDP_CT_REPLIED]);
  93                /* Also, more likely to be important, and not a probe */
  94                if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
  95                        nf_conntrack_event_cache(IPCT_ASSURED, ct);
  96        } else {
  97                nf_ct_refresh_acct(ct, ctinfo, skb,
  98                                   timeouts[UDP_CT_UNREPLIED]);
  99        }
 100        return NF_ACCEPT;
 101}
 102
 103/* Called when a new connection for this protocol found. */
 104static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb,
 105                    unsigned int dataoff, unsigned int *timeouts)
 106{
 107        return true;
 108}
 109
 110#ifdef CONFIG_NF_CT_PROTO_UDPLITE
 111static int udplite_error(struct net *net, struct nf_conn *tmpl,
 112                         struct sk_buff *skb,
 113                         unsigned int dataoff,
 114                         enum ip_conntrack_info *ctinfo,
 115                         u8 pf, unsigned int hooknum)
 116{
 117        unsigned int udplen = skb->len - dataoff;
 118        const struct udphdr *hdr;
 119        struct udphdr _hdr;
 120        unsigned int cscov;
 121
 122        /* Header is too small? */
 123        hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
 124        if (!hdr) {
 125                if (LOG_INVALID(net, IPPROTO_UDPLITE))
 126                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 127                                      "nf_ct_udplite: short packet ");
 128                return -NF_ACCEPT;
 129        }
 130
 131        cscov = ntohs(hdr->len);
 132        if (cscov == 0) {
 133                cscov = udplen;
 134        } else if (cscov < sizeof(*hdr) || cscov > udplen) {
 135                if (LOG_INVALID(net, IPPROTO_UDPLITE))
 136                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 137                                      "nf_ct_udplite: invalid checksum coverage ");
 138                return -NF_ACCEPT;
 139        }
 140
 141        /* UDPLITE mandates checksums */
 142        if (!hdr->check) {
 143                if (LOG_INVALID(net, IPPROTO_UDPLITE))
 144                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 145                                      "nf_ct_udplite: checksum missing ");
 146                return -NF_ACCEPT;
 147        }
 148
 149        /* Checksum invalid? Ignore. */
 150        if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 151            nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP,
 152                                pf)) {
 153                if (LOG_INVALID(net, IPPROTO_UDPLITE))
 154                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 155                                      "nf_ct_udplite: bad UDPLite checksum ");
 156                return -NF_ACCEPT;
 157        }
 158
 159        return NF_ACCEPT;
 160}
 161#endif
 162
 163static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
 164                     unsigned int dataoff, enum ip_conntrack_info *ctinfo,
 165                     u_int8_t pf,
 166                     unsigned int hooknum)
 167{
 168        unsigned int udplen = skb->len - dataoff;
 169        const struct udphdr *hdr;
 170        struct udphdr _hdr;
 171
 172        /* Header is too small? */
 173        hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
 174        if (hdr == NULL) {
 175                if (LOG_INVALID(net, IPPROTO_UDP))
 176                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 177                                      "nf_ct_udp: short packet ");
 178                return -NF_ACCEPT;
 179        }
 180
 181        /* Truncated/malformed packets */
 182        if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
 183                if (LOG_INVALID(net, IPPROTO_UDP))
 184                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 185                                "nf_ct_udp: truncated/malformed packet ");
 186                return -NF_ACCEPT;
 187        }
 188
 189        /* Packet with no checksum */
 190        if (!hdr->check)
 191                return NF_ACCEPT;
 192
 193        /* Checksum invalid? Ignore.
 194         * We skip checking packets on the outgoing path
 195         * because the checksum is assumed to be correct.
 196         * FIXME: Source route IP option packets --RR */
 197        if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 198            nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
 199                if (LOG_INVALID(net, IPPROTO_UDP))
 200                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 201                                "nf_ct_udp: bad UDP checksum ");
 202                return -NF_ACCEPT;
 203        }
 204
 205        return NF_ACCEPT;
 206}
 207
 208#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 209
 210#include <linux/netfilter/nfnetlink.h>
 211#include <linux/netfilter/nfnetlink_cttimeout.h>
 212
 213static int udp_timeout_nlattr_to_obj(struct nlattr *tb[],
 214                                     struct net *net, void *data)
 215{
 216        unsigned int *timeouts = data;
 217        struct nf_udp_net *un = udp_pernet(net);
 218
 219        /* set default timeouts for UDP. */
 220        timeouts[UDP_CT_UNREPLIED] = un->timeouts[UDP_CT_UNREPLIED];
 221        timeouts[UDP_CT_REPLIED] = un->timeouts[UDP_CT_REPLIED];
 222
 223        if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) {
 224                timeouts[UDP_CT_UNREPLIED] =
 225                        ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ;
 226        }
 227        if (tb[CTA_TIMEOUT_UDP_REPLIED]) {
 228                timeouts[UDP_CT_REPLIED] =
 229                        ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ;
 230        }
 231        return 0;
 232}
 233
 234static int
 235udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
 236{
 237        const unsigned int *timeouts = data;
 238
 239        if (nla_put_be32(skb, CTA_TIMEOUT_UDP_UNREPLIED,
 240                         htonl(timeouts[UDP_CT_UNREPLIED] / HZ)) ||
 241            nla_put_be32(skb, CTA_TIMEOUT_UDP_REPLIED,
 242                         htonl(timeouts[UDP_CT_REPLIED] / HZ)))
 243                goto nla_put_failure;
 244        return 0;
 245
 246nla_put_failure:
 247        return -ENOSPC;
 248}
 249
 250static const struct nla_policy
 251udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = {
 252       [CTA_TIMEOUT_UDP_UNREPLIED]      = { .type = NLA_U32 },
 253       [CTA_TIMEOUT_UDP_REPLIED]        = { .type = NLA_U32 },
 254};
 255#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 256
 257#ifdef CONFIG_SYSCTL
 258static struct ctl_table udp_sysctl_table[] = {
 259        {
 260                .procname       = "nf_conntrack_udp_timeout",
 261                .maxlen         = sizeof(unsigned int),
 262                .mode           = 0644,
 263                .proc_handler   = proc_dointvec_jiffies,
 264        },
 265        {
 266                .procname       = "nf_conntrack_udp_timeout_stream",
 267                .maxlen         = sizeof(unsigned int),
 268                .mode           = 0644,
 269                .proc_handler   = proc_dointvec_jiffies,
 270        },
 271        { }
 272};
 273#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 274static struct ctl_table udp_compat_sysctl_table[] = {
 275        {
 276                .procname       = "ip_conntrack_udp_timeout",
 277                .maxlen         = sizeof(unsigned int),
 278                .mode           = 0644,
 279                .proc_handler   = proc_dointvec_jiffies,
 280        },
 281        {
 282                .procname       = "ip_conntrack_udp_timeout_stream",
 283                .maxlen         = sizeof(unsigned int),
 284                .mode           = 0644,
 285                .proc_handler   = proc_dointvec_jiffies,
 286        },
 287        { }
 288};
 289#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 290#endif /* CONFIG_SYSCTL */
 291
 292static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn,
 293                                    struct nf_udp_net *un)
 294{
 295#ifdef CONFIG_SYSCTL
 296        if (pn->ctl_table)
 297                return 0;
 298        pn->ctl_table = kmemdup(udp_sysctl_table,
 299                                sizeof(udp_sysctl_table),
 300                                GFP_KERNEL);
 301        if (!pn->ctl_table)
 302                return -ENOMEM;
 303        pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
 304        pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED];
 305#endif
 306        return 0;
 307}
 308
 309static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
 310                                           struct nf_udp_net *un)
 311{
 312#ifdef CONFIG_SYSCTL
 313#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 314        pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table,
 315                                       sizeof(udp_compat_sysctl_table),
 316                                       GFP_KERNEL);
 317        if (!pn->ctl_compat_table)
 318                return -ENOMEM;
 319
 320        pn->ctl_compat_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
 321        pn->ctl_compat_table[1].data = &un->timeouts[UDP_CT_REPLIED];
 322#endif
 323#endif
 324        return 0;
 325}
 326
 327static int udp_init_net(struct net *net, u_int16_t proto)
 328{
 329        int ret;
 330        struct nf_udp_net *un = udp_pernet(net);
 331        struct nf_proto_net *pn = &un->pn;
 332
 333        if (!pn->users) {
 334                int i;
 335
 336                for (i = 0; i < UDP_CT_MAX; i++)
 337                        un->timeouts[i] = udp_timeouts[i];
 338        }
 339
 340        if (proto == AF_INET) {
 341                ret = udp_kmemdup_compat_sysctl_table(pn, un);
 342                if (ret < 0)
 343                        return ret;
 344
 345                ret = udp_kmemdup_sysctl_table(pn, un);
 346                if (ret < 0)
 347                        nf_ct_kfree_compat_sysctl_table(pn);
 348        } else
 349                ret = udp_kmemdup_sysctl_table(pn, un);
 350
 351        return ret;
 352}
 353
 354static struct nf_proto_net *udp_get_net_proto(struct net *net)
 355{
 356        return &net->ct.nf_ct_proto.udp.pn;
 357}
 358
 359struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
 360{
 361        .l3proto                = PF_INET,
 362        .l4proto                = IPPROTO_UDP,
 363        .name                   = "udp",
 364        .pkt_to_tuple           = udp_pkt_to_tuple,
 365        .invert_tuple           = udp_invert_tuple,
 366        .print_tuple            = udp_print_tuple,
 367        .packet                 = udp_packet,
 368        .get_timeouts           = udp_get_timeouts,
 369        .new                    = udp_new,
 370        .error                  = udp_error,
 371#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 372        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 373        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 374        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 375        .nla_policy             = nf_ct_port_nla_policy,
 376#endif
 377#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 378        .ctnl_timeout           = {
 379                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 380                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 381                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 382                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 383                .nla_policy     = udp_timeout_nla_policy,
 384        },
 385#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 386        .init_net               = udp_init_net,
 387        .get_net_proto          = udp_get_net_proto,
 388};
 389EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
 390
 391#ifdef CONFIG_NF_CT_PROTO_UDPLITE
 392struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
 393{
 394        .l3proto                = PF_INET,
 395        .l4proto                = IPPROTO_UDPLITE,
 396        .name                   = "udplite",
 397        .pkt_to_tuple           = udp_pkt_to_tuple,
 398        .invert_tuple           = udp_invert_tuple,
 399        .print_tuple            = udp_print_tuple,
 400        .packet                 = udp_packet,
 401        .get_timeouts           = udp_get_timeouts,
 402        .new                    = udp_new,
 403        .error                  = udplite_error,
 404#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 405        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 406        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 407        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 408        .nla_policy             = nf_ct_port_nla_policy,
 409#endif
 410#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 411        .ctnl_timeout           = {
 412                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 413                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 414                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 415                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 416                .nla_policy     = udp_timeout_nla_policy,
 417        },
 418#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 419        .init_net               = udp_init_net,
 420        .get_net_proto          = udp_get_net_proto,
 421};
 422EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite4);
 423#endif
 424
 425struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
 426{
 427        .l3proto                = PF_INET6,
 428        .l4proto                = IPPROTO_UDP,
 429        .name                   = "udp",
 430        .pkt_to_tuple           = udp_pkt_to_tuple,
 431        .invert_tuple           = udp_invert_tuple,
 432        .print_tuple            = udp_print_tuple,
 433        .packet                 = udp_packet,
 434        .get_timeouts           = udp_get_timeouts,
 435        .new                    = udp_new,
 436        .error                  = udp_error,
 437#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 438        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 439        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 440        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 441        .nla_policy             = nf_ct_port_nla_policy,
 442#endif
 443#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 444        .ctnl_timeout           = {
 445                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 446                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 447                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 448                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 449                .nla_policy     = udp_timeout_nla_policy,
 450        },
 451#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 452        .init_net               = udp_init_net,
 453        .get_net_proto          = udp_get_net_proto,
 454};
 455EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);
 456
 457#ifdef CONFIG_NF_CT_PROTO_UDPLITE
 458struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
 459{
 460        .l3proto                = PF_INET6,
 461        .l4proto                = IPPROTO_UDPLITE,
 462        .name                   = "udplite",
 463        .pkt_to_tuple           = udp_pkt_to_tuple,
 464        .invert_tuple           = udp_invert_tuple,
 465        .print_tuple            = udp_print_tuple,
 466        .packet                 = udp_packet,
 467        .get_timeouts           = udp_get_timeouts,
 468        .new                    = udp_new,
 469        .error                  = udplite_error,
 470#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 471        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 472        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 473        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 474        .nla_policy             = nf_ct_port_nla_policy,
 475#endif
 476#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 477        .ctnl_timeout           = {
 478                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 479                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 480                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 481                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 482                .nla_policy     = udp_timeout_nla_policy,
 483        },
 484#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 485        .init_net               = udp_init_net,
 486        .get_net_proto          = udp_get_net_proto,
 487};
 488EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite6);
 489#endif
 490