Branch data Line data Source code
1 : : // tapset for netfilter hooks
2 : : // Copyright (C) 2012 Red Hat Inc.
3 : : //
4 : : // This file is part of systemtap, and is free software. You can
5 : : // redistribute it and/or modify it under the terms of the GNU General
6 : : // Public License (GPL); either version 2, or (at your option) any
7 : : // later version.
8 : :
9 : :
10 : : #include "session.h"
11 : : #include "tapsets.h"
12 : : #include "translate.h"
13 : : #include "util.h"
14 : : #include <cstring>
15 : : #include <string>
16 : : #include <limits.h>
17 : :
18 : : using namespace std;
19 : : using namespace __gnu_cxx;
20 : :
21 [ + - ]: 2414 : static const string TOK_NETFILTER("netfilter");
22 [ + - ]: 2414 : static const string TOK_HOOK("hook");
23 [ + - ]: 2414 : static const string TOK_PF("pf");
24 [ + - ]: 2414 : static const string TOK_PRIORITY("priority");
25 : :
26 : : // ------------------------------------------------------------------------
27 : : // netfilter derived probes
28 : : // ------------------------------------------------------------------------
29 : :
30 : :
31 [ # # ][ # # ]: 0 : struct netfilter_derived_probe: public derived_probe
[ # # ][ # # ]
[ # # ]
32 : : {
33 : : string hook;
34 : : string pf;
35 : : string priority;
36 : : unsigned nf_index;
37 : :
38 : : set<string> context_vars;
39 : :
40 : : netfilter_derived_probe (systemtap_session &, probe* p,
41 : : probe_point* l, string h,
42 : : string protof, string pri);
43 : : virtual void join_group (systemtap_session& s);
44 : : };
45 : :
46 : :
47 [ # # ]: 9 : struct netfilter_derived_probe_group: public generic_dpg<netfilter_derived_probe>
48 : : {
49 : : public:
50 : : void emit_module_decls (systemtap_session& s);
51 : : void emit_module_init (systemtap_session& s);
52 : : void emit_module_exit (systemtap_session& s);
53 : : };
54 : :
55 [ + - ][ + - ]: 12 : struct netfilter_var_expanding_visitor: public var_expanding_visitor
[ - + ]
56 : : {
57 : : netfilter_var_expanding_visitor(systemtap_session& s, const string& pn);
58 : :
59 : : systemtap_session& sess;
60 : : string probe_name;
61 : : set<string> context_vars;
62 : :
63 : : void visit_target_symbol (target_symbol* e);
64 : : };
65 : :
66 : 13 : netfilter_derived_probe::netfilter_derived_probe (systemtap_session &s, probe* p,
67 : : probe_point* l, string h,
68 : : string protof, string pri):
69 [ + - ][ + - ]: 13 : derived_probe (p, l), hook (h), pf (protof), priority (pri)
[ + - ][ + - ]
70 : : {
71 : : static unsigned nf_index_ctr = 0;
72 : 13 : this->nf_index = nf_index_ctr++; // PR14137: need to generate unique
73 : : // identifier, since p->name may be
74 : : // shared in c_unparser::emit_probe()
75 : :
76 : 13 : bool hook_error = false;
77 : 13 : bool pf_error = false;
78 : :
79 : : // Map the strings passed in to the actual values defined in netfilter_*.h
80 : : // NOTE: We need to hard code all the following
81 : : // constants rather than just include the
82 : : // appropriate kernel headers because in different
83 : : // versions of the kernel, certain constants are not
84 : : // defined. This was the best method at the time to
85 : : // get them to compile properly.
86 : :
87 : : // Validate hook, pf, priority
88 [ + - ][ + + ]: 13 : if(pf == "NFPROTO_IPV4")
89 : : {
90 : : // Protocol Family
91 [ + - ]: 11 : pf = "2";
92 : :
93 : : // Hook
94 [ + - ][ + + ]: 11 : if (hook == "NF_INET_PRE_ROUTING") hook = "0";
[ + - ]
95 [ + - ][ + - ]: 2 : else if (hook == "NF_INET_LOCAL_IN") hook = "1";
[ + - ]
96 [ # # ][ # # ]: 0 : else if (hook == "NF_INET_FORWARD") hook = "2";
[ # # ]
97 [ # # ][ # # ]: 0 : else if (hook == "NF_INET_LOCAL_OUT") hook = "3";
[ # # ]
98 [ # # ][ # # ]: 0 : else if (hook == "NF_INET_POST_ROUTING") hook = "4";
[ # # ]
99 [ # # ][ # # ]: 0 : else if (hook == "NF_IP_PRE_ROUTING") hook = "0";
[ # # ]
100 [ # # ][ # # ]: 0 : else if (hook == "NF_IP_LOCAL_IN") hook = "1";
[ # # ]
101 [ # # ][ # # ]: 0 : else if (hook == "NF_IP_FORWARD") hook = "2";
[ # # ]
102 [ # # ][ # # ]: 0 : else if (hook == "NF_IP_LOCAL_OUT") hook = "3";
[ # # ]
103 [ # # ][ # # ]: 0 : else if (hook == "NF_IP_POST_ROUTING") hook = "4";
[ # # ]
104 : 0 : else hook_error = true;
105 : :
106 : : // Priority
107 [ + - ][ - + ]: 11 : if (priority == "NF_IP_PRI_FIRST") priority = lex_cast(INT_MIN);
[ # # ][ # # ]
[ # # ]
108 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_CONNTRACK_DEFRAG") priority = "-400";
[ # # ]
109 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_RAW") priority = "-300";
[ # # ]
110 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_SELINUX_FIRST") priority = "-225";
[ # # ]
111 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_CONNTRACK") priority = "-200";
[ # # ]
112 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_MANGLE") priority = "-150";
[ # # ]
113 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_NAT_DST") priority = "-100";
[ # # ]
114 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_FILTER") priority = "0";
[ # # ]
115 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_SECURITY") priority = "50";
[ # # ]
116 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_NAT_SRC") priority = "100";
[ # # ]
117 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_SELINUX_LAST") priority = "225";
[ # # ]
118 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_CONNTRACK_CONFIRM") priority = lex_cast(INT_MAX);
[ # # ][ # # ]
[ # # ]
119 [ + - ][ - + ]: 11 : else if (priority == "NF_IP_PRI_LAST") priority = lex_cast(INT_MAX);
[ # # ][ # # ]
[ # # ]
120 : : }
121 [ + - ][ - + ]: 2 : else if(pf=="NFPROTO_IPV6")
122 : : {
123 : : // Protocol Family
124 [ # # ]: 0 : pf = "10";
125 : :
126 : : // Hook
127 [ # # ][ # # ]: 0 : if (hook == "NF_IP6_PRE_ROUTING") hook = "0";
[ # # ]
128 [ # # ][ # # ]: 0 : else if (hook == "NF_IP6_LOCAL_IN") hook = "1";
[ # # ]
129 [ # # ][ # # ]: 0 : else if (hook == "NF_IP6_FORWARD") hook = "2";
[ # # ]
130 [ # # ][ # # ]: 0 : else if (hook == "NF_IP6_LOCAL_OUT") hook = "3";
[ # # ]
131 [ # # ][ # # ]: 0 : else if (hook == "NF_IP6_POST_ROUTING") hook = "4";
[ # # ]
132 : 0 : else hook_error = true;
133 : :
134 : : // Priority
135 [ # # ][ # # ]: 0 : if (priority == "NF_IP6_PRI_FIRST") priority = lex_cast(INT_MIN);
[ # # ][ # # ]
[ # # ]
136 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_CONNTRACK_DEFRAG") priority = "-400";
[ # # ]
137 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_RAW") priority = "-300";
[ # # ]
138 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_SELINUX_FIRST") priority = "-225";
[ # # ]
139 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_CONNTRACK") priority = "-200";
[ # # ]
140 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_MANGLE") priority = "-150";
[ # # ]
141 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_NAT_DST") priority = "-100";
[ # # ]
142 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_FILTER") priority = "0";
[ # # ]
143 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_SECURITY") priority = "50";
[ # # ]
144 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_NAT_SRC") priority = "100";
[ # # ]
145 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_SELINUX_LAST") priority = "225";
[ # # ]
146 [ # # ][ # # ]: 0 : else if (priority == "NF_IP6_PRI_LAST") priority = lex_cast(INT_MAX);
[ # # ][ # # ]
[ # # ]
147 : : }
148 [ + - ][ - + ]: 2 : else if (pf == "NFPROTO_ARP")
149 : : {
150 : : // Protocol Family
151 [ # # ]: 0 : pf = "3";
152 : :
153 : : // Hook
154 [ # # ][ # # ]: 0 : if (hook == "NF_ARP_IN") hook = "0";
[ # # ]
155 [ # # ][ # # ]: 0 : else if (hook == "NF_ARP_OUT") hook = "1";
[ # # ]
156 [ # # ][ # # ]: 0 : else if (hook == "NF_ARP_FORWARD") hook = "2";
[ # # ]
157 : 0 : else hook_error = true;
158 : : }
159 [ + - ][ - + ]: 2 : else if (pf == "NFPROTO_BRIDGE")
160 : : {
161 : : // Protocol Family
162 [ # # ]: 0 : pf = "7";
163 : :
164 : : // Hook
165 [ # # ][ # # ]: 0 : if (hook == "NF_BR_PRE_ROUTING") hook = "0";
[ # # ]
166 [ # # ][ # # ]: 0 : else if (hook == "NF_BR_LOCAL_IN") hook = "1";
[ # # ]
167 [ # # ][ # # ]: 0 : else if (hook == "NF_BR_FORWARD") hook = "2";
[ # # ]
168 [ # # ][ # # ]: 0 : else if (hook == "NF_BR_LOCAL_OUT") hook = "3";
[ # # ]
169 [ # # ][ # # ]: 0 : else if (hook == "NF_BR_POST_ROUTING") hook = "4";
[ # # ]
170 : 0 : else hook_error = true;
171 : : }
172 : : else
173 : 2 : pf_error = true;
174 : :
175 : : // If not running in guru mode, we need more strict checks on hook name,
176 : : // protocol family and priority to avoid people putting in wacky embedded c
177 : : // nastiness. Otherwise, and if it didn't match any of the above lists,
178 : : // pass the string in as is.
179 [ + + ]: 13 : if(!s.guru_mode)
180 : : {
181 : : // At this point the priority should be a 32 bit integer encoded as a string.
182 : : // Ensure that this is the case.
183 : : try
184 : : {
185 [ + - ]: 9 : int prio = lex_cast<int32_t>(priority);
186 : : (void) prio;
187 : : }
188 [ # # ]: : catch (const runtime_error&)
189 : : {
190 : : throw semantic_error
191 : : (_F("unsupported netfilter priority \"%s\" for protocol family \"%s\"; need stap -g",
192 [ # # # # : : priority.c_str(), pf.c_str()));
# # # # ]
193 : : }
194 : :
195 : : // Complain and abort if there were any hook name errors
196 [ - + ]: 9 : if (hook_error)
197 : : throw semantic_error
198 : 0 : (_F("unsupported netfilter hook \"%s\" for protocol family \"%s\"; need stap -g",
199 [ # # ][ # # ]: 0 : hook.c_str(), pf.c_str()));
[ # # ][ # # ]
200 : :
201 : : // Complain and abort if there were any pf errors
202 [ + + ]: 9 : if (pf_error)
203 : : throw semantic_error
204 [ + - ][ + - ]: 1 : (_F("unsupported netfilter protocol family \"%s\"; need stap -g", pf.c_str()));
[ + - ]
205 : : }
206 : :
207 : : // Expand local variables in the probe body
208 [ + - ]: 12 : netfilter_var_expanding_visitor v (s, name);
209 [ + - ]: 12 : v.replace (this->body);
210 : :
211 : : // Create probe-local vardecls, before symbol resolution might make
212 : : // one for us, so that we can set the all-important synthetic flag.
213 [ + - ][ + + ]: 54 : for (set<string>::iterator it = v.context_vars.begin();
214 [ + - ]: 27 : it != v.context_vars.end();
215 : : it++)
216 : : {
217 [ + - ]: 15 : string name = *it;
218 [ + - ]: 15 : this->context_vars.insert(name);
219 [ + - ][ + - ]: 15 : vardecl *v = new vardecl;
220 [ + - ]: 15 : v->name = name;
221 : 15 : v->tok = this->tok; /* XXX: but really the $context var. */
222 [ + - ]: 15 : v->set_arity (0, this->tok);
223 : 15 : v->type = pe_long;
224 : 15 : v->synthetic = true; // suppress rvalue or lvalue optimizations
225 [ + - ]: 15 : this->locals.push_back (v);
226 [ + - ][ + - ]: 28 : }
227 : 13 : }
228 : :
229 : : void
230 : 12 : netfilter_derived_probe::join_group (systemtap_session& s)
231 : : {
232 [ + + ]: 12 : if (! s.netfilter_derived_probes)
233 [ + - ]: 9 : s.netfilter_derived_probes = new netfilter_derived_probe_group ();
234 : 12 : s.netfilter_derived_probes->enroll (this);
235 : 12 : }
236 : :
237 : :
238 : : void
239 : 6 : netfilter_derived_probe_group::emit_module_decls (systemtap_session& s)
240 : : {
241 [ - + ]: 12 : if (probes.empty()) return;
242 : :
243 : : // Here we emit any global data structures and functions, including callback functions
244 : : // to be invoked by netfilter.
245 : : //
246 : : // For other kernel callbacks, a token is passed back to help identify a particular
247 : : // probe-point registration. For netfilter, nope, so once we're in a notification callback,
248 : : // we can't find out exactly on whose (which probe point's) behalf we were called.
249 : : //
250 : : // So, we just emit one netfilter callback function per systemtap probe, each with its
251 : : // own nf_hook_ops structure. Note that the translator already emits a stp_probes[] array,
252 : : // pre-filled with probe names and handler functions and that sort of stuff.
253 : :
254 : 6 : s.op->newline() << "/* ---- netfilter probes ---- */";
255 : :
256 : 6 : s.op->newline() << "#include <linux/netfilter.h>";
257 : 6 : s.op->newline() << "#include <linux/skbuff.h>";
258 : 6 : s.op->newline() << "#include <linux/udp.h>";
259 : 6 : s.op->newline() << "#include <linux/tcp.h>";
260 : 6 : s.op->newline() << "#include <linux/ip.h>";
261 : :
262 [ + + ]: 15 : for (unsigned i=0; i < probes.size(); i++)
263 : : {
264 : 9 : netfilter_derived_probe *np = probes[i];
265 [ + - ][ + - ]: 9 : s.op->newline() << "static unsigned int enter_netfilter_probe_" << np->nf_index;
[ + - ]
266 : :
267 : : // Previous to kernel 2.6.22, the hookfunction definition takes a struct sk_buff **skb,
268 : : // whereas currently it uses a *skb. We need emit the right version so this will
269 : : // compile on RHEL5, for example.
270 [ + - ][ + - ]: 9 : s.op->newline() << "#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22)";
271 [ + - ][ + - ]: 9 : s.op->newline() << "(unsigned int nf_hooknum, struct sk_buff *nf_skb, const struct net_device *nf_in, const struct net_device *nf_out, int (*nf_okfn)(struct sk_buff *))";
272 [ + - ][ + - ]: 9 : s.op->newline() << "{";
273 : :
274 [ + - ][ + - ]: 9 : s.op->newline() << "#else";
275 : :
276 [ + - ][ + - ]: 9 : s.op->newline() << "(unsigned int nf_hooknum, struct sk_buff **nf_pskb, const struct net_device *nf_in, const struct net_device *nf_out, int (*nf_okfn)(struct sk_buff *))";
277 [ + - ][ + - ]: 9 : s.op->newline() << "{";
278 [ + - ][ + - ]: 9 : s.op->newline(1) << "struct sk_buff *nf_skb = nf_pskb ? *nf_pskb : NULL;";
279 : :
280 [ + - ][ + - ]: 9 : s.op->newline(-1) << "#endif";
281 [ + - ][ + - ]: 9 : s.op->newline(1) << "const struct stap_probe * const stp = & stap_probes[" << np->session_index << "];";
[ + - ][ + - ]
282 [ + - ][ + - ]: 9 : s.op->newline() << "int nf_verdict = NF_ACCEPT;"; // default NF_ACCEPT, to be used by $verdict context var
283 : : common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp",
284 : : "stp_probe_type_netfilter",
285 [ + - ][ + - ]: 9 : false);
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
286 : :
287 : : // Copy or pretend-to-touch each incoming parameter.
288 : :
289 [ + - ][ + - ]: 9 : string c_p = "c->probe_locals." + lex_cast(np->name); // this is where the $context vars show up
[ + - ]
290 : : // NB: PR14137: this should be the potentially shared name,
291 : : // since the generated probe handler body refers to that name.
292 : :
293 [ + - ][ + - ]: 9 : if (np->context_vars.find("__nf_hooknum") != np->context_vars.end())
[ + - ][ + - ]
[ - + ]
294 [ # # ][ # # ]: 0 : s.op->newline() << c_p + "." + s.up->c_localname("__nf_hooknum") + " = (int64_t)(uintptr_t) nf_hooknum;";
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
295 : : else
296 [ + - ][ + - ]: 9 : s.op->newline() << "(void) nf_hooknum;";
297 [ + - ][ + - ]: 9 : if (np->context_vars.find("__nf_skb") != np->context_vars.end())
[ + - ][ + - ]
[ + + ]
298 [ + - ][ + - ]: 2 : s.op->newline() << c_p + "." + s.up->c_localname("__nf_skb") + " = (int64_t)(uintptr_t) nf_skb;";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
299 : : else
300 [ + - ][ + - ]: 7 : s.op->newline() << "(void) nf_skb;";
301 [ + - ][ + - ]: 9 : if (np->context_vars.find("__nf_in") != np->context_vars.end())
[ + - ][ + - ]
[ + + ]
302 [ + - ][ + - ]: 2 : s.op->newline() << c_p + "." + s.up->c_localname("__nf_in") + " = (int64_t)(uintptr_t) nf_in;";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
303 : : else
304 [ + - ][ + - ]: 7 : s.op->newline() << "(void) nf_in;";
305 [ + - ][ + - ]: 9 : if (np->context_vars.find("__nf_out") != np->context_vars.end())
[ + - ][ + - ]
[ + + ]
306 [ + - ][ + - ]: 2 : s.op->newline() << c_p + "." + s.up->c_localname("__nf_in") + " = (int64_t)(uintptr_t) nf_out;";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
307 : : else
308 [ + - ][ + - ]: 7 : s.op->newline() << "(void) nf_out;";
309 [ + - ][ + - ]: 9 : if (np->context_vars.find("__nf_verdict") != np->context_vars.end())
[ + - ][ + - ]
[ + + ]
310 [ + - ][ + - ]: 2 : s.op->newline() << c_p + "." + s.up->c_localname("__nf_verdict") + " = (int64_t) nf_verdict;";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
311 : : else
312 [ + - ][ + - ]: 7 : s.op->newline() << "(void) nf_out;";
313 : :
314 : : // Invoke the probe handler
315 [ + - ][ + - ]: 9 : s.op->newline() << "(*stp->ph) (c);";
316 : :
317 [ + - ]: 9 : common_probe_entryfn_epilogue (s, false);
318 : :
319 [ + - ][ + - ]: 9 : if (np->context_vars.find("__nf_verdict") != np->context_vars.end())
[ + - ][ + - ]
[ + + ]
320 [ + - ][ + - ]: 2 : s.op->newline() << "nf_verdict = (int) "+c_p+"." + s.up->c_localname("__nf_verdict") + ";";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
321 : :
322 [ + - ][ + - ]: 9 : s.op->newline() << "return nf_verdict;";
323 [ + - ][ + - ]: 9 : s.op->newline(-1) << "}";
324 : :
325 : : // now emit the nf_hook_ops struct for this probe.
326 [ + - ][ + - ]: 9 : s.op->newline() << "static struct nf_hook_ops netfilter_opts_" << np->nf_index << " = {";
[ + - ][ + - ]
327 [ + - ][ + - ]: 9 : s.op->newline() << ".hook = enter_netfilter_probe_" << np->nf_index << ",";
[ + - ][ + - ]
328 [ + - ][ + - ]: 9 : s.op->newline() << ".owner = THIS_MODULE,";
329 : :
330 : : // XXX: if these strings/numbers are not range-limited / validated before we get here,
331 : : // ie during the netfilter_derived_probe ctor, then we will emit potential trash here,
332 : : // leading to all kinds of horror. Like zombie women eating roach-filled walnuts. Dogs
333 : : // and cats living together. Foreign foods taking over the refrigerator. Don't let this
334 : : // happen to you!
335 [ + - ][ + - ]: 9 : s.op->newline() << ".hooknum = " << np->hook << ",";
[ + - ][ + - ]
336 [ + - ][ + - ]: 9 : s.op->newline() << ".pf = " << np->pf << ",";
[ + - ][ + - ]
337 [ + - ][ + - ]: 9 : s.op->newline() << ".priority = " << np->priority << ",";
[ + - ][ + - ]
338 [ + - ][ + - ]: 9 : s.op->newline() << "};";
339 [ + - ]: 9 : }
340 : 6 : s.op->newline();
341 : : }
342 : :
343 : :
344 : : void
345 : 6 : netfilter_derived_probe_group::emit_module_init (systemtap_session& s)
346 : : {
347 [ - + ]: 12 : if (probes.empty()) return;
348 : :
349 : : // We register (do not execute) the probes here.
350 : : // NB: since we anticipate only a few netfilter/hook type probes, there is no need to
351 : : // emit an initialization loop into the generated C code. We can simply unroll it.
352 [ + + ]: 15 : for (unsigned i=0; i < probes.size(); i++)
353 : : {
354 : 9 : netfilter_derived_probe *np = probes[i];
355 : 9 : s.op->newline() << "rc = nf_register_hook (& netfilter_opts_" << np->nf_index << ");";
356 [ + + ]: 9 : if (i > 0) // unregister others upon failure
357 : : {
358 : 3 : s.op->newline() << "if (rc < 0) {";
359 : 3 : s.op->indent(1);
360 [ + + ]: 7 : for (int j=i-1; j>=0; j--) // XXX: j must be signed for loop to work
361 : : {
362 : 4 : netfilter_derived_probe *np2 = probes[j];
363 : 4 : s.op->newline() << "nf_unregister_hook (& netfilter_opts_" << np2->nf_index << ");";
364 : : }
365 : 3 : s.op->newline(-1) << "}";
366 : : }
367 : : }
368 : : }
369 : :
370 : :
371 : : void
372 : 6 : netfilter_derived_probe_group::emit_module_exit (systemtap_session& s)
373 : : {
374 [ - + ]: 12 : if (probes.empty()) return;
375 : :
376 : : // We register (do not execute) the probes here.
377 [ + + ]: 15 : for (unsigned i=0; i < probes.size(); i++)
378 : : {
379 : 9 : netfilter_derived_probe *np = probes[i];
380 : 9 : s.op->newline() << "nf_unregister_hook (& netfilter_opts_" << np->nf_index << ");";
381 : : }
382 : : }
383 : :
384 : :
385 : 12 : netfilter_var_expanding_visitor::netfilter_var_expanding_visitor (systemtap_session& s,
386 : : const string& pn):
387 [ + - ][ + - ]: 12 : sess (s), probe_name (pn)
388 : : {
389 : 12 : }
390 : :
391 : :
392 : : void
393 : 23 : netfilter_var_expanding_visitor::visit_target_symbol (target_symbol* e)
394 : : {
395 : : try
396 : : {
397 [ + - ][ + - ]: 23 : assert(e->name.size() > 0 && e->name[0] == '$');
[ + - ][ - + ]
398 : :
399 [ - + ]: 23 : if (e->addressof)
400 [ # # ][ # # ]: 0 : throw semantic_error(_("cannot take address of netfilter hook context variable"), e->tok);
401 : :
402 : : // We map all $context variables to similarly named probe locals.
403 : : // See emit_module_decls for how the parameters & result are handled.
404 [ + - ]: 23 : string c_var;
405 : 23 : bool lvalue_ok = false;
406 : 23 : bool need_guru = false;
407 [ + - ][ - + ]: 23 : if (e->name == "$hooknum") { c_var = "__nf_hooknum"; }
[ # # ]
408 [ + - ][ + + ]: 23 : else if (e->name == "$skb") { c_var = "__nf_skb"; }
[ + - ]
409 [ + - ][ + + ]: 11 : else if (e->name == "$in") { c_var = "__nf_in"; }
[ + - ]
410 [ + - ][ + + ]: 7 : else if (e->name == "$out") { c_var = "__nf_out"; }
[ + - ]
411 [ + - ][ - + ]: 3 : else if (e->name == "$okfn") { c_var = "__nf_okfn"; }
[ # # ]
412 [ + - ][ + - ]: 3 : else if (e->name == "$verdict") { c_var = "__nf_verdict"; lvalue_ok = true; need_guru = true; }
[ + - ]
413 : : // XXX: also support $$vars / $$parms
414 : : else
415 [ # # ][ # # ]: 0 : throw semantic_error(_("unsupported context variable"), e->tok);
416 : :
417 [ + + ][ + - ]: 23 : if (! lvalue_ok && is_active_lvalue (e))
[ - + ][ - + ]
418 [ # # ][ # # ]: 0 : throw semantic_error(_("write to netfilter parameter not permitted"), e->tok);
419 : :
420 : : // Writing to variables like $verdict requires guru mode, for obvious reasons
421 [ + + ][ - + ]: 23 : if(need_guru && !sess.guru_mode)
422 [ # # ][ # # ]: 0 : throw semantic_error(_("write to netfilter verdict requires guru mode; need stap -g"), e->tok);
423 : :
424 [ + - ]: 23 : context_vars.insert (c_var);
425 : :
426 : : // Synthesize a symbol to reference those variables
427 [ + - ][ + - ]: 23 : symbol* sym = new symbol;
428 : 23 : sym->type = pe_long;
429 : 23 : sym->tok = e->tok;
430 [ + - ]: 23 : sym->name = c_var;
431 [ + - ][ + - ]: 23 : provide (sym);
432 : : }
433 [ # # ]: : catch (const semantic_error &er)
434 : : {
435 [ # # ]: : e->chain (er);
436 [ # # ]: : provide (e);
437 : : }
438 : 23 : }
439 : : // ------------------------------------------------------------------------
440 : : // unified probe builder for netfilter probes
441 : : // ------------------------------------------------------------------------
442 : :
443 : :
444 [ # # ]: 1218 : struct netfilter_builder: public derived_probe_builder
445 : : {
446 : : virtual void build(systemtap_session & sess,
447 : : probe * base, probe_point * location,
448 : : literal_map_t const & parameters,
449 : : vector<derived_probe *> & finished_results);
450 : :
451 : : static void register_patterns(systemtap_session& s);
452 : : };
453 : :
454 : :
455 : : void
456 : 13 : netfilter_builder::build(systemtap_session & sess,
457 : : probe * base,
458 : : probe_point * location,
459 : : literal_map_t const & parameters,
460 : : vector<derived_probe *> & finished_results)
461 : : {
462 [ + - ]: 13 : string hook; // no default
463 [ + - ]: 13 : string pf; // no default
464 [ + - ]: 13 : string priority = "0"; // Default: somewhere in the middle
465 : :
466 [ + - ][ - + ]: 13 : if(!get_param(parameters, TOK_HOOK, hook))
467 [ # # ][ # # ]: 0 : throw semantic_error (_("missing hooknum"));
468 : :
469 [ + - ][ - + ]: 13 : if(!get_param(parameters, TOK_PF, pf))
470 [ # # ][ # # ]: 0 : throw semantic_error (_("missing protocol family"));
471 : :
472 [ + - ]: 13 : get_param(parameters, TOK_PRIORITY, priority);
473 : :
474 [ + - ][ + - ]: 13 : finished_results.push_back(new netfilter_derived_probe(sess, base, location, hook, pf, priority));
[ + - ][ + - ]
[ + + ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
475 : 12 : }
476 : :
477 : : void
478 : 1218 : register_tapset_netfilter(systemtap_session& s)
479 : : {
480 : 1218 : match_node* root = s.pattern_root;
481 : 1218 : derived_probe_builder *builder = new netfilter_builder();
482 : :
483 : :
484 : : //netfilter.hook().pf()
485 : 1218 : root->bind(TOK_NETFILTER)->bind_str(TOK_HOOK)->bind_str(TOK_PF)->bind(builder);
486 : :
487 : : //netfilter.pf().hook()
488 : 1218 : root->bind(TOK_NETFILTER)->bind_str(TOK_PF)->bind_str(TOK_HOOK)->bind(builder);
489 : :
490 : : //netfilter.hook().pf().priority()
491 : 1218 : root->bind(TOK_NETFILTER)->bind_str(TOK_HOOK)->bind_str(TOK_PF)->bind_str(TOK_PRIORITY)->bind(builder);
492 : :
493 : : //netfilter.pf().hook().priority()
494 : 1218 : root->bind(TOK_NETFILTER)->bind_str(TOK_PF)->bind_str(TOK_HOOK)->bind_str(TOK_PRIORITY)->bind(builder);
495 [ + - ][ + - ]: 8460 : }
496 : :
497 : : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
|