WIP Packer
This commit is contained in:
		
							parent
							
								
									367c0207d0
								
							
						
					
					
						commit
						12fef62e09
					
				| @ -43,6 +43,7 @@ Similar API to `dns.js` and `native-dns-packet`. | ||||
| , "answer": [] | ||||
| , "authority": [] | ||||
| , "additional": [] | ||||
| , "edns_options": [] | ||||
| , "byteLength": 44 | ||||
| } | ||||
| ``` | ||||
|  | ||||
							
								
								
									
										117
									
								
								dns.packer.js
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								dns.packer.js
									
									
									
									
									
								
							| @ -1,15 +1,21 @@ | ||||
| (function (exports) { | ||||
| 'use strict'; | ||||
| 
 | ||||
| var classes = exports.DNS_CLASSES || require('./dns.classes.js').DNS_CLASSES; | ||||
| var types = exports.DNS_TYPES || require('./dns.types.js').DNS_TYPES; | ||||
| 
 | ||||
| var dnspack = exports.DNS_PACKER = { | ||||
|   pack: function (packet) { | ||||
| 
 | ||||
|     // TODO update for edns payload size
 | ||||
|     var ab = new ArrayBuffer(576);                  // http://serverfault.com/a/587626/93930
 | ||||
|     var dv = new DataView(ab); | ||||
|     var labelsMap = {}; | ||||
|     var total = 0; | ||||
|     var id = packet.header.id;                      // 2 bytes
 | ||||
|     var header = dnspack.packHeader(packet.header); // 2 bytes
 | ||||
|     total = 12;                                     // 2+2+2+2 bytes ({qd,an,ns,ar}count)
 | ||||
| 
 | ||||
|     var ab = new ArrayBuffer(total); | ||||
|     var dv = new DataView(ab); | ||||
|     dv.setUint16(0, id, false); | ||||
|     dv.setUint16(2, header, false); | ||||
|     dv.setUint16(4, packet.question.length, false); | ||||
| @ -18,8 +24,112 @@ var dnspack = exports.DNS_PACKER = { | ||||
|     // EDNS is added as an additional with TYPE 41 (OPT, 0x29)
 | ||||
|     dv.setUint16(10, packet.additional.length + (packet.payload ? 1 : 0), false); | ||||
| 
 | ||||
|     return ab; | ||||
|     function lint(r) { | ||||
|       if (!r.name) { | ||||
|         throw new Error("missing name"); | ||||
|       } | ||||
| 
 | ||||
|       if (!r.class) { | ||||
|         if (!r.className) { | ||||
|           throw new Error("no className"); | ||||
|         } | ||||
|         r.class = classes[r.className]; | ||||
|       } | ||||
| 
 | ||||
|       if (!r.type) { | ||||
|         if (!r.typeName) { | ||||
|           throw new Error("no typeName"); | ||||
|         } | ||||
|         r.type = types[r.typeName]; | ||||
|         if (!r.type) { | ||||
|           console.warn("ignoring invalid type '" + r.type + "' for '" + r.name + "', ignoring"); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     function packLabel(sequence, terminates) { | ||||
|       if (terminates) { | ||||
|         // we don't want non-terminating rdata cached, just terminating names
 | ||||
|         labelsMap[total] = { total: total, name: sequence }; | ||||
|         labelsMap[sequence] = labelsMap[total]; | ||||
|       } | ||||
|       sequence.split('.').forEach(function (label) { | ||||
|         dv.setUint8(total, label.length, false); | ||||
|         total += 1; | ||||
| 
 | ||||
|         label.split('').forEach(function (ch) { | ||||
|           dv.setUint8(total, ch.charCodeAt(0), false); | ||||
|           total += 1; | ||||
|         }); | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|     function packQuestion(q) { | ||||
|       lint(q); | ||||
| 
 | ||||
|       packLabel(q.name); | ||||
|       // trailing 0 (null) as label sequence terminator
 | ||||
|       dv.setUint8(total, 0, false); | ||||
|       total += 1; | ||||
| 
 | ||||
|       dv.setUint16(total, q.type, false); | ||||
|       dv.setUint16(total + 2, q.class, false); | ||||
|       total += 4; // two bytes type two bytes class
 | ||||
|     } | ||||
| 
 | ||||
|     function packRdata(a) { | ||||
|       dv.setUint16(total, 8, false); | ||||
|       total += 2; | ||||
|       dv.setUint32(total, 0xFFFFFFFF, false) | ||||
|       total += 4; | ||||
|       dv.setUint32(total, 0xFFFFFFFF, false) | ||||
|       total += 4; | ||||
|       //throw new Error('not implemented');
 | ||||
|     } | ||||
| 
 | ||||
|     function packAnswer(a) { | ||||
|       packQuestion(a); | ||||
| 
 | ||||
|       if ('undefined' === typeof a.ttl) { | ||||
|         throw new Error("missing ttl"); | ||||
|       } | ||||
| 
 | ||||
|       // 32-bit ttl
 | ||||
|       dv.setUint32(total, a.ttl, false); | ||||
|       total += 4; | ||||
| 
 | ||||
|       if (a.rdata) { | ||||
|         // 16-bit
 | ||||
|         dv.setUint16(total, a.rdata.byteLength, false); | ||||
|         total += 2; | ||||
|         (new Uint8Array(a.rdata)).forEach(function (b) { | ||||
|           dv.setUint8(total, b, false); | ||||
|           total += 1; | ||||
|         }); | ||||
|       } else { | ||||
|         packRdata(a); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     //console.log(packet);
 | ||||
|     // fixed size, other than labels
 | ||||
| 
 | ||||
|     packet.question.forEach(packQuestion); | ||||
|     packet.answer.forEach(packAnswer); | ||||
|     packet.authority.forEach(packAnswer); | ||||
|     packet.additional.forEach(packAnswer); | ||||
| 
 | ||||
|     // TODO handle compression pointers
 | ||||
|     // TODO handle edns
 | ||||
| 
 | ||||
|     return ab.slice(0, total); | ||||
|   } | ||||
| 
 | ||||
|   /* | ||||
| , packLabels: function(map, labels) { | ||||
|   } | ||||
|   */ | ||||
| 
 | ||||
| , packHeader: function(h) { | ||||
|     var val = 0; | ||||
| 
 | ||||
| @ -36,6 +146,7 @@ var dnspack = exports.DNS_PACKER = { | ||||
| 
 | ||||
|     return val; | ||||
|   } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| }('undefined' !== typeof window ? window : exports)); | ||||
|  | ||||
| @ -232,6 +232,7 @@ pdns.unpack = function (ab) { | ||||
|     packet.authority.push(rec); | ||||
|   } | ||||
| 
 | ||||
|   packet.edns_options = []; | ||||
|   packet.additional = []; | ||||
|   for (i = 0; i < packet.arcount; i += 1) { | ||||
|     rec = unpackAnswer(ab, dv, ui8, total); | ||||
|  | ||||
| @ -14,6 +14,7 @@ var types = exports.DNS_TYPES = { | ||||
| , OPT: 		0x29  //  41
 | ||||
| , ANY: 		0xff  // 255
 | ||||
| }; | ||||
| 
 | ||||
| // and in reverse
 | ||||
| Object.keys(types).forEach(function (key) { | ||||
|   types[types[key]] = key; | ||||
|  | ||||
| @ -32,9 +32,9 @@ | ||||
|       h = '0' + h; | ||||
|     } | ||||
|     return h; | ||||
|   }).join('').match(/.{1,2}/g).join(' ').match(/.{1,47}/g).map(function (str) { | ||||
|   }).join('').match(/.{1,2}/g).join(' ').match(/.{1,48}/g).map(function (str) { | ||||
|     var lead = bytecount.toString(16); | ||||
|     bytecount += 10; | ||||
|     bytecount += 16; | ||||
| 
 | ||||
|     while (lead.length < 7) { | ||||
|       lead = '0' + lead; | ||||
| @ -51,10 +51,15 @@ | ||||
|   console.log('DEBUG with hexdump: '); | ||||
|   console.log('hexdump ' + onefile.replace(/\.[^\.]*$/, '.bin')); | ||||
|   console.log(''); | ||||
|   console.log('        0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F'); | ||||
|   console.log(str + '\n' + trail); | ||||
|   console.log(''); | ||||
| 
 | ||||
|   console.error('test implementation not complete'); | ||||
|   console.error(''); | ||||
|   console.error('!!!'); | ||||
|   console.error('Test implementation not complete.'); | ||||
|   console.error('!!!'); | ||||
|   console.error(''); | ||||
|   process.exit(1); | ||||
| 
 | ||||
| }()); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user