linux/net/netfilter/nf_conntrack_proto_udplite.c
<<
>>
Prefs
   1/* (C) 1999-2001 Paul `Rusty' Russell
   2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
   3 * (C) 2007 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
  27static unsigned int nf_ct_udplite_timeout __read_mostly = 30*HZ;
  28static unsigned int nf_ct_udplite_timeout_stream __read_mostly = 180*HZ;
  29
  30static bool udplite_pkt_to_tuple(const struct sk_buff *skb,
  31                                 unsigned int dataoff,
  32                                 struct nf_conntrack_tuple *tuple)
  33{
  34        const struct udphdr *hp;
  35        struct udphdr _hdr;
  36
  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        return true;
  44}
  45
  46static bool udplite_invert_tuple(struct nf_conntrack_tuple *tuple,
  47                                 const struct nf_conntrack_tuple *orig)
  48{
  49        tuple->src.u.udp.port = orig->dst.u.udp.port;
  50        tuple->dst.u.udp.port = orig->src.u.udp.port;
  51        return true;
  52}
  53
  54/* Print out the per-protocol part of the tuple. */
  55static int udplite_print_tuple(struct seq_file *s,
  56                               const struct nf_conntrack_tuple *tuple)
  57{
  58        return seq_printf(s, "sport=%hu dport=%hu ",
  59                          ntohs(tuple->src.u.udp.port),
  60                          ntohs(tuple->dst.u.udp.port));
  61}
  62
  63/* Returns verdict for packet, and may modify conntracktype */
  64static int udplite_packet(struct nf_conn *ct,
  65                          const struct sk_buff *skb,
  66                          unsigned int dataoff,
  67                          enum ip_conntrack_info ctinfo,
  68                          u_int8_t pf,
  69                          unsigned int hooknum)
  70{
  71        /* If we've seen traffic both ways, this is some kind of UDP
  72           stream.  Extend timeout. */
  73        if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
  74                nf_ct_refresh_acct(ct, ctinfo, skb,
  75                                   nf_ct_udplite_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_ASSURED, ct);
  79        } else
  80                nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udplite_timeout);
  81
  82        return NF_ACCEPT;
  83}
  84
  85/* Called when a new connection for this protocol found. */
  86static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb,
  87                        unsigned int dataoff)
  88{
  89        return true;
  90}
  91
  92static int udplite_error(struct net *net, struct nf_conn *tmpl,
  93                         struct sk_buff *skb,
  94                         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        unsigned int cscov;
 103
 104        /* Header is too small? */
 105        hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
 106        if (hdr == NULL) {
 107                if (LOG_INVALID(net, IPPROTO_UDPLITE))
 108                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 109                                      "nf_ct_udplite: short packet ");
 110                return -NF_ACCEPT;
 111        }
 112
 113        cscov = ntohs(hdr->len);
 114        if (cscov == 0)
 115                cscov = udplen;
 116        else if (cscov < sizeof(*hdr) || cscov > udplen) {
 117                if (LOG_INVALID(net, IPPROTO_UDPLITE))
 118                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 119                                "nf_ct_udplite: invalid checksum coverage ");
 120                return -NF_ACCEPT;
 121        }
 122
 123        /* UDPLITE mandates checksums */
 124        if (!hdr->check) {
 125                if (LOG_INVALID(net, IPPROTO_UDPLITE))
 126                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 127                                      "nf_ct_udplite: checksum missing ");
 128                return -NF_ACCEPT;
 129        }
 130
 131        /* Checksum invalid? Ignore. */
 132        if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
 133            nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP,
 134                                pf)) {
 135                if (LOG_INVALID(net, IPPROTO_UDPLITE))
 136                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
 137                                      "nf_ct_udplite: bad UDPLite checksum ");
 138                return -NF_ACCEPT;
 139        }
 140
 141        return NF_ACCEPT;
 142}
 143
 144#ifdef CONFIG_SYSCTL
 145static unsigned int udplite_sysctl_table_users;
 146static struct ctl_table_header *udplite_sysctl_header;
 147static struct ctl_table udplite_sysctl_table[] = {
 148        {
 149                .procname       = "nf_conntrack_udplite_timeout",
 150                .data           = &nf_ct_udplite_timeout,
 151                .maxlen         = sizeof(unsigned int),
 152                .mode           = 0644,
 153                .proc_handler   = proc_dointvec_jiffies,
 154        },
 155        {
 156                .procname       = "nf_conntrack_udplite_timeout_stream",
 157                .data           = &nf_ct_udplite_timeout_stream,
 158                .maxlen         = sizeof(unsigned int),
 159                .mode           = 0644,
 160                .proc_handler   = proc_dointvec_jiffies,
 161        },
 162        { }
 163};
 164#endif /* CONFIG_SYSCTL */
 165
 166static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
 167{
 168        .l3proto                = PF_INET,
 169        .l4proto                = IPPROTO_UDPLITE,
 170        .name                   = "udplite",
 171        .pkt_to_tuple           = udplite_pkt_to_tuple,
 172        .invert_tuple           = udplite_invert_tuple,
 173        .print_tuple            = udplite_print_tuple,
 174        .packet                 = udplite_packet,
 175        .new                    = udplite_new,
 176        .error                  = udplite_error,
 177#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
 178        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 179        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 180        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 181        .nla_policy             = nf_ct_port_nla_policy,
 182#endif
 183#ifdef CONFIG_SYSCTL
 184        .ctl_table_users        = &udplite_sysctl_table_users,
 185        .ctl_table_header       = &udplite_sysctl_header,
 186        .ctl_table              = udplite_sysctl_table,
 187#endif
 188};
 189
 190static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
 191{
 192        .l3proto                = PF_INET6,
 193        .l4proto                = IPPROTO_UDPLITE,
 194        .name                   = "udplite",
 195        .pkt_to_tuple           = udplite_pkt_to_tuple,
 196        .invert_tuple           = udplite_invert_tuple,
 197        .print_tuple            = udplite_print_tuple,
 198        .packet                 = udplite_packet,
 199        .new                    = udplite_new,
 200        .error                  = udplite_error,
 201#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
 202        .tuple_to_nlattr        = nf_ct_port_tuple_to_nlattr,
 203        .nlattr_tuple_size      = nf_ct_port_nlattr_tuple_size,
 204        .nlattr_to_tuple        = nf_ct_port_nlattr_to_tuple,
 205        .nla_policy             = nf_ct_port_nla_policy,
 206#endif
 207#ifdef CONFIG_SYSCTL
 208        .ctl_table_users        = &udplite_sysctl_table_users,
 209        .ctl_table_header       = &udplite_sysctl_header,
 210        .ctl_table              = udplite_sysctl_table,
 211#endif
 212};
 213
 214static int __init nf_conntrack_proto_udplite_init(void)
 215{
 216        int err;
 217
 218        err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite4);
 219        if (err < 0)
 220                goto err1;
 221        err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite6);
 222        if (err < 0)
 223                goto err2;
 224        return 0;
 225err2:
 226        nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
 227err1:
 228        return err;
 229}
 230
 231static void __exit nf_conntrack_proto_udplite_exit(void)
 232{
 233        nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite6);
 234        nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
 235}
 236
 237module_init(nf_conntrack_proto_udplite_init);
 238module_exit(nf_conntrack_proto_udplite_exit);
 239
 240MODULE_LICENSE("GPL");
 241