asn icon indicating copy to clipboard operation
asn copied to clipboard

Feature Request: Multi source lookups

Open ScrumpyJack opened this issue 3 years ago • 13 comments

I've been using this a bit and I really like it in server mode. Excellent as a looking glass. Nice crisp, colourful output. And I've discovered aha, which is now my new favourite toy.

I can't help wondering if we could get this to execute on a bunch of remove machines (via ssh and keys) and output the results to the same page, one after the other. A bit like mtr.sh

What are you thoughts?

ScrumpyJack avatar Apr 13 '21 06:04 ScrumpyJack

That's an interesting idea. Beside the ssh approach, it can be done very easily with an external script aggregating output from different asn server instances, for example if you want textual traces from multiple servers, just add them to the $asnservers variable and run the script below. It should output textual results on screen. Of course this can be obtained using html, or even aggregating the html in a nice looking page with, say, sections reporting the asn server source country for every result etc. - I think this all belongs to an external script, and it should be not be hard to make. Let me know if this is what you meant. Thanks for the feedback!

#!/usr/bin/env bash

# change this to the list of your asn server instances, space separated
asnservers="127.0.0.1 1.2.3.4 5.6.7.8"

target="$1"
output=""
for asnserver in $asnservers; do
    echo "Running asn lookup for '$target' on server $asnserver"
    output+="$(curl -s "http://$asnserver:49200/asn_lookup&$target" | sed -n "s:.*id='tracedata'>\(.*\)</div>.*:\1:p" | base64 -d | gunzip)\n\n"
done

echo -e "$output" | less

The script above is meant to be invoked with the <target> parameter on command line. For example ./multiasn 8.8.8.8

nitefood avatar Apr 13 '21 14:04 nitefood

Clever. I hadn't thought of looping a curl.

How would you get that output back into a browser window with the pretty colours though? 😁

ScrumpyJack avatar Apr 13 '21 21:04 ScrumpyJack

Well in the above script, I just extracted the tracedata div content from the html - which is just a gzipped + base64-encoded version of the textual asn output, which I use when sharing the text-only version on termbin. That means you can instead grab the full html (just take out the sed part) and that should do the trick.

nitefood avatar Apr 13 '21 21:04 nitefood

I reckon perhaps the above needs a clearer explanation: when I run a remote trace, I instruct the remote server to run a trace and convert the trace output to html (using your new friend aha ;-) in order to display it back to the client. In the meantime, since I needed an easy way to share the text output on termbin if the client so decided, and since converting it from html back to text was rather stupid (since in the process I had the text server-side all along), I decided to append (on server side) a "text-only" version of the trace output to the output HTML, so that the client already had what it needed to feed to termbin. I needed a way that was lightweight (ie: gzip) and - since it had to be passed along in a web page - textual-only (no non-printable characters, ie: base64). The method I used was to append a <div> (having id=tracedata) to the output HTML. That way I could generate the termbin-sharing code dynamically on the client side (or actually, I could hardcode it directly into the output html without any worries on the actual contents of the trace) and already have the termbin input to pass to the sharing function (which is just another GET from the remote server).

nitefood avatar Apr 13 '21 21:04 nitefood

