The why?
This is a shell script that I do use quite frequently, since it’s been run in a cron job to check for host lookup ip changes (utilizing dynamic DNS). This saves users from being locked out if their home ip address changes, also helps keep a stronger firewall.
This basic example will allow two people to access SSH and HTTPS ports.. This works so long as those two people are allowed access on those ports, so this script would probably need modified to accomodate, or just use seperate scripts for groups of individuals.
The only section of this script to adjust are the two arrays, one for ports and the other is clients, at the top of the script. If you want to add more, just follow the same format with ports and clients. Comment out or delete sections with nginx or hosts.allow if not required.
If using hosts.deny, this script will accomdate a hosts.allow, but obviously this could be modified also. If you want to use this TCP wrapper, put a ‘sshd: ALL’ or something along those lines which suits your needs in your hosts.deny.
If using the nginx side, place this key in the server block of your nginx config. #SED-MATCH-LEAVE I could have used a substitute option for sed up to a point, but at least with this method, it will help with the set up of a newly created config or new user. Also if using the nginx config like me, and you don’t need the world wide web on your server, place a deny all; in the server block underneath the allowed ip’s.
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
#!/bin/bash
#allow a dyndns name through your firewall. The idea is to set up a crontab
#to look up the dns hostname so you always have access to the server, via
#your port and protocol of choice. I use something like this to keep a VPN
#tunnel open to a server.
#for manual entry, syntax in terminal for UFW....
#./script.sh ip port proto, i.e.
#./script.sh 123.12.123.12 22 tcp
declare -A ports
# Update ports to cycle through your firewall
ports[ssh]=12345
ports[https]=443
#ports[]=
declare -A clients
# Check hosts associated with client
clients[jamie]=$(host homeIPaddress1.ddns.net | cut -f4 -d' ')
clients[holly]=$(host homeIPaddress2.ddns.net | cut -f4 -d' ')
#clients[]=
# nginx config file
nginx_conf='/etc/nginx/conf.d/web.conf'
# Check if any ufw rules
if [[ $(sudo ufw status | wc -l) == 1 ]]
then
append=True
fi
mkdir -p "$HOME"/logs
timelog="$HOME"/logs/dyndnstime.log
now=$(printf '%(%d-%m-%Y %H:%M:%S)T\n')
function sed-nginx {
# Update an nginx config if you have one? Test on a dummy nginx config beforehand.
# You might also want to change a subnet instead, replace or leave out entirely
# An example of append (Placing that comment '#SED-MATCH-LEAVE' somewhere in your nginx config file (server block))
# I'm using \\\t to get a tab space in the conf, might need adjusted
sudo sed -i "/#SED-MATCH-LEAVE/a \\\tallow ${clients[$client]};" "$nginx_conf"
}
# adds new UFW firewall rules
function add-new-rules {
for port in "${ports[@]}"; do
if [[ $append == True ]]; then
sudo ufw allow from "${clients[$client]}" to any port "$port" proto tcp
else
# The reason for inserting new rules, is to keep them above any rate limiting rules which might interfere with the users. I've chosen 1 to keep above all rules.
sudo ufw insert 1 allow from "${clients[$client]}" to any port "$port" proto tcp
fi
done
}
# If no commandline options...
if [[ -z "$1" ]]
then
for client in "${!clients[@]}"
do
# If no ip found from host, continue to next host, otherwise hosts.allow may fill with junk
if [[ ! ${clients[$client]} =~ [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} ]]; then
echo "No ip found from ${client}, moving to next client"
continue
fi
logfile="${HOME}/logs/${client}.ip.log"
if [[ ! -f "$logfile" ]]
then
# data will be stored in the users $HOME directory and not the root directory.
# add new UFW rules
add-new-rules
# Update an nginx config if you have one? Test on a dummy nginx config beforehand.
# Remove or comment out line below if you don't need this
sed-nginx
# hosts allow file update
echo "ALL: ${clients[$client]} # Home" | sudo tee -a /etc/hosts.allow
echo "${clients[$client]}" > "$logfile"
echo "New host time log created" > "$timelog"
else
old_ip=$(< "$logfile")
if [[ ${clients[$client]} == "$old_ip" ]]
then
echo "$client IP address has not changed"
echo "$now : $client : log running every hour, no changes" >> "$timelog"
else
# Remove old IPs from client
num_rules=$(sudo ufw status numbered | grep -c "$old_ip")
for (( a=1; a<=num_rules; a++ )); do
first_rule=$(sudo ufw status numbered | grep "$old_ip" | sed -En "1s/.*([0-9]+)\].*/\1/p")
echo "y" | sudo ufw delete "$first_rule"
done
# Clean up hosts.allow file
sudo sed -i "/$old_ip/d" /etc/hosts.allow
# Clean up nginx conf
sudo sed -i "/$old_ip/d" "$nginx_conf"
# Add new rules
add-new-rules
# Update an nginx config if you have one? Test on a dummy nginx config beforehand. You might change to many ip addresses with this command.
# Remove line below if you don't need this
sed-nginx
# update hosts allow file
echo "ALL: ${clients[$client]} # Home" | sudo tee -a /etc/hosts.allow
echo "${clients[$client]}" > "$logfile"
echo "$client IP has been updated"
echo "$now : $client New IP updated" >> "$timelog"
fi
fi
done
else
# Sense checking the commandline entries
if [[ ! $1 =~ [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} ]]; then
echo "$1 is not a valid ip address"
exit 1
fi
if [[ ! $2 =~ [0-9]{1,5} ]]; then
echo "$2 is not a valid port number"
exit 1
fi
if [[ ! $3 =~ ^tcp$|^udp$ ]]; then
echo "$3 is not a valid protocol, use tcp or udp"
exit 1
fi
if [[ $append == True ]]; then
sudo ufw allow from "$1" to any port "$2" proto "$3"
else
sudo ufw insert 1 allow from "$1" to any port "$2" proto "$3"
fi
echo "ALL: $1 # Home" | sudo tee -a /etc/hosts.allow
# Update an nginx config if you have one? Test on a dummy nginx config beforehand.
# Remove line below if you don't need this
# An example of append (Placing that comment '#SED-MATCH-LEAVE' somewhere in your nginx config file (server block))
# I'm using \\\t to get a tab space in the conf, might need adjusted
sudo sed -i "/#SED-MATCH-LEAVE/a \\\tallow $1;" "$nginx_conf"
fi