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)

}

wan:in

Input from the upstream interface ($WANIF)

lan:in

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

wan:out

Packets forwarded upstream to the internet over the $WANIF interface

lan:out

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

drop:private

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

drop:forward

Packets that were dropped during forward

drop:input

Input packets into SPR that were dropped

drop:mac

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

packetlogs

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

Install dependencies:

apt install jq
go install github.com/charmbracelet/gum@latest
#!/bin/sh
# packet_logs json stream build if not running on spr:
# cd packet_logs/stream-json-logs && go build -o stream
# ./stream > log.json
F="$PWD/log.json"
F_CSV="${F}.csv"
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"

IS_TABLE=0

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")
else
SEL_ROW=$(cat "$F_CSV" \
| sed 's/,/ /g' \
| gum filter --no-fuzzy --indicator.foreground="99" --match.foreground="99" --height 20)
fi

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

if [ -z "$SEL_TS" ]; then
exit
fi

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
log_stream
fi

while true; do table; done

save the script in packetlogs.sh and run it:

./packetlogs.sh