Skip to main content

Packet Logs

This service receives packets over NFLog netlink messages.

The packet info is sent to the sprbus where clients subscribing to the nft-prefix gets notified. It's easier to talk to sprbus for packet inspection but also available by packet_logs.

Example: The db service can enable storage of logs by adding the topic to configs/db/config.json under the SaveEvents key.

See also: sprbus

The Groups

Group 0

chain INPUT  { ...
$(if [ "$WANIF" ]; then echo "iifname $WANIF log prefix \"wan:in \" group 0"; fi)
$(if [ "$WANIF" ]; then echo "iifname ne $WANIF log prefix \"lan:in \" group 0"; else echo "log prefix \"lan:in \" group 0"; fi)


chain FORWARD { ...

$(if [ "$WANIF" ]; then echo "oifname $WANIF log prefix \"wan:out \" group 0"; fi)
$(if [ "$WANIF" ]; then echo "oifname ne $WANIF log prefix \"lan:out \" group 0"; else echo "log prefix \"lan:out \" group 0"; fi)



Input from the upstream interface ($WANIF)


Input from all other devices (wireguard, wireless clients, wired devices)


Packets forwarded upstream to the internet over the $WANIF interface


Packets forwaded to any other non-upstream interface

Group 1 - Dropped packets

log prefix "drop:private " group 1
counter log prefix "drop:forward " group 1
counter log prefix "drop:input " group 1
log prefix "drop:mac " group 1


This prefix marks packets that were dropped because they were headed upstream to a private network address, but blocked from doing so because they were not in a permitted group


Packets that were dropped during forward


Input packets into SPR that were dropped


Packets that were dropped because of an strict MAC filtering in the INPUT chain in the FORWARD chain.

⇨ View the code

Inspecting packets

Retrieve JSON packet logs on SPR with:

docker exec -it superpacket_logs /stream-json-logs > log.json

will log packets for 20 seconds, can specify with -timeout flag.

Packets can be inspected with jq, see following section for fields. Raw data is available and base64 encoded.

Script to inspect traffic


Example script with gum - a tool for glamorous shell scripts.

Install dependencies:

apt install jq
go install
# packet_logs json stream build if not running on spr:
# cd packet_logs/stream-json-logs && go build -o stream
# ./stream > log.json
BIN_STREAM="docker exec -it superpacket_logs /stream-json-logs"

log_stream() {
gum spin -s moon --title "Logging traffic... 20s" -- sh -c "$BIN_STREAM > $F"

table() {
F_UDP='[.Timestamp,"UDP",.Prefix, ([.IP.SrcIP,.UDP.SrcPort|tostring]|join(":")), ([.IP.DstIP,.UDP.DstPort|tostring]|join(":"))]'
F_TCP='[.Timestamp,"TCP",.Prefix, ([.IP.SrcIP,.TCP.SrcPort|tostring]|join(":")), ([.IP.DstIP,.TCP.DstPort|tostring]|join(":"))]'

cat "$F" \
| jq -r -c "if .UDP!=null then $F_UDP elif .TCP!=null then $F_TCP else empty end | @csv" \
| sed 's/"//g' > "$F_CSV"


if [ $IS_TABLE -eq 1 ]; then
SEL_ROW=$(gum table -c "ts, proto, prefix, src, dst" -w 30,8,10,20,20 --height 20 -f "$F_CSV")
SEL_ROW=$(cat "$F_CSV" \
| sed 's/,/ /g' \
| gum filter --no-fuzzy --indicator.foreground="99" --match.foreground="99" --height 20)

SEL_TS=$(echo $SEL_ROW|sed 's/,/\t/g'|awk '{print $1}')

if [ -z "$SEL_TS" ]; then

SEL_JSON=$(cat "$F" | jq "select(.Timestamp == \"$SEL_TS\")")

echo "$SEL_JSON" | gum pager

gum style --foreground 99 --border double --border-foreground 99 --padding "0 4" --margin 1 "SPR packet logs cli"
gum input --placeholder="Press ENTER to start"

if [ ! -f "$F" ]; then

while true; do table; done

save the script in and run it: