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 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   8
   9#include <linux/types.h>
  10#include <linux/timer.h>
  11#include <linux/module.h>
  12#include <linux/udp.h>
  13#include <linux/seq_file.h>
  14#include <linux/skbuff.h>
  15#include <linux/ipv6.h>
  16#include <net/ip6_checksum.h>
  17#include <net/checksum.h>
  18
  19#include <linux/netfilter.h>
  20#include <linux/netfilter_ipv4.h>
  21#include <linux/netfilter_ipv6.h>
  22#include <net/netfilter/nf_conntrack_l4proto.h>
  23#include <net/netfilter/nf_conntrack_ecache.h>
  24#include <net/netfilter/nf_log.h>
  25#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
  26#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
  27
  28static unsigned int udp_timeouts[UDP_CT_MAX] = {
  29        [UDP_CT_UNREPLIED]      = 30*HZ,
  30        [UDP_CT_REPLIED]        = 180*HZ,
  31};
  32
  33static inline struct nf_udp_net *udp_pernet(struct net *net)
  34{
  35        return &net->ct.nf_ct_proto.udp;
  36}
  37
  38static bool udp_pkt_to_tuple(const struct sk_buff *skb,
  39                             unsigned int dataoff,
  40                             struct nf_conntrack_tuple *tuple)
  41{
  42        const struct udphdr *hp;
  43        struct udphdr _hdr;
  44
  45        /* Actually only need first 8 bytes. */
  46        hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
  47        if (hp == NULL)
  48                return false;
  49
  50        tuple->src.u.udp.port = hp->source;
  51        tuple->dst.u.udp.port = hp->dest;
  52
  53        return true;
  54}
  55
  56static bool udp_invert_tuple(struct nf_conntrack_tuple *tuple,
  57                             const struct nf_conntrack_tuple *orig)
  58{
  59        tuple->src.u.udp.port = orig->dst.u.udp.port;
  60        tuple->dst.u.udp.port = orig->src.u.udp.port;
  61        return true;
  62}
  63
  64/* Print out the per-protocol part of the tuple. */
  65static int udp_print_tuple(struct seq_file *s,
  66                           const struct nf_conntrack_tuple *tuple)
  67{
  68        return seq_printf(s, "sport=%hu dport=%hu ",
  69                          ntohs(tuple->src.u.udp.port),
  70                          ntohs(tuple->dst.u.udp.port));
  71}
  72
  73static unsigned int *udp_get_timeouts(struct net *net)
  74{
  75        return udp_pernet(net)->timeouts;
  76}
  77
  78/* Returns verdict for packet, and may modify conntracktype */
  79static int udp_packet(struct nf_conn *ct,
  80                      const struct sk_buff *skb,
  81                      unsigned int dataoff,
  82                      enum ip_conntrack_info ctinfo,
  83                      u_int8_t pf,
  84                      unsigned int hooknum,
  85                      unsigned int *timeouts)
  86{
  87        /* If we've seen traffic both ways, this is some kind of UDP
  88           stream.  Extend timeout. */
  89        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
  90                nf_ct_refresh_acct(ct, ctinfo, skb,
  91                                   timeouts[UDP_CT_REPLIED]);
  92                /* Also, more likely to be important, and not a probe */
  93                if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
  94                        nf_conntrack_event_cache(IPCT_ASSURED, ct);
  95        } else {
  96                nf_ct_refresh_acct(ct, ctinfo, skb,
  97                                   timeouts[UDP_CT_UNREPLIED]);
  98        }
  99        return NF_ACCEPT;
 100}
 101
 102/* Called when a new connection for this protocol found. */
 103static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb,
 104                    unsigned int dataoff, unsigned int *timeouts)
 105{
 106        return true;
 107}
 108
 109static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
 110                     unsigned int dataoff, enum ip_conntrack_info *ctinfo,
 111                     u_int8_t pf,
 112                     unsigned int hooknum)
 113{
 114        unsigned int udplen = skb->len - dataoff;
 115        const struct udphdr *hdr;
 116        struct udphdr _hdr;
 117
 118        /* Header is too small? */
 119        hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
 120        if (hdr == NULL) {
 121                if (LOG_INVALID(net, IPPROTO_UDP))
 122                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 123                                      "nf_ct_udp: short packet ");
 124                return -NF_ACCEPT;
 125        }
 126
 127        /* Truncated/malformed packets */
 128        if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
 129                if (LOG_INVALID(net, IPPROTO_UDP))
 130                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 131                                "nf_ct_udp: truncated/malformed packet ");
 132                return -NF_ACCEPT;
 133        }
 134
 135        /* Packet with no checksum */
 136        if (!hdr->check)
 137                return NF_ACCEPT;
 138
 139        /* Checksum invalid? Ignore.
 140         * We skip checking packets on the outgoing path
 141         * because the checksum is assumed to be correct.
 142         * FIXME: Source route IP option packets --RR */
 143        if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 144            nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
 145                if (LOG_INVALID(net, IPPROTO_UDP))
 146                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 147                                "nf_ct_udp: bad UDP checksum ");
 148                return -NF_ACCEPT;
 149        }
 150
 151        return NF_ACCEPT;
 152}
 153
 154#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 155
 156#include <linux/netfilter/nfnetlink.h>
 157#include <linux/netfilter/nfnetlink_cttimeout.h>
 158
 159static int udp_timeout_nlattr_to_obj(struct nlattr *tb[],
 160                                     struct net *net, void *data)
 161{
 162        unsigned int *timeouts = data;
 163        struct nf_udp_net *un = udp_pernet(net);
 164
 165        /* set default timeouts for UDP. */
 166        timeouts[UDP_CT_UNREPLIED] = un->timeouts[UDP_CT_UNREPLIED];
 167        timeouts[UDP_CT_REPLIED] = un->timeouts[UDP_CT_REPLIED];
 168
 169        if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) {
 170                timeouts[UDP_CT_UNREPLIED] =
 171                        ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ;
 172        }
 173        if (tb[CTA_TIMEOUT_UDP_REPLIED]) {
 174                timeouts[UDP_CT_REPLIED] =
 175                        ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ;
 176        }
 177        return 0;
 178}
 179
 180static int
 181udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
 182{
 183        const unsigned int *timeouts = data;
 184
 185        if (nla_put_be32(skb, CTA_TIMEOUT_UDP_UNREPLIED,
 186                         htonl(timeouts[UDP_CT_UNREPLIED] / HZ)) ||
 187            nla_put_be32(skb, CTA_TIMEOUT_UDP_REPLIED,
 188                         htonl(timeouts[UDP_CT_REPLIED] / HZ)))
 189                goto nla_put_failure;
 190        return 0;
 191
 192nla_put_failure:
 193        return -ENOSPC;
 194}
 195
 196static const struct nla_policy
 197udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = {
 198       [CTA_TIMEOUT_UDP_UNREPLIED]      = { .type = NLA_U32 },
 199       [CTA_TIMEOUT_UDP_REPLIED]        = { .type = NLA_U32 },
 200};
 201#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 202
 203#ifdef CONFIG_SYSCTL
 204static struct ctl_table udp_sysctl_table[] = {
 205        {
 206                .procname       = "nf_conntrack_udp_timeout",
 207                .maxlen         = sizeof(unsigned int),
 208                .mode           = 0644,
 209                .proc_handler   = proc_dointvec_jiffies,
 210        },
 211        {
 212                .procname       = "nf_conntrack_udp_timeout_stream",
 213                .maxlen         = sizeof(unsigned int),
 214                .mode           = 0644,
 215                .proc_handler   = proc_dointvec_jiffies,
 216        },
 217        { }
 218};
 219#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 220static struct ctl_table udp_compat_sysctl_table[] = {
 221        {
 222                .procname       = "ip_conntrack_udp_timeout",
 223                .maxlen         = sizeof(unsigned int),
 224                .mode           = 0644,
 225                .proc_handler   = proc_dointvec_jiffies,
 226        },
 227        {
 228                .procname       = "ip_conntrack_udp_timeout_stream",
 229                .maxlen         = sizeof(unsigned int),
 230                .mode           = 0644,
 231                .proc_handler   = proc_dointvec_jiffies,
 232        },
 233        { }
 234};
 235#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 236#endif /* CONFIG_SYSCTL */
 237
 238static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn,
 239                                    struct nf_udp_net *un)
 240{
 241#ifdef CONFIG_SYSCTL
 242        if (pn->ctl_table)
 243                return 0;
 244        pn->ctl_table = kmemdup(udp_sysctl_table,
 245                                sizeof(udp_sysctl_table),
 246                                GFP_KERNEL);
 247        if (!pn->ctl_table)
 248                return -ENOMEM;
 249        pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
 250        pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED];
 251#endif
 252        return 0;
 253}
 254
 255static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn,
 256                                           struct nf_udp_net *un)
 257{
 258#ifdef CONFIG_SYSCTL
 259#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 260        pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table,
 261                                       sizeof(udp_compat_sysctl_table),
 262                                       GFP_KERNEL);
 263        if (!pn->ctl_compat_table)
 264                return -ENOMEM;
 265
 266        pn->ctl_compat_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
 267        pn->ctl_compat_table[1].data = &un->timeouts[UDP_CT_REPLIED];
 268#endif
 269#endif
 270        return 0;
 271}
 272
 273static int udp_init_net(struct net *net, u_int16_t proto)
 274{
 275        int ret;
 276        struct nf_udp_net *un = udp_pernet(net);
 277        struct nf_proto_net *pn = &un->pn;
 278
 279        if (!pn->users) {
 280                int i;
 281
 282                for (i = 0; i < UDP_CT_MAX; i++)
 283                        un->timeouts[i] = udp_timeouts[i];
 284        }
 285
 286        if (proto == AF_INET) {
 287                ret = udp_kmemdup_compat_sysctl_table(pn, un);
 288                if (ret < 0)
 289                        return ret;
 290
 291                ret = udp_kmemdup_sysctl_table(pn, un);
 292                if (ret < 0)
 293                        nf_ct_kfree_compat_sysctl_table(pn);
 294        } else
 295                ret = udp_kmemdup_sysctl_table(pn, un);
 296
 297        return ret;
 298}
 299
 300static struct nf_proto_net *udp_get_net_proto(struct net *net)
 301{
 302        return &net->ct.nf_ct_proto.udp.pn;
 303}
 304
 305struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
 306{
 307        .l3proto                = PF_INET,
 308        .l4proto                = IPPROTO_UDP,
 309        .name                   = "udp",
 310        .pkt_to_tuple           = udp_pkt_to_tuple,
 311        .invert_tuple           = udp_invert_tuple,
 312        .print_tuple            = udp_print_tuple,
 313        .packet                 = udp_packet,
 314        .get_timeouts           = udp_get_timeouts,
 315        .new                    = udp_new,
 316        .error                  = udp_error,
 317#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 318        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 319        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 320        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 321        .nla_policy             = nf_ct_port_nla_policy,
 322#endif
 323#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 324        .ctnl_timeout           = {
 325                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 326                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 327                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 328                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 329                .nla_policy     = udp_timeout_nla_policy,
 330        },
 331#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 332        .init_net               = udp_init_net,
 333        .get_net_proto          = udp_get_net_proto,
 334};
 335EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
 336
 337struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
 338{
 339        .l3proto                = PF_INET6,
 340        .l4proto                = IPPROTO_UDP,
 341        .name                   = "udp",
 342        .pkt_to_tuple           = udp_pkt_to_tuple,
 343        .invert_tuple           = udp_invert_tuple,
 344        .print_tuple            = udp_print_tuple,
 345        .packet                 = udp_packet,
 346        .get_timeouts           = udp_get_timeouts,
 347        .new                    = udp_new,
 348        .error                  = udp_error,
 349#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
 350        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 351        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 352        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 353        .nla_policy             = nf_ct_port_nla_policy,
 354#endif
 355#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
 356        .ctnl_timeout           = {
 357                .nlattr_to_obj  = udp_timeout_nlattr_to_obj,
 358                .obj_to_nlattr  = udp_timeout_obj_to_nlattr,
 359                .nlattr_max     = CTA_TIMEOUT_UDP_MAX,
 360                .obj_size       = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
 361                .nla_policy     = udp_timeout_nla_policy,
 362        },
 363#endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 364        .init_net               = udp_init_net,
 365        .get_net_proto          = udp_get_net_proto,
 366};
 367EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);
 368
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.