Skip to content

Commit

Permalink
fix: refactor autonat to handle messages in separate method
Browse files Browse the repository at this point in the history
Small refactor to reduce code complexity and make refactorting to
web streams a little less disruptive.
  • Loading branch information
achingbrain committed Jun 6, 2024
1 parent 4bd8e4f commit 5562deb
Showing 1 changed file with 152 additions and 160 deletions.
312 changes: 152 additions & 160 deletions packages/protocol-autonat/src/autonat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from './constants.js'
import { Message } from './pb/index.js'
import type { AutoNATComponents, AutoNATServiceInit } from './index.js'
import type { Logger, Connection, PeerId, PeerInfo, Startable } from '@libp2p/interface'
import type { Logger, Connection, PeerId, PeerInfo, Startable, AbortOptions } from '@libp2p/interface'
import type { IncomingStreamData } from '@libp2p/interface-internal'

// if more than 3 peers manage to dial us on what we believe to be our external
Expand Down Expand Up @@ -95,9 +95,6 @@ export class AutoNATService implements Startable {
// appearing in the console
setMaxListeners(Infinity, signal)

const ourHosts = this.components.addressManager.getAddresses()
.map(ma => ma.toOptions().host)

try {
const self = this

Expand Down Expand Up @@ -138,193 +135,188 @@ export class AutoNATService implements Startable {
return
}

const dialRequest = request.dial

if (dialRequest == null) {
self.log.error('dial was missing from message')
yield Message.encode(await self.handleAutonatMessage(request, data.connection, {
signal
}))
},
(source) => lp.encode(source),
data.stream
)
} catch (err) {
this.log.error('error handling incoming autonat stream', err)

Check warning on line 146 in packages/protocol-autonat/src/autonat.ts

View check run for this annotation

Codecov / codecov/patch

packages/protocol-autonat/src/autonat.ts#L146

Added line #L146 was not covered by tests
} finally {
signal.removeEventListener('abort', onAbort)
}
}

yield Message.encode({
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_BAD_REQUEST,
statusText: 'No Dial message found in message'
}
})
_verifyExternalAddresses (): void {
void this.verifyExternalAddresses()
.catch(err => {
this.log.error('error verifying external address', err)
})
}

Check warning on line 157 in packages/protocol-autonat/src/autonat.ts

View check run for this annotation

Codecov / codecov/patch

packages/protocol-autonat/src/autonat.ts#L153-L157

Added lines #L153 - L157 were not covered by tests

return
}
private async handleAutonatMessage (message: Message, connection: Connection, options?: AbortOptions): Promise<Message> {
const ourHosts = this.components.addressManager.getAddresses()
.map(ma => ma.toOptions().host)

let peerId: PeerId
const peer = dialRequest.peer
const dialRequest = message.dial

if (peer == null || peer.id == null) {
self.log.error('PeerId missing from message')
if (dialRequest == null) {
this.log.error('dial was missing from message')

yield Message.encode({
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_BAD_REQUEST,
statusText: 'missing peer info'
}
})
return {
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_BAD_REQUEST,
statusText: 'No Dial message found in message'
}
}
}

return
}
let peerId: PeerId
const peer = dialRequest.peer

try {
peerId = peerIdFromBytes(peer.id)
} catch (err) {
self.log.error('invalid PeerId', err)
if (peer == null || peer.id == null) {
this.log.error('PeerId missing from message')

yield Message.encode({
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_BAD_REQUEST,
statusText: 'bad peer id'
}
})
return {
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_BAD_REQUEST,
statusText: 'missing peer info'
}
}
}

return
}
try {
peerId = peerIdFromBytes(peer.id)
} catch (err) {
this.log.error('invalid PeerId', err)

self.log('incoming request from %p', peerId)
return {
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_BAD_REQUEST,
statusText: 'bad peer id'
}
}
}

// reject any dial requests that arrive via relays
if (!data.connection.remotePeer.equals(peerId)) {
self.log('target peer %p did not equal sending peer %p', peerId, data.connection.remotePeer)
this.log('incoming request from %p', peerId)

yield Message.encode({
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_BAD_REQUEST,
statusText: 'peer id mismatch'
}
})
// reject any dial requests that arrive via relays
if (!connection.remotePeer.equals(peerId)) {
this.log('target peer %p did not equal sending peer %p', peerId, connection.remotePeer)

return
}
return {
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_BAD_REQUEST,
statusText: 'peer id mismatch'
}
}
}

