Commit | Line | Data |
---|---|---|
4910a087 PM |
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 | ||
23 | static u_int16_t dccp_port_rover; | |
24 | ||
25 | static int | |
26 | dccp_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 | return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, | |
32 | &dccp_port_rover); | |
33 | } | |
34 | ||
35 | static int | |
36 | dccp_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 | struct iphdr *iph = (struct iphdr *)(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 0; | |
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 1; | |
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 1; | |
79 | } | |
80 | ||
81 | static 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 | ||
93 | static int __init nf_nat_proto_dccp_init(void) | |
94 | { | |
95 | return nf_nat_protocol_register(&nf_nat_protocol_dccp); | |
96 | } | |
97 | ||
98 | static void __exit nf_nat_proto_dccp_fini(void) | |
99 | { | |
100 | nf_nat_protocol_unregister(&nf_nat_protocol_dccp); | |
101 | } | |
102 | ||
103 | module_init(nf_nat_proto_dccp_init); | |
104 | module_exit(nf_nat_proto_dccp_fini); | |
105 | ||
106 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | |
107 | MODULE_DESCRIPTION("DCCP NAT protocol helper"); | |
108 | MODULE_LICENSE("GPL"); |