1 /* (C) 1999-2001 Paul `Rusty' Russell 2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 3 * (C) 2006-2012 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 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> 27 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> 28 29 static unsigned int udp_timeouts[UDP_CT_MAX] = { 30 [UDP_CT_UNREPLIED] = 30*HZ, 31 [UDP_CT_REPLIED] = 180*HZ, 32 }; 33 34 static inline struct nf_udp_net *udp_pernet(struct net *net) 35 { 36 return &net->ct.nf_ct_proto.udp; 37 } 38 39 static bool udp_pkt_to_tuple(const struct sk_buff *skb, 40 unsigned int dataoff, 41 struct nf_conntrack_tuple *tuple) 42 { 43 const struct udphdr *hp; 44 struct udphdr _hdr; 45 46 /* Actually only need first 8 bytes. */ 47 hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); 48 if (hp == NULL) 49 return false; 50 51 tuple->src.u.udp.port = hp->source; 52 tuple->dst.u.udp.port = hp->dest; 53 54 return true; 55 } 56 57 static bool udp_invert_tuple(struct nf_conntrack_tuple *tuple, 58 const struct nf_conntrack_tuple *orig) 59 { 60 tuple->src.u.udp.port = orig->dst.u.udp.port; 61 tuple->dst.u.udp.port = orig->src.u.udp.port; 62 return true; 63 } 64 65 /* Print out the per-protocol part of the tuple. */ 66 static void udp_print_tuple(struct seq_file *s, 67 const struct nf_conntrack_tuple *tuple) 68 { 69 seq_printf(s, "sport=%hu dport=%hu ", 70 ntohs(tuple->src.u.udp.port), 71 ntohs(tuple->dst.u.udp.port)); 72 } 73 74 static unsigned int *udp_get_timeouts(struct net *net) 75 { 76 return udp_pernet(net)->timeouts; 77 } 78 79 /* Returns verdict for packet, and may modify conntracktype */ 80 static int udp_packet(struct nf_conn *ct, 81 const struct sk_buff *skb, 82 unsigned int dataoff, 83 enum ip_conntrack_info ctinfo, 84 u_int8_t pf, 85 unsigned int hooknum, 86 unsigned int *timeouts) 87 { 88 /* If we've seen traffic both ways, this is some kind of UDP 89 stream. Extend timeout. */ 90 if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { 91 nf_ct_refresh_acct(ct, ctinfo, skb, 92 timeouts[UDP_CT_REPLIED]); 93 /* Also, more likely to be important, and not a probe */ 94 if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) 95 nf_conntrack_event_cache(IPCT_ASSURED, ct); 96 } else { 97 nf_ct_refresh_acct(ct, ctinfo, skb, 98 timeouts[UDP_CT_UNREPLIED]); 99 } 100 return NF_ACCEPT; 101 } 102 103 /* Called when a new connection for this protocol found. */ 104 static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, 105 unsigned int dataoff, unsigned int *timeouts) 106 { 107 return true; 108 } 109 110 static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, 111 unsigned int dataoff, enum ip_conntrack_info *ctinfo, 112 u_int8_t pf, 113 unsigned int hooknum) 114 { 115 unsigned int udplen = skb->len - dataoff; 116 const struct udphdr *hdr; 117 struct udphdr _hdr; 118 119 /* Header is too small? */ 120 hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); 121 if (hdr == NULL) { 122 if (LOG_INVALID(net, IPPROTO_UDP)) 123 nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, 124 "nf_ct_udp: short packet "); 125 return -NF_ACCEPT; 126 } 127 128 /* Truncated/malformed packets */ 129 if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { 130 if (LOG_INVALID(net, IPPROTO_UDP)) 131 nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, 132 "nf_ct_udp: truncated/malformed packet "); 133 return -NF_ACCEPT; 134 } 135 136 /* Packet with no checksum */ 137 if (!hdr->check) 138 return NF_ACCEPT; 139 140 /* Checksum invalid? Ignore. 141 * We skip checking packets on the outgoing path 142 * because the checksum is assumed to be correct. 143 * FIXME: Source route IP option packets --RR */ 144 if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && 145 nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) { 146 if (LOG_INVALID(net, IPPROTO_UDP)) 147 nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, 148 "nf_ct_udp: bad UDP checksum "); 149 return -NF_ACCEPT; 150 } 151 152 return NF_ACCEPT; 153 } 154 155 #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) 156 157 #include <linux/netfilter/nfnetlink.h> 158 #include <linux/netfilter/nfnetlink_cttimeout.h> 159 160 static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], 161 struct net *net, void *data) 162 { 163 unsigned int *timeouts = data; 164 struct nf_udp_net *un = udp_pernet(net); 165 166 /* set default timeouts for UDP. */ 167 timeouts[UDP_CT_UNREPLIED] = un->timeouts[UDP_CT_UNREPLIED]; 168 timeouts[UDP_CT_REPLIED] = un->timeouts[UDP_CT_REPLIED]; 169 170 if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) { 171 timeouts[UDP_CT_UNREPLIED] = 172 ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ; 173 } 174 if (tb[CTA_TIMEOUT_UDP_REPLIED]) { 175 timeouts[UDP_CT_REPLIED] = 176 ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ; 177 } 178 return 0; 179 } 180 181 static int 182 udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data) 183 { 184 const unsigned int *timeouts = data; 185 186 if (nla_put_be32(skb, CTA_TIMEOUT_UDP_UNREPLIED, 187 htonl(timeouts[UDP_CT_UNREPLIED] / HZ)) || 188 nla_put_be32(skb, CTA_TIMEOUT_UDP_REPLIED, 189 htonl(timeouts[UDP_CT_REPLIED] / HZ))) 190 goto nla_put_failure; 191 return 0; 192 193 nla_put_failure: 194 return -ENOSPC; 195 } 196 197 static const struct nla_policy 198 udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = { 199 [CTA_TIMEOUT_UDP_UNREPLIED] = { .type = NLA_U32 }, 200 [CTA_TIMEOUT_UDP_REPLIED] = { .type = NLA_U32 }, 201 }; 202 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 203 204 #ifdef CONFIG_SYSCTL 205 static struct ctl_table udp_sysctl_table[] = { 206 { 207 .procname = "nf_conntrack_udp_timeout", 208 .maxlen = sizeof(unsigned int), 209 .mode = 0644, 210 .proc_handler = proc_dointvec_jiffies, 211 }, 212 { 213 .procname = "nf_conntrack_udp_timeout_stream", 214 .maxlen = sizeof(unsigned int), 215 .mode = 0644, 216 .proc_handler = proc_dointvec_jiffies, 217 }, 218 { } 219 }; 220 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 221 static struct ctl_table udp_compat_sysctl_table[] = { 222 { 223 .procname = "ip_conntrack_udp_timeout", 224 .maxlen = sizeof(unsigned int), 225 .mode = 0644, 226 .proc_handler = proc_dointvec_jiffies, 227 }, 228 { 229 .procname = "ip_conntrack_udp_timeout_stream", 230 .maxlen = sizeof(unsigned int), 231 .mode = 0644, 232 .proc_handler = proc_dointvec_jiffies, 233 }, 234 { } 235 }; 236 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */ 237 #endif /* CONFIG_SYSCTL */ 238 239 static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn, 240 struct nf_udp_net *un) 241 { 242 #ifdef CONFIG_SYSCTL 243 if (pn->ctl_table) 244 return 0; 245 pn->ctl_table = kmemdup(udp_sysctl_table, 246 sizeof(udp_sysctl_table), 247 GFP_KERNEL); 248 if (!pn->ctl_table) 249 return -ENOMEM; 250 pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED]; 251 pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED]; 252 #endif 253 return 0; 254 } 255 256 static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn, 257 struct nf_udp_net *un) 258 { 259 #ifdef CONFIG_SYSCTL 260 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT 261 pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table, 262 sizeof(udp_compat_sysctl_table), 263 GFP_KERNEL); 264 if (!pn->ctl_compat_table) 265 return -ENOMEM; 266 267 pn->ctl_compat_table[0].data = &un->timeouts[UDP_CT_UNREPLIED]; 268 pn->ctl_compat_table[1].data = &un->timeouts[UDP_CT_REPLIED]; 269 #endif 270 #endif 271 return 0; 272 } 273 274 static int udp_init_net(struct net *net, u_int16_t proto) 275 { 276 int ret; 277 struct nf_udp_net *un = udp_pernet(net); 278 struct nf_proto_net *pn = &un->pn; 279 280 if (!pn->users) { 281 int i; 282 283 for (i = 0; i < UDP_CT_MAX; i++) 284 un->timeouts[i] = udp_timeouts[i]; 285 } 286 287 if (proto == AF_INET) { 288 ret = udp_kmemdup_compat_sysctl_table(pn, un); 289 if (ret < 0) 290 return ret; 291 292 ret = udp_kmemdup_sysctl_table(pn, un); 293 if (ret < 0) 294 nf_ct_kfree_compat_sysctl_table(pn); 295 } else 296 ret = udp_kmemdup_sysctl_table(pn, un); 297 298 return ret; 299 } 300 301 static struct nf_proto_net *udp_get_net_proto(struct net *net) 302 { 303 return &net->ct.nf_ct_proto.udp.pn; 304 } 305 306 struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly = 307 { 308 .l3proto = PF_INET, 309 .l4proto = IPPROTO_UDP, 310 .name = "udp", 311 .pkt_to_tuple = udp_pkt_to_tuple, 312 .invert_tuple = udp_invert_tuple, 313 .print_tuple = udp_print_tuple, 314 .packet = udp_packet, 315 .get_timeouts = udp_get_timeouts, 316 .new = udp_new, 317 .error = udp_error, 318 #if IS_ENABLED(CONFIG_NF_CT_NETLINK) 319 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 320 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 321 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, 322 .nla_policy = nf_ct_port_nla_policy, 323 #endif 324 #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) 325 .ctnl_timeout = { 326 .nlattr_to_obj = udp_timeout_nlattr_to_obj, 327 .obj_to_nlattr = udp_timeout_obj_to_nlattr, 328 .nlattr_max = CTA_TIMEOUT_UDP_MAX, 329 .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, 330 .nla_policy = udp_timeout_nla_policy, 331 }, 332 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 333 .init_net = udp_init_net, 334 .get_net_proto = udp_get_net_proto, 335 }; 336 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4); 337 338 struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly = 339 { 340 .l3proto = PF_INET6, 341 .l4proto = IPPROTO_UDP, 342 .name = "udp", 343 .pkt_to_tuple = udp_pkt_to_tuple, 344 .invert_tuple = udp_invert_tuple, 345 .print_tuple = udp_print_tuple, 346 .packet = udp_packet, 347 .get_timeouts = udp_get_timeouts, 348 .new = udp_new, 349 .error = udp_error, 350 #if IS_ENABLED(CONFIG_NF_CT_NETLINK) 351 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, 352 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 353 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size, 354 .nla_policy = nf_ct_port_nla_policy, 355 #endif 356 #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) 357 .ctnl_timeout = { 358 .nlattr_to_obj = udp_timeout_nlattr_to_obj, 359 .obj_to_nlattr = udp_timeout_obj_to_nlattr, 360 .nlattr_max = CTA_TIMEOUT_UDP_MAX, 361 .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX, 362 .nla_policy = udp_timeout_nla_policy, 363 }, 364 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */ 365 .init_net = udp_init_net, 366 .get_net_proto = udp_get_net_proto, 367 }; 368 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6); 369
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.