summaryrefslogtreecommitdiffstats
path: root/scripts/sh/pf.sh
blob: 5cd5e45ffaa3b0e6d8760690ccc5b1095fa821ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/bin/sh
# 
# Helps you edit a production packet filter configuration and reduces the risk of doing something really bad.
# 
# Author: Georg Pfuetzenreuter <georg@lysergic.dev>
# Created: 02/11/2021
# Last edit: 07/12/2021
# Version: 2.1
#
# This assumes .ssh/config being configured to ssh into your router with a user having write access to /tmp/* and $prodfile as well as having doas permissions for `pfctl -f $prodfile`.

editor="$(which nvim)"
difftool="/home/lysergic/lysergic-venv/bin/icdiff"
diffargs=( -L "CURRENT CONFIGURATION" -L "YOUR CONFIGURATION" -N -U2 )
prodfile="/etc/pf.conf"
backupfile="/tmp/pf.conf.bak-$(date -u +%d%m%y-%H%M)"
stagefile="/tmp/pf.conf-work-$USER-$(date -u +%d%m%y-%H%M)"

gethostaddress () {
        ssh -G "$host" |grep hostname |awk '{print $2}' |head -n1
}

init () {
        #hostaddress=$(gethostaddress)
        hostaddress="$host"
        if nc -z $hostaddress 22 2>/dev/null; then
                workfile="/tmp/pf.conf.$host-$USER-$(date -u +%d%m%y-%H%M)"
                ssh -q $host cp $prodfile $backupfile
                scp -q $host:$prodfile $workfile
                localbackupfile="${workfile}_original"
                cp $workfile $localbackupfile
                edit
        else
                echo "Host not reachable."
        fi
}


edit () {
        if [ ! -f "$workfile" ]; then
                echo "Could not create workfile."
                exit 1
        else
                $editor "$workfile"
                scp -q $workfile $host:$stagefile
                check
        fi
}

check () {
        #echo "$stagefile"
        render_diff
        ssh -q $host pfctl -nf $stagefile
        result="$?"
        case $result in
                0 ) edit_ok
                ;;
                1 ) edit_failed
                ;;
                * ) echo "$result - Unhandled condition. Aborting." && exit 1
                ;;
        esac
}

render_diff () {
        $difftool "${diffargs[@]}" $localbackupfile $workfile
}

send_report () {
        maildiff=$(diff -u --color=never $localbackupfile $workfile)
        echo -e "$USER deployed packet filter changes on $host at $(date):\n\n$maildiff" | mail -s "pf changes on $host by $USER" system@lysergic.dev 
}

edit_ok () {
        echo "Syntax OK. Type YES to deploy changes, edit to edit, or anything else to abort."
        read choice
        if [ "$choice" = "YES" ]; then
                deploy
        elif [ "$choice" = "edit" ]; then
                edit
        else
                #rollback
                abort
        fi
}

edit_failed () {
        echo "Syntax error. [e]dit or [a]bort?"
        read choice
        if [ "$choice" = "e" ]; then
                edit
        elif [ "$choice" = "a" ]; then
                abort
                echo "OK. Exiting."
        else
                echo "Invalid choice. Let's try this again."
                edit_failed
        fi
}

abort () {
        rm $workfile
        ssh -q $host rm $stagefile
}

rollback () {
        ssh -q $host cp $backupfile $prodfile
        ssh -q $host pfctl -nf $prodfile
        result="$?"
        case $result in
                0 ) echo "Rollback ok." && exit
                ;;
                1 ) echo "Rollback failed. You NEED to investigate this."
                ;;
                * ) echo "Unhandled rollback return code. Investigate this!"
                ;;
        esac

}

deploy () {
        ssh -q $host cp $stagefile $prodfile
        ssh -q $host pfctl -nf $prodfile
        result="$?"
        case $result in
                0 )
                send_report
                ssh -q $host "doas pfctl -f $prodfile && rm $stagefile"
                echo "OK."
                rm $workfile
                ;;
                1 )
                echo "Deployment failed. Initiating rollback."
                rollback
                ;;
                * ) echo "Unhandled condition. Investigate this! Initiating rollback."
                rollback
                ;;
        esac
}

if [ -z "$1" ]; then
        echo "Missing argument. Specify a host."
        exit 1
else
        host="$1"
        init
fi