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