From cc0901e06ffd9b0c156d399d80f3c92479c0477c Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 12 Apr 2012 16:19:36 -0400 Subject: [PATCH] PR13667: rework/simplify rough draft for netfilter.hook probes --- tapset-nethook.cxx | 241 +++++++++++++++++++-------------------------- 1 file changed, 101 insertions(+), 140 deletions(-) diff --git a/tapset-nethook.cxx b/tapset-nethook.cxx index 8d1e5bcca..0f28fda1c 100644 --- a/tapset-nethook.cxx +++ b/tapset-nethook.cxx @@ -1,7 +1,5 @@ -// tapset for nethooks -// Copyright (C) 2005-2011 Red Hat Inc. -// Copyright (C) 2005-2007 Intel Corporation. -// Copyright (C) 2008 +// tapset for netfilter hooks +// Copyright (C) 2012 Red Hat Inc. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General @@ -21,31 +19,25 @@ using namespace std; using namespace __gnu_cxx; -static const string TOK_NETHOOK("nethook"); +static const string TOK_NETFILTER("netfilter"); +static const string TOK_HOOK("hook"); // ------------------------------------------------------------------------ -// nethook derived probes +// netfilter derived probes // ------------------------------------------------------------------------ -struct nethook_derived_probe: public derived_probe +struct netfilter_derived_probe: public derived_probe { - int64_t hook, protocol; - nethook_derived_probe (probe* p, probe_point* l, - int64_t hook, int64_t hooknum); + netfilter_derived_probe (probe* p, probe_point* l); virtual void join_group (systemtap_session& s); - - // No assertion need be emitted, since this probe is allowed for unprivileged - // users. - void emit_privilege_assertion (translator_output*) {} void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); } }; -struct nethook_derived_probe_group: public generic_dpg +struct netfilter_derived_probe_group: public generic_dpg { - void emit_netfunc (translator_output* o); public: void emit_module_decls (systemtap_session& s); void emit_module_init (systemtap_session& s); @@ -53,93 +45,38 @@ public: }; -nethook_derived_probe::nethook_derived_probe (probe* p, probe_point* l, - int64_t h, int64_t proto, int64_t r): - derived_probe (p, l), hook (h), protocol (proto), resault(r) +netfilter_derived_probe::netfilter_derived_probe (probe* p, probe_point* l): + derived_probe (p, l) { - if (hook < 0 || hook > 4) // h must be within hooks - //TRANSLATORS: 'nethook' is the name of a probe point - throw semantic_error (_("invalid hook for nethook")); - - if (proto < 0 || proto > 255) - //TRANSLATORS: 'protocol' is a key word - throw semantic_error (_("invalid protocol for nethook")); - - if (locations.size() != 1) - throw semantic_error (_("only expect one probe point")); - // so we don't have to loop over them in the other functions } void -nethook_derived_probe::join_group (systemtap_session& s) +netfilter_derived_probe::join_group (systemtap_session& s) { - if (! s.nethook_derived_probes) - s.nethook_derived_probes = new nethook_derived_probe_group (); - s.nethook_derived_probes->enroll (this); + if (! s.netfilter_derived_probes) + s.netfilter_derived_probes = new netfilter_derived_probe_group (); + s.netfilter_derived_probes->enroll (this); } void -nethook_derived_probe_group::emit_netfunc (systemtap_session& s) -{ - s.op->newline() << "unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))"; - s.op->newline() << "{"; - s.op->newline(1) << "sock_buff = skb;"; - s.op->newline() << "if(!sock_buff) { return NF_ACCEPT;}"; - s.op->newline() << "ip_header = (struct iphdr *)skb_network_header(sock_buff);"; - s.op->newline() << "if(!ip_header) { return NF_ACCEPT;}"; - s.op->newline() << "if (ip_header->protocol==TCP) {"; - s.op->newline(1) << "tcp_header = (struct tcphdr *)skb_transport_header(sock_buff);"; - s.op->newline() << "printk(KERN_INFO \"[TCP, HTTP] Packet Recieved...\n From: %d.%d.%d.%d:%d\n To:%d.%d.%d.%d:%d\","; - s.op->newline(1) << "(ip_header->saddr & 0x000000FF),"; - s.op->newline() << "(ip_header->saddr & 0x0000FF00) >> 8,"; - s.op->newline() << "(ip_header->saddr & 0x00FF0000) >> 16,"; - s.op->newline() << "(ip_header->saddr & 0xFF000000) >> 24,"; - s.op->newline() << "ntohs(tcp_header->source),"; - s.op->newline() << "(ip_header->daddr & 0x000000FF),"; - s.op->newline() << "(ip_header->daddr & 0x0000FF00) >> 8,"; - s.op->newline() << "(ip_header->daddr & 0x00FF0000) >> 16,"; - s.op->newline() << "(ip_header->daddr & 0xFF000000) >> 24,"; - s.op->newline() << "ntohs(tcp_header->dest));"; - s.op->newline(-1) << "return NF_ACCEPT;"; - s.op->newline(-1) << "}"; - s.op->newline() << "return NF_ACCEPT;"; - s.op->newline(-1) << "}"; -} - - -void -nethook_derived_probe_group::emit_module_decls (systemtap_session& s) +netfilter_derived_probe_group::emit_module_decls (systemtap_session& s) { if (probes.empty()) return; - s.op->newline() << "/* ---- nethook probes ---- */"; - - s.op->newline() << "static struct stap_nethook_probe {"; - s.op->newline(1) << "struct nethook_list nethook_list;"; - s.op->newline() << "struct stap_probe * const probe;"; - s.op->newline() << "unsigned hook, protocol;"; - s.op->newline(-1) << "} stap_nethook_probes [" << probes.size() << "] = {"; - s.op->indent(1); - for (unsigned i=0; i < probes.size(); i++) - { - s.op->newline () << "{"; - s.op->line() << " .probe=" << common_probe_init (probes[i]) << ","; - s.op->line() << " .hook=" << probes[i]->hook << ","; - s.op->line() << " .protocol=" << probes[i]->protocol << ","; - s.op->line() << " },"; - } - s.op->newline(-1) << "};"; - s.op->newline(); - - s.op->newline() << "static void enter_nethook_probe (struct stap_be_probe *stp) {"; - s.op->indent(1); - common_probe_entryfn_prologue (s.op, "stp->state", "stp->probe", - "_STP_PROBE_HANDLER_NETHOOK", false); - s.op->newline() << "(*stp->probe->ph) (c);"; - common_probe_entryfn_epilogue (s.op, false, s.suppress_handler_errors); - s.op->newline(-1) << "}"; + // Here we emit any global data structures and functions, including callback functions + // to be invoked by netfilter. + // + // For other kernel callbacks, a token is passed back to help identify a particular + // probe-point registration. For netfilter, nope, so once we're in a notification callback, + // we can't find out exactly on whose (which probe point's) behalf we were called. + // + // So, we just emit one netfilter callback function per systemtap probe, each with its + // own nf_hook_ops structure. Note that the translator already emits a stp_probes[] array, + // pre-filled with probe names and handler functions and that sort of stuff. + + s.op->newline() << "/* ---- netfilter probes ---- */"; s.op->newline() << "#include "; s.op->newline() << "#include "; @@ -147,58 +84,90 @@ nethook_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "#include "; s.op->newline() << "#include "; s.op->newline() << "#include "; - s.op->newline() << "#define TCP 6"; - s.op->newline() << "#define UDP 17"; - s.op->newline() << "static struct nf_hook_ops nfho;"; - s.op->newline() << "struct sk_buff *sock_buff;"; - s.op->newline() << "struct udphdr *udp_header;"; - s.op->newline() << "struct tcphdr *tcp_header;"; - s.op->newline() << "struct iphdr *ip_header;"; + + for (unsigned i=0; i < probes.size(); i++) + { + netfilter_derived_probe *np = probes[i]; + s.op->newline() << "static void enter_netfilter_probe_" << np->name; + s.op->newline() << "(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))"; + s.op->newline() << "{"; + s.op->newline(1) << "struct stap_probe * const stp = & stap_probes[", p->session_index << "];"; + common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp", + "_STP_PROBE_HANDLER_NETFILTER", + false); + // Pretend to touch each netfilter hook callback argument, so we + // don't get complaints about unused parameters. + s.op->newline() << "(void) hooknum;"; + s.op->newline() << "(void) skb;"; + s.op->newline() << "(void) in;"; + s.op->newline() << "(void) out;"; + s.op->newline() << "(void) okfn;"; + // Finally, invoke the probe handler + s.op->newline() << "(*stp->ph) (c);"; + common_probe_entryfn_epilogue (s.op, false, s.suppress_handler_errors); + s.op->newline() << "return NF_ACCEPT;"; // XXX: this could instead be an output from the handler + s.op->newline(-1) << "}"; + + // now emit the nf_hook_ops struct for this probe. + s.op->newline() << "static struct nf_hook_ops netfilter_opts_ = {" << np->name; + s.op->newline() << ".hook = & enter_netfilter_probe_" << np->name << ","; + s.op->newline() << ".owner = THIS_MODULE,"; + s.op->newline() << ".hooknum = 0,"; // XXX: should be probe point argument + s.op->newline() << ".pf = PF_INET,"; // XXX: should be probe point argument + s.op->newline() << ".priority = PF_INET,"; // XXX: should be probe point argument + s.op->newline(-1) << "};"; + } + s.op->newline(); } void -nethook_derived_probe_group::emit_module_init (systemtap_session& s) +netfilter_derived_probe_group::emit_module_init (systemtap_session& s) { if (probes.empty()) return; - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {"; - s.op->newline(1) << "struct stap_nethook_probe* stp = & stap_nethook_probes [i];"; - s.op->newline(1) << "enter_nethook_probe (stp); /* rc = 0 */"; - s.op->newline() << "stap_nethook_probes[i].hook = hook_func;"; - s.op->newline() << "stap_nethook_probes[i].hooknum = 0;"; - s.op->newline() << "stap_nethook_probes[i].pf = PF_INET;"; - s.op->newline() << "stap_nethook_probes[i].priority = NF_IP_PRI_FIRST;"; - s.op->newline() << "int rc = nf_register_hook(&stap_nethook_probes[i]);"; - s.op->newline() << "if (rc < 0)"; - s.op->newline() << "{"; - s.op->newline(1) << "for (j=i-1; j>=0; j--)"; - s.op->newline(1) << "nf_unregister_hook(&stap_nethook_probes[j]);"; - s.op->newline(-2) << "}"; - s.op->newline(-1) << "}"; - - emit_netfunc(s.op); + // We register (do not execute) the probes here. + // NB: since we anticipate only a few netfilter/hook type probes, there is no need to + // emit an initialization loop into the generated C code. We can simply unroll it. + for (unsigned i=0; i < probes.size(); i++) + { + netfilter_derived_probe *np = probes[i]; + s.op->newline() << "rc = nf_register_hook (& netfilter_opts_" << np->name << ");"; + if (i > 0) // unregister others upon failure + { + s.op->newline() << "if (rc < 0) {"; + s.op->newline(1); + for (unsigned j=i-1; j>=0; j++) + { + netfilter_derived_probe *np2 = probes[j]; + s.op->newline() << "nf_unregister_hook (& netfilter_opts_" << np2->name << ");"; + } + s.op->newline(-1) << "}"; + } + } } void -nethook_derived_probe_group::emit_module_exit (systemtap_session& s) +netfilter_derived_probe_group::emit_module_exit (systemtap_session& s) { - if (probes.empty()) return; - s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)"; - s.op->newline(1) << "nf_unregister_hook(&stap_nethook_probes[i]);"; - s.op->indent(-1); - - + if (probes.empty()) return; + + // We register (do not execute) the probes here. + for (unsigned i=0; i < probes.size(); i++) + { + netfilter_derived_probe *np = probes[i]; + s.op->newline() << "nf_unregister_hook (& netfilter_opts_" << np->name << ");"; + } } // ------------------------------------------------------------------------ -// unified probe builder for nethook probes +// unified probe builder for netfilter probes // ------------------------------------------------------------------------ -struct nethook_builder: public derived_probe_builder +struct netfilter_builder: public derived_probe_builder { virtual void build(systemtap_session & sess, probe * base, probe_point * location, @@ -208,35 +177,27 @@ struct nethook_builder: public derived_probe_builder static void register_patterns(systemtap_session& s); }; + void -nethook_builder::build(systemtap_session & sess, +netfilter_builder::build(systemtap_session & sess, probe * base, probe_point * location, literal_map_t const & parameters, vector & finished_results) { - int64_t hook, protocol; - - - if (get_param(parameters, "hook", hook) && get_param(parameters, "protocol", protocol)); - { - finished_results.push_back - (new nethook_derived_probe(base, location, hook, protocol)); - } - return; + // XXX: extract optional probe point arguments later + finished_results.push_back(new netfilter_derived_probe(base, location)); } + void -register_tapset_nethooks(systemtap_session& s) +register_tapset_netfilters(systemtap_session& s) { match_node* root = s.pattern_root; - derived_probe_builder *builder = new nethook_builder(); - - root = root->bind(TOK_NETHOOK); + derived_probe_builder *builder = new netfilter_builder(); - root->bind_num(TOK_NETHOOK) - ->bind_privilege(pr_all) - ->bind(builder); + // netfilter.hook + root->bind(TOK_NETFILTER)->bind(TOK_HOOK)->bind(builder); } /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ -- 2.43.5