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 28 static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; 29 static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; 30 31 static 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 49 static 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. */ 58 static 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 */ 67 static 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. */ 88 static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, 89 unsigned int dataoff) 90 { 91 return true; 92 } 93 94 static 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 /* 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 140 static unsigned int udp_sysctl_table_users; 141 static struct ctl_table_header *udp_sysctl_header; 142 static 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 }; 159 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 160 static 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 }; 177 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 178 #endif /* CONFIG_SYSCTL */ 179 180 struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = 181 { 182 .l3proto = PF_INET, 183 .l4proto = IPPROTO_UDP, 184 .name = "udp", 185 .pkt_to_tuple = udp_pkt_to_tuple, 186 .invert_tuple = udp_invert_tuple, 187 .print_tuple = udp_print_tuple, 188 .packet = udp_packet, 189 .new = udp_new, 190 .error = udp_error, 191 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 192 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 193 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 194 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, 195 .nla_policy = nf_ct_port_nla_policy, 196 #endif 197 #ifdef CONFIG_SYSCTL 198 .ctl_table_users = &udp_sysctl_table_users, 199 .ctl_table_header = &udp_sysctl_header, 200 .ctl_table = udp_sysctl_table, 201 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 202 .ctl_compat_table = udp_compat_sysctl_table, 203 #endif 204 #endif 205 }; 206 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4); 207 208 struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = 209 { 210 .l3proto = PF_INET6, 211 .l4proto = IPPROTO_UDP, 212 .name = "udp", 213 .pkt_to_tuple = udp_pkt_to_tuple, 214 .invert_tuple = udp_invert_tuple, 215 .print_tuple = udp_print_tuple, 216 .packet = udp_packet, 217 .new = udp_new, 218 .error = udp_error, 219 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 220 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 221 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 222 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, 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 }; 231 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); 232