forked from freifunk/icvpn-topo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
freifunk-topo-icvpn.sh
executable file
·463 lines (381 loc) · 13.8 KB
/
freifunk-topo-icvpn.sh
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
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
#!/bin/bash
#version 3
#date 24.06.2014
# creates tinc topologies
# bgpd.conf muss die gleichen namen verwenden wie tinc, da sonst die zuordung nicht funktioniert
# um nur die png generierung zu testen, einfach ein beliebiges argument
# beim aufruf angeben
# freifunk-topo-icvpn.sh blabla
#
u=$(id | sed 's#[^(]*(\([^)]*\)).*#\1#')
test "$u" != "freifunk" && echo "Als User freifunk starten" && exit
# own bgp values
export ICVPN_HOST_IP="10.207.0.19"
export ICVPN_HOST_NAME="dresden1"
export ICVPN_HOST_AS="65051"
# define the host name that is used to create links. Links in this script are created
# as http://<citiy-ip>.$PROXY_HOST/
# If the local webserver is configured as proxy, user may access the info page of the internal icvpn servers.
export PROXY_HOST="freifunk-dresden.de"
# set number of entries of IP ranges shown in each box
export NET_BOX_ENTRIES=10
# path to bgpd config file. this is used to extract some values
# and find the relation to tinc clients
export BGPD_CONF=/etc/quagga/bgpd.conf
# dot file generated by tinc
IN_DOT_FILE=/var/lib/freifunk/dot/tinc-icvpn.dot
# dot file generated by this script
OUT_DOT_FILE=/var/lib/freifunk/output/icvpn.dot
# output directory for generated image and image map
OUT_DIR=/var/www_info/info
OUT_FILE=$OUT_DIR/topo-icvpn.png
OUT_FILE_MAP=$OUT_DIR/topo-icvpn.map
# temp directory for storing collected data
TMP_DIR=/tmp/topo-icvpn
TMP_DIR_ICVPN_PING=$TMP_DIR/icvpn-ping
TMP_DIR_INFO_PAGE=$TMP_DIR/info-page
SIZE_ICVPN=8,8
BGCOLOR=white
FILLCOLOR=#ffcb05
BORDERCOLOR=#dc0067
# this defines the color to reflect current state.
# legend of coloured circles:
# color | icvpn connection ok | bgp server reachable | info page present | network behind bpg server reachable
# -------------------------+-----------------------+----------------------+-------------------+-----------------------------------
# COLOR_NETWORK_REACHABLE | yes | yes | yes | yes
# COLOR_INFOPAGE_PRESENT | yes | yes | yes | no or invalid
# COLOR_ACTIVE | yes | yes | no | no
# COLOR_INACTIVE | yes | no | no | no
# COLOR_UNKOWN | no | no | no | no
export COLOR_UNKOWN=grey
export COLOR_INACTIVE=#dc0067
export COLOR_ACTIVE=#ffdc67
export COLOR_INFOPAGE_PRESENT=#ccdcff
export COLOR_NETWORK_REACHABLE=#00dc67
export COLOR_NETWORK_UNREACHABLE=#ff0000
export COLOR_INFOPAGE_NOTPRESENT=#ffffff
export COLOR_INFOPAGE_OK=#00dc67
export COLOR_INFOPAGE_ERROR=#ff0000
# delete previous files in case that infopage is not reachable
rm -r $TMP_DIR
mkdir -p $OUT_DIR
mkdir -p $TMP_DIR
mkdir -p $TMP_DIR_ICVPN_PING
mkdir -p $TMP_DIR_INFO_PAGE
str_swap () {
while read left separator right other
do
if [ "$left" \< "$right" ]; then
#swap nodes
echo $right $separator $left $other
else
#no change of order
echo $left $separator $right $other
fi
done
}
if [ -z "$1" ]; then
################ get city names and IP ########################
echo "get city names/ip"
IFS='
'
i=0
for x in $(cat $BGPD_CONF | sed -n '/^[ ]*neighbor[ ]\+[0-9.]\+[ ]\+description/p')
do
# echo "$i [$x]"
IFS=' '
set $x
# echo "$i [$1-$2-$3-$4-$5-$6]"
db_name[$i]=$(echo $4 | tr "[:upper:]" "[:lower:]")
db_ip[$i]=$2
echo " -> ${db_ip[$i]} -> ${db_name[$i]}"
i=$((i+1))
done
unset IFS
# add own icvpn data, because those are not in bgpd.conf
db_name[$i]="$ICVPN_HOST_NAME"
db_ip[$i]="$ICVPN_HOST_IP"
db_as[$i]="$ICVPN_HOST_AS"
i=$((i+1))
#remember entries
db_entries=$i
#echo "${#db_name[*]}:${db_name[*]}"
#echo "${#db_ip[*]}:${db_ip[*]}"
################ get AS-Numbers ########################
echo "get AS Numbers"
#die reihenfolge der AS nummern ist gleich den citiy namen (description und ips) die
#zuvor ermittelt worden sind. somit brauche ich nicht durch alle IPs iterieren und
#das bgpd.conf jedes mal durchsuchen
IFS='
'
i=0
for x in $(cat $BGPD_CONF | sed -n '/^[ ]*neighbor[ ]\+[0-9.]\+[ ]\+remote-as/p')
do
# echo "$i [$x]"
IFS=' '
set $x
# echo "$i [$1-$2-$3-$4-$5-$6]"
db_as[$i]=$4
echo " -> ${db_ip[$i]} -> ${db_as[$i]}"
i=$((i+1))
done
unset IFS
echo "${#db_as[*]}:${db_as[*]}"
######### debug print ####
function print_db()
{
for((idx=0;idx<$db_entries;idx++))
do
echo "[$idx]: name=[${db_name[$idx]}]; ip=[${db_ip[$idx]}]; as=[${db_as[$idx]}]"
done
}
print_db
############ get icvpn ping info ############################
echo "ping icvpn servers"
# I have two possiblities: 1. fping each ip and write it to a file
# 2. fping can request all ips in parallel.
# I use way 2. fping all ip and create a command for each answer that is run after to store ping result
IFS='
'
for i in $(fping -t 200 ${db_ip[*]} 2>/dev/null | sed "s#\(.*\) is \(.*\)#echo \2 > $TMP_DIR_ICVPN_PING/\1#")
do
eval $i
done
IFS=' '
# build array from temp files
i=0
for ip in ${db_ip[*]}
do
db_icvpn_ping[$i]=$(cat $TMP_DIR_ICVPN_PING/$ip)
echo " -> $ip -> ${db_icvpn_ping[$i]}"
i=$((i+1))
done
############ get info pages from clients ############################
echo "get info pages:"
i=0
for ip in ${db_ip[*]}
do
echo -n " -> $ip"
#get page and remove shell-characters;
#NOTE: do not add "/" after infopage. some webserver use "infopage" as filename instead dir name
wget --tries=2 --timeout=2 -O - http://$ip/infopage 2>/dev/null | dd bs=1024 count=10 2>/dev/null | sed '
s#[$)(*`\]#.#g '>$TMP_DIR_INFO_PAGE/$ip
if [ $(ls -s $TMP_DIR_INFO_PAGE/$ip|cut -d' ' -f1) = 0 ]
then
db_infopage[$i]=""
else
db_infopage[$i]="$ip"
fi
echo " -> ${db_infopage[$i]}"
i=$((i+1))
done
############ ping networks behind the icvpn server ############################
echo "ping networks:"
i=0
IFS=' '
for ip in ${db_ip[*]}
do
netip=$(cat $TMP_DIR_INFO_PAGE/$ip | sed -n '/^[ ]*ping_ip[ ]*=[ ]*[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+/{s#^[ ]*ping_ip[ ]*=[ ]*\([0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+\).*#\1#;p}')
echo -n " ping net: -> $ip: [$netip]"
s=""
if [ -n "$netip" ]; then
IFS='
'
#a portal may offer more than one ping ip
for nip in $netip
do
#echo -n "xxx:$nip"
s=$(ping -c2 $nip 2>/dev/null >/dev/null && echo "alive" )
# one ip could be pinged. no need to ping all other for one city
[ -n "$s" ] && break;
done
if [ -n "$s" ]
then
db_netping[$i]=$s
else
db_netping[$i]=""
fi
#netip seems to be a list of ip. so use last ip
db_netping_ip[$i]=$nip
fi
echo " -> ${db_netping[$i]}"
i=$((i+1))
done
############ get public portal url ############################
echo "get public portal url:"
i=0
for ip in ${db_ip[*]}
do
url=$(cat $TMP_DIR_INFO_PAGE/$ip | sed -n '/^[ ]*public_portal_url[ ]*=[ ]*.*/{s#^[ ]*public_portal_url[ ]*=[ ]*\([^ ]*\).*$#\1#;p}')
db_puburl[$i]=$url
url=$(cat $TMP_DIR_INFO_PAGE/$ip | sed -n '/^[ ]*portal_ip[ ]*=[ ]*.*/{s#^[ ]*portal_ip[ ]*=[ ]*\([^ ]*\).*$#\1#;p}')
db_portal_ip[$i]=$url
#try to get port ip
port=$(cat $TMP_DIR_INFO_PAGE/$ip | sed -n '/^[ ]*topo_dot_port[ ]*=[ "]*.*/{s#^[ ]*topo_dot_port[ ]*=[" ]*\([^ "]*\).*$#\1#;p}' | tr "[:upper:]" "[:lower:]")
#if not set, use portal ip. not ping ip, because some cities have no node in dot file,only a network mask that covers this ip
[ -z "$port" ] && [ -n "${db_netping_ip[$i]}" ] && port="$(ping -Rc1 "${db_netping_ip[$i]}" | sed -n '/^RR/,${/10\.207\./d;s#[ ]*##g;p;q}')"
[ -z "$port" ] && port="${db_portal_ip[$i]}"
#if still not set use my own name
[ -z "$port" ] && port="network_${db_name[$i]}"
db_topo_port[$i]="$port"
echo " -> $ip: [${db_name[$i]}], url:[${db_puburl[$i]}],portal_ip:[${db_portal_ip[$i]}],ping_ip:[${db_netping_ip[$i]}],topo_port: [${db_topo_port[$i]}]"
i=$((i+1))
done
#-------------------------------------------
export db_name
export db_ip
export db_as
export db_icvpn_server_present
export db_icvpn_ping
export db_netping
export db_netping_ip
export db_puburl
export db_infopage
export db_portal_ip
export db_topo_port
export db_entries
################ modify dot file created by tinc #############################
>$OUT_DOT_FILE
#ranksep: knotenabstand icvpn:networkbox:citymainknoten:weiter entferne knoten
#echo "digraph { layout=\"twopi\"; nodesep=0; ranksep=\"4:1.8:3\"; root=\"icvpn\"" >>$OUT_DOT_FILE
echo "digraph { nodesep=0; ranksep=\"4:1.8:3\"; root=\"icvpn\"" >>$OUT_DOT_FILE
echo "\"icvpn\" [label=\"icvpn\", tooltip=\"icvpn\", URL=\"http://wiki.freifunk.net/IC-VPN\"];" >> $OUT_DOT_FILE
# indotfile nach den lables durchsuchen und daraus die neuen labesl baun mit farbe
IFS='
'
for node in $(cat $IN_DOT_FILE | sed -n '/".*"/{s#^[ ]*\([^ ]*\).*#\1#;p}' | tr "[:upper:]" "[:lower:]")
do
#echo "check:[$node]"
#get index
tmp=""
for((idx=0;idx<$db_entries;idx++))
do
#echo " - idx=$idx:[${db_name[$idx]}]"
tmp=$(echo ${db_name[$idx]} | tr "[:upper:]" "[:lower:]")
if [ "$tmp" = "$node" ]; then break; fi
done
echo "process: [$idx/$db_entries]: check node:$node; db[as=${db_as[$idx]}; ip=${db_ip[$idx]}; name:${db_name[$idx]}]; tmp=$tmp"
#node found in bgp?
if [ $idx -eq $db_entries ]; then
color=$COLOR_UNKOWN
else
color=$COLOR_INACTIVE
#remember that this server is present
db_icvpn_server_present[$idx]="ok"
#icvpn server pingable
[ "${db_icvpn_ping[$idx]}" = "alive" ] && color=$COLOR_ACTIVE
#infopage present
[ -n "${db_infopage[$idx]}" ] && color=$COLOR_INFOPAGE_PRESENT
#network pingable
[ "${db_netping[$idx]}" = "alive" ] && color=$COLOR_NETWORK_REACHABLE
#add network ip box
IFS=' '
#echo "test: ${db_ip[$idx]} = $ICVPN_HOST_IP"
if [ "${db_ip[$idx]}" = "$ICVPN_HOST_IP" ]; then
n="10.200.0.0/15"
else
n=$(ip route list table zebra | grep -w ${db_ip[$idx]} | cut -d' ' -f1)
fi
echo "-> network=[$n]"
count=$(echo $n | wc -l)
#echo "count=$count"
n_box=$n
n_tip=$n
#restrict number of networks displayed in box to $NET_BOX_ENTRIES
#add "..." if there are more than $NET_BOX_ENTRIES
if [ $count -gt $NET_BOX_ENTRIES ]; then
n_box=$(echo $n_box | head -n $NET_BOX_ENTRIES)" ..."
fi
#echo n2=[$n]
IFS='
'
#net_box=$(echo $n_box | sed 's# #\\n#g')
net_box=$(echo $n_box | sed 's# #<br />#g')
net_tooltip=$(echo $n_tip | sed 's# #, #g')
#echo net_box=[$net_box]
#echo net_tooltip=[$net_tooltip]
#sleep 10
portal_ip=${db_portal_ip[$idx]}
netping_ip=${db_netping_ip[$idx]}
infopage_ip=${db_infopage[$idx]:-no-infopage-found}
if [ -n "$net_box" ]; then
#network pingable
net_portal_bgcolor=$COLOR_INFOPAGE_NOTPRESENT; [ -n "${db_infopage[$idx]}" ] && net_portal_bgcolor=$COLOR_INFOPAGE_PRESENT
net_bgcolor=$COLOR_NETWORK_UNREACHABLE; [ "${db_netping[$idx]}" = "alive" ] && net_bgcolor=$COLOR_NETWORK_REACHABLE
net_portalip_bgcolor=$COLOR_INFOPAGE_OK; [ -z "$(echo $portal_ip | sed -n '/^[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+$/p')" ] && net_portalip_bgcolor=$COLOR_INFOPAGE_ERROR
label="<<table border=\"0\" cellborder=\"1\">
<tr><td bgcolor=\"$net_portal_bgcolor\" href=\"http://$infopage_ip.$PROXY_HOST/\" tooltip=\"http://$infopage_ip.$PROXY_HOST/\">Infopage</td></tr>
<tr><td bgcolor=\"$net_portalip_bgcolor\" href=\"http://$portal_ip/\" tooltip=\"Netzinternes Portal\">Portal: $portal_ip</td></tr>
<tr><td bgcolor=\"$net_bgcolor\" href=\"http://$netping_ip/\" tooltip=\"Ping IP:$netping_ip\">Ping: $netping_ip</td></tr>
<tr><td bgcolor=\"$net_portal_bgcolor\" href=\"http://$infopage_ip.$PROXY_HOST/\" tooltip=\"http://$infopage_ip.$PROXY_HOST/\">Networks ($count)</td></tr>
</table>>"
#add prefix: icvpn_ to avoid conflics if a city uses the same ids or adds the icvpn.dot as its own dot-file
echo "\"icvpn_$node""_box\" [ label=$label, fillcolor=\"$net_portal_bgcolor\", shape=box, color=\"black\", tooltip=\"$net_tooltip\" , URL=\"http://$infopage_ip.$PROXY_HOST/\"];" >> $OUT_DOT_FILE
echo "\"icvpn_$node\" -> \"icvpn_$node""_box\" [arrowhead=none];" >> $OUT_DOT_FILE
fi
fi
#check for url
url=${db_puburl[$idx]}
#echo "[$node] idx=$idx color=$color url=[$url]"
if [ "$url" = "" ]; then
city=$(echo $node | sed 's#[0-9]##')
url="http://$city.freifunk.net/"
fi
label="$node\n${db_ip[$idx]}\nAS${db_as[$idx]}"
label2="$node - ${db_ip[$idx]} - AS${db_as[$idx]}"
echo "\"icvpn_$node\" [label=\"$label\", tooltip=\"$label2\", color=\"$color\", fillcolor=\"$color\", URL=\"$url\"];" >> $OUT_DOT_FILE
#add connection to dummy node that belongs to the center
echo "\"icvpn_$node\" -> \"icvpn\" [arrowhead=none, color=blue]" >> $OUT_DOT_FILE
done
#- dann den rest vom dot file kombinieren ohne die alten labels:
#cat $IN_DOT_FILE | sed ' /".*"/d; /digraph/d; /}/d; s#\([^ -<>;]\+\)#icvpn_\1#g ' | tr "[:upper:]" "[:lower:]" >> $OUT_DOT_FILE
cat $IN_DOT_FILE | sed ' /".*"/d; /digraph/d; /}/d; s#^[ ]*\([^-<>; ]\+\)\([ -<>;]\+\)\([^-<>; ]\+\)[ ;]*#icvpn_\1 -> icvpn_\3;# ' | tr "[:upper:]" "[:lower:]" >> $OUT_DOT_FILE
#add closing and layout specific to icvpn.dot
echo "layout=\"twopi\"" >> $OUT_DOT_FILE
echo "}" >> $OUT_DOT_FILE
if false; then
echo x | sed '
s#"a#"A#
s#"b#"B#
s#"c#"C#
s#"d#"D#
s#"e#"E#
s#"f#"F#
s#"g#"G#
s#"h#"H#
s#"i#"I#
s#"j#"J#
s#"k#"K#
s#"l#"L#
s#"m#"M#
s#"n#"N#
s#"o#"O#
s#"p#"P#
s#"q#"Q#
s#"r#"R#
s#"s#"S#
s#"t#"T#
s#"u#"U#
s#"v#"V#
s#"w#"W#
s#"x#"X#
s#"y#"Y#
s#"z#"Z#
s#"\([a-zA-Z_]*\)\(.*\)#"\1 \2#
' > $OUT_DOT_FILE
fi
################ create png #################################
#fi: used for debugging
fi
unset IFS
#lines
Efont="-Efontname=misc -Efontsize=10 -Efontcolor=grey"
E="$Efont -Ecolor=grey -Elen=4 -Earrowsize=0"
#knoten
Nfont="-Nfontname=misc -Nfontsize=10 -Nfontcolor=black"
N="$Nfont -Nstyle=filled -Ncolor=$BORDERCOLOR -Nfillcolor=white"
##graph
Gfont="-Gfontname=misc -Gfontsize=10 -Gfontcolor=black"
G="$Gfont -Gsize=$SIZE_ICVPN -Gbgcolor=$BGCOLOR -Gsplines=true"
echo "generate icvpn image/map"
dot -Tpng -o $OUT_FILE -Tcmap -o $OUT_FILE_MAP $G $N $E $OUT_DOT_FILE