Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add timestamp to handshake #183

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lib/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ module.exports = function connect (dht, publicKey, opts = {}) {
relaySocket: null,
relayClient: null,
relayPaired: false,
relayKeepAlive: opts.relayKeepAlive || 5000
relayKeepAlive: opts.relayKeepAlive || 5000,

// Used by the server when tie-breaking between two connections from the same peer
timestamp: opts.timestamp ?? -1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this default of -1 makes the timestamp behavior opt in... which may be a pain-in-the-butt for most users, who'll not benefit from this change until they modify their code to pass { timestamp: Date.now() } in the options to connect.

However, I tend to be very conservative when it comes to breaking changes, and my philosophy is usually to make all enhancements "opt in" until the next major version bump, at which time I update the defaults.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just use 0 as the default, then the uint can be unsigned, and 0 is pretty appropriate for that. also means we can just do || 0

}

// If the raw stream receives an error signal pre connect (ie from the firewall hook), make sure
Expand Down Expand Up @@ -374,7 +377,8 @@ async function connectThroughNode (c, address, socket) {
secretStream: {},
relayThrough: c.relayThrough
? { publicKey: c.relayThrough, token: c.relayToken }
: null
: null,
timestamp: c.timestamp
})
if (isDone(c)) return
}
Expand Down Expand Up @@ -410,6 +414,8 @@ async function connectThroughNode (c, address, socket) {
serverAddress,
payload
}
c.encryptedSocket.userData ??= {}
c.encryptedSocket.userData.timestamp = payload.timestamp
billiegoose marked this conversation as resolved.
Show resolved Hide resolved

c.payload = new SecurePayload(hs.holepunchSecret)

Expand Down
9 changes: 7 additions & 2 deletions lib/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ exports.noisePayload = {
if (m.udx) udxInfo.preencode(state, m.udx)
if (m.secretStream) secretStreamInfo.preencode(state, m.secretStream)
if (m.relayThrough) relayThroughInfo.preencode(state, m.relayThrough)
if (m.timestamp >= 0) c.uint.preencode(state, m.timestamp)
billiegoose marked this conversation as resolved.
Show resolved Hide resolved
},
encode (state, m) {
let flags = 0
Expand All @@ -172,6 +173,7 @@ exports.noisePayload = {
if (m.udx) flags |= 8
if (m.secretStream) flags |= 16
if (m.relayThrough) flags |= 32
if (m.timestamp >= 0) flags |= 64

c.uint.encode(state, 1) // version
c.uint.encode(state, flags)
Expand All @@ -184,6 +186,7 @@ exports.noisePayload = {
if (m.udx) udxInfo.encode(state, m.udx)
if (m.secretStream) secretStreamInfo.encode(state, m.secretStream)
if (m.relayThrough) relayThroughInfo.encode(state, m.relayThrough)
if (m.timestamp >= 0) c.uint.encode(state, m.timestamp)
},
decode (state) {
const version = c.uint.decode(state)
Expand All @@ -200,7 +203,8 @@ exports.noisePayload = {
addresses6: [],
udx: null,
secretStream: null,
relayThrough: null
relayThrough: null,
timestamp: -1
}
}

Expand All @@ -215,7 +219,8 @@ exports.noisePayload = {
addresses6: (flags & 4) !== 0 ? ipv6Array.decode(state) : [],
udx: (flags & 8) !== 0 ? udxInfo.decode(state) : null,
secretStream: (flags & 16) !== 0 ? secretStreamInfo.decode(state) : null,
relayThrough: (flags & 32) !== 0 ? relayThroughInfo.decode(state) : null
relayThrough: (flags & 32) !== 0 ? relayThroughInfo.decode(state) : null,
timestamp: (flags & 64) !== 0 ? c.uint.decode(state) : -1
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ module.exports = class Server extends EventEmitter {
keepAlive: this.dht.connectionKeepAlive
})

hs.encryptedSocket.userData ??= {}
hs.encryptedSocket.userData.timestamp = remotePayload.timestamp
this.onconnection(hs.encryptedSocket)
}

Expand Down Expand Up @@ -355,7 +357,8 @@ module.exports = class Server extends EventEmitter {
secretStream: {},
relayThrough: relayThrough
? { publicKey: relayThrough, token: hs.relayToken }
: null
: null,
timestamp: Date.now()
})
} catch (err) {
safetyCatch(err)
Expand Down Expand Up @@ -650,6 +653,8 @@ module.exports = class Server extends EventEmitter {

hs.encryptedSocket = this.createSecretStream(false, rawStream, { handshake: h })

hs.encryptedSocket.userData ??= {}
hs.encryptedSocket.userData.timestamp = remotePayload.timestamp
this.onconnection(hs.encryptedSocket)
})

Expand Down
44 changes: 39 additions & 5 deletions test/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ test('basic noise payload', function (t) {
addresses6: [],
udx: null,
secretStream: null,
relayThrough: null
relayThrough: null,
timestamp: -1
}

m.noisePayload.preencode(state, c)
Expand Down Expand Up @@ -56,7 +57,8 @@ test('noise payload with holepunch and addresses', function (t) {
addresses6: [],
udx: null,
secretStream: null,
relayThrough: null
relayThrough: null,
timestamp: -1
}

m.noisePayload.preencode(state, c)
Expand Down Expand Up @@ -87,7 +89,8 @@ test('noise payload only addresses', function (t) {
addresses6: [],
udx: null,
secretStream: null,
relayThrough: null
relayThrough: null,
timestamp: -1
}

m.noisePayload.preencode(state, c)
Expand Down Expand Up @@ -118,7 +121,8 @@ test('noise payload ipv6', function (t) {
}],
udx: null,
secretStream: null,
relayThrough: null
relayThrough: null,
timestamp: -1
}

m.noisePayload.preencode(state, c)
Expand Down Expand Up @@ -150,10 +154,40 @@ test('noise payload newer version', function (t) {
addresses6: [],
udx: null,
secretStream: null,
relayThrough: null
relayThrough: null,
timestamp: -1
})
})

test('noise payload timestamp', function (t) {
const state = { start: 0, end: 0, buffer: null }

const c = {
version: 1,
error: 0,
firewall: 2,
holepunch: null,
addresses4: [],
addresses6: [],
udx: null,
secretStream: null,
relayThrough: null,
timestamp: Date.now()
}

m.noisePayload.preencode(state, c)

state.buffer = b4a.allocUnsafe(state.end)
m.noisePayload.encode(state, c)

state.start = 0

const d = m.noisePayload.decode(state)

t.is(state.start, state.end)
t.alike(d, c)
})

test('basic holepunch payload', function (t) {
const state = { start: 0, end: 0, buffer: null }

Expand Down
Loading