-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathknock
executable file
·171 lines (138 loc) · 4.25 KB
/
knock
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#! /bin/bash
# Script to knock, but not more often than a specific number of seconds
# (so it's a no-op if we try and knock before that).
#
# NOTE: the flaw in this method is that if the firewall is rebooted or the
# rules cleared from the firewall, then we may need to knock before
# the time period is over.
#
# TODO:
# - make knock period configurable
###############################################################################
# User settable parameters
# The actual knock period minus 30 minutes
# (From FW_ACCESS_TIMEOUT in ficonfig/hosts/fw0/etc/fwknop/access.conf)
knock_period_seconds=$(( 28800 - 30 * 60 ))
knockroot=$HOME/.knock.d
###############################################################################
set -eu
mkdir -p "$knockroot"
rc="$HOME/.knockrc"
# shellcheck disable=SC1090
[ -f "$rc" ] && source "$rc"
: "${quiet:=}"
: "${verbose:=}"
function verbose {
if [ "$verbose" ]; then
echo "$@"
fi
}
function now {
date +%s
}
function usage {
cat 1>&2 <<EOF
Usage: knock [-q] [-v] [-f] hostname
-v :: be verbose
-q :: be quiet
-f :: force knock regardless of how long it's been since fwknop was called
Knock, with fwknop, on "hostname", where "hostname" is the name
of a stanza in \$HOME/.fwknoprc. The difference is that we do not
knock more than once each $knock_period_seconds seconds.
"knock" creates and uses $knockroot.
\$HOME/.knockrc is sourced at the start of knock. Two user-defined
functions can be defined in it, which are called if they exist:
knock_preknock_hook :: a function called before pretty much anything is done
knock_user_knock :: called in place of fwknop -- can be useful if you
want to tweak the arguments to fwknop. It is given a single argument,
\$hostname.
EOF
exit 1
}
function errordie {
echo "Error: $*" 1>&2
exit 1
}
if [ "$(uname -s)" = "Darwin" ]; then
if stat=$(type -p gstat); then
: # found it
else
errordie "cannot find 'gstat': install brew/macports coreutils"
fi
elif [ -x /usr/bin/stat ]; then
stat=/usr/bin/stat
else
errordie "cannot find 'stat' program"
fi
hostname=
force=
while test $# -gt 0; do
case $1 in
--help) usage ;;
-f) force=$1 ;;
-v) verbose=$1 ;;
-q) quiet=$1 ;;
-*) usage ;;
*) [ $# -eq 1 ] || usage
hostname=$1 ;;
esac
shift
done
[ "$hostname" ] || usage hostname not given
if [ "$(type -t knock_user_seconds)" = "function" ]; then
knock_period_seconds=$(knock_user_seconds "$hostname")
fi
# The modification time of this directory is use to record when we knock
knockdir=$knockroot/knock.${hostname}
# A lock directory to make sure two invocations of this script don't
# run at the same time
lockdir=$knockroot/knock.${hostname}.lock
if [ "$(type -t knock_preknock_hook)" = "function" ]; then
knock_preknock_hook
fi
if ! mkdir "$lockdir" > /dev/null 2>&1; then
# Couldn't make it. Make sure the lock isn't older than a
# minute.
st_mtime=$($stat --format=%Y "$lockdir")
since_modified=$(( $(now) - st_mtime ))
if [ $since_modified -gt 60 ]; then
# this script shouldn't take more than a minute to run, so
# tell the caller we have a dead lock and remove it.
## for reasons I don't understand, Michelle often has dead locks
## hanging around.
echo "$lockdir held too long, removing..."
if ! rmdir "$lockdir"; then
echo Warning: rmdir failed
fi
else
verbose another copy of this script is running, exiting
exit 0
fi
fi
# shellcheck disable=SC2064
trap "rmdir $lockdir" 0
if [ -d "$knockdir" ]; then
st_mtime=$($stat --format=%Y "$knockdir")
seconds_since_knock=$(( $(now) - st_mtime ))
verbose seconds_since_knock=$seconds_since_knock
else
seconds_since_knock=
fi
if [ -z "$seconds_since_knock" ]; then
verbose initialize knockdir since it does not exist
mkdir "$knockdir"
elif [ "$force" ]; then
: # force the knock
elif [ $seconds_since_knock -lt "$knock_period_seconds" ]; then
left=$(( knock_period_seconds - seconds_since_knock ))
verbose "not time to knock yet ($left more seconds)"
exit 0
fi
[ "$quiet" ] || echo "$(date): time to knock for $hostname"
if [ "$(type -t knock_user_knock)" = "function" ]; then
knock_user_knock "$hostname"
else
verbose fwknop -n "$hostname"
fwknop -n "$hostname"
fi
touch "$knockdir"