2 This file is part of systemd.
4 Copyright 2015 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #warning "Temporary work-around for broken glibc vs. linux kernel header definitions"
21 #warning "This really should be removed sooner rather than later, when this is fixed upstream"
25 #include <arpa/inet.h>
30 #include <sys/socket.h>
35 /* Let's make sure to include this one, too, if IFNAMSIZ isn't defined yet, as it is for kernels <= 4.2 */
38 #include <linux/netfilter_ipv4/ip_tables.h>
39 #include <linux/netfilter/nf_nat.h>
40 #include <linux/netfilter/xt_addrtype.h>
41 #include <libiptc/libiptc.h>
43 #include "alloc-util.h"
44 #include "firewall-util.h"
45 #include "in-addr-util.h"
47 #include "socket-util.h"
49 DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle
*, iptc_free
);
51 static int entry_fill_basics(
52 struct ipt_entry
*entry
,
54 const char *in_interface
,
55 const union in_addr_union
*source
,
56 unsigned source_prefixlen
,
57 const char *out_interface
,
58 const union in_addr_union
*destination
,
59 unsigned destination_prefixlen
) {
63 if (out_interface
&& !ifname_valid(out_interface
))
65 if (in_interface
&& !ifname_valid(in_interface
))
68 entry
->ip
.proto
= protocol
;
71 strcpy(entry
->ip
.iniface
, in_interface
);
72 memset(entry
->ip
.iniface_mask
, 0xFF, strlen(in_interface
)+1);
75 entry
->ip
.src
= source
->in
;
76 in_addr_prefixlen_to_netmask(&entry
->ip
.smsk
, source_prefixlen
);
80 strcpy(entry
->ip
.outiface
, out_interface
);
81 memset(entry
->ip
.outiface_mask
, 0xFF, strlen(out_interface
)+1);
84 entry
->ip
.dst
= destination
->in
;
85 in_addr_prefixlen_to_netmask(&entry
->ip
.dmsk
, destination_prefixlen
);
91 int fw_add_masquerade(
95 const union in_addr_union
*source
,
96 unsigned source_prefixlen
,
97 const char *out_interface
,
98 const union in_addr_union
*destination
,
99 unsigned destination_prefixlen
) {
101 _cleanup_(iptc_freep
) struct xtc_handle
*h
= NULL
;
102 struct ipt_entry
*entry
, *mask
;
103 struct ipt_entry_target
*t
;
105 struct nf_nat_ipv4_multi_range_compat
*mr
;
111 if (protocol
!= 0 && protocol
!= IPPROTO_TCP
&& protocol
!= IPPROTO_UDP
)
114 h
= iptc_init("nat");
118 sz
= XT_ALIGN(sizeof(struct ipt_entry
)) +
119 XT_ALIGN(sizeof(struct ipt_entry_target
)) +
120 XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat
));
122 /* Put together the entry we want to add or remove */
124 entry
->next_offset
= sz
;
125 entry
->target_offset
= XT_ALIGN(sizeof(struct ipt_entry
));
126 r
= entry_fill_basics(entry
, protocol
, NULL
, source
, source_prefixlen
, out_interface
, destination
, destination_prefixlen
);
130 /* Fill in target part */
131 t
= ipt_get_target(entry
);
133 XT_ALIGN(sizeof(struct ipt_entry_target
)) +
134 XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat
));
135 strncpy(t
->u
.user
.name
, "MASQUERADE", sizeof(t
->u
.user
.name
));
136 mr
= (struct nf_nat_ipv4_multi_range_compat
*) t
->data
;
139 /* Create a search mask entry */
141 memset(mask
, 0xFF, sz
);
144 if (iptc_check_entry("POSTROUTING", entry
, (unsigned char*) mask
, h
))
146 if (errno
!= ENOENT
) /* if other error than not existing yet, fail */
149 if (!iptc_insert_entry("POSTROUTING", entry
, 0, h
))
152 if (!iptc_delete_entry("POSTROUTING", entry
, (unsigned char*) mask
, h
)) {
153 if (errno
== ENOENT
) /* if it's already gone, all is good! */
166 int fw_add_local_dnat(
170 const char *in_interface
,
171 const union in_addr_union
*source
,
172 unsigned source_prefixlen
,
173 const union in_addr_union
*destination
,
174 unsigned destination_prefixlen
,
176 const union in_addr_union
*remote
,
177 uint16_t remote_port
,
178 const union in_addr_union
*previous_remote
) {
181 _cleanup_(iptc_freep
) struct xtc_handle
*h
= NULL
;
182 struct ipt_entry
*entry
, *mask
;
183 struct ipt_entry_target
*t
;
184 struct ipt_entry_match
*m
;
185 struct xt_addrtype_info_v1
*at
;
186 struct nf_nat_ipv4_multi_range_compat
*mr
;
190 assert(add
|| !previous_remote
);
195 if (protocol
!= IPPROTO_TCP
&& protocol
!= IPPROTO_UDP
)
201 if (remote_port
<= 0)
204 h
= iptc_init("nat");
208 sz
= XT_ALIGN(sizeof(struct ipt_entry
)) +
209 XT_ALIGN(sizeof(struct ipt_entry_match
)) +
210 XT_ALIGN(sizeof(struct xt_addrtype_info_v1
)) +
211 XT_ALIGN(sizeof(struct ipt_entry_target
)) +
212 XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat
));
214 if (protocol
== IPPROTO_TCP
)
215 msz
= XT_ALIGN(sizeof(struct ipt_entry_match
)) +
216 XT_ALIGN(sizeof(struct xt_tcp
));
218 msz
= XT_ALIGN(sizeof(struct ipt_entry_match
)) +
219 XT_ALIGN(sizeof(struct xt_udp
));
223 /* Fill in basic part */
225 entry
->next_offset
= sz
;
226 entry
->target_offset
=
227 XT_ALIGN(sizeof(struct ipt_entry
)) +
228 XT_ALIGN(sizeof(struct ipt_entry_match
)) +
229 XT_ALIGN(sizeof(struct xt_addrtype_info_v1
)) +
231 r
= entry_fill_basics(entry
, protocol
, in_interface
, source
, source_prefixlen
, NULL
, destination
, destination_prefixlen
);
235 /* Fill in first match */
236 m
= (struct ipt_entry_match
*) ((uint8_t*) entry
+ XT_ALIGN(sizeof(struct ipt_entry
)));
237 m
->u
.match_size
= msz
;
238 if (protocol
== IPPROTO_TCP
) {
241 strncpy(m
->u
.user
.name
, "tcp", sizeof(m
->u
.user
.name
));
242 tcp
= (struct xt_tcp
*) m
->data
;
243 tcp
->dpts
[0] = tcp
->dpts
[1] = local_port
;
245 tcp
->spts
[1] = 0xFFFF;
250 strncpy(m
->u
.user
.name
, "udp", sizeof(m
->u
.user
.name
));
251 udp
= (struct xt_udp
*) m
->data
;
252 udp
->dpts
[0] = udp
->dpts
[1] = local_port
;
254 udp
->spts
[1] = 0xFFFF;
257 /* Fill in second match */
258 m
= (struct ipt_entry_match
*) ((uint8_t*) entry
+ XT_ALIGN(sizeof(struct ipt_entry
)) + msz
);
260 XT_ALIGN(sizeof(struct ipt_entry_match
)) +
261 XT_ALIGN(sizeof(struct xt_addrtype_info_v1
));
262 strncpy(m
->u
.user
.name
, "addrtype", sizeof(m
->u
.user
.name
));
263 m
->u
.user
.revision
= 1;
264 at
= (struct xt_addrtype_info_v1
*) m
->data
;
265 at
->dest
= XT_ADDRTYPE_LOCAL
;
267 /* Fill in target part */
268 t
= ipt_get_target(entry
);
270 XT_ALIGN(sizeof(struct ipt_entry_target
)) +
271 XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat
));
272 strncpy(t
->u
.user
.name
, "DNAT", sizeof(t
->u
.user
.name
));
273 mr
= (struct nf_nat_ipv4_multi_range_compat
*) t
->data
;
275 mr
->range
[0].flags
= NF_NAT_RANGE_PROTO_SPECIFIED
|NF_NAT_RANGE_MAP_IPS
;
276 mr
->range
[0].min_ip
= mr
->range
[0].max_ip
= remote
->in
.s_addr
;
277 if (protocol
== IPPROTO_TCP
)
278 mr
->range
[0].min
.tcp
.port
= mr
->range
[0].max
.tcp
.port
= htons(remote_port
);
280 mr
->range
[0].min
.udp
.port
= mr
->range
[0].max
.udp
.port
= htons(remote_port
);
283 memset(mask
, 0xFF, sz
);
286 /* Add the PREROUTING rule, if it is missing so far */
287 if (!iptc_check_entry("PREROUTING", entry
, (unsigned char*) mask
, h
)) {
291 if (!iptc_insert_entry("PREROUTING", entry
, 0, h
))
295 /* If a previous remote is set, remove its entry */
296 if (previous_remote
&& previous_remote
->in
.s_addr
!= remote
->in
.s_addr
) {
297 mr
->range
[0].min_ip
= mr
->range
[0].max_ip
= previous_remote
->in
.s_addr
;
299 if (!iptc_delete_entry("PREROUTING", entry
, (unsigned char*) mask
, h
)) {
304 mr
->range
[0].min_ip
= mr
->range
[0].max_ip
= remote
->in
.s_addr
;
307 /* Add the OUTPUT rule, if it is missing so far */
310 /* Don't apply onto loopback addresses */
312 entry
->ip
.dst
.s_addr
= htobe32(0x7F000000);
313 entry
->ip
.dmsk
.s_addr
= htobe32(0xFF000000);
314 entry
->ip
.invflags
= IPT_INV_DSTIP
;
317 if (!iptc_check_entry("OUTPUT", entry
, (unsigned char*) mask
, h
)) {
321 if (!iptc_insert_entry("OUTPUT", entry
, 0, h
))
325 /* If a previous remote is set, remove its entry */
326 if (previous_remote
&& previous_remote
->in
.s_addr
!= remote
->in
.s_addr
) {
327 mr
->range
[0].min_ip
= mr
->range
[0].max_ip
= previous_remote
->in
.s_addr
;
329 if (!iptc_delete_entry("OUTPUT", entry
, (unsigned char*) mask
, h
)) {
336 if (!iptc_delete_entry("PREROUTING", entry
, (unsigned char*) mask
, h
)) {
343 entry
->ip
.dst
.s_addr
= htobe32(0x7F000000);
344 entry
->ip
.dmsk
.s_addr
= htobe32(0xFF000000);
345 entry
->ip
.invflags
= IPT_INV_DSTIP
;
348 if (!iptc_delete_entry("OUTPUT", entry
, (unsigned char*) mask
, h
)) {