I just hacked together what I had in mind when I spoke about "sections". Output looks like this (sorry, I'm not a web designer :-P) :

image

Note: you need GNU sed for this to work. Make sure you have the coreutils package installed if running the following script on MacOS/FreeBSD.

#!/usr/bin/env bash

# change this to the list of your asn server instances, space separated
asnservers="127.0.0.1 1.2.3.4 5.6.7.8"
# output html filename
output_file="output.html"

# no changes needed below

target="$1"
[[ -z "$target" ]] && { echo "Usage: $0 <target>"; exit 1; }

green=$'\e[38;5;035m'
red=$'\e[38;5;203m'
default=$'\e[0m'

# make sure we use GNU sed if running on FreeBSD/MacOS
if [ -x "$(command -v gsed)" ]; then
    sed() { gsed "$@"; }
    export -f sed
fi

read -r -d '' output <<- END_OF_HTML_HEADER
	<?xml version="1.0" encoding="UTF-8" ?>
	<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
	<html xmlns="http://www.w3.org/1999/xhtml">
END_OF_HTML_HEADER

# cheers https://www.cssscript.com/responsive-css-accordion-tabs-component/
read -r -d '' accordioncss <<- END_OF_ACCORDION_CSS
<style>
.tabs {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
}

.tabs label {
  -webkit-box-ordinal-group: 2;
  -webkit-order: 1;
  -ms-flex-order: 1;
  order: 1;
  display: block;
  padding: 0.5rem 2rem;
  margin-right: 0.2rem;
  cursor: pointer;
  background: #d5d5d5;
  -webkit-transition: background ease 0.2s;
  transition: background ease 0.2s;
}

.tabs .tab {
  -webkit-box-ordinal-group: 100;
  -webkit-order: 99;
  -ms-flex-order: 99;
  order: 99;
  -webkit-box-flex: 1;
  -webkit-flex-grow: 1;
  -ms-flex-positive: 1;
  flex-grow: 1;
  width: 100%;
  display: none;
  padding: 0.05rem;
  background: #fafafa;
}

.tabs input[type="radio"] {
  position: absolute;
  opacity: 0;
}

.tabs input[type="radio"] + label { background: #999999; color: #404040; }
.tabs input[type="radio"]:checked + label { background: #fafafa; font-weight: bold; color: #1e1e1e; }
.tabs input[type="radio"]:checked + label + .tab { display: block; }

@media (max-width: 45em) {

.tabs .tab,  .tabs label {
  -webkit-box-ordinal-group: NaN;
  -webkit-order: initial;
  -ms-flex-order: initial;
  order: initial;
}

.tabs label {
  width: 100%;
  margin-right: 0;
  margin-top: 0.2rem;
}
}
</style>
END_OF_ACCORDION_CSS

first_run=true
srvnum=1
for asnserver in $asnservers; do
    echo -en "${default}- Running asn lookup for '$target' on server $asnserver..."
    tmp_output="$(curl -s "http://$asnserver:49200/asn_lookup&$target" | grep -v 'class="loader"')"
    if [ -z "$tmp_output" ]; then
        echo "${red}Error!${default}"
    else
        if [ "$first_run" = true ]; then
            # grab the <head> tag from the first successful run, so to apply proper styling to the remaining results
            htmlhead=$(sed -zn "s:.*<head>\(.*\)</head>.*:\1:p" <<<"$tmp_output")
            output+="\n\n<head>\n$htmlhead\n$accordioncss\n</head>\n<body>\n\
            <div style='text-align: center;'><hr>Multiple ASN trace to target:<br /><span style='color:#ff5f5f; font-size: 2em'>$target</span><br /><hr></div> \
            <div class='tabs'>"
        fi
        # extract <body> content for this trace
        htmlbody=$(sed -zn "s:.*<body>\(.*\)</body>.*:\1:p" <<<"$tmp_output")
        # clean up the html by stripping unneeded js
        htmlbody=$(\
            sed -e "s/<script>window.scrollTo.*<\/script>//g" \
                -e "s/<script>top.document.title.*<\/script>//g" <<<"$htmlbody"
        )
        # strip sharing-related html
        htmlbody=$(sed -z "s/<span id='share-container'>.*/<\/div><\/pre>/" <<<"$htmlbody")
        # extract asn server name from html
        srvname=$(sed -n "s:.*running on \(.*\) in.*:\1:p" <<<"$htmlbody")
        # extract server flag svg from html
        srvflag=$(sed -n "s:.*\(http[s*]\://.*/flag-icon-css/.*svg\).*:\1:p" <<<"$htmlbody" | head -n1)
        # create the output tab related to this trace
        output+="<input type=\"radio\" name=\"tabs\" id=\"$srvnum\""
        [[ "$first_run" = true ]] && { output+=" checked='checked'"; first_run=false; }
        output+=">\n \
            <label for=\"$srvnum\">${srvnum}. $srvname <img src='$srvflag' style='height:1.05em; border-radius: 0; vertical-align: middle;'></label> \
        <div class=\"tab\"> \
            $htmlbody \
        </div>\n"

        echo "${green}OK!${default}"
    fi
    (( srvnum++ ))
done
output+="\n</body>\n</html>"
echo -e "$output" > "$output_file"

echo -e "\nOutput written to file ${green}${output_file}${default}\n"

nitefood avatar Apr 19 '21 22:04 nitefood

Oh my goodness that is amazing. I will try this out as

ScrumpyJack avatar Apr 26 '21 08:04 ScrumpyJack

I changed

tmp_output="$(curl -s "http://$asnserver:49200/asn_lookup&$target" | grep -v 'class="loader"')"

to

tmp_output="$(curl -s "$asnserver/asn_lookup&$target" | grep -v 'class="loader"')"

as it allows variation on protocol and ports in the list of $asnservers

How and where would you add class="hidden_underline" to this script?

ScrumpyJack avatar May 08 '21 15:05 ScrumpyJack

How and where would you add class="hidden_underline" to this script?

no need to, I just pushed v0.71.6 which implements hidden underlines out of the box. Try it with the newest version, should work just fine.

nitefood avatar May 08 '21 17:05 nitefood

Would be awesome to add netcat listen to multiasn so that the hyperlinks would work. Hmm, seems complex though as the html output currently goes to a file instead of back out to the http client.

ScrumpyJack avatar May 08 '21 19:05 ScrumpyJack

Actually, hrefs point to file:// URLs just because you open it from disk and they're relative links (therefore not able to figure out which site to point to). This could be easily bulk-translated on the fly in the multiasn script, to point to the current server's IP (as in, changing "/" to "$asnserver/") while being parsed before going out to the file. That way each tab would have proper hyperlinks pointing to the appropriate server instead of useless "file://" links pointing nowhere. Will add that as soon as I get a minute.

nitefood avatar May 08 '21 19:05 nitefood

This oughta get you working hyperlinks (includes your protocol and port modification, even though for https to work I guess you'd have to place it behind a proxy as there's no ssl handling currently built into the script):

#!/usr/bin/env bash

# change this to the list of your asn server instances, space separated
asnservers="http://127.0.0.1:49200 http://1.2.3.4:49200 http://5.6.7.8:49200"
# output html filename
output_file="output.html"
# no changes needed below

target="$1"
[[ -z "$target" ]] && { echo "Usage: $0 <target>"; exit 1; }

green=$'\e[38;5;035m'
red=$'\e[38;5;203m'
default=$'\e[0m'

# make sure we use GNU sed if running on FreeBSD/MacOS
if [ -x "$(command -v gsed)" ]; then
    sed() { gsed "$@"; }
    export -f sed
fi

read -r -d '' output <<- END_OF_HTML_HEADER
	<?xml version="1.0" encoding="UTF-8" ?>
	<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
	<html xmlns="http://www.w3.org/1999/xhtml">
END_OF_HTML_HEADER

# cheers https://www.cssscript.com/responsive-css-accordion-tabs-component/
read -r -d '' accordioncss <<- END_OF_ACCORDION_CSS
<style>
.tabs {
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-flex-wrap: wrap;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
}

.tabs label {
  -webkit-box-ordinal-group: 2;
  -webkit-order: 1;
  -ms-flex-order: 1;
  order: 1;
  display: block;
  padding: 0.5rem 2rem;
  margin-right: 0.2rem;
  cursor: pointer;
  background: #d5d5d5;
  -webkit-transition: background ease 0.2s;
  transition: background ease 0.2s;
}

.tabs .tab {
  -webkit-box-ordinal-group: 100;
  -webkit-order: 99;
  -ms-flex-order: 99;
  order: 99;
  -webkit-box-flex: 1;
  -webkit-flex-grow: 1;
  -ms-flex-positive: 1;
  flex-grow: 1;
  width: 100%;
  display: none;
  padding: 0.05rem;
  background: #fafafa;
}

.tabs input[type="radio"] {
  position: absolute;
  opacity: 0;
}

.tabs input[type="radio"] + label { background: #999999; color: #404040; }
.tabs input[type="radio"]:checked + label { background: #fafafa; font-weight: bold; color: #1e1e1e; }
.tabs input[type="radio"]:checked + label + .tab { display: block; }

@media (max-width: 45em) {

.tabs .tab,  .tabs label {
  -webkit-box-ordinal-group: NaN;
  -webkit-order: initial;
  -ms-flex-order: initial;
  order: initial;
}

.tabs label {
  width: 100%;
  margin-right: 0;
  margin-top: 0.2rem;
}
}
</style>
END_OF_ACCORDION_CSS

first_run=true
srvnum=1
for asnserver in $asnservers; do
    echo -en "${default}- Running asn lookup for '$target' on server $asnserver..."
    tmp_output="$(curl -s "$asnserver/asn_lookup&$target" | grep -v 'class="loader"')"
    if [ -z "$tmp_output" ]; then
        echo "${red}Error!${default}"
    else
        if [ "$first_run" = true ]; then
            # grab the <head> tag from the first successful run, so to apply proper styling to the remaining results
            htmlhead=$(sed -zn "s:.*<head>\(.*\)</head>.*:\1:p" <<<"$tmp_output")
            output+="\n\n<head>\n$htmlhead\n$accordioncss\n</head>\n<body>\n\
            <div style='text-align: center;'><hr>Multiple ASN trace to target:<br /><span style='color:#ff5f5f; font-size: 2em'>$target</span><br /><hr></div> \
            <div class='tabs'>"
        fi
        # extract <body> content for this trace
        htmlbody=$(sed -zn "s:.*<body>\(.*\)</body>.*:\1:p" <<<"$tmp_output")
        # clean up the html by stripping unneeded js
        htmlbody=$(\
            sed -e "s/<script>window.scrollTo.*<\/script>//g" \
                -e "s/<script>top.document.title.*<\/script>//g" <<<"$htmlbody"
        )
        # fixup relative hyperlinks with absolute ones pointing to the right server
        htmlbody=$(sed -E "s,<a href=\"/asn_lookup,<a href=\"$asnserver/asn_lookup," <<<"$htmlbody")
        # strip sharing-related html
        htmlbody=$(sed -z "s/<span id='share-container'>.*/<\/div><\/pre>/" <<<"$htmlbody")
        # extract asn server name from html
        srvname=$(sed -n "s:.*running on \(.*\) in.*:\1:p" <<<"$htmlbody")
        # extract server flag svg from html
        srvflag=$(sed -n "s:.*\(http[s*]\://.*/flag-icon-css/.*svg\).*:\1:p" <<<"$htmlbody" | head -n1)
        # create the output tab related to this trace
        output+="<input type=\"radio\" name=\"tabs\" id=\"$srvnum\""
        [[ "$first_run" = true ]] && { output+=" checked='checked'"; first_run=false; }
        output+=">\n \
            <label for=\"$srvnum\">${srvnum}. $srvname <img src='$srvflag' style='height:1.05em; border-radius: 0; vertical-align: middle;'></label> \
        <div class=\"tab\"> \
            $htmlbody \
        </div>\n"

        echo "${green}OK!${default}"
    fi
    (( srvnum++ ))
done
output+="\n</body>\n</html>"
echo -e "$output" > "$output_file"

echo -e "\nOutput written to file ${green}${output_file}${default}\n"

nitefood avatar May 08 '21 21:05 nitefood

This is very cool and work pretty well. You are now costing me a fortune on VMs dotted round the place used as remote looking glasses

ScrumpyJack avatar Jun 15 '21 14:06 ScrumpyJack

This multiasn is my new favorite toy, but I can't help thinking that it would be cool to have a listener that could then farm out the lookups to $asnservers and then display the result in a browser, in the same way as asn does for itself, if that makes sense.

ScrumpyJack avatar Jul 08 '21 12:07 ScrumpyJack

closing this issue to cleanup the repo a bit. Hope all is well over there. Have a nice day!

nitefood avatar Apr 29 '23 23:04 nitefood