GNU Linux-libre 4.14.290-gnu1
[releases.git] / net / netfilter / nf_nat_proto_udp.c
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/export.h>
11 #include <linux/init.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_l3proto.h>
18 #include <net/netfilter/nf_nat_l4proto.h>
19
20 static void
21 udp_unique_tuple(const struct nf_nat_l3proto *l3proto,
22                  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_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
28 }
29
30 static void
31 __udp_manip_pkt(struct sk_buff *skb,
32                 const struct nf_nat_l3proto *l3proto,
33                 unsigned int iphdroff, struct udphdr *hdr,
34                 const struct nf_conntrack_tuple *tuple,
35                 enum nf_nat_manip_type maniptype, bool do_csum)
36 {
37         __be16 *portptr, newport;
38
39         if (maniptype == NF_NAT_MANIP_SRC) {
40                 /* Get rid of src port */
41                 newport = tuple->src.u.udp.port;
42                 portptr = &hdr->source;
43         } else {
44                 /* Get rid of dst port */
45                 newport = tuple->dst.u.udp.port;
46                 portptr = &hdr->dest;
47         }
48         if (do_csum) {
49                 l3proto->csum_update(skb, iphdroff, &hdr->check,
50                                      tuple, maniptype);
51                 inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport,
52                                          false);
53                 if (!hdr->check)
54                         hdr->check = CSUM_MANGLED_0;
55         }
56         *portptr = newport;
57 }
58
59 static bool udp_manip_pkt(struct sk_buff *skb,
60                           const struct nf_nat_l3proto *l3proto,
61                           unsigned int iphdroff, unsigned int hdroff,
62                           const struct nf_conntrack_tuple *tuple,
63                           enum nf_nat_manip_type maniptype)
64 {
65         struct udphdr *hdr;
66
67         if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
68                 return false;
69
70         hdr = (struct udphdr *)(skb->data + hdroff);
71         __udp_manip_pkt(skb, l3proto, iphdroff, hdr, tuple, maniptype,
72                         !!hdr->check);
73
74         return true;
75 }
76
77 #ifdef CONFIG_NF_NAT_PROTO_UDPLITE
78 static bool udplite_manip_pkt(struct sk_buff *skb,
79                               const struct nf_nat_l3proto *l3proto,
80                               unsigned int iphdroff, unsigned int hdroff,
81                               const struct nf_conntrack_tuple *tuple,
82                               enum nf_nat_manip_type maniptype)
83 {
84         struct udphdr *hdr;
85
86         if (!skb_make_writable(skb, hdroff + sizeof(*hdr)))
87                 return false;
88
89         hdr = (struct udphdr *)(skb->data + hdroff);
90         __udp_manip_pkt(skb, l3proto, iphdroff, hdr, tuple, maniptype, true);
91         return true;
92 }
93
94 static void
95 udplite_unique_tuple(const struct nf_nat_l3proto *l3proto,
96                      struct nf_conntrack_tuple *tuple,
97                      const struct nf_nat_range *range,
98                      enum nf_nat_manip_type maniptype,
99                      const struct nf_conn *ct)
100 {
101         nf_nat_l4proto_unique_tuple(l3proto, tuple, range, maniptype, ct);
102 }
103
104 const struct nf_nat_l4proto nf_nat_l4proto_udplite = {
105         .l4proto                = IPPROTO_UDPLITE,
106         .manip_pkt              = udplite_manip_pkt,
107         .in_range               = nf_nat_l4proto_in_range,
108         .unique_tuple           = udplite_unique_tuple,
109 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
110         .nlattr_to_range        = nf_nat_l4proto_nlattr_to_range,
111 #endif
112 };
113 #endif /* CONFIG_NF_NAT_PROTO_UDPLITE */
114
115 const struct nf_nat_l4proto nf_nat_l4proto_udp = {
116         .l4proto                = IPPROTO_UDP,
117         .manip_pkt              = udp_manip_pkt,
118         .in_range               = nf_nat_l4proto_in_range,
119         .unique_tuple           = udp_unique_tuple,
120 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
121         .nlattr_to_range        = nf_nat_l4proto_nlattr_to_range,
122 #endif
123 };