aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/netfilter
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /net/ipv4/netfilter
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'net/ipv4/netfilter')
-rw-r--r--net/ipv4/netfilter/ip_queue.c637
-rw-r--r--net/ipv4/netfilter/ipt_LOG.c516
-rw-r--r--net/ipv4/netfilter/ipt_NETMAP.c98
-rw-r--r--net/ipv4/netfilter/ipt_REDIRECT.c110
-rw-r--r--net/ipv4/netfilter/ipt_ecn.c127
-rw-r--r--net/ipv4/netfilter/nf_nat_amanda.c85
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c779
-rw-r--r--net/ipv4/netfilter/nf_nat_ftp.c137
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c451
-rw-r--r--net/ipv4/netfilter/nf_nat_irc.c99
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_common.c125
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_dccp.c108
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_sctp.c97
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_tcp.c92
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_udp.c83
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_udplite.c99
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_unknown.c53
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c214
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c561
-rw-r--r--net/ipv4/netfilter/nf_nat_standalone.c326
-rw-r--r--net/ipv4/netfilter/nf_nat_tftp.c51
21 files changed, 4848 insertions, 0 deletions
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
new file mode 100644
index 00000000000..e59aabd0eae
--- /dev/null
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -0,0 +1,637 @@
1/*
2 * This is a module which is used for queueing IPv4 packets and
3 * communicating with userspace via netlink.
4 *
5 * (C) 2000-2002 James Morris <jmorris@intercode.com.au>
6 * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/skbuff.h>
14#include <linux/init.h>
15#include <linux/ip.h>
16#include <linux/notifier.h>
17#include <linux/netdevice.h>
18#include <linux/netfilter.h>
19#include <linux/netfilter_ipv4/ip_queue.h>
20#include <linux/netfilter_ipv4/ip_tables.h>
21#include <linux/netlink.h>
22#include <linux/spinlock.h>
23#include <linux/sysctl.h>
24#include <linux/proc_fs.h>
25#include <linux/seq_file.h>
26#include <linux/security.h>
27#include <linux/net.h>
28#include <linux/mutex.h>
29#include <linux/slab.h>
30#include <net/net_namespace.h>
31#include <net/sock.h>
32#include <net/route.h>
33#include <net/netfilter/nf_queue.h>
34#include <net/ip.h>
35
36#define IPQ_QMAX_DEFAULT 1024
37#define IPQ_PROC_FS_NAME "ip_queue"
38#define NET_IPQ_QMAX 2088
39#define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
40
41typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long);
42
43static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE;
44static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT;
45static DEFINE_SPINLOCK(queue_lock);
46static int peer_pid __read_mostly;
47static unsigned int copy_range __read_mostly;
48static unsigned int queue_total;
49static unsigned int queue_dropped = 0;
50static unsigned int queue_user_dropped = 0;
51static struct sock *ipqnl __read_mostly;
52static LIST_HEAD(queue_list);
53static DEFINE_MUTEX(ipqnl_mutex);
54
55static inline void
56__ipq_enqueue_entry(struct nf_queue_entry *entry)
57{
58 list_add_tail(&entry->list, &queue_list);
59 queue_total++;
60}
61
62static inline int
63__ipq_set_mode(unsigned char mode, unsigned int range)
64{
65 int status = 0;
66
67 switch(mode) {
68 case IPQ_COPY_NONE:
69 case IPQ_COPY_META:
70 copy_mode = mode;
71 copy_range = 0;
72 break;
73
74 case IPQ_COPY_PACKET:
75 if (range > 0xFFFF)
76 range = 0xFFFF;
77 copy_range = range;
78 copy_mode = mode;
79 break;
80
81 default:
82 status = -EINVAL;
83
84 }
85 return status;
86}
87
88static void __ipq_flush(ipq_cmpfn cmpfn, unsigned long data);
89
90static inline void
91__ipq_reset(void)
92{
93 peer_pid = 0;
94 net_disable_timestamp();
95 __ipq_set_mode(IPQ_COPY_NONE, 0);
96 __ipq_flush(NULL, 0);
97}
98
99static struct nf_queue_entry *
100ipq_find_dequeue_entry(unsigned long id)
101{
102 struct nf_queue_entry *entry = NULL, *i;
103
104 spin_lock_bh(&queue_lock);
105
106 list_for_each_entry(i, &queue_list, list) {
107 if ((unsigned long)i == id) {
108 entry = i;
109 break;
110 }
111 }
112
113 if (entry) {
114 list_del(&entry->list);
115 queue_total--;
116 }
117
118 spin_unlock_bh(&queue_lock);
119 return entry;
120}
121
122static void
123__ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
124{
125 struct nf_queue_entry *entry, *next;
126
127 list_for_each_entry_safe(entry, next, &queue_list, list) {
128 if (!cmpfn || cmpfn(entry, data)) {
129 list_del(&entry->list);
130 queue_total--;
131 nf_reinject(entry, NF_DROP);
132 }
133 }
134}
135
136static void
137ipq_flush(ipq_cmpfn cmpfn, unsigned long data)
138{
139 spin_lock_bh(&queue_lock);
140 __ipq_flush(cmpfn, data);
141 spin_unlock_bh(&queue_lock);
142}
143
144static struct sk_buff *
145ipq_build_packet_message(struct nf_queue_entry *entry, int *errp)
146{
147 sk_buff_data_t old_tail;
148 size_t size = 0;
149 size_t data_len = 0;
150 struct sk_buff *skb;
151 struct ipq_packet_msg *pmsg;
152 struct nlmsghdr *nlh;
153 struct timeval tv;
154
155 switch (ACCESS_ONCE(copy_mode)) {
156 case IPQ_COPY_META:
157 case IPQ_COPY_NONE:
158 size = NLMSG_SPACE(sizeof(*pmsg));
159 break;
160
161 case IPQ_COPY_PACKET:
162 if (entry->skb->ip_summed == CHECKSUM_PARTIAL &&
163 (*errp = skb_checksum_help(entry->skb)))
164 return NULL;
165
166 data_len = ACCESS_ONCE(copy_range);
167 if (data_len == 0 || data_len > entry->skb->len)
168 data_len = entry->skb->len;
169
170 size = NLMSG_SPACE(sizeof(*pmsg) + data_len);
171 break;
172
173 default:
174 *errp = -EINVAL;
175 return NULL;
176 }
177
178 skb = alloc_skb(size, GFP_ATOMIC);
179 if (!skb)
180 goto nlmsg_failure;
181
182 old_tail = skb->tail;
183 nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh));
184 pmsg = NLMSG_DATA(nlh);
185 memset(pmsg, 0, sizeof(*pmsg));
186
187 pmsg->packet_id = (unsigned long )entry;
188 pmsg->data_len = data_len;
189 tv = ktime_to_timeval(entry->skb->tstamp);
190 pmsg->timestamp_sec = tv.tv_sec;
191 pmsg->timestamp_usec = tv.tv_usec;
192 pmsg->mark = entry->skb->mark;
193 pmsg->hook = entry->hook;
194 pmsg->hw_protocol = entry->skb->protocol;
195
196 if (entry->indev)
197 strcpy(pmsg->indev_name, entry->indev->name);
198 else
199 pmsg->indev_name[0] = '\0';
200
201 if (entry->outdev)
202 strcpy(pmsg->outdev_name, entry->outdev->name);
203 else
204 pmsg->outdev_name[0] = '\0';
205
206 if (entry->indev && entry->skb->dev &&
207 entry->skb->mac_header != entry->skb->network_header) {
208 pmsg->hw_type = entry->skb->dev->type;
209 pmsg->hw_addrlen = dev_parse_header(entry->skb,
210 pmsg->hw_addr);
211 }
212
213 if (data_len)
214 if (skb_copy_bits(entry->skb, 0, pmsg->payload, data_len))
215 BUG();
216
217 nlh->nlmsg_len = skb->tail - old_tail;
218 return skb;
219
220nlmsg_failure:
221 kfree_skb(skb);
222 *errp = -EINVAL;
223 printk(KERN_ERR "ip_queue: error creating packet message\n");
224 return NULL;
225}
226
227static int
228ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
229{
230 int status = -EINVAL;
231 struct sk_buff *nskb;
232
233 if (copy_mode == IPQ_COPY_NONE)
234 return -EAGAIN;
235
236 nskb = ipq_build_packet_message(entry, &status);
237 if (nskb == NULL)
238 return status;
239
240 spin_lock_bh(&queue_lock);
241
242 if (!peer_pid)
243 goto err_out_free_nskb;
244
245 if (queue_total >= queue_maxlen) {
246 queue_dropped++;
247 status = -ENOSPC;
248 if (net_ratelimit())
249 printk (KERN_WARNING "ip_queue: full at %d entries, "
250 "dropping packets(s). Dropped: %d\n", queue_total,
251 queue_dropped);
252 goto err_out_free_nskb;
253 }
254
255 /* netlink_unicast will either free the nskb or attach it to a socket */
256 status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT);
257 if (status < 0) {
258 queue_user_dropped++;
259 goto err_out_unlock;
260 }
261
262 __ipq_enqueue_entry(entry);
263
264 spin_unlock_bh(&queue_lock);
265 return status;
266
267err_out_free_nskb:
268 kfree_skb(nskb);
269
270err_out_unlock:
271 spin_unlock_bh(&queue_lock);
272 return status;
273}
274
275static int
276ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct nf_queue_entry *e)
277{
278 int diff;
279 struct iphdr *user_iph = (struct iphdr *)v->payload;
280 struct sk_buff *nskb;
281
282 if (v->data_len < sizeof(*user_iph))
283 return 0;
284 diff = v->data_len - e->skb->len;
285 if (diff < 0) {
286 if (pskb_trim(e->skb, v->data_len))
287 return -ENOMEM;
288 } else if (diff > 0) {
289 if (v->data_len > 0xFFFF)
290 return -EINVAL;
291 if (diff > skb_tailroom(e->skb)) {
292 nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
293 diff, GFP_ATOMIC);
294 if (!nskb) {
295 printk(KERN_WARNING "ip_queue: error "
296 "in mangle, dropping packet\n");
297 return -ENOMEM;
298 }
299 kfree_skb(e->skb);
300 e->skb = nskb;
301 }
302 skb_put(e->skb, diff);
303 }
304 if (!skb_make_writable(e->skb, v->data_len))
305 return -ENOMEM;
306 skb_copy_to_linear_data(e->skb, v->payload, v->data_len);
307 e->skb->ip_summed = CHECKSUM_NONE;
308
309 return 0;
310}
311
312static int
313ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len)
314{
315 struct nf_queue_entry *entry;
316
317 if (vmsg->value > NF_MAX_VERDICT || vmsg->value == NF_STOLEN)
318 return -EINVAL;
319
320 entry = ipq_find_dequeue_entry(vmsg->id);
321 if (entry == NULL)
322 return -ENOENT;
323 else {
324 int verdict = vmsg->value;
325
326 if (vmsg->data_len && vmsg->data_len == len)
327 if (ipq_mangle_ipv4(vmsg, entry) < 0)
328 verdict = NF_DROP;
329
330 nf_reinject(entry, verdict);
331 return 0;
332 }
333}
334
335static int
336ipq_set_mode(unsigned char mode, unsigned int range)
337{
338 int status;
339
340 spin_lock_bh(&queue_lock);
341 status = __ipq_set_mode(mode, range);
342 spin_unlock_bh(&queue_lock);
343 return status;
344}
345
346static int
347ipq_receive_peer(struct ipq_peer_msg *pmsg,
348 unsigned char type, unsigned int len)
349{
350 int status = 0;
351
352 if (len < sizeof(*pmsg))
353 return -EINVAL;
354
355 switch (type) {
356 case IPQM_MODE:
357 status = ipq_set_mode(pmsg->msg.mode.value,
358 pmsg->msg.mode.range);
359 break;
360
361 case IPQM_VERDICT:
362 status = ipq_set_verdict(&pmsg->msg.verdict,
363 len - sizeof(*pmsg));
364 break;
365 default:
366 status = -EINVAL;
367 }
368 return status;
369}
370
371static int
372dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
373{
374 if (entry->indev)
375 if (entry->indev->ifindex == ifindex)
376 return 1;
377 if (entry->outdev)
378 if (entry->outdev->ifindex == ifindex)
379 return 1;
380#ifdef CONFIG_BRIDGE_NETFILTER
381 if (entry->skb->nf_bridge) {
382 if (entry->skb->nf_bridge->physindev &&
383 entry->skb->nf_bridge->physindev->ifindex == ifindex)
384 return 1;
385 if (entry->skb->nf_bridge->physoutdev &&
386 entry->skb->nf_bridge->physoutdev->ifindex == ifindex)
387 return 1;
388 }
389#endif
390 return 0;
391}
392
393static void
394ipq_dev_drop(int ifindex)
395{
396 ipq_flush(dev_cmp, ifindex);
397}
398
399#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
400
401static inline void
402__ipq_rcv_skb(struct sk_buff *skb)
403{
404 int status, type, pid, flags;
405 unsigned int nlmsglen, skblen;
406 struct nlmsghdr *nlh;
407
408 skblen = skb->len;
409 if (skblen < sizeof(*nlh))
410 return;
411
412 nlh = nlmsg_hdr(skb);
413 nlmsglen = nlh->nlmsg_len;
414 if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
415 return;
416
417 pid = nlh->nlmsg_pid;
418 flags = nlh->nlmsg_flags;
419
420 if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI)
421 RCV_SKB_FAIL(-EINVAL);
422
423 if (flags & MSG_TRUNC)
424 RCV_SKB_FAIL(-ECOMM);
425
426 type = nlh->nlmsg_type;
427 if (type < NLMSG_NOOP || type >= IPQM_MAX)
428 RCV_SKB_FAIL(-EINVAL);
429
430 if (type <= IPQM_BASE)
431 return;
432
433 if (security_netlink_recv(skb, CAP_NET_ADMIN))
434 RCV_SKB_FAIL(-EPERM);
435
436 spin_lock_bh(&queue_lock);
437
438 if (peer_pid) {
439 if (peer_pid != pid) {
440 spin_unlock_bh(&queue_lock);
441 RCV_SKB_FAIL(-EBUSY);
442 }
443 } else {
444 net_enable_timestamp();
445 peer_pid = pid;
446 }
447
448 spin_unlock_bh(&queue_lock);
449
450 status = ipq_receive_peer(NLMSG_DATA(nlh), type,
451 nlmsglen - NLMSG_LENGTH(0));
452 if (status < 0)
453 RCV_SKB_FAIL(status);
454
455 if (flags & NLM_F_ACK)
456 netlink_ack(skb, nlh, 0);
457}
458
459static void
460ipq_rcv_skb(struct sk_buff *skb)
461{
462 mutex_lock(&ipqnl_mutex);
463 __ipq_rcv_skb(skb);
464 mutex_unlock(&ipqnl_mutex);
465}
466
467static int
468ipq_rcv_dev_event(struct notifier_block *this,
469 unsigned long event, void *ptr)
470{
471 struct net_device *dev = ptr;
472
473 if (!net_eq(dev_net(dev), &init_net))
474 return NOTIFY_DONE;
475
476 /* Drop any packets associated with the downed device */
477 if (event == NETDEV_DOWN)
478 ipq_dev_drop(dev->ifindex);
479 return NOTIFY_DONE;
480}
481
482static struct notifier_block ipq_dev_notifier = {
483 .notifier_call = ipq_rcv_dev_event,
484};
485
486static int
487ipq_rcv_nl_event(struct notifier_block *this,
488 unsigned long event, void *ptr)
489{
490 struct netlink_notify *n = ptr;
491
492 if (event == NETLINK_URELEASE && n->protocol == NETLINK_FIREWALL) {
493 spin_lock_bh(&queue_lock);
494 if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid))
495 __ipq_reset();
496 spin_unlock_bh(&queue_lock);
497 }
498 return NOTIFY_DONE;
499}
500
501static struct notifier_block ipq_nl_notifier = {
502 .notifier_call = ipq_rcv_nl_event,
503};
504
505#ifdef CONFIG_SYSCTL
506static struct ctl_table_header *ipq_sysctl_header;
507
508static ctl_table ipq_table[] = {
509 {
510 .procname = NET_IPQ_QMAX_NAME,
511 .data = &queue_maxlen,
512 .maxlen = sizeof(queue_maxlen),
513 .mode = 0644,
514 .proc_handler = proc_dointvec
515 },
516 { }
517};
518#endif
519
520#ifdef CONFIG_PROC_FS
521static int ip_queue_show(struct seq_file *m, void *v)
522{
523 spin_lock_bh(&queue_lock);
524
525 seq_printf(m,
526 "Peer PID : %d\n"
527 "Copy mode : %hu\n"
528 "Copy range : %u\n"
529 "Queue length : %u\n"
530 "Queue max. length : %u\n"
531 "Queue dropped : %u\n"
532 "Netlink dropped : %u\n",
533 peer_pid,
534 copy_mode,
535 copy_range,
536 queue_total,
537 queue_maxlen,
538 queue_dropped,
539 queue_user_dropped);
540
541 spin_unlock_bh(&queue_lock);
542 return 0;
543}
544
545static int ip_queue_open(struct inode *inode, struct file *file)
546{
547 return single_open(file, ip_queue_show, NULL);
548}
549
550static const struct file_operations ip_queue_proc_fops = {
551 .open = ip_queue_open,
552 .read = seq_read,
553 .llseek = seq_lseek,
554 .release = single_release,
555 .owner = THIS_MODULE,
556};
557#endif
558
559static const struct nf_queue_handler nfqh = {
560 .name = "ip_queue",
561 .outfn = &ipq_enqueue_packet,
562};
563
564static int __init ip_queue_init(void)
565{
566 int status = -ENOMEM;
567 struct proc_dir_entry *proc __maybe_unused;
568
569 netlink_register_notifier(&ipq_nl_notifier);
570 ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0,
571 ipq_rcv_skb, NULL, THIS_MODULE);
572 if (ipqnl == NULL) {
573 printk(KERN_ERR "ip_queue: failed to create netlink socket\n");
574 goto cleanup_netlink_notifier;
575 }
576
577#ifdef CONFIG_PROC_FS
578 proc = proc_create(IPQ_PROC_FS_NAME, 0, init_net.proc_net,
579 &ip_queue_proc_fops);
580 if (!proc) {
581 printk(KERN_ERR "ip_queue: failed to create proc entry\n");
582 goto cleanup_ipqnl;
583 }
584#endif
585 register_netdevice_notifier(&ipq_dev_notifier);
586#ifdef CONFIG_SYSCTL
587 ipq_sysctl_header = register_sysctl_paths(net_ipv4_ctl_path, ipq_table);
588#endif
589 status = nf_register_queue_handler(NFPROTO_IPV4, &nfqh);
590 if (status < 0) {
591 printk(KERN_ERR "ip_queue: failed to register queue handler\n");
592 goto cleanup_sysctl;
593 }
594 return status;
595
596cleanup_sysctl:
597#ifdef CONFIG_SYSCTL
598 unregister_sysctl_table(ipq_sysctl_header);
599#endif
600 unregister_netdevice_notifier(&ipq_dev_notifier);
601 proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
602cleanup_ipqnl: __maybe_unused
603 netlink_kernel_release(ipqnl);
604 mutex_lock(&ipqnl_mutex);
605 mutex_unlock(&ipqnl_mutex);
606
607cleanup_netlink_notifier:
608 netlink_unregister_notifier(&ipq_nl_notifier);
609 return status;
610}
611
612static void __exit ip_queue_fini(void)
613{
614 nf_unregister_queue_handlers(&nfqh);
615
616 ipq_flush(NULL, 0);
617
618#ifdef CONFIG_SYSCTL
619 unregister_sysctl_table(ipq_sysctl_header);
620#endif
621 unregister_netdevice_notifier(&ipq_dev_notifier);
622 proc_net_remove(&init_net, IPQ_PROC_FS_NAME);
623
624 netlink_kernel_release(ipqnl);
625 mutex_lock(&ipqnl_mutex);
626 mutex_unlock(&ipqnl_mutex);
627
628 netlink_unregister_notifier(&ipq_nl_notifier);
629}
630
631MODULE_DESCRIPTION("IPv4 packet queue handler");
632MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
633MODULE_LICENSE("GPL");
634MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_FIREWALL);
635
636module_init(ip_queue_init);
637module_exit(ip_queue_fini);
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
new file mode 100644
index 00000000000..d76d6c9ed94
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -0,0 +1,516 @@
1/*
2 * This is a module which is used for logging packets.
3 */
4
5/* (C) 1999-2001 Paul `Rusty' Russell
6 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13#include <linux/module.h>
14#include <linux/spinlock.h>
15#include <linux/skbuff.h>
16#include <linux/if_arp.h>
17#include <linux/ip.h>
18#include <net/icmp.h>
19#include <net/udp.h>
20#include <net/tcp.h>
21#include <net/route.h>
22
23#include <linux/netfilter.h>
24#include <linux/netfilter/x_tables.h>
25#include <linux/netfilter_ipv4/ipt_LOG.h>
26#include <net/netfilter/nf_log.h>
27#include <net/netfilter/xt_log.h>
28
29MODULE_LICENSE("GPL");
30MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
31MODULE_DESCRIPTION("Xtables: IPv4 packet logging to syslog");
32
33/* One level of recursion won't kill us */
34static void dump_packet(struct sbuff *m,
35 const struct nf_loginfo *info,
36 const struct sk_buff *skb,
37 unsigned int iphoff)
38{
39 struct iphdr _iph;
40 const struct iphdr *ih;
41 unsigned int logflags;
42
43 if (info->type == NF_LOG_TYPE_LOG)
44 logflags = info->u.log.logflags;
45 else
46 logflags = NF_LOG_MASK;
47
48 ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
49 if (ih == NULL) {
50 sb_add(m, "TRUNCATED");
51 return;
52 }
53
54 /* Important fields:
55 * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
56 /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
57 sb_add(m, "SRC=%pI4 DST=%pI4 ",
58 &ih->saddr, &ih->daddr);
59
60 /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
61 sb_add(m, "LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
62 ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK,
63 ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id));
64
65 /* Max length: 6 "CE DF MF " */
66 if (ntohs(ih->frag_off) & IP_CE)
67 sb_add(m, "CE ");
68 if (ntohs(ih->frag_off) & IP_DF)
69 sb_add(m, "DF ");
70 if (ntohs(ih->frag_off) & IP_MF)
71 sb_add(m, "MF ");
72
73 /* Max length: 11 "FRAG:65535 " */
74 if (ntohs(ih->frag_off) & IP_OFFSET)
75 sb_add(m, "FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
76
77 if ((logflags & IPT_LOG_IPOPT) &&
78 ih->ihl * 4 > sizeof(struct iphdr)) {
79 const unsigned char *op;
80 unsigned char _opt[4 * 15 - sizeof(struct iphdr)];
81 unsigned int i, optsize;
82
83 optsize = ih->ihl * 4 - sizeof(struct iphdr);
84 op = skb_header_pointer(skb, iphoff+sizeof(_iph),
85 optsize, _opt);
86 if (op == NULL) {
87 sb_add(m, "TRUNCATED");
88 return;
89 }
90
91 /* Max length: 127 "OPT (" 15*4*2chars ") " */
92 sb_add(m, "OPT (");
93 for (i = 0; i < optsize; i++)
94 sb_add(m, "%02X", op[i]);
95 sb_add(m, ") ");
96 }
97
98 switch (ih->protocol) {
99 case IPPROTO_TCP: {
100 struct tcphdr _tcph;
101 const struct tcphdr *th;
102
103 /* Max length: 10 "PROTO=TCP " */
104 sb_add(m, "PROTO=TCP ");
105
106 if (ntohs(ih->frag_off) & IP_OFFSET)
107 break;
108
109 /* Max length: 25 "INCOMPLETE [65535 bytes] " */
110 th = skb_header_pointer(skb, iphoff + ih->ihl * 4,
111 sizeof(_tcph), &_tcph);
112 if (th == NULL) {
113 sb_add(m, "INCOMPLETE [%u bytes] ",
114 skb->len - iphoff - ih->ihl*4);
115 break;
116 }
117
118 /* Max length: 20 "SPT=65535 DPT=65535 " */
119 sb_add(m, "SPT=%u DPT=%u ",
120 ntohs(th->source), ntohs(th->dest));
121 /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
122 if (logflags & IPT_LOG_TCPSEQ)
123 sb_add(m, "SEQ=%u ACK=%u ",
124 ntohl(th->seq), ntohl(th->ack_seq));
125 /* Max length: 13 "WINDOW=65535 " */
126 sb_add(m, "WINDOW=%u ", ntohs(th->window));
127 /* Max length: 9 "RES=0x3F " */
128 sb_add(m, "RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
129 /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
130 if (th->cwr)
131 sb_add(m, "CWR ");
132 if (th->ece)
133 sb_add(m, "ECE ");
134 if (th->urg)
135 sb_add(m, "URG ");
136 if (th->ack)
137 sb_add(m, "ACK ");
138 if (th->psh)
139 sb_add(m, "PSH ");
140 if (th->rst)
141 sb_add(m, "RST ");
142 if (th->syn)
143 sb_add(m, "SYN ");
144 if (th->fin)
145 sb_add(m, "FIN ");
146 /* Max length: 11 "URGP=65535 " */
147 sb_add(m, "URGP=%u ", ntohs(th->urg_ptr));
148
149 if ((logflags & IPT_LOG_TCPOPT) &&
150 th->doff * 4 > sizeof(struct tcphdr)) {
151 unsigned char _opt[4 * 15 - sizeof(struct tcphdr)];
152 const unsigned char *op;
153 unsigned int i, optsize;
154
155 optsize = th->doff * 4 - sizeof(struct tcphdr);
156 op = skb_header_pointer(skb,
157 iphoff+ih->ihl*4+sizeof(_tcph),
158 optsize, _opt);
159 if (op == NULL) {
160 sb_add(m, "TRUNCATED");
161 return;
162 }
163
164 /* Max length: 127 "OPT (" 15*4*2chars ") " */
165 sb_add(m, "OPT (");
166 for (i = 0; i < optsize; i++)
167 sb_add(m, "%02X", op[i]);
168 sb_add(m, ") ");
169 }
170 break;
171 }
172 case IPPROTO_UDP:
173 case IPPROTO_UDPLITE: {
174 struct udphdr _udph;
175 const struct udphdr *uh;
176
177 if (ih->protocol == IPPROTO_UDP)
178 /* Max length: 10 "PROTO=UDP " */
179 sb_add(m, "PROTO=UDP " );
180 else /* Max length: 14 "PROTO=UDPLITE " */
181 sb_add(m, "PROTO=UDPLITE ");
182
183 if (ntohs(ih->frag_off) & IP_OFFSET)
184 break;
185
186 /* Max length: 25 "INCOMPLETE [65535 bytes] " */
187 uh = skb_header_pointer(skb, iphoff+ih->ihl*4,
188 sizeof(_udph), &_udph);
189 if (uh == NULL) {
190 sb_add(m, "INCOMPLETE [%u bytes] ",
191 skb->len - iphoff - ih->ihl*4);
192 break;
193 }
194
195 /* Max length: 20 "SPT=65535 DPT=65535 " */
196 sb_add(m, "SPT=%u DPT=%u LEN=%u ",
197 ntohs(uh->source), ntohs(uh->dest),
198 ntohs(uh->len));
199 break;
200 }
201 case IPPROTO_ICMP: {
202 struct icmphdr _icmph;
203 const struct icmphdr *ich;
204 static const size_t required_len[NR_ICMP_TYPES+1]
205 = { [ICMP_ECHOREPLY] = 4,
206 [ICMP_DEST_UNREACH]
207 = 8 + sizeof(struct iphdr),
208 [ICMP_SOURCE_QUENCH]
209 = 8 + sizeof(struct iphdr),
210 [ICMP_REDIRECT]
211 = 8 + sizeof(struct iphdr),
212 [ICMP_ECHO] = 4,
213 [ICMP_TIME_EXCEEDED]
214 = 8 + sizeof(struct iphdr),
215 [ICMP_PARAMETERPROB]
216 = 8 + sizeof(struct iphdr),
217 [ICMP_TIMESTAMP] = 20,
218 [ICMP_TIMESTAMPREPLY] = 20,
219 [ICMP_ADDRESS] = 12,
220 [ICMP_ADDRESSREPLY] = 12 };
221
222 /* Max length: 11 "PROTO=ICMP " */
223 sb_add(m, "PROTO=ICMP ");
224
225 if (ntohs(ih->frag_off) & IP_OFFSET)
226 break;
227
228 /* Max length: 25 "INCOMPLETE [65535 bytes] " */
229 ich = skb_header_pointer(skb, iphoff + ih->ihl * 4,
230 sizeof(_icmph), &_icmph);
231 if (ich == NULL) {
232 sb_add(m, "INCOMPLETE [%u bytes] ",
233 skb->len - iphoff - ih->ihl*4);
234 break;
235 }
236
237 /* Max length: 18 "TYPE=255 CODE=255 " */
238 sb_add(m, "TYPE=%u CODE=%u ", ich->type, ich->code);
239
240 /* Max length: 25 "INCOMPLETE [65535 bytes] " */
241 if (ich->type <= NR_ICMP_TYPES &&
242 required_len[ich->type] &&
243 skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) {
244 sb_add(m, "INCOMPLETE [%u bytes] ",
245 skb->len - iphoff - ih->ihl*4);
246 break;
247 }
248
249 switch (ich->type) {
250 case ICMP_ECHOREPLY:
251 case ICMP_ECHO:
252 /* Max length: 19 "ID=65535 SEQ=65535 " */
253 sb_add(m, "ID=%u SEQ=%u ",
254 ntohs(ich->un.echo.id),
255 ntohs(ich->un.echo.sequence));
256 break;
257
258 case ICMP_PARAMETERPROB:
259 /* Max length: 14 "PARAMETER=255 " */
260 sb_add(m, "PARAMETER=%u ",
261 ntohl(ich->un.gateway) >> 24);
262 break;
263 case ICMP_REDIRECT:
264 /* Max length: 24 "GATEWAY=255.255.255.255 " */
265 sb_add(m, "GATEWAY=%pI4 ", &ich->un.gateway);
266 /* Fall through */
267 case ICMP_DEST_UNREACH:
268 case ICMP_SOURCE_QUENCH:
269 case ICMP_TIME_EXCEEDED:
270 /* Max length: 3+maxlen */
271 if (!iphoff) { /* Only recurse once. */
272 sb_add(m, "[");
273 dump_packet(m, info, skb,
274 iphoff + ih->ihl*4+sizeof(_icmph));
275 sb_add(m, "] ");
276 }
277
278 /* Max length: 10 "MTU=65535 " */
279 if (ich->type == ICMP_DEST_UNREACH &&
280 ich->code == ICMP_FRAG_NEEDED)
281 sb_add(m, "MTU=%u ", ntohs(ich->un.frag.mtu));
282 }
283 break;
284 }
285 /* Max Length */
286 case IPPROTO_AH: {
287 struct ip_auth_hdr _ahdr;
288 const struct ip_auth_hdr *ah;
289
290 if (ntohs(ih->frag_off) & IP_OFFSET)
291 break;
292
293 /* Max length: 9 "PROTO=AH " */
294 sb_add(m, "PROTO=AH ");
295
296 /* Max length: 25 "INCOMPLETE [65535 bytes] " */
297 ah = skb_header_pointer(skb, iphoff+ih->ihl*4,
298 sizeof(_ahdr), &_ahdr);
299 if (ah == NULL) {
300 sb_add(m, "INCOMPLETE [%u bytes] ",
301 skb->len - iphoff - ih->ihl*4);
302 break;
303 }
304
305 /* Length: 15 "SPI=0xF1234567 " */
306 sb_add(m, "SPI=0x%x ", ntohl(ah->spi));
307 break;
308 }
309 case IPPROTO_ESP: {
310 struct ip_esp_hdr _esph;
311 const struct ip_esp_hdr *eh;
312
313 /* Max length: 10 "PROTO=ESP " */
314 sb_add(m, "PROTO=ESP ");
315
316 if (ntohs(ih->frag_off) & IP_OFFSET)
317 break;
318
319 /* Max length: 25 "INCOMPLETE [65535 bytes] " */
320 eh = skb_header_pointer(skb, iphoff+ih->ihl*4,
321 sizeof(_esph), &_esph);
322 if (eh == NULL) {
323 sb_add(m, "INCOMPLETE [%u bytes] ",
324 skb->len - iphoff - ih->ihl*4);
325 break;
326 }
327
328 /* Length: 15 "SPI=0xF1234567 " */
329 sb_add(m, "SPI=0x%x ", ntohl(eh->spi));
330 break;
331 }
332 /* Max length: 10 "PROTO 255 " */
333 default:
334 sb_add(m, "PROTO=%u ", ih->protocol);
335 }
336
337 /* Max length: 15 "UID=4294967295 " */
338 if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) {
339 read_lock_bh(&skb->sk->sk_callback_lock);
340 if (skb->sk->sk_socket && skb->sk->sk_socket->file)
341 sb_add(m, "UID=%u GID=%u ",
342 skb->sk->sk_socket->file->f_cred->fsuid,
343 skb->sk->sk_socket->file->f_cred->fsgid);
344 read_unlock_bh(&skb->sk->sk_callback_lock);
345 }
346
347 /* Max length: 16 "MARK=0xFFFFFFFF " */
348 if (!iphoff && skb->mark)
349 sb_add(m, "MARK=0x%x ", skb->mark);
350
351 /* Proto Max log string length */
352 /* IP: 40+46+6+11+127 = 230 */
353 /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */
354 /* UDP: 10+max(25,20) = 35 */
355 /* UDPLITE: 14+max(25,20) = 39 */
356 /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */
357 /* ESP: 10+max(25)+15 = 50 */
358 /* AH: 9+max(25)+15 = 49 */
359 /* unknown: 10 */
360
361 /* (ICMP allows recursion one level deep) */
362 /* maxlen = IP + ICMP + IP + max(TCP,UDP,ICMP,unknown) */
363 /* maxlen = 230+ 91 + 230 + 252 = 803 */
364}
365
366static void dump_mac_header(struct sbuff *m,
367 const struct nf_loginfo *info,
368 const struct sk_buff *skb)
369{
370 struct net_device *dev = skb->dev;
371 unsigned int logflags = 0;
372
373 if (info->type == NF_LOG_TYPE_LOG)
374 logflags = info->u.log.logflags;
375
376 if (!(logflags & IPT_LOG_MACDECODE))
377 goto fallback;
378
379 switch (dev->type) {
380 case ARPHRD_ETHER:
381 sb_add(m, "MACSRC=%pM MACDST=%pM MACPROTO=%04x ",
382 eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
383 ntohs(eth_hdr(skb)->h_proto));
384 return;
385 default:
386 break;
387 }
388
389fallback:
390 sb_add(m, "MAC=");
391 if (dev->hard_header_len &&
392 skb->mac_header != skb->network_header) {
393 const unsigned char *p = skb_mac_header(skb);
394 unsigned int i;
395
396 sb_add(m, "%02x", *p++);
397 for (i = 1; i < dev->hard_header_len; i++, p++)
398 sb_add(m, ":%02x", *p);
399 }
400 sb_add(m, " ");
401}
402
403static struct nf_loginfo default_loginfo = {
404 .type = NF_LOG_TYPE_LOG,
405 .u = {
406 .log = {
407 .level = 5,
408 .logflags = NF_LOG_MASK,
409 },
410 },
411};
412
413static void
414ipt_log_packet(u_int8_t pf,
415 unsigned int hooknum,
416 const struct sk_buff *skb,
417 const struct net_device *in,
418 const struct net_device *out,
419 const struct nf_loginfo *loginfo,
420 const char *prefix)
421{
422 struct sbuff *m = sb_open();
423
424 if (!loginfo)
425 loginfo = &default_loginfo;
426
427 sb_add(m, "<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
428 prefix,
429 in ? in->name : "",
430 out ? out->name : "");
431#ifdef CONFIG_BRIDGE_NETFILTER
432 if (skb->nf_bridge) {
433 const struct net_device *physindev;
434 const struct net_device *physoutdev;
435
436 physindev = skb->nf_bridge->physindev;
437 if (physindev && in != physindev)
438 sb_add(m, "PHYSIN=%s ", physindev->name);
439 physoutdev = skb->nf_bridge->physoutdev;
440 if (physoutdev && out != physoutdev)
441 sb_add(m, "PHYSOUT=%s ", physoutdev->name);
442 }
443#endif
444
445 if (in != NULL)
446 dump_mac_header(m, loginfo, skb);
447
448 dump_packet(m, loginfo, skb, 0);
449
450 sb_close(m);
451}
452
453static unsigned int
454log_tg(struct sk_buff *skb, const struct xt_action_param *par)
455{
456 const struct ipt_log_info *loginfo = par->targinfo;
457 struct nf_loginfo li;
458
459 li.type = NF_LOG_TYPE_LOG;
460 li.u.log.level = loginfo->level;
461 li.u.log.logflags = loginfo->logflags;
462
463 ipt_log_packet(NFPROTO_IPV4, par->hooknum, skb, par->in, par->out, &li,
464 loginfo->prefix);
465 return XT_CONTINUE;
466}
467
468static int log_tg_check(const struct xt_tgchk_param *par)
469{
470 const struct ipt_log_info *loginfo = par->targinfo;
471
472 if (loginfo->level >= 8) {
473 pr_debug("level %u >= 8\n", loginfo->level);
474 return -EINVAL;
475 }
476 if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
477 pr_debug("prefix is not null-terminated\n");
478 return -EINVAL;
479 }
480 return 0;
481}
482
483static struct xt_target log_tg_reg __read_mostly = {
484 .name = "LOG",
485 .family = NFPROTO_IPV4,
486 .target = log_tg,
487 .targetsize = sizeof(struct ipt_log_info),
488 .checkentry = log_tg_check,
489 .me = THIS_MODULE,
490};
491
492static struct nf_logger ipt_log_logger __read_mostly = {
493 .name = "ipt_LOG",
494 .logfn = &ipt_log_packet,
495 .me = THIS_MODULE,
496};
497
498static int __init log_tg_init(void)
499{
500 int ret;
501
502 ret = xt_register_target(&log_tg_reg);
503 if (ret < 0)
504 return ret;
505 nf_log_register(NFPROTO_IPV4, &ipt_log_logger);
506 return 0;
507}
508
509static void __exit log_tg_exit(void)
510{
511 nf_log_unregister(&ipt_log_logger);
512 xt_unregister_target(&log_tg_reg);
513}
514
515module_init(log_tg_init);
516module_exit(log_tg_exit);
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
new file mode 100644
index 00000000000..6cdb298f103
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -0,0 +1,98 @@
1/* NETMAP - static NAT mapping of IP network addresses (1:1).
2 * The mapping can be applied to source (POSTROUTING),
3 * destination (PREROUTING), or both (with separate rules).
4 */
5
6/* (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13#include <linux/ip.h>
14#include <linux/module.h>
15#include <linux/netdevice.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter_ipv4.h>
18#include <linux/netfilter/x_tables.h>
19#include <net/netfilter/nf_nat_rule.h>
20
21MODULE_LICENSE("GPL");
22MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>");
23MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of IPv4 subnets");
24
25static int netmap_tg_check(const struct xt_tgchk_param *par)
26{
27 const struct nf_nat_multi_range_compat *mr = par->targinfo;
28
29 if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
30 pr_debug("bad MAP_IPS.\n");
31 return -EINVAL;
32 }
33 if (mr->rangesize != 1) {
34 pr_debug("bad rangesize %u.\n", mr->rangesize);
35 return -EINVAL;
36 }
37 return 0;
38}
39
40static unsigned int
41netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
42{
43 struct nf_conn *ct;
44 enum ip_conntrack_info ctinfo;
45 __be32 new_ip, netmask;
46 const struct nf_nat_multi_range_compat *mr = par->targinfo;
47 struct nf_nat_range newrange;
48
49 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
50 par->hooknum == NF_INET_POST_ROUTING ||
51 par->hooknum == NF_INET_LOCAL_OUT ||
52 par->hooknum == NF_INET_LOCAL_IN);
53 ct = nf_ct_get(skb, &ctinfo);
54
55 netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
56
57 if (par->hooknum == NF_INET_PRE_ROUTING ||
58 par->hooknum == NF_INET_LOCAL_OUT)
59 new_ip = ip_hdr(skb)->daddr & ~netmask;
60 else
61 new_ip = ip_hdr(skb)->saddr & ~netmask;
62 new_ip |= mr->range[0].min_ip & netmask;
63
64 newrange = ((struct nf_nat_range)
65 { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
66 new_ip, new_ip,
67 mr->range[0].min, mr->range[0].max });
68
69 /* Hand modified range to generic setup. */
70 return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
71}
72
73static struct xt_target netmap_tg_reg __read_mostly = {
74 .name = "NETMAP",
75 .family = NFPROTO_IPV4,
76 .target = netmap_tg,
77 .targetsize = sizeof(struct nf_nat_multi_range_compat),
78 .table = "nat",
79 .hooks = (1 << NF_INET_PRE_ROUTING) |
80 (1 << NF_INET_POST_ROUTING) |
81 (1 << NF_INET_LOCAL_OUT) |
82 (1 << NF_INET_LOCAL_IN),
83 .checkentry = netmap_tg_check,
84 .me = THIS_MODULE
85};
86
87static int __init netmap_tg_init(void)
88{
89 return xt_register_target(&netmap_tg_reg);
90}
91
92static void __exit netmap_tg_exit(void)
93{
94 xt_unregister_target(&netmap_tg_reg);
95}
96
97module_init(netmap_tg_init);
98module_exit(netmap_tg_exit);
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
new file mode 100644
index 00000000000..18a0656505a
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -0,0 +1,110 @@
1/* Redirect. Simple mapping which alters dst to a local IP address. */
2/* (C) 1999-2001 Paul `Rusty' Russell
3 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10#include <linux/types.h>
11#include <linux/ip.h>
12#include <linux/timer.h>
13#include <linux/module.h>
14#include <linux/netfilter.h>
15#include <linux/netdevice.h>
16#include <linux/if.h>
17#include <linux/inetdevice.h>
18#include <net/protocol.h>
19#include <net/checksum.h>
20#include <linux/netfilter_ipv4.h>
21#include <linux/netfilter/x_tables.h>
22#include <net/netfilter/nf_nat_rule.h>
23
24MODULE_LICENSE("GPL");
25MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
26MODULE_DESCRIPTION("Xtables: Connection redirection to localhost");
27
28/* FIXME: Take multiple ranges --RR */
29static int redirect_tg_check(const struct xt_tgchk_param *par)
30{
31 const struct nf_nat_multi_range_compat *mr = par->targinfo;
32
33 if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
34 pr_debug("bad MAP_IPS.\n");
35 return -EINVAL;
36 }
37 if (mr->rangesize != 1) {
38 pr_debug("bad rangesize %u.\n", mr->rangesize);
39 return -EINVAL;
40 }
41 return 0;
42}
43
44static unsigned int
45redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
46{
47 struct nf_conn *ct;
48 enum ip_conntrack_info ctinfo;
49 __be32 newdst;
50 const struct nf_nat_multi_range_compat *mr = par->targinfo;
51 struct nf_nat_range newrange;
52
53 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
54 par->hooknum == NF_INET_LOCAL_OUT);
55
56 ct = nf_ct_get(skb, &ctinfo);
57 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
58
59 /* Local packets: make them go to loopback */
60 if (par->hooknum == NF_INET_LOCAL_OUT)
61 newdst = htonl(0x7F000001);
62 else {
63 struct in_device *indev;
64 struct in_ifaddr *ifa;
65
66 newdst = 0;
67
68 rcu_read_lock();
69 indev = __in_dev_get_rcu(skb->dev);
70 if (indev && (ifa = indev->ifa_list))
71 newdst = ifa->ifa_local;
72 rcu_read_unlock();
73
74 if (!newdst)
75 return NF_DROP;
76 }
77
78 /* Transfer from original range. */
79 newrange = ((struct nf_nat_range)
80 { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
81 newdst, newdst,
82 mr->range[0].min, mr->range[0].max });
83
84 /* Hand modified range to generic setup. */
85 return nf_nat_setup_info(ct, &newrange, IP_NAT_MANIP_DST);
86}
87
88static struct xt_target redirect_tg_reg __read_mostly = {
89 .name = "REDIRECT",
90 .family = NFPROTO_IPV4,
91 .target = redirect_tg,
92 .targetsize = sizeof(struct nf_nat_multi_range_compat),
93 .table = "nat",
94 .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT),
95 .checkentry = redirect_tg_check,
96 .me = THIS_MODULE,
97};
98
99static int __init redirect_tg_init(void)
100{
101 return xt_register_target(&redirect_tg_reg);
102}
103
104static void __exit redirect_tg_exit(void)
105{
106 xt_unregister_target(&redirect_tg_reg);
107}
108
109module_init(redirect_tg_init);
110module_exit(redirect_tg_exit);
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
new file mode 100644
index 00000000000..2b57e52c746
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_ecn.c
@@ -0,0 +1,127 @@
1/* IP tables module for matching the value of the IPv4 and TCP ECN bits
2 *
3 * (C) 2002 by Harald Welte <laforge@gnumonks.org>
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10#include <linux/in.h>
11#include <linux/ip.h>
12#include <net/ip.h>
13#include <linux/module.h>
14#include <linux/skbuff.h>
15#include <linux/tcp.h>
16
17#include <linux/netfilter/x_tables.h>
18#include <linux/netfilter_ipv4/ip_tables.h>
19#include <linux/netfilter_ipv4/ipt_ecn.h>
20
21MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
22MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match for IPv4");
23MODULE_LICENSE("GPL");
24
25static inline bool match_ip(const struct sk_buff *skb,
26 const struct ipt_ecn_info *einfo)
27{
28 return ((ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect) ^
29 !!(einfo->invert & IPT_ECN_OP_MATCH_IP);
30}
31
32static inline bool match_tcp(const struct sk_buff *skb,
33 const struct ipt_ecn_info *einfo,
34 bool *hotdrop)
35{
36 struct tcphdr _tcph;
37 const struct tcphdr *th;
38
39 /* In practice, TCP match does this, so can't fail. But let's
40 * be good citizens.
41 */
42 th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
43 if (th == NULL) {
44 *hotdrop = false;
45 return false;
46 }
47
48 if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
49 if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
50 if (th->ece == 1)
51 return false;
52 } else {
53 if (th->ece == 0)
54 return false;
55 }
56 }
57
58 if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
59 if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
60 if (th->cwr == 1)
61 return false;
62 } else {
63 if (th->cwr == 0)
64 return false;
65 }
66 }
67
68 return true;
69}
70
71static bool ecn_mt(const struct sk_buff *skb, struct xt_action_param *par)
72{
73 const struct ipt_ecn_info *info = par->matchinfo;
74
75 if (info->operation & IPT_ECN_OP_MATCH_IP)
76 if (!match_ip(skb, info))
77 return false;
78
79 if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
80 if (!match_tcp(skb, info, &par->hotdrop))
81 return false;
82 }
83
84 return true;
85}
86
87static int ecn_mt_check(const struct xt_mtchk_param *par)
88{
89 const struct ipt_ecn_info *info = par->matchinfo;
90 const struct ipt_ip *ip = par->entryinfo;
91
92 if (info->operation & IPT_ECN_OP_MATCH_MASK)
93 return -EINVAL;
94
95 if (info->invert & IPT_ECN_OP_MATCH_MASK)
96 return -EINVAL;
97
98 if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR) &&
99 (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) {
100 pr_info("cannot match TCP bits in rule for non-tcp packets\n");
101 return -EINVAL;
102 }
103
104 return 0;
105}
106
107static struct xt_match ecn_mt_reg __read_mostly = {
108 .name = "ecn",
109 .family = NFPROTO_IPV4,
110 .match = ecn_mt,
111 .matchsize = sizeof(struct ipt_ecn_info),
112 .checkentry = ecn_mt_check,
113 .me = THIS_MODULE,
114};
115
116static int __init ecn_mt_init(void)
117{
118 return xt_register_match(&ecn_mt_reg);
119}
120
121static void __exit ecn_mt_exit(void)
122{
123 xt_unregister_match(&ecn_mt_reg);
124}
125
126module_init(ecn_mt_init);
127module_exit(ecn_mt_exit);
diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c
new file mode 100644
index 00000000000..703f366fd23
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_amanda.c
@@ -0,0 +1,85 @@
1/* Amanda extension for TCP NAT alteration.
2 * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
3 * based on a copy of HW's ip_nat_irc.c as well as other modules
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/skbuff.h>
14#include <linux/udp.h>
15
16#include <net/netfilter/nf_nat_helper.h>
17#include <net/netfilter/nf_nat_rule.h>
18#include <net/netfilter/nf_conntrack_helper.h>
19#include <net/netfilter/nf_conntrack_expect.h>
20#include <linux/netfilter/nf_conntrack_amanda.h>
21
22MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
23MODULE_DESCRIPTION("Amanda NAT helper");
24MODULE_LICENSE("GPL");
25MODULE_ALIAS("ip_nat_amanda");
26
27static unsigned int help(struct sk_buff *skb,
28 enum ip_conntrack_info ctinfo,
29 unsigned int matchoff,
30 unsigned int matchlen,
31 struct nf_conntrack_expect *exp)
32{
33 char buffer[sizeof("65535")];
34 u_int16_t port;
35 unsigned int ret;
36
37 /* Connection comes from client. */
38 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
39 exp->dir = IP_CT_DIR_ORIGINAL;
40
41 /* When you see the packet, we need to NAT it the same as the
42 * this one (ie. same IP: it will be TCP and master is UDP). */
43 exp->expectfn = nf_nat_follow_master;
44
45 /* Try to get same port: if not, try to change it. */
46 for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
47 int res;
48
49 exp->tuple.dst.u.tcp.port = htons(port);
50 res = nf_ct_expect_related(exp);
51 if (res == 0)
52 break;
53 else if (res != -EBUSY) {
54 port = 0;
55 break;
56 }
57 }
58
59 if (port == 0)
60 return NF_DROP;
61
62 sprintf(buffer, "%u", port);
63 ret = nf_nat_mangle_udp_packet(skb, exp->master, ctinfo,
64 matchoff, matchlen,
65 buffer, strlen(buffer));
66 if (ret != NF_ACCEPT)
67 nf_ct_unexpect_related(exp);
68 return ret;
69}
70
71static void __exit nf_nat_amanda_fini(void)
72{
73 rcu_assign_pointer(nf_nat_amanda_hook, NULL);
74 synchronize_rcu();
75}
76
77static int __init nf_nat_amanda_init(void)
78{
79 BUG_ON(nf_nat_amanda_hook != NULL);
80 rcu_assign_pointer(nf_nat_amanda_hook, help);
81 return 0;
82}
83
84module_init(nf_nat_amanda_init);
85module_exit(nf_nat_amanda_fini);
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
new file mode 100644
index 00000000000..3346de5d94d
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -0,0 +1,779 @@
1/* NAT for netfilter; shared with compatibility layer. */
2
3/* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/types.h>
13#include <linux/timer.h>
14#include <linux/skbuff.h>
15#include <linux/gfp.h>
16#include <net/checksum.h>
17#include <net/icmp.h>
18#include <net/ip.h>
19#include <net/tcp.h> /* For tcp_prot in getorigdst */
20#include <linux/icmp.h>
21#include <linux/udp.h>
22#include <linux/jhash.h>
23
24#include <linux/netfilter_ipv4.h>
25#include <net/netfilter/nf_conntrack.h>
26#include <net/netfilter/nf_conntrack_core.h>
27#include <net/netfilter/nf_nat.h>
28#include <net/netfilter/nf_nat_protocol.h>
29#include <net/netfilter/nf_nat_core.h>
30#include <net/netfilter/nf_nat_helper.h>
31#include <net/netfilter/nf_conntrack_helper.h>
32#include <net/netfilter/nf_conntrack_l3proto.h>
33#include <net/netfilter/nf_conntrack_l4proto.h>
34#include <net/netfilter/nf_conntrack_zones.h>
35
36static DEFINE_SPINLOCK(nf_nat_lock);
37
38static struct nf_conntrack_l3proto *l3proto __read_mostly;
39
40#define MAX_IP_NAT_PROTO 256
41static const struct nf_nat_protocol __rcu *nf_nat_protos[MAX_IP_NAT_PROTO]
42 __read_mostly;
43
44static inline const struct nf_nat_protocol *
45__nf_nat_proto_find(u_int8_t protonum)
46{
47 return rcu_dereference(nf_nat_protos[protonum]);
48}
49
50/* We keep an extra hash for each conntrack, for fast searching. */
51static inline unsigned int
52hash_by_src(const struct net *net, u16 zone,
53 const struct nf_conntrack_tuple *tuple)
54{
55 unsigned int hash;
56
57 /* Original src, to ensure we map it consistently if poss. */
58 hash = jhash_3words((__force u32)tuple->src.u3.ip,
59 (__force u32)tuple->src.u.all ^ zone,
60 tuple->dst.protonum, 0);
61 return ((u64)hash * net->ipv4.nat_htable_size) >> 32;
62}
63
64/* Is this tuple already taken? (not by us) */
65int
66nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
67 const struct nf_conn *ignored_conntrack)
68{
69 /* Conntrack tracking doesn't keep track of outgoing tuples; only
70 incoming ones. NAT means they don't have a fixed mapping,
71 so we invert the tuple and look for the incoming reply.
72
73 We could keep a separate hash if this proves too slow. */
74 struct nf_conntrack_tuple reply;
75
76 nf_ct_invert_tuplepr(&reply, tuple);
77 return nf_conntrack_tuple_taken(&reply, ignored_conntrack);
78}
79EXPORT_SYMBOL(nf_nat_used_tuple);
80
81/* If we source map this tuple so reply looks like reply_tuple, will
82 * that meet the constraints of range. */
83static int
84in_range(const struct nf_conntrack_tuple *tuple,
85 const struct nf_nat_range *range)
86{
87 const struct nf_nat_protocol *proto;
88 int ret = 0;
89
90 /* If we are supposed to map IPs, then we must be in the
91 range specified, otherwise let this drag us onto a new src IP. */
92 if (range->flags & IP_NAT_RANGE_MAP_IPS) {
93 if (ntohl(tuple->src.u3.ip) < ntohl(range->min_ip) ||
94 ntohl(tuple->src.u3.ip) > ntohl(range->max_ip))
95 return 0;
96 }
97
98 rcu_read_lock();
99 proto = __nf_nat_proto_find(tuple->dst.protonum);
100 if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) ||
101 proto->in_range(tuple, IP_NAT_MANIP_SRC,
102 &range->min, &range->max))
103 ret = 1;
104 rcu_read_unlock();
105
106 return ret;
107}
108
109static inline int
110same_src(const struct nf_conn *ct,
111 const struct nf_conntrack_tuple *tuple)
112{
113 const struct nf_conntrack_tuple *t;
114
115 t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
116 return (t->dst.protonum == tuple->dst.protonum &&
117 t->src.u3.ip == tuple->src.u3.ip &&
118 t->src.u.all == tuple->src.u.all);
119}
120
121/* Only called for SRC manip */
122static int
123find_appropriate_src(struct net *net, u16 zone,
124 const struct nf_conntrack_tuple *tuple,
125 struct nf_conntrack_tuple *result,
126 const struct nf_nat_range *range)
127{
128 unsigned int h = hash_by_src(net, zone, tuple);
129 const struct nf_conn_nat *nat;
130 const struct nf_conn *ct;
131 const struct hlist_node *n;
132
133 rcu_read_lock();
134 hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
135 ct = nat->ct;
136 if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) {
137 /* Copy source part from reply tuple. */
138 nf_ct_invert_tuplepr(result,
139 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
140 result->dst = tuple->dst;
141
142 if (in_range(result, range)) {
143 rcu_read_unlock();
144 return 1;
145 }
146 }
147 }
148 rcu_read_unlock();
149 return 0;
150}
151
152/* For [FUTURE] fragmentation handling, we want the least-used
153 src-ip/dst-ip/proto triple. Fairness doesn't come into it. Thus
154 if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
155 1-65535, we don't do pro-rata allocation based on ports; we choose
156 the ip with the lowest src-ip/dst-ip/proto usage.
157*/
158static void
159find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
160 const struct nf_nat_range *range,
161 const struct nf_conn *ct,
162 enum nf_nat_manip_type maniptype)
163{
164 __be32 *var_ipp;
165 /* Host order */
166 u_int32_t minip, maxip, j;
167
168 /* No IP mapping? Do nothing. */
169 if (!(range->flags & IP_NAT_RANGE_MAP_IPS))
170 return;
171
172 if (maniptype == IP_NAT_MANIP_SRC)
173 var_ipp = &tuple->src.u3.ip;
174 else
175 var_ipp = &tuple->dst.u3.ip;
176
177 /* Fast path: only one choice. */
178 if (range->min_ip == range->max_ip) {
179 *var_ipp = range->min_ip;
180 return;
181 }
182
183 /* Hashing source and destination IPs gives a fairly even
184 * spread in practice (if there are a small number of IPs
185 * involved, there usually aren't that many connections
186 * anyway). The consistency means that servers see the same
187 * client coming from the same IP (some Internet Banking sites
188 * like this), even across reboots. */
189 minip = ntohl(range->min_ip);
190 maxip = ntohl(range->max_ip);
191 j = jhash_2words((__force u32)tuple->src.u3.ip,
192 range->flags & IP_NAT_RANGE_PERSISTENT ?
193 0 : (__force u32)tuple->dst.u3.ip ^ zone, 0);
194 j = ((u64)j * (maxip - minip + 1)) >> 32;
195 *var_ipp = htonl(minip + j);
196}
197
198/* Manipulate the tuple into the range given. For NF_INET_POST_ROUTING,
199 * we change the source to map into the range. For NF_INET_PRE_ROUTING
200 * and NF_INET_LOCAL_OUT, we change the destination to map into the
201 * range. It might not be possible to get a unique tuple, but we try.
202 * At worst (or if we race), we will end up with a final duplicate in
203 * __ip_conntrack_confirm and drop the packet. */
204static void
205get_unique_tuple(struct nf_conntrack_tuple *tuple,
206 const struct nf_conntrack_tuple *orig_tuple,
207 const struct nf_nat_range *range,
208 struct nf_conn *ct,
209 enum nf_nat_manip_type maniptype)
210{
211 struct net *net = nf_ct_net(ct);
212 const struct nf_nat_protocol *proto;
213 u16 zone = nf_ct_zone(ct);
214
215 /* 1) If this srcip/proto/src-proto-part is currently mapped,
216 and that same mapping gives a unique tuple within the given
217 range, use that.
218
219 This is only required for source (ie. NAT/masq) mappings.
220 So far, we don't do local source mappings, so multiple
221 manips not an issue. */
222 if (maniptype == IP_NAT_MANIP_SRC &&
223 !(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
224 /* try the original tuple first */
225 if (in_range(orig_tuple, range)) {
226 if (!nf_nat_used_tuple(orig_tuple, ct)) {
227 *tuple = *orig_tuple;
228 return;
229 }
230 } else if (find_appropriate_src(net, zone, orig_tuple, tuple,
231 range)) {
232 pr_debug("get_unique_tuple: Found current src map\n");
233 if (!nf_nat_used_tuple(tuple, ct))
234 return;
235 }
236 }
237
238 /* 2) Select the least-used IP/proto combination in the given
239 range. */
240 *tuple = *orig_tuple;
241 find_best_ips_proto(zone, tuple, range, ct, maniptype);
242
243 /* 3) The per-protocol part of the manip is made to map into
244 the range to make a unique tuple. */
245
246 rcu_read_lock();
247 proto = __nf_nat_proto_find(orig_tuple->dst.protonum);
248
249 /* Only bother mapping if it's not already in range and unique */
250 if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
251 if (range->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
252 if (proto->in_range(tuple, maniptype, &range->min,
253 &range->max) &&
254 (range->min.all == range->max.all ||
255 !nf_nat_used_tuple(tuple, ct)))
256 goto out;
257 } else if (!nf_nat_used_tuple(tuple, ct)) {
258 goto out;
259 }
260 }
261
262 /* Last change: get protocol to try to obtain unique tuple. */
263 proto->unique_tuple(tuple, range, maniptype, ct);
264out:
265 rcu_read_unlock();
266}
267
268unsigned int
269nf_nat_setup_info(struct nf_conn *ct,
270 const struct nf_nat_range *range,
271 enum nf_nat_manip_type maniptype)
272{
273 struct net *net = nf_ct_net(ct);
274 struct nf_conntrack_tuple curr_tuple, new_tuple;
275 struct nf_conn_nat *nat;
276
277 /* nat helper or nfctnetlink also setup binding */
278 nat = nfct_nat(ct);
279 if (!nat) {
280 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
281 if (nat == NULL) {
282 pr_debug("failed to add NAT extension\n");
283 return NF_ACCEPT;
284 }
285 }
286
287 NF_CT_ASSERT(maniptype == IP_NAT_MANIP_SRC ||
288 maniptype == IP_NAT_MANIP_DST);
289 BUG_ON(nf_nat_initialized(ct, maniptype));
290
291 /* What we've got will look like inverse of reply. Normally
292 this is what is in the conntrack, except for prior
293 manipulations (future optimization: if num_manips == 0,
294 orig_tp =
295 conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple) */
296 nf_ct_invert_tuplepr(&curr_tuple,
297 &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
298
299 get_unique_tuple(&new_tuple, &curr_tuple, range, ct, maniptype);
300
301 if (!nf_ct_tuple_equal(&new_tuple, &curr_tuple)) {
302 struct nf_conntrack_tuple reply;
303
304 /* Alter conntrack table so will recognize replies. */
305 nf_ct_invert_tuplepr(&reply, &new_tuple);
306 nf_conntrack_alter_reply(ct, &reply);
307
308 /* Non-atomic: we own this at the moment. */
309 if (maniptype == IP_NAT_MANIP_SRC)
310 ct->status |= IPS_SRC_NAT;
311 else
312 ct->status |= IPS_DST_NAT;
313 }
314
315 if (maniptype == IP_NAT_MANIP_SRC) {
316 unsigned int srchash;
317
318 srchash = hash_by_src(net, nf_ct_zone(ct),
319 &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
320 spin_lock_bh(&nf_nat_lock);
321 /* nf_conntrack_alter_reply might re-allocate exntension aera */
322 nat = nfct_nat(ct);
323 nat->ct = ct;
324 hlist_add_head_rcu(&nat->bysource,
325 &net->ipv4.nat_bysource[srchash]);
326 spin_unlock_bh(&nf_nat_lock);
327 }
328
329 /* It's done. */
330 if (maniptype == IP_NAT_MANIP_DST)
331 ct->status |= IPS_DST_NAT_DONE;
332 else
333 ct->status |= IPS_SRC_NAT_DONE;
334
335 return NF_ACCEPT;
336}
337EXPORT_SYMBOL(nf_nat_setup_info);
338
339/* Returns true if succeeded. */
340static bool
341manip_pkt(u_int16_t proto,
342 struct sk_buff *skb,
343 unsigned int iphdroff,
344 const struct nf_conntrack_tuple *target,
345 enum nf_nat_manip_type maniptype)
346{
347 struct iphdr *iph;
348 const struct nf_nat_protocol *p;
349
350 if (!skb_make_writable(skb, iphdroff + sizeof(*iph)))
351 return false;
352
353 iph = (void *)skb->data + iphdroff;
354
355 /* Manipulate protcol part. */
356
357 /* rcu_read_lock()ed by nf_hook_slow */
358 p = __nf_nat_proto_find(proto);
359 if (!p->manip_pkt(skb, iphdroff, target, maniptype))
360 return false;
361
362 iph = (void *)skb->data + iphdroff;
363
364 if (maniptype == IP_NAT_MANIP_SRC) {
365 csum_replace4(&iph->check, iph->saddr, target->src.u3.ip);
366 iph->saddr = target->src.u3.ip;
367 } else {
368 csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip);
369 iph->daddr = target->dst.u3.ip;
370 }
371 return true;
372}
373
374/* Do packet manipulations according to nf_nat_setup_info. */
375unsigned int nf_nat_packet(struct nf_conn *ct,
376 enum ip_conntrack_info ctinfo,
377 unsigned int hooknum,
378 struct sk_buff *skb)
379{
380 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
381 unsigned long statusbit;
382 enum nf_nat_manip_type mtype = HOOK2MANIP(hooknum);
383
384 if (mtype == IP_NAT_MANIP_SRC)
385 statusbit = IPS_SRC_NAT;
386 else
387 statusbit = IPS_DST_NAT;
388
389 /* Invert if this is reply dir. */
390 if (dir == IP_CT_DIR_REPLY)
391 statusbit ^= IPS_NAT_MASK;
392
393 /* Non-atomic: these bits don't change. */
394 if (ct->status & statusbit) {
395 struct nf_conntrack_tuple target;
396
397 /* We are aiming to look like inverse of other direction. */
398 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
399
400 if (!manip_pkt(target.dst.protonum, skb, 0, &target, mtype))
401 return NF_DROP;
402 }
403 return NF_ACCEPT;
404}
405EXPORT_SYMBOL_GPL(nf_nat_packet);
406
407/* Dir is direction ICMP is coming from (opposite to packet it contains) */
408int nf_nat_icmp_reply_translation(struct nf_conn *ct,
409 enum ip_conntrack_info ctinfo,
410 unsigned int hooknum,
411 struct sk_buff *skb)
412{
413 struct {
414 struct icmphdr icmp;
415 struct iphdr ip;
416 } *inside;
417 const struct nf_conntrack_l4proto *l4proto;
418 struct nf_conntrack_tuple inner, target;
419 int hdrlen = ip_hdrlen(skb);
420 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
421 unsigned long statusbit;
422 enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
423
424 if (!skb_make_writable(skb, hdrlen + sizeof(*inside)))
425 return 0;
426
427 inside = (void *)skb->data + hdrlen;
428
429 /* We're actually going to mangle it beyond trivial checksum
430 adjustment, so make sure the current checksum is correct. */
431 if (nf_ip_checksum(skb, hooknum, hdrlen, 0))
432 return 0;
433
434 /* Must be RELATED */
435 NF_CT_ASSERT(skb->nfctinfo == IP_CT_RELATED ||
436 skb->nfctinfo == IP_CT_RELATED_REPLY);
437
438 /* Redirects on non-null nats must be dropped, else they'll
439 start talking to each other without our translation, and be
440 confused... --RR */
441 if (inside->icmp.type == ICMP_REDIRECT) {
442 /* If NAT isn't finished, assume it and drop. */
443 if ((ct->status & IPS_NAT_DONE_MASK) != IPS_NAT_DONE_MASK)
444 return 0;
445
446 if (ct->status & IPS_NAT_MASK)
447 return 0;
448 }
449
450 if (manip == IP_NAT_MANIP_SRC)
451 statusbit = IPS_SRC_NAT;
452 else
453 statusbit = IPS_DST_NAT;
454
455 /* Invert if this is reply dir. */
456 if (dir == IP_CT_DIR_REPLY)
457 statusbit ^= IPS_NAT_MASK;
458
459 if (!(ct->status & statusbit))
460 return 1;
461
462 pr_debug("icmp_reply_translation: translating error %p manip %u "
463 "dir %s\n", skb, manip,
464 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
465
466 /* rcu_read_lock()ed by nf_hook_slow */
467 l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
468
469 if (!nf_ct_get_tuple(skb, hdrlen + sizeof(struct icmphdr),
470 (hdrlen +
471 sizeof(struct icmphdr) + inside->ip.ihl * 4),
472 (u_int16_t)AF_INET, inside->ip.protocol,
473 &inner, l3proto, l4proto))
474 return 0;
475
476 /* Change inner back to look like incoming packet. We do the
477 opposite manip on this hook to normal, because it might not
478 pass all hooks (locally-generated ICMP). Consider incoming
479 packet: PREROUTING (DST manip), routing produces ICMP, goes
480 through POSTROUTING (which must correct the DST manip). */
481 if (!manip_pkt(inside->ip.protocol, skb, hdrlen + sizeof(inside->icmp),
482 &ct->tuplehash[!dir].tuple, !manip))
483 return 0;
484
485 if (skb->ip_summed != CHECKSUM_PARTIAL) {
486 /* Reloading "inside" here since manip_pkt inner. */
487 inside = (void *)skb->data + hdrlen;
488 inside->icmp.checksum = 0;
489 inside->icmp.checksum =
490 csum_fold(skb_checksum(skb, hdrlen,
491 skb->len - hdrlen, 0));
492 }
493
494 /* Change outer to look the reply to an incoming packet
495 * (proto 0 means don't invert per-proto part). */
496 nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
497 if (!manip_pkt(0, skb, 0, &target, manip))
498 return 0;
499
500 return 1;
501}
502EXPORT_SYMBOL_GPL(nf_nat_icmp_reply_translation);
503
504/* Protocol registration. */
505int nf_nat_protocol_register(const struct nf_nat_protocol *proto)
506{
507 int ret = 0;
508
509 spin_lock_bh(&nf_nat_lock);
510 if (rcu_dereference_protected(
511 nf_nat_protos[proto->protonum],
512 lockdep_is_held(&nf_nat_lock)
513 ) != &nf_nat_unknown_protocol) {
514 ret = -EBUSY;
515 goto out;
516 }
517 rcu_assign_pointer(nf_nat_protos[proto->protonum], proto);
518 out:
519 spin_unlock_bh(&nf_nat_lock);
520 return ret;
521}
522EXPORT_SYMBOL(nf_nat_protocol_register);
523
524/* No one stores the protocol anywhere; simply delete it. */
525void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto)
526{
527 spin_lock_bh(&nf_nat_lock);
528 rcu_assign_pointer(nf_nat_protos[proto->protonum],
529 &nf_nat_unknown_protocol);
530 spin_unlock_bh(&nf_nat_lock);
531 synchronize_rcu();
532}
533EXPORT_SYMBOL(nf_nat_protocol_unregister);
534
535/* No one using conntrack by the time this called. */
536static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
537{
538 struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
539
540 if (nat == NULL || nat->ct == NULL)
541 return;
542
543 NF_CT_ASSERT(nat->ct->status & IPS_SRC_NAT_DONE);
544
545 spin_lock_bh(&nf_nat_lock);
546 hlist_del_rcu(&nat->bysource);
547 spin_unlock_bh(&nf_nat_lock);
548}
549
550static void nf_nat_move_storage(void *new, void *old)
551{
552 struct nf_conn_nat *new_nat = new;
553 struct nf_conn_nat *old_nat = old;
554 struct nf_conn *ct = old_nat->ct;
555
556 if (!ct || !(ct->status & IPS_SRC_NAT_DONE))
557 return;
558
559 spin_lock_bh(&nf_nat_lock);
560 hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource);
561 spin_unlock_bh(&nf_nat_lock);
562}
563
564static struct nf_ct_ext_type nat_extend __read_mostly = {
565 .len = sizeof(struct nf_conn_nat),
566 .align = __alignof__(struct nf_conn_nat),
567 .destroy = nf_nat_cleanup_conntrack,
568 .move = nf_nat_move_storage,
569 .id = NF_CT_EXT_NAT,
570 .flags = NF_CT_EXT_F_PREALLOC,
571};
572
573#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
574
575#include <linux/netfilter/nfnetlink.h>
576#include <linux/netfilter/nfnetlink_conntrack.h>
577
578static const struct nf_nat_protocol *
579nf_nat_proto_find_get(u_int8_t protonum)
580{
581 const struct nf_nat_protocol *p;
582
583 rcu_read_lock();
584 p = __nf_nat_proto_find(protonum);
585 if (!try_module_get(p->me))
586 p = &nf_nat_unknown_protocol;
587 rcu_read_unlock();
588
589 return p;
590}
591
592static void
593nf_nat_proto_put(const struct nf_nat_protocol *p)
594{
595 module_put(p->me);
596}
597
598static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
599 [CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
600 [CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
601};
602
603static int nfnetlink_parse_nat_proto(struct nlattr *attr,
604 const struct nf_conn *ct,
605 struct nf_nat_range *range)
606{
607 struct nlattr *tb[CTA_PROTONAT_MAX+1];
608 const struct nf_nat_protocol *npt;
609 int err;
610
611 err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
612 if (err < 0)
613 return err;
614
615 npt = nf_nat_proto_find_get(nf_ct_protonum(ct));
616 if (npt->nlattr_to_range)
617 err = npt->nlattr_to_range(tb, range);
618 nf_nat_proto_put(npt);
619 return err;
620}
621
622static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = {
623 [CTA_NAT_MINIP] = { .type = NLA_U32 },
624 [CTA_NAT_MAXIP] = { .type = NLA_U32 },
625};
626
627static int
628nfnetlink_parse_nat(const struct nlattr *nat,
629 const struct nf_conn *ct, struct nf_nat_range *range)
630{
631 struct nlattr *tb[CTA_NAT_MAX+1];
632 int err;
633
634 memset(range, 0, sizeof(*range));
635
636 err = nla_parse_nested(tb, CTA_NAT_MAX, nat, nat_nla_policy);
637 if (err < 0)
638 return err;
639
640 if (tb[CTA_NAT_MINIP])
641 range->min_ip = nla_get_be32(tb[CTA_NAT_MINIP]);
642
643 if (!tb[CTA_NAT_MAXIP])
644 range->max_ip = range->min_ip;
645 else
646 range->max_ip = nla_get_be32(tb[CTA_NAT_MAXIP]);
647
648 if (range->min_ip)
649 range->flags |= IP_NAT_RANGE_MAP_IPS;
650
651 if (!tb[CTA_NAT_PROTO])
652 return 0;
653
654 err = nfnetlink_parse_nat_proto(tb[CTA_NAT_PROTO], ct, range);
655 if (err < 0)
656 return err;
657
658 return 0;
659}
660
661static int
662nfnetlink_parse_nat_setup(struct nf_conn *ct,
663 enum nf_nat_manip_type manip,
664 const struct nlattr *attr)
665{
666 struct nf_nat_range range;
667
668 if (nfnetlink_parse_nat(attr, ct, &range) < 0)
669 return -EINVAL;
670 if (nf_nat_initialized(ct, manip))
671 return -EEXIST;
672
673 return nf_nat_setup_info(ct, &range, manip);
674}
675#else
676static int
677nfnetlink_parse_nat_setup(struct nf_conn *ct,
678 enum nf_nat_manip_type manip,
679 const struct nlattr *attr)
680{
681 return -EOPNOTSUPP;
682}
683#endif
684
685static int __net_init nf_nat_net_init(struct net *net)
686{
687 /* Leave them the same for the moment. */
688 net->ipv4.nat_htable_size = net->ct.htable_size;
689 net->ipv4.nat_bysource = nf_ct_alloc_hashtable(&net->ipv4.nat_htable_size, 0);
690 if (!net->ipv4.nat_bysource)
691 return -ENOMEM;
692 return 0;
693}
694
695/* Clear NAT section of all conntracks, in case we're loaded again. */
696static int clean_nat(struct nf_conn *i, void *data)
697{
698 struct nf_conn_nat *nat = nfct_nat(i);
699
700 if (!nat)
701 return 0;
702 memset(nat, 0, sizeof(*nat));
703 i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
704 return 0;
705}
706
707static void __net_exit nf_nat_net_exit(struct net *net)
708{
709 nf_ct_iterate_cleanup(net, &clean_nat, NULL);
710 synchronize_rcu();
711 nf_ct_free_hashtable(net->ipv4.nat_bysource, net->ipv4.nat_htable_size);
712}
713
714static struct pernet_operations nf_nat_net_ops = {
715 .init = nf_nat_net_init,
716 .exit = nf_nat_net_exit,
717};
718
719static int __init nf_nat_init(void)
720{
721 size_t i;
722 int ret;
723
724 need_ipv4_conntrack();
725
726 ret = nf_ct_extend_register(&nat_extend);
727 if (ret < 0) {
728 printk(KERN_ERR "nf_nat_core: Unable to register extension\n");
729 return ret;
730 }
731
732 ret = register_pernet_subsys(&nf_nat_net_ops);
733 if (ret < 0)
734 goto cleanup_extend;
735
736 /* Sew in builtin protocols. */
737 spin_lock_bh(&nf_nat_lock);
738 for (i = 0; i < MAX_IP_NAT_PROTO; i++)
739 rcu_assign_pointer(nf_nat_protos[i], &nf_nat_unknown_protocol);
740 rcu_assign_pointer(nf_nat_protos[IPPROTO_TCP], &nf_nat_protocol_tcp);
741 rcu_assign_pointer(nf_nat_protos[IPPROTO_UDP], &nf_nat_protocol_udp);
742 rcu_assign_pointer(nf_nat_protos[IPPROTO_ICMP], &nf_nat_protocol_icmp);
743 spin_unlock_bh(&nf_nat_lock);
744
745 /* Initialize fake conntrack so that NAT will skip it */
746 nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
747
748 l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
749
750 BUG_ON(nf_nat_seq_adjust_hook != NULL);
751 rcu_assign_pointer(nf_nat_seq_adjust_hook, nf_nat_seq_adjust);
752 BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
753 rcu_assign_pointer(nfnetlink_parse_nat_setup_hook,
754 nfnetlink_parse_nat_setup);
755 BUG_ON(nf_ct_nat_offset != NULL);
756 rcu_assign_pointer(nf_ct_nat_offset, nf_nat_get_offset);
757 return 0;
758
759 cleanup_extend:
760 nf_ct_extend_unregister(&nat_extend);
761 return ret;
762}
763
764static void __exit nf_nat_cleanup(void)
765{
766 unregister_pernet_subsys(&nf_nat_net_ops);
767 nf_ct_l3proto_put(l3proto);
768 nf_ct_extend_unregister(&nat_extend);
769 rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL);
770 rcu_assign_pointer(nfnetlink_parse_nat_setup_hook, NULL);
771 rcu_assign_pointer(nf_ct_nat_offset, NULL);
772 synchronize_net();
773}
774
775MODULE_LICENSE("GPL");
776MODULE_ALIAS("nf-nat-ipv4");
777
778module_init(nf_nat_init);
779module_exit(nf_nat_cleanup);
diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c
new file mode 100644
index 00000000000..dc73abb3fe2
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_ftp.c
@@ -0,0 +1,137 @@
1/* FTP extension for TCP NAT alteration. */
2
3/* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/moduleparam.h>
13#include <linux/ip.h>
14#include <linux/tcp.h>
15#include <linux/netfilter_ipv4.h>
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_helper.h>
18#include <net/netfilter/nf_nat_rule.h>
19#include <net/netfilter/nf_conntrack_helper.h>
20#include <net/netfilter/nf_conntrack_expect.h>
21#include <linux/netfilter/nf_conntrack_ftp.h>
22
23MODULE_LICENSE("GPL");
24MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
25MODULE_DESCRIPTION("ftp NAT helper");
26MODULE_ALIAS("ip_nat_ftp");
27
28/* FIXME: Time out? --RR */
29
30static int nf_nat_ftp_fmt_cmd(enum nf_ct_ftp_type type,
31 char *buffer, size_t buflen,
32 __be32 addr, u16 port)
33{
34 switch (type) {
35 case NF_CT_FTP_PORT:
36 case NF_CT_FTP_PASV:
37 return snprintf(buffer, buflen, "%u,%u,%u,%u,%u,%u",
38 ((unsigned char *)&addr)[0],
39 ((unsigned char *)&addr)[1],
40 ((unsigned char *)&addr)[2],
41 ((unsigned char *)&addr)[3],
42 port >> 8,
43 port & 0xFF);
44 case NF_CT_FTP_EPRT:
45 return snprintf(buffer, buflen, "|1|%pI4|%u|", &addr, port);
46 case NF_CT_FTP_EPSV:
47 return snprintf(buffer, buflen, "|||%u|", port);
48 }
49
50 return 0;
51}
52
53/* So, this packet has hit the connection tracking matching code.
54 Mangle it, and change the expectation to match the new version. */
55static unsigned int nf_nat_ftp(struct sk_buff *skb,
56 enum ip_conntrack_info ctinfo,
57 enum nf_ct_ftp_type type,
58 unsigned int matchoff,
59 unsigned int matchlen,
60 struct nf_conntrack_expect *exp)
61{
62 __be32 newip;
63 u_int16_t port;
64 int dir = CTINFO2DIR(ctinfo);
65 struct nf_conn *ct = exp->master;
66 char buffer[sizeof("|1|255.255.255.255|65535|")];
67 unsigned int buflen;
68
69 pr_debug("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);
70
71 /* Connection will come from wherever this packet goes, hence !dir */
72 newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
73 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
74 exp->dir = !dir;
75
76 /* When you see the packet, we need to NAT it the same as the
77 * this one. */
78 exp->expectfn = nf_nat_follow_master;
79
80 /* Try to get same port: if not, try to change it. */
81 for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
82 int ret;
83
84 exp->tuple.dst.u.tcp.port = htons(port);
85 ret = nf_ct_expect_related(exp);
86 if (ret == 0)
87 break;
88 else if (ret != -EBUSY) {
89 port = 0;
90 break;
91 }
92 }
93
94 if (port == 0)
95 return NF_DROP;
96
97 buflen = nf_nat_ftp_fmt_cmd(type, buffer, sizeof(buffer), newip, port);
98 if (!buflen)
99 goto out;
100
101 pr_debug("calling nf_nat_mangle_tcp_packet\n");
102
103 if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, matchoff,
104 matchlen, buffer, buflen))
105 goto out;
106
107 return NF_ACCEPT;
108
109out:
110 nf_ct_unexpect_related(exp);
111 return NF_DROP;
112}
113
114static void __exit nf_nat_ftp_fini(void)
115{
116 rcu_assign_pointer(nf_nat_ftp_hook, NULL);
117 synchronize_rcu();
118}
119
120static int __init nf_nat_ftp_init(void)
121{
122 BUG_ON(nf_nat_ftp_hook != NULL);
123 rcu_assign_pointer(nf_nat_ftp_hook, nf_nat_ftp);
124 return 0;
125}
126
127/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */
128static int warn_set(const char *val, struct kernel_param *kp)
129{
130 printk(KERN_INFO KBUILD_MODNAME
131 ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
132 return 0;
133}
134module_param_call(ports, warn_set, NULL, NULL, 0);
135
136module_init(nf_nat_ftp_init);
137module_exit(nf_nat_ftp_fini);
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
new file mode 100644
index 00000000000..ebc5f8894f9
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -0,0 +1,451 @@
1/* ip_nat_helper.c - generic support functions for NAT helpers
2 *
3 * (C) 2000-2002 Harald Welte <laforge@netfilter.org>
4 * (C) 2003-2006 Netfilter Core Team <coreteam@netfilter.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10#include <linux/module.h>
11#include <linux/gfp.h>
12#include <linux/kmod.h>
13#include <linux/types.h>
14#include <linux/timer.h>
15#include <linux/skbuff.h>
16#include <linux/tcp.h>
17#include <linux/udp.h>
18#include <net/checksum.h>
19#include <net/tcp.h>
20#include <net/route.h>
21
22#include <linux/netfilter_ipv4.h>
23#include <net/netfilter/nf_conntrack.h>
24#include <net/netfilter/nf_conntrack_helper.h>
25#include <net/netfilter/nf_conntrack_ecache.h>
26#include <net/netfilter/nf_conntrack_expect.h>
27#include <net/netfilter/nf_nat.h>
28#include <net/netfilter/nf_nat_protocol.h>
29#include <net/netfilter/nf_nat_core.h>
30#include <net/netfilter/nf_nat_helper.h>
31
32#define DUMP_OFFSET(x) \
33 pr_debug("offset_before=%d, offset_after=%d, correction_pos=%u\n", \
34 x->offset_before, x->offset_after, x->correction_pos);
35
36static DEFINE_SPINLOCK(nf_nat_seqofs_lock);
37
38/* Setup TCP sequence correction given this change at this sequence */
39static inline void
40adjust_tcp_sequence(u32 seq,
41 int sizediff,
42 struct nf_conn *ct,
43 enum ip_conntrack_info ctinfo)
44{
45 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
46 struct nf_conn_nat *nat = nfct_nat(ct);
47 struct nf_nat_seq *this_way = &nat->seq[dir];
48
49 pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n",
50 seq, sizediff);
51
52 pr_debug("adjust_tcp_sequence: Seq_offset before: ");
53 DUMP_OFFSET(this_way);
54
55 spin_lock_bh(&nf_nat_seqofs_lock);
56
57 /* SYN adjust. If it's uninitialized, or this is after last
58 * correction, record it: we don't handle more than one
59 * adjustment in the window, but do deal with common case of a
60 * retransmit */
61 if (this_way->offset_before == this_way->offset_after ||
62 before(this_way->correction_pos, seq)) {
63 this_way->correction_pos = seq;
64 this_way->offset_before = this_way->offset_after;
65 this_way->offset_after += sizediff;
66 }
67 spin_unlock_bh(&nf_nat_seqofs_lock);
68
69 pr_debug("adjust_tcp_sequence: Seq_offset after: ");
70 DUMP_OFFSET(this_way);
71}
72
73/* Get the offset value, for conntrack */
74s16 nf_nat_get_offset(const struct nf_conn *ct,
75 enum ip_conntrack_dir dir,
76 u32 seq)
77{
78 struct nf_conn_nat *nat = nfct_nat(ct);
79 struct nf_nat_seq *this_way;
80 s16 offset;
81
82 if (!nat)
83 return 0;
84
85 this_way = &nat->seq[dir];
86 spin_lock_bh(&nf_nat_seqofs_lock);
87 offset = after(seq, this_way->correction_pos)
88 ? this_way->offset_after : this_way->offset_before;
89 spin_unlock_bh(&nf_nat_seqofs_lock);
90
91 return offset;
92}
93EXPORT_SYMBOL_GPL(nf_nat_get_offset);
94
95/* Frobs data inside this packet, which is linear. */
96static void mangle_contents(struct sk_buff *skb,
97 unsigned int dataoff,
98 unsigned int match_offset,
99 unsigned int match_len,
100 const char *rep_buffer,
101 unsigned int rep_len)
102{
103 unsigned char *data;
104
105 BUG_ON(skb_is_nonlinear(skb));
106 data = skb_network_header(skb) + dataoff;
107
108 /* move post-replacement */
109 memmove(data + match_offset + rep_len,
110 data + match_offset + match_len,
111 skb->tail - (skb->network_header + dataoff +
112 match_offset + match_len));
113
114 /* insert data from buffer */
115 memcpy(data + match_offset, rep_buffer, rep_len);
116
117 /* update skb info */
118 if (rep_len > match_len) {
119 pr_debug("nf_nat_mangle_packet: Extending packet by "
120 "%u from %u bytes\n", rep_len - match_len, skb->len);
121 skb_put(skb, rep_len - match_len);
122 } else {
123 pr_debug("nf_nat_mangle_packet: Shrinking packet from "
124 "%u from %u bytes\n", match_len - rep_len, skb->len);
125 __skb_trim(skb, skb->len + rep_len - match_len);
126 }
127
128 /* fix IP hdr checksum information */
129 ip_hdr(skb)->tot_len = htons(skb->len);
130 ip_send_check(ip_hdr(skb));
131}
132
133/* Unusual, but possible case. */
134static int enlarge_skb(struct sk_buff *skb, unsigned int extra)
135{
136 if (skb->len + extra > 65535)
137 return 0;
138
139 if (pskb_expand_head(skb, 0, extra - skb_tailroom(skb), GFP_ATOMIC))
140 return 0;
141
142 return 1;
143}
144
145void nf_nat_set_seq_adjust(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
146 __be32 seq, s16 off)
147{
148 if (!off)
149 return;
150 set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
151 adjust_tcp_sequence(ntohl(seq), off, ct, ctinfo);
152 nf_conntrack_event_cache(IPCT_NATSEQADJ, ct);
153}
154EXPORT_SYMBOL_GPL(nf_nat_set_seq_adjust);
155
156static void nf_nat_csum(struct sk_buff *skb, const struct iphdr *iph, void *data,
157 int datalen, __sum16 *check, int oldlen)
158{
159 struct rtable *rt = skb_rtable(skb);
160
161 if (skb->ip_summed != CHECKSUM_PARTIAL) {
162 if (!(rt->rt_flags & RTCF_LOCAL) &&
163 (!skb->dev || skb->dev->features & NETIF_F_V4_CSUM)) {
164 skb->ip_summed = CHECKSUM_PARTIAL;
165 skb->csum_start = skb_headroom(skb) +
166 skb_network_offset(skb) +
167 iph->ihl * 4;
168 skb->csum_offset = (void *)check - data;
169 *check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
170 datalen, iph->protocol, 0);
171 } else {
172 *check = 0;
173 *check = csum_tcpudp_magic(iph->saddr, iph->daddr,
174 datalen, iph->protocol,
175 csum_partial(data, datalen,
176 0));
177 if (iph->protocol == IPPROTO_UDP && !*check)
178 *check = CSUM_MANGLED_0;
179 }
180 } else
181 inet_proto_csum_replace2(check, skb,
182 htons(oldlen), htons(datalen), 1);
183}
184
185/* Generic function for mangling variable-length address changes inside
186 * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
187 * command in FTP).
188 *
189 * Takes care about all the nasty sequence number changes, checksumming,
190 * skb enlargement, ...
191 *
192 * */
193int __nf_nat_mangle_tcp_packet(struct sk_buff *skb,
194 struct nf_conn *ct,
195 enum ip_conntrack_info ctinfo,
196 unsigned int match_offset,
197 unsigned int match_len,
198 const char *rep_buffer,
199 unsigned int rep_len, bool adjust)
200{
201 struct iphdr *iph;
202 struct tcphdr *tcph;
203 int oldlen, datalen;
204
205 if (!skb_make_writable(skb, skb->len))
206 return 0;
207
208 if (rep_len > match_len &&
209 rep_len - match_len > skb_tailroom(skb) &&
210 !enlarge_skb(skb, rep_len - match_len))
211 return 0;
212
213 SKB_LINEAR_ASSERT(skb);
214
215 iph = ip_hdr(skb);
216 tcph = (void *)iph + iph->ihl*4;
217
218 oldlen = skb->len - iph->ihl*4;
219 mangle_contents(skb, iph->ihl*4 + tcph->doff*4,
220 match_offset, match_len, rep_buffer, rep_len);
221
222 datalen = skb->len - iph->ihl*4;
223 nf_nat_csum(skb, iph, tcph, datalen, &tcph->check, oldlen);
224
225 if (adjust && rep_len != match_len)
226 nf_nat_set_seq_adjust(ct, ctinfo, tcph->seq,
227 (int)rep_len - (int)match_len);
228
229 return 1;
230}
231EXPORT_SYMBOL(__nf_nat_mangle_tcp_packet);
232
233/* Generic function for mangling variable-length address changes inside
234 * NATed UDP connections (like the CONNECT DATA XXXXX MESG XXXXX INDEX XXXXX
235 * command in the Amanda protocol)
236 *
237 * Takes care about all the nasty sequence number changes, checksumming,
238 * skb enlargement, ...
239 *
240 * XXX - This function could be merged with nf_nat_mangle_tcp_packet which
241 * should be fairly easy to do.
242 */
243int
244nf_nat_mangle_udp_packet(struct sk_buff *skb,
245 struct nf_conn *ct,
246 enum ip_conntrack_info ctinfo,
247 unsigned int match_offset,
248 unsigned int match_len,
249 const char *rep_buffer,
250 unsigned int rep_len)
251{
252 struct iphdr *iph;
253 struct udphdr *udph;
254 int datalen, oldlen;
255
256 /* UDP helpers might accidentally mangle the wrong packet */
257 iph = ip_hdr(skb);
258 if (skb->len < iph->ihl*4 + sizeof(*udph) +
259 match_offset + match_len)
260 return 0;
261
262 if (!skb_make_writable(skb, skb->len))
263 return 0;
264
265 if (rep_len > match_len &&
266 rep_len - match_len > skb_tailroom(skb) &&
267 !enlarge_skb(skb, rep_len - match_len))
268 return 0;
269
270 iph = ip_hdr(skb);
271 udph = (void *)iph + iph->ihl*4;
272
273 oldlen = skb->len - iph->ihl*4;
274 mangle_contents(skb, iph->ihl*4 + sizeof(*udph),
275 match_offset, match_len, rep_buffer, rep_len);
276
277 /* update the length of the UDP packet */
278 datalen = skb->len - iph->ihl*4;
279 udph->len = htons(datalen);
280
281 /* fix udp checksum if udp checksum was previously calculated */
282 if (!udph->check && skb->ip_summed != CHECKSUM_PARTIAL)
283 return 1;
284
285 nf_nat_csum(skb, iph, udph, datalen, &udph->check, oldlen);
286
287 return 1;
288}
289EXPORT_SYMBOL(nf_nat_mangle_udp_packet);
290
291/* Adjust one found SACK option including checksum correction */
292static void
293sack_adjust(struct sk_buff *skb,
294 struct tcphdr *tcph,
295 unsigned int sackoff,
296 unsigned int sackend,
297 struct nf_nat_seq *natseq)
298{
299 while (sackoff < sackend) {
300 struct tcp_sack_block_wire *sack;
301 __be32 new_start_seq, new_end_seq;
302
303 sack = (void *)skb->data + sackoff;
304 if (after(ntohl(sack->start_seq) - natseq->offset_before,
305 natseq->correction_pos))
306 new_start_seq = htonl(ntohl(sack->start_seq)
307 - natseq->offset_after);
308 else
309 new_start_seq = htonl(ntohl(sack->start_seq)
310 - natseq->offset_before);
311
312 if (after(ntohl(sack->end_seq) - natseq->offset_before,
313 natseq->correction_pos))
314 new_end_seq = htonl(ntohl(sack->end_seq)
315 - natseq->offset_after);
316 else
317 new_end_seq = htonl(ntohl(sack->end_seq)
318 - natseq->offset_before);
319
320 pr_debug("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
321 ntohl(sack->start_seq), new_start_seq,
322 ntohl(sack->end_seq), new_end_seq);
323
324 inet_proto_csum_replace4(&tcph->check, skb,
325 sack->start_seq, new_start_seq, 0);
326 inet_proto_csum_replace4(&tcph->check, skb,
327 sack->end_seq, new_end_seq, 0);
328 sack->start_seq = new_start_seq;
329 sack->end_seq = new_end_seq;
330 sackoff += sizeof(*sack);
331 }
332}
333
334/* TCP SACK sequence number adjustment */
335static inline unsigned int
336nf_nat_sack_adjust(struct sk_buff *skb,
337 struct tcphdr *tcph,
338 struct nf_conn *ct,
339 enum ip_conntrack_info ctinfo)
340{
341 unsigned int dir, optoff, optend;
342 struct nf_conn_nat *nat = nfct_nat(ct);
343
344 optoff = ip_hdrlen(skb) + sizeof(struct tcphdr);
345 optend = ip_hdrlen(skb) + tcph->doff * 4;
346
347 if (!skb_make_writable(skb, optend))
348 return 0;
349
350 dir = CTINFO2DIR(ctinfo);
351
352 while (optoff < optend) {
353 /* Usually: option, length. */
354 unsigned char *op = skb->data + optoff;
355
356 switch (op[0]) {
357 case TCPOPT_EOL:
358 return 1;
359 case TCPOPT_NOP:
360 optoff++;
361 continue;
362 default:
363 /* no partial options */
364 if (optoff + 1 == optend ||
365 optoff + op[1] > optend ||
366 op[1] < 2)
367 return 0;
368 if (op[0] == TCPOPT_SACK &&
369 op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
370 ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
371 sack_adjust(skb, tcph, optoff+2,
372 optoff+op[1], &nat->seq[!dir]);
373 optoff += op[1];
374 }
375 }
376 return 1;
377}
378
379/* TCP sequence number adjustment. Returns 1 on success, 0 on failure */
380int
381nf_nat_seq_adjust(struct sk_buff *skb,
382 struct nf_conn *ct,
383 enum ip_conntrack_info ctinfo)
384{
385 struct tcphdr *tcph;
386 int dir;
387 __be32 newseq, newack;
388 s16 seqoff, ackoff;
389 struct nf_conn_nat *nat = nfct_nat(ct);
390 struct nf_nat_seq *this_way, *other_way;
391
392 dir = CTINFO2DIR(ctinfo);
393
394 this_way = &nat->seq[dir];
395 other_way = &nat->seq[!dir];
396
397 if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
398 return 0;
399
400 tcph = (void *)skb->data + ip_hdrlen(skb);
401 if (after(ntohl(tcph->seq), this_way->correction_pos))
402 seqoff = this_way->offset_after;
403 else
404 seqoff = this_way->offset_before;
405
406 if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
407 other_way->correction_pos))
408 ackoff = other_way->offset_after;
409 else
410 ackoff = other_way->offset_before;
411
412 newseq = htonl(ntohl(tcph->seq) + seqoff);
413 newack = htonl(ntohl(tcph->ack_seq) - ackoff);
414
415 inet_proto_csum_replace4(&tcph->check, skb, tcph->seq, newseq, 0);
416 inet_proto_csum_replace4(&tcph->check, skb, tcph->ack_seq, newack, 0);
417
418 pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
419 ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
420 ntohl(newack));
421
422 tcph->seq = newseq;
423 tcph->ack_seq = newack;
424
425 return nf_nat_sack_adjust(skb, tcph, ct, ctinfo);
426}
427
428/* Setup NAT on this expected conntrack so it follows master. */
429/* If we fail to get a free NAT slot, we'll get dropped on confirm */
430void nf_nat_follow_master(struct nf_conn *ct,
431 struct nf_conntrack_expect *exp)
432{
433 struct nf_nat_range range;
434
435 /* This must be a fresh one. */
436 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
437
438 /* Change src to where master sends to */
439 range.flags = IP_NAT_RANGE_MAP_IPS;
440 range.min_ip = range.max_ip
441 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
442 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
443
444 /* For DST manip, map port here to where it's expected. */
445 range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
446 range.min = range.max = exp->saved_proto;
447 range.min_ip = range.max_ip
448 = ct->master->tuplehash[!exp->dir].tuple.src.u3.ip;
449 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
450}
451EXPORT_SYMBOL(nf_nat_follow_master);
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c
new file mode 100644
index 00000000000..535e1a80235
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_irc.c
@@ -0,0 +1,99 @@
1/* IRC extension for TCP NAT alteration.
2 *
3 * (C) 2000-2001 by Harald Welte <laforge@gnumonks.org>
4 * (C) 2004 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
5 * based on a copy of RR's ip_nat_ftp.c
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/tcp.h>
16#include <linux/kernel.h>
17
18#include <net/netfilter/nf_nat.h>
19#include <net/netfilter/nf_nat_helper.h>
20#include <net/netfilter/nf_nat_rule.h>
21#include <net/netfilter/nf_conntrack_helper.h>
22#include <net/netfilter/nf_conntrack_expect.h>
23#include <linux/netfilter/nf_conntrack_irc.h>
24
25MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
26MODULE_DESCRIPTION("IRC (DCC) NAT helper");
27MODULE_LICENSE("GPL");
28MODULE_ALIAS("ip_nat_irc");
29
30static unsigned int help(struct sk_buff *skb,
31 enum ip_conntrack_info ctinfo,
32 unsigned int matchoff,
33 unsigned int matchlen,
34 struct nf_conntrack_expect *exp)
35{
36 char buffer[sizeof("4294967296 65635")];
37 u_int32_t ip;
38 u_int16_t port;
39 unsigned int ret;
40
41 /* Reply comes from server. */
42 exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
43 exp->dir = IP_CT_DIR_REPLY;
44 exp->expectfn = nf_nat_follow_master;
45
46 /* Try to get same port: if not, try to change it. */
47 for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
48 int ret;
49
50 exp->tuple.dst.u.tcp.port = htons(port);
51 ret = nf_ct_expect_related(exp);
52 if (ret == 0)
53 break;
54 else if (ret != -EBUSY) {
55 port = 0;
56 break;
57 }
58 }
59
60 if (port == 0)
61 return NF_DROP;
62
63 ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip);
64 sprintf(buffer, "%u %u", ip, port);
65 pr_debug("nf_nat_irc: inserting '%s' == %pI4, port %u\n",
66 buffer, &ip, port);
67
68 ret = nf_nat_mangle_tcp_packet(skb, exp->master, ctinfo,
69 matchoff, matchlen, buffer,
70 strlen(buffer));
71 if (ret != NF_ACCEPT)
72 nf_ct_unexpect_related(exp);
73 return ret;
74}
75
76static void __exit nf_nat_irc_fini(void)
77{
78 rcu_assign_pointer(nf_nat_irc_hook, NULL);
79 synchronize_rcu();
80}
81
82static int __init nf_nat_irc_init(void)
83{
84 BUG_ON(nf_nat_irc_hook != NULL);
85 rcu_assign_pointer(nf_nat_irc_hook, help);
86 return 0;
87}
88
89/* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */
90static int warn_set(const char *val, struct kernel_param *kp)
91{
92 printk(KERN_INFO KBUILD_MODNAME
93 ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n");
94 return 0;
95}
96module_param_call(ports, warn_set, NULL, NULL, 0);
97
98module_init(nf_nat_irc_init);
99module_exit(nf_nat_irc_fini);
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c
new file mode 100644
index 00000000000..f52d41ea069
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_proto_common.c
@@ -0,0 +1,125 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 * (C) 2008 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/random.h>
12#include <linux/ip.h>
13
14#include <linux/netfilter.h>
15#include <net/secure_seq.h>
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_core.h>
18#include <net/netfilter/nf_nat_rule.h>
19#include <net/netfilter/nf_nat_protocol.h>
20
21bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple,
22 enum nf_nat_manip_type maniptype,
23 const union nf_conntrack_man_proto *min,
24 const union nf_conntrack_man_proto *max)
25{
26 __be16 port;
27
28 if (maniptype == IP_NAT_MANIP_SRC)
29 port = tuple->src.u.all;
30 else
31 port = tuple->dst.u.all;
32
33 return ntohs(port) >= ntohs(min->all) &&
34 ntohs(port) <= ntohs(max->all);
35}
36EXPORT_SYMBOL_GPL(nf_nat_proto_in_range);
37
38void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
39 const struct nf_nat_range *range,
40 enum nf_nat_manip_type maniptype,
41 const struct nf_conn *ct,
42 u_int16_t *rover)
43{
44 unsigned int range_size, min, i;
45 __be16 *portptr;
46 u_int16_t off;
47
48 if (maniptype == IP_NAT_MANIP_SRC)
49 portptr = &tuple->src.u.all;
50 else
51 portptr = &tuple->dst.u.all;
52
53 /* If no range specified... */
54 if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
55 /* If it's dst rewrite, can't change port */
56 if (maniptype == IP_NAT_MANIP_DST)
57 return;
58
59 if (ntohs(*portptr) < 1024) {
60 /* Loose convention: >> 512 is credential passing */
61 if (ntohs(*portptr) < 512) {
62 min = 1;
63 range_size = 511 - min + 1;
64 } else {
65 min = 600;
66 range_size = 1023 - min + 1;
67 }
68 } else {
69 min = 1024;
70 range_size = 65535 - 1024 + 1;
71 }
72 } else {
73 min = ntohs(range->min.all);
74 range_size = ntohs(range->max.all) - min + 1;
75 }
76
77 if (range->flags & IP_NAT_RANGE_PROTO_RANDOM)
78 off = secure_ipv4_port_ephemeral(tuple->src.u3.ip, tuple->dst.u3.ip,
79 maniptype == IP_NAT_MANIP_SRC
80 ? tuple->dst.u.all
81 : tuple->src.u.all);
82 else
83 off = *rover;
84
85 for (i = 0; ; ++off) {
86 *portptr = htons(min + off % range_size);
87 if (++i != range_size && nf_nat_used_tuple(tuple, ct))
88 continue;
89 if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
90 *rover = off;
91 return;
92 }
93 return;
94}
95EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple);
96
97#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
98int nf_nat_proto_range_to_nlattr(struct sk_buff *skb,
99 const struct nf_nat_range *range)
100{
101 NLA_PUT_BE16(skb, CTA_PROTONAT_PORT_MIN, range->min.all);
102 NLA_PUT_BE16(skb, CTA_PROTONAT_PORT_MAX, range->max.all);
103 return 0;
104
105nla_put_failure:
106 return -1;
107}
108EXPORT_SYMBOL_GPL(nf_nat_proto_nlattr_to_range);
109
110int nf_nat_proto_nlattr_to_range(struct nlattr *tb[],
111 struct nf_nat_range *range)
112{
113 if (tb[CTA_PROTONAT_PORT_MIN]) {
114 range->min.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MIN]);
115 range->max.all = range->min.tcp.port;
116 range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
117 }
118 if (tb[CTA_PROTONAT_PORT_MAX]) {
119 range->max.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MAX]);
120 range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
121 }
122 return 0;
123}
124EXPORT_SYMBOL_GPL(nf_nat_proto_range_to_nlattr);
125#endif
diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c
new file mode 100644
index 00000000000..570faf2667b
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_proto_dccp.c
@@ -0,0 +1,108 @@
1/*
2 * DCCP NAT protocol helper
3 *
4 * Copyright (c) 2005, 2006. 2008 Patrick McHardy <kaber@trash.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/skbuff.h>
16#include <linux/ip.h>
17#include <linux/dccp.h>
18
19#include <net/netfilter/nf_conntrack.h>
20#include <net/netfilter/nf_nat.h>
21#include <net/netfilter/nf_nat_protocol.h>
22
23static u_int16_t dccp_port_rover;
24
25static void
26dccp_unique_tuple(struct nf_conntrack_tuple *tuple,
27 const struct nf_nat_range *range,
28 enum nf_nat_manip_type maniptype,
29 const struct nf_conn *ct)
30{
31 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
32 &dccp_port_rover);
33}
34
35static bool
36dccp_manip_pkt(struct sk_buff *skb,
37 unsigned int iphdroff,
38 const struct nf_conntrack_tuple *tuple,
39 enum nf_nat_manip_type maniptype)
40{
41 const struct iphdr *iph = (const void *)(skb->data + iphdroff);
42 struct dccp_hdr *hdr;
43 unsigned int hdroff = iphdroff + iph->ihl * 4;
44 __be32 oldip, newip;
45 __be16 *portptr, oldport, newport;
46 int hdrsize = 8; /* DCCP connection tracking guarantees this much */
47
48 if (skb->len >= hdroff + sizeof(struct dccp_hdr))
49 hdrsize = sizeof(struct dccp_hdr);
50
51 if (!skb_make_writable(skb, hdroff + hdrsize))
52 return false;
53
54 iph = (struct iphdr *)(skb->data + iphdroff);
55 hdr = (struct dccp_hdr *)(skb->data + hdroff);
56
57 if (maniptype == IP_NAT_MANIP_SRC) {
58 oldip = iph->saddr;
59 newip = tuple->src.u3.ip;
60 newport = tuple->src.u.dccp.port;
61 portptr = &hdr->dccph_sport;
62 } else {
63 oldip = iph->daddr;
64 newip = tuple->dst.u3.ip;
65 newport = tuple->dst.u.dccp.port;
66 portptr = &hdr->dccph_dport;
67 }
68
69 oldport = *portptr;
70 *portptr = newport;
71
72 if (hdrsize < sizeof(*hdr))
73 return true;
74
75 inet_proto_csum_replace4(&hdr->dccph_checksum, skb, oldip, newip, 1);
76 inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport,
77 0);
78 return true;
79}
80
81static const struct nf_nat_protocol nf_nat_protocol_dccp = {
82 .protonum = IPPROTO_DCCP,
83 .me = THIS_MODULE,
84 .manip_pkt = dccp_manip_pkt,
85 .in_range = nf_nat_proto_in_range,
86 .unique_tuple = dccp_unique_tuple,
87#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
88 .range_to_nlattr = nf_nat_proto_range_to_nlattr,
89 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
90#endif
91};
92
93static int __init nf_nat_proto_dccp_init(void)
94{
95 return nf_nat_protocol_register(&nf_nat_protocol_dccp);
96}
97
98static void __exit nf_nat_proto_dccp_fini(void)
99{
100 nf_nat_protocol_unregister(&nf_nat_protocol_dccp);
101}
102
103module_init(nf_nat_proto_dccp_init);
104module_exit(nf_nat_proto_dccp_fini);
105
106MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
107MODULE_DESCRIPTION("DCCP NAT protocol helper");
108MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c
new file mode 100644
index 00000000000..756331d4266
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c
@@ -0,0 +1,97 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
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/init.h>
11#include <linux/ip.h>
12#include <linux/sctp.h>
13#include <net/sctp/checksum.h>
14
15#include <net/netfilter/nf_nat_protocol.h>
16
17static u_int16_t nf_sctp_port_rover;
18
19static void
20sctp_unique_tuple(struct nf_conntrack_tuple *tuple,
21 const struct nf_nat_range *range,
22 enum nf_nat_manip_type maniptype,
23 const struct nf_conn *ct)
24{
25 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
26 &nf_sctp_port_rover);
27}
28
29static bool
30sctp_manip_pkt(struct sk_buff *skb,
31 unsigned int iphdroff,
32 const struct nf_conntrack_tuple *tuple,
33 enum nf_nat_manip_type maniptype)
34{
35 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
36 struct sk_buff *frag;
37 sctp_sctphdr_t *hdr;
38 unsigned int hdroff = iphdroff + iph->ihl*4;
39 __be32 oldip, newip;
40 __be32 crc32;
41
42 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
43 return false;
44
45 iph = (struct iphdr *)(skb->data + iphdroff);
46 hdr = (struct sctphdr *)(skb->data + hdroff);
47
48 if (maniptype == IP_NAT_MANIP_SRC) {
49 /* Get rid of src ip and src pt */
50 oldip = iph->saddr;
51 newip = tuple->src.u3.ip;
52 hdr->source = tuple->src.u.sctp.port;
53 } else {
54 /* Get rid of dst ip and dst pt */
55 oldip = iph->daddr;
56 newip = tuple->dst.u3.ip;
57 hdr->dest = tuple->dst.u.sctp.port;
58 }
59
60 crc32 = sctp_start_cksum((u8 *)hdr, skb_headlen(skb) - hdroff);
61 skb_walk_frags(skb, frag)
62 crc32 = sctp_update_cksum((u8 *)frag->data, skb_headlen(frag),
63 crc32);
64 crc32 = sctp_end_cksum(crc32);
65 hdr->checksum = crc32;
66
67 return true;
68}
69
70static const struct nf_nat_protocol nf_nat_protocol_sctp = {
71 .protonum = IPPROTO_SCTP,
72 .me = THIS_MODULE,
73 .manip_pkt = sctp_manip_pkt,
74 .in_range = nf_nat_proto_in_range,
75 .unique_tuple = sctp_unique_tuple,
76#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
77 .range_to_nlattr = nf_nat_proto_range_to_nlattr,
78 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
79#endif
80};
81
82static int __init nf_nat_proto_sctp_init(void)
83{
84 return nf_nat_protocol_register(&nf_nat_protocol_sctp);
85}
86
87static void __exit nf_nat_proto_sctp_exit(void)
88{
89 nf_nat_protocol_unregister(&nf_nat_protocol_sctp);
90}
91
92module_init(nf_nat_proto_sctp_init);
93module_exit(nf_nat_proto_sctp_exit);
94
95MODULE_LICENSE("GPL");
96MODULE_DESCRIPTION("SCTP NAT protocol helper");
97MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
new file mode 100644
index 00000000000..aa460a595d5
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c
@@ -0,0 +1,92 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 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/init.h>
11#include <linux/ip.h>
12#include <linux/tcp.h>
13
14#include <linux/netfilter.h>
15#include <linux/netfilter/nfnetlink_conntrack.h>
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_rule.h>
18#include <net/netfilter/nf_nat_protocol.h>
19#include <net/netfilter/nf_nat_core.h>
20
21static u_int16_t tcp_port_rover;
22
23static void
24tcp_unique_tuple(struct nf_conntrack_tuple *tuple,
25 const struct nf_nat_range *range,
26 enum nf_nat_manip_type maniptype,
27 const struct nf_conn *ct)
28{
29 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &tcp_port_rover);
30}
31
32static bool
33tcp_manip_pkt(struct sk_buff *skb,
34 unsigned int iphdroff,
35 const struct nf_conntrack_tuple *tuple,
36 enum nf_nat_manip_type maniptype)
37{
38 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
39 struct tcphdr *hdr;
40 unsigned int hdroff = iphdroff + iph->ihl*4;
41 __be32 oldip, newip;
42 __be16 *portptr, newport, oldport;
43 int hdrsize = 8; /* TCP connection tracking guarantees this much */
44
45 /* this could be a inner header returned in icmp packet; in such
46 cases we cannot update the checksum field since it is outside of
47 the 8 bytes of transport layer headers we are guaranteed */
48 if (skb->len >= hdroff + sizeof(struct tcphdr))
49 hdrsize = sizeof(struct tcphdr);
50
51 if (!skb_make_writable(skb, hdroff + hdrsize))
52 return false;
53
54 iph = (struct iphdr *)(skb->data + iphdroff);
55 hdr = (struct tcphdr *)(skb->data + hdroff);
56
57 if (maniptype == IP_NAT_MANIP_SRC) {
58 /* Get rid of src ip and src pt */
59 oldip = iph->saddr;
60 newip = tuple->src.u3.ip;
61 newport = tuple->src.u.tcp.port;
62 portptr = &hdr->source;
63 } else {
64 /* Get rid of dst ip and dst pt */
65 oldip = iph->daddr;
66 newip = tuple->dst.u3.ip;
67 newport = tuple->dst.u.tcp.port;
68 portptr = &hdr->dest;
69 }
70
71 oldport = *portptr;
72 *portptr = newport;
73
74 if (hdrsize < sizeof(*hdr))
75 return true;
76
77 inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1);
78 inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, 0);
79 return true;
80}
81
82const struct nf_nat_protocol nf_nat_protocol_tcp = {
83 .protonum = IPPROTO_TCP,
84 .me = THIS_MODULE,
85 .manip_pkt = tcp_manip_pkt,
86 .in_range = nf_nat_proto_in_range,
87 .unique_tuple = tcp_unique_tuple,
88#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
89 .range_to_nlattr = nf_nat_proto_range_to_nlattr,
90 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
91#endif
92};
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
new file mode 100644
index 00000000000..dfe65c7e292
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_proto_udp.c
@@ -0,0 +1,83 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 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/init.h>
11#include <linux/ip.h>
12#include <linux/udp.h>
13
14#include <linux/netfilter.h>
15#include <net/netfilter/nf_nat.h>
16#include <net/netfilter/nf_nat_core.h>
17#include <net/netfilter/nf_nat_rule.h>
18#include <net/netfilter/nf_nat_protocol.h>
19
20static u_int16_t udp_port_rover;
21
22static void
23udp_unique_tuple(struct nf_conntrack_tuple *tuple,
24 const struct nf_nat_range *range,
25 enum nf_nat_manip_type maniptype,
26 const struct nf_conn *ct)
27{
28 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, &udp_port_rover);
29}
30
31static bool
32udp_manip_pkt(struct sk_buff *skb,
33 unsigned int iphdroff,
34 const struct nf_conntrack_tuple *tuple,
35 enum nf_nat_manip_type maniptype)
36{
37 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
38 struct udphdr *hdr;
39 unsigned int hdroff = iphdroff + iph->ihl*4;
40 __be32 oldip, newip;
41 __be16 *portptr, newport;
42
43 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
44 return false;
45
46 iph = (struct iphdr *)(skb->data + iphdroff);
47 hdr = (struct udphdr *)(skb->data + hdroff);
48
49 if (maniptype == IP_NAT_MANIP_SRC) {
50 /* Get rid of src ip and src pt */
51 oldip = iph->saddr;
52 newip = tuple->src.u3.ip;
53 newport = tuple->src.u.udp.port;
54 portptr = &hdr->source;
55 } else {
56 /* Get rid of dst ip and dst pt */
57 oldip = iph->daddr;
58 newip = tuple->dst.u3.ip;
59 newport = tuple->dst.u.udp.port;
60 portptr = &hdr->dest;
61 }
62 if (hdr->check || skb->ip_summed == CHECKSUM_PARTIAL) {
63 inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1);
64 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport,
65 0);
66 if (!hdr->check)
67 hdr->check = CSUM_MANGLED_0;
68 }
69 *portptr = newport;
70 return true;
71}
72
73const struct nf_nat_protocol nf_nat_protocol_udp = {
74 .protonum = IPPROTO_UDP,
75 .me = THIS_MODULE,
76 .manip_pkt = udp_manip_pkt,
77 .in_range = nf_nat_proto_in_range,
78 .unique_tuple = udp_unique_tuple,
79#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
80 .range_to_nlattr = nf_nat_proto_range_to_nlattr,
81 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
82#endif
83};
diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/ipv4/netfilter/nf_nat_proto_udplite.c
new file mode 100644
index 00000000000..3cc8c8af39e
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_proto_udplite.c
@@ -0,0 +1,99 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
3 * (C) 2008 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/init.h>
12#include <linux/ip.h>
13#include <linux/udp.h>
14
15#include <linux/netfilter.h>
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_protocol.h>
18
19static u_int16_t udplite_port_rover;
20
21static void
22udplite_unique_tuple(struct nf_conntrack_tuple *tuple,
23 const struct nf_nat_range *range,
24 enum nf_nat_manip_type maniptype,
25 const struct nf_conn *ct)
26{
27 nf_nat_proto_unique_tuple(tuple, range, maniptype, ct,
28 &udplite_port_rover);
29}
30
31static bool
32udplite_manip_pkt(struct sk_buff *skb,
33 unsigned int iphdroff,
34 const struct nf_conntrack_tuple *tuple,
35 enum nf_nat_manip_type maniptype)
36{
37 const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff);
38 struct udphdr *hdr;
39 unsigned int hdroff = iphdroff + iph->ihl*4;
40 __be32 oldip, newip;
41 __be16 *portptr, newport;
42
43 if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
44 return false;
45
46 iph = (struct iphdr *)(skb->data + iphdroff);
47 hdr = (struct udphdr *)(skb->data + hdroff);
48
49 if (maniptype == IP_NAT_MANIP_SRC) {
50 /* Get rid of src ip and src pt */
51 oldip = iph->saddr;
52 newip = tuple->src.u3.ip;
53 newport = tuple->src.u.udp.port;
54 portptr = &hdr->source;
55 } else {
56 /* Get rid of dst ip and dst pt */
57 oldip = iph->daddr;
58 newip = tuple->dst.u3.ip;
59 newport = tuple->dst.u.udp.port;
60 portptr = &hdr->dest;
61 }
62
63 inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1);
64 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport, 0);
65 if (!hdr->check)
66 hdr->check = CSUM_MANGLED_0;
67
68 *portptr = newport;
69 return true;
70}
71
72static const struct nf_nat_protocol nf_nat_protocol_udplite = {
73 .protonum = IPPROTO_UDPLITE,
74 .me = THIS_MODULE,
75 .manip_pkt = udplite_manip_pkt,
76 .in_range = nf_nat_proto_in_range,
77 .unique_tuple = udplite_unique_tuple,
78#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
79 .range_to_nlattr = nf_nat_proto_range_to_nlattr,
80 .nlattr_to_range = nf_nat_proto_nlattr_to_range,
81#endif
82};
83
84static int __init nf_nat_proto_udplite_init(void)
85{
86 return nf_nat_protocol_register(&nf_nat_protocol_udplite);
87}
88
89static void __exit nf_nat_proto_udplite_fini(void)
90{
91 nf_nat_protocol_unregister(&nf_nat_protocol_udplite);
92}
93
94module_init(nf_nat_proto_udplite_init);
95module_exit(nf_nat_proto_udplite_fini);
96
97MODULE_LICENSE("GPL");
98MODULE_DESCRIPTION("UDP-Lite NAT protocol helper");
99MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c
new file mode 100644
index 00000000000..a50f2bc1c73
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c
@@ -0,0 +1,53 @@
1/* The "unknown" protocol. This is what is used for protocols we
2 * don't understand. It's returned by ip_ct_find_proto().
3 */
4
5/* (C) 1999-2001 Paul `Rusty' Russell
6 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/types.h>
14#include <linux/init.h>
15
16#include <linux/netfilter.h>
17#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_rule.h>
19#include <net/netfilter/nf_nat_protocol.h>
20
21static bool unknown_in_range(const struct nf_conntrack_tuple *tuple,
22 enum nf_nat_manip_type manip_type,
23 const union nf_conntrack_man_proto *min,
24 const union nf_conntrack_man_proto *max)
25{
26 return true;
27}
28
29static void unknown_unique_tuple(struct nf_conntrack_tuple *tuple,
30 const struct nf_nat_range *range,
31 enum nf_nat_manip_type maniptype,
32 const struct nf_conn *ct)
33{
34 /* Sorry: we can't help you; if it's not unique, we can't frob
35 anything. */
36 return;
37}
38
39static bool
40unknown_manip_pkt(struct sk_buff *skb,
41 unsigned int iphdroff,
42 const struct nf_conntrack_tuple *tuple,
43 enum nf_nat_manip_type maniptype)
44{
45 return true;
46}
47
48const struct nf_nat_protocol nf_nat_unknown_protocol = {
49 /* .me isn't set: getting a ref to this cannot fail. */
50 .manip_pkt = unknown_manip_pkt,
51 .in_range = unknown_in_range,
52 .unique_tuple = unknown_unique_tuple,
53};
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
new file mode 100644
index 00000000000..733c9abc1cb
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -0,0 +1,214 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 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/* Everything about the rules for NAT. */
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11#include <linux/types.h>
12#include <linux/ip.h>
13#include <linux/netfilter.h>
14#include <linux/netfilter_ipv4.h>
15#include <linux/module.h>
16#include <linux/kmod.h>
17#include <linux/skbuff.h>
18#include <linux/proc_fs.h>
19#include <linux/slab.h>
20#include <net/checksum.h>
21#include <net/route.h>
22#include <linux/bitops.h>
23
24#include <linux/netfilter_ipv4/ip_tables.h>
25#include <net/netfilter/nf_nat.h>
26#include <net/netfilter/nf_nat_core.h>
27#include <net/netfilter/nf_nat_rule.h>
28
29#define NAT_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | \
30 (1 << NF_INET_POST_ROUTING) | \
31 (1 << NF_INET_LOCAL_OUT) | \
32 (1 << NF_INET_LOCAL_IN))
33
34static const struct xt_table nat_table = {
35 .name = "nat",
36 .valid_hooks = NAT_VALID_HOOKS,
37 .me = THIS_MODULE,
38 .af = NFPROTO_IPV4,
39};
40
41/* Source NAT */
42static unsigned int
43ipt_snat_target(struct sk_buff *skb, const struct xt_action_param *par)
44{
45 struct nf_conn *ct;
46 enum ip_conntrack_info ctinfo;
47 const struct nf_nat_multi_range_compat *mr = par->targinfo;
48
49 NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING ||
50 par->hooknum == NF_INET_LOCAL_IN);
51
52 ct = nf_ct_get(skb, &ctinfo);
53
54 /* Connection must be valid and new. */
55 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED ||
56 ctinfo == IP_CT_RELATED_REPLY));
57 NF_CT_ASSERT(par->out != NULL);
58
59 return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC);
60}
61
62static unsigned int
63ipt_dnat_target(struct sk_buff *skb, const struct xt_action_param *par)
64{
65 struct nf_conn *ct;
66 enum ip_conntrack_info ctinfo;
67 const struct nf_nat_multi_range_compat *mr = par->targinfo;
68
69 NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
70 par->hooknum == NF_INET_LOCAL_OUT);
71
72 ct = nf_ct_get(skb, &ctinfo);
73
74 /* Connection must be valid and new. */
75 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
76
77 return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_DST);
78}
79
80static int ipt_snat_checkentry(const struct xt_tgchk_param *par)
81{
82 const struct nf_nat_multi_range_compat *mr = par->targinfo;
83
84 /* Must be a valid range */
85 if (mr->rangesize != 1) {
86 pr_info("SNAT: multiple ranges no longer supported\n");
87 return -EINVAL;
88 }
89 return 0;
90}
91
92static int ipt_dnat_checkentry(const struct xt_tgchk_param *par)
93{
94 const struct nf_nat_multi_range_compat *mr = par->targinfo;
95
96 /* Must be a valid range */
97 if (mr->rangesize != 1) {
98 pr_info("DNAT: multiple ranges no longer supported\n");
99 return -EINVAL;
100 }
101 return 0;
102}
103
104static unsigned int
105alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
106{
107 /* Force range to this IP; let proto decide mapping for
108 per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
109 */
110 struct nf_nat_range range;
111
112 range.flags = 0;
113 pr_debug("Allocating NULL binding for %p (%pI4)\n", ct,
114 HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC ?
115 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip :
116 &ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip);
117
118 return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
119}
120
121int nf_nat_rule_find(struct sk_buff *skb,
122 unsigned int hooknum,
123 const struct net_device *in,
124 const struct net_device *out,
125 struct nf_conn *ct)
126{
127 struct net *net = nf_ct_net(ct);
128 int ret;
129
130 ret = ipt_do_table(skb, hooknum, in, out, net->ipv4.nat_table);
131
132 if (ret == NF_ACCEPT) {
133 if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
134 /* NUL mapping */
135 ret = alloc_null_binding(ct, hooknum);
136 }
137 return ret;
138}
139
140static struct xt_target ipt_snat_reg __read_mostly = {
141 .name = "SNAT",
142 .target = ipt_snat_target,
143 .targetsize = sizeof(struct nf_nat_multi_range_compat),
144 .table = "nat",
145 .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_IN),
146 .checkentry = ipt_snat_checkentry,
147 .family = AF_INET,
148};
149
150static struct xt_target ipt_dnat_reg __read_mostly = {
151 .name = "DNAT",
152 .target = ipt_dnat_target,
153 .targetsize = sizeof(struct nf_nat_multi_range_compat),
154 .table = "nat",
155 .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT),
156 .checkentry = ipt_dnat_checkentry,
157 .family = AF_INET,
158};
159
160static int __net_init nf_nat_rule_net_init(struct net *net)
161{
162 struct ipt_replace *repl;
163
164 repl = ipt_alloc_initial_table(&nat_table);
165 if (repl == NULL)
166 return -ENOMEM;
167 net->ipv4.nat_table = ipt_register_table(net, &nat_table, repl);
168 kfree(repl);
169 if (IS_ERR(net->ipv4.nat_table))
170 return PTR_ERR(net->ipv4.nat_table);
171 return 0;
172}
173
174static void __net_exit nf_nat_rule_net_exit(struct net *net)
175{
176 ipt_unregister_table(net, net->ipv4.nat_table);
177}
178
179static struct pernet_operations nf_nat_rule_net_ops = {
180 .init = nf_nat_rule_net_init,
181 .exit = nf_nat_rule_net_exit,
182};
183
184int __init nf_nat_rule_init(void)
185{
186 int ret;
187
188 ret = register_pernet_subsys(&nf_nat_rule_net_ops);
189 if (ret != 0)
190 goto out;
191 ret = xt_register_target(&ipt_snat_reg);
192 if (ret != 0)
193 goto unregister_table;
194
195 ret = xt_register_target(&ipt_dnat_reg);
196 if (ret != 0)
197 goto unregister_snat;
198
199 return ret;
200
201 unregister_snat:
202 xt_unregister_target(&ipt_snat_reg);
203 unregister_table:
204 unregister_pernet_subsys(&nf_nat_rule_net_ops);
205 out:
206 return ret;
207}
208
209void nf_nat_rule_cleanup(void)
210{
211 xt_unregister_target(&ipt_dnat_reg);
212 xt_unregister_target(&ipt_snat_reg);
213 unregister_pernet_subsys(&nf_nat_rule_net_ops);
214}
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
new file mode 100644
index 00000000000..e40cf7816fd
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -0,0 +1,561 @@
1/* SIP extension for NAT alteration.
2 *
3 * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
4 * based on RR's ip_nat_ftp.c and other modules.
5 * (C) 2007 United Security Providers
6 * (C) 2007, 2008 Patrick McHardy <kaber@trash.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/skbuff.h>
15#include <linux/ip.h>
16#include <net/ip.h>
17#include <linux/udp.h>
18#include <linux/tcp.h>
19
20#include <net/netfilter/nf_nat.h>
21#include <net/netfilter/nf_nat_helper.h>
22#include <net/netfilter/nf_nat_rule.h>
23#include <net/netfilter/nf_conntrack_helper.h>
24#include <net/netfilter/nf_conntrack_expect.h>
25#include <linux/netfilter/nf_conntrack_sip.h>
26
27MODULE_LICENSE("GPL");
28MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
29MODULE_DESCRIPTION("SIP NAT helper");
30MODULE_ALIAS("ip_nat_sip");
31
32
33static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff,
34 const char **dptr, unsigned int *datalen,
35 unsigned int matchoff, unsigned int matchlen,
36 const char *buffer, unsigned int buflen)
37{
38 enum ip_conntrack_info ctinfo;
39 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
40 struct tcphdr *th;
41 unsigned int baseoff;
42
43 if (nf_ct_protonum(ct) == IPPROTO_TCP) {
44 th = (struct tcphdr *)(skb->data + ip_hdrlen(skb));
45 baseoff = ip_hdrlen(skb) + th->doff * 4;
46 matchoff += dataoff - baseoff;
47
48 if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
49 matchoff, matchlen,
50 buffer, buflen, false))
51 return 0;
52 } else {
53 baseoff = ip_hdrlen(skb) + sizeof(struct udphdr);
54 matchoff += dataoff - baseoff;
55
56 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
57 matchoff, matchlen,
58 buffer, buflen))
59 return 0;
60 }
61
62 /* Reload data pointer and adjust datalen value */
63 *dptr = skb->data + dataoff;
64 *datalen += buflen - matchlen;
65 return 1;
66}
67
68static int map_addr(struct sk_buff *skb, unsigned int dataoff,
69 const char **dptr, unsigned int *datalen,
70 unsigned int matchoff, unsigned int matchlen,
71 union nf_inet_addr *addr, __be16 port)
72{
73 enum ip_conntrack_info ctinfo;
74 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
75 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
76 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
77 unsigned int buflen;
78 __be32 newaddr;
79 __be16 newport;
80
81 if (ct->tuplehash[dir].tuple.src.u3.ip == addr->ip &&
82 ct->tuplehash[dir].tuple.src.u.udp.port == port) {
83 newaddr = ct->tuplehash[!dir].tuple.dst.u3.ip;
84 newport = ct->tuplehash[!dir].tuple.dst.u.udp.port;
85 } else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip &&
86 ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
87 newaddr = ct->tuplehash[!dir].tuple.src.u3.ip;
88 newport = ct->tuplehash[!dir].tuple.src.u.udp.port;
89 } else
90 return 1;
91
92 if (newaddr == addr->ip && newport == port)
93 return 1;
94
95 buflen = sprintf(buffer, "%pI4:%u", &newaddr, ntohs(newport));
96
97 return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
98 buffer, buflen);
99}
100
101static int map_sip_addr(struct sk_buff *skb, unsigned int dataoff,
102 const char **dptr, unsigned int *datalen,
103 enum sip_header_types type)
104{
105 enum ip_conntrack_info ctinfo;
106 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
107 unsigned int matchlen, matchoff;
108 union nf_inet_addr addr;
109 __be16 port;
110
111 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
112 &matchoff, &matchlen, &addr, &port) <= 0)
113 return 1;
114 return map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
115 &addr, port);
116}
117
118static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
119 const char **dptr, unsigned int *datalen)
120{
121 enum ip_conntrack_info ctinfo;
122 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
123 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
124 unsigned int coff, matchoff, matchlen;
125 enum sip_header_types hdr;
126 union nf_inet_addr addr;
127 __be16 port;
128 int request, in_header;
129
130 /* Basic rules: requests and responses. */
131 if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
132 if (ct_sip_parse_request(ct, *dptr, *datalen,
133 &matchoff, &matchlen,
134 &addr, &port) > 0 &&
135 !map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
136 &addr, port))
137 return NF_DROP;
138 request = 1;
139 } else
140 request = 0;
141
142 if (nf_ct_protonum(ct) == IPPROTO_TCP)
143 hdr = SIP_HDR_VIA_TCP;
144 else
145 hdr = SIP_HDR_VIA_UDP;
146
147 /* Translate topmost Via header and parameters */
148 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
149 hdr, NULL, &matchoff, &matchlen,
150 &addr, &port) > 0) {
151 unsigned int matchend, poff, plen, buflen, n;
152 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
153
154 /* We're only interested in headers related to this
155 * connection */
156 if (request) {
157 if (addr.ip != ct->tuplehash[dir].tuple.src.u3.ip ||
158 port != ct->tuplehash[dir].tuple.src.u.udp.port)
159 goto next;
160 } else {
161 if (addr.ip != ct->tuplehash[dir].tuple.dst.u3.ip ||
162 port != ct->tuplehash[dir].tuple.dst.u.udp.port)
163 goto next;
164 }
165
166 if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
167 &addr, port))
168 return NF_DROP;
169
170 matchend = matchoff + matchlen;
171
172 /* The maddr= parameter (RFC 2361) specifies where to send
173 * the reply. */
174 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
175 "maddr=", &poff, &plen,
176 &addr) > 0 &&
177 addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
178 addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
179 buflen = sprintf(buffer, "%pI4",
180 &ct->tuplehash[!dir].tuple.dst.u3.ip);
181 if (!mangle_packet(skb, dataoff, dptr, datalen,
182 poff, plen, buffer, buflen))
183 return NF_DROP;
184 }
185
186 /* The received= parameter (RFC 2361) contains the address
187 * from which the server received the request. */
188 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
189 "received=", &poff, &plen,
190 &addr) > 0 &&
191 addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
192 addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
193 buflen = sprintf(buffer, "%pI4",
194 &ct->tuplehash[!dir].tuple.src.u3.ip);
195 if (!mangle_packet(skb, dataoff, dptr, datalen,
196 poff, plen, buffer, buflen))
197 return NF_DROP;
198 }
199
200 /* The rport= parameter (RFC 3581) contains the port number
201 * from which the server received the request. */
202 if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
203 "rport=", &poff, &plen,
204 &n) > 0 &&
205 htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
206 htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
207 __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
208 buflen = sprintf(buffer, "%u", ntohs(p));
209 if (!mangle_packet(skb, dataoff, dptr, datalen,
210 poff, plen, buffer, buflen))
211 return NF_DROP;
212 }
213 }
214
215next:
216 /* Translate Contact headers */
217 coff = 0;
218 in_header = 0;
219 while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen,
220 SIP_HDR_CONTACT, &in_header,
221 &matchoff, &matchlen,
222 &addr, &port) > 0) {
223 if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
224 &addr, port))
225 return NF_DROP;
226 }
227
228 if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) ||
229 !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO))
230 return NF_DROP;
231
232 return NF_ACCEPT;
233}
234
235static void ip_nat_sip_seq_adjust(struct sk_buff *skb, s16 off)
236{
237 enum ip_conntrack_info ctinfo;
238 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
239 const struct tcphdr *th;
240
241 if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0)
242 return;
243
244 th = (struct tcphdr *)(skb->data + ip_hdrlen(skb));
245 nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off);
246}
247
248/* Handles expected signalling connections and media streams */
249static void ip_nat_sip_expected(struct nf_conn *ct,
250 struct nf_conntrack_expect *exp)
251{
252 struct nf_nat_range range;
253
254 /* This must be a fresh one. */
255 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
256
257 /* For DST manip, map port here to where it's expected. */
258 range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
259 range.min = range.max = exp->saved_proto;
260 range.min_ip = range.max_ip = exp->saved_ip;
261 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
262
263 /* Change src to where master sends to, but only if the connection
264 * actually came from the same source. */
265 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
266 ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
267 range.flags = IP_NAT_RANGE_MAP_IPS;
268 range.min_ip = range.max_ip
269 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
270 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
271 }
272}
273
274static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
275 const char **dptr, unsigned int *datalen,
276 struct nf_conntrack_expect *exp,
277 unsigned int matchoff,
278 unsigned int matchlen)
279{
280 enum ip_conntrack_info ctinfo;
281 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
282 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
283 __be32 newip;
284 u_int16_t port;
285 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
286 unsigned buflen;
287
288 /* Connection will come from reply */
289 if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip)
290 newip = exp->tuple.dst.u3.ip;
291 else
292 newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
293
294 /* If the signalling port matches the connection's source port in the
295 * original direction, try to use the destination port in the opposite
296 * direction. */
297 if (exp->tuple.dst.u.udp.port ==
298 ct->tuplehash[dir].tuple.src.u.udp.port)
299 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
300 else
301 port = ntohs(exp->tuple.dst.u.udp.port);
302
303 exp->saved_ip = exp->tuple.dst.u3.ip;
304 exp->tuple.dst.u3.ip = newip;
305 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
306 exp->dir = !dir;
307 exp->expectfn = ip_nat_sip_expected;
308
309 for (; port != 0; port++) {
310 int ret;
311
312 exp->tuple.dst.u.udp.port = htons(port);
313 ret = nf_ct_expect_related(exp);
314 if (ret == 0)
315 break;
316 else if (ret != -EBUSY) {
317 port = 0;
318 break;
319 }
320 }
321
322 if (port == 0)
323 return NF_DROP;
324
325 if (exp->tuple.dst.u3.ip != exp->saved_ip ||
326 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
327 buflen = sprintf(buffer, "%pI4:%u", &newip, port);
328 if (!mangle_packet(skb, dataoff, dptr, datalen,
329 matchoff, matchlen, buffer, buflen))
330 goto err;
331 }
332 return NF_ACCEPT;
333
334err:
335 nf_ct_unexpect_related(exp);
336 return NF_DROP;
337}
338
339static int mangle_content_len(struct sk_buff *skb, unsigned int dataoff,
340 const char **dptr, unsigned int *datalen)
341{
342 enum ip_conntrack_info ctinfo;
343 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
344 unsigned int matchoff, matchlen;
345 char buffer[sizeof("65536")];
346 int buflen, c_len;
347
348 /* Get actual SDP length */
349 if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
350 SDP_HDR_VERSION, SDP_HDR_UNSPEC,
351 &matchoff, &matchlen) <= 0)
352 return 0;
353 c_len = *datalen - matchoff + strlen("v=");
354
355 /* Now, update SDP length */
356 if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH,
357 &matchoff, &matchlen) <= 0)
358 return 0;
359
360 buflen = sprintf(buffer, "%u", c_len);
361 return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
362 buffer, buflen);
363}
364
365static int mangle_sdp_packet(struct sk_buff *skb, unsigned int dataoff,
366 const char **dptr, unsigned int *datalen,
367 unsigned int sdpoff,
368 enum sdp_header_types type,
369 enum sdp_header_types term,
370 char *buffer, int buflen)
371{
372 enum ip_conntrack_info ctinfo;
373 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
374 unsigned int matchlen, matchoff;
375
376 if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
377 &matchoff, &matchlen) <= 0)
378 return -ENOENT;
379 return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
380 buffer, buflen) ? 0 : -EINVAL;
381}
382
383static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, unsigned int dataoff,
384 const char **dptr, unsigned int *datalen,
385 unsigned int sdpoff,
386 enum sdp_header_types type,
387 enum sdp_header_types term,
388 const union nf_inet_addr *addr)
389{
390 char buffer[sizeof("nnn.nnn.nnn.nnn")];
391 unsigned int buflen;
392
393 buflen = sprintf(buffer, "%pI4", &addr->ip);
394 if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, type, term,
395 buffer, buflen))
396 return 0;
397
398 return mangle_content_len(skb, dataoff, dptr, datalen);
399}
400
401static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int dataoff,
402 const char **dptr, unsigned int *datalen,
403 unsigned int matchoff,
404 unsigned int matchlen,
405 u_int16_t port)
406{
407 char buffer[sizeof("nnnnn")];
408 unsigned int buflen;
409
410 buflen = sprintf(buffer, "%u", port);
411 if (!mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
412 buffer, buflen))
413 return 0;
414
415 return mangle_content_len(skb, dataoff, dptr, datalen);
416}
417
418static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int dataoff,
419 const char **dptr, unsigned int *datalen,
420 unsigned int sdpoff,
421 const union nf_inet_addr *addr)
422{
423 char buffer[sizeof("nnn.nnn.nnn.nnn")];
424 unsigned int buflen;
425
426 /* Mangle session description owner and contact addresses */
427 buflen = sprintf(buffer, "%pI4", &addr->ip);
428 if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
429 SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA,
430 buffer, buflen))
431 return 0;
432
433 switch (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
434 SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA,
435 buffer, buflen)) {
436 case 0:
437 /*
438 * RFC 2327:
439 *
440 * Session description
441 *
442 * c=* (connection information - not required if included in all media)
443 */
444 case -ENOENT:
445 break;
446 default:
447 return 0;
448 }
449
450 return mangle_content_len(skb, dataoff, dptr, datalen);
451}
452
453/* So, this packet has hit the connection tracking matching code.
454 Mangle it, and change the expectation to match the new version. */
455static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
456 const char **dptr, unsigned int *datalen,
457 struct nf_conntrack_expect *rtp_exp,
458 struct nf_conntrack_expect *rtcp_exp,
459 unsigned int mediaoff,
460 unsigned int medialen,
461 union nf_inet_addr *rtp_addr)
462{
463 enum ip_conntrack_info ctinfo;
464 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
465 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
466 u_int16_t port;
467
468 /* Connection will come from reply */
469 if (ct->tuplehash[dir].tuple.src.u3.ip ==
470 ct->tuplehash[!dir].tuple.dst.u3.ip)
471 rtp_addr->ip = rtp_exp->tuple.dst.u3.ip;
472 else
473 rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
474
475 rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
476 rtp_exp->tuple.dst.u3.ip = rtp_addr->ip;
477 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
478 rtp_exp->dir = !dir;
479 rtp_exp->expectfn = ip_nat_sip_expected;
480
481 rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
482 rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip;
483 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
484 rtcp_exp->dir = !dir;
485 rtcp_exp->expectfn = ip_nat_sip_expected;
486
487 /* Try to get same pair of ports: if not, try to change them. */
488 for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
489 port != 0; port += 2) {
490 int ret;
491
492 rtp_exp->tuple.dst.u.udp.port = htons(port);
493 ret = nf_ct_expect_related(rtp_exp);
494 if (ret == -EBUSY)
495 continue;
496 else if (ret < 0) {
497 port = 0;
498 break;
499 }
500 rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
501 ret = nf_ct_expect_related(rtcp_exp);
502 if (ret == 0)
503 break;
504 else if (ret != -EBUSY) {
505 nf_ct_unexpect_related(rtp_exp);
506 port = 0;
507 break;
508 }
509 }
510
511 if (port == 0)
512 goto err1;
513
514 /* Update media port. */
515 if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
516 !ip_nat_sdp_port(skb, dataoff, dptr, datalen,
517 mediaoff, medialen, port))
518 goto err2;
519
520 return NF_ACCEPT;
521
522err2:
523 nf_ct_unexpect_related(rtp_exp);
524 nf_ct_unexpect_related(rtcp_exp);
525err1:
526 return NF_DROP;
527}
528
529static void __exit nf_nat_sip_fini(void)
530{
531 rcu_assign_pointer(nf_nat_sip_hook, NULL);
532 rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, NULL);
533 rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
534 rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL);
535 rcu_assign_pointer(nf_nat_sdp_port_hook, NULL);
536 rcu_assign_pointer(nf_nat_sdp_session_hook, NULL);
537 rcu_assign_pointer(nf_nat_sdp_media_hook, NULL);
538 synchronize_rcu();
539}
540
541static int __init nf_nat_sip_init(void)
542{
543 BUG_ON(nf_nat_sip_hook != NULL);
544 BUG_ON(nf_nat_sip_seq_adjust_hook != NULL);
545 BUG_ON(nf_nat_sip_expect_hook != NULL);
546 BUG_ON(nf_nat_sdp_addr_hook != NULL);
547 BUG_ON(nf_nat_sdp_port_hook != NULL);
548 BUG_ON(nf_nat_sdp_session_hook != NULL);
549 BUG_ON(nf_nat_sdp_media_hook != NULL);
550 rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
551 rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, ip_nat_sip_seq_adjust);
552 rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
553 rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
554 rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port);
555 rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session);
556 rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media);
557 return 0;
558}
559
560module_init(nf_nat_sip_init);
561module_exit(nf_nat_sip_fini);
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
new file mode 100644
index 00000000000..a6e606e8482
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -0,0 +1,326 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2006 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#include <linux/types.h>
9#include <linux/icmp.h>
10#include <linux/gfp.h>
11#include <linux/ip.h>
12#include <linux/netfilter.h>
13#include <linux/netfilter_ipv4.h>
14#include <linux/module.h>
15#include <linux/skbuff.h>
16#include <linux/proc_fs.h>
17#include <net/ip.h>
18#include <net/checksum.h>
19#include <linux/spinlock.h>
20
21#include <net/netfilter/nf_conntrack.h>
22#include <net/netfilter/nf_conntrack_core.h>
23#include <net/netfilter/nf_conntrack_extend.h>
24#include <net/netfilter/nf_nat.h>
25#include <net/netfilter/nf_nat_rule.h>
26#include <net/netfilter/nf_nat_protocol.h>
27#include <net/netfilter/nf_nat_core.h>
28#include <net/netfilter/nf_nat_helper.h>
29#include <linux/netfilter_ipv4/ip_tables.h>
30
31#ifdef CONFIG_XFRM
32static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
33{
34 struct flowi4 *fl4 = &fl->u.ip4;
35 const struct nf_conn *ct;
36 const struct nf_conntrack_tuple *t;
37 enum ip_conntrack_info ctinfo;
38 enum ip_conntrack_dir dir;
39 unsigned long statusbit;
40
41 ct = nf_ct_get(skb, &ctinfo);
42 if (ct == NULL)
43 return;
44 dir = CTINFO2DIR(ctinfo);
45 t = &ct->tuplehash[dir].tuple;
46
47 if (dir == IP_CT_DIR_ORIGINAL)
48 statusbit = IPS_DST_NAT;
49 else
50 statusbit = IPS_SRC_NAT;
51
52 if (ct->status & statusbit) {
53 fl4->daddr = t->dst.u3.ip;
54 if (t->dst.protonum == IPPROTO_TCP ||
55 t->dst.protonum == IPPROTO_UDP ||
56 t->dst.protonum == IPPROTO_UDPLITE ||
57 t->dst.protonum == IPPROTO_DCCP ||
58 t->dst.protonum == IPPROTO_SCTP)
59 fl4->fl4_dport = t->dst.u.tcp.port;
60 }
61
62 statusbit ^= IPS_NAT_MASK;
63
64 if (ct->status & statusbit) {
65 fl4->saddr = t->src.u3.ip;
66 if (t->dst.protonum == IPPROTO_TCP ||
67 t->dst.protonum == IPPROTO_UDP ||
68 t->dst.protonum == IPPROTO_UDPLITE ||
69 t->dst.protonum == IPPROTO_DCCP ||
70 t->dst.protonum == IPPROTO_SCTP)
71 fl4->fl4_sport = t->src.u.tcp.port;
72 }
73}
74#endif
75
76static unsigned int
77nf_nat_fn(unsigned int hooknum,
78 struct sk_buff *skb,
79 const struct net_device *in,
80 const struct net_device *out,
81 int (*okfn)(struct sk_buff *))
82{
83 struct nf_conn *ct;
84 enum ip_conntrack_info ctinfo;
85 struct nf_conn_nat *nat;
86 /* maniptype == SRC for postrouting. */
87 enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
88
89 /* We never see fragments: conntrack defrags on pre-routing
90 and local-out, and nf_nat_out protects post-routing. */
91 NF_CT_ASSERT(!ip_is_fragment(ip_hdr(skb)));
92
93 ct = nf_ct_get(skb, &ctinfo);
94 /* Can't track? It's not due to stress, or conntrack would
95 have dropped it. Hence it's the user's responsibilty to
96 packet filter it out, or implement conntrack/NAT for that
97 protocol. 8) --RR */
98 if (!ct)
99 return NF_ACCEPT;
100
101 /* Don't try to NAT if this packet is not conntracked */
102 if (nf_ct_is_untracked(ct))
103 return NF_ACCEPT;
104
105 nat = nfct_nat(ct);
106 if (!nat) {
107 /* NAT module was loaded late. */
108 if (nf_ct_is_confirmed(ct))
109 return NF_ACCEPT;
110 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
111 if (nat == NULL) {
112 pr_debug("failed to add NAT extension\n");
113 return NF_ACCEPT;
114 }
115 }
116
117 switch (ctinfo) {
118 case IP_CT_RELATED:
119 case IP_CT_RELATED_REPLY:
120 if (ip_hdr(skb)->protocol == IPPROTO_ICMP) {
121 if (!nf_nat_icmp_reply_translation(ct, ctinfo,
122 hooknum, skb))
123 return NF_DROP;
124 else
125 return NF_ACCEPT;
126 }
127 /* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
128 case IP_CT_NEW:
129
130 /* Seen it before? This can happen for loopback, retrans,
131 or local packets.. */
132 if (!nf_nat_initialized(ct, maniptype)) {
133 unsigned int ret;
134
135 ret = nf_nat_rule_find(skb, hooknum, in, out, ct);
136 if (ret != NF_ACCEPT)
137 return ret;
138 } else
139 pr_debug("Already setup manip %s for ct %p\n",
140 maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
141 ct);
142 break;
143
144 default:
145 /* ESTABLISHED */
146 NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
147 ctinfo == IP_CT_ESTABLISHED_REPLY);
148 }
149
150 return nf_nat_packet(ct, ctinfo, hooknum, skb);
151}
152
153static unsigned int
154nf_nat_in(unsigned int hooknum,
155 struct sk_buff *skb,
156 const struct net_device *in,
157 const struct net_device *out,
158 int (*okfn)(struct sk_buff *))
159{
160 unsigned int ret;
161 __be32 daddr = ip_hdr(skb)->daddr;
162
163 ret = nf_nat_fn(hooknum, skb, in, out, okfn);
164 if (ret != NF_DROP && ret != NF_STOLEN &&
165 daddr != ip_hdr(skb)->daddr)
166 skb_dst_drop(skb);
167
168 return ret;
169}
170
171static unsigned int
172nf_nat_out(unsigned int hooknum,
173 struct sk_buff *skb,
174 const struct net_device *in,
175 const struct net_device *out,
176 int (*okfn)(struct sk_buff *))
177{
178#ifdef CONFIG_XFRM
179 const struct nf_conn *ct;
180 enum ip_conntrack_info ctinfo;
181#endif
182 unsigned int ret;
183
184 /* root is playing with raw sockets. */
185 if (skb->len < sizeof(struct iphdr) ||
186 ip_hdrlen(skb) < sizeof(struct iphdr))
187 return NF_ACCEPT;
188
189 ret = nf_nat_fn(hooknum, skb, in, out, okfn);
190#ifdef CONFIG_XFRM
191 if (ret != NF_DROP && ret != NF_STOLEN &&
192 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
193 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
194
195 if ((ct->tuplehash[dir].tuple.src.u3.ip !=
196 ct->tuplehash[!dir].tuple.dst.u3.ip) ||
197 (ct->tuplehash[dir].tuple.src.u.all !=
198 ct->tuplehash[!dir].tuple.dst.u.all)
199 )
200 return ip_xfrm_me_harder(skb) == 0 ? ret : NF_DROP;
201 }
202#endif
203 return ret;
204}
205
206static unsigned int
207nf_nat_local_fn(unsigned int hooknum,
208 struct sk_buff *skb,
209 const struct net_device *in,
210 const struct net_device *out,
211 int (*okfn)(struct sk_buff *))
212{
213 const struct nf_conn *ct;
214 enum ip_conntrack_info ctinfo;
215 unsigned int ret;
216
217 /* root is playing with raw sockets. */
218 if (skb->len < sizeof(struct iphdr) ||
219 ip_hdrlen(skb) < sizeof(struct iphdr))
220 return NF_ACCEPT;
221
222 ret = nf_nat_fn(hooknum, skb, in, out, okfn);
223 if (ret != NF_DROP && ret != NF_STOLEN &&
224 (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
225 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
226
227 if (ct->tuplehash[dir].tuple.dst.u3.ip !=
228 ct->tuplehash[!dir].tuple.src.u3.ip) {
229 if (ip_route_me_harder(skb, RTN_UNSPEC))
230 ret = NF_DROP;
231 }
232#ifdef CONFIG_XFRM
233 else if (ct->tuplehash[dir].tuple.dst.u.all !=
234 ct->tuplehash[!dir].tuple.src.u.all)
235 if (ip_xfrm_me_harder(skb))
236 ret = NF_DROP;
237#endif
238 }
239 return ret;
240}
241
242/* We must be after connection tracking and before packet filtering. */
243
244static struct nf_hook_ops nf_nat_ops[] __read_mostly = {
245 /* Before packet filtering, change destination */
246 {
247 .hook = nf_nat_in,
248 .owner = THIS_MODULE,
249 .pf = NFPROTO_IPV4,
250 .hooknum = NF_INET_PRE_ROUTING,
251 .priority = NF_IP_PRI_NAT_DST,
252 },
253 /* After packet filtering, change source */
254 {
255 .hook = nf_nat_out,
256 .owner = THIS_MODULE,
257 .pf = NFPROTO_IPV4,
258 .hooknum = NF_INET_POST_ROUTING,
259 .priority = NF_IP_PRI_NAT_SRC,
260 },
261 /* Before packet filtering, change destination */
262 {
263 .hook = nf_nat_local_fn,
264 .owner = THIS_MODULE,
265 .pf = NFPROTO_IPV4,
266 .hooknum = NF_INET_LOCAL_OUT,
267 .priority = NF_IP_PRI_NAT_DST,
268 },
269 /* After packet filtering, change source */
270 {
271 .hook = nf_nat_fn,
272 .owner = THIS_MODULE,
273 .pf = NFPROTO_IPV4,
274 .hooknum = NF_INET_LOCAL_IN,
275 .priority = NF_IP_PRI_NAT_SRC,
276 },
277};
278
279static int __init nf_nat_standalone_init(void)
280{
281 int ret = 0;
282
283 need_ipv4_conntrack();
284
285#ifdef CONFIG_XFRM
286 BUG_ON(ip_nat_decode_session != NULL);
287 rcu_assign_pointer(ip_nat_decode_session, nat_decode_session);
288#endif
289 ret = nf_nat_rule_init();
290 if (ret < 0) {
291 pr_err("nf_nat_init: can't setup rules.\n");
292 goto cleanup_decode_session;
293 }
294 ret = nf_register_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
295 if (ret < 0) {
296 pr_err("nf_nat_init: can't register hooks.\n");
297 goto cleanup_rule_init;
298 }
299 return ret;
300
301 cleanup_rule_init:
302 nf_nat_rule_cleanup();
303 cleanup_decode_session:
304#ifdef CONFIG_XFRM
305 rcu_assign_pointer(ip_nat_decode_session, NULL);
306 synchronize_net();
307#endif
308 return ret;
309}
310
311static void __exit nf_nat_standalone_fini(void)
312{
313 nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
314 nf_nat_rule_cleanup();
315#ifdef CONFIG_XFRM
316 rcu_assign_pointer(ip_nat_decode_session, NULL);
317 synchronize_net();
318#endif
319 /* Conntrack caches are unregistered in nf_conntrack_cleanup */
320}
321
322module_init(nf_nat_standalone_init);
323module_exit(nf_nat_standalone_fini);
324
325MODULE_LICENSE("GPL");
326MODULE_ALIAS("ip_nat");
diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c
new file mode 100644
index 00000000000..7274a43c7a1
--- /dev/null
+++ b/net/ipv4/netfilter/nf_nat_tftp.c
@@ -0,0 +1,51 @@
1/* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
6 */
7
8#include <linux/module.h>
9#include <linux/udp.h>
10
11#include <net/netfilter/nf_nat_helper.h>
12#include <net/netfilter/nf_nat_rule.h>
13#include <net/netfilter/nf_conntrack_helper.h>
14#include <net/netfilter/nf_conntrack_expect.h>
15#include <linux/netfilter/nf_conntrack_tftp.h>
16
17MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
18MODULE_DESCRIPTION("TFTP NAT helper");
19MODULE_LICENSE("GPL");
20MODULE_ALIAS("ip_nat_tftp");
21
22static unsigned int help(struct sk_buff *skb,
23 enum ip_conntrack_info ctinfo,
24 struct nf_conntrack_expect *exp)
25{
26 const struct nf_conn *ct = exp->master;
27
28 exp->saved_proto.udp.port
29 = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
30 exp->dir = IP_CT_DIR_REPLY;
31 exp->expectfn = nf_nat_follow_master;
32 if (nf_ct_expect_related(exp) != 0)
33 return NF_DROP;
34 return NF_ACCEPT;
35}
36
37static void __exit nf_nat_tftp_fini(void)
38{
39 rcu_assign_pointer(nf_nat_tftp_hook, NULL);
40 synchronize_rcu();
41}
42
43static int __init nf_nat_tftp_init(void)
44{
45 BUG_ON(nf_nat_tftp_hook != NULL);
46 rcu_assign_pointer(nf_nat_tftp_hook, help);
47 return 0;
48}
49
50module_init(nf_nat_tftp_init);
51module_exit(nf_nat_tftp_fini);