diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 0e9dcc52d..44e5640c3 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -57,7 +57,8 @@ GENERATE_PERLMOD = NO #--------------------------------------------------------------------------- INCLUDE_PATH = "@CMAKE_SOURCE_DIR@/src" "@CMAKE_SOURCE_DIR@/tests" MACRO_EXPANSION = YES -PREDEFINED = bf_aligned(x)= +PREDEFINED = bf_aligned(x)= \ + DOXYGEN #--------------------------------------------------------------------------- # Configuration options related to diagram generator tools diff --git a/doc/usage/bfcli.rst b/doc/usage/bfcli.rst index 2db7090e5..611d1350d 100644 --- a/doc/usage/bfcli.rst +++ b/doc/usage/bfcli.rst @@ -129,14 +129,16 @@ Print a chain. ``chain logs`` ~~~~~~~~~~~~~~ -Print a chain's logged packets. +Print a chain's log entries. -bfcli will print the logged headers as they are published by the chain. Only the headers requested in the ``log`` action will be printed. Hit ``Ctrl+C`` to quit. +bfcli will print log entries as they are published by the chain. Only the data requested in the ``log`` action will be printed. Hit ``Ctrl+C`` to quit. -For each logged packet, bfcli will print the receive timestamp and the packet size, followed by each requested layer (see the ``log`` action below). If one of the requested layer could not be processed by the chain, the corresponding output will be truncated. +For packet-based hooks, each log entry contains the receive timestamp and the packet size, followed by each requested layer (see the ``log`` action below). If a requested layer could not be processed by the chain, the corresponding output will be truncated. + +For ``BF_HOOK_CGROUP_SOCK_ADDR_*`` hooks, each log entry contains the receive timestamp and verdict. If ``internet`` is requested, source and destination addresses are included. If ``transport`` is requested, the destination port is included. If ``pid`` is requested, the process ID is included. If ``comm`` is requested, the process name is included. **Options** - - ``--name NAME``: name of the chain to print the logged packets for. + - ``--name NAME``: name of the chain to print the log entries for. **Examples** @@ -403,14 +405,17 @@ Rules are defined such as: rule [$MATCHER...] [$SET...] - [log link,internet,transport] + [log $LOG_OPTS] [counter] [mark $MARK] $VERDICT With: - ``$MATCHER``: zero or more matchers. Matchers are defined later. - - ``log``: optional. If set, log the requested protocol headers. ``link`` will log the link (layer 2) header, ``internet`` with log the internet (layer 3) header, and ``transport`` will log the transport (layer 4) header. At least one header type is required. ``log`` is **not** supported by ``BF_HOOK_CGROUP_SOCK_ADDR_*`` hooks. + - ``log``: optional. If set, log the requested data. At least one option is required. Available options depend on the hook type: + + - Packet hooks (XDP, TC, NF, cgroup_skb): ``link`` (layer 2 header), ``internet`` (layer 3 header), ``transport`` (layer 4 header). + - Socket hooks (``BF_HOOK_CGROUP_SOCK_ADDR_*``): ``internet`` (source and destination addresses), ``transport`` (destination port), ``pid`` (process ID), ``comm`` (process name). - ``counter``: optional literal. If set, the filter will count the number of events matched by the rule. For packet-based hooks, this includes both the number of packets and the total bytes. For ``BF_HOOK_CGROUP_SOCK_ADDR_*`` hooks, this counts the number of socket operations (``connect()`` or ``sendmsg()`` calls). - ``mark``: optional, ``$MARK`` must be a valid decimal or hexadecimal 32-bits value. If set, write the packet's marker value. This marker can be used later on in a rule (see ``meta.mark``) or with a TC filter. - ``$VERDICT``: action taken by the rule if the packet is matched against **all** the criteria: either ``ACCEPT``, ``DROP``, ``CONTINUE``, or ``REDIRECT``. diff --git a/src/bfcli/lexer.l b/src/bfcli/lexer.l index 8a04987a7..16476d854 100644 --- a/src/bfcli/lexer.l +++ b/src/bfcli/lexer.l @@ -101,7 +101,7 @@ log { BEGIN(STATE_LOG_OPTS); return LOG; } [0-9a-zA-Z]+(,[0-9a-zA-Z]+)* { BEGIN(INITIAL); yylval.sval = strdup(yytext); - return LOG_HEADERS; + return LOG_OPTS; } } diff --git a/src/bfcli/parser.y b/src/bfcli/parser.y index 98a4cd238..9655c0c79 100644 --- a/src/bfcli/parser.y +++ b/src/bfcli/parser.y @@ -103,7 +103,7 @@ %token SET %token LOG COUNTER MARK %token REDIRECT_TOKEN -%token LOG_HEADERS +%token LOG_OPTS %token SET_TYPE %token SET_RAW_PAYLOAD %token STRING @@ -320,7 +320,7 @@ rule : RULE matchers rule_options rule_verdict } ; -rule_option : LOG LOG_HEADERS +rule_option : LOG LOG_OPTS { _cleanup_free_ char *in = $2; char *tmp = in; @@ -329,12 +329,12 @@ rule_option : LOG LOG_HEADERS uint8_t log = 0; while ((token = strtok_r(tmp, ",", &saveptr))) { - enum bf_pkthdr header; + enum bf_log_opt opt; - if (bf_pkthdr_from_str(token, &header) < 0) - bf_parse_err("unknown packet header '%s'", token); + if (bf_log_opt_from_str(token, &opt) < 0) + bf_parse_err("unknown log option '%s'", token); - log |= BF_FLAG(header); + log |= BF_FLAG(opt); tmp = NULL; } diff --git a/src/bfcli/print.c b/src/bfcli/print.c index b920dc21d..23c32e331 100644 --- a/src/bfcli/print.c +++ b/src/bfcli/print.c @@ -265,12 +265,12 @@ void bfc_chain_dump(struct bf_chain *chain, struct bf_hookopts *hookopts, (void)fprintf(stdout, " log "); - for (enum bf_pkthdr hdr = 0; hdr < _BF_PKTHDR_MAX; ++hdr) { - if (!(log & BF_FLAG(hdr))) + for (enum bf_log_opt opt = 0; opt < _BF_LOG_OPT_MAX; ++opt) { + if (!(log & BF_FLAG(opt))) continue; - log &= ~BF_FLAG(hdr); - (void)fprintf(stdout, "%s%s", bf_pkthdr_to_str(hdr), + log &= ~BF_FLAG(opt); + (void)fprintf(stdout, "%s%s", bf_log_opt_to_str(opt), log ? "," : "\n"); } } @@ -360,6 +360,8 @@ static void _bf_chain_log_header(const struct bf_log *log) struct timespec time; char time_str[64]; + assert(log); + // Convert timestamp to readable format time.tv_sec = (long)log->ts / BF_TIME_S; time.tv_nsec = (long)log->ts % BF_TIME_S; @@ -367,23 +369,29 @@ static void _bf_chain_log_header(const struct bf_log *log) (void)strftime(time_str, sizeof(time_str), "%H:%M:%S", localtime(&time.tv_sec)); - (void)fprintf( - stdout, - "\n%s[%s.%06ld]%s Rule #%u matched %s%llu bytes%s with verdict %s\n", - bf_logger_get_color(BF_COLOR_LIGHT_CYAN, BF_STYLE_NORMAL), time_str, - time.tv_nsec / BF_TIME_US, - bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET), log->rule_id, - bf_logger_get_color(BF_COLOR_DEFAULT, BF_STYLE_BOLD), log->pkt_size, - bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET), - bf_verdict_to_str((enum bf_verdict)log->verdict)); + (void)fprintf(stdout, "\n%s[%s.%06ld]%s Rule #%u", + bf_logger_get_color(BF_COLOR_LIGHT_CYAN, BF_STYLE_NORMAL), + time_str, time.tv_nsec / BF_TIME_US, + bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET), + log->rule_id); + + if (log->log_type == BF_LOG_TYPE_PACKET) { + (void)fprintf(stdout, " matched %s%llu bytes%s with", + bf_logger_get_color(BF_COLOR_DEFAULT, BF_STYLE_BOLD), + log->pkt.pkt_size, + bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET)); + } + + (void)fprintf(stdout, " verdict %s\n", + bf_verdict_to_str((enum bf_verdict)log->verdict)); } static void _bf_chain_log_l2(const struct bf_log *log) { - struct ethhdr *ethhdr = (void *)log->l2hdr; + struct ethhdr *ethhdr = (void *)log->pkt.l2hdr; const char *ethertype; - if (!(log->headers & (1 << BF_PKTHDR_LINK))) { + if (!(log->pkt.headers & (1 << BF_LOG_OPT_LINK))) { (void)fprintf(stdout, " Ethernet : \n"); return; } @@ -418,14 +426,14 @@ static void _bf_chain_log_l3(const struct bf_log *log) char dst_addr[INET6_ADDRSTRLEN]; const char *protocol; - if (!(log->headers & (1 << BF_PKTHDR_INTERNET))) { + if (!(log->pkt.headers & (1 << BF_LOG_OPT_INTERNET))) { (void)fprintf(stdout, " Internet : \n"); return; } switch (log->l3_proto) { case ETH_P_IP: - iphdr = (struct iphdr *)&log->l3hdr[0]; + iphdr = (struct iphdr *)&log->pkt.l3hdr[0]; inet_ntop(AF_INET, &iphdr->saddr, src_addr, sizeof(src_addr)); inet_ntop(AF_INET, &iphdr->daddr, dst_addr, sizeof(dst_addr)); @@ -451,7 +459,7 @@ static void _bf_chain_log_l3(const struct bf_log *log) break; case ETH_P_IPV6: - ipv6hdr = (struct ipv6hdr *)log->l3hdr; + ipv6hdr = (struct ipv6hdr *)log->pkt.l3hdr; inet_ntop(AF_INET6, &ipv6hdr->saddr, src_addr, sizeof(src_addr)); inet_ntop(AF_INET6, &ipv6hdr->daddr, dst_addr, sizeof(dst_addr)); @@ -490,14 +498,14 @@ static void _bf_chain_log_l4(const struct bf_log *log) struct udphdr *udphdr; const char *tcp_flags_str; - if (!(log->headers & (1 << BF_PKTHDR_TRANSPORT))) { + if (!(log->pkt.headers & (1 << BF_LOG_OPT_TRANSPORT))) { (void)fprintf(stdout, " Transport : \n"); return; } switch (log->l4_proto) { case IPPROTO_TCP: - tcphdr = (struct tcphdr *)log->l4hdr; + tcphdr = (struct tcphdr *)log->pkt.l4hdr; tcp_flags_str = _bf_tcp_flags_to_str(tcphdr); (void)fprintf(stdout, " TCP : %s%-5u%s → %s%-5u%s", @@ -522,7 +530,7 @@ static void _bf_chain_log_l4(const struct bf_log *log) break; case IPPROTO_UDP: - udphdr = (struct udphdr *)log->l4hdr; + udphdr = (struct udphdr *)log->pkt.l4hdr; (void)fprintf(stdout, " UDP : %s%-5u%s → %s%-5u%s [len=%u]\n", bf_logger_get_color(BF_COLOR_LIGHT_YELLOW, BF_STYLE_BOLD), @@ -535,7 +543,7 @@ static void _bf_chain_log_l4(const struct bf_log *log) break; case IPPROTO_ICMP: - icmphdr = (struct icmphdr *)log->l4hdr; + icmphdr = (struct icmphdr *)log->pkt.l4hdr; (void)fprintf(stdout, " ICMP : type=%-3u code=%-3u", icmphdr->type, icmphdr->code); @@ -550,7 +558,7 @@ static void _bf_chain_log_l4(const struct bf_log *log) break; case IPPROTO_ICMPV6: - icmp6hdr = (struct icmp6hdr *)log->l4hdr; + icmp6hdr = (struct icmp6hdr *)log->pkt.l4hdr; (void)fprintf(stdout, " ICMPv6 : type=%-3u code=%-3u", icmp6hdr->icmp6_type, icmp6hdr->icmp6_code); @@ -571,14 +579,112 @@ static void _bf_chain_log_l4(const struct bf_log *log) } } +static void _bf_chain_log_sock_addr(const struct bf_log *log) +{ + uint8_t req; + + assert(log); + + req = log->sock_addr.req_log_opts; + + if (req & (1 << BF_LOG_OPT_INTERNET)) { + char src_addr[INET6_ADDRSTRLEN]; + char dst_addr[INET6_ADDRSTRLEN]; + const char *protocol = bf_ipproto_to_str(log->l4_proto); + const char *label = NULL; + const char *color = NULL; + int family = 0; + + if (log->l3_proto == ETH_P_IP) { + family = AF_INET; + label = "IPv4"; + color = bf_logger_get_color(BF_COLOR_CYAN, BF_STYLE_BOLD); + } else if (log->l3_proto == ETH_P_IPV6) { + family = AF_INET6; + label = "IPv6"; + color = bf_logger_get_color(BF_COLOR_LIGHT_CYAN, BF_STYLE_BOLD); + } + + if (label) { + inet_ntop(family, log->sock_addr.saddr, src_addr, sizeof(src_addr)); + inet_ntop(family, log->sock_addr.daddr, dst_addr, sizeof(dst_addr)); + + (void)fprintf(stdout, " %-10s: %s%-15s%s → %s%-15s%s", label, + color, src_addr, + bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET), + color, dst_addr, + bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET)); + + if (protocol) { + (void)fprintf( + stdout, " [%s%s%s]\n", + bf_logger_get_color(BF_COLOR_LIGHT_MAGENTA, BF_STYLE_BOLD), + protocol, + bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET)); + } else { + (void)fprintf(stdout, " [proto=%u]\n", log->l4_proto); + } + } else { + (void)fprintf(stdout, " Internet : \n", + log->l3_proto); + } + } + + if (req & (1 << BF_LOG_OPT_TRANSPORT)) { + const char *l4_label; + + switch (log->l4_proto) { + case IPPROTO_TCP: + l4_label = "TCP"; + break; + case IPPROTO_UDP: + l4_label = "UDP"; + break; + default: + l4_label = "Transport"; + break; + } + + (void)fprintf(stdout, " %-10s: → %s%-5u%s\n", l4_label, + bf_logger_get_color(BF_COLOR_LIGHT_YELLOW, BF_STYLE_BOLD), + log->sock_addr.dport, + bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET)); + } + + if (req & (1 << BF_LOG_OPT_PID)) { + (void)fprintf(stdout, " PID : %s%u%s\n", + bf_logger_get_color(BF_COLOR_LIGHT_YELLOW, BF_STYLE_BOLD), + log->sock_addr.pid, + bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET)); + } + + if (req & (1 << BF_LOG_OPT_COMM)) { + (void)fprintf(stdout, " Process : %s%.*s%s\n", + bf_logger_get_color(BF_COLOR_LIGHT_GREEN, BF_STYLE_BOLD), + BF_COMM_LEN, log->sock_addr.comm, + bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET)); + } +} + void bfc_print_log(const struct bf_log *log) { + assert(log); + _bf_chain_log_header(log); - if (log->req_headers & (1 << BF_PKTHDR_LINK)) - _bf_chain_log_l2(log); - if (log->req_headers & (1 << BF_PKTHDR_INTERNET)) - _bf_chain_log_l3(log); - if (log->req_headers & (1 << BF_PKTHDR_TRANSPORT)) - _bf_chain_log_l4(log); + switch (log->log_type) { + case BF_LOG_TYPE_PACKET: + if (log->pkt.req_headers & (1 << BF_LOG_OPT_LINK)) + _bf_chain_log_l2(log); + if (log->pkt.req_headers & (1 << BF_LOG_OPT_INTERNET)) + _bf_chain_log_l3(log); + if (log->pkt.req_headers & (1 << BF_LOG_OPT_TRANSPORT)) + _bf_chain_log_l4(log); + break; + case BF_LOG_TYPE_SOCK_ADDR: + _bf_chain_log_sock_addr(log); + break; + default: + break; + } } diff --git a/src/libbpfilter/CMakeLists.txt b/src/libbpfilter/CMakeLists.txt index 47d98e674..abebf9feb 100644 --- a/src/libbpfilter/CMakeLists.txt +++ b/src/libbpfilter/CMakeLists.txt @@ -64,9 +64,9 @@ set(libbpfilter_srcs ${CMAKE_CURRENT_SOURCE_DIR}/cgen/jmp.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/jmp.c ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/cmp.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/cmp.c ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/meta.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/meta.c - ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/packet.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/packet.c ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/set.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/matcher/set.c ${CMAKE_CURRENT_SOURCE_DIR}/cgen/nf.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/nf.c + ${CMAKE_CURRENT_SOURCE_DIR}/cgen/packet.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/packet.c ${CMAKE_CURRENT_SOURCE_DIR}/cgen/printer.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/printer.c ${CMAKE_CURRENT_SOURCE_DIR}/cgen/program.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/program.c ${CMAKE_CURRENT_SOURCE_DIR}/cgen/prog/link.h ${CMAKE_CURRENT_SOURCE_DIR}/cgen/prog/link.c @@ -109,8 +109,9 @@ bf_target_add_elfstubs(libbpfilter "parse_ipv6_eh" "parse_ipv6_nh" "update_counters" - "log" + "pkt_log" "flow_hash" + "sock_addr_log" ) target_compile_definitions(libbpfilter diff --git a/src/libbpfilter/bpf/log.bpf.c b/src/libbpfilter/bpf/log.bpf.c deleted file mode 100644 index bdd71516f..000000000 --- a/src/libbpfilter/bpf/log.bpf.c +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright (c) 2023 Meta Platforms, Inc. and affiliates. - */ - -#include - -#include -#include -#include - -#include "cgen/runtime.h" - -__u8 bf_log(struct bf_runtime *ctx, __u32 rule_id, __u8 headers, __u32 verdict, - __u32 l3_l4_proto) -{ - struct bf_log *log; - __u16 l3_proto = (__u16)(l3_l4_proto >> 16); - __u8 l4_proto = (__u8)l3_l4_proto; - - log = bpf_ringbuf_reserve(ctx->log_map, sizeof(struct bf_log), 0); - if (!log) { - bpf_printk("failed to reserve %d bytes in ringbuf", - sizeof(struct bf_log)); - return 1; - } - - log->ts = bpf_ktime_get_ns(); - log->rule_id = rule_id; - log->verdict = verdict; - log->pkt_size = ctx->pkt_size; - log->req_headers = headers; - log->headers = 0; - log->l3_proto = bpf_ntohs(l3_proto); - log->l4_proto = l4_proto; - - if (headers & (1 << BF_PKTHDR_LINK) && ctx->l2_hdr && - ctx->l2_size <= BF_L2_SLICE_LEN) { - bpf_probe_read_kernel(log->l2hdr, ctx->l2_size, ctx->l2_hdr); - log->headers |= (1 << BF_PKTHDR_LINK); - } - - if (headers & (1 << BF_PKTHDR_INTERNET) && ctx->l3_hdr && - ctx->l3_size <= BF_L3_SLICE_LEN) { - bpf_probe_read_kernel(log->l3hdr, ctx->l3_size, ctx->l3_hdr); - log->headers |= (1 << BF_PKTHDR_INTERNET); - } - - if (headers & (1 << BF_PKTHDR_TRANSPORT) && ctx->l4_hdr && - ctx->l4_size <= BF_L4_SLICE_LEN) { - bpf_probe_read_kernel(log->l4hdr, ctx->l4_size, ctx->l4_hdr); - log->headers |= (1 << BF_PKTHDR_TRANSPORT); - } - - bpf_ringbuf_submit(log, 0); - - return 0; -} diff --git a/src/libbpfilter/bpf/pkt_log.bpf.c b/src/libbpfilter/bpf/pkt_log.bpf.c new file mode 100644 index 000000000..c2ba7af92 --- /dev/null +++ b/src/libbpfilter/bpf/pkt_log.bpf.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + */ + +#include + +#include +#include +#include + +#include "cgen/runtime.h" + +__u8 bf_pkt_log(struct bf_runtime *ctx, __u32 rule_id, __u8 headers, + __u32 verdict, __u32 l3_l4_proto) +{ + struct bf_log *log; + __u16 l3_proto = (__u16)(l3_l4_proto >> 16); + __u8 l4_proto = (__u8)l3_l4_proto; + + log = bpf_ringbuf_reserve(ctx->log_map, sizeof(struct bf_log), 0); + if (!log) { + bpf_printk("failed to reserve %d bytes in ringbuf", + sizeof(struct bf_log)); + return 1; + } + + log->ts = bpf_ktime_get_ns(); + log->rule_id = rule_id; + log->verdict = verdict; + log->l3_proto = bpf_ntohs(l3_proto); + log->l4_proto = l4_proto; + log->log_type = BF_LOG_TYPE_PACKET; + log->pkt.pkt_size = ctx->pkt_size; + log->pkt.req_headers = headers; + log->pkt.headers = 0; + + if (headers & (1 << BF_LOG_OPT_LINK) && ctx->l2_hdr && + ctx->l2_size <= BF_L2_SLICE_LEN) { + bpf_probe_read_kernel(log->pkt.l2hdr, ctx->l2_size, ctx->l2_hdr); + log->pkt.headers |= (1 << BF_LOG_OPT_LINK); + } + + if (headers & (1 << BF_LOG_OPT_INTERNET) && ctx->l3_hdr && + ctx->l3_size <= BF_L3_SLICE_LEN) { + bpf_probe_read_kernel(log->pkt.l3hdr, ctx->l3_size, ctx->l3_hdr); + log->pkt.headers |= (1 << BF_LOG_OPT_INTERNET); + } + + if (headers & (1 << BF_LOG_OPT_TRANSPORT) && ctx->l4_hdr && + ctx->l4_size <= BF_L4_SLICE_LEN) { + bpf_probe_read_kernel(log->pkt.l4hdr, ctx->l4_size, ctx->l4_hdr); + log->pkt.headers |= (1 << BF_LOG_OPT_TRANSPORT); + } + + bpf_ringbuf_submit(log, 0); + + return 0; +} diff --git a/src/libbpfilter/bpf/sock_addr_log.bpf.c b/src/libbpfilter/bpf/sock_addr_log.bpf.c new file mode 100644 index 000000000..a7527e887 --- /dev/null +++ b/src/libbpfilter/bpf/sock_addr_log.bpf.c @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + */ + +#include + +#include +#include + +#include "cgen/runtime.h" + +__u8 bf_sock_addr_log(struct bf_runtime *ctx, __u32 rule_id, __u8 log_opts, + __u32 verdict, __u32 l3_l4_proto) +{ + struct bf_log *log; + __u16 l3_proto = (__u16)(l3_l4_proto >> 16); + __u8 l4_proto = (__u8)l3_l4_proto; + + log = bpf_ringbuf_reserve(ctx->log_map, sizeof(struct bf_log), 0); + if (!log) { + bpf_printk("failed to reserve %d bytes in ringbuf", + sizeof(struct bf_log)); + return 1; + } + + log->ts = bpf_ktime_get_ns(); + log->rule_id = rule_id; + log->verdict = verdict; + log->l3_proto = bpf_ntohs(l3_proto); + log->l4_proto = l4_proto; + log->log_type = BF_LOG_TYPE_SOCK_ADDR; + log->sock_addr.req_log_opts = log_opts; + + if (log_opts & (1 << BF_LOG_OPT_PID)) + log->sock_addr.pid = (__u32)(bpf_get_current_pid_tgid() >> 32); + + if (log_opts & (1 << BF_LOG_OPT_COMM)) + bpf_get_current_comm(log->sock_addr.comm, sizeof(log->sock_addr.comm)); + + if (log_opts & (1 << BF_LOG_OPT_INTERNET)) { + __builtin_memcpy(log->sock_addr.saddr, ctx->sock_addr.saddr, + sizeof(ctx->sock_addr.saddr)); + __builtin_memcpy(log->sock_addr.daddr, ctx->sock_addr.daddr, + sizeof(ctx->sock_addr.daddr)); + } + + if (log_opts & (1 << BF_LOG_OPT_TRANSPORT)) + log->sock_addr.dport = ctx->sock_addr.dport; + + bpf_ringbuf_submit(log, 0); + + return 0; +} diff --git a/src/libbpfilter/cgen/cgroup_skb.c b/src/libbpfilter/cgen/cgroup_skb.c index 459238e0e..46eea5319 100644 --- a/src/libbpfilter/cgen/cgroup_skb.c +++ b/src/libbpfilter/cgen/cgroup_skb.c @@ -20,7 +20,7 @@ #include "cgen/cgen.h" #include "cgen/matcher/cmp.h" -#include "cgen/matcher/packet.h" +#include "cgen/packet.h" #include "cgen/program.h" #include "cgen/stub.h" #include "cgen/swich.h" @@ -133,7 +133,7 @@ static int _bf_cgroup_skb_gen_inline_matcher(struct bf_program *program, return bf_cmp_value(program, bf_matcher_get_op(matcher), bf_matcher_payload(matcher), 4, BPF_REG_1); default: - return bf_matcher_generate_packet(program, matcher); + return bf_packet_gen_inline_matcher(program, matcher); } } @@ -161,4 +161,5 @@ const struct bf_flavor_ops bf_flavor_ops_cgroup_skb = { .gen_inline_set_mark = _bf_cgroup_skb_gen_inline_set_mark, .get_verdict = _bf_cgroup_skb_get_verdict, .gen_inline_matcher = _bf_cgroup_skb_gen_inline_matcher, + .gen_inline_log = bf_packet_gen_inline_log, }; diff --git a/src/libbpfilter/cgen/cgroup_sock_addr.c b/src/libbpfilter/cgen/cgroup_sock_addr.c index 7d4c4d841..dce4efe76 100644 --- a/src/libbpfilter/cgen/cgroup_sock_addr.c +++ b/src/libbpfilter/cgen/cgroup_sock_addr.c @@ -14,67 +14,25 @@ #include #include +#include #include +#include #include #include +#include #include #include #include "cgen/matcher/cmp.h" #include "cgen/matcher/meta.h" #include "cgen/program.h" +#include "cgen/runtime.h" #include "cgen/swich.h" #include "filter.h" // Forward definition to avoid header conflicts. uint16_t htons(uint16_t hostshort); -static int _bf_cgroup_sock_addr_gen_inline_prologue(struct bf_program *program) -{ - int r; - - assert(program); - - /* `R6` = `bpf_sock_addr` context pointer. Unlike packet-based flavors where - * `R6` changes per header, the socket context is fixed so we set it once. */ - EMIT(program, BPF_MOV64_REG(BPF_REG_6, BPF_REG_1)); - - // The counters stub reads `pkt_size` unconditionally; zero it out. - EMIT(program, BPF_ST_MEM(BPF_DW, BPF_REG_10, BF_PROG_CTX_OFF(pkt_size), 0)); - - /* Convert `bpf_sock_addr.family` to L3 protocol ID in `R7`, using the same - * `bf_swich` pattern as cgroup_skb. */ - EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_6, - offsetof(struct bpf_sock_addr, family))); - - { - _clean_bf_swich_ struct bf_swich swich = - bf_swich_get(program, BPF_REG_2); - - EMIT_SWICH_OPTION(&swich, AF_INET, - BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IP))); - EMIT_SWICH_OPTION(&swich, AF_INET6, - BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IPV6))); - EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0)); - - r = bf_swich_generate(&swich); - if (r) - return r; - } - - EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_6, - offsetof(struct bpf_sock_addr, protocol))); - - return 0; -} - -static int _bf_cgroup_sock_addr_gen_inline_epilogue(struct bf_program *program) -{ - (void)program; - - return 0; -} - /** * @brief Load a field from the `bpf_sock_addr` context into a register. * @@ -138,6 +96,159 @@ static int _bf_cgroup_sock_addr_load_field(struct bf_program *program, return 0; } +/** + * @brief Store a register value at an offset from `BPF_REG_10`. + * + * Counterpart to `_bf_cgroup_sock_addr_load_field`. For 16-byte stores, + * `reg` holds the low 8 bytes and `reg + 1` the high 8 bytes, matching + * the layout produced by `_bf_cgroup_sock_addr_load_field`. + * + * @param program Program to emit into. Can't be NULL. + * @param offset Byte offset from `BPF_REG_10` (use `BF_PROG_CTX_OFF`). + * @param size Field size in bytes: 1, 2, 4, 8, or 16. + * @param reg BPF register holding the value to store. + * @return 0 on success, negative errno on error. + */ +static int _bf_cgroup_sock_addr_store_field(struct bf_program *program, + int offset, size_t size, int reg) +{ + assert(program); + + switch (size) { + case 1: + EMIT(program, BPF_STX_MEM(BPF_B, BPF_REG_10, reg, offset)); + break; + case 2: + EMIT(program, BPF_STX_MEM(BPF_H, BPF_REG_10, reg, offset)); + break; + case 4: + EMIT(program, BPF_STX_MEM(BPF_W, BPF_REG_10, reg, offset)); + break; + case 8: + EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, reg, offset)); + break; + case 16: + EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, reg, offset)); + EMIT(program, BPF_STX_MEM(BPF_DW, BPF_REG_10, reg + 1, offset + 8)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int _bf_cgroup_sock_addr_gen_inline_prologue(struct bf_program *program) +{ + int r; + + assert(program); + + /* `R6` = `bpf_sock_addr` context pointer. Unlike packet-based flavors where + * `R6` changes per header, the socket context is fixed so we set it once. */ + EMIT(program, BPF_MOV64_REG(BPF_REG_6, BPF_REG_1)); + + // The counters stub reads `pkt_size` unconditionally; zero it out. + EMIT(program, BPF_ST_MEM(BPF_DW, BPF_REG_10, BF_PROG_CTX_OFF(pkt_size), 0)); + + /* Convert `bpf_sock_addr.family` to L3 protocol ID in `R7`, using the same + * `bf_swich` pattern as cgroup_skb. */ + EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_6, + offsetof(struct bpf_sock_addr, family))); + + { + _clean_bf_swich_ struct bf_swich swich = + bf_swich_get(program, BPF_REG_2); + + EMIT_SWICH_OPTION(&swich, AF_INET, + BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IP))); + EMIT_SWICH_OPTION(&swich, AF_INET6, + BPF_MOV64_IMM(BPF_REG_7, htons(ETH_P_IPV6))); + EMIT_SWICH_DEFAULT(&swich, BPF_MOV64_IMM(BPF_REG_7, 0)); + + r = bf_swich_generate(&swich); + if (r) + return r; + } + + EMIT(program, BPF_LDX_MEM(BPF_W, BPF_REG_8, BPF_REG_6, + offsetof(struct bpf_sock_addr, protocol))); + + /* Copy context fields into the runtime for the logging stub. + * The verifier restricts context access by attach type, so the shared + * stub reads from here instead of the context directly. */ + if (program->runtime.chain->flags & BF_FLAG(BF_CHAIN_LOG)) { + bool has_saddr = false; + size_t addr_size = 0; + size_t saddr_off = 0; + size_t daddr_off = 0; + + /* Destination port: valid for all cgroup_sock_addr hooks. + * user_port is __be32; BSWAP 16 converts to host order. */ + r = _bf_cgroup_sock_addr_load_field( + program, offsetof(struct bpf_sock_addr, user_port), 4, BPF_REG_1); + if (r) + return r; + EMIT(program, BPF_BSWAP(BPF_REG_1, 16)); + r = _bf_cgroup_sock_addr_store_field( + program, BF_PROG_CTX_OFF(sock_addr.dport), 2, BPF_REG_1); + if (r) + return r; + + switch (program->runtime.chain->hook) { + case BF_HOOK_CGROUP_SOCK_ADDR_SENDMSG4: + has_saddr = true; + saddr_off = offsetof(struct bpf_sock_addr, msg_src_ip4); + __attribute__((fallthrough)); + case BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4: + addr_size = 4; + daddr_off = offsetof(struct bpf_sock_addr, user_ip4); + break; + case BF_HOOK_CGROUP_SOCK_ADDR_SENDMSG6: + has_saddr = true; + saddr_off = offsetof(struct bpf_sock_addr, msg_src_ip6); + __attribute__((fallthrough)); + case BF_HOOK_CGROUP_SOCK_ADDR_CONNECT6: + addr_size = 16; + daddr_off = offsetof(struct bpf_sock_addr, user_ip6); + break; + default: + return bf_err_r(-ENOTSUP, "unexpected hook: %s", + bf_hook_to_str(program->runtime.chain->hook)); + } + + if (has_saddr) { + r = _bf_cgroup_sock_addr_load_field(program, saddr_off, addr_size, + BPF_REG_1); + if (r) + return r; + r = _bf_cgroup_sock_addr_store_field( + program, BF_PROG_CTX_OFF(sock_addr.saddr), addr_size, + BPF_REG_1); + if (r) + return r; + } + + r = _bf_cgroup_sock_addr_load_field(program, daddr_off, addr_size, + BPF_REG_1); + if (r) + return r; + r = _bf_cgroup_sock_addr_store_field( + program, BF_PROG_CTX_OFF(sock_addr.daddr), addr_size, BPF_REG_1); + if (r) + return r; + } + + return 0; +} + +static int _bf_cgroup_sock_addr_gen_inline_epilogue(struct bf_program *program) +{ + (void)program; + + return 0; +} + static int _bf_cgroup_sock_addr_load_and_cmp(struct bf_program *program, const struct bf_matcher *matcher, size_t offset, size_t size) @@ -273,9 +384,32 @@ static int _bf_cgroup_sock_addr_get_verdict(enum bf_verdict verdict) } } +static int _bf_cgroup_sock_addr_gen_inline_log(struct bf_program *program, + const struct bf_rule *rule) +{ + assert(program); + assert(rule); + + EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10)); + EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg))); + EMIT(program, BPF_MOV64_IMM(BPF_REG_2, rule->index)); + EMIT(program, BPF_MOV64_IMM(BPF_REG_3, rule->log)); + EMIT(program, BPF_MOV64_IMM(BPF_REG_4, rule->verdict)); + + // Pack l3_proto and l4_proto + EMIT(program, BPF_MOV64_REG(BPF_REG_5, BPF_REG_7)); + EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_5, 16)); + EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_5, BPF_REG_8)); + + EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_SOCK_ADDR_LOG); + + return 0; +} + const struct bf_flavor_ops bf_flavor_ops_cgroup_sock_addr = { .gen_inline_prologue = _bf_cgroup_sock_addr_gen_inline_prologue, .gen_inline_epilogue = _bf_cgroup_sock_addr_gen_inline_epilogue, .get_verdict = _bf_cgroup_sock_addr_get_verdict, .gen_inline_matcher = _bf_cgroup_sock_addr_gen_inline_matcher, + .gen_inline_log = _bf_cgroup_sock_addr_gen_inline_log, }; diff --git a/src/libbpfilter/cgen/nf.c b/src/libbpfilter/cgen/nf.c index 08c596e81..2fdba83c3 100644 --- a/src/libbpfilter/cgen/nf.c +++ b/src/libbpfilter/cgen/nf.c @@ -24,7 +24,7 @@ #include "cgen/jmp.h" #include "cgen/matcher/cmp.h" -#include "cgen/matcher/packet.h" +#include "cgen/packet.h" #include "cgen/program.h" #include "cgen/stub.h" #include "cgen/swich.h" @@ -149,7 +149,7 @@ static int _bf_nf_gen_inline_matcher(struct bf_program *program, return bf_cmp_value(program, bf_matcher_get_op(matcher), bf_matcher_payload(matcher), 4, BPF_REG_1); default: - return bf_matcher_generate_packet(program, matcher); + return bf_packet_gen_inline_matcher(program, matcher); } } @@ -176,4 +176,5 @@ const struct bf_flavor_ops bf_flavor_ops_nf = { .gen_inline_epilogue = _bf_nf_gen_inline_epilogue, .get_verdict = _bf_nf_get_verdict, .gen_inline_matcher = _bf_nf_gen_inline_matcher, + .gen_inline_log = bf_packet_gen_inline_log, }; diff --git a/src/libbpfilter/cgen/matcher/packet.c b/src/libbpfilter/cgen/packet.c similarity index 92% rename from src/libbpfilter/cgen/matcher/packet.c rename to src/libbpfilter/cgen/packet.c index 3974edba9..115874149 100644 --- a/src/libbpfilter/cgen/matcher/packet.c +++ b/src/libbpfilter/cgen/packet.c @@ -3,7 +3,7 @@ * Copyright (c) Meta Platforms, Inc. and affiliates. */ -#include "cgen/matcher/packet.h" +#include "cgen/packet.h" #include #include @@ -14,14 +14,17 @@ #include #include +#include #include #include #include +#include #include "cgen/matcher/cmp.h" #include "cgen/matcher/meta.h" #include "cgen/matcher/set.h" #include "cgen/program.h" +#include "cgen/runtime.h" #include "cgen/stub.h" #include "filter.h" @@ -296,8 +299,8 @@ static int _bf_matcher_pkt_generate_ip6_dscp(struct bf_program *program, return 0; } -int bf_matcher_generate_packet(struct bf_program *program, - const struct bf_matcher *matcher) +int bf_packet_gen_inline_matcher(struct bf_program *program, + const struct bf_matcher *matcher) { const struct bf_matcher_meta *meta; @@ -355,3 +358,25 @@ int bf_matcher_generate_packet(struct bf_program *program, bf_matcher_get_type(matcher)); } } + +int bf_packet_gen_inline_log(struct bf_program *program, + const struct bf_rule *rule) +{ + assert(program); + assert(rule); + + EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10)); + EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg))); + EMIT(program, BPF_MOV64_IMM(BPF_REG_2, rule->index)); + EMIT(program, BPF_MOV64_IMM(BPF_REG_3, rule->log)); + EMIT(program, BPF_MOV64_IMM(BPF_REG_4, rule->verdict)); + + // Pack l3_proto and l4_proto + EMIT(program, BPF_MOV64_REG(BPF_REG_5, BPF_REG_7)); + EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_5, 16)); + EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_5, BPF_REG_8)); + + EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_PKT_LOG); + + return 0; +} diff --git a/src/libbpfilter/cgen/matcher/packet.h b/src/libbpfilter/cgen/packet.h similarity index 54% rename from src/libbpfilter/cgen/matcher/packet.h rename to src/libbpfilter/cgen/packet.h index 54acd0a1a..06303eb7c 100644 --- a/src/libbpfilter/cgen/matcher/packet.h +++ b/src/libbpfilter/cgen/packet.h @@ -7,6 +7,7 @@ struct bf_matcher; struct bf_program; +struct bf_rule; /** * @brief Generate bytecode for a packet-based matcher. @@ -23,5 +24,18 @@ struct bf_program; * @param matcher Matcher to generate code for. Can't be NULL. * @return 0 on success, negative errno on error. */ -int bf_matcher_generate_packet(struct bf_program *program, - const struct bf_matcher *matcher); +int bf_packet_gen_inline_matcher(struct bf_program *program, + const struct bf_matcher *matcher); + +/** + * @brief Generate bytecode for packet-based rule logging. + * + * Sets up registers and calls the packet log ELF stub. Shared by all + * packet-based flavors (TC, NF, XDP, cgroup_skb). + * + * @param program Program being generated. Can't be NULL. + * @param rule Rule whose log action to generate. Can't be NULL. + * @return 0 on success, negative errno on error. + */ +int bf_packet_gen_inline_log(struct bf_program *program, + const struct bf_rule *rule); diff --git a/src/libbpfilter/cgen/program.c b/src/libbpfilter/cgen/program.c index 84f8d7b5f..5195d024d 100644 --- a/src/libbpfilter/cgen/program.c +++ b/src/libbpfilter/cgen/program.c @@ -292,6 +292,7 @@ static int _bf_program_generate_rule(struct bf_program *program, assert(program); assert(rule); assert(program->runtime.ops->gen_inline_matcher); + assert(program->runtime.ops->gen_inline_log); if (rule->disabled) return 0; @@ -346,18 +347,9 @@ static int _bf_program_generate_rule(struct bf_program *program, } if (rule->log) { - EMIT(program, BPF_MOV64_REG(BPF_REG_1, BPF_REG_10)); - EMIT(program, BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, BF_PROG_CTX_OFF(arg))); - EMIT(program, BPF_MOV64_IMM(BPF_REG_2, rule->index)); - EMIT(program, BPF_MOV64_IMM(BPF_REG_3, rule->log)); - EMIT(program, BPF_MOV64_IMM(BPF_REG_4, rule->verdict)); - - // Pack l3_proto and l4_proto - EMIT(program, BPF_MOV64_REG(BPF_REG_5, BPF_REG_7)); - EMIT(program, BPF_ALU64_IMM(BPF_LSH, BPF_REG_5, 16)); - EMIT(program, BPF_ALU64_REG(BPF_OR, BPF_REG_5, BPF_REG_8)); - - EMIT_FIXUP_ELFSTUB(program, BF_ELFSTUB_LOG); + r = program->runtime.ops->gen_inline_log(program, rule); + if (r) + return r; } if (rule->counters) { diff --git a/src/libbpfilter/cgen/runtime.h b/src/libbpfilter/cgen/runtime.h index 9f224cf4d..dc28311e9 100644 --- a/src/libbpfilter/cgen/runtime.h +++ b/src/libbpfilter/cgen/runtime.h @@ -42,6 +42,31 @@ (-(int)sizeof(struct bf_runtime) + \ (int)offsetof(struct bf_runtime, scratch) + (index)) +/** + * @brief Pre-read socket address fields for `cgroup_sock_addr` logging. + * + * The BPF verifier restricts which `bpf_sock_addr` context fields a program + * can access based on its attach type (e.g. `msg_src_ip4` is only valid for + * `UDP4_SENDMSG`, `user_ip4` only for IPv4 hooks). Because the `sock_addr_log` + * ELF stub is shared across all hook types, it cannot read these fields + * directly. + * + * Instead, the per-hook inline codegen pre-reads the permitted fields into + * this struct before calling the stub. The stub then copies from here into + * the log entry, avoiding any restricted context access. + */ +struct bf_runtime_sock_addr +{ + /** Source address (IPv4: first 4 bytes, IPv6: all 16). */ + __u8 bf_aligned(8) saddr[16]; + + /** Destination address (IPv4: first 4 bytes, IPv6: all 16). */ + __u8 bf_aligned(8) daddr[16]; + + /** Destination port in host byte order. */ + __u16 bf_aligned(8) dport; +}; + /** * @brief Runtime stack layout for the generated BPF programs. * @@ -124,6 +149,9 @@ struct bf_runtime /** Layer 4 header. */ __u8 bf_aligned(8) l4[BF_L4_SLICE_LEN]; + /** Pre-read socket address fields for cgroup_sock_addr logging. */ + struct bf_runtime_sock_addr sock_addr; + /** Scratch area. */ __u8 bf_aligned(8) scratch[64]; }; diff --git a/src/libbpfilter/cgen/tc.c b/src/libbpfilter/cgen/tc.c index d83fcd411..dd4d64aa0 100644 --- a/src/libbpfilter/cgen/tc.c +++ b/src/libbpfilter/cgen/tc.c @@ -20,7 +20,7 @@ #include "cgen/cgen.h" #include "cgen/matcher/cmp.h" -#include "cgen/matcher/packet.h" +#include "cgen/packet.h" #include "cgen/program.h" #include "cgen/stub.h" #include "filter.h" @@ -116,7 +116,7 @@ static int _bf_tc_gen_inline_matcher(struct bf_program *program, return bf_cmp_value(program, bf_matcher_get_op(matcher), bf_matcher_payload(matcher), 4, BPF_REG_0); default: - return bf_matcher_generate_packet(program, matcher); + return bf_packet_gen_inline_matcher(program, matcher); } } @@ -175,4 +175,5 @@ const struct bf_flavor_ops bf_flavor_ops_tc = { .gen_inline_redirect = _bf_tc_gen_inline_redirect, .get_verdict = _bf_tc_get_verdict, .gen_inline_matcher = _bf_tc_gen_inline_matcher, + .gen_inline_log = bf_packet_gen_inline_log, }; diff --git a/src/libbpfilter/cgen/xdp.c b/src/libbpfilter/cgen/xdp.c index a57ddeeca..7c2030e45 100644 --- a/src/libbpfilter/cgen/xdp.c +++ b/src/libbpfilter/cgen/xdp.c @@ -14,7 +14,7 @@ #include #include -#include "cgen/matcher/packet.h" +#include "cgen/packet.h" #include "cgen/program.h" #include "cgen/stub.h" #include "filter.h" @@ -124,5 +124,6 @@ const struct bf_flavor_ops bf_flavor_ops_xdp = { .gen_inline_epilogue = _bf_xdp_gen_inline_epilogue, .gen_inline_redirect = _bf_xdp_gen_inline_redirect, .get_verdict = _bf_xdp_get_verdict, - .gen_inline_matcher = bf_matcher_generate_packet, + .gen_inline_matcher = bf_packet_gen_inline_matcher, + .gen_inline_log = bf_packet_gen_inline_log, }; diff --git a/src/libbpfilter/chain.c b/src/libbpfilter/chain.c index 4c7f47059..c56be2426 100644 --- a/src/libbpfilter/chain.c +++ b/src/libbpfilter/chain.c @@ -132,14 +132,21 @@ int _bf_chain_check_rule(struct bf_chain *chain, struct bf_rule *rule) rule->disabled = r; } - if (rule->log && - bf_hook_to_flavor(chain->hook) == BF_FLAVOR_CGROUP_SOCK_ADDR) { - return bf_err_r(-ENOTSUP, "logging is not supported by %s", - bf_hook_to_str(chain->hook)); - } + if (rule->log && !rule->disabled) { + uint8_t valid = + bf_hook_to_flavor(chain->hook) == BF_FLAVOR_CGROUP_SOCK_ADDR ? + BF_FLAGS(BF_LOG_OPT_INTERNET, BF_LOG_OPT_TRANSPORT, + BF_LOG_OPT_PID, BF_LOG_OPT_COMM) : + BF_FLAGS(BF_LOG_OPT_LINK, BF_LOG_OPT_INTERNET, + BF_LOG_OPT_TRANSPORT); + + if (rule->log & ~valid) { + return bf_err_r(-EINVAL, "invalid log options for %s", + bf_hook_to_str(chain->hook)); + } - if (rule->log && !rule->disabled) chain->flags |= BF_FLAG(BF_CHAIN_LOG); + } if (bf_rule_mark_is_set(rule) && bf_hook_to_flavor(chain->hook) != BF_FLAVOR_TC && diff --git a/src/libbpfilter/include/bpfilter/elfstub.h b/src/libbpfilter/include/bpfilter/elfstub.h index 31a05ac80..e23afadcb 100644 --- a/src/libbpfilter/include/bpfilter/elfstub.h +++ b/src/libbpfilter/include/bpfilter/elfstub.h @@ -122,7 +122,7 @@ enum bf_elfstub_id /** * Log user-requested packet headers to a ring buffer. * - * `__u8 bf_log(struct bf_runtime *ctx, __u32 rule_id, __u8 headers, __u32 verdict, __u32 l3_l4_proto)` + * `__u8 bf_pkt_log(struct bf_runtime *ctx, __u32 rule_id, __u8 headers, __u32 verdict, __u32 l3_l4_proto)` * * **Parameters** * - `ctx`: address of the `bf_runtime` context of the program. @@ -133,7 +133,7 @@ enum bf_elfstub_id * * **Return** 0 on success, or 1 on error. */ - BF_ELFSTUB_LOG, + BF_ELFSTUB_PKT_LOG, /** * Calculate flow hash from packet 5-tuple + IPv6 flow label. @@ -153,6 +153,23 @@ enum bf_elfstub_id */ BF_ELFSTUB_FLOW_HASH, + /** + * Log socket address information to a ring buffer. + * + * `__u8 bf_sock_addr_log(struct bf_runtime *ctx, __u32 rule_id, __u8 log_opts, __u32 verdict, __u32 l3_l4_proto)` + * + * **Parameters** + * - `ctx`: address of the `bf_runtime` context of the program. + * - `rule_id`: id of the matched rule. + * - `log_opts`: user-requested log options bitmask. + * - `verdict`: verdict of the matched rule. + * - `l3_l4_proto`: layer 3 (internet) and layer 4 (transport) protocols + * packed (l3 << 16 | l4) + * + * **Return** 0 on success, or 1 on error. + */ + BF_ELFSTUB_SOCK_ADDR_LOG, + _BF_ELFSTUB_MAX, }; diff --git a/src/libbpfilter/include/bpfilter/flavor.h b/src/libbpfilter/include/bpfilter/flavor.h index 51c7440dd..82ccc4505 100644 --- a/src/libbpfilter/include/bpfilter/flavor.h +++ b/src/libbpfilter/include/bpfilter/flavor.h @@ -11,6 +11,7 @@ struct bf_matcher; struct bf_program; +struct bf_rule; /** * @file flavor.h @@ -135,6 +136,19 @@ struct bf_flavor_ops */ int (*gen_inline_matcher)(struct bf_program *program, const struct bf_matcher *matcher); + + /** + * @brief Generate bytecode for rule logging. + * + * Each flavor controls its own register setup and ELF stub selection. + * Required for all flavors. + * + * @param program Program being generated. Can't be NULL. + * @param rule Rule whose log action to generate. Can't be NULL. + * @return 0 on success, or negative errno on error. + */ + int (*gen_inline_log)(struct bf_program *program, + const struct bf_rule *rule); }; /** diff --git a/src/libbpfilter/include/bpfilter/rule.h b/src/libbpfilter/include/bpfilter/rule.h index c1d6bcc72..91cd6d5ba 100644 --- a/src/libbpfilter/include/bpfilter/rule.h +++ b/src/libbpfilter/include/bpfilter/rule.h @@ -19,28 +19,23 @@ #define BF_RULE_MARK_MASK (0x00000000ffffffffULL) /** - * @brief Return the string representation of a `bf_pkthdr` enumeration value. + * @brief Return the string representation of a `bf_log_opt` enumeration value. * - * @param hdr `bf_pkthdr` enumeration value. - * @return A pointer to the C-string representation of `hdr`. + * @param opt `bf_log_opt` enumeration value. + * @return A pointer to the C-string representation of `opt`. */ -const char *bf_pkthdr_to_str(enum bf_pkthdr hdr); +const char *bf_log_opt_to_str(enum bf_log_opt opt); /** - * @brief Return the `bf_pkthdr` enumeration value corresponding to a string. + * @brief Return the `bf_log_opt` enumeration value corresponding to a string. * - * @pre - * - `str` is a non-NULL pointer to a C-string. - * - `hdr != NULL` - * @post - * - On failure, `hdr` is unchanged. - * - * @param str String to get the corresponding `bf_pkthdr` enumeration value for. - * @param hdr On success, contains the `bf_pkthdr` enumeration value - * corresponding to `str`. + * @param str String to get the corresponding `bf_log_opt` enumeration value + * for. + * @param opt On success, contains the `bf_log_opt` enumeration value + * corresponding to `str`. Can't be NULL. * @return 0 on success, or a negative error value on failure. */ -int bf_pkthdr_from_str(const char *str, enum bf_pkthdr *hdr); +int bf_log_opt_from_str(const char *str, enum bf_log_opt *opt); #define _free_bf_rule_ __attribute__((__cleanup__(bf_rule_free))) @@ -77,8 +72,8 @@ struct bf_rule }; static_assert( - _BF_PKTHDR_MAX < 8, - "bf_pkthdr has more than 8 values, it won't fit in bf_rule.log's 8 bits"); + _BF_LOG_OPT_MAX <= 8, + "bf_log_opt has more than 8 values, it won't fit in bf_rule.log's 8 bits"); /** * Allocated and initialise a new rule. diff --git a/src/libbpfilter/include/bpfilter/runtime.h b/src/libbpfilter/include/bpfilter/runtime.h index f245bb62b..6199f31af 100644 --- a/src/libbpfilter/include/bpfilter/runtime.h +++ b/src/libbpfilter/include/bpfilter/runtime.h @@ -7,11 +7,24 @@ #define bf_aligned(x) __attribute__((aligned(x))) +/** + * @brief Give an anonymous union or struct a name only for Doxygen. + * + * Allows anonymous unions/structs in code while keeping Doxygen's parser happy. + */ +#ifdef DOXYGEN +#define ANONYMOUS_MEMBER(name) name +#else +#define ANONYMOUS_MEMBER(name) +#endif + // _Static_assert doesn't exist in C++ #ifndef __cplusplus #define static_assert _Static_assert #endif +#include + #include /** @@ -50,31 +63,101 @@ static_assert(BF_L3_SLICE_LEN % 8 == 0, static_assert(BF_L4_SLICE_LEN % 8 == 0, "BF_L4_SLICE_LEN should be aligned to 8 bytes"); +/** Size of the process name buffer, matches TASK_COMM_LEN. */ +#define BF_COMM_LEN 16 + /** - * @brief Types of network packet headers. + * @brief Log options controlling what data is captured in a log entry. + * + * Packet-based hooks support l2, l3, and l4 headers. Socket-based hooks + * support addresses, port, and process metadata (internet, transport, + * pid, comm). */ -enum bf_pkthdr +enum bf_log_opt { - /** - * Link layer header: Ethernet, ... - */ - BF_PKTHDR_LINK, + /** Link layer data: Ethernet header. */ + BF_LOG_OPT_LINK, - /** - * Internet header: IPv4, IPv6, ... - */ - BF_PKTHDR_INTERNET, + /** Internet layer data: IPv4/IPv6 header. */ + BF_LOG_OPT_INTERNET, /** - * Transport header: TCP, UDP, ... + * Transport layer data: TCP/UDP header. * * ICMPv6 is an internet layer (L3) header, but it's encapsulated inside an - * IPv6 packet, so it's considered a transport layer (L4) header in - * bpfilter. + * IPv6 packet, so it's considered layer 4 in bpfilter. */ - BF_PKTHDR_TRANSPORT, + BF_LOG_OPT_TRANSPORT, + + /** Process ID (root namespace tgid). */ + BF_LOG_OPT_PID, + + /** Process name (comm). */ + BF_LOG_OPT_COMM, + + _BF_LOG_OPT_MAX, +}; + +/** + * @brief Log entry type discriminator. + */ +enum bf_log_type +{ + /** Packet-based log entry (XDP, TC, NF, cgroup_skb). */ + BF_LOG_TYPE_PACKET, + + /** Socket address log entry (cgroup_sock_addr). */ + BF_LOG_TYPE_SOCK_ADDR, + + _BF_LOG_TYPE_MAX, +}; + +/** + * @brief Packet log payload fields (XDP, TC, NF, cgroup_skb). + */ +struct bf_log_pkt +{ + /** Total size of the packet, including the payload. */ + __u64 pkt_size; + + /** User-requested headers, as defined in the rule. */ + __u8 req_headers:4; + + /** Logged headers, as not all hooks can access all headers. */ + __u8 headers:4; + + /** Layer 2 header. */ + bf_aligned(8) __u8 l2hdr[BF_L2_SLICE_LEN]; + + /** Layer 3 header. */ + bf_aligned(8) __u8 l3hdr[BF_L3_SLICE_LEN]; + + /** Layer 4 header. */ + bf_aligned(8) __u8 l4hdr[BF_L4_SLICE_LEN]; +}; - _BF_PKTHDR_MAX, +/** + * @brief Socket address log payload fields (cgroup_sock_addr). + */ +struct bf_log_sock_addr +{ + /** Root namespace PID (tgid) of the process. */ + __u32 pid; + + /** Destination port in host byteorder. */ + __u16 dport; + + /** User-requested log options bitmask. */ + __u8 req_log_opts; + + /** Process name. */ + bf_aligned(8) __u8 comm[BF_COMM_LEN]; + + /** Source address (4 bytes for IPv4, 16 for IPv6). */ + bf_aligned(8) __u8 saddr[sizeof(struct in6_addr)]; + + /** Destination address (4 bytes for IPv4, 16 for IPv6). */ + bf_aligned(8) __u8 daddr[sizeof(struct in6_addr)]; }; /** @@ -83,17 +166,13 @@ enum bf_pkthdr * The structure is published into a log buffer by the chain, when a hit rule * has a `log` action defined. * - * Except for the raw packet headers (`l2hdr`, `l3hdr`, and `l4hdr`), all the - * values are stored in host byteorder. + * All fields are stored in host byteorder unless noted otherwise. */ struct bf_log { - /** Timestamp of the packet processing. */ + /** Timestamp of the event. */ __u64 ts; - /** Total size of the packet, including the payload. */ - __u64 pkt_size; - /** ID of the rule triggering the log. */ __u32 rule_id; @@ -106,20 +185,22 @@ struct bf_log /** Layer 4 (transport) protocol identifier. */ __u8 l4_proto; - /** User-request headers, as defined in the rule. */ - __u8 req_headers:4; - - /** Logged headers, as not all hooks can access all headers. */ - __u8 headers:4; - - /** Layer 2 header. */ - bf_aligned(8) __u8 l2hdr[BF_L2_SLICE_LEN]; + /** Log entry type. */ + __u8 log_type; - /** Layer 3 header. */ - bf_aligned(8) __u8 l3hdr[BF_L3_SLICE_LEN]; - - /** Layer 4 header. */ - bf_aligned(8) __u8 l4hdr[BF_L4_SLICE_LEN]; + /** + * Flavor-specific payload, discriminated by `log_type`. + * + * - `BF_LOG_TYPE_PACKET`: use `pkt` — raw packet headers in network + * byteorder. + * - `BF_LOG_TYPE_SOCK_ADDR`: use `sock_addr` — socket address, port, + * and process metadata. + */ + union + { + struct bf_log_pkt pkt; + struct bf_log_sock_addr sock_addr; + } ANONYMOUS_MEMBER(payload); }; struct bf_ip4_lpm_key diff --git a/src/libbpfilter/rule.c b/src/libbpfilter/rule.c index 22b86ab27..ccd98a9ec 100644 --- a/src/libbpfilter/rule.c +++ b/src/libbpfilter/rule.c @@ -19,28 +19,28 @@ #include "bpfilter/runtime.h" #include "bpfilter/verdict.h" -static const char *_bf_pkthdr_strs[] = { - [BF_PKTHDR_LINK] = "link", - [BF_PKTHDR_INTERNET] = "internet", - [BF_PKTHDR_TRANSPORT] = "transport", +static const char *_bf_log_opt_strs[] = { + [BF_LOG_OPT_LINK] = "link", [BF_LOG_OPT_INTERNET] = "internet", + [BF_LOG_OPT_TRANSPORT] = "transport", [BF_LOG_OPT_PID] = "pid", + [BF_LOG_OPT_COMM] = "comm", }; -static_assert_enum_mapping(_bf_pkthdr_strs, _BF_PKTHDR_MAX); +static_assert_enum_mapping(_bf_log_opt_strs, _BF_LOG_OPT_MAX); -const char *bf_pkthdr_to_str(enum bf_pkthdr hdr) +const char *bf_log_opt_to_str(enum bf_log_opt opt) { - if (hdr < 0 || hdr >= _BF_PKTHDR_MAX) - return ""; + if (opt < 0 || opt >= _BF_LOG_OPT_MAX) + return ""; - return _bf_pkthdr_strs[hdr]; + return _bf_log_opt_strs[opt]; } -int bf_pkthdr_from_str(const char *str, enum bf_pkthdr *hdr) +int bf_log_opt_from_str(const char *str, enum bf_log_opt *opt) { - assert(hdr); + assert(opt); - for (int i = 0; i < _BF_PKTHDR_MAX; ++i) { - if (bf_streq_i(str, _bf_pkthdr_strs[i])) { - *hdr = (enum bf_pkthdr)i; + for (int i = 0; i < _BF_LOG_OPT_MAX; ++i) { + if (bf_streq_i(str, _bf_log_opt_strs[i])) { + *opt = (enum bf_log_opt)i; return 0; } } diff --git a/tests/e2e/hooks/cgroup_sock_addr_connect4.sh b/tests/e2e/hooks/cgroup_sock_addr_connect4.sh index 009e425f4..86c475a8c 100755 --- a/tests/e2e/hooks/cgroup_sock_addr_connect4.sh +++ b/tests/e2e/hooks/cgroup_sock_addr_connect4.sh @@ -21,6 +21,20 @@ ${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_C ${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule udp.dport eq 53 counter DROP" ${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule udp.dport range 1024-65535 counter DROP" +# Logging +${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.l4_proto eq tcp log pid,comm counter DROP" +${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule ip4.daddr eq 1.1.1.1 log pid counter DROP" +${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.dport eq 443 log pid,comm counter DROP" +${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule ip4.daddr eq 1.1.1.1 log internet counter DROP" +${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.dport eq 443 log transport counter DROP" +${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.dport eq 443 log internet,transport,pid,comm counter DROP" +${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.dport eq 443 log pid,internet counter DROP" +${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.dport eq 443 log comm,transport counter DROP" + +# Unsupported log options for socket hooks (link is packet-only) +(! ${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.dport eq 443 log link,internet,transport counter DROP") +(! ${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.dport eq 443 log link counter DROP") + # Unsupported matchers (! ${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.iface eq lo counter DROP") (! ${BFCLI} ruleset set --dry-run --from-str "chain test BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4 ACCEPT rule meta.sport eq 1234 counter DROP") @@ -112,3 +126,9 @@ ${FROM_NS} ${BFCLI} chain set --from-str "chain c BF_HOOK_CGROUP_SOCK_ADDR_CONNE udp4_connect ${HOST_IP_ADDR} 9990 (! udp4_connect ${HOST_IP_ADDR} 9991) ${FROM_NS} ${BFCLI} ruleset flush + +# Logging with internet,transport,pid,comm +${FROM_NS} ${BFCLI} chain set --from-str "chain c BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4{cgpath=${CGROUP_PATH}} ACCEPT rule meta.dport eq 9990 log internet,transport,pid,comm DROP" +(! udp4_connect ${HOST_IP_ADDR} 9990) +udp4_connect ${HOST_IP_ADDR} 9991 +${FROM_NS} ${BFCLI} ruleset flush diff --git a/tests/e2e/rules/log.sh b/tests/e2e/rules/log.sh index 0fb9bec9b..fac3c5176 100755 --- a/tests/e2e/rules/log.sh +++ b/tests/e2e/rules/log.sh @@ -6,7 +6,10 @@ make_sandbox (! ${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log counter DROP") (! ${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log ip counter DROP") +(! ${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log internet,pid counter DROP") +(! ${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log link,comm counter DROP") +(! ${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log pid,comm counter DROP") ${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log link counter DROP" ${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log link,internet counter DROP" ${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log link,transport counter DROP" -${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log internet,link counter DROP" \ No newline at end of file +${FROM_NS} ${BFCLI} chain set --from-str "chain chain_load_xdp_3 BF_HOOK_XDP ACCEPT rule ip4.proto icmp log internet,link counter DROP" diff --git a/tests/fuzz/keywords.dict b/tests/fuzz/keywords.dict index 2377d20e1..7e285dd59 100644 --- a/tests/fuzz/keywords.dict +++ b/tests/fuzz/keywords.dict @@ -132,10 +132,12 @@ "ipv4" "ipv6" -# Log headers (bf_pkthdr) +# Log options (bf_log_opt) "link" "internet" "transport" +"pid" +"comm" "ip4" "ip6" "ip4,tcp" diff --git a/tests/harness/Rule.hpp b/tests/harness/Rule.hpp index 7a4a99068..45da2a1ed 100644 --- a/tests/harness/Rule.hpp +++ b/tests/harness/Rule.hpp @@ -21,7 +21,7 @@ extern "C" { namespace bf { -using RuleLogBitset = std::bitset<_BF_PKTHDR_MAX>; +using RuleLogBitset = std::bitset<_BF_LOG_OPT_MAX>; class Rule { diff --git a/tests/harness/fake.c b/tests/harness/fake.c index 8792305d7..f29538b67 100644 --- a/tests/harness/fake.c +++ b/tests/harness/fake.c @@ -189,7 +189,7 @@ struct bf_rule *bft_rule_dummy(size_t n_matchers) return NULL; rule->index = 0; - rule->log = BF_FLAGS(BF_PKTHDR_INTERNET, BF_PKTHDR_TRANSPORT); + rule->log = BF_FLAGS(BF_LOG_OPT_INTERNET, BF_LOG_OPT_TRANSPORT); rule->mark = 0x17; rule->counters = true; rule->verdict = BF_VERDICT_ACCEPT; diff --git a/tests/unit/libbpfilter/chain.c b/tests/unit/libbpfilter/chain.c index 61c75352e..e7f4f2372 100644 --- a/tests/unit/libbpfilter/chain.c +++ b/tests/unit/libbpfilter/chain.c @@ -141,6 +141,61 @@ static void mixed_enabled_disabled_log_flag(void **state) assert_int_equal(chain->flags & BF_FLAG(BF_CHAIN_LOG), 0); } +static void sock_addr_log_flag(void **state) +{ + _free_bf_chain_ struct bf_chain *chain = NULL; + _clean_bf_list_ bf_list rules = bf_list_default(bf_rule_free, bf_rule_pack); + struct bf_rule *r0 = NULL; + + (void)state; + + assert_ok(bf_rule_new(&r0)); + r0->log = BF_FLAGS(BF_LOG_OPT_PID, BF_LOG_OPT_COMM); + assert_ok(bf_list_add_tail(&rules, r0)); + + assert_ok(bf_chain_new(&chain, "test", BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4, + BF_VERDICT_ACCEPT, NULL, &rules)); + + assert_false(r0->disabled); + assert_int_not_equal(chain->flags & BF_FLAG(BF_CHAIN_LOG), 0); +} + +static void invalid_log_opts_for_hook(void **state) +{ + (void)state; + + // Packet header options on a sock_addr hook + { + _free_bf_chain_ struct bf_chain *chain = NULL; + _clean_bf_list_ bf_list rules = + bf_list_default(bf_rule_free, bf_rule_pack); + struct bf_rule *r0 = NULL; + + assert_ok(bf_rule_new(&r0)); + r0->log = BF_FLAG(BF_LOG_OPT_LINK); + assert_ok(bf_list_add_tail(&rules, r0)); + + assert_err(bf_chain_new(&chain, "test", + BF_HOOK_CGROUP_SOCK_ADDR_CONNECT4, + BF_VERDICT_ACCEPT, NULL, &rules)); + } + + // Process metadata options on a packet hook + { + _free_bf_chain_ struct bf_chain *chain = NULL; + _clean_bf_list_ bf_list rules = + bf_list_default(bf_rule_free, bf_rule_pack); + struct bf_rule *r0 = NULL; + + assert_ok(bf_rule_new(&r0)); + r0->log = BF_FLAG(BF_LOG_OPT_PID); + assert_ok(bf_list_add_tail(&rules, r0)); + + assert_err(bf_chain_new(&chain, "test", BF_HOOK_TC_EGRESS, + BF_VERDICT_ACCEPT, NULL, &rules)); + } +} + static void incompatible_matchers_disable_rule(void **state) { (void)state; @@ -246,6 +301,8 @@ int main(void) cmocka_unit_test(dump), cmocka_unit_test(get_set_from_matcher), cmocka_unit_test(mixed_enabled_disabled_log_flag), + cmocka_unit_test(sock_addr_log_flag), + cmocka_unit_test(invalid_log_opts_for_hook), cmocka_unit_test(incompatible_matchers_disable_rule), cmocka_unit_test(get_set_by_name), }; diff --git a/tests/unit/libbpfilter/rule.c b/tests/unit/libbpfilter/rule.c index b70f99653..3b7c431f2 100644 --- a/tests/unit/libbpfilter/rule.c +++ b/tests/unit/libbpfilter/rule.c @@ -15,8 +15,9 @@ static void to_from_str(void **state) { (void)state; - assert_enum_to_from_str(enum bf_pkthdr, bf_pkthdr_to_str, - bf_pkthdr_from_str, BF_PKTHDR_LINK, _BF_PKTHDR_MAX); + assert_enum_to_from_str(enum bf_log_opt, bf_log_opt_to_str, + bf_log_opt_from_str, BF_LOG_OPT_LINK, + _BF_LOG_OPT_MAX); } static void new_and_free(void **state)