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 net *net,
  42                             struct nf_conntrack_tuple *tuple)
  43{
  44        const struct udphdr *hp;
  45        struct udphdr _hdr;
  46
  47        /* Actually only need first 4 bytes to get ports. */
  48        hp = skb_header_pointer(skb, dataoff, 4, &_hdr);
  49        if (hp == NULL)
  50                return false;
  51
  52        tuple->src.u.udp.port = hp->source;
  53        tuple->dst.u.udp.port = hp->dest;
  54
  55        return true;
  56}
  57
  58static bool udp_invert_tuple(struct nf_conntrack_tuple *tuple,
  59                             const struct nf_conntrack_tuple *orig)
  60{
  61        tuple->src.u.udp.port = orig->dst.u.udp.port;
  62        tuple->dst.u.udp.port = orig->src.u.udp.port;
  63        return true;
  64}
  65
  66/* Print out the per-protocol part of the tuple. */
  67static void udp_print_tuple(struct seq_file *s,
  68                            const struct nf_conntrack_tuple *tuple)
  69{
  70        seq_printf(s, "sport=%hu dport=%hu ",
  71                   ntohs(tuple->src.u.udp.port),
  72                   ntohs(tuple->dst.u.udp.port));
  73}
  74
  75static unsigned int *udp_get_timeouts(struct net *net)
  76{
  77        return udp_pernet(net)->timeouts;
  78}
  79
  80/* Returns verdict for packet, and may modify conntracktype */
  81static int udp_packet(struct nf_conn *ct,
  82                      const struct sk_buff *skb,
  83                      unsigned int dataoff,
  84                      enum ip_conntrack_info ctinfo,
  85                      u_int8_t pf,
  86                      unsigned int hooknum,
  87                      unsigned int *timeouts)
  88{
  89        /* If we've seen traffic both ways, this is some kind of UDP
  90           stream.  Extend timeout. */
  91        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
  92                nf_ct_refresh_acct(ct, ctinfo, skb,
  93                                   timeouts[UDP_CT_REPLIED]);
  94                /* Also, more likely to be important, and not a probe */
  95                if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
  96                        nf_conntrack_event_cache(IPCT_ASSURED, ct);
  97        } else {
  98                nf_ct_refresh_acct(ct, ctinfo, skb,
  99                                   timeouts[UDP_CT_UNREPLIED]);
 100        }
 101        return NF_ACCEPT;
 102}
 103
 104/* Called when a new connection for this protocol found. */
 105static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb,
 106                    unsigned int dataoff, unsigned int *timeouts)
 107{
 108        return true;
 109}
 110
 111#ifdef CONFIG_NF_CT_PROTO_UDPLITE
 112static int udplite_error(struct net *net, struct nf_conn *tmpl,
 113                         struct sk_buff *skb,
 114                         unsigned int dataoff,
 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,
 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#endif /* CONFIG_SYSCTL */
 274
 275static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn,
 276                                    struct nf_udp_net *un)
 277{
 278#ifdef CONFIG_SYSCTL
 279        if (pn->ctl_table)
 280                return 0;
 281        pn->ctl_table = kmemdup(udp_sysctl_table,
 282                                sizeof(udp_sysctl_table),
 283                                GFP_KERNEL);
 284        if (!pn->ctl_table)
 285                return -ENOMEM;
 286        pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
 287        pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED];
 288#endif
 289        return 0;
 290}
 291
 292static int udp_init_net(struct net *net, u_int16_t proto)
 293{
 294        struct nf_udp_net *un = udp_pernet(net);
 295        struct nf_proto_net *pn = &un->pn;
 296
 297        if (!pn->users) {
 298                int i;
 299
 300                for (i = 0; i < UDP_CT_MAX; i++)
 301                        un->timeouts[i] = udp_timeouts[i];
 302        }
 303
 304        return udp_kmemdup_sysctl_table(pn, un);
 305}
 306
 307static struct nf_proto_net *udp_get_net_proto(struct net *net)
 308{
 309        return &net->ct.nf_ct_proto.udp.pn;
 310}
 311
 312struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
 313{
 314        .l3proto                = PF_INET,
 315        .l4proto                = IPPROTO_UDP,
 316        .name                   = "udp",
 317        .allow_clash            = true,
 318        .pkt_to_tuple           = udp_pkt_to_tuple,
 319        .invert_tuple           = udp_invert_tuple,
 320        .print_tuple            = udp_print_tuple,
 321        .packet                 = udp_packet,
 322        .get_timeouts           = udp_get_timeouts,
 323        .new                    = udp_new,
 324        .error                  = udp_error,
 325#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 326        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 327        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 328        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 329        .nla_policy             = nf_ct_port_nla_policy,
 330#endif
 331#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 332        .ctnl_timeout           = {
 333                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 334                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 335                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 336                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 337                .nla_policy     = udp_timeout_nla_policy,
 338        },
 339#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 340        .init_net               = udp_init_net,
 341        .get_net_proto          = udp_get_net_proto,
 342};
 343EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
 344
 345#ifdef CONFIG_NF_CT_PROTO_UDPLITE
 346struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
 347{
 348        .l3proto                = PF_INET,
 349        .l4proto                = IPPROTO_UDPLITE,
 350        .name                   = "udplite",
 351        .allow_clash            = true,
 352        .pkt_to_tuple           = udp_pkt_to_tuple,
 353        .invert_tuple           = udp_invert_tuple,
 354        .print_tuple            = udp_print_tuple,
 355        .packet                 = udp_packet,
 356        .get_timeouts           = udp_get_timeouts,
 357        .new                    = udp_new,
 358        .error                  = udplite_error,
 359#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 360        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 361        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 362        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 363        .nla_policy             = nf_ct_port_nla_policy,
 364#endif
 365#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 366        .ctnl_timeout           = {
 367                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 368                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 369                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 370                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 371                .nla_policy     = udp_timeout_nla_policy,
 372        },
 373#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 374        .init_net               = udp_init_net,
 375        .get_net_proto          = udp_get_net_proto,
 376};
 377EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite4);
 378#endif
 379
 380struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
 381{
 382        .l3proto                = PF_INET6,
 383        .l4proto                = IPPROTO_UDP,
 384        .name                   = "udp",
 385        .allow_clash            = true,
 386        .pkt_to_tuple           = udp_pkt_to_tuple,
 387        .invert_tuple           = udp_invert_tuple,
 388        .print_tuple            = udp_print_tuple,
 389        .packet                 = udp_packet,
 390        .get_timeouts           = udp_get_timeouts,
 391        .new                    = udp_new,
 392        .error                  = udp_error,
 393#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 394        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 395        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 396        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 397        .nla_policy             = nf_ct_port_nla_policy,
 398#endif
 399#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 400        .ctnl_timeout           = {
 401                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 402                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 403                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 404                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 405                .nla_policy     = udp_timeout_nla_policy,
 406        },
 407#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 408        .init_net               = udp_init_net,
 409        .get_net_proto          = udp_get_net_proto,
 410};
 411EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);
 412
 413#ifdef CONFIG_NF_CT_PROTO_UDPLITE
 414struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
 415{
 416        .l3proto                = PF_INET6,
 417        .l4proto                = IPPROTO_UDPLITE,
 418        .name                   = "udplite",
 419        .allow_clash            = true,
 420        .pkt_to_tuple           = udp_pkt_to_tuple,
 421        .invert_tuple           = udp_invert_tuple,
 422        .print_tuple            = udp_print_tuple,
 423        .packet                 = udp_packet,
 424        .get_timeouts           = udp_get_timeouts,
 425        .new                    = udp_new,
 426        .error                  = udplite_error,
 427#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 428        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 429        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 430        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 431        .nla_policy             = nf_ct_port_nla_policy,
 432#endif
 433#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 434        .ctnl_timeout           = {
 435                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 436                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 437                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 438                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 439                .nla_policy     = udp_timeout_nla_policy,
 440        },
 441#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 442        .init_net               = udp_init_net,
 443        .get_net_proto          = udp_get_net_proto,
 444};
 445EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udplite6);
 446#endif
 447