dns-suite.js/node_modules/dns-js/lib/bufferconsumer.js

170 lines
4.0 KiB
JavaScript

/* global Buffer */
var debug = require('debug')('mdns-packet:lib:dns:bufferconsumer');
var util = require('util');
var LABEL_POINTER = 0xc0;
var BufferConsumer = module.exports = function BufferConsumer(arg) {
if (!(arg instanceof Buffer)) {
debug('arg', arg);
throw new Error('Expected instance of Buffer');
}
this.buffer = arg;
this.length = this.buffer.length;
debug('new consumer of %d bytes', this.length);
this._offset = 0;
};
BufferConsumer.prototype.tell = function () {
return this._offset;
};
BufferConsumer.prototype.seek = function (pos) {
debug('seek(%d)', pos);
if (pos < 0) {
throw new Error('Negative pos not allowed');
}
if (pos > this.length) {
debug('bad packet', this.buffer.toString('hex'));
throw new Error(util.format('Cannot seek after EOF. %d > %d',
pos, this.length));
}
this._offset = pos;
return this;
};
BufferConsumer.prototype.slice = function (length) {
var v;
if (typeof length === 'undefined') {
v = this.buffer.slice(this._offset);
this._offset = this.length - 1;
return v;
}
else {
if ((this._offset + length) > this.length) {
debug('Buffer owerflow. Slice beyond buffer.', {
offset: this._offset,
length: length,
bufferLength: this.length
});
debug('so far', this);
throw new Error('Buffer overflow');
}
v = this.buffer.slice(this._offset, this._offset + length);
this._offset += length;
return v;
}
};
BufferConsumer.prototype.isEOF = function () {
return this._offset >= this.length;
};
BufferConsumer.prototype.byte = function () {
this._offset += 1;
return this.buffer.readUInt8(this._offset - 1);
};
BufferConsumer.prototype.short = function () {
debug('reading short at %d of %d', this._offset, this.length);
this._offset += 2;
return this.buffer.readUInt16BE(this._offset - 2);
};
BufferConsumer.prototype.long = function () {
this._offset += 4;
return this.buffer.readUInt32BE(this._offset - 4);
};
BufferConsumer.prototype.string = function (encoding, length) {
var end;
var ret;
if (length === undefined) {
end = this.buffer.length;
}
else {
end = this.tell() + length;
// if (end > this.length) {
// throw new errors.MalformedPacket(
// 'Trying to read past eof. Start=%d, End=%s, Length=%s',
// this.tell(), end, this.length);
// }
}
if (!encoding) {
encoding = 'utf8';
}
ret = this.buffer.toString(encoding, this._offset, end);
debug('got a %s character string:', length, ret);
this.seek(end);
return ret;
};
/**
* Consumes a DNS name, which will either finish with a NULL byte or a suffix
* reference (i.e., 0xc0 <ref>).
*/
BufferConsumer.prototype.name = function (join, endAt) {
debug('.name(join:%s, endAt:%s)', join, endAt);
if (typeof join === 'undefined') { join = true; }
var parts = [];
var ret;
var len;
var pos;
var end;
var comp = false;
len = this.byte();
debug('name initial len', len);
if (len === 0) {
parts.push('');
}
while (len !== 0) {
if ((len & LABEL_POINTER) === LABEL_POINTER) {
debug('has label');
len -= LABEL_POINTER;
len = len << 8;
pos = len + this.byte();
if (!comp) {
end = this.tell();
}
this.seek(pos);
len = this.byte();
comp = true;
continue;
}
debug('no label');
// Otherwise, consume a string!
var v = this.string('utf8', len);
if (v.length > 0) {
parts.push(v);
}
if (endAt && this.tell() >= endAt) {
debug('leaving at', endAt);
break;
}
len = this.byte();
debug('got len', len);
}
if (!comp) {
end = this.tell();
}
debug('ended with %d parts at %d', parts.length, end);
this.seek(end);
if (join) {
ret = parts.join('.');
}
else {
ret = parts;
}
debug('ret', ret);
return ret;
};