Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "dump.h"
7 :
8 : #include <linux/netfilter.h>
9 : #include <linux/netfilter/x_tables.h>
10 : #include <linux/netfilter_ipv4/ip_tables.h>
11 :
12 : #include <stdbool.h>
13 : #include <stdint.h>
14 : #include <stdio.h>
15 :
16 : #include "bpfilter/xlate/ipt/helpers.h"
17 : #include "core/dump.h"
18 : #include "core/helper.h"
19 :
20 : /**
21 : * Map each hook to its name as a string.
22 : */
23 : static const char *hook_name[] = {
24 : [NF_INET_PRE_ROUTING] = "PRE_ROUTING", [NF_INET_LOCAL_IN] = "LOCAL_IN",
25 : [NF_INET_FORWARD] = "FORWARD", [NF_INET_LOCAL_OUT] = "LOCAL_OUT",
26 : [NF_INET_POST_ROUTING] = "POST_ROUTING",
27 : };
28 :
29 : /**
30 : * Map each target to its name as a string.
31 : */
32 : static const char *target_name[] = {
33 : [NF_DROP] = "DROP", [NF_ACCEPT] = "ACCEPT", [NF_STOLEN] = "STOLEN",
34 : [NF_QUEUE] = "QUEUE", [NF_REPEAT] = "REPEAT", [NF_STOP] = "STOP",
35 : };
36 :
37 : /**
38 : * Dump content of @p ipt_counters structure.
39 : *
40 : * @param counters @p ipt_counters structure. Must be non-NULL.
41 : * @param prefix @p log_prefix structure.
42 : */
43 0 : static inline void ipt_dump_counters(const struct ipt_counters *counters,
44 : prefix_t *prefix)
45 : {
46 0 : prefix_t _prefix = {};
47 0 : prefix = prefix ?: &_prefix;
48 :
49 0 : DUMP(prefix, "struct ipt_counters at %p", counters);
50 0 : }
51 :
52 : /**
53 : * Dump content of @p ipt_ip structure.
54 : *
55 : * @param ip @p ipt_ip structure. Must be non-NULL.
56 : * @param prefix @p log_prefix structure.
57 : */
58 0 : static void ipt_dump_ip(const struct ipt_ip *ip, prefix_t *prefix)
59 : {
60 0 : prefix_t _prefix = {};
61 0 : prefix = prefix ?: &_prefix;
62 :
63 0 : DUMP(prefix, "struct ipt_ip at %p", ip);
64 :
65 0 : bf_dump_prefix_push(prefix);
66 0 : DUMP(prefix, "src: " IP4_FMT, IP4_SPLIT(ip->src));
67 0 : DUMP(prefix, "dst: " IP4_FMT, IP4_SPLIT(ip->dst));
68 0 : DUMP(prefix, "src_mask: " IP4_FMT, IP4_SPLIT(ip->smsk));
69 0 : DUMP(prefix, "dst_mask: " IP4_FMT, IP4_SPLIT(ip->dmsk));
70 0 : DUMP(prefix, "in_iface: %s", ip->iniface);
71 0 : DUMP(prefix, "out_iface: %s", ip->outiface);
72 0 : DUMP(prefix, "in_iface_mask: %s", ip->iniface_mask);
73 0 : DUMP(prefix, "out_iface_mask: %s", ip->outiface_mask);
74 0 : DUMP(prefix, "protocol: %d", ip->proto);
75 0 : DUMP(prefix, "flags: %d", ip->flags);
76 0 : DUMP(bf_dump_prefix_last(prefix), "invflags: %d", ip->invflags);
77 0 : bf_dump_prefix_pop(prefix);
78 0 : }
79 :
80 : /**
81 : * Dump content of @p ipt_entry_match structure.
82 : *
83 : * @param match @p ipt_entry_match structure. Must be non-NULL.
84 : * @param prefix @p log_prefix structure.
85 : */
86 0 : static void ipt_dump_match(const struct ipt_entry_match *match,
87 : prefix_t *prefix)
88 : {
89 0 : prefix_t _prefix = {};
90 0 : prefix = prefix ?: &_prefix;
91 :
92 0 : DUMP(prefix, "struct ipt_entry_match at %p", match);
93 :
94 0 : bf_dump_prefix_push(prefix);
95 0 : DUMP(prefix, "user:");
96 0 : DUMP(prefix, "match_size: %d", match->u.user.match_size);
97 0 : DUMP(prefix, "name: %s", match->u.user.name);
98 0 : DUMP(prefix, "revision: %d", match->u.user.revision);
99 0 : DUMP(prefix, "kernel:");
100 0 : DUMP(prefix, "match_size: %d", match->u.kernel.match_size);
101 0 : DUMP(prefix, "match at %p", match->u.kernel.match);
102 0 : DUMP(bf_dump_prefix_last(prefix), "match_size: %d", match->u.match_size);
103 0 : bf_dump_prefix_pop(prefix);
104 0 : }
105 :
106 : static inline int _bf_ipt_convert_verdict(int verdict)
107 : {
108 0 : return -verdict - 1;
109 : }
110 :
111 : /**
112 : * Dump content of @p ipt_entry_target structure.
113 : *
114 : * @param target @p ipt_entry_target structure. Must be non-NULL.
115 : * @param prefix @p log_prefix structure.
116 : */
117 0 : static void ipt_dump_target(const struct ipt_entry_target *target,
118 : prefix_t *prefix)
119 : {
120 0 : prefix_t _prefix = {};
121 0 : prefix = prefix ?: &_prefix;
122 : bool is_standard;
123 : struct ipt_standard_target *std_target = (void *)target;
124 :
125 : is_standard = bf_streq(target->u.user.name, "");
126 :
127 0 : DUMP(prefix, "struct ipt_entry_target at %p", target);
128 :
129 0 : bf_dump_prefix_push(prefix);
130 0 : DUMP(prefix, "user:");
131 :
132 0 : bf_dump_prefix_push(prefix);
133 0 : DUMP(prefix, "target_size: %d", target->u.user.target_size);
134 0 : DUMP(prefix, "name: '%s'", target->u.user.name);
135 0 : DUMP(bf_dump_prefix_last(prefix), "revision: %d", target->u.user.revision);
136 0 : bf_dump_prefix_pop(prefix);
137 :
138 0 : DUMP(prefix, "kernel:");
139 :
140 0 : bf_dump_prefix_push(prefix);
141 0 : DUMP(prefix, "target_size: %d", target->u.kernel.target_size);
142 0 : DUMP(bf_dump_prefix_last(prefix), "target: %p", target->u.kernel.target);
143 0 : bf_dump_prefix_pop(prefix);
144 :
145 0 : DUMP((is_standard ? prefix : bf_dump_prefix_last(prefix)),
146 : "target_size: %d", target->u.target_size);
147 0 : if (is_standard) {
148 0 : DUMP(bf_dump_prefix_last(prefix), "verdict: %s",
149 : target_name[_bf_ipt_convert_verdict(std_target->verdict)]);
150 : }
151 :
152 0 : bf_dump_prefix_pop(prefix);
153 0 : }
154 :
155 0 : void bf_ipt_dump_replace(struct ipt_replace *ipt, prefix_t *prefix)
156 : {
157 0 : prefix_t _prefix = {};
158 0 : prefix = prefix ?: &_prefix;
159 : int i;
160 : uint32_t offset;
161 : struct ipt_entry *first_rule;
162 : struct ipt_entry *last_rule;
163 :
164 0 : DUMP(prefix, "struct ipt_replace at %p", ipt);
165 :
166 0 : bf_dump_prefix_push(prefix);
167 :
168 0 : DUMP(prefix, "name: '%s'", ipt->name);
169 0 : DUMP(prefix, "valid_hooks: " BIN_FMT "", BIN_SPLIT(ipt->valid_hooks));
170 0 : DUMP(prefix, "num_entries: %d", ipt->num_entries);
171 0 : DUMP(prefix, "size: %d", ipt->size);
172 0 : DUMP(bf_dump_prefix_last(prefix), "struct ipt_entry at %p", ipt->entries);
173 :
174 0 : bf_dump_prefix_push(prefix);
175 :
176 : // Loop over each hook to print its rules (if defined).
177 0 : for (i = 0; i < NF_INET_NUMHOOKS; ++i) {
178 0 : if (i == NF_INET_POST_ROUTING)
179 0 : bf_dump_prefix_last(prefix);
180 :
181 0 : if (!ipt_is_hook_enabled(ipt, i)) {
182 0 : DUMP(prefix, "%s: no rule defined", hook_name[i]);
183 0 : continue;
184 : }
185 :
186 0 : DUMP(prefix, "%s (from %x to %x):", hook_name[i], ipt->hook_entry[i],
187 : ipt->underflow[i]);
188 :
189 0 : bf_dump_prefix_push(prefix);
190 :
191 0 : first_rule = ipt_get_first_rule(ipt, i);
192 0 : last_rule = ipt_get_last_rule(ipt, i);
193 : offset = sizeof(*first_rule);
194 :
195 : // Loop over the rules for the current hook.
196 0 : while (first_rule <= last_rule) {
197 0 : if (first_rule == last_rule)
198 0 : bf_dump_prefix_last(prefix);
199 :
200 0 : DUMP(prefix, "struct ipt_entry at %p", first_rule);
201 :
202 0 : bf_dump_prefix_push(prefix);
203 :
204 0 : ipt_dump_ip(&first_rule->ip, prefix);
205 :
206 0 : DUMP(prefix, "target_offset: %d", first_rule->target_offset);
207 0 : DUMP(prefix, "next_offset: %d", first_rule->next_offset);
208 0 : DUMP(prefix, "comefrom: %d", first_rule->comefrom);
209 :
210 0 : ipt_dump_counters(&first_rule->counters, prefix);
211 :
212 : // Loop over the matches for the current rule.
213 0 : while (offset < first_rule->target_offset) {
214 0 : ipt_dump_match(ipt_get_match(first_rule, offset), prefix);
215 0 : offset += ipt_get_match(first_rule, offset)->u.match_size;
216 : }
217 :
218 0 : ipt_dump_target(ipt_get_target(first_rule),
219 : bf_dump_prefix_last(prefix));
220 :
221 0 : bf_dump_prefix_pop(prefix);
222 :
223 0 : if (!first_rule->next_offset)
224 : break;
225 :
226 0 : first_rule = ipt_get_next_rule(first_rule);
227 : }
228 0 : bf_dump_prefix_pop(prefix);
229 : }
230 :
231 0 : bf_dump_prefix_pop(prefix);
232 :
233 : // Force flush, otherwise output on stderr might appear.
234 0 : (void)fflush(stdout);
235 0 : }
|