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 "string-table.h"
12 
13 static const char * const firewall_backend_table[_FW_BACKEND_MAX] = {
14         [FW_BACKEND_NONE] = "none",
15 #if HAVE_LIBIPTC
16         [FW_BACKEND_IPTABLES] = "iptables",
17 #endif
18         [FW_BACKEND_NFTABLES] = "nftables",
19 };
20 
21 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(firewall_backend, FirewallBackend);
22 
firewall_backend_probe(FirewallContext * ctx)23 static void firewall_backend_probe(FirewallContext *ctx) {
24         assert(ctx);
25 
26         if (ctx->backend != _FW_BACKEND_INVALID)
27                 return;
28 
29         if (fw_nftables_init(ctx) >= 0)
30                 ctx->backend = FW_BACKEND_NFTABLES;
31         else
32 #if HAVE_LIBIPTC
33                 ctx->backend = FW_BACKEND_IPTABLES;
34 #else
35                 ctx->backend = FW_BACKEND_NONE;
36 #endif
37 
38         if (ctx->backend != FW_BACKEND_NONE)
39                 log_debug("Using %s as firewall backend.", firewall_backend_to_string(ctx->backend));
40         else
41                 log_debug("No firewall backend found.");
42 }
43 
fw_ctx_new(FirewallContext ** ret)44 int fw_ctx_new(FirewallContext **ret) {
45         _cleanup_free_ FirewallContext *ctx = NULL;
46 
47         ctx = new(FirewallContext, 1);
48         if (!ctx)
49                 return -ENOMEM;
50 
51         *ctx = (FirewallContext) {
52                 .backend = _FW_BACKEND_INVALID,
53         };
54 
55         firewall_backend_probe(ctx);
56 
57         *ret = TAKE_PTR(ctx);
58         return 0;
59 }
60 
fw_ctx_free(FirewallContext * ctx)61 FirewallContext *fw_ctx_free(FirewallContext *ctx) {
62         if (!ctx)
63                 return NULL;
64 
65         fw_nftables_exit(ctx);
66 
67         return mfree(ctx);
68 }
69 
fw_add_masquerade(FirewallContext ** ctx,bool add,int af,const union in_addr_union * source,unsigned source_prefixlen)70 int fw_add_masquerade(
71                 FirewallContext **ctx,
72                 bool add,
73                 int af,
74                 const union in_addr_union *source,
75                 unsigned source_prefixlen) {
76 
77         int r;
78 
79         assert(ctx);
80 
81         if (!*ctx) {
82                 r = fw_ctx_new(ctx);
83                 if (r < 0)
84                         return r;
85         }
86 
87         switch ((*ctx)->backend) {
88 #if HAVE_LIBIPTC
89         case FW_BACKEND_IPTABLES:
90                 return fw_iptables_add_masquerade(add, af, source, source_prefixlen);
91 #endif
92         case FW_BACKEND_NFTABLES:
93                 return fw_nftables_add_masquerade(*ctx, add, af, source, source_prefixlen);
94         default:
95                 return -EOPNOTSUPP;
96         }
97 }
98 
fw_add_local_dnat(FirewallContext ** ctx,bool add,int af,int protocol,uint16_t local_port,const union in_addr_union * remote,uint16_t remote_port,const union in_addr_union * previous_remote)99 int fw_add_local_dnat(
100                 FirewallContext **ctx,
101                 bool add,
102                 int af,
103                 int protocol,
104                 uint16_t local_port,
105                 const union in_addr_union *remote,
106                 uint16_t remote_port,
107                 const union in_addr_union *previous_remote) {
108 
109         int r;
110 
111         assert(ctx);
112 
113         if (!*ctx) {
114                 r = fw_ctx_new(ctx);
115                 if (r < 0)
116                         return r;
117         }
118 
119         switch ((*ctx)->backend) {
120 #if HAVE_LIBIPTC
121         case FW_BACKEND_IPTABLES:
122                 return fw_iptables_add_local_dnat(add, af, protocol, local_port, remote, remote_port, previous_remote);
123 #endif
124         case FW_BACKEND_NFTABLES:
125                 return fw_nftables_add_local_dnat(*ctx, add, af, protocol, local_port, remote, remote_port, previous_remote);
126         default:
127                 return -EOPNOTSUPP;
128         }
129 }
130