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
 110static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
 111                     unsigned int dataoff, enum ip_conntrack_info *ctinfo,
 112                     u_int8_t pf,
 113                     unsigned int hooknum)
 114{
 115        unsigned int udplen = skb->len - dataoff;
 116        const struct udphdr *hdr;
 117        struct udphdr _hdr;
 118
 119        /* Header is too small? */
 120        hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
 121        if (hdr == NULL) {
 122                if (LOG_INVALID(net, IPPROTO_UDP))
 123                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 124                                      "nf_ct_udp: short packet ");
 125                return -NF_ACCEPT;
 126        }
 127
 128        /* Truncated/malformed packets */
 129        if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
 130                if (LOG_INVALID(net, IPPROTO_UDP))
 131                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 132                                "nf_ct_udp: truncated/malformed packet ");
 133                return -NF_ACCEPT;
 134        }
 135
 136        /* Packet with no checksum */
 137        if (!hdr->check)
 138                return NF_ACCEPT;
 139
 140        /* Checksum invalid? Ignore.
 141         * We skip checking packets on the outgoing path
 142         * because the checksum is assumed to be correct.
 143         * FIXME: Source route IP option packets --RR */
 144        if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 145            nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
 146                if (LOG_INVALID(net, IPPROTO_UDP))
 147                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
 148                                "nf_ct_udp: bad UDP checksum ");
 149                return -NF_ACCEPT;
 150        }
 151
 152        return NF_ACCEPT;
 153}
 154
 155#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 156
 157#include <linux/netfilter/nfnetlink.h>
 158#include <linux/netfilter/nfnetlink_cttimeout.h>
 159
 160static int udp_timeout_nlattr_to_obj(struct nlattr *tb[],
 161                                     struct net *net, void *data)
 162{
 163        unsigned int *timeouts = data;
 164        struct nf_udp_net *un = udp_pernet(net);
 165
 166        /* set default timeouts for UDP. */
 167        timeouts[UDP_CT_UNREPLIED] = un->timeouts[UDP_CT_UNREPLIED];
 168        timeouts[UDP_CT_REPLIED] = un->timeouts[UDP_CT_REPLIED];
 169
 170        if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) {
 171                timeouts[UDP_CT_UNREPLIED] =
 172                        ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ;
 173        }
 174        if (tb[CTA_TIMEOUT_UDP_REPLIED]) {
 175                timeouts[UDP_CT_REPLIED] =
 176                        ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ;
 177        }
 178        return 0;
 179}
 180
 181static int
 182udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
 183{
 184        const unsigned int *timeouts = data;
 185
 186        if (nla_put_be32(skb, CTA_TIMEOUT_UDP_UNREPLIED,
 187                         htonl(timeouts[UDP_CT_UNREPLIED] / HZ)) ||
 188            nla_put_be32(skb, CTA_TIMEOUT_UDP_REPLIED,
 189                         htonl(timeouts[UDP_CT_REPLIED] / HZ)))
 190                goto nla_put_failure;
 191        return 0;
 192
 193nla_put_failure:
 194        return -ENOSPC;
 195}
 196
 197static const struct nla_policy
 198udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = {
 199       [CTA_TIMEOUT_UDP_UNREPLIED]      = { .type = NLA_U32 },
 200       [CTA_TIMEOUT_UDP_REPLIED]        = { .type = NLA_U32 },
 201};
 202#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 203
 204#ifdef CONFIG_SYSCTL
 205static struct ctl_table udp_sysctl_table[] = {
 206        {
 207                .procname       = "nf_conntrack_udp_timeout",
 208                .maxlen         = sizeof(unsigned int),
 209                .mode           = 0644,
 210                .proc_handler   = proc_dointvec_jiffies,
 211        },
 212        {
 213                .procname       = "nf_conntrack_udp_timeout_stream",
 214                .maxlen         = sizeof(unsigned int),
 215                .mode           = 0644,
 216                .proc_handler   = proc_dointvec_jiffies,
 217        },
 218        { }
 219};
 220#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 221static struct ctl_table udp_compat_sysctl_table[] = {
 222        {
 223                .procname       = "ip_conntrack_udp_timeout",
 224                .maxlen         = sizeof(unsigned int),
 225                .mode           = 0644,
 226                .proc_handler   = proc_dointvec_jiffies,
 227        },
 228        {
 229                .procname       = "ip_conntrack_udp_timeout_stream",
 230                .maxlen         = sizeof(unsigned int),
 231                .mode           = 0644,
 232                .proc_handler   = proc_dointvec_jiffies,
 233        },
 234        { }
 235};
 236#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 237#endif /* CONFIG_SYSCTL */
 238
 239static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn,
 240                                    struct nf_udp_net *un)
 241{
 242#ifdef CONFIG_SYSCTL
 243        if (pn->ctl_table)
 244                return 0;
 245        pn->ctl_table = kmemdup(udp_sysctl_table,
 246                                sizeof(udp_sysctl_table),
 247                                GFP_KERNEL);
 248        if (!pn->ctl_table)
 249                return -ENOMEM;
 250        pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
 251        pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED];
 252#endif
 253        return 0;
 254}
 255
 256static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
 257                                           struct nf_udp_net *un)
 258{
 259#ifdef CONFIG_SYSCTL
 260#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 261        pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table,
 262                                       sizeof(udp_compat_sysctl_table),
 263                                       GFP_KERNEL);
 264        if (!pn->ctl_compat_table)
 265                return -ENOMEM;
 266
 267        pn->ctl_compat_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
 268        pn->ctl_compat_table[1].data = &un->timeouts[UDP_CT_REPLIED];
 269#endif
 270#endif
 271        return 0;
 272}
 273
 274static int udp_init_net(struct net *net, u_int16_t proto)
 275{
 276        int ret;
 277        struct nf_udp_net *un = udp_pernet(net);
 278        struct nf_proto_net *pn = &un->pn;
 279
 280        if (!pn->users) {
 281                int i;
 282
 283                for (i = 0; i < UDP_CT_MAX; i++)
 284                        un->timeouts[i] = udp_timeouts[i];
 285        }
 286
 287        if (proto == AF_INET) {
 288                ret = udp_kmemdup_compat_sysctl_table(pn, un);
 289                if (ret < 0)
 290                        return ret;
 291
 292                ret = udp_kmemdup_sysctl_table(pn, un);
 293                if (ret < 0)
 294                        nf_ct_kfree_compat_sysctl_table(pn);
 295        } else
 296                ret = udp_kmemdup_sysctl_table(pn, un);
 297
 298        return ret;
 299}
 300
 301static struct nf_proto_net *udp_get_net_proto(struct net *net)
 302{
 303        return &net->ct.nf_ct_proto.udp.pn;
 304}
 305
 306struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
 307{
 308        .l3proto                = PF_INET,
 309        .l4proto                = IPPROTO_UDP,
 310        .name                   = "udp",
 311        .pkt_to_tuple           = udp_pkt_to_tuple,
 312        .invert_tuple           = udp_invert_tuple,
 313        .print_tuple            = udp_print_tuple,
 314        .packet                 = udp_packet,
 315        .get_timeouts           = udp_get_timeouts,
 316        .new                    = udp_new,
 317        .error                  = udp_error,
 318#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 319        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 320        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 321        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 322        .nla_policy             = nf_ct_port_nla_policy,
 323#endif
 324#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 325        .ctnl_timeout           = {
 326                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 327                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 328                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 329                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 330                .nla_policy     = udp_timeout_nla_policy,
 331        },
 332#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 333        .init_net               = udp_init_net,
 334        .get_net_proto          = udp_get_net_proto,
 335};
 336EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
 337
 338struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
 339{
 340        .l3proto                = PF_INET6,
 341        .l4proto                = IPPROTO_UDP,
 342        .name                   = "udp",
 343        .pkt_to_tuple           = udp_pkt_to_tuple,
 344        .invert_tuple           = udp_invert_tuple,
 345        .print_tuple            = udp_print_tuple,
 346        .packet                 = udp_packet,
 347        .get_timeouts           = udp_get_timeouts,
 348        .new                    = udp_new,
 349        .error                  = udp_error,
 350#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 351        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 352        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 353        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 354        .nla_policy             = nf_ct_port_nla_policy,
 355#endif
 356#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 357        .ctnl_timeout           = {
 358                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 359                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 360                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 361                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 362                .nla_policy     = udp_timeout_nla_policy,
 363        },
 364#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 365        .init_net               = udp_init_net,
 366        .get_net_proto          = udp_get_net_proto,
 367};
 368EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);
 369
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.