Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "core/opts.h"
7 :
8 : #include <argp.h>
9 : #include <errno.h>
10 : #include <limits.h>
11 : #include <stdbool.h>
12 : #include <stddef.h>
13 : #include <stdint.h>
14 : #include <stdlib.h>
15 :
16 : #include "core/front.h"
17 : #include "core/helper.h"
18 : #include "core/logger.h"
19 : #include "version.h"
20 :
21 : enum
22 : {
23 : BF_OPT_NO_IPTABLES_KEY,
24 : BF_OPT_NO_NFTABLES_KEY,
25 : BF_OPT_NO_CLI_KEY,
26 : BF_OPT_VERSION,
27 : };
28 :
29 : static const char *_bf_verbose_strs[] = {
30 : [BF_VERBOSE_DEBUG] = "debug",
31 : [BF_VERBOSE_BPF] = "bpf",
32 : [BF_VERBOSE_BYTECODE] = "bytecode",
33 : };
34 :
35 : static_assert(ARRAY_SIZE(_bf_verbose_strs) == _BF_VERBOSE_MAX,
36 : "missing entries in _bf_verbose_strs array");
37 :
38 0 : int bf_verbose_to_str(const char *str, enum bf_verbose *opt)
39 : {
40 0 : bf_assert(str && opt);
41 :
42 0 : for (size_t i = 0; i < _BF_VERBOSE_MAX; ++i) {
43 0 : if (bf_streq(_bf_verbose_strs[i], str)) {
44 0 : *opt = i;
45 0 : return 0;
46 : }
47 : }
48 :
49 : return -EINVAL;
50 : }
51 :
52 : /**
53 : * bpfilter runtime configuration
54 : */
55 : static struct bf_options
56 : {
57 : /** If true, bpfilter won't load or save its state to the filesystem, and
58 : * all the loaded BPF programs will be unloaded before shuting down. Hence,
59 : * as long as bpfilter is running, filtering rules will be applied. When
60 : * bpfilter is stopped, everything is cleaned up. */
61 : bool transient;
62 :
63 : /** Size of the log buffer when loading a BPF program, as a power of 2. */
64 : unsigned int bpf_log_buf_len_pow;
65 :
66 : /** Bit flags for enabled fronts. */
67 : uint16_t fronts;
68 :
69 : /** Verbose flags. Supported flags are:
70 : * - @c debug Print all the debug logs.
71 : * - @c bpf Add debug log messages in the generated BPF programs. */
72 : uint16_t verbose;
73 : } _bf_opts = {
74 : .transient = false,
75 : .bpf_log_buf_len_pow = 16,
76 : .fronts = 0xffff,
77 : .verbose = 0,
78 : };
79 :
80 : static struct argp_option options[] = {
81 : {"transient", 't', 0, 0,
82 : "Do not load or save runtime context and remove all BPF programs on shutdown",
83 : 0},
84 : {"buffer-len", 'b', "BUF_LEN_POW", 0,
85 : "Size of the BPF log buffer as a power of 2 (only used when --verbose is used). Default: 16.",
86 : 0},
87 : {"no-iptables", BF_OPT_NO_IPTABLES_KEY, 0, 0, "Disable iptables support",
88 : 0},
89 : {"no-nftables", BF_OPT_NO_NFTABLES_KEY, 0, 0, "Disable nftables support",
90 : 0},
91 : {"no-cli", BF_OPT_NO_CLI_KEY, 0, 0, "Disable CLI support", 0},
92 : {"verbose", 'v', "VERBOSE_FLAG", 0,
93 : "Verbose flags to enable. Can be used more than once.", 0},
94 : {"version", BF_OPT_VERSION, 0, 0, "Print the version and return.", 0},
95 : {0},
96 : };
97 :
98 : /**
99 : * argp callback to process command line arguments.
100 : *
101 : * @return 0 on succcess, non-zero on failure.
102 : */
103 6 : static error_t _bf_opts_parser(int key, char *arg, struct argp_state *state)
104 : {
105 : UNUSED(arg);
106 :
107 6 : struct bf_options *args = state->input;
108 : enum bf_verbose opt;
109 : long pow;
110 : char *end;
111 : int r;
112 :
113 6 : switch (key) {
114 0 : case 't':
115 0 : args->transient = true;
116 0 : break;
117 0 : case 'b':
118 0 : errno = 0;
119 0 : pow = strtol(arg, &end, 0);
120 0 : if (errno == ERANGE) {
121 0 : return bf_err_r(EINVAL, "failed to convert '%s' into an integer",
122 : arg);
123 : }
124 0 : if (pow > UINT_MAX) {
125 0 : return bf_err_r(EINVAL, "--buffer-len can't be bigger than %d",
126 : UINT_MAX);
127 : }
128 0 : if (pow < 0)
129 0 : return bf_err_r(EINVAL, "--buffer-len can't be negative");
130 0 : args->bpf_log_buf_len_pow = (unsigned int)pow;
131 0 : break;
132 0 : case BF_OPT_NO_IPTABLES_KEY:
133 0 : bf_info("disabling iptables support");
134 0 : args->fronts &= ~(1 << BF_FRONT_IPT);
135 0 : break;
136 1 : case BF_OPT_NO_NFTABLES_KEY:
137 1 : bf_info("disabling nftables support");
138 1 : args->fronts &= ~(1 << BF_FRONT_NFT);
139 1 : break;
140 0 : case BF_OPT_NO_CLI_KEY:
141 0 : bf_info("disabling CLI support");
142 0 : args->fronts &= ~(1 << BF_FRONT_CLI);
143 0 : break;
144 0 : case 'v':
145 0 : r = bf_verbose_to_str(arg, &opt);
146 0 : if (r < 0)
147 0 : return bf_err_r(
148 : EINVAL,
149 : "unknown --verbose option '%s', valid --verbose options: [debug, bpf, bytecode]",
150 : arg);
151 0 : bf_info("enabling verbose for '%s'", arg);
152 0 : args->verbose |= (1 << opt);
153 0 : break;
154 0 : case BF_OPT_VERSION:
155 0 : bf_info("bpfilter version %s", BF_VERSION);
156 0 : exit(0);
157 : default:
158 : return ARGP_ERR_UNKNOWN;
159 : }
160 :
161 : return 0;
162 : }
163 :
164 1 : int bf_opts_init(int argc, char *argv[])
165 : {
166 1 : struct argp argp = {options, _bf_opts_parser, NULL, NULL, 0, NULL, NULL};
167 :
168 1 : return argp_parse(&argp, argc, argv, 0, 0, &_bf_opts);
169 : }
170 :
171 0 : bool bf_opts_transient(void)
172 : {
173 0 : return _bf_opts.transient;
174 : }
175 :
176 0 : unsigned int bf_opts_bpf_log_buf_len_pow(void)
177 : {
178 0 : return _bf_opts.bpf_log_buf_len_pow;
179 : }
180 :
181 0 : bool bf_opts_is_front_enabled(enum bf_front front)
182 : {
183 0 : return _bf_opts.fronts & (1 << front);
184 : }
185 :
186 8 : bool bf_opts_is_verbose(enum bf_verbose opt)
187 : {
188 8 : return _bf_opts.verbose & (1 << opt);
189 : }
190 :
191 0 : void bf_opts_set_verbose(enum bf_verbose opt)
192 : {
193 0 : _bf_opts.verbose |= (1 << opt);
194 0 : }
|