Add dtrace SDT probe ipfw:::rule-matched.
It helps to reduce complexity with debugging of large ipfw rulesets. Also define several constants and translators, that can by used by dtrace scripts with this probe. Reviewed by: gnn Obtained from: Yandex LLC MFC after: 2 weeks Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D26879
This commit is contained in:
parent
2f1c35053c
commit
7ec2f6bce5
@ -21,7 +21,7 @@ SCRIPTS= blocking \
|
|||||||
|
|
||||||
SCRIPTSDIR= ${SHAREDIR}/dtrace
|
SCRIPTSDIR= ${SHAREDIR}/dtrace
|
||||||
|
|
||||||
DSRCS= mbuf.d
|
DSRCS= mbuf.d ipfw.d
|
||||||
|
|
||||||
FILES= ${DSRCS}
|
FILES= ${DSRCS}
|
||||||
FILESDIR= /usr/lib/dtrace
|
FILESDIR= /usr/lib/dtrace
|
||||||
|
219
share/dtrace/ipfw.d
Normal file
219
share/dtrace/ipfw.d
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/*-
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Yandex LLC
|
||||||
|
* Copyright (c) 2020 Andrey V. Elsukov <ae@FreeBSD.org>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $FreeBSD$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma D depends_on provider ipfw
|
||||||
|
|
||||||
|
/* ipfw_chk() return values */
|
||||||
|
#pragma D binding "1.0" IP_FW_PASS
|
||||||
|
inline int IP_FW_PASS = 0;
|
||||||
|
#pragma D binding "1.0" IP_FW_DENY
|
||||||
|
inline int IP_FW_DENY = 1;
|
||||||
|
#pragma D binding "1.0" IP_FW_DIVERT
|
||||||
|
inline int IP_FW_DIVERT = 2;
|
||||||
|
#pragma D binding "1.0" IP_FW_TEE
|
||||||
|
inline int IP_FW_TEE = 3;
|
||||||
|
#pragma D binding "1.0" IP_FW_DUMMYNET
|
||||||
|
inline int IP_FW_DUMMYNET = 4;
|
||||||
|
#pragma D binding "1.0" IP_FW_NETGRAPH
|
||||||
|
inline int IP_FW_NETGRAPH = 5;
|
||||||
|
#pragma D binding "1.0" IP_FW_NGTEE
|
||||||
|
inline int IP_FW_NGTEE = 6;
|
||||||
|
#pragma D binding "1.0" IP_FW_NAT
|
||||||
|
inline int IP_FW_NAT = 7;
|
||||||
|
#pragma D binding "1.0" IP_FW_REASS
|
||||||
|
inline int IP_FW_REASS = 8;
|
||||||
|
#pragma D binding "1.0" IP_FW_NAT64
|
||||||
|
inline int IP_FW_NAT64 = 9;
|
||||||
|
|
||||||
|
#pragma D binding "1.0" ipfw_retcodes
|
||||||
|
inline string ipfw_retcodes[int ret] =
|
||||||
|
ret == IP_FW_PASS ? "PASS" :
|
||||||
|
ret == IP_FW_DENY ? "DENY" :
|
||||||
|
ret == IP_FW_DIVERT ? "DIVERT" :
|
||||||
|
ret == IP_FW_TEE ? "TEE" :
|
||||||
|
ret == IP_FW_DUMMYNET ? "DUMMYNET" :
|
||||||
|
ret == IP_FW_NETGRAPH ? "NETGRAPH" :
|
||||||
|
ret == IP_FW_NGTEE ? "NGTEE" :
|
||||||
|
ret == IP_FW_NAT ? "NAT" :
|
||||||
|
ret == IP_FW_REASS ? "REASS" :
|
||||||
|
ret == IP_FW_NAT64 ? "NAT64" :
|
||||||
|
"<unknown>";
|
||||||
|
|
||||||
|
/* ip_fw_args flags */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_ETHER
|
||||||
|
inline int IPFW_ARGS_ETHER = 0x00010000; /* valid ethernet header */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_NH4
|
||||||
|
inline int IPFW_ARGS_NH4 = 0x00020000; /* IPv4 next hop in hopstore */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_NH6
|
||||||
|
inline int IPFW_ARGS_NH6 = 0x00040000; /* IPv6 next hop in hopstore */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_NH4PTR
|
||||||
|
inline int IPFW_ARGS_NH4PTR = 0x00080000; /* IPv4 next hop in next_hop */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_NH6PTR
|
||||||
|
inline int IPFW_ARGS_NH6PTR = 0x00100000; /* IPv6 next hop in next_hop6 */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_REF
|
||||||
|
inline int IPFW_ARGS_REF = 0x00200000; /* valid ipfw_rule_ref */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_IN
|
||||||
|
inline int IPFW_ARGS_IN = 0x00400000; /* called on input */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_OUT
|
||||||
|
inline int IPFW_ARGS_OUT = 0x00800000; /* called on output */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_IP4
|
||||||
|
inline int IPFW_ARGS_IP4 = 0x01000000; /* belongs to v4 ISR */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_IP6
|
||||||
|
inline int IPFW_ARGS_IP6 = 0x02000000; /* belongs to v6 ISR */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_DROP
|
||||||
|
inline int IPFW_ARGS_DROP = 0x04000000; /* drop it (dummynet) */
|
||||||
|
#pragma D binding "1.0" IPFW_ARGS_LENMASK
|
||||||
|
inline int IPFW_ARGS_LENMASK = 0x0000ffff; /* length of data in *mem */
|
||||||
|
|
||||||
|
/* ipfw_rule_ref.info */
|
||||||
|
#pragma D binding "1.0" IPFW_INFO_MASK
|
||||||
|
inline int IPFW_INFO_MASK = 0x0000ffff;
|
||||||
|
#pragma D binding "1.0" IPFW_INFO_OUT
|
||||||
|
inline int IPFW_INFO_OUT = 0x00000000;
|
||||||
|
#pragma D binding "1.0" IPFW_INFO_IN
|
||||||
|
inline int IPFW_INFO_IN = 0x80000000;
|
||||||
|
#pragma D binding "1.0" IPFW_ONEPASS
|
||||||
|
inline int IPFW_ONEPASS = 0x40000000;
|
||||||
|
#pragma D binding "1.0" IPFW_IS_MASK
|
||||||
|
inline int IPFW_IS_MASK = 0x30000000;
|
||||||
|
#pragma D binding "1.0" IPFW_IS_DIVERT
|
||||||
|
inline int IPFW_IS_DIVERT = 0x20000000;
|
||||||
|
#pragma D binding "1.0" IPFW_IS_DUMMYNET
|
||||||
|
inline int IPFW_IS_DUMMYNET = 0x10000000;
|
||||||
|
#pragma D binding "1.0" IPFW_IS_PIPE
|
||||||
|
inline int IPFW_IS_PIPE = 0x08000000;
|
||||||
|
|
||||||
|
typedef struct ipfw_match_info {
|
||||||
|
uint32_t flags;
|
||||||
|
|
||||||
|
struct mbuf *m;
|
||||||
|
void *mem;
|
||||||
|
struct inpcb *inp;
|
||||||
|
struct ifnet *ifp;
|
||||||
|
struct ip *ipp;
|
||||||
|
struct ip6_hdr *ip6p;
|
||||||
|
|
||||||
|
/* flow id */
|
||||||
|
uint8_t addr_type;
|
||||||
|
uint8_t proto;
|
||||||
|
uint8_t proto_flags;
|
||||||
|
uint16_t fib; /* XXX */
|
||||||
|
in_addr_t dst_ip; /* in network byte order */
|
||||||
|
in_addr_t src_ip; /* in network byte order */
|
||||||
|
struct in6_addr dst_ip6;
|
||||||
|
struct in6_addr src_ip6;
|
||||||
|
|
||||||
|
uint16_t dst_port; /* in host byte order */
|
||||||
|
uint16_t src_port; /* in host byte order */
|
||||||
|
|
||||||
|
uint32_t flowid; /* IPv6 flowid */
|
||||||
|
uint32_t extra;
|
||||||
|
|
||||||
|
/* ipfw_rule_ref */
|
||||||
|
uint32_t slot;
|
||||||
|
uint32_t rulenum;
|
||||||
|
uint32_t rule_id;
|
||||||
|
uint32_t chain_id;
|
||||||
|
uint32_t match_info;
|
||||||
|
} ipfw_match_info_t;
|
||||||
|
|
||||||
|
#pragma D binding "1.0" translator
|
||||||
|
translator ipfw_match_info_t < struct ip_fw_args *p > {
|
||||||
|
flags = p->flags;
|
||||||
|
m = (p->flags & IPFW_ARGS_LENMASK) ? NULL : p->m;
|
||||||
|
mem = (p->flags & IPFW_ARGS_LENMASK) ? p->mem : NULL;
|
||||||
|
inp = p->inp;
|
||||||
|
ifp = p->ifp;
|
||||||
|
/* Initialize IP pointer corresponding to addr_type */
|
||||||
|
ipp = (p->flags & IPFW_ARGS_IP4) ?
|
||||||
|
(p->flags & IPFW_ARGS_LENMASK) ? (struct ip *)p->mem :
|
||||||
|
(p->m != NULL) ? (struct ip *)p->m->m_data : NULL : NULL;
|
||||||
|
ip6p = (p->flags & IPFW_ARGS_IP6) ?
|
||||||
|
(p->flags & IPFW_ARGS_LENMASK) ? (struct ip6_hdr *)p->mem :
|
||||||
|
(p->m != NULL) ? (struct ip6_hdr *)p->m->m_data : NULL : NULL;
|
||||||
|
|
||||||
|
/* fill f_id fields */
|
||||||
|
addr_type = p->f_id.addr_type;
|
||||||
|
proto = p->f_id.proto;
|
||||||
|
proto_flags = p->f_id._flags;
|
||||||
|
|
||||||
|
/* f_id.fib keeps truncated fibnum, use mbuf's fibnum if possible */
|
||||||
|
fib = p->m != NULL ? p->m->m_pkthdr.fibnum : p->f_id.fib;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ipfw_chk() keeps IPv4 addresses in host byte order. But for
|
||||||
|
* dtrace script it is useful to have them in network byte order,
|
||||||
|
* because inet_ntoa() uses address in network byte order.
|
||||||
|
*/
|
||||||
|
dst_ip = htonl(p->f_id.dst_ip);
|
||||||
|
src_ip = htonl(p->f_id.src_ip);
|
||||||
|
|
||||||
|
dst_ip6 = p->f_id.dst_ip6;
|
||||||
|
src_ip6 = p->f_id.src_ip6;
|
||||||
|
|
||||||
|
dst_port = p->f_id.dst_port;
|
||||||
|
src_port = p->f_id.src_port;
|
||||||
|
|
||||||
|
flowid = p->f_id.flow_id6;
|
||||||
|
extra = p->f_id.extra;
|
||||||
|
|
||||||
|
/* ipfw_rule_ref */
|
||||||
|
slot = (p->flags & IPFW_ARGS_REF) ? p->rule.slot : 0;
|
||||||
|
rulenum = (p->flags & IPFW_ARGS_REF) ? p->rule.rulenum : 0;
|
||||||
|
rule_id = (p->flags & IPFW_ARGS_REF) ? p->rule.rule_id : 0;
|
||||||
|
chain_id = (p->flags & IPFW_ARGS_REF) ? p->rule.chain_id : 0;
|
||||||
|
match_info = (p->flags & IPFW_ARGS_REF) ? p->rule.info : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ipfw_rule_info {
|
||||||
|
uint16_t act_ofs;
|
||||||
|
uint16_t cmd_len;
|
||||||
|
uint32_t rulenum;
|
||||||
|
uint8_t flags;
|
||||||
|
uint8_t set;
|
||||||
|
uint32_t rule_id;
|
||||||
|
uint32_t cached_id;
|
||||||
|
uint32_t cached_pos;
|
||||||
|
uint32_t refcnt;
|
||||||
|
} ipfw_rule_info_t;
|
||||||
|
|
||||||
|
#pragma D binding "1.0" translator
|
||||||
|
translator ipfw_rule_info_t < struct ip_fw *r > {
|
||||||
|
act_ofs = r->act_ofs;
|
||||||
|
cmd_len = r->cmd_len;
|
||||||
|
rulenum = r->rulenum;
|
||||||
|
flags = r->flags;
|
||||||
|
set = r->set;
|
||||||
|
rule_id = r->id;
|
||||||
|
cached_id = r->cached_id;
|
||||||
|
cached_pos = r->cached_pos;
|
||||||
|
refcnt = r->refcnt;
|
||||||
|
};
|
||||||
|
|
@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
#include <sys/rwlock.h>
|
#include <sys/rwlock.h>
|
||||||
#include <sys/rmlock.h>
|
#include <sys/rmlock.h>
|
||||||
|
#include <sys/sdt.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/socketvar.h>
|
#include <sys/socketvar.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
@ -106,6 +107,18 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <security/mac/mac_framework.h>
|
#include <security/mac/mac_framework.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define IPFW_PROBE(probe, arg0, arg1, arg2, arg3, arg4, arg5) \
|
||||||
|
SDT_PROBE6(ipfw, , , probe, arg0, arg1, arg2, arg3, arg4, arg5)
|
||||||
|
|
||||||
|
SDT_PROVIDER_DEFINE(ipfw);
|
||||||
|
SDT_PROBE_DEFINE6(ipfw, , , rule__matched,
|
||||||
|
"int", /* retval */
|
||||||
|
"int", /* af */
|
||||||
|
"void *", /* src addr */
|
||||||
|
"void *", /* dst addr */
|
||||||
|
"struct ip_fw_args *", /* args */
|
||||||
|
"struct ip_fw *" /* rule */);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* static variables followed by global ones.
|
* static variables followed by global ones.
|
||||||
* All ipfw global variables are here.
|
* All ipfw global variables are here.
|
||||||
@ -3237,6 +3250,13 @@ do { \
|
|||||||
struct ip_fw *rule = chain->map[f_pos];
|
struct ip_fw *rule = chain->map[f_pos];
|
||||||
/* Update statistics */
|
/* Update statistics */
|
||||||
IPFW_INC_RULE_COUNTER(rule, pktlen);
|
IPFW_INC_RULE_COUNTER(rule, pktlen);
|
||||||
|
IPFW_PROBE(rule__matched, retval,
|
||||||
|
is_ipv4 ? AF_INET : AF_INET6,
|
||||||
|
is_ipv4 ? (uintptr_t)&src_ip :
|
||||||
|
(uintptr_t)&args->f_id.src_ip6,
|
||||||
|
is_ipv4 ? (uintptr_t)&dst_ip :
|
||||||
|
(uintptr_t)&args->f_id.dst_ip6,
|
||||||
|
args, rule);
|
||||||
} else {
|
} else {
|
||||||
retval = IP_FW_DENY;
|
retval = IP_FW_DENY;
|
||||||
printf("ipfw: ouch!, skip past end of rules, denying packet\n");
|
printf("ipfw: ouch!, skip past end of rules, denying packet\n");
|
||||||
|
Loading…
Reference in New Issue
Block a user