]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/firewall-util.c
mkosi: update arch commit reference
[thirdparty/systemd.git] / src / shared / firewall-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <stddef.h>
5 #include <string.h>
6
7 #include "alloc-util.h"
8 #include "firewall-util.h"
9 #include "firewall-util-private.h"
10 #include "log.h"
11 #include "netlink-util.h"
12 #include "string-table.h"
13
14 static const char * const firewall_backend_table[_FW_BACKEND_MAX] = {
15 [FW_BACKEND_NONE] = "none",
16 #if HAVE_LIBIPTC
17 [FW_BACKEND_IPTABLES] = "iptables",
18 #endif
19 [FW_BACKEND_NFTABLES] = "nftables",
20 };
21
22 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(firewall_backend, FirewallBackend);
23
24 static void firewall_backend_probe(FirewallContext *ctx, bool init_tables) {
25 const char *e;
26
27 assert(ctx);
28
29 if (ctx->backend != _FW_BACKEND_INVALID)
30 return;
31
32 e = secure_getenv("SYSTEMD_FIREWALL_BACKEND");
33 if (e) {
34 if (streq(e, "nftables"))
35 ctx->backend = FW_BACKEND_NFTABLES;
36 else if (streq(e, "iptables"))
37 #if HAVE_LIBIPTC
38 ctx->backend = FW_BACKEND_IPTABLES;
39 #else
40 log_debug("Unsupported firewall backend requested, ignoring: %s", e);
41 #endif
42 else
43 log_debug("Unrecognized $SYSTEMD_FIREWALL_BACKEND value, ignoring: %s", e);
44 }
45
46 if (ctx->backend == _FW_BACKEND_INVALID) {
47
48 if (fw_nftables_init_full(ctx, init_tables) >= 0)
49 ctx->backend = FW_BACKEND_NFTABLES;
50 else
51 #if HAVE_LIBIPTC
52 ctx->backend = FW_BACKEND_IPTABLES;
53 #else
54 ctx->backend = FW_BACKEND_NONE;
55 #endif
56 }
57
58 if (ctx->backend != FW_BACKEND_NONE)
59 log_debug("Using %s as firewall backend.", firewall_backend_to_string(ctx->backend));
60 else
61 log_debug("No firewall backend found.");
62 }
63
64 int fw_ctx_new_full(FirewallContext **ret, bool init_tables) {
65 _cleanup_free_ FirewallContext *ctx = NULL;
66
67 ctx = new(FirewallContext, 1);
68 if (!ctx)
69 return -ENOMEM;
70
71 *ctx = (FirewallContext) {
72 .backend = _FW_BACKEND_INVALID,
73 };
74
75 firewall_backend_probe(ctx, init_tables);
76
77 *ret = TAKE_PTR(ctx);
78 return 0;
79 }
80
81 int fw_ctx_new(FirewallContext **ret) {
82 return fw_ctx_new_full(ret, /* init_tables= */ true);
83 }
84
85 FirewallContext *fw_ctx_free(FirewallContext *ctx) {
86 if (!ctx)
87 return NULL;
88
89 fw_nftables_exit(ctx);
90
91 return mfree(ctx);
92 }
93
94 size_t fw_ctx_get_reply_callback_count(FirewallContext *ctx) {
95 if (!ctx || !ctx->nfnl)
96 return 0;
97
98 return netlink_get_reply_callback_count(ctx->nfnl);
99 }
100
101 int fw_add_masquerade(
102 FirewallContext **ctx,
103 bool add,
104 int af,
105 const union in_addr_union *source,
106 unsigned source_prefixlen) {
107
108 int r;
109
110 assert(ctx);
111
112 if (!*ctx) {
113 r = fw_ctx_new(ctx);
114 if (r < 0)
115 return r;
116 }
117
118 switch ((*ctx)->backend) {
119 #if HAVE_LIBIPTC
120 case FW_BACKEND_IPTABLES:
121 return fw_iptables_add_masquerade(add, af, source, source_prefixlen);
122 #endif
123 case FW_BACKEND_NFTABLES:
124 return fw_nftables_add_masquerade(*ctx, add, af, source, source_prefixlen);
125 default:
126 return -EOPNOTSUPP;
127 }
128 }
129
130 int fw_add_local_dnat(
131 FirewallContext **ctx,
132 bool add,
133 int af,
134 int protocol,
135 uint16_t local_port,
136 const union in_addr_union *remote,
137 uint16_t remote_port,
138 const union in_addr_union *previous_remote) {
139
140 int r;
141
142 assert(ctx);
143
144 if (!*ctx) {
145 r = fw_ctx_new(ctx);
146 if (r < 0)
147 return r;
148 }
149
150 switch ((*ctx)->backend) {
151 #if HAVE_LIBIPTC
152 case FW_BACKEND_IPTABLES:
153 return fw_iptables_add_local_dnat(add, af, protocol, local_port, remote, remote_port, previous_remote);
154 #endif
155 case FW_BACKEND_NFTABLES:
156 return fw_nftables_add_local_dnat(*ctx, add, af, protocol, local_port, remote, remote_port, previous_remote);
157 default:
158 return -EOPNOTSUPP;
159 }
160 }