1 var readline = require('readline');
2 var net = require('net');
8 var asPaths = new Array();
9 var readyToSend = false;
17 var cState = "starting";
21 var timerIntervalObject;
23 var sequentialIPs = true;
24 var usePrivateRanges = false;
25 var randomNextHop = false;
26 var timeBetweenUpdates = 1000;
27 var routesPerUpdate = 100;
28 var updatesPerInterval = 20;
33 if(typeof process.argv[2] == "undefined") {
37 if(typeof process.argv[3] == "undefined") {
42 console.log("Usage: "+process.argv[1]+" MyAS MyIP");
50 // ----------- startup
52 myAS = process.argv[2];
53 myIP = process.argv[3];
58 createAsPathArray(1048576);
63 // ----------- startup
76 function updatePrompt() {
77 currentPrompt = "("+myAS+"/"+myIP+") "+cState+":"+nCons+"/"+nSent+" ("+currentIPa+"."+currentIPb+"."+currentIPc+") > ";
81 currentPrompt = "("+myAS+"/"+myIP+") starting... > ";
83 rl = readline.createInterface({
85 output: process.stdout
88 rl.on('line', function (cmd) {
102 togglePrivateRange();
108 toggleRandomNextHop();
134 function printStatus() {
135 console.log("---- Status ----");
136 console.log("Currently "+cState);
137 console.log("Private ranges: "+usePrivateRanges);
138 console.log("Sequential publication: "+sequentialIPs);
139 console.log("Random NextHop: "+randomNextHop);
140 console.log("Number of connected peers: " + nCons);
141 console.log("Number of routes published: " + nSent);
142 console.log("My IP address: " + myIP);
143 console.log("My ASN: " + myAS);
144 console.log("Current IP (for sequential publications): " + currentIPa + "." + currentIPb + "." + currentIPc + "0/24");
145 console.log("AS path table size: "+asPaths.length);
148 function togglePrivateRange() {
149 if(usePrivateRanges) {
150 console.log("Switching off private range publication");
151 usePrivateRanges = false;
153 console.log("Switching on private range publication");
154 usePrivateRanges = true;
158 function toggleIPChoice() {
160 sequentialIPs = false;
161 console.log("Switching to random IP addresses");
163 console.log("Switching to sequential IP addresses");
164 sequentialIPs = true;
169 function toggleRandomNextHop() {
171 randomNextHop = false;
172 console.log("Switching form random next-hop to next-hop-self");
174 randomNextHop = true;
175 console.log("Switching form next-hop-self to random next-hop");
180 function doPrompt() {
182 rl.setPrompt(currentPrompt);
186 function printCLIUsage() {
188 console.log("\th[elp],? - this help menu");
189 console.log("\tu - start sending route updates to connected peers");
190 console.log("\tp - pause sending route updates to connected peers");
191 console.log("\ta - toggle use of private ranges");
192 console.log("\tm - toggle between random next hop and my ip as next hop (randomise last octet - assumes /24 on the ip address of this node)");
193 console.log("\ts - status");
194 console.log("\tt - toggles between random and sequential addressing");
195 console.log("\tr - reset IP range back to beginning");
196 console.log("\tq[uit],exit,end - Quit");
197 console.log("Prompt layout");
198 console.log("\t(AS/IP) state:connections/updates-sent (current-route)");
201 function updateState(newstate) {
202 if(cState == newstate) {
208 if(newstate == "starting") {
215 if(newstate == "idle") {
222 if(newstate == "connected") {
229 if(newstate == "ready") {
230 if(cState == "sending") return;
237 if(newstate == "sending") {
243 if(newstate == "stopping") {
266 //------------- network
268 function startUpdates() {
269 if(cState == "sending") {
270 console.log("LOG: already sending...");
274 if(cState != "ready") {
275 console.log("LOG: not ready to send yet");
281 console.log("LOG: starting update sending");
282 updateState("sending");
283 timerIntervalObject = setInterval(sendUpdate, timeBetweenUpdates);
284 //console.log("LOG: stopped sending updates");
288 function sendUpdate()
290 if(cState != "sending") {
291 console.log("oh, your killing me now?");
292 clearInterval(timerIntervalObject);
293 updateState("ready");
295 for(var i=0; i<updatesPerInterval; i++) {
296 var msg = constructUpdateMessage(routesPerUpdate);
297 currentCon.write(msg);
304 function stopUpdates() {
305 if(cState != "sending") {
306 console.log("LOG: not in a sending state, cant pause.");
310 updateState("stopping");
313 function serverconnection(c) {
317 c.on("end", function() {
318 //console.log("Server disconnected");
327 c.on("data", function(buffer) {
328 parseBuffer(buffer, c);
334 cState = "connected";
340 console.log("LOG: connection from "+c.remoteAddress);
343 //c.write("hello\r\n");
347 function startServer() {
348 server = net.createServer(serverconnection);
350 server.listen(179, function() {
351 //console.log("LOG: Server bound");
357 //------------- network
368 // -------------- BGP
370 function getRandomNextHop() {
371 ipa = 1+Math.round(Math.random()*120);
372 ipb = 1+Math.round(Math.random()*254);
373 ipc = 1+Math.round(Math.random()*254);
374 ipd = 1+Math.round(Math.random()*254);
376 return ipa+"."+ipb+"."+ipc+"."+ipd;
380 function getNextIP() {
382 //var currentIPa = 1;
383 //var currentIPb = 0;
384 //var currentIPc = 0;
389 if(currentIPc > 254) {
393 if(!usePrivateRanges) if(currentIPb == 168 && currentIPa == 192) currentIPb++;
394 if(currentIPb > 254) {
398 // dont publish bogons or 127
399 if(!usePrivateRanges) {
400 if(currentIPa == 10) currentIPa++;
401 if(currentIPa == 127) currentIPa++;
402 if(currentIPa == 128) currentIPa++;
403 if(currentIPa == 172) currentIPa++;
408 if(currentIPa > 223) {
409 console.log("LOG: hit the end of the range, wrapping");
415 //console.log("created "+a+"."+b+"."+c+" from "+i);
416 return currentIPa+"."+currentIPb+"."+currentIPc;
418 ipa = 1+Math.round(Math.random()*223);
419 ipb = 1+Math.round(Math.random()*254);
420 ipc = 1+Math.round(Math.random()*254);
427 if(!usePrivateRanges) {
428 if(ipb == 168 && ipa == 192) ipb++;
430 if(ipa == 127) ipa++;
431 if(ipa == 128) ipa++;
432 if(ipa == 172) ipa++;
435 return ipa+"."+ipb+"."+ipc;
440 function getASPath() {
441 var n = Math.random();
443 return asPaths[Math.round(asPaths.length*n)];
446 function constructUpdateMessage(n_up) {
449 var aspath = getASPath();
450 //console.log("aspath is");
451 //console.log(aspath);
453 // first the header components
456 // next the length component
459 // next the n unfeasible
462 // next, path attr length
466 // now we begin the path attrs
467 // first origin - simple
470 // next as path - hard, flag + type + len + aspath segment
473 // as path segment size = 1 (type), + 1 (len) + as's*2
474 var aspathlen = ((aspath.length+1)*2)+1+1;
475 aspathn += aspathlen;
477 // now next hop attrs = flag (1) + type (1) + len (1) + octets (4);
481 // now nlri = prefix len (1) + prefix fixed in our case (3)
487 //console.log("size: " + bsize + ", an: " + aspathn + " al:" + aspathlen);
488 var buf = new Buffer(bsize);
491 // now lets create the buffer
492 buf.fill(0xff, bp, bp+16);
494 buf.writeUInt16BE(bsize, bp);
496 buf.writeUInt8(2, bp);
498 buf.writeUInt16BE(0, bp);
500 buf.writeUInt16BE(aspathn, bp);
505 buf.writeUInt8(0x40, bp);
507 buf.writeUInt8(1, bp);
509 buf.writeUInt8(1, bp);
511 buf.writeUInt8(0, bp);
515 buf.writeUInt8(0x40, bp);
517 buf.writeUInt8(2, bp);
519 buf.writeUInt8(aspathlen, bp);
521 buf.writeUInt8(2, bp);
523 buf.writeUInt8(aspath.length+1, bp);
525 //console.log("writing in my aspath: "+myas);
526 buf.writeUInt16BE(myAS, bp);
528 aspath.forEach(function (ed) {
529 //console.log("writing in aspath: "+ed);
530 buf.writeUInt16BE(ed, bp);
535 buf.writeUInt8(0x40, bp);
537 buf.writeUInt8(3, bp);
539 buf.writeUInt8(4, bp);
542 // if(randomNextHop) {
543 // rnh = getRandomNextHop();
544 // rnh.split(".").forEach(function (ed) {
545 // //console.log("writing in next hop info: " + ed);
546 // buf.writeUInt8(parseInt(ed), bp);
549 myIP.split(".").forEach(function (ed) {
550 //console.log("writing in next hop info: " + ed);
551 buf.writeUInt8(parseInt(ed), bp);
556 nhns = Math.round(1+(Math.random()*250));
558 buf.writeUInt8(nhns, bp);
563 for(var nn=0; nn < n_up; nn++) {
564 //console.log("bsize: "+bsize+" bp "+bp);
565 buf.writeUInt8(24, bp);
567 var ip = getNextIP();
568 ip.split(".").forEach(function(ed){
569 //console.log("Writing in nlri: "+ed);
570 buf.writeUInt8(parseInt(ed), bp);
578 //console.log("buf is:");
580 //console.log(buf.length);
585 function createAsPathArray(size) {
586 for(var i=0; i<size; i++) {
587 asPaths[i] = createaspath(i);
592 function createaspath(i) {
595 var ret = new Array();
597 for(var t=0; t<n; t++) {
599 as = 1024 + (i%30000);
605 function parseBuffer(b, c) {
606 var len = b.readUInt16BE(16);
607 var type = b.readUInt8(18);
609 //console.log("got input: " + len + ", type: " + type);
612 var vers = b.readUInt8(19);
613 var as = b.readUInt16BE(20);
614 var ht = b.readUInt16BE(22);
615 var ot1 = b.readUInt8(24);
616 var ot2 = b.readUInt8(25);
617 var ot3 = b.readUInt8(26);
618 var ot4 = b.readUInt8(27);
619 var opl = b.readUInt8(28);
620 //console.log("got open type, vers: "+vers+", as: " + as);
621 //console.log("ht: " + ht + ", id: "+ot1+"."+ot2+"."+ot3+"."+ot4+", opl: "+opl);
624 //console.log("sending our open type");
625 var out = new Buffer(29);
628 out.fill(0xff, 0, 16);
629 out.writeUInt16BE(29, 16);
630 out.writeUInt8(1, 18);
631 out.writeUInt8(4, 19);
632 out.writeUInt16BE(myAS, 20);
633 out.writeUInt16BE(90, 22);
634 out.writeUInt8(10, 24);
635 out.writeUInt8(99, 25);
636 out.writeUInt8(99, 26);
637 out.writeUInt8(1,27);
638 out.writeUInt8(0,28);
641 } else if(type == 4) {
642 //console.log("writing keepalive - exact as sent");
643 console.log("LOG: keepalive from remote ("+c.remoteAddress+")");
646 updateState("ready");
647 //if(updateSent ==0) beginUpdateSend(c);
648 } else if(type == 2) {
649 //console.log("got update...");
650 console.log("LOG: update from remote ("+c.remoteAddress+")");
652 updateState("ready");
653 } else if(type == 3) {
654 var loc = b.readUInt8(19);
655 var msg = b.readUInt8(20);
656 var fromremote = parseNotifyMessage(loc, msg);
657 console.log("LOG: Notification message from server ("+loc+"/"+msg+"): " + fromremote);
659 //console.log("sending end...");
667 function parseNotifyMessage(loc, msg) {
671 retmsg += "Header Error - ";
672 if(msg == 1) retmsg += "Not Synchronised";
673 else if(msg == 2) retmsg += "Bad Message Length";
674 else if(msg == 3) retmsg += "Bad Message Type";
675 else retmsg += "Unknown error code: "+msg;
678 retmsg += "Open Error - ";
679 if(msg == 1) retmsg += "Unsupported Version";
680 else if(msg == 2) retmsg += "AS Missmatch";
681 else if(msg == 3) retmsg += "Bad BGP ID";
682 else if(msg == 4) retmsg += "Unsupported Option Parameter";
683 else retmsg += "Unknown error code: "+msg;
686 retmsg += "Update Error - ";
687 if(msg == 1) retmsg += "Malformed attribute list";
688 else if(msg == 2) retmsg += "Unknown recognised well-known attribute";
689 else if(msg == 3) retmsg += "Missing well-known attribute";
690 else if(msg == 4) retmsg += "Attribute flag error";
691 else if(msg == 5) retmsg += "Attribute length error";
692 else if(msg == 6) retmsg += "Invalid origin attribute";
693 else if(msg == 7) retmsg += "Deprecated error message (other end is waaay too old)";
694 else if(msg == 8) retmsg += "Invalid next hop attribute";
695 else if(msg == 9) retmsg += "Optional attribute error";
696 else if(msg == 10) retmsg += "Invalid network field";
697 else if(msg == 11) retmsg += "Malformed AS path";
698 else retmsg += "Unknown error code: "+msg;
701 retmsg += "Hold Timer Expired - ";
704 retmsg += "Finite State Machine error - "+msg;
707 retmsg += "Unknown erorr type - "+msg;