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_ASSURED, 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 nf_conn *tmpl, struct sk_buff *skb, 95 unsigned int dataoff, 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 if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && 125 nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) { 126 if (LOG_INVALID(net, IPPROTO_UDP)) 127 nf_log_packet(pf, 0, skb, NULL, NULL, NULL, 128 "nf_ct_udp: bad UDP checksum "); 129 return -NF_ACCEPT; 130 } 131 132 return NF_ACCEPT; 133} 134 135#ifdef CONFIG_SYSCTL 136static unsigned int udp_sysctl_table_users; 137static struct ctl_table_header *udp_sysctl_header; 138static struct ctl_table udp_sysctl_table[] = { 139 { 140 .procname = "nf_conntrack_udp_timeout", 141 .data = &nf_ct_udp_timeout, 142 .maxlen = sizeof(unsigned int), 143 .mode = 0644, 144 .proc_handler = proc_dointvec_jiffies, 145 }, 146 { 147 .procname = "nf_conntrack_udp_timeout_stream", 148 .data = &nf_ct_udp_timeout_stream, 149 .maxlen = sizeof(unsigned int), 150 .mode = 0644, 151 .proc_handler = proc_dointvec_jiffies, 152 }, 153 { } 154}; 155#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 156static struct ctl_table udp_compat_sysctl_table[] = { 157 { 158 .procname = "ip_conntrack_udp_timeout", 159 .data = &nf_ct_udp_timeout, 160 .maxlen = sizeof(unsigned int), 161 .mode = 0644, 162 .proc_handler = proc_dointvec_jiffies, 163 }, 164 { 165 .procname = "ip_conntrack_udp_timeout_stream", 166 .data = &nf_ct_udp_timeout_stream, 167 .maxlen = sizeof(unsigned int), 168 .mode = 0644, 169 .proc_handler = proc_dointvec_jiffies, 170 }, 171 { } 172}; 173#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 174#endif /* CONFIG_SYSCTL */ 175 176struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = 177{ 178 .l3proto = PF_INET, 179 .l4proto = IPPROTO_UDP, 180 .name = "udp", 181 .pkt_to_tuple = udp_pkt_to_tuple, 182 .invert_tuple = udp_invert_tuple, 183 .print_tuple = udp_print_tuple, 184 .packet = udp_packet, 185 .new = udp_new, 186 .error = udp_error, 187#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 188 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 189 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 190 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, 191 .nla_policy = nf_ct_port_nla_policy, 192#endif 193#ifdef CONFIG_SYSCTL 194 .ctl_table_users = &udp_sysctl_table_users, 195 .ctl_table_header = &udp_sysctl_header, 196 .ctl_table = udp_sysctl_table, 197#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 198 .ctl_compat_table = udp_compat_sysctl_table, 199#endif 200#endif 201}; 202EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4); 203 204struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = 205{ 206 .l3proto = PF_INET6, 207 .l4proto = IPPROTO_UDP, 208 .name = "udp", 209 .pkt_to_tuple = udp_pkt_to_tuple, 210 .invert_tuple = udp_invert_tuple, 211 .print_tuple = udp_print_tuple, 212 .packet = udp_packet, 213 .new = udp_new, 214 .error = udp_error, 215#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 216 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 217 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 218 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, 219 .nla_policy = nf_ct_port_nla_policy, 220#endif 221#ifdef CONFIG_SYSCTL 222 .ctl_table_users = &udp_sysctl_table_users, 223 .ctl_table_header = &udp_sysctl_header, 224 .ctl_table = udp_sysctl_table, 225#endif 226}; 227EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); 228