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>
36 #include <linux/netfilter_ipv4/ip_tables.h>
37 #include <linux/netfilter/nf_nat.h>
38 #include <linux/netfilter/xt_addrtype.h>
39 #include <libiptc/libiptc.h>
41 #include "alloc-util.h"
42 #include "firewall-util.h"
43 #include "in-addr-util.h"
45 #include "socket-util.h"
47 DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle
*, iptc_free
);
49 static int entry_fill_basics(
50 struct ipt_entry
*entry
,
52 const char *in_interface
,
53 const union in_addr_union
*source
,
54 unsigned source_prefixlen
,
55 const char *out_interface
,
56 const union in_addr_union
*destination
,
57 unsigned destination_prefixlen
) {
61 if (out_interface
&& !ifname_valid(out_interface
))
63 if (in_interface
&& !ifname_valid(in_interface
))
66 entry
->ip
.proto
= protocol
;
69 strcpy(entry
->ip
.iniface
, in_interface
);
70 memset(entry
->ip
.iniface_mask
, 0xFF, strlen(in_interface
)+1);
73 entry
->ip
.src
= source
->in
;
74 in_addr_prefixlen_to_netmask(&entry
->ip
.smsk
, source_prefixlen
);
78 strcpy(entry
->ip
.outiface
, out_interface
);
79 memset(entry
->ip
.outiface_mask
, 0xFF, strlen(out_interface
)+1);
82 entry
->ip
.dst
= destination
->in
;
83 in_addr_prefixlen_to_netmask(&entry
->ip
.dmsk
, destination_prefixlen
);
89 int fw_add_masquerade(
93 const union in_addr_union
*source
,
94 unsigned source_prefixlen
,
95 const char *out_interface
,
96 const union in_addr_union
*destination
,
97 unsigned destination_prefixlen
) {
99 _cleanup_(iptc_freep
) struct xtc_handle
*h
= NULL
;
100 struct ipt_entry
*entry
, *mask
;
101 struct ipt_entry_target
*t
;
103 struct nf_nat_ipv4_multi_range_compat
*mr
;
109 if (protocol
!= 0 && protocol
!= IPPROTO_TCP
&& protocol
!= IPPROTO_UDP
)
112 h
= iptc_init("nat");
116 sz
= XT_ALIGN(sizeof(struct ipt_entry
)) +
117 XT_ALIGN(sizeof(struct ipt_entry_target
)) +
118 XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat
));
120 /* Put together the entry we want to add or remove */
122 entry
->next_offset
= sz
;
123 entry
->target_offset
= XT_ALIGN(sizeof(struct ipt_entry
));
124 r
= entry_fill_basics(entry
, protocol
, NULL
, source
, source_prefixlen
, out_interface
, destination
, destination_prefixlen
);
128 /* Fill in target part */
129 t
= ipt_get_target(entry
);
131 XT_ALIGN(sizeof(struct ipt_entry_target
)) +
132 XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat
));
133 strncpy(t
->u
.user
.name
, "MASQUERADE", sizeof(t
->u
.user
.name
));
134 mr
= (struct nf_nat_ipv4_multi_range_compat
*) t
->data
;
137 /* Create a search mask entry */
139 memset(mask
, 0xFF, sz
);
142 if (iptc_check_entry("POSTROUTING", entry
, (unsigned char*) mask
, h
))
144 if (errno
!= ENOENT
) /* if other error than not existing yet, fail */
147 if (!iptc_insert_entry("POSTROUTING", entry
, 0, h
))
150 if (!iptc_delete_entry("POSTROUTING", entry
, (unsigned char*) mask
, h
)) {
151 if (errno
== ENOENT
) /* if it's already gone, all is good! */
164 int fw_add_local_dnat(
168 const char *in_interface
,
169 const union in_addr_union
*source
,
170 unsigned source_prefixlen
,
171 const union in_addr_union
*destination
,
172 unsigned destination_prefixlen
,
174 const union in_addr_union
*remote
,
175 uint16_t remote_port
,
176 const union in_addr_union
*previous_remote
) {
179 _cleanup_(iptc_freep
) struct xtc_handle
*h
= NULL
;
180 struct ipt_entry
*entry
, *mask
;
181 struct ipt_entry_target
*t
;
182 struct ipt_entry_match
*m
;
183 struct xt_addrtype_info_v1
*at
;
184 struct nf_nat_ipv4_multi_range_compat
*mr
;
188 assert(add
|| !previous_remote
);
193 if (protocol
!= IPPROTO_TCP
&& protocol
!= IPPROTO_UDP
)
199 if (remote_port
<= 0)
202 h
= iptc_init("nat");
206 sz
= XT_ALIGN(sizeof(struct ipt_entry
)) +
207 XT_ALIGN(sizeof(struct ipt_entry_match
)) +
208 XT_ALIGN(sizeof(struct xt_addrtype_info_v1
)) +
209 XT_ALIGN(sizeof(struct ipt_entry_target
)) +
210 XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat
));
212 if (protocol
== IPPROTO_TCP
)
213 msz
= XT_ALIGN(sizeof(struct ipt_entry_match
)) +
214 XT_ALIGN(sizeof(struct xt_tcp
));
216 msz
= XT_ALIGN(sizeof(struct ipt_entry_match
)) +
217 XT_ALIGN(sizeof(struct xt_udp
));
221 /* Fill in basic part */
223 entry
->next_offset
= sz
;
224 entry
->target_offset
=
225 XT_ALIGN(sizeof(struct ipt_entry
)) +
226 XT_ALIGN(sizeof(struct ipt_entry_match
)) +
227 XT_ALIGN(sizeof(struct xt_addrtype_info_v1
)) +
229 r
= entry_fill_basics(entry
, protocol
, in_interface
, source
, source_prefixlen
, NULL
, destination
, destination_prefixlen
);
233 /* Fill in first match */
234 m
= (struct ipt_entry_match
*) ((uint8_t*) entry
+ XT_ALIGN(sizeof(struct ipt_entry
)));
235 m
->u
.match_size
= msz
;
236 if (protocol
== IPPROTO_TCP
) {
239 strncpy(m
->u
.user
.name
, "tcp", sizeof(m
->u
.user
.name
));
240 tcp
= (struct xt_tcp
*) m
->data
;
241 tcp
->dpts
[0] = tcp
->dpts
[1] = local_port
;
243 tcp
->spts
[1] = 0xFFFF;
248 strncpy(m
->u
.user
.name
, "udp", sizeof(m
->u
.user
.name
));
249 udp
= (struct xt_udp
*) m
->data
;
250 udp
->dpts
[0] = udp
->dpts
[1] = local_port
;
252 udp
->spts
[1] = 0xFFFF;
255 /* Fill in second match */
256 m
= (struct ipt_entry_match
*) ((uint8_t*) entry
+ XT_ALIGN(sizeof(struct ipt_entry
)) + msz
);
258 XT_ALIGN(sizeof(struct ipt_entry_match
)) +
259 XT_ALIGN(sizeof(struct xt_addrtype_info_v1
));
260 strncpy(m
->u
.user
.name
, "addrtype", sizeof(m
->u
.user
.name
));
261 m
->u
.user
.revision
= 1;
262 at
= (struct xt_addrtype_info_v1
*) m
->data
;
263 at
->dest
= XT_ADDRTYPE_LOCAL
;
265 /* Fill in target part */
266 t
= ipt_get_target(entry
);
268 XT_ALIGN(sizeof(struct ipt_entry_target
)) +
269 XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat
));
270 strncpy(t
->u
.user
.name
, "DNAT", sizeof(t
->u
.user
.name
));
271 mr
= (struct nf_nat_ipv4_multi_range_compat
*) t
->data
;
273 mr
->range
[0].flags
= NF_NAT_RANGE_PROTO_SPECIFIED
|NF_NAT_RANGE_MAP_IPS
;
274 mr
->range
[0].min_ip
= mr
->range
[0].max_ip
= remote
->in
.s_addr
;
275 if (protocol
== IPPROTO_TCP
)
276 mr
->range
[0].min
.tcp
.port
= mr
->range
[0].max
.tcp
.port
= htons(remote_port
);
278 mr
->range
[0].min
.udp
.port
= mr
->range
[0].max
.udp
.port
= htons(remote_port
);
281 memset(mask
, 0xFF, sz
);
284 /* Add the PREROUTING rule, if it is missing so far */
285 if (!iptc_check_entry("PREROUTING", entry
, (unsigned char*) mask
, h
)) {
289 if (!iptc_insert_entry("PREROUTING", entry
, 0, h
))
293 /* If a previous remote is set, remove its entry */
294 if (previous_remote
&& previous_remote
->in
.s_addr
!= remote
->in
.s_addr
) {
295 mr
->range
[0].min_ip
= mr
->range
[0].max_ip
= previous_remote
->in
.s_addr
;
297 if (!iptc_delete_entry("PREROUTING", entry
, (unsigned char*) mask
, h
)) {
302 mr
->range
[0].min_ip
= mr
->range
[0].max_ip
= remote
->in
.s_addr
;
305 /* Add the OUTPUT rule, if it is missing so far */
308 /* Don't apply onto loopback addresses */
310 entry
->ip
.dst
.s_addr
= htobe32(0x7F000000);
311 entry
->ip
.dmsk
.s_addr
= htobe32(0xFF000000);
312 entry
->ip
.invflags
= IPT_INV_DSTIP
;
315 if (!iptc_check_entry("OUTPUT", entry
, (unsigned char*) mask
, h
)) {
319 if (!iptc_insert_entry("OUTPUT", entry
, 0, h
))
323 /* If a previous remote is set, remove its entry */
324 if (previous_remote
&& previous_remote
->in
.s_addr
!= remote
->in
.s_addr
) {
325 mr
->range
[0].min_ip
= mr
->range
[0].max_ip
= previous_remote
->in
.s_addr
;
327 if (!iptc_delete_entry("OUTPUT", entry
, (unsigned char*) mask
, h
)) {
334 if (!iptc_delete_entry("PREROUTING", entry
, (unsigned char*) mask
, h
)) {
341 entry
->ip
.dst
.s_addr
= htobe32(0x7F000000);
342 entry
->ip
.dmsk
.s_addr
= htobe32(0xFF000000);
343 entry
->ip
.invflags
= IPT_INV_DSTIP
;
346 if (!iptc_delete_entry("OUTPUT", entry
, (unsigned char*) mask
, h
)) {