-
Notifications
You must be signed in to change notification settings - Fork 0
/
nodeUP
365 lines (326 loc) · 17.6 KB
/
nodeUP
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
#!/bin/bash
########################## MASTER TO-ADD ############################
############################################################################
# add variables for fine tuning; like timeout for ssh and scp
# create feature to keep code updated between the nodes, check when to download from node when majority provides same src hash?
# make scripts check if anyone on subnet has different serverconfig or servername setup and respond accordingly
# create a local record of my ip address once subnet is populated to remove need for external service
# sync https://www.rlocman.ru/i/File/2007/10/24/2006_WSL_Firefly_Synchronization_Ad_Hoc_Networks.pdf
#
######################## Extra details ########################
############################################################################
# Repeat(default=false):
# the repeat function is used to introduce all locally known hosts(except noted in .ignore) to the current remote node being updated
# if this is your first run you may create the file .nodes.ignore file and populate it with nodes to ignore
# the "node names" is used to determine which nodes should be ignored, the file should be a list of hostnames, each on a new line
# # # # # # # # # # # # # #
# Script will install itself into users ~/home/bin folder, (the .bashrc file and the ~/home/bin folder will be checked, then install itself accordingly)
############################ REQUIREMENTS ############################
############################################################################
#
# Script assumes all nodes are uniquely identified by their "node names" within a "subnet"
# Account running the script is considered a PUBLIC account within a subnet!
# Script assumes ssh service is running with a publicly accessible ssh port AND accepts key based authentication
# The account password may be removed
#
############################################################################
############################################################################
#remote node details file location and install script name
#note: make sure these are the SAME across ALL NODES within a "subnet"
serverconfig=".nodes"
SCRIPTNAME=nodeUP
#check for stored configuration variables from .nodes.myconfig file, otherwise input and save node details
if [ ! -f "$HOME/$serverconfig.myconfig" ] ; then
echo "First use detected... Please input next setup parameters carefully:-"
while ! [[ "$correct" =~ ^yes$ ]]; do
while ! [[ "$servname" =~ ^[a-zA-Z0-9]+$ ]] ; do read -p "Enter a name for this node(a-Z1-9):" servname; done
while ! [[ "$myport" =~ ^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$ ]] ; do read -p "Enter the SSH port used(EXTERNAL):" myport; done
read -p "Would you like to use this node as a REPEATER?(y/N):" repeat; echo ""
if [[ "$repeat" =~ ^[yY]$ ]] ; then repeat=true; else repeat=false; fi
read -p "Was the provided information above correct?(type yes to continue):" correct
done
echo "servname=$servname" >> "$HOME/$serverconfig.myconfig"
echo "myport=$myport" >> "$HOME/$serverconfig.myconfig"
echo "repeat=$repeat" >> "$HOME/$serverconfig.myconfig"
chmod 600 "$HOME/$serverconfig.myconfig"
echo "Saved node details to file $HOME/$serverconfig.myconfig"
else source "$HOME/$serverconfig.myconfig"; fi
#### Install Script ####
# check if .bashrc has $HOME/bin entry
if ! grep -q '$HOME/bin' "$HOME/.bashrc" ; then
echo 'if [ -d "$HOME/bin" ] ; then PATH="$HOME/bin:$PATH" ; fi' >> "$HOME/.bashrc"
fi
# check if script needs to be installed into the ~/bin folder (copy if script found running from outside the bin folder)
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
if [[ ! "$DIR" =~ $HOME/bin ]] ; then
if [ ! -d "$HOME/bin" ] ; then mkdir "$HOME/bin" ; fi
ME=`basename "$0"`
cp "$DIR/$ME" "$HOME/bin/$SCRIPTNAME"
echo "Please logout and back in for effects to take place!"
echo "You may use the command $SCRIPTNAME -h for the help page"
exit 0
fi
#### .nodes cleanup ####
#check for .nodes file & remove old entries (lower is newer!)
if [ ! -f "$HOME/$serverconfig" ]; then #create new file
echo "File $HOME/$serverconfig not found... Creating new"
touch "$HOME/$serverconfig" && chmod 600 "$HOME/$serverconfig"
else #cleanup file
record=$(cat "$HOME/$serverconfig" | awk -F: -vOFS=':' '{array[$1]=$0} END{for(a in array) print array[a]}')
if ! [ -z "$record" ]; then echo "$record" > "$HOME/$serverconfig"; fi
echo "Removing duplicate records...done"
fi
if [ -z ${USER} ]; then USER=$(whoami); fi
############################ FLAG TESTING ############################
############################################################################
if [ "$1" == "-c" ] || [ "$1" == "--connect" ] ; then
if [ "$#" -eq 2 ] ; then
if [ -f "$HOME/.ssh/$2" ] && grep -q "$2" "$HOME/$serverconfig" ; then
IFS=':' read -r -a node <<< $(grep "$2" "$HOME/$serverconfig")
#MODIFY FOR SPECIAL SSH CONSOLE
ssh "${node[2]}@${node[1]}" -p "${node[3]}" -i "$HOME/.ssh/${node[0]}"
exit 0
else
echo "Node $2 not found"
exit 1
fi
else
echo "Incorrect number of parameters passed with the $1 flag, please check $SCRIPTNAME -h"
exit 1
fi
elif [ "$1" == "-l" ] || [ "$1" == "--list" ]; then
echo "Servers List"
printf "%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\n" "Node name" "IP Address" "Username" "SSH port" "Date Updated" "STATUS"
while IFS= read -r -u3 line; do
IFS=':' read -r -a node <<< "$line"
#check if server is online
if ssh "${node[2]}@${node[1]}" -p "${node[3]}" -i "$HOME/.ssh/${node[0]}" "echo ping" >&/dev/null ; then cStat="Online" ; else cStat="Offline" ; fi #check if the given host is online
printf "%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\n" "${node[0]}" "${node[1]}" "${node[2]}" "${node[3]}" "${node[4]}" "$cStat"
done 3< "$HOME/$serverconfig"
exit 0
elif [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
echo "$SCRIPTNAME help page:"
printf "%25s\t-\t%s\n" "-h --help" "list help commands(this page)"
printf "%25s\t-\t%s\n" "-l --list" "list saved servers from $serverconfig and check if they are online"
printf "%25s\t-\t%s\n" "-u --update" "update known servers, send my ip address to known hosts"
printf "%25s\t-\t%s\n" "-cp --copy [src] [dst]" "copy a file from/to a known host (SCP)"
printf "%25s\t-\t%s\n" "-c --connect [node]" "connect to a known host (SSH)"
printf "%25s\t-\t%s\n" "-a --add" "start the node addition helper, add node to \"subnet\""
printf "%25s\t-\t%s\n" "-i --introduce [node] [node]" "introduce two nodes to one another"
printf "%25s\t-\t%s\n" "-f --forget [node]" "forget given node, remove keys and records from both local and remote nodes"
printf "%25s\t-\t%s\n" "--force [node]" "forget given node, remove keys and records ONLY the local node"
exit 0
#### TODO: change mylastip to use non server source..
elif [ "$1" == "-a" ] || [ "$1" == "--add" ] ; then
mylastip="$(curl -s ifconfig.me)"
if [ "$#" -eq 4 ] ; then
echo "Welcome to the $SCRIPTNAME node addition helper"
#### CHECK FOR INPUT VALIDITY
if ! [[ "$2" =~ ^[a-zA-Z0-9]+$ ]] ; then echo "Incorrect Node Name format"; exit 1; fi
if ! [[ "$3" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]] ; then echo "Incorrect Ip Address format"; exit 1; fi
if ! [[ "$4" =~ ^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$ ]] ; then echo "Incorrect Port Number format"; exit 1; fi
if grep -q "$2" "$HOME/$serverconfig" && [ -f "$HOME/.ssh/$2" ] ; then echo "Node already known! quitting..."; exit 1; fi
#### Give my key
ssh-keygen -t rsa -N "" -f "$HOME/.ssh/$2"
echo ""
echo "COPY THIS SSH AUTH KEY INTO THE FIRST NODE NOW!!!"
mykey=$(awk '{printf $1; printf " "; printf $2; printf " "}' <<< $(cat "$HOME/.ssh/$2.pub") && printf '%s@%s\n' "$USER" "$servname") && rm "$HOME/.ssh/$2.pub"
echo ""; echo "$mykey"; echo ""
echo "My node details:"
echo " IP & Port: $mylastip $myport"
echo ""
#### input remote key
rkey=""
while ! [[ "$rkey" =~ ^[^\ ]+\ [^\ ]+\ [^\ ]+@[^\ ]+$ ]] ; do
read -p "Enter the SSH Auth Key provied:" rkey
done
ruser=$(cut -f1 -d '@' <<< $rkey <<< $(cut -f3 -d ' ' <<< $rkey))
#### add key and send ping
echo "$rkey" >> "$HOME/.ssh/authorized_keys"; rkey=""
echo "Please allow me to connect.."
while ! ssh "$ruser@$3" -p "$4" -i "$HOME/.ssh/$2" "(printf '$servname:'; echo \$SSH_CLIENT | awk '{ printf \$1}'; printf ':$USER:$myport:$(date +%x:%H:%M:%S)\n') >> \$HOME/$serverconfig" >&/dev/null ; do sleep 2 ; done
echo "Waiting for remote node to ping"
while ! grep -q "$2" "$HOME/$serverconfig" ; do sleep 0.5 ; done
echo "Entry has been recorded successfully"
exit 0
elif [ "$#" -eq 1 ] ; then # local node addition helper code
echo "Welcome to the $SCRIPTNAME node addition helper"
echo "To add a node to the subnet please make sure you have $SCRIPTNAME installed and ready to use..."
echo "Please run the following command on the second machine:"
echo " $SCRIPTNAME -a $servname $mylastip $myport"
#### input key
rkey=""
while ! [[ "$rkey" =~ ^[^\ ]+\ [^\ ]+\ [^\ ]+@[^\ ]+$ ]] ; do
read -p "Enter the provied SSH Auth Key:" rkey
done
ruser=$(cut -f1 -d '@' <<< $rkey <<< $(cut -f3 -d ' ' <<< $rkey))
rname=$(cut -f2 -d '@' <<< $rkey <<< $(cut -f3 -d ' ' <<< $rkey))
#### input ip and port
read -p "Enter the IP & Port (space seperated):" rip rport
if ! [[ "$rip" =~ ^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]] ; then echo "error: incorrect Ip Address format"; exit 1; fi
if ! [[ "$rport" =~ ^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$ ]] ; then echo "error: incorrect Port Number format"; exit 1; fi
ssh-keygen -t rsa -N "" -f "$HOME/.ssh/$rname"
echo "COPY THIS KEY INTO THE REMOTE NODE NOW!!!"
mykey=$(awk '{printf $1; printf " "; printf $2; printf " "}' <<< $(cat "$HOME/.ssh/$rname.pub") && printf '%s@%s\n' "$USER" "$servname") && rm "$HOME/.ssh/$rname.pub"
echo ""; echo "$mykey"; echo ""
#### add key and send ping
echo "$rkey" >> "$HOME/.ssh/authorized_keys"; rkey=""
echo "Waiting for remote node to ping"
while ! grep -q "$rname" "$HOME/$serverconfig" ; do sleep 0.5 ; done
echo "Please allow me to connect.."
while ! ssh "$ruser@$rip" -p "$rport" -i "$HOME/.ssh/$rname" "(printf '$servname:'; echo \$SSH_CLIENT | awk '{ printf \$1}'; printf ':$USER:$myport:$(date +%x:%H:%M:%S)\n') >> \$HOME/$serverconfig" >&/dev/null ; do sleep 2 ; done
echo "Entry has been recorded successfully"
exit 0
else
echo "Incorrect number of parameters passed with the $1 flag, please check $SCRIPTNAME -h"
exit 1
fi
elif [ "$1" == "-f" ] || [ "$1" == "--forget" ] || [ "$1" == "--force" ] ; then
if [ "$#" -eq 2 ] ; then
if [ "$1" == "--force" ] ; then # force forget a node.. remove local access keys and entries only, called on "remote" node when using -f
if grep -q "$2" "$HOME/$serverconfig" ; then
IFS=':' read -r -a node <<< $(grep "$2" "$HOME/$serverconfig")
sed -i "/^$2.*\$/d" "$HOME/$serverconfig"
rm "$HOME/.ssh/$2"
sed -i "/${node[2]}@${node[0]}/d" "$HOME/.ssh/authorized_keys"
echo "Removal of local entries...done"
exit 0
else
echo "Node $2 not found"
exit 1
fi
else
if [ -f "$HOME/.ssh/$2" ] && grep -q "$2" "$HOME/$serverconfig" ; then
read -p "Are you sure? (to continue type HostName: $2) " reply
if ! [[ "$reply" =~ ^$2$ ]] ; then echo "Reply did not match, quitting..."; exit 1; else
IFS=':' read -r -a node <<< $(grep "$2" "$HOME/$serverconfig")
printf '%s' "Removal of remote entries at node $2..."
if ssh "${node[2]}@${node[1]}" -p "${node[3]}" -i "$HOME/.ssh/${node[0]}" "\$HOME/bin/$SCRIPTNAME --force $servname" >&/dev/null ; then
echo "done"
sed -i "/^$2.*\$/d" "$HOME/$serverconfig"
rm "$HOME/.ssh/$2"
sed -i "/${node[2]}@${node[0]}/d" "$HOME/.ssh/authorized_keys"
echo "Removal of local entries...done"
exit 0
else
echo "fail..error removing records from remote node $2..quitting"
exit 1
fi
fi
else
echo "Node $2 not found"
exit 1
fi
fi
else
echo "Incorrect number of parameters passed with the $1 flag, please check $SCRIPTNAME -h"
exit 1
fi
elif [ "$1" == "-cp" ] || [ "$1" == "--copy" ]; then
if [ "$#" -eq 3 ]; then
if [[ "$2" =~ ^[a-zA-Z0-9]+:[^\0:]+$ ]] && [[ "$3" =~ ^[^\0:]+$ ]] ; then # syntax: from-remote to-local
rnode=$(cut -f1 -d: <<< "$2")
rpath=$(cut -f2 -d: <<< "$2")
if [ -f "$HOME/.ssh/$rnode" ] && grep -q "$rnode" "$HOME/$serverconfig" ; then
IFS=':' read -r -a node <<< $(grep "$rnode" "$HOME/$serverconfig")
printf "Retrieving file(s)..."
if ! scp -P "${node[3]}" -i "$HOME/.ssh/${node[0]}" "${node[2]}@${node[1]}:$rpath" "$3" >&/dev/null ; then echo "fail... scp failed to download" ; exit 1 ; fi
echo "done"
exit 0
else
echo "Node $rnode not found"
exit 1
fi
elif [[ "$2" =~ ^[^\0:]+$ ]] && [[ "$3" =~ ^[a-zA-Z0-9]+:[^\0:]+$ ]] ; then # syntax: from-local to-remote
rnode=$(cut -f1 -d: <<< "$3")
rpath=$(cut -f2 -d: <<< "$3")
if [ -f "$HOME/.ssh/$rnode" ] && grep -q "$rnode" "$HOME/$serverconfig" ; then
IFS=':' read -r -a node <<< $(grep "$rnode" "$HOME/$serverconfig")
printf "Sending file(s)..."
if ! scp -P "${node[3]}" -i "$HOME/.ssh/${node[0]}" "$2" "${node[2]}@${node[1]}:$rpath" >&/dev/null ; then echo "fail... scp failed to upload" ; exit 1 ; fi
echo "done"
exit 0
else
echo "Node $rnode not found..."
exit 1
fi
else
echo "The passed Source/Destination variable(s) are not formatted correctly. please check $SCRIPTNAME -h"
exit 1
fi
else
echo "Incorrect number of parameters passed with the $1 flag, $SCRIPTNAME -h"
exit 1
fi
#### when introducing the nodes instead create fresh entries into .nodes instead of taking local copies
elif [ "$1" == "-i" ] || [ "$1" == "--introduce" ]; then
if [ "$#" -eq 3 ]; then
if [ -f "$HOME/.ssh/$2" ] && grep -q "$2" "$HOME/$serverconfig" ; then
if [ -f "$HOME/.ssh/$3" ] && grep -q "$3" "$HOME/$serverconfig" ; then
n1=$(grep "$2" "$HOME/$serverconfig")
n2=$(grep "$3" "$HOME/$serverconfig")
IFS=':' read -r -a node1 <<< "$n1"
IFS=':' read -r -a node2 <<< "$n2"
if ssh "${node1[2]}@${node1[1]}" -p "${node1[3]}" -i "$HOME/.ssh/${node1[0]}" "echo ping" >&/dev/null ; then
if ssh "${node2[2]}@${node2[1]}" -p "${node2[3]}" -i "$HOME/.ssh/${node2[0]}" "echo ping" >&/dev/null ; then
printf "Generating keys at nodes..."
n2keytmp=$(ssh ${node1[2]}@${node1[1]} -p ${node1[3]} -i $HOME/.ssh/${node1[0]} "ssh-keygen -t rsa -N '' -f \$HOME/.ssh/${node2[0]} >&/dev/null && cat \$HOME/.ssh/${node2[0]}.pub && rm \$HOME/.ssh/${node2[0]}.pub")
n2key=$(awk '{printf $1; printf " "; printf $2; printf " "}' <<< $n2keytmp && printf '%s@%s\n' "${node1[2]}" "${node1[0]}")
n1keytmp=$(ssh ${node2[2]}@${node2[1]} -p ${node2[3]} -i $HOME/.ssh/${node2[0]} "echo '$n2key' >> \$HOME/.ssh/authorized_keys; ssh-keygen -t rsa -N '' -f \$HOME/.ssh/${node1[0]} >&/dev/null && cat \$HOME/.ssh/${node1[0]}.pub && rm \$HOME/.ssh/${node1[0]}.pub")
n1key=$(awk '{printf $1; printf " "; printf $2; printf " "}' <<< $n1keytmp && printf '%s@%s\n' "${node2[2]}" "${node2[0]}")
echo "done"
echo "Introducing Node $2 to $3..."
ssh -t "${node1[2]}@${node1[1]}" -p "${node1[3]}" -i "$HOME/.ssh/${node1[0]}" "echo '$n1key' >> \$HOME/.ssh/authorized_keys; ssh ${node2[2]}@${node2[1]} -p ${node2[3]} -i \$HOME/.ssh/${node2[0]} 'echo $n1 >> ~/$serverconfig'"
ssh -t "${node2[2]}@${node2[1]}" -p "${node2[3]}" -i "$HOME/.ssh/${node2[0]}" "ssh ${node1[2]}@${node1[1]} -p ${node1[3]} -i \$HOME/.ssh/${node1[0]} 'echo $n2 >> ~/$serverconfig'"
echo "Nodes $2 and $3 are acquainted"
exit 0
else
echo "Node ${node2[0]} seems to be offline"
exit 1
fi
else
echo "Node ${node1[0]} seems to be offline"
exit 1
fi
else
echo "Node $3 not found"
exit 1
fi
else
echo "Node $2 not found"
exit 1
fi
else
echo "Incorrect number of parameters passed with the $1 flag, please check $SCRIPTNAME -h"
exit 1
fi
elif [ "$1" == "-u" ] || [ "$1" == "--update" ] || [ $# = 0 ]; then
while IFS= read -r -u3 line; do
IFS=':' read -r -a node <<< "$line"
if [ "$repeat" = true ] ; then
printf "Repeating known hosts to ${node[0]}..."
clienthostsfile="$HOME/.ssh/.${node[0]}" #save the retrived .nodes file from "remote" as .ssh/"node-name"
if ! scp -P "${node[3]}" -i "$HOME/.ssh/${node[0]}" "${node[2]}@${node[1]}:~/$serverconfig $clienthostsfile" >&/dev/null ; then echo "fail... client does not have $serverconfig file correctly setup" ; else
for host in $HOME/.ssh/* ; do #for each known host in .ssh check if client has host details
if ! [ "$host" == "${node[0]}" ] && grep -q "$host" "$HOME/$serverconfig" && ! grep -q "$host" "$clienthostsfile" ; then #if the given key is not from client and the file is detailed in .nodes file and is not in the clients .nodes file
if ! [ -f "$HOME/$serverconfig.ignore" ] || ! grep -q "$host" "$HOME/$serverconfig.ignore"; then
bash "$HOME/bin/$SCRIPTNAME" -i "$host" "${node[0]}" >&/dev/null
fi
fi
done
rm "$clienthostsfile"
echo "done"
fi
fi
printf "Sending my details to: ${node[2]}@${node[0]} on port ${node[3]}..."
if ! ssh "${node[2]}@${node[1]}" -p "${node[3]}" -i "$HOME/.ssh/${node[0]}" "(printf '$servname:'; echo \$SSH_CLIENT | awk '{ printf \$1}'; printf ':$USER:$myport:$(date +%x:%H:%M:%S)\n') >> \$HOME/$serverconfig" >&/dev/null ; then #send new copy of my ip address to the client
echo "fail... Skipping"
else
echo "done"
fi
done 3< "$HOME/$serverconfig"
exit 0
else
echo "Unknown flag $1 please use $SCRIPTNAME -h for more information"
exit 1
fi