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 nf_ct_udp_timeout __read_mostly = 30*HZ;
  29static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ;
  30
  31static bool udp_pkt_to_tuple(const struct sk_buff *skb,
  32                             unsigned int dataoff,
  33                             struct nf_conntrack_tuple *tuple)
  34{
  35        const struct udphdr *hp;
  36        struct udphdr _hdr;
  37
  38        /* Actually only need first 8 bytes. */
  39        hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
  40        if (hp == NULL)
  41                return false;
  42
  43        tuple->src.u.udp.port = hp->source;
  44        tuple->dst.u.udp.port = hp->dest;
  45
  46        return true;
  47}
  48
  49static bool udp_invert_tuple(struct nf_conntrack_tuple *tuple,
  50                             const struct nf_conntrack_tuple *orig)
  51{
  52        tuple->src.u.udp.port = orig->dst.u.udp.port;
  53        tuple->dst.u.udp.port = orig->src.u.udp.port;
  54        return true;
  55}
  56
  57/* Print out the per-protocol part of the tuple. */
  58static int udp_print_tuple(struct seq_file *s,
  59                           const struct nf_conntrack_tuple *tuple)
  60{
  61        return seq_printf(s, "sport=%hu dport=%hu ",
  62                          ntohs(tuple->src.u.udp.port),
  63                          ntohs(tuple->dst.u.udp.port));
  64}
  65
  66/* Returns verdict for packet, and may modify conntracktype */
  67static int udp_packet(struct nf_conn *ct,
  68                      const struct sk_buff *skb,
  69                      unsigned int dataoff,
  70                      enum ip_conntrack_info ctinfo,
  71                      u_int8_t pf,
  72                      unsigned int hooknum)
  73{
  74        /* If we've seen traffic both ways, this is some kind of UDP
  75           stream.  Extend timeout. */
  76        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
  77                nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream);
  78                /* Also, more likely to be important, and not a probe */
  79                if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
  80                        nf_conntrack_event_cache(IPCT_STATUS, ct);
  81        } else
  82                nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout);
  83
  84        return NF_ACCEPT;
  85}
  86
  87/* Called when a new connection for this protocol found. */
  88static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb,
  89                    unsigned int dataoff)
  90{
  91        return true;
  92}
  93
  94static int udp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
  95                     enum ip_conntrack_info *ctinfo,
  96                     u_int8_t pf,
  97                     unsigned int hooknum)
  98{
  99        unsigned int udplen = skb->len - dataoff;
 100        const struct udphdr *hdr;
 101        struct udphdr _hdr;
 102
 103        /* Header is too small? */
 104        hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
 105        if (hdr == NULL) {
 106                if (LOG_INVALID(net, IPPROTO_UDP))
 107                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 108                                      "nf_ct_udp: short packet ");
 109                return -NF_ACCEPT;
 110        }
 111
 112        /* Truncated/malformed packets */
 113        if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
 114                if (LOG_INVALID(net, IPPROTO_UDP))
 115                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 116                                "nf_ct_udp: truncated/malformed packet ");
 117                return -NF_ACCEPT;
 118        }
 119
 120        /* Packet with no checksum */
 121        if (!hdr->check)
 122                return NF_ACCEPT;
 123
 124        /* Checksum invalid? Ignore.
 125         * We skip checking packets on the outgoing path
 126         * because the checksum is assumed to be correct.
 127         * FIXME: Source route IP option packets --RR */
 128        if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 129            nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
 130                if (LOG_INVALID(net, IPPROTO_UDP))
 131                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 132                                "nf_ct_udp: bad UDP checksum ");
 133                return -NF_ACCEPT;
 134        }
 135
 136        return NF_ACCEPT;
 137}
 138
 139#ifdef CONFIG_SYSCTL
 140static unsigned int udp_sysctl_table_users;
 141static struct ctl_table_header *udp_sysctl_header;
 142static struct ctl_table udp_sysctl_table[] = {
 143        {
 144                .procname       = "nf_conntrack_udp_timeout",
 145                .data           = &nf_ct_udp_timeout,
 146                .maxlen         = sizeof(unsigned int),
 147                .mode           = 0644,
 148                .proc_handler   = proc_dointvec_jiffies,
 149        },
 150        {
 151                .procname       = "nf_conntrack_udp_timeout_stream",
 152                .data           = &nf_ct_udp_timeout_stream,
 153                .maxlen         = sizeof(unsigned int),
 154                .mode           = 0644,
 155                .proc_handler   = proc_dointvec_jiffies,
 156        },
 157        {
 158                .ctl_name       = 0
 159        }
 160};
 161#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 162static struct ctl_table udp_compat_sysctl_table[] = {
 163        {
 164                .procname       = "ip_conntrack_udp_timeout",
 165                .data           = &nf_ct_udp_timeout,
 166                .maxlen         = sizeof(unsigned int),
 167                .mode           = 0644,
 168                .proc_handler   = proc_dointvec_jiffies,
 169        },
 170        {
 171                .procname       = "ip_conntrack_udp_timeout_stream",
 172                .data           = &nf_ct_udp_timeout_stream,
 173                .maxlen         = sizeof(unsigned int),
 174                .mode           = 0644,
 175                .proc_handler   = proc_dointvec_jiffies,
 176        },
 177        {
 178                .ctl_name       = 0
 179        }
 180};
 181#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 182#endif /* CONFIG_SYSCTL */
 183
 184struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
 185{
 186        .l3proto                = PF_INET,
 187        .l4proto                = IPPROTO_UDP,
 188        .name                   = "udp",
 189        .pkt_to_tuple           = udp_pkt_to_tuple,
 190        .invert_tuple           = udp_invert_tuple,
 191        .print_tuple            = udp_print_tuple,
 192        .packet                 = udp_packet,
 193        .new                    = udp_new,
 194        .error                  = udp_error,
 195#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
 196        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 197        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 198        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 199        .nla_policy             = nf_ct_port_nla_policy,
 200#endif
 201#ifdef CONFIG_SYSCTL
 202        .ctl_table_users        = &udp_sysctl_table_users,
 203        .ctl_table_header       = &udp_sysctl_header,
 204        .ctl_table              = udp_sysctl_table,
 205#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
 206        .ctl_compat_table       = udp_compat_sysctl_table,
 207#endif
 208#endif
 209};
 210EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
 211
 212struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
 213{
 214        .l3proto                = PF_INET6,
 215        .l4proto                = IPPROTO_UDP,
 216        .name                   = "udp",
 217        .pkt_to_tuple           = udp_pkt_to_tuple,
 218        .invert_tuple           = udp_invert_tuple,
 219        .print_tuple            = udp_print_tuple,
 220        .packet                 = udp_packet,
 221        .new                    = udp_new,
 222        .error                  = udp_error,
 223#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
 224        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 225        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 226        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 227        .nla_policy             = nf_ct_port_nla_policy,
 228#endif
 229#ifdef CONFIG_SYSCTL
 230        .ctl_table_users        = &udp_sysctl_table_users,
 231        .ctl_table_header       = &udp_sysctl_header,
 232        .ctl_table              = udp_sysctl_table,
 233#endif
 234};
 235EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);
 236