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 = 20;
27 var routesPerUpdate = 100;
28 var updatesPerInterval = 40;
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);
423 if(!usePrivateRanges) {
424 if(ipb == 168 && ipa == 192) ipb++;
426 if(ipa == 127) ipa++;
427 if(ipa == 128) ipa++;
428 if(ipa == 172) ipa++;
431 return ipa+"."+ipb+"."+ipc;
436 function getASPath() {
437 var n = Math.random();
439 return asPaths[Math.round(asPaths.length*n)];
442 function constructUpdateMessage(n_up) {
445 var aspath = getASPath();
446 //console.log("aspath is");
447 //console.log(aspath);
449 // first the header components
452 // next the length component
455 // next the n unfeasible
458 // next, path attr length
462 // now we begin the path attrs
463 // first origin - simple
466 // next as path - hard, flag + type + len + aspath segment
469 // as path segment size = 1 (type), + 1 (len) + as's*2
470 var aspathlen = ((aspath.length+1)*2)+1+1;
471 aspathn += aspathlen;
473 // now next hop attrs = flag (1) + type (1) + len (1) + octets (4);
477 // now nlri = prefix len (1) + prefix fixed in our case (3)
483 //console.log("size: " + bsize + ", an: " + aspathn + " al:" + aspathlen);
484 var buf = new Buffer(bsize);
487 // now lets create the buffer
488 buf.fill(0xff, bp, bp+16);
490 buf.writeUInt16BE(bsize, bp);
492 buf.writeUInt8(2, bp);
494 buf.writeUInt16BE(0, bp);
496 buf.writeUInt16BE(aspathn, bp);
501 buf.writeUInt8(0x40, bp);
503 buf.writeUInt8(1, bp);
505 buf.writeUInt8(1, bp);
507 buf.writeUInt8(0, bp);
511 buf.writeUInt8(0x40, bp);
513 buf.writeUInt8(2, bp);
515 buf.writeUInt8(aspathlen, bp);
517 buf.writeUInt8(2, bp);
519 buf.writeUInt8(aspath.length+1, bp);
521 //console.log("writing in my aspath: "+myas);
522 buf.writeUInt16BE(myAS, bp);
524 aspath.forEach(function (ed) {
525 //console.log("writing in aspath: "+ed);
526 buf.writeUInt16BE(ed, bp);
531 buf.writeUInt8(0x40, bp);
533 buf.writeUInt8(3, bp);
535 buf.writeUInt8(4, bp);
538 // if(randomNextHop) {
539 // rnh = getRandomNextHop();
540 // rnh.split(".").forEach(function (ed) {
541 // //console.log("writing in next hop info: " + ed);
542 // buf.writeUInt8(parseInt(ed), bp);
545 myIP.split(".").forEach(function (ed) {
546 //console.log("writing in next hop info: " + ed);
547 buf.writeUInt8(parseInt(ed), bp);
552 nhns = Math.round(1+(Math.random()*250));
554 buf.writeUInt8(nhns, bp);
559 for(var nn=0; nn < n_up; nn++) {
560 //console.log("bsize: "+bsize+" bp "+bp);
561 buf.writeUInt8(24, bp);
563 var ip = getNextIP();
564 ip.split(".").forEach(function(ed){
565 //console.log("Writing in nlri: "+ed);
566 buf.writeUInt8(parseInt(ed), bp);
574 //console.log("buf is:");
576 //console.log(buf.length);
581 function createAsPathArray(size) {
582 for(var i=0; i<size; i++) {
583 asPaths[i] = createaspath(i);
588 function createaspath(i) {
591 var ret = new Array();
593 for(var t=0; t<n; t++) {
595 as = 1024 + (i%30000);
601 function parseBuffer(b, c) {
602 var len = b.readUInt16BE(16);
603 var type = b.readUInt8(18);
605 //console.log("got input: " + len + ", type: " + type);
608 var vers = b.readUInt8(19);
609 var as = b.readUInt16BE(20);
610 var ht = b.readUInt16BE(22);
611 var ot1 = b.readUInt8(24);
612 var ot2 = b.readUInt8(25);
613 var ot3 = b.readUInt8(26);
614 var ot4 = b.readUInt8(27);
615 var opl = b.readUInt8(28);
616 //console.log("got open type, vers: "+vers+", as: " + as);
617 //console.log("ht: " + ht + ", id: "+ot1+"."+ot2+"."+ot3+"."+ot4+", opl: "+opl);
620 //console.log("sending our open type");
621 var out = new Buffer(29);
624 out.fill(0xff, 0, 16);
625 out.writeUInt16BE(29, 16);
626 out.writeUInt8(1, 18);
627 out.writeUInt8(4, 19);
628 out.writeUInt16BE(myAS, 20);
629 out.writeUInt16BE(90, 22);
630 out.writeUInt8(10, 24);
631 out.writeUInt8(99, 25);
632 out.writeUInt8(99, 26);
633 out.writeUInt8(1,27);
634 out.writeUInt8(0,28);
637 } else if(type == 4) {
638 //console.log("writing keepalive - exact as sent");
639 console.log("LOG: keepalive from remote ("+c.remoteAddress+")");
642 updateState("ready");
643 //if(updateSent ==0) beginUpdateSend(c);
644 } else if(type == 2) {
645 //console.log("got update...");
646 console.log("LOG: update from remote ("+c.remoteAddress+")");
648 updateState("ready");
649 } else if(type == 3) {
650 var loc = b.readUInt8(19);
651 var msg = b.readUInt8(20);
652 var fromremote = parseNotifyMessage(loc, msg);
653 console.log("LOG: Notification message from server ("+loc+"/"+msg+"): " + fromremote);
655 //console.log("sending end...");
663 function parseNotifyMessage(loc, msg) {
667 retmsg += "Header Error - ";
668 if(msg == 1) retmsg += "Not Synchronised";
669 else if(msg == 2) retmsg += "Bad Message Length";
670 else if(msg == 3) retmsg += "Bad Message Type";
671 else retmsg += "Unknown error code: "+msg;
674 retmsg += "Open Error - ";
675 if(msg == 1) retmsg += "Unsupported Version";
676 else if(msg == 2) retmsg += "AS Missmatch";
677 else if(msg == 3) retmsg += "Bad BGP ID";
678 else if(msg == 4) retmsg += "Unsupported Option Parameter";
679 else retmsg += "Unknown error code: "+msg;
682 retmsg += "Update Error - ";
683 if(msg == 1) retmsg += "Malformed attribute list";
684 else if(msg == 2) retmsg += "Unknown recognised well-known attribute";
685 else if(msg == 3) retmsg += "Missing well-known attribute";
686 else if(msg == 4) retmsg += "Attribute flag error";
687 else if(msg == 5) retmsg += "Attribute length error";
688 else if(msg == 6) retmsg += "Invalid origin attribute";
689 else if(msg == 7) retmsg += "Deprecated error message (other end is waaay too old)";
690 else if(msg == 8) retmsg += "Invalid next hop attribute";
691 else if(msg == 9) retmsg += "Optional attribute error";
692 else if(msg == 10) retmsg += "Invalid network field";
693 else if(msg == 11) retmsg += "Malformed AS path";
694 else retmsg += "Unknown error code: "+msg;
697 retmsg += "Hold Timer Expired - ";
700 retmsg += "Finite State Machine error - "+msg;
703 retmsg += "Unknown erorr type - "+msg;