new bgp fake script
[random_node_code.git] / bgpfake / bf2.js
1 var readline = require('readline');
2 var net = require('net');
3
4
5
6 // ---- vars
7
8 var asPaths = new Array();
9 var readyToSend = false;
10 var currentPrompt;
11 var rl;
12 var nCons = 0;
13 var nSent = 0;
14 var myAS;
15 var myIP;
16 var server;
17 var cState = "starting";
18 var currentIPa = 1;
19 var currentIPb = 0;
20 var currentIPc = 0;
21 var timerIntervalObject;
22 var currentCon = 0;
23 var sequentialIPs = true;
24 var usePrivateRanges = false;
25
26 // ---- vars
27
28
29 if(typeof process.argv[2] == "undefined") {
30         usage();
31 }
32
33 if(typeof process.argv[3] == "undefined") {
34         usage();
35 }
36
37 function usage() {
38         console.log("Usage: "+process.argv[1]+" MyAS MyIP");
39         process.exit(1);
40 }
41
42
43
44
45
46 // ----------- startup
47
48 myAS = process.argv[2];
49 myIP = process.argv[3];
50
51
52 startCLI();
53 doPrompt();
54 createAsPathArray(1048576);
55 startServer();
56 cState = "idle";
57 doPrompt();
58
59 // ----------- startup
60
61
62
63
64
65
66
67
68
69
70 // --------- CLI
71
72 function updatePrompt() {
73         currentPrompt = "("+myAS+"/"+myIP+") "+cState+":"+nCons+"/"+nSent+" ("+currentIPa+"."+currentIPb+"."+currentIPc+") > ";
74 }
75
76 function startCLI() {
77         currentPrompt = "("+myAS+"/"+myIP+") starting... > ";
78
79         rl = readline.createInterface({
80                   input: process.stdin,
81                   output: process.stdout
82                 });
83         
84         rl.on('line', function (cmd) {
85                 switch(cmd) {
86                 
87                 case "?":
88                 case "help":
89                 case "h":
90                         printCLIUsage();
91                         break;
92                 case "r":
93                         currentIPa = 1;
94                         currentIPb = 0;
95                         currentIPc = 0;
96                         break;
97                 case "a":
98                         togglePrivateRange();
99                         break;
100                 case "t":
101                         toggleIPChoice();
102                         break;
103                 case "s":
104                         printStatus();
105                         break;
106                 case "u":
107                         startUpdates();
108                         break;
109                 case "p":
110                         stopUpdates();
111                         break;
112                 case "q":
113                 case "quit":
114                 case "end":
115                           rl.close();
116                           process.exit(0);
117                           break;
118                 case "":
119                         break;
120                 }
121                 
122                 doPrompt();
123         });
124 }
125
126 function togglePrivateRange() {
127         if(usePrivateRanges) {
128                 console.log("Switching off private range publication");
129                 usePrivateRanges = false;
130         } else {
131                 console.log("Switching on private range publication");
132                 usePrivateRanges = true;
133         }
134 }
135
136 function toggleIPChoice() {
137         if(sequentialIPs) {
138                 sequentialIPs = false;
139                 console.log("Switching to random IP addresses");
140         } else {
141                 console.log("Switching to sequential IP addresses");
142                 sequentialIPs = true;
143         }
144         
145         
146 }
147
148 function doPrompt() {
149         updatePrompt();
150         rl.setPrompt(currentPrompt);
151         rl.prompt();    
152 }
153
154 function printCLIUsage() {
155         console.log("Help");
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)");
166 }
167
168 function updateState(newstate) {
169         if(cState == newstate) {
170                 doPrompt();
171                 return;
172         }
173         
174         //starting
175         if(newstate == "starting") {
176                 cState = newstate;
177                 doPrompt();
178                 return;
179         }
180         
181         // idle
182         if(newstate == "idle") {
183                 cState = newstate;
184                 doPrompt();
185                 return;
186         }
187
188         // connected
189         if(newstate == "connected") {
190                 cState = newstate;
191                 doPrompt();
192                 return;
193         }
194         
195         // ready
196         if(newstate == "ready") {
197                 if(cState == "sending") return;
198                 cState = newstate;
199                 doPrompt();
200                 return;
201         }
202
203         // sending
204         if(newstate == "sending") {
205                 cState = newstate;
206                 doPrompt();
207                 return;
208         }
209         
210         if(newstate == "stopping") {
211                 cState = "stopping";
212                 doPrompt();
213                 return;
214         }
215
216         
217 }
218
219 // ------------- CLI
220
221
222
223
224
225
226
227
228
229
230
231
232
233 //------------- network
234
235 function startUpdates() {
236         if(cState == "sending") {
237                 console.log("LOG: already sending...");
238                 return;
239         }
240         
241         if(cState != "ready") {
242                 console.log("LOG: not ready to send yet");
243                 return;
244         }
245         
246         
247         // here goes nothing
248         console.log("LOG: starting update sending");
249         updateState("sending");
250         timerIntervalObject = setInterval(sendUpdate, 5);
251         //console.log("LOG: stopped sending updates");
252 }
253
254
255 function sendUpdate()
256 {
257         if(cState != "sending") {
258                 console.log("oh, your killing me now?");
259                 clearInterval(timerIntervalObject);
260                 updateState("ready");
261         } else {
262                 for(var i=0; i<10; i++) {
263                         var msg = constructUpdateMessage(100);
264                         currentCon.write(msg);
265                 }
266         }
267         
268 }
269
270
271 function stopUpdates() {
272         if(cState != "sending") {
273                 console.log("LOG: not in a sending state, cant pause.");
274                 return;
275         }
276         
277         updateState("stopping");
278 }
279
280 function serverconnection(c) {
281
282         scon = c;
283
284         c.on("end", function() {
285                 //console.log("Server disconnected");
286                 nCons--;
287                 if(nCons < 1) {
288                         cState = "idle";
289                         doPrompt();
290                 }
291                 currentCon = 0;
292         });
293
294         c.on("data", function(buffer) {
295                 parseBuffer(buffer, c);
296         });
297         
298
299         currentCon = c;
300         
301         cState = "connected";
302         nCons++;
303         doPrompt();
304         
305
306
307         console.log("LOG: connection from "+c.remoteAddress);
308         doPrompt();
309
310         //c.write("hello\r\n");
311 }
312
313
314 function startServer() {
315         server = net.createServer(serverconnection);
316
317         server.listen(179, function() {
318                 //console.log("LOG: Server bound");
319                 doPrompt();
320         });
321         
322 }
323
324 //------------- network
325
326
327
328
329
330
331
332
333
334
335 // -------------- BGP 
336
337 function getNextIP() {
338         // split into octets
339         //var currentIPa = 1;
340         //var currentIPb = 0;
341         //var currentIPc = 0;
342
343         
344         if(sequentialIPs) {
345                 currentIPc++;
346                 if(currentIPc > 254) {
347                         
348                         currentIPb++;
349                         currentIPc = 0;
350                         if(!usePrivateRanges) if(currentIPb == 168 && currentIPa == 192) currentIPb++;
351                         if(currentIPb > 254) {
352                                 currentIPa++;
353                                 currentIPb = 0;
354                                 
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++;
361                                 }
362                         }
363                 }
364                 
365                 if(currentIPa > 223) {
366                         console.log("LOG: hit the end of the range, wrapping");
367                         currentIPa = 1;
368                         currentIPb = 0;
369                         currentIPc = 0;
370                 }
371                 
372                 //console.log("created "+a+"."+b+"."+c+" from "+i);
373                 return currentIPa+"."+currentIPb+"."+currentIPc;
374         } else {
375                 ipa = 1+Math.round(Math.random()*223);
376                 ipb = 1+Math.round(Math.random()*254);
377                 ipc = 1+Math.round(Math.random()*254);
378                 
379                 
380                 if(!usePrivateRanges) {
381                         if(ipb == 168 && ipa == 192) ipb++;
382                         if(ipa == 10) ipa++;
383                         if(ipa == 127) ipa++;
384                         if(ipa == 128) ipa++;                   
385                         if(ipa == 172) ipa++;
386                 }                       
387
388                 return ipa+"."+ipb+"."+ipc;
389         }
390
391 }
392
393 function getASPath() {
394         var n = Math.random();
395         
396         return asPaths[Math.round(asPaths.length*n)];
397 }
398
399 function constructUpdateMessage(n_up) {
400         var bsize = 0;
401
402         var aspath = getASPath();
403         //console.log("aspath is");
404         //console.log(aspath);
405         
406         // first the header components
407         bsize += 16;
408
409         // next the length component
410         bsize += 2;
411
412         // next the n unfeasible
413         bsize += 2;
414
415         // next, path attr length
416         bsize += 2;
417
418
419         // now we begin the path attrs
420         // first origin - simple
421         var aspathn = 4;
422
423         // next as path - hard, flag + type + len + aspath segment
424         aspathn += 3;
425
426         // as path segment size = 1 (type), + 1 (len) + as's*2
427         var aspathlen = ((aspath.length+1)*2)+1+1;
428         aspathn += aspathlen;
429         
430         // now next hop attrs = flag (1) + type (1) + len (1) + octets (4);
431         aspathn += 7;
432         bsize += aspathn;
433
434         // now nlri = prefix len (1) + prefix fixed in our case (3)
435         bsize += 4*n_up;
436
437         // fudge
438         bsize+=1;
439
440         //console.log("size: " + bsize + ", an: " + aspathn + " al:" + aspathlen);
441         var buf = new Buffer(bsize);
442         var bp = 0;
443
444         // now lets create the buffer
445         buf.fill(0xff, bp, bp+16);
446         bp+=16;
447         buf.writeUInt16BE(bsize, bp);
448         bp+=2;
449         buf.writeUInt8(2, bp);
450         bp++;
451         buf.writeUInt16BE(0, bp);
452         bp+=2;
453         buf.writeUInt16BE(aspathn, bp);
454         bp+=2;
455
456         // path attr
457         // origin
458         buf.writeUInt8(0x40, bp);
459         bp++;
460         buf.writeUInt8(1, bp);
461         bp++;
462         buf.writeUInt8(1, bp);
463         bp++;
464         buf.writeUInt8(0, bp);
465         bp++;
466
467         // as path
468         buf.writeUInt8(0x40, bp);
469         bp++;
470         buf.writeUInt8(2, bp);
471         bp++;
472         buf.writeUInt8(aspathlen, bp);
473         bp++;
474         buf.writeUInt8(2, bp);
475         bp++;
476         buf.writeUInt8(aspath.length+1, bp);
477         bp++;
478         //console.log("writing in my aspath: "+myas);
479         buf.writeUInt16BE(myAS, bp);
480         bp+=2;
481         aspath.forEach(function (ed) {
482                 //console.log("writing in aspath: "+ed);
483                 buf.writeUInt16BE(ed, bp);
484                 bp+=2;
485         });
486
487         // next hop
488         buf.writeUInt8(0x40, bp);
489         bp++;
490         buf.writeUInt8(3, bp);
491         bp++;
492         buf.writeUInt8(4, bp);
493         bp++;
494         myIP.split(".").forEach(function (ed) {
495                 //console.log("writing in next hop info: " + ed);
496                 buf.writeUInt8(parseInt(ed), bp);
497                 bp++;
498         }); 
499
500         // last, nlri
501         for(var nn=0; nn < n_up; nn++) {
502                 //console.log("bsize: "+bsize+" bp "+bp);
503                 buf.writeUInt8(24, bp);
504                 bp++;
505                 var ip = getNextIP();
506                 ip.split(".").forEach(function(ed){
507                         //console.log("Writing in nlri: "+ed);
508                         buf.writeUInt8(parseInt(ed), bp);
509                         bp++;
510                 });
511         }
512         
513         
514         nSent += n_up;
515
516         //console.log("buf is:");
517         //console.log(buf);
518         //console.log(buf.length);
519
520         return buf;
521 }
522
523 function createAsPathArray(size) {
524         for(var i=0; i<size; i++) {
525                 asPaths[i] = createaspath(i);
526         }
527 }
528
529
530 function createaspath(i) {
531         var n=(i%5)+2;
532         var as = 1024;
533         var ret = new Array();
534
535         for(var t=0; t<n; t++) {
536                 i = i << 1;
537                 as = 1024 + (i%30000);
538                 ret[t] = as;
539         }
540         return ret;
541 }
542
543 function parseBuffer(b, c) {
544         var len = b.readUInt16BE(16);
545         var type = b.readUInt8(18);
546
547         //console.log("got input: " + len + ", type: " + type);
548
549         if(type == 1) {
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);
560
561
562                 //console.log("sending our open type");
563                 var out = new Buffer(29);
564
565
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);
577
578                 c.write(out);
579         } else if(type == 4) {
580                 //console.log("writing keepalive - exact as sent");
581                 console.log("LOG: keepalive from remote ("+c.remoteAddress+")");
582                 c.write(b);
583                 readyToSend = true;
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+")");
589                 readyToSend = true;
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);
596         } else {
597                 //console.log("sending end...");
598                 c.end();
599         }
600
601         doPrompt();
602         
603 }
604
605 function parseNotifyMessage(loc, msg) {
606         var retmsg = "";
607         switch(loc) {
608                 case 1:
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;
614                         break;
615                 case 2:
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;
622                         break;
623                 case 3:
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;
637                         break;
638                 case 4:
639                         retmsg += "Hold Timer Expired - ";
640                         break;
641                 case 5:
642                         retmsg += "Finite State Machine error - "+msg;
643                         break;
644                 default:
645                         retmsg += "Unknown erorr type - "+msg; 
646         }
647         
648         return retmsg;
649         
650 }
651
652 //-------------- BGP