require('DB.php');
$db=DB::Connect('pgsql://www-data@localhost/tr');
$openas=explode(",",$_REQUEST["openas"]);
$host=substr($_SERVER["PATH_INFO"],1);
if (!preg_match("/^[0-9_a-z\.:-]+$/",$host)) {
$d=opendir("output");
echo "
";
while(FALSE!==($f=readdir($d))) {
if (substr($f,-4)!=".dat")
continue;
echo "- $f\n";
}
exit;
}
if (!file_exists("output/$host.dat")) {
echo "No data";
exit;
}
function parse_dat($path)
{
$f=fopen($path,"r");
while($l=fgets($f)) {
$arg=explode(" ",trim($l));
switch ($arg[0]) {
case 'dest':
$dest=$arg[1];
break;
case 'date':
$time=$arg[1];
break;
case 'host':
if ($arg[2] == "?")
$arg[2] = "Unknown";
$host[$arg[1]]=array(
'as' => $arg[2],
'host' => $arg[3],
'ip' => $arg[4],
);
break;
case 'hop':
$hop[$arg[1]][]=$arg[2];
$revhop[$arg[2]][]=$arg[1];
break;
case 'star':
$star[$arg[1]]=array();
break;
default:
echo "eh?";
print_r($arg);
break;
}
}
return array($host,$hop,$revhop,$star);
}
$announced=array();
function colour($as)
{
while (substr($as,0,1)>="A" && substr($as,0,1)<="Z") {
$as=substr($as,1);
}
$as=(int)$as;
if ($as==0) return array(255,255,255);
$col=array(0,0,0);
for($i=0;$i<8;++$i) {
for($j=0;$j<3;++$j) {
$col[$j]=($col[$j]<<1)|($as&1);
$as=$as>>1;
}
}
return $col;
}
function fore_color($col)
{
list($r,$g,$b)=$col;
$y = $r*.299+$g*.587+$b*.144;
if ($y<128) return array(255,255,255);
return array(0,0,0);
}
function get_asname($as)
{
global $db;
while (substr($as,0,1)>="A" && substr($as,0,1)<="Z") {
$as=substr($as,1);
}
$as=(int)$as;
if ($as == 0)
return "Unknown";
$ret=$db->query("SELECT * FROM asnames WHERE asnum=?",$as);
$ret=$ret->fetchrow(DB_FETCHMODE_ASSOC);
if ($ret)
return $ret["name"];
return "AS$as";
}
function make_closed_label($as)
{
global $openas,$announced;
$dot="";
if (!array_key_exists($as,$announced)) {
array_push($openas,$as);
$col=colour($as);
$fcol=fore_color($col);
$dot.=" ".$as." [label=\"".get_asname($as)."\", URL=\"?openas=".implode($openas,",")."\",fill color=\"#".sprintf("%02x%02x%02x",$col[0],$col[1],$col[2])."\",style=\"filled\",fontcolor=\"#".sprintf("%02x%02x%02x",$fcol[0],$fcol[1],$fcol[2])."\",shape=\"record\",height=\".01\"];\n";
array_pop($openas);
}
return array($dot,$as);
}
function make_open_label($node,$as,$label,$fillcolour,$fontcolour,$circle=0)
{
global $announced,$openas;
if (array_key_exists($node,$announced))
return array("",$node);
$dot=" subgraph cluster_".$as." {\n";
$col=colour($as);
$fcol=fore_color($col);
$URL="?openas=".implode(array_diff($openas,array($as)),",");
$dot.=" [label = \"".get_asname($as)."\",fillcolor=\"#".sprintf("%02x%02x%02x",$col[0],$col[1],$col[2])."\",style=\"filled\",fontcolor=\"#".sprintf("%02x%02x%02x",$fcol[0],$fcol[1],$fcol[2])."\",URL=\"$URL\"];\n";
$dot.=" $node [ label=\"$label\",fillcolor=\"$fillcolour\",style=\"filled\",fontcolor=\"$fontcolour\"";
if (!$circle)
$dot.=",shape=\"record\",height=\".01\"";
$dot.="];\n";
$dot.=" };\n";
return array($dot,$node);
}
function make_label($node)
{
global $host,$hop,$star,$announced,$openas;
$dot="";
if (array_key_exists($node,$star)) {
/* If this is a "free floating" as, just draw it. */
if (!array_key_exists("as",$star[$node])) {
$dot .= " $node [label=\"*\",style=\"filled\",fillcolor=\"#888888\",fontcolor=\"#ff0000\"];\n";
return array($dot,$node);
}
/* If it's closed, just draw the AS as normal */
if (!in_array($star[$node]["as"],$openas)) {
return make_closed_label($star[$node]["as"]);
}
/* It's an * within an open AS */
return make_open_label($node,$star[$node]["as"],
"*","#888888","#FF0000",1);
} else if ($node == "?" || substr($host[$node]["as"],0,3)=="RFC") {
if (!array_key_exists($node,$announced)) {
$dot.=" $node [label=\"".$host[$node]["ip"]."\"];\n";
}
return array($dot,$node);
} else if (in_array($host[$node]["as"],$openas)) {
return make_open_label($node,$host[$node]["as"],
$host[$node]["host"],"#FFFFFF","#000000");
} else {
return make_closed_label($host[$node]["as"]);
}
}
function make_dot($host,$hop,$star)
{
global $openas;
$dot="digraph traceroute {\n";
$link=array();
$announced=array();
foreach($hop as $fromhost=>$tohosts) {
foreach($tohosts as $tohost) {
list($dotextra1,$fromas) = make_label($fromhost);
list($dotextra2,$toas) = make_label($tohost);
if ($fromas == $toas
&& !in_array($fromas,$openas)) {
/* If the AS is closed, and it's an internal link */
continue;
} else {
$dot.=$dotextra1.$dotextra2;
$announced[$fromas]=1;
$announced[$toas]=1;
if (!array_key_exists($fromas,$link)
|| !array_key_exists($toas,$link[$fromas])) {
$dot.=" $fromas -> $toas;\n";
$link[$fromas][$toas]=1;
}
}
}
}
$dot.="}\n";
return $dot;
}
/* Finds the best AS that this node is probably in, given that it's probably
* either a "*" or RFC1918 which don't have an explicit AS.
*
* It does it by walking backwards until it finds a node with an AS, saving
* as's as it goes. This function updates this nodes AS (if one is found),
* and perhaps a few other AS's for caching purporses.
*/
function find_best_as($node)
{
global $star,$host,$revhop,$hop;
if (array_key_exists($node,$host)
&&array_key_exists("as",$host[$node])) {
if ($host[$node]["as"]!="RFC1918")
return $host[$node]["as"];
}
if (array_key_exists($node,$star)
&&array_key_exists("as",$star[$node]))
return $star[$node]["as"];
if (array_key_exists($node,$revhop)) {
$as=find_best_as($revhop[$node][0]);
if ($as=="") {
}
else if (array_key_exists($node,$host))
$host[$node]["as"]=$as;
else if (array_key_exists($node,$star))
$star[$node]["as"]=$as;
return $as;
}
return "";
}
list($host,$hop,$revhop,$star)=parse_dat("output/$host.dat");
/* Ok, now I need to figure out what AS's RFC1918 and *'s are in */
foreach($star as $node=>$data) {
find_best_as($node);
}
/* And do all the hosts for good luck too to catch the RFC1918 hosts*/
foreach($host as $node=>$data) {
find_best_as($node);
}
$dot= make_dot($host,$hop,$star);
if ($_REQUEST["format"]=="dot") {
echo "
$dot";
exit;
}
$f=fopen("/tmp/foo.dot","w");
fwrite($f,$dot);
fclose($f);
switch ($_REQUEST["format"]) {
case "png":
header("Content-type: image/png");
passthru("dot -Tpng /tmp/foo.dot");
//unlink("/tmp/foo.dot");
break;
case "dot":
echo "Dot:";
echo $dot;
break;
default:
?>
break;
}
?>