#!/usr/bin/perl

sub TOHEX {
    $a = $_[0];
    #print $a, "\t";
    
    $a =~ /(\d*).(\d*).(\d*).(\d*)/;
    
    #print $1, " ", $2, " ", $3, " ", $4, "\t";
    $tohex = sprintf ("%02x%02x%02x%02x", $1, $2, $3, $4);
    
}

# --------- MAIN ----------
if (scalar(@ARGV) < 4){
    print("Not enough arguments\n");
    print("usage: make-adapt-ron.pl meIP meHW exitpointIP gwIP [neighborIP...]\n\n");
    exit(-1);
}

$meIP      = shift(@ARGV);
$meHW      = shift(@ARGV);
$exitIP    = shift(@ARGV);
$gwIP      = shift(@ARGV);
@neighbors = @ARGV;
$neigh     = scalar(@neighbors);
#print "[", $neigh, "]\n";

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();

print "// This configuration was generated by make-adapt-ron.pl\n";
print "// $mon/$mday/$year  $hour:$min:$sec\n";
print "//\n";
print "// make-adapt-ron.pl ",$meIP, " ", $meHW, " ", $exitIP, " ", $gwIP, " ";
for($i=0; $i<$neigh; $i++) {
    print $neighbors[$i], " ";
}
print "\n//\n";
print "// This IP:\t", $meIP, "\n";
print "// This HW:\t", $meHW, "\n";
print "// Exit IP:\t", $exitIP, "\n";
print "// GW IP:  \t", $gwIP, "\n";
for($i=0; $i<$neigh; $i++) {
    print "// Neighbor", $i, ":\t", $neighbors[$i], "\n";
}

print "\n";

print "require(ron);\n\n";

print "elementclass ICMPClassifier {\n";
print "	input -> c :: IPClassifier(tcp or udp, icmp type echo or icmp type echo_reply, icmp, -);\n";
print "	c[0] -> [0]output;\n";
print "	c[1] -> [1]output;\n"; 
print "	c[2] -> [2]output;\n";
print "	c[3] -> [3]output;\n";
print "	}\n\n";

print "from0 :: FromDevice(eth0);\n";
print "to0 :: ToDevice(eth0);\n";


print "mainclassifier :: Classifier (\n";
for($i=0; $i<$neigh; $i++) {
    print "\t12/0800 26/", (do TOHEX($neighbors[$i]));
    print " 23/04, \t// IP encap from neighbor ", $i+1, "(", $neighbors[$i], ")\n";
}

print "\t12/0800 30/", (do TOHEX($exitIP)), " !26/", (do TOHEX($exitIP));
print ", \t\t// IP to my exit point (", $exitIP, ")\n";

print "\t12/0800 !30/", (do TOHEX($meIP)), " !26/", (do TOHEX($exitIP)) ;
print " !19/ff,	// IP not to me, not broadcast (forward path entracepoint)\n";

print "\t12/0806 20/0002,		// ARP Replies\n";
print "\t12/0806 20/0001			// ARP Queries\n";
print "\t);\n\n";

print "routingtable :: LookupIPRouteRON(", $neigh + 1, ");\n\n";


print "// ----- Rewriters -----\n";
print "iprw :: IPRewriter(\n";

for($i=0; $i<$neigh+1; $i++) {
    print "\tpattern ", $exitIP, " ";
    print 4000 + $i * 100, "-", 4099 + $i * 100, " - - ";
    print 2*$i, " ", 2*$i + 1, ",\n";
}
print "\tdrop);\n\n";

print "icmprw :: ICMPRewriter(iprw);\n\n";

print "icmppingrw :: ICMPPingRewriter(", $exitIP, ", -);\n\n";

print "setgw :: SetIPAddress(", $gwIP, ");\n\n";

print "arpq :: ARPQuerier(", $meIP, ", ", $meHW, ");\n";
print "arpr :: ARPResponder(", $exitIP, " ", $meHW, ");\n\n";

print "dirPathC :: ICMPClassifier;\n";
print "revPathC :: ICMPClassifier;\n";

for ($i=0; $i<$neigh; $i++) {
    print "c", $i+1, " :: ICMPClassifier;\n";
}
print "\n";

print "elementclass directionclassifier {\n";
print "\tinput\n";
print "\t-> t :: Tee(2)[0] -> pt0 :: PaintTee(0);\n";
print "\tt[1] -> pt1 :: PaintTee(1);\n";
print "\tpt0[0] -> Discard;\n";
print "\tpt0[1] -> [0]output;\n";
print "\tpt1[0] -> Discard;\n";
print "\tpt1[1] -> [1]output;\n";
print "\t}\n\n";

print "// -----------------------------------------------------------\n";

print "from0 -> mainclassifier;\n\n";

for($i=2; $i<$neigh+2; $i++) {
    print "dc", $i," :: directionclassifier;\n";
}
print "\n";


print "mainclassifier[", $neigh+1, "]\n";
print "\t-> Strip(14)\n";
print "\t-> CheckIPHeader\n";
print "\t-> DropBroadcasts\n";
print "\t-> Print(InClassPort2)\n";
print "\t-> IPPrint(InClassPort2)\n";
print "\t-> GetIPAddress(16)\n";
print "\t-> routingtable;\n\n";

