]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/firewall-util.c
Merge pull request #3247 from fbuihuu/ask-passowrd-on-all-consoles
[thirdparty/systemd.git] / src / shared / firewall-util.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2015 Lennart Poettering
5
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.
10
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.
15
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/>.
18 ***/
19
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"
22 #define _NET_IF_H 1
23
24 #include <alloca.h>
25 #include <arpa/inet.h>
26 #include <endian.h>
27 #include <errno.h>
28 #include <stddef.h>
29 #include <string.h>
30 #include <sys/socket.h>
31 #include <net/if.h>
32 #ifndef IFNAMSIZ
33 #define IFNAMSIZ 16
34 #endif
35 #include <linux/if.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>
40
41 #include "alloc-util.h"
42 #include "firewall-util.h"
43 #include "in-addr-util.h"
44 #include "macro.h"
45 #include "socket-util.h"
46
47 DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free);
48
49 static int entry_fill_basics(
50 struct ipt_entry *entry,
51 int protocol,
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) {
58
59 assert(entry);
60
61 if (out_interface && !ifname_valid(out_interface))
62 return -EINVAL;
63 if (in_interface && !ifname_valid(in_interface))
64 return -EINVAL;
65
66 entry->ip.proto = protocol;
67
68 if (in_interface) {
69 strcpy(entry->ip.iniface, in_interface);
70 memset(entry->ip.iniface_mask, 0xFF, strlen(in_interface)+1);
71 }
72 if (source) {
73 entry->ip.src = source->in;
74 in_addr_prefixlen_to_netmask(&entry->ip.smsk, source_prefixlen);
75 }
76
77 if (out_interface) {
78 strcpy(entry->ip.outiface, out_interface);
79 memset(entry->ip.outiface_mask, 0xFF, strlen(out_interface)+1);
80 }
81 if (destination) {
82 entry->ip.dst = destination->in;
83 in_addr_prefixlen_to_netmask(&entry->ip.dmsk, destination_prefixlen);
84 }
85
86 return 0;
87 }
88
89 int fw_add_masquerade(
90 bool add,
91 int af,
92 int protocol,
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) {
98
99 _cleanup_(iptc_freep) struct xtc_handle *h = NULL;
100 struct ipt_entry *entry, *mask;
101 struct ipt_entry_target *t;
102 size_t sz;
103 struct nf_nat_ipv4_multi_range_compat *mr;
104 int r;
105
106 if (af != AF_INET)
107 return -EOPNOTSUPP;
108
109 if (protocol != 0 && protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
110 return -EOPNOTSUPP;
111
112 h = iptc_init("nat");
113 if (!h)
114 return -errno;
115
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));
119
120 /* Put together the entry we want to add or remove */
121 entry = alloca0(sz);
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);
125 if (r < 0)
126 return r;
127
128 /* Fill in target part */
129 t = ipt_get_target(entry);
130 t->u.target_size =
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;
135 mr->rangesize = 1;
136
137 /* Create a search mask entry */
138 mask = alloca(sz);
139 memset(mask, 0xFF, sz);
140
141 if (add) {
142 if (iptc_check_entry("POSTROUTING", entry, (unsigned char*) mask, h))
143 return 0;
144 if (errno != ENOENT) /* if other error than not existing yet, fail */
145 return -errno;
146
147 if (!iptc_insert_entry("POSTROUTING", entry, 0, h))
148 return -errno;
149 } else {
150 if (!iptc_delete_entry("POSTROUTING", entry, (unsigned char*) mask, h)) {
151 if (errno == ENOENT) /* if it's already gone, all is good! */
152 return 0;
153
154 return -errno;
155 }
156 }
157
158 if (!iptc_commit(h))
159 return -errno;
160
161 return 0;
162 }
163
164 int fw_add_local_dnat(
165 bool add,
166 int af,
167 int protocol,
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,
173 uint16_t local_port,
174 const union in_addr_union *remote,
175 uint16_t remote_port,
176 const union in_addr_union *previous_remote) {
177
178
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;
185 size_t sz, msz;
186 int r;
187
188 assert(add || !previous_remote);
189
190 if (af != AF_INET)
191 return -EOPNOTSUPP;
192
193 if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP)
194 return -EOPNOTSUPP;
195
196 if (local_port <= 0)
197 return -EINVAL;
198
199 if (remote_port <= 0)
200 return -EINVAL;
201
202 h = iptc_init("nat");
203 if (!h)
204 return -errno;
205
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));
211
212 if (protocol == IPPROTO_TCP)
213 msz = XT_ALIGN(sizeof(struct ipt_entry_match)) +
214 XT_ALIGN(sizeof(struct xt_tcp));
215 else
216 msz = XT_ALIGN(sizeof(struct ipt_entry_match)) +
217 XT_ALIGN(sizeof(struct xt_udp));
218
219 sz += msz;
220
221 /* Fill in basic part */
222 entry = alloca0(sz);
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)) +
228 msz;
229 r = entry_fill_basics(entry, protocol, in_interface, source, source_prefixlen, NULL, destination, destination_prefixlen);
230 if (r < 0)
231 return r;
232
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) {
237 struct xt_tcp *tcp;
238
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;
242 tcp->spts[0] = 0;
243 tcp->spts[1] = 0xFFFF;
244
245 } else {
246 struct xt_udp *udp;
247
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;
251 udp->spts[0] = 0;
252 udp->spts[1] = 0xFFFF;
253 }
254
255 /* Fill in second match */
256 m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)) + msz);
257 m->u.match_size =
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;
264
265 /* Fill in target part */
266 t = ipt_get_target(entry);
267 t->u.target_size =
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;
272 mr->rangesize = 1;
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);
277 else
278 mr->range[0].min.udp.port = mr->range[0].max.udp.port = htons(remote_port);
279
280 mask = alloca0(sz);
281 memset(mask, 0xFF, sz);
282
283 if (add) {
284 /* Add the PREROUTING rule, if it is missing so far */
285 if (!iptc_check_entry("PREROUTING", entry, (unsigned char*) mask, h)) {
286 if (errno != ENOENT)
287 return -EINVAL;
288
289 if (!iptc_insert_entry("PREROUTING", entry, 0, h))
290 return -errno;
291 }
292
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;
296
297 if (!iptc_delete_entry("PREROUTING", entry, (unsigned char*) mask, h)) {
298 if (errno != ENOENT)
299 return -errno;
300 }
301
302 mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr;
303 }
304
305 /* Add the OUTPUT rule, if it is missing so far */
306 if (!in_interface) {
307
308 /* Don't apply onto loopback addresses */
309 if (!destination) {
310 entry->ip.dst.s_addr = htobe32(0x7F000000);
311 entry->ip.dmsk.s_addr = htobe32(0xFF000000);
312 entry->ip.invflags = IPT_INV_DSTIP;
313 }
314
315 if (!iptc_check_entry("OUTPUT", entry, (unsigned char*) mask, h)) {
316 if (errno != ENOENT)
317 return -errno;
318
319 if (!iptc_insert_entry("OUTPUT", entry, 0, h))
320 return -errno;
321 }
322
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;
326
327 if (!iptc_delete_entry("OUTPUT", entry, (unsigned char*) mask, h)) {
328 if (errno != ENOENT)
329 return -errno;
330 }
331 }
332 }
333 } else {
334 if (!iptc_delete_entry("PREROUTING", entry, (unsigned char*) mask, h)) {
335 if (errno != ENOENT)
336 return -errno;
337 }
338
339 if (!in_interface) {
340 if (!destination) {
341 entry->ip.dst.s_addr = htobe32(0x7F000000);
342 entry->ip.dmsk.s_addr = htobe32(0xFF000000);
343 entry->ip.invflags = IPT_INV_DSTIP;
344 }
345
346 if (!iptc_delete_entry("OUTPUT", entry, (unsigned char*) mask, h)) {
347 if (errno != ENOENT)
348 return -errno;
349 }
350 }
351 }
352
353 if (!iptc_commit(h))
354 return -errno;
355
356 return 0;
357 }