ipt-enable-logs (#267)

* Add some more on_boot..d examples

* Add ipt-enable-logs
This commit is contained in:
Pedro Pombeiro 2021-11-17 07:07:24 +01:00 committed by GitHub
parent cb6ff86d30
commit 9967161b80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 161 additions and 0 deletions

67
ipt-enable-logs/README.md Normal file
View File

@ -0,0 +1,67 @@
# Enable log tags on your UDM
## Features
If you're used to the Unifi Security Gateway, you may miss the USG log prefixes that allow you to know which rule blocked certain traffic.
This mod adds logging prefixes to messages from `/var/log/messages` allowing you to trace a particular log message to the respective iptable rule (which is generated from the firewall rules you configure on the Network application, among other things)
## Requirements
1. You have successfully setup the on boot script described [here](https://github.com/boostchicken/udm-utilities/tree/master/on-boot-script)
## General idea
This mod builds a small Go program that modifies the existing iptables to add `--log-prefix` to entries that are defined as loggable through the `-j LOG` directive. The Go program is built in a Docker container local to the UDM.
Here's an example snippet of an iptable modified by this program:
```
-A UBIOS_PREROUTING_USER_HOOK -p tcp -m set --match-set UBIOS_ADDRv4_eth8 dst -m tcp --dport 15060 -j LOG --log-prefix "[DNAT-PRER_U_HK-4294967310] "
-A UBIOS_PREROUTING_USER_HOOK -p tcp -m set --match-set UBIOS_ADDRv4_eth8 dst -m tcp --dport 15060 -m comment --comment 00000000004294967310 -j DNAT --to-destination 192.168.36.10:15060
```
## Steps
1. Copy [on_boot.d/30-ipt-enable-logs-launch.sh](./on_boot.d/30-ipt-enable-logs-launch.sh) to /mnt/data/on_boot.d
1. Copy the [scripts/ipt-enable-logs](./scripts/ipt-enable-logs) folder to /mnt/data/scripts
1. Copy [scripts/ipt-enable-logs.sh](./scripts/ipt-enable-logs.sh) to /mnt/data/scripts
1. Execute /mnt/data/on_boot.d/30-ipt-enable-logs-launch.sh
1. Copy [scripts/refresh-iptables.sh](./scripts/refresh-iptables.sh) to /mnt/data/scripts
## Refreshing iptables
Whenever you update the firewall rules on the Network application, the iptables will be reprovisioned and will need to be reprocessed
by calling /mnt/data/scripts/refresh-iptables.sh.
## Looking at logs
Logs can be followed easily from another machine through SSH by using the following bash functions:
```shell
function logunifijson() {
ssh unifi "tail -f /var/log/messages" | \
rg "kernel:" | \
sed "s/]IN/] IN/" | \
jq --unbuffered -R '. | rtrimstr(" ") | split(": ") | {date: (.[0] | split(" ") | .[0:3] | join(" "))} + (.[1] | capture("\\[.+\\] \\[(?<rule>.*)\\].*")) + ((.[1] | capture("\\[.+\\] (?<rest>.*)") | .rest | split(" ") | map(select(startswith("[") == false) | split("=") | {(.[0]): .[1]})) | (reduce .[] as $item ({}; . + $item)))'
}
function logunifi() {
logunifijson | jq --unbuffered -r '"\(.date) - \(.rule)\tIN=\(.IN) \t\(.PROTO)\tSRC=\(.SRC)@\(.SPT)\tDST=\(.DST)@\(.DPT)\tLEN=\(.LEN)\t"'
}
```
Here's what the output of `logunifi` looks like:
```
Nov 14 10:58:31 - A-LAN_LOCAL_U-1097364144127 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-1097364144127 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-1097364144127 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-1097364144127 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-1097364144127 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
Nov 14 10:58:31 - A-LAN_LOCAL_U-1097364144127 IN=br0 TCP SRC=192.168.16.10@55804 DST=192.168.16.1@443 LEN=52
```
## Acknowledgements
Thanks a lot to [@opustecnica](https://github.com/opustecnica) for the [initial implementation](https://github.com/opustecnica/public/wiki/UDM-&-UDM-PRO-NOTES) and idea (based on a bash script)!

View File

@ -0,0 +1,9 @@
#!/bin/sh
set -e
if ! iptables-save | grep -e '\-A UBIOS_.* \--log-prefix "\[' > /dev/null; then
/mnt/data/scripts/ipt-enable-logs.sh | iptables-restore -c
else
echo "iptables already contains USER log prefixes, ignoring."
fi

View File

@ -0,0 +1,7 @@
#!/bin/sh
set -e
docker run -it --rm -v /mnt/data/scripts/ipt-enable-logs:/src -w /src --network=none golang:1.17.3 go build -v -o /src/ipt-enable-logs /src >&2
/mnt/data/scripts/ipt-enable-logs/ipt-enable-logs

View File

@ -0,0 +1,3 @@
module pedropombeiro.com/ipt-enable-logs
go 1.17

View File

@ -0,0 +1,62 @@
package main
import (
"fmt"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
)
func main() {
cmd := exec.Command("iptables-save")
outputBytes, err := cmd.Output()
if err != nil {
_ = fmt.Errorf("Failed to run iptables-save: %v", err)
os.Exit(1)
}
str := string(outputBytes)
lines := strings.Split(str, "\n")
re := regexp.MustCompile(`-A UBIOS_([A-Z_]+) .* --comment (\d+) -j ([A-Z]+)`)
for i, line := range lines {
if i != 0 {
fmt.Println()
}
if !strings.HasSuffix(line, "-j LOG") {
fmt.Print(line)
continue
}
matches := re.FindSubmatch([]byte(lines[i+1]))
commentNr, err := strconv.Atoi(string(matches[2]))
if err != nil {
commentNr = 0
}
actionName := getActionName(string(matches[3]))
ruleName := getRuleName(string(matches[1]), commentNr)
fmt.Printf(`%s --log-prefix "[%s-%s] "`, line, actionName, ruleName)
}
}
func getActionName(action string) string {
action = strings.Replace(action, "RETURN", "A", 1)
action = strings.Replace(action, "REJECT", "R", 1)
action = strings.Replace(action, "DROP", "D", 1)
action = strings.Replace(action, "MASQUERADE", "M", 1)
return action
}
func getRuleName(rule string, commentNr int) string {
rule = strings.Replace(rule, "PREROUTING", "PRER", 1)
rule = strings.Replace(rule, "POSTROUTING", "POSTR", 1)
rule = strings.Replace(rule, "HOOK", "HK", 1)
rule = strings.Replace(rule, "USER", "U", 1)
if commentNr != 0 {
rule = fmt.Sprintf("%s-%d", rule, commentNr)
}
return rule
}

View File

@ -0,0 +1,13 @@
#!/bin/sh
set -e
if [ -f /mnt/data/on_boot.d/10-dns.sh ]; then
if ! iptables-save | grep -e '\-A PREROUTING.* \--log-prefix "\[' > /dev/null; then
/mnt/data/on_boot.d/10-dns.sh
else
echo "iptables already contains DNAT log prefixes, ignoring."
fi
fi
/mnt/data/on_boot.d/30-ipt-enable-logs-launch.sh