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