]>
Commit | Line | Data |
---|---|---|
4910a087 PM |
1 | /* |
2 | * DCCP NAT protocol helper | |
3 | * | |
c7232c99 | 4 | * Copyright (c) 2005, 2006, 2008 Patrick McHardy <kaber@trash.net> |
4910a087 PM |
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> | |
4910a087 | 13 | #include <linux/skbuff.h> |
4910a087 PM |
14 | #include <linux/dccp.h> |
15 | ||
16 | #include <net/netfilter/nf_conntrack.h> | |
17 | #include <net/netfilter/nf_nat.h> | |
c7232c99 PM |
18 | #include <net/netfilter/nf_nat_l3proto.h> |
19 | #include <net/netfilter/nf_nat_l4proto.h> | |
4910a087 PM |
20 | |
21 | static u_int16_t dccp_port_rover; | |
22 | ||
f43dc98b | 23 | static void |
c7232c99 PM |
24 | dccp_unique_tuple(const struct nf_nat_l3proto *l3proto, |
25 | struct nf_conntrack_tuple *tuple, | |
26 | const struct nf_nat_range *range, | |
4910a087 PM |
27 | enum nf_nat_manip_type maniptype, |
28 | const struct nf_conn *ct) | |
29 | { | |
c7232c99 PM |
30 | nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct, |
31 | &dccp_port_rover); | |
4910a087 PM |
32 | } |
33 | ||
f2ea825f | 34 | static bool |
4910a087 | 35 | dccp_manip_pkt(struct sk_buff *skb, |
c7232c99 PM |
36 | const struct nf_nat_l3proto *l3proto, |
37 | unsigned int iphdroff, unsigned int hdroff, | |
4910a087 PM |
38 | const struct nf_conntrack_tuple *tuple, |
39 | enum nf_nat_manip_type maniptype) | |
40 | { | |
4910a087 | 41 | struct dccp_hdr *hdr; |
4910a087 PM |
42 | __be16 *portptr, oldport, newport; |
43 | int hdrsize = 8; /* DCCP connection tracking guarantees this much */ | |
44 | ||
45 | if (skb->len >= hdroff + sizeof(struct dccp_hdr)) | |
46 | hdrsize = sizeof(struct dccp_hdr); | |
47 | ||
48 | if (!skb_make_writable(skb, hdroff + hdrsize)) | |
f2ea825f | 49 | return false; |
4910a087 | 50 | |
4910a087 PM |
51 | hdr = (struct dccp_hdr *)(skb->data + hdroff); |
52 | ||
cbc9f2f4 | 53 | if (maniptype == NF_NAT_MANIP_SRC) { |
4910a087 PM |
54 | newport = tuple->src.u.dccp.port; |
55 | portptr = &hdr->dccph_sport; | |
56 | } else { | |
4910a087 PM |
57 | newport = tuple->dst.u.dccp.port; |
58 | portptr = &hdr->dccph_dport; | |
59 | } | |
60 | ||
61 | oldport = *portptr; | |
62 | *portptr = newport; | |
63 | ||
64 | if (hdrsize < sizeof(*hdr)) | |
f2ea825f | 65 | return true; |
4910a087 | 66 | |
c7232c99 PM |
67 | l3proto->csum_update(skb, iphdroff, &hdr->dccph_checksum, |
68 | tuple, maniptype); | |
4910a087 | 69 | inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport, |
4b048d6d | 70 | false); |
f2ea825f | 71 | return true; |
4910a087 PM |
72 | } |
73 | ||
0c4e966e | 74 | const struct nf_nat_l4proto nf_nat_l4proto_dccp = { |
c7232c99 | 75 | .l4proto = IPPROTO_DCCP, |
4910a087 | 76 | .manip_pkt = dccp_manip_pkt, |
c7232c99 | 77 | .in_range = nf_nat_l4proto_in_range, |
4910a087 | 78 | .unique_tuple = dccp_unique_tuple, |
24de3d37 | 79 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) |
c7232c99 | 80 | .nlattr_to_range = nf_nat_l4proto_nlattr_to_range, |
4910a087 PM |
81 | #endif |
82 | }; |