summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rwxr-xr-xnetwork-topology-scanner197
2 files changed, 198 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d3127d7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+network.png
diff --git a/network-topology-scanner b/network-topology-scanner
new file mode 100755
index 0000000..8db3315
--- /dev/null
+++ b/network-topology-scanner
@@ -0,0 +1,197 @@
+#!/bin/bash
+
+hosts=(
+ 'router 192.168.0.13'
+ 'rpi3 192.168.1.3'
+)
+
+tmp_dir=$(mktemp -d)
+trap 'rm -rf --one-file-system "${tmp_dir:?}"' EXIT
+
+for host in "${hosts[@]}"; do
+ name="${host% *}"
+ addr="${host##* }"
+ printf '"%s" [fontcolor="#800000"];\n' "${name}" >> "${tmp_dir}/print-content"
+ ssh "${addr}" ip -o addr | \
+ sed -n '
+ s/\s*\\.*$//
+ s/\s\+/ /g
+ / scope link/d
+ s/^[0-9]\+: //
+ /^lo /d
+ h
+ s/^\(\S\+\) .*$/'"${name}"' \1/
+ w '"${tmp_dir}"'/interfaces
+ s/^\(.\+\) \(\S\+\)$/"\0" [label = "\2", fontcolor="#00ff00"];/
+ w '"${tmp_dir}/print-content"'
+ g
+ s/^\(\S\+\) .*$/"'"${name}"'" -> "'"${name}"' \1";/
+ w '"${tmp_dir}/print-content"'
+ g
+ s/^\(\S\+\) \S\+ \(\S\+\) .*$/"'"${name}"' \1" -> "\2";/
+ w '"${tmp_dir}/print-content"'
+ g
+ s/^\S\+ \(\S\+\) \(\S\+\) .*$/\1 \2/
+ w '"${tmp_dir}"'/ips
+ '
+ for file in ips interfaces print-content; do
+ cat "${tmp_dir}/${file}" >> "${tmp_dir}/all-${file}"
+ done
+ ssh "${addr}" 'sudo iptables-save | sed "s/^/4 /"; sudo ip6tables-save | sed "s/^/6 /"' 2>/dev/null | \
+ sed '
+ s/^/'"${name}"' /
+ ' >> \
+ "${tmp_dir}/iptables"
+done
+
+while read -r version address; do
+ case ${version} in
+ inet)
+ printf '"%s" [fontcolor="#000080"];\n' "${address}" >> "${tmp_dir}/adress-types"
+ ;;
+ inet6)
+ printf '"%s" [fontcolor="#0000ff"];\n' "${address}" >> "${tmp_dir}/adress-types"
+ ;;
+ esac
+ subnet_mask=${address##*/}
+ if [ -z "${subnet_mask}" ] || [ "${subnet_mask}" = "${address}" ]; then
+ continue;
+ fi
+ case ${version} in
+ inet)
+ printf '"%s" [fontcolor="#000080"];\n' "${address}" >> "${tmp_dir}/adress-types"
+ if [ "${subnet_mask}" = 32 ]; then
+ continue
+ fi
+ base_address=$(
+ sipcalc "${address}" | \
+ sed '
+ s/^Network\s\+address\s\+-\s\+\(\S\+\)\s*$/\1/
+ t
+ d
+ '
+ )
+ ;;
+ inet6)
+ if [ "${subnet_mask}" = 128 ]; then
+ continue
+ fi
+ base_address=$(
+ sipcalc "${address}" | \
+ sed -n '
+ s/^Subnet\s\+prefix\s\+(masked)\s\+-\s\+\(\S\+\)\s*$/\1/
+ T
+ s,0\(:0\)*/,:/,
+ p
+ '
+ )
+ ;;
+ *)
+ continue
+ ;;
+ esac
+ printf '%s %s\n' \
+ "${address}" \
+ "${base_address}"
+done \
+ < "${tmp_dir}/all-ips" \
+ | sort -u \
+ | sort -k2,2 -k1,1 \
+ | uniq -Df1 \
+ | sed '
+ s/^\(\S\+\) \(\S\+\)$/"\1" -> "\2";\n/
+ ' \
+ | tee -a "${tmp_dir}/all-print-content" \
+ | sed -n '
+ s/^".*" -> "\(\S\+\)";$/\1/
+ T
+ /:/ {
+ s/.*/"\0" [fontcolor="#a0a000"];/
+ p
+ }
+ /\./ {
+ s/.*/"\0" [fontcolor="#808000"];/
+ p
+ }
+ ' \
+ >> "${tmp_dir}/adress-types"
+
+cat "${tmp_dir}/adress-types" >> "${tmp_dir}/all-print-content"
+
+grep '\S\+ [46] :FORWARD ACCEPT ' "${tmp_dir}/iptables" | \
+ while read -r host ipver _; do
+ grep "^${host} " "${tmp_dir}/all-interfaces"
+ done | \
+ sort -u > \
+ "${tmp_dir}/ifs-routed"
+join -j1 "${tmp_dir}/ifs-routed" "${tmp_dir}/ifs-routed" \
+ | grep -v ' \(\S\+\) \1$' \
+ | sed '
+ s/^\(\S\+\)\( .*\)$/\1 4\2\n\1 6\2/
+ ' \
+ > "${tmp_dir}/routes"
+
+grep -vwF "$(
+ grep -vwF -- '-m conntrack' "${tmp_dir}/iptables" | \
+ grep -v '^\S\+ 4 .*/32 ' | \
+ grep -v '^\S\+ 6 .*/128 ' | \
+ sed -n '
+ s/^\(\S\+\) \([46]\) \(.* \)\?-A FORWARD \(.* \)\?-i \(\S\+\) \(.* \)\?-j DROP/\1 \2 \5/
+ T
+ p
+ '
+)" "${tmp_dir}/routes" \
+ > "${tmp_dir}/routes.new"
+mv "${tmp_dir}/routes.new" "${tmp_dir}/routes"
+
+grep -vwF -- '-m conntrack' "${tmp_dir}/iptables" | \
+ grep -v '^\S\+ 4 .*/32 ' | \
+ grep -v '^\S\+ 6 .*/128 ' | \
+ sed '
+ s/^\(\S\+\) \([46]\) \(.* \)\?-A FORWARD \(.* \)\?-i \(\S\+\) \(.* \)\?-o \(\S\+\) \(.* \)\?-j ACCEPT/\1 \2 \5 \7/
+ t
+ s/^\(\S\+\) \([46]\) \(.* \)\?-A FORWARD \(.* \)\?-o \(\S\+\) \(.* \)\?-i \(\S\+\) \(.* \)\?-j ACCEPT/\1 \2 \7 \5/
+ t
+ d
+ ' \
+ >> "${tmp_dir}/routes"
+
+sed '
+ s/^\(\S\+ \S\+\) \(\S\+\) \(\S\+\)$/f \1 \2 \3\nr \1 \3 \2/
+' "${tmp_dir}/routes" \
+ | sort -k2,5 -k1,1 \
+ > "${tmp_dir}/routes.new"
+
+uniq -uf1 "${tmp_dir}/routes.new" | tee /dev/stderr \
+ | grep '^f ' \
+ > "${tmp_dir}/routes"
+
+# todo : remove duplicates
+
+uniq -df1 "${tmp_dir}/routes.new" \
+ | sed 's/^[fr] /b /' \
+ >> "${tmp_dir}/routes"
+rm "${tmp_dir}/routes.new"
+
+sed '
+ s/^f \(\S\+\) 4 \(\S\+\) \(\S\+\)$/"\1 \2" -> "\1 \3" [weight=0, color="#808080"];\n/
+ t
+ s/^f \(\S\+\) 6 \(\S\+\) \(\S\+\)$/"\1 \2" -> "\1 \3" [weight=0, color="#000000"];\n/
+ t
+ s/^b \(\S\+\) 4 \(\S\+\) \(\S\+\)$/"\1 \2" -> "\1 \3" [dir=both, weight=0, color="#808080"];\n/
+ t
+ s/^b \(\S\+\) 6 \(\S\+\) \(\S\+\)$/"\1 \2" -> "\1 \3" [dir=both, weight=0, color="#000000"];\n/
+ t
+ d
+' "${tmp_dir}/routes" \
+ >> "${tmp_dir}/all-print-content"
+
+sort -u "${tmp_dir}/all-print-content" | cat -n
+
+{
+ echo 'digraph network {'
+ echo 'rankdir=LR;'
+ sort -u "${tmp_dir}/all-print-content"
+ echo '}'
+} | \
+ dot -Tpng -onetwork.png