#!/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 if [ -f "infos" ]; then cp "infos" "${tmp_dir}/infos" else for host in "${hosts[@]}"; do name="${host% *}" addr="${host##* }" ssh "${addr}" ' ip -o addr | sed "s/^/ip /" sudo iptables-save | sed "s/^/ip4tables /" sudo ip6tables-save | sed "s/^/ip6tables /" sed "s/^[^#]/tayga \0/;t;d" /etc/tayga.conf ' 2>/dev/null \ | sed ' s/^\S\+ /\0'"${name}"' / ' \ >> "${tmp_dir}/infos" done fi cp "${tmp_dir}/infos" "infos" sed ' s/^ip // t ip s/^ip\([64]\)tables /\1 / t iptables s/^tayga // t tayga s/^/>> unknown: >>/ w /dev/stderr d :iptables w '"${tmp_dir}"'/iptables d :ip s/\s*\\.*$// s/\s\+/ /g / scope link/d s/^\(\S\+ \)[0-9]\+: /\1/ /^\S\+ lo /d h s/^\(\S\+ \S\+\) .*$/\1/ w '"${tmp_dir}"'/interfaces s/^\(\S\+\) \(\S\+\)$/"\0" [label = "\2", fontcolor="#00ff00"];/ w '"${tmp_dir}/print-content"' g s/^\(\S\+\)\( \S\+\) .*$/"\1" -> "\1\2";/ w '"${tmp_dir}/print-content"' g s/^\(\S\+ \S\+\) \S\+ \(\S\+\) .*$/"\1" -> "\2";/ w '"${tmp_dir}/print-content"' g s/^\S\+ \S\+ \(\S\+\) \(\S\+\) .*$/\1 \2/ w '"${tmp_dir}"'/ips d :tayga w '"${tmp_dir}"'/tayga d ' "${tmp_dir}/infos" printf '%s\n' "${hosts[@]}" \ | sed ' s/^\(.*\) \S\+$/"\1" [fontcolor="#800000"];/ ' \ >> "${tmp_dir}/print-content" sort "${tmp_dir}/tayga" | sed ' :a N s/^\(\S\+ \)\(.*\S\)\s*\n\1\([^\n]*\S\)\s*$/\1\2\\\3/ ta P D ' | tee /dev/stderr \ | sed ' h s/^\(\S\+ \)\(.*\\\)\?dynamic-pool \([^\\[:space:]]\+\)\\\(.*\\\)\?prefix \([^\\[:space:]]\+\)\(\\.*\)\?$/"\3" -> "\5" [dir=both, weight=0, color="#0000ff"];/ w '"${tmp_dir}/tayga-print-content"' g s/^\(\S\+\) \(.*\\\)\?dynamic-pool \([^\\[:space:]]\+\)\\\(.*\\\)\?tun-device \([^\\[:space:]]\+\)\(\\.*\)\?$/"\1 \5" -> "\3" [color="#808080"];/ w '"${tmp_dir}/tayga-print-content"' g s/^\(\S\+\) \(.*\\\)\?prefix \([^\\[:space:]]\+\)\\\(.*\\\)\?tun-device \([^\\[:space:]]\+\)\(\\.*\)\?$/"\1 \5" -> "\3" [color="#000000"];/ w '"${tmp_dir}/tayga-print-content"' g s/^\S\+ \(.*\\\)\?prefix \([^\\[:space:]]\+\)\(\\.*\)\?$/"\2" [fontcolor="#a0a000"];/ w '"${tmp_dir}/tayga-print-content"' g s/^\S\+ \(.*\\\)\?dynamic-pool \([^\\[:space:]]\+\)\(\\.*\)\?$/"\2" [fontcolor="#808000"];/ w '"${tmp_dir}/tayga-print-content"' g p d ' for name in ips print-content; do cat "${tmp_dir}/tayga-${name}" >> "${tmp_dir}/${name}" rm "${tmp_dir}/tayga-${name}" done while read -r version address; do case ${version} in inet) printf '"%s" [fontcolor="#000080"];\n' "${address}" >> "${tmp_dir}/print-content" ;; inet6) printf '"%s" [fontcolor="#0000ff"];\n' "${address}" >> "${tmp_dir}/print-content" ;; 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}/print-content" if [ "${subnet_mask}" = 32 ]; then continue fi base_address=$( sipcalc "${address}" | \ sed ' s/^Network address\s\+- \+\(\S\+\)\s*$/\1/ t s/^Network mask (bits)\s\+- \+\([0-9]\+\)\s*$/\1/ t d ' | \ sed ' N s,\n,/, ' ) ;; 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}/ips" \ | sort -u \ | sort -k2,2 -k1,1 \ | uniq -Df1 \ | sed ' s/^\(\S\+\) \(\S\+\)$/"\1" -> "\2";\n/ ' \ | tee -a "${tmp_dir}/print-content" \ | sed -n ' s/^".*" -> "\(\S\+\)";$/\1/ T /:/ { s/.*/"\0" [fontcolor="#a0a000"];/ p } /\./ { s/.*/"\0" [fontcolor="#808000"];/ p } ' \ >> "${tmp_dir}/print-content" grep '[46] \S\+ :FORWARD ACCEPT ' "${tmp_dir}/iptables" | \ while read -r ipver host _; do grep "^${host} " "${tmp_dir}/interfaces" done | \ sort -u > \ "${tmp_dir}/ifs-routed" join -j1 "${tmp_dir}/ifs-routed" "${tmp_dir}/ifs-routed" \ | grep -v ' \(\S\+\) \1$' \ | sed ' s/^.*$/4 \0\n6 \0/ ' \ > "${tmp_dir}/routes" grep -vwF "$( grep -vwF -- '-m conntrack' "${tmp_dir}/iptables" | \ grep -v '^4 .*/32 ' | \ grep -v '^6 .*/128 ' | \ sed -n ' s/^\([46]\) \(\S\+\) \(.* \)\?-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 '^4 \S\+ .*/32 ' | \ grep -v '^6 \S\+ .*/128 ' | \ sed ' s/^\([46]\) \(\S\+\) \(.* \)\?-A FORWARD \(.* \)\?-i \(\S\+\) \(.* \)\?-o \(\S\+\) \(.* \)\?-j ACCEPT/\1 \2 \5 \7/ t s/^\([46]\) \(\S\+\) \(.* \)\?-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" \ | while read -r dir ip host from to; do printf '%s %s %s %s %s %s\n' \ "${dir}" \ "${from}" \ "${to}" \ "${host}" \ "${ip}" \ "$( printf '%s\n' "${from}" "${to}" | \ sort | \ tr -d '\n' )" done \ | sort -k2,6 -k1,1 \ > "${tmp_dir}/routes.new" uniq -uf1 "${tmp_dir}/routes.new" \ | grep '^f ' \ > "${tmp_dir}/routes" uniq -df1 "${tmp_dir}/routes.new" \ | sed 's/^[fr] /b /' \ | sort -k4,6 -k1,3 \ | uniq -f3 \ >> "${tmp_dir}/routes" rm "${tmp_dir}/routes.new" sed ' s/^f \(\S\+\) \(\S\+\) \(\S\+\) 4 \S\+$/"\3 \1" -> "\3 \2" [weight=0, color="#808080"];\n/ t s/^f \(\S\+\) \(\S\+\) \(\S\+\) 6 \S\+$/"\3 \1" -> "\3 \2" [weight=0, color="#000000"];\n/ t s/^b \(\S\+\) \(\S\+\) \(\S\+\) 4 \S\+$/"\3 \1" -> "\3 \2" [dir=both, weight=0, color="#808080"];\n/ t s/^b \(\S\+\) \(\S\+\) \(\S\+\) 6 \S\+$/"\3 \1" -> "\3 \2" [dir=both, weight=0, color="#000000"];\n/ t d ' "${tmp_dir}/routes" \ >> "${tmp_dir}/print-content" sort -u "${tmp_dir}/print-content" | cat -n { echo 'digraph network {' echo 'rankdir=LR;' sort -u "${tmp_dir}/print-content" echo '}' } | \ dot -Tpng -onetwork.png