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;
29 if(typeof process.argv[2] == "undefined") {
33 if(typeof process.argv[3] == "undefined") {
38 console.log("Usage: "+process.argv[1]+" MyAS MyIP");
46 // ----------- startup
48 myAS = process.argv[2];
49 myIP = process.argv[3];
54 createAsPathArray(1048576);
59 // ----------- startup
72 function updatePrompt() {
73 currentPrompt = "("+myAS+"/"+myIP+") "+cState+":"+nCons+"/"+nSent+" ("+currentIPa+"."+currentIPb+"."+currentIPc+") > ";
77 currentPrompt = "("+myAS+"/"+myIP+") starting... > ";
79 rl = readline.createInterface({
81 output: process.stdout
84 rl.on('line', function (cmd) {
126 function togglePrivateRange() {
127 if(usePrivateRanges) {
128 console.log("Switching off private range publication");
129 usePrivateRanges = false;
131 console.log("Switching on private range publication");
132 usePrivateRanges = true;
136 function toggleIPChoice() {
138 sequentialIPs = false;
139 console.log("Switching to random IP addresses");
141 console.log("Switching to sequential IP addresses");
142 sequentialIPs = true;
148 function doPrompt() {
150 rl.setPrompt(currentPrompt);
154 function printCLIUsage() {
156 console.log("\th[elp],? - this help menu");
157 console.log("\tu - start sending route updates to connected peers");
158 console.log("\tp - pause sending route updates to connected peers");
159 console.log("\ta - toggle use of private ranges");
160 console.log("\ts - status");
161 console.log("\tt - toggles between random and sequential addressing");
162 console.log("\tr - reset IP range back to beginning");
163 console.log("\tq[uit],exit,end - Quit");
164 console.log("Prompt layout");
165 console.log("\t(AS/IP) state:connections/updates-sent (current-route)");
168 function updateState(newstate) {
169 if(cState == newstate) {
175 if(newstate == "starting") {
182 if(newstate == "idle") {
189 if(newstate == "connected") {
196 if(newstate == "ready") {
197 if(cState == "sending") return;
204 if(newstate == "sending") {
210 if(newstate == "stopping") {
233 //------------- network
235 function startUpdates() {
236 if(cState == "sending") {
237 console.log("LOG: already sending...");
241 if(cState != "ready") {
242 console.log("LOG: not ready to send yet");
248 console.log("LOG: starting update sending");
249 updateState("sending");
250 timerIntervalObject = setInterval(sendUpdate, 5);
251 //console.log("LOG: stopped sending updates");
255 function sendUpdate()
257 if(cState != "sending") {
258 console.log("oh, your killing me now?");
259 clearInterval(timerIntervalObject);
260 updateState("ready");
262 for(var i=0; i<10; i++) {
263 var msg = constructUpdateMessage(100);
264 currentCon.write(msg);
271 function stopUpdates() {
272 if(cState != "sending") {
273 console.log("LOG: not in a sending state, cant pause.");
277 updateState("stopping");
280 function serverconnection(c) {
284 c.on("end", function() {
285 //console.log("Server disconnected");
294 c.on("data", function(buffer) {
295 parseBuffer(buffer, c);
301 cState = "connected";
307 console.log("LOG: connection from "+c.remoteAddress);
310 //c.write("hello\r\n");
314 function startServer() {
315 server = net.createServer(serverconnection);
317 server.listen(179, function() {
318 //console.log("LOG: Server bound");
324 //------------- network
335 // -------------- BGP
337 function getNextIP() {
339 //var currentIPa = 1;
340 //var currentIPb = 0;
341 //var currentIPc = 0;
346 if(currentIPc > 254) {
350 if(!usePrivateRanges) if(currentIPb == 168 && currentIPa == 192) currentIPb++;
351 if(currentIPb > 254) {
355 // dont publish bogons or 127
356 if(!usePrivateRanges) {
357 if(currentIPa == 10) currentIPa++;
358 if(currentIPa == 127) currentIPa++;
359 if(currentIPa == 128) currentIPa++;
360 if(currentIPa == 172) currentIPa++;
365 if(currentIPa > 223) {
366 console.log("LOG: hit the end of the range, wrapping");
372 //console.log("created "+a+"."+b+"."+c+" from "+i);
373 return currentIPa+"."+currentIPb+"."+currentIPc;
375 ipa = 1+Math.round(Math.random()*223);
376 ipb = 1+Math.round(Math.random()*254);
377 ipc = 1+Math.round(Math.random()*254);
380 if(!usePrivateRanges) {
381 if(ipb == 168 && ipa == 192) ipb++;
383 if(ipa == 127) ipa++;
384 if(ipa == 128) ipa++;
385 if(ipa == 172) ipa++;
388 return ipa+"."+ipb+"."+ipc;
393 function getASPath() {
394 var n = Math.random();
396 return asPaths[Math.round(asPaths.length*n)];
399 function constructUpdateMessage(n_up) {
402 var aspath = getASPath();
403 //console.log("aspath is");
404 //console.log(aspath);
406 // first the header components
409 // next the length component
412 // next the n unfeasible
415 // next, path attr length
419 // now we begin the path attrs
420 // first origin - simple
423 // next as path - hard, flag + type + len + aspath segment
426 // as path segment size = 1 (type), + 1 (len) + as's*2
427 var aspathlen = ((aspath.length+1)*2)+1+1;
428 aspathn += aspathlen;
430 // now next hop attrs = flag (1) + type (1) + len (1) + octets (4);
434 // now nlri = prefix len (1) + prefix fixed in our case (3)
440 //console.log("size: " + bsize + ", an: " + aspathn + " al:" + aspathlen);
441 var buf = new Buffer(bsize);
444 // now lets create the buffer
445 buf.fill(0xff, bp, bp+16);
447 buf.writeUInt16BE(bsize, bp);
449 buf.writeUInt8(2, bp);
451 buf.writeUInt16BE(0, bp);
453 buf.writeUInt16BE(aspathn, bp);
458 buf.writeUInt8(0x40, bp);
460 buf.writeUInt8(1, bp);
462 buf.writeUInt8(1, bp);
464 buf.writeUInt8(0, bp);
468 buf.writeUInt8(0x40, bp);
470 buf.writeUInt8(2, bp);
472 buf.writeUInt8(aspathlen, bp);
474 buf.writeUInt8(2, bp);
476 buf.writeUInt8(aspath.length+1, bp);
478 //console.log("writing in my aspath: "+myas);
479 buf.writeUInt16BE(myAS, bp);
481 aspath.forEach(function (ed) {
482 //console.log("writing in aspath: "+ed);
483 buf.writeUInt16BE(ed, bp);
488 buf.writeUInt8(0x40, bp);
490 buf.writeUInt8(3, bp);
492 buf.writeUInt8(4, bp);
494 myIP.split(".").forEach(function (ed) {
495 //console.log("writing in next hop info: " + ed);
496 buf.writeUInt8(parseInt(ed), bp);
501 for(var nn=0; nn < n_up; nn++) {
502 //console.log("bsize: "+bsize+" bp "+bp);
503 buf.writeUInt8(24, bp);
505 var ip = getNextIP();
506 ip.split(".").forEach(function(ed){
507 //console.log("Writing in nlri: "+ed);
508 buf.writeUInt8(parseInt(ed), bp);
516 //console.log("buf is:");
518 //console.log(buf.length);
523 function createAsPathArray(size) {
524 for(var i=0; i<size; i++) {
525 asPaths[i] = createaspath(i);
530 function createaspath(i) {
533 var ret = new Array();
535 for(var t=0; t<n; t++) {
537 as = 1024 + (i%30000);
543 function parseBuffer(b, c) {
544 var len = b.readUInt16BE(16);
545 var type = b.readUInt8(18);
547 //console.log("got input: " + len + ", type: " + type);
550 var vers = b.readUInt8(19);
551 var as = b.readUInt16BE(20);
552 var ht = b.readUInt16BE(22);
553 var ot1 = b.readUInt8(24);
554 var ot2 = b.readUInt8(25);
555 var ot3 = b.readUInt8(26);
556 var ot4 = b.readUInt8(27);
557 var opl = b.readUInt8(28);
558 //console.log("got open type, vers: "+vers+", as: " + as);
559 //console.log("ht: " + ht + ", id: "+ot1+"."+ot2+"."+ot3+"."+ot4+", opl: "+opl);
562 //console.log("sending our open type");
563 var out = new Buffer(29);
566 out.fill(0xff, 0, 16);
567 out.writeUInt16BE(29, 16);
568 out.writeUInt8(1, 18);
569 out.writeUInt8(4, 19);
570 out.writeUInt16BE(myAS, 20);
571 out.writeUInt16BE(90, 22);
572 out.writeUInt8(10, 24);
573 out.writeUInt8(99, 25);
574 out.writeUInt8(99, 26);
575 out.writeUInt8(1,27);
576 out.writeUInt8(0,28);
579 } else if(type == 4) {
580 //console.log("writing keepalive - exact as sent");
581 console.log("LOG: keepalive from remote ("+c.remoteAddress+")");
584 updateState("ready");
585 //if(updateSent ==0) beginUpdateSend(c);
586 } else if(type == 2) {
587 //console.log("got update...");
588 console.log("LOG: update from remote ("+c.remoteAddress+")");
590 updateState("ready");
591 } else if(type == 3) {
592 var loc = b.readUInt8(19);
593 var msg = b.readUInt8(20);
594 var fromremote = parseNotifyMessage(loc, msg);
595 console.log("LOG: Notification message from server ("+loc+"/"+msg+"): " + fromremote);
597 //console.log("sending end...");
605 function parseNotifyMessage(loc, msg) {
609 retmsg += "Header Error - ";
610 if(msg == 1) retmsg += "Not Synchronised";
611 else if(msg == 2) retmsg += "Bad Message Length";
612 else if(msg == 3) retmsg += "Bad Message Type";
613 else retmsg += "Unknown error code: "+msg;
616 retmsg += "Open Error - ";
617 if(msg == 1) retmsg += "Unsupported Version";
618 else if(msg == 2) retmsg += "AS Missmatch";
619 else if(msg == 3) retmsg += "Bad BGP ID";
620 else if(msg == 4) retmsg += "Unsupported Option Parameter";
621 else retmsg += "Unknown error code: "+msg;
624 retmsg += "Update Error - ";
625 if(msg == 1) retmsg += "Malformed attribute list";
626 else if(msg == 2) retmsg += "Unknown recognised well-known attribute";
627 else if(msg == 3) retmsg += "Missing well-known attribute";
628 else if(msg == 4) retmsg += "Attribute flag error";
629 else if(msg == 5) retmsg += "Attribute length error";
630 else if(msg == 6) retmsg += "Invalid origin attribute";
631 else if(msg == 7) retmsg += "Deprecated error message (other end is waaay too old)";
632 else if(msg == 8) retmsg += "Invalid next hop attribute";
633 else if(msg == 9) retmsg += "Optional attribute error";
634 else if(msg == 10) retmsg += "Invalid network field";
635 else if(msg == 11) retmsg += "Malformed AS path";
636 else retmsg += "Unknown error code: "+msg;
639 retmsg += "Hold Timer Expired - ";
642 retmsg += "Finite State Machine error - "+msg;
645 retmsg += "Unknown erorr type - "+msg;