Skip to content

Commit

Permalink
Correct encode/decode for mail name representation
Browse files Browse the repository at this point in the history
  • Loading branch information
M4t7e committed Aug 25, 2023
1 parent 519f55d commit 0c8e8e5
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 8 deletions.
36 changes: 28 additions & 8 deletions index.js
Expand Up @@ -17,15 +17,31 @@ const NOT_QU_MASK = ~QU_MASK

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 (!offset) offset = 0
const oldOffset = offset

// strip leading and trailing .
const n = str.replace(/^\.|\.$/gm, '')
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++) {
const len = buf.write(list[i], offset + 1)
Expand All @@ -42,7 +58,7 @@ name.encode = function (str, buf, offset) {

name.encode.bytes = 0

name.decode = function (buf, offset) {
name.decode = function (buf, offset, mail = false) {
if (!offset) offset = 0

const list = []
Expand All @@ -68,7 +84,11 @@ name.decode = function (buf, offset) {
if (totalLength > 254) {
throw new Error('Cannot decode name (name too long)')
}
list.push(buf.toString('utf-8', offset, offset + len))
if (mail) {
list.push(buf.toString('utf-8', offset, offset + len).replace(/\./g, '\\.'))
} else {
list.push(buf.toString('utf-8', offset, offset + len))
}
offset += len
consumedBytes += jumped ? 0 : len
} else if ((len & 0xc0) === 0xc0) {
Expand Down Expand Up @@ -254,7 +274,7 @@ rsoa.encode = function (data, buf, offset) {
offset += 2
name.encode(data.mname, buf, offset)
offset += name.encode.bytes
name.encode(data.rname, buf, offset)
name.encode(data.rname, buf, offset, true)
offset += name.encode.bytes
buf.writeUInt32BE(data.serial || 0, offset)
offset += 4
Expand Down Expand Up @@ -283,7 +303,7 @@ rsoa.decode = function (buf, offset) {
offset += 2
data.mname = name.decode(buf, offset)
offset += name.decode.bytes
data.rname = name.decode(buf, offset)
data.rname = name.decode(buf, offset, true)
offset += name.decode.bytes
data.serial = buf.readUInt32BE(offset)
offset += 4
Expand Down Expand Up @@ -1007,7 +1027,7 @@ rrp.encode = function (data, buf, offset) {
const oldOffset = offset

offset += 2 // Leave space for length
name.encode(data.mbox || '.', buf, offset)
name.encode(data.mbox || '.', buf, offset, true)
offset += name.encode.bytes
name.encode(data.txt || '.', buf, offset)
offset += name.encode.bytes
Expand All @@ -1024,7 +1044,7 @@ rrp.decode = function (buf, offset) {

const data = {}
offset += 2
data.mbox = name.decode(buf, offset) || '.'
data.mbox = name.decode(buf, offset, true) || '.'
offset += name.decode.bytes
data.txt = name.decode(buf, offset) || '.'
offset += name.decode.bytes
Expand Down
30 changes: 30 additions & 0 deletions test.js
Expand Up @@ -310,6 +310,36 @@ tape('name_encoding', function (t) {
t.ok(packet.name.encode.bytes === 1, 'name 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, 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, true)
t.ok(packet.name.encode.bytes === 21, 'name (mail) encoding length matches')
dd = packet.name.decode(buf, offset, 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, true)
t.ok(packet.name.encode.bytes === 21, 'name (mail) encoding length matches')
dd = packet.name.decode(buf, offset, true)
t.ok(data === dd, 'encode/decode matches')
offset += packet.name.encode.bytes

data = 'root\\.mail'
packet.name.encode(data, buf, offset, true)
t.ok(packet.name.encode.bytes === 11, 'name (mail) encoding length matches')
dd = packet.name.decode(buf, offset, true)
t.ok(data === dd, 'encode/decode matches')
offset += packet.name.encode.bytes

t.end()
})

Expand Down

0 comments on commit 0c8e8e5

Please sign in to comment.