Proper Encoding/Decoding for Email Name Representation for SOA and RP Records (#93)
* Correct encode/decode for mail name representation * Embeddedd `mail` in an option object * Cleaner case distinction in decode function
This commit is contained in:
parent
519f55d403
commit
13f19d9b63
36
index.js
36
index.js
@ -17,7 +17,7 @@ const NOT_QU_MASK = ~QU_MASK
|
|||||||
|
|
||||||
const name = exports.name = {}
|
const name = exports.name = {}
|
||||||
|
|
||||||
name.encode = function (str, buf, offset) {
|
name.encode = function (str, buf, offset, { mail = false } = {}) {
|
||||||
if (!buf) buf = Buffer.alloc(name.encodingLength(str))
|
if (!buf) buf = Buffer.alloc(name.encodingLength(str))
|
||||||
if (!offset) offset = 0
|
if (!offset) offset = 0
|
||||||
const oldOffset = offset
|
const oldOffset = offset
|
||||||
@ -25,7 +25,23 @@ name.encode = function (str, buf, offset) {
|
|||||||
// strip leading and trailing .
|
// strip leading and trailing .
|
||||||
const n = str.replace(/^\.|\.$/gm, '')
|
const n = str.replace(/^\.|\.$/gm, '')
|
||||||
if (n.length) {
|
if (n.length) {
|
||||||
const list = n.split('.')
|
let list = []
|
||||||
|
if (mail) {
|
||||||
|
let localPart = ''
|
||||||
|
n.split('.').forEach(label => {
|
||||||
|
if (label.endsWith('\\')) {
|
||||||
|
localPart += (localPart.length ? '.' : '') + label.slice(0, -1)
|
||||||
|
} else {
|
||||||
|
if (list.length === 0 && localPart.length) {
|
||||||
|
list.push(localPart + '.' + label)
|
||||||
|
} else {
|
||||||
|
list.push(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
list = n.split('.')
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < list.length; i++) {
|
for (let i = 0; i < list.length; i++) {
|
||||||
const len = buf.write(list[i], offset + 1)
|
const len = buf.write(list[i], offset + 1)
|
||||||
@ -42,7 +58,7 @@ name.encode = function (str, buf, offset) {
|
|||||||
|
|
||||||
name.encode.bytes = 0
|
name.encode.bytes = 0
|
||||||
|
|
||||||
name.decode = function (buf, offset) {
|
name.decode = function (buf, offset, { mail = false } = {}) {
|
||||||
if (!offset) offset = 0
|
if (!offset) offset = 0
|
||||||
|
|
||||||
const list = []
|
const list = []
|
||||||
@ -68,7 +84,11 @@ name.decode = function (buf, offset) {
|
|||||||
if (totalLength > 254) {
|
if (totalLength > 254) {
|
||||||
throw new Error('Cannot decode name (name too long)')
|
throw new Error('Cannot decode name (name too long)')
|
||||||
}
|
}
|
||||||
list.push(buf.toString('utf-8', offset, offset + len))
|
let label = buf.toString('utf-8', offset, offset + len)
|
||||||
|
if (mail) {
|
||||||
|
label = label.replace(/\./g, '\\.')
|
||||||
|
}
|
||||||
|
list.push(label)
|
||||||
offset += len
|
offset += len
|
||||||
consumedBytes += jumped ? 0 : len
|
consumedBytes += jumped ? 0 : len
|
||||||
} else if ((len & 0xc0) === 0xc0) {
|
} else if ((len & 0xc0) === 0xc0) {
|
||||||
@ -254,7 +274,7 @@ rsoa.encode = function (data, buf, offset) {
|
|||||||
offset += 2
|
offset += 2
|
||||||
name.encode(data.mname, buf, offset)
|
name.encode(data.mname, buf, offset)
|
||||||
offset += name.encode.bytes
|
offset += name.encode.bytes
|
||||||
name.encode(data.rname, buf, offset)
|
name.encode(data.rname, buf, offset, { mail: true })
|
||||||
offset += name.encode.bytes
|
offset += name.encode.bytes
|
||||||
buf.writeUInt32BE(data.serial || 0, offset)
|
buf.writeUInt32BE(data.serial || 0, offset)
|
||||||
offset += 4
|
offset += 4
|
||||||
@ -283,7 +303,7 @@ rsoa.decode = function (buf, offset) {
|
|||||||
offset += 2
|
offset += 2
|
||||||
data.mname = name.decode(buf, offset)
|
data.mname = name.decode(buf, offset)
|
||||||
offset += name.decode.bytes
|
offset += name.decode.bytes
|
||||||
data.rname = name.decode(buf, offset)
|
data.rname = name.decode(buf, offset, { mail: true })
|
||||||
offset += name.decode.bytes
|
offset += name.decode.bytes
|
||||||
data.serial = buf.readUInt32BE(offset)
|
data.serial = buf.readUInt32BE(offset)
|
||||||
offset += 4
|
offset += 4
|
||||||
@ -1007,7 +1027,7 @@ rrp.encode = function (data, buf, offset) {
|
|||||||
const oldOffset = offset
|
const oldOffset = offset
|
||||||
|
|
||||||
offset += 2 // Leave space for length
|
offset += 2 // Leave space for length
|
||||||
name.encode(data.mbox || '.', buf, offset)
|
name.encode(data.mbox || '.', buf, offset, { mail: true })
|
||||||
offset += name.encode.bytes
|
offset += name.encode.bytes
|
||||||
name.encode(data.txt || '.', buf, offset)
|
name.encode(data.txt || '.', buf, offset)
|
||||||
offset += name.encode.bytes
|
offset += name.encode.bytes
|
||||||
@ -1024,7 +1044,7 @@ rrp.decode = function (buf, offset) {
|
|||||||
|
|
||||||
const data = {}
|
const data = {}
|
||||||
offset += 2
|
offset += 2
|
||||||
data.mbox = name.decode(buf, offset) || '.'
|
data.mbox = name.decode(buf, offset, { mail: true }) || '.'
|
||||||
offset += name.decode.bytes
|
offset += name.decode.bytes
|
||||||
data.txt = name.decode(buf, offset) || '.'
|
data.txt = name.decode(buf, offset) || '.'
|
||||||
offset += name.decode.bytes
|
offset += name.decode.bytes
|
||||||
|
|||||||
37
test.js
37
test.js
@ -310,6 +310,43 @@ tape('name_encoding', function (t) {
|
|||||||
t.ok(packet.name.encode.bytes === 1, 'name encoding length matches')
|
t.ok(packet.name.encode.bytes === 1, 'name encoding length matches')
|
||||||
dd = packet.name.decode(buf, offset)
|
dd = packet.name.decode(buf, offset)
|
||||||
t.ok(data === dd, 'encode/decode matches')
|
t.ok(data === dd, 'encode/decode matches')
|
||||||
|
offset += packet.name.encode.bytes
|
||||||
|
|
||||||
|
data = 'a.b.c.d.example.com'
|
||||||
|
packet.name.encode(data, buf, offset, { mail: false })
|
||||||
|
t.ok(packet.name.encode.bytes === 21, 'name (mail) encoding length matches')
|
||||||
|
dd = packet.name.decode(buf, offset)
|
||||||
|
t.ok(data === dd, 'encode/decode matches')
|
||||||
|
offset += packet.name.encode.bytes
|
||||||
|
|
||||||
|
data = 'a.b.c.d.example.com'
|
||||||
|
packet.name.encode(data, buf, offset, { mail: true })
|
||||||
|
t.ok(packet.name.encode.bytes === 21, 'name (mail) encoding length matches')
|
||||||
|
dd = packet.name.decode(buf, offset)
|
||||||
|
t.ok(data === dd, 'encode/decode matches')
|
||||||
|
offset += packet.name.encode.bytes
|
||||||
|
|
||||||
|
data = 'a\\.b.c.d.example.com'
|
||||||
|
packet.name.encode(data, buf, offset, { mail: true })
|
||||||
|
t.ok(packet.name.encode.bytes === 21, 'name (mail) encoding length matches')
|
||||||
|
dd = packet.name.decode(buf, offset, { mail: true })
|
||||||
|
t.ok(data === dd, 'encode/decode matches')
|
||||||
|
offset += packet.name.encode.bytes
|
||||||
|
|
||||||
|
data = 'a\\.b\\.c.d.example.com'
|
||||||
|
packet.name.encode(data, buf, offset, { mail: true })
|
||||||
|
t.ok(packet.name.encode.bytes === 21, 'name (mail) encoding length matches')
|
||||||
|
dd = packet.name.decode(buf, offset, { mail: true })
|
||||||
|
t.ok(data === dd, 'encode/decode matches')
|
||||||
|
offset += packet.name.encode.bytes
|
||||||
|
|
||||||
|
data = 'root\\.mail'
|
||||||
|
packet.name.encode(data, buf, offset, { mail: true })
|
||||||
|
t.ok(packet.name.encode.bytes === 11, 'name (mail) encoding length matches')
|
||||||
|
dd = packet.name.decode(buf, offset, { mail: true })
|
||||||
|
t.ok(data === dd, 'encode/decode matches')
|
||||||
|
offset += packet.name.encode.bytes
|
||||||
|
|
||||||
t.end()
|
t.end()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user