for($i=0; $i<$neigh; $i++) {
    print "mainclassifier[", $i, "]\n";
    print "\t-> Strip(14)\n";
    print "\t-> CheckIPHeader\n";
    print "\t-> Print(InClassPort0)\n";
    print "\t-> IPDecapPaint\n";
    print "\t-> CheckIPHeader\n";
    print "\t-> IPPrint(EncapsulatedPac)\n";
    print "\t-> dc", $i+2, "[0] // FORWARD path\n";
    print "\t-> IPReassembler\n";
    print "\t-> c", $i+1, ";\n\n";
}

print "mainclassifier[", $neigh, "]\n";
print "\t-> Strip(14)\n";
print "\t-> CheckIPHeader\n";
print "\t-> fragforA::IPFragmenter(1470)\n";
print "\t-> Print(InClassPort1)\n";
print "\t-> IPReassembler\n";
print "\t-> IPReassembler\n";
print "\t-> CheckIPHeader\n";
print "\t-> IPPrint(InClassPort1)\n";
print "\t-> revPathC;\n\n";

print "mainclassifier[", $neigh + 2, "]\n";
print "//\t-> Print(SawARPReply, 64)\n";
print "\t-> [1]arpq;\n\n";

print "mainclassifier[", $neigh+3, "]\n";
print "//\t-> Print(SawARPQuery, 64)\n";
print "\t-> arpr;\n\n";

print "routingtable[0] -> setgw; // REPLY pkts\n\n";
	
print "routingtable[1]\n";
print "\t-> Print(ROUTE1(direct))\n";
print "\t-> IPReassembler\n";
print "\t-> dirPathC;\n\n";

for($i=2; $i<$neigh+2; $i++) {
    print "routingtable[", $i, "]\n";
    print "\t-> Print(ROUTE2(forw", $i, "_))\n";
    print "\t-> fragforB", $i-2, "::IPFragmenter(1470)\n";
    print "\t-> SetIPAddress(", $neighbors[$i-2], ")\n";
    print "\t-> IPEncapPaint(0, 4, ", $meIP, ") // FORWARD pkts get painted 0 \n";
    print "\t-> setgw;\n\n";
}

print "// Direct pkts\n";
print "dirPathC[0] -> IPPrint(IP) -> [0]iprw;	// TCP, UDP\n";
print "dirPathC[1] -> icmppingrw;	// ICMP Pings\n";
print "dirPathC[2] -> icmprw;	// ICMP errors\n";
print "dirPathC[3] -> Discard;\n\n";

for ($i=1; $i<$neigh+1; $i++) {
    print "// Forward pkts received through tunnel\n";
    print "c", $i, "[0] -> [", $i, "]iprw;	// TCP, UDP\n";
    print "c", $i, "[1] -> icmppingrw;	// ICMP Pings\n";
    print "c", $i, "[2] -> icmprw;	// ICMP errors\n";
    print "c", $i, "[3] -> Discard;\n\n";
}

print "// Reverse pkts received at Exit Point\n";
print "revPathC[0] -> [", $neigh+1, "]iprw;	// TCP, UDP\n";
print "revPathC[1] -> icmppingrw;	// ICMP Pings\n";
print "revPathC[2] -> icmprw;	// ICMP errors\n";
print "revPathC[3] -> Discard;\n\n";

print "// REVERSE pkts received through tunnel\n";
for ($i=2; $i<$neigh+2; $i++) {
    print "dc", $i, "[1]\n";
    print "\t->IPReassembler\n";
    print "\t->CheckIPHeader\n";
    print "\t->GetIPAddress(16)\n";
    print "\t->IPPrint(RCVTunnelREVERSE)\n";
    print "\t-> [", $i, "]routingtable\n";
}
print "\n";

print "// Direct rewrite pattern\n";
print "iprw[0] -> Queue(50) -> DelayShaper(1) -> Unqueue -> IPPrint(IPRewritten0) -> setgw;\n";
print "iprw[1] -> IPPrint(IPRewritten1) -> GetIPAddress(16) -> [1]routingtable;\n\n";

for ($i=1; $i<$neigh+1; $i++) {
    print "iprw[", 2*$i,   "] -> setgw;\n";
    print "iprw[", 2*$i+1, "] -> fragrev",$i-1,"::IPFragmenter(1470)\n";
    print "\t-> SetIPAddress(", $neighbors[$i-1], ")\n";
    print "\t-> IPEncapPaint(1, 4, ", $meIP, ") // Tunnel (REV)\n";
    print "\t-> setgw;\n\n";
}


print "icmprw -> setgw;\n";
print "icmppingrw[0] -> IPPrint(IPPingRewritten1) -> setgw;\n";
print "icmppingrw[1] -> IPPrint(IPPingRewritten2) -> setgw; // this is only for direct pings\n";
#print "//icmppingrw[1] -> IPPrint(IPPingRewritten2) -> SetIPAddress(18.239.2.103) -> arpq;   // this is only for direct pings\n\n";

print "setgw -> [0]arpq;\n";
print "//setlaptop -> [0]arpq;\n\n";

print "icmperror :: ICMPError(", $exitIP, ", 3, 4) -> SetIPAddress(", $gwIP, ") -> arpq;\n";
print "fragforA[1] -> icmperror;\n";
for($i=0; $i<$neigh; $i++) {
    print "fragforB", $i, "[1] -> icmperror;\n";
    print "fragrev", $i, "[1] -> icmperror;\n";
}

print "arpq -> q :: Queue(100) -> Print(OutEth0,56) -> to0;\n";
print "arpr -> Print(ARPResponseSent) -> q;\n";

print "\n";