// get a list of multiaddrs to dial
const multiaddrs = peer.addrs
.map(buf => multiaddr(buf))
.filter(ma => {
const isFromSameHost = ma.toOptions().host === data.connection.remoteAddr.toOptions().host
// get a list of multiaddrs to dial
const multiaddrs = peer.addrs
.map(buf => multiaddr(buf))
.filter(ma => {
const isFromSameHost = ma.toOptions().host === connection.remoteAddr.toOptions().host

self.log.trace('request to dial %a was sent from %a is same host %s', ma, data.connection.remoteAddr, isFromSameHost)
// skip any Multiaddrs where the target node's IP does not match the sending node's IP
return isFromSameHost
})
.filter(ma => {
const host = ma.toOptions().host
const isPublicIp = !(isPrivateIp(host) ?? false)
this.log.trace('request to dial %a was sent from %a is same host %s', ma, connection.remoteAddr, isFromSameHost)
// skip any Multiaddrs where the target node's IP does not match the sending node's IP
return isFromSameHost
})
.filter(ma => {
const host = ma.toOptions().host
const isPublicIp = !(isPrivateIp(host) ?? false)

self.log.trace('host %s was public %s', host, isPublicIp)
// don't try to dial private addresses
return isPublicIp
})
.filter(ma => {
const host = ma.toOptions().host
const isNotOurHost = !ourHosts.includes(host)
this.log.trace('host %s was public %s', host, isPublicIp)
// don't try to dial private addresses
return isPublicIp
})
.filter(ma => {
const host = ma.toOptions().host
const isNotOurHost = !ourHosts.includes(host)

self.log.trace('host %s was not our host %s', host, isNotOurHost)
// don't try to dial nodes on the same host as us
return isNotOurHost
})
.filter(ma => {
const isSupportedTransport = Boolean(self.components.transportManager.dialTransportForMultiaddr(ma))
this.log.trace('host %s was not our host %s', host, isNotOurHost)
// don't try to dial nodes on the same host as us
return isNotOurHost
})
.filter(ma => {
const isSupportedTransport = Boolean(this.components.transportManager.dialTransportForMultiaddr(ma))

self.log.trace('transport for %a is supported %s', ma, isSupportedTransport)
// skip any Multiaddrs that have transports we do not support
return isSupportedTransport
})
.map(ma => {
if (ma.getPeerId() == null) {
// make sure we have the PeerId as part of the Multiaddr
ma = ma.encapsulate(`/p2p/${peerId.toString()}`)
}
this.log.trace('transport for %a is supported %s', ma, isSupportedTransport)
// skip any Multiaddrs that have transports we do not support
return isSupportedTransport
})
.map(ma => {
if (ma.getPeerId() == null) {
// make sure we have the PeerId as part of the Multiaddr
ma = ma.encapsulate(`/p2p/${peerId.toString()}`)
}

return ma
})
return ma
})

// make sure we have something to dial
if (multiaddrs.length === 0) {
self.log('no valid multiaddrs for %p in message', peerId)
// make sure we have something to dial
if (multiaddrs.length === 0) {
this.log('no valid multiaddrs for %p in message', peerId)

yield Message.encode({
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_DIAL_REFUSED,
statusText: 'no dialable addresses'
}
})
return {
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_DIAL_REFUSED,
statusText: 'no dialable addresses'
}
}
}

return
}
this.log('dial multiaddrs %s for peer %p', multiaddrs.map(ma => ma.toString()).join(', '), peerId)

self.log('dial multiaddrs %s for peer %p', multiaddrs.map(ma => ma.toString()).join(', '), peerId)
let errorMessage = ''
let lastMultiaddr = multiaddrs[0]

let errorMessage = ''
let lastMultiaddr = multiaddrs[0]
for await (const multiaddr of multiaddrs) {
let connection: Connection | undefined
lastMultiaddr = multiaddr

for await (const multiaddr of multiaddrs) {
let connection: Connection | undefined
lastMultiaddr = multiaddr
try {
connection = await this.components.connectionManager.openConnection(multiaddr, options)

try {
connection = await self.components.connectionManager.openConnection(multiaddr, {
signal
})
if (!connection.remoteAddr.equals(multiaddr)) {
this.log.error('tried to dial %a but dialed %a', multiaddr, connection.remoteAddr)
throw new Error('Unexpected remote address')

Check warning on line 290 in packages/protocol-autonat/src/autonat.ts

View check run for this annotation

Codecov / codecov/patch

packages/protocol-autonat/src/autonat.ts#L289-L290

Added lines #L289 - L290 were not covered by tests
}

if (!connection.remoteAddr.equals(multiaddr)) {
self.log.error('tried to dial %a but dialed %a', multiaddr, connection.remoteAddr)
throw new Error('Unexpected remote address')
}
this.log('Success %p', peerId)

self.log('Success %p', peerId)

yield Message.encode({
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.OK,
addr: connection.remoteAddr.decapsulateCode(protocols('p2p').code).bytes
}
})

return
} catch (err: any) {
self.log('could not dial %p', peerId, err)
errorMessage = err.message
} finally {
if (connection != null) {
await connection.close()
}
}
return {
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.OK,
addr: connection.remoteAddr.decapsulateCode(protocols('p2p').code).bytes
}

yield Message.encode({
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_DIAL_ERROR,
statusText: errorMessage,
addr: lastMultiaddr.bytes
}
})
},
(source) => lp.encode(source),
data.stream
)
} catch (err) {
this.log.error('error handling incoming autonat stream', err)
} finally {
signal.removeEventListener('abort', onAbort)
}
} catch (err: any) {
this.log('could not dial %p', peerId, err)
errorMessage = err.message
} finally {
if (connection != null) {
await connection.close()
}
}
}
}

_verifyExternalAddresses (): void {
void this.verifyExternalAddresses()
.catch(err => {
this.log.error('error verifying external address', err)
})
return {
type: Message.MessageType.DIAL_RESPONSE,
dialResponse: {
status: Message.ResponseStatus.E_DIAL_ERROR,
statusText: errorMessage,
addr: lastMultiaddr.bytes
}
}
}

/**
Expand Down

0 comments on commit 5562deb

Please sign in to comment.