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": []
 | 
					, "answer": []
 | 
				
			||||||
, "authority": []
 | 
					, "authority": []
 | 
				
			||||||
, "additional": []
 | 
					, "additional": []
 | 
				
			||||||
 | 
					, "edns_options": []
 | 
				
			||||||
, "byteLength": 44
 | 
					, "byteLength": 44
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										117
									
								
								dns.packer.js
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								dns.packer.js
									
									
									
									
									
								
							@ -1,15 +1,21 @@
 | 
				
			|||||||
(function (exports) {
 | 
					(function (exports) {
 | 
				
			||||||
'use strict';
 | 
					'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 = {
 | 
					var dnspack = exports.DNS_PACKER = {
 | 
				
			||||||
  pack: function (packet) {
 | 
					  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 total = 0;
 | 
				
			||||||
    var id = packet.header.id;                      // 2 bytes
 | 
					    var id = packet.header.id;                      // 2 bytes
 | 
				
			||||||
    var header = dnspack.packHeader(packet.header); // 2 bytes
 | 
					    var header = dnspack.packHeader(packet.header); // 2 bytes
 | 
				
			||||||
    total = 12;                                     // 2+2+2+2 bytes ({qd,an,ns,ar}count)
 | 
					    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(0, id, false);
 | 
				
			||||||
    dv.setUint16(2, header, false);
 | 
					    dv.setUint16(2, header, false);
 | 
				
			||||||
    dv.setUint16(4, packet.question.length, 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)
 | 
					    // EDNS is added as an additional with TYPE 41 (OPT, 0x29)
 | 
				
			||||||
    dv.setUint16(10, packet.additional.length + (packet.payload ? 1 : 0), false);
 | 
					    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) {
 | 
					, packHeader: function(h) {
 | 
				
			||||||
    var val = 0;
 | 
					    var val = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -36,6 +146,7 @@ var dnspack = exports.DNS_PACKER = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return val;
 | 
					    return val;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}('undefined' !== typeof window ? window : exports));
 | 
					}('undefined' !== typeof window ? window : exports));
 | 
				
			||||||
 | 
				
			|||||||
@ -232,6 +232,7 @@ pdns.unpack = function (ab) {
 | 
				
			|||||||
    packet.authority.push(rec);
 | 
					    packet.authority.push(rec);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  packet.edns_options = [];
 | 
				
			||||||
  packet.additional = [];
 | 
					  packet.additional = [];
 | 
				
			||||||
  for (i = 0; i < packet.arcount; i += 1) {
 | 
					  for (i = 0; i < packet.arcount; i += 1) {
 | 
				
			||||||
    rec = unpackAnswer(ab, dv, ui8, total);
 | 
					    rec = unpackAnswer(ab, dv, ui8, total);
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,7 @@ var types = exports.DNS_TYPES = {
 | 
				
			|||||||
, OPT: 		0x29  //  41
 | 
					, OPT: 		0x29  //  41
 | 
				
			||||||
, ANY: 		0xff  // 255
 | 
					, ANY: 		0xff  // 255
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// and in reverse
 | 
					// and in reverse
 | 
				
			||||||
Object.keys(types).forEach(function (key) {
 | 
					Object.keys(types).forEach(function (key) {
 | 
				
			||||||
  types[types[key]] = key;
 | 
					  types[types[key]] = key;
 | 
				
			||||||
 | 
				
			|||||||
@ -32,9 +32,9 @@
 | 
				
			|||||||
      h = '0' + h;
 | 
					      h = '0' + h;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return 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);
 | 
					    var lead = bytecount.toString(16);
 | 
				
			||||||
    bytecount += 10;
 | 
					    bytecount += 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (lead.length < 7) {
 | 
					    while (lead.length < 7) {
 | 
				
			||||||
      lead = '0' + lead;
 | 
					      lead = '0' + lead;
 | 
				
			||||||
@ -51,10 +51,15 @@
 | 
				
			|||||||
  console.log('DEBUG with hexdump: ');
 | 
					  console.log('DEBUG with hexdump: ');
 | 
				
			||||||
  console.log('hexdump ' + onefile.replace(/\.[^\.]*$/, '.bin'));
 | 
					  console.log('hexdump ' + onefile.replace(/\.[^\.]*$/, '.bin'));
 | 
				
			||||||
  console.log('');
 | 
					  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(str + '\n' + trail);
 | 
				
			||||||
  console.log('');
 | 
					  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);
 | 
					  process.exit(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}());
 | 
					}());
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user