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

feat: all unverified inbound sessions #180

Merged
merged 9 commits into from
May 25, 2022

Conversation

acolytec3
Copy link
Contributor

@acolytec3 acolytec3 commented May 18, 2022

Features

  • Adds new optional sessionConfig parameter to allow inbound sessions with invalid ENRs (i.e. where observed socket address doesn't match socket address reported in ENR - to allow nodes reporting local IP/port combinations to receive discv5 PONG messages in order to update ENRs).
    • Note: nodes with "unverified sessions" are not added to the discv5 routing table so the discv5 service will never send outbound messages to them to ensure we aren't propagating DDoS attacks
  • Allows sendTalkResp to specify a target node via session key (nodeId + socketAddr) to allow responding to nodes with unverified sessions (so will not have an ENR in the routing table)
  • Makes service.sendPing public so it can be triggered by portal network layer to trigger enrUpdate logic via PONG messages.

Fixes

  • Fixes tests

@acolytec3 acolytec3 requested a review from a team as a code owner May 18, 2022 12:32
@acolytec3 acolytec3 force-pushed the all-unverified-sessions branch from b5bcf75 to d5a0e50 Compare May 18, 2022 12:37
@acolytec3 acolytec3 changed the title All unverified inbound sessions feat: all unverified inbound sessions May 18, 2022
@@ -13,7 +13,7 @@
"lint": "eslint --color --ext .ts src/",
"test": "yarn test:unit && yarn test:e2e",
"test:unit": "mocha 'test/unit/**/*.test.ts'",
"test:e2e": "mocha 'test/unit/**/*.test.ts'"
"test:e2e": "mocha 'test/e2e/**/*.test.ts'"
Copy link
Contributor

Choose a reason for hiding this comment

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

🙏

@dapplion dapplion requested a review from wemeetagain May 19, 2022 03:40
@acolytec3 acolytec3 force-pushed the all-unverified-sessions branch from d5a0e50 to 413ce5c Compare May 19, 2022 13:20
@acolytec3
Copy link
Contributor Author

This should be ready for review.

Copy link
Member

@wemeetagain wemeetagain left a comment

Choose a reason for hiding this comment

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

Does it make sense to also also allow outbound unverified sessions?
They seem less useful, but you could dial a peer via a full multiaddr, and currently, if they respond with 'unverified' ENR (wrong or no IP+port), the session is dropped.
If we allowed unverified outbound sessions, we'd be able to use them for TALKREQ/RESP at least.

src/service/service.ts Outdated Show resolved Hide resolved
src/service/service.ts Outdated Show resolved Hide resolved
@acolytec3
Copy link
Contributor Author

Does it make sense to also also allow outbound unverified sessions? They seem less useful, but you could dial a peer via a full multiaddr, and currently, if they respond with 'unverified' ENR (wrong or no IP+port), the session is dropped. If we allowed unverified outbound sessions, we'd be able to use them for TALKREQ/RESP at least.

Potentially, though at least in a Portal Network context, we have no inbuilt way to obtain a full Multiaddr (including the public key). We do have one subprotocol that relies entirely upon TALKREQ and drops the corresponding TALKRESPs and it could be useful to allow that subprotocol to work based just upon the INodeAddress.

@acolytec3
Copy link
Contributor Author

And now that I think about it, another way to approach this might be to have the sessionService "established" event include the observed socket address along with the ENR as well as a "verified" flag and then update the routing table to only if the verified is set. Then, Portal Network can listen for that and update our own ENR cache (since we are already also maintaining our own routing tables) with the ENRs and multiaddrs and then we can call TALKREQ/TALKRESP with ENR or multiaddr. Thoughts?

@acolytec3
Copy link
Contributor Author

Disregard my previous feedback, I think this is now ready for review again.

@acolytec3
Copy link
Contributor Author

Does it make sense to also also allow outbound unverified sessions? They seem less useful, but you could dial a peer via a full multiaddr, and currently, if they respond with 'unverified' ENR (wrong or no IP+port), the session is dropped. If we allowed unverified outbound sessions, we'd be able to use them for TALKREQ/RESP at least.

I went ahead and added this in as I think I now can see where it can be useful down the line. I can't think of a use case where we'll be able to make use of it within Portal Network in our current code base unless we set up an ENR/socket address cache since we wouldn't have any other way to know the correct socket address to send a TALKREQ to but as I noted above, we do have one use case where we might want to still send outbound messages to a node with an invalid ENR so this will be a useful stepping stone to that use case.

Copy link
Member

@wemeetagain wemeetagain left a comment

Choose a reason for hiding this comment

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

And now that I think about it, another way to approach this might be to have the sessionService "established" event include the observed socket address along with the ENR as well as a "verified" flag and then update the routing table to only if the verified is set. Then, Portal Network can listen for that and update our own ENR cache (since we are already also maintaining our own routing tables) with the ENRs and multiaddrs and then we can call TALKREQ/TALKRESP with ENR or multiaddr. Thoughts?

I think thats a good idea. We can update the established event type to:
established: (nodeAddr: INodeAddress, enr: ENR, connectionDirection: ConnectionDirection, verified: boolean) => void;
and filter out unverified sessions as a first step in onEstablished.

This also wouldn't effect performance/behavior in the default configuration, since only verified sessions will emit established events.


// Drop session if invalid ENR and session service not configured to allow unverified sessions
if (!verified && !this.config.allowUnverifiedSessions) {
log("ENR contains invalid socket address. Dropping session with %o", nodeAddr);
Copy link
Member

Choose a reason for hiding this comment

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

I think there should be a this.failSession(nodeAddr, RequestErrorType.InvalidRemoteENR, true) after this log and the similar log below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added.

@acolytec3
Copy link
Contributor Author

I think thats a good idea. We can update the established event type to:
established: (nodeAddr: INodeAddress, enr: ENR, connectionDirection: ConnectionDirection, verified: boolean) => void;
and filter out unverified sessions as a first step in onEstablished.

I've made these updates. Can we also bubble up this established event to the discv5 service layer? I'd have to add a new event at that level. Otherwise, I can hack around it with a little ;(discv5 as any).sessionService.on("established... in our portalnetwork code if you don't want it exposed in the main API.

@acolytec3
Copy link
Contributor Author

Looks like I have a broken test now so will look at that too.

@wemeetagain
Copy link
Member

I think thats a good idea. We can update the established event type to:
established: (nodeAddr: INodeAddress, enr: ENR, connectionDirection: ConnectionDirection, verified: boolean) => void;
and filter out unverified sessions as a first step in onEstablished.

I've made these updates. Can we also bubble up this established event to the discv5 service layer? I'd have to add a new event at that level. Otherwise, I can hack around it with a little ;(discv5 as any).sessionService.on("established... in our portalnetwork code if you don't want it exposed in the main API.

Maybe we can just make the sessionService public. You could then subscribe to events there without having to cast to any. Make it up to consumers of the library to not meddle with the sessionService in sketchy ways.

@acolytec3
Copy link
Contributor Author

I think thats a good idea. We can update the established event type to:
established: (nodeAddr: INodeAddress, enr: ENR, connectionDirection: ConnectionDirection, verified: boolean) => void;
and filter out unverified sessions as a first step in onEstablished.

I've made these updates. Can we also bubble up this established event to the discv5 service layer? I'd have to add a new event at that level. Otherwise, I can hack around it with a little ;(discv5 as any).sessionService.on("established... in our portalnetwork code if you don't want it exposed in the main API.

Maybe we can just make the sessionService public. You could then subscribe to events there without having to cast to any. Make it up to consumers of the library to not meddle with the sessionService in sketchy ways.

That works for me though it is another event emitter for me and any other consumer to keep track of. Doesn't seem like there are any other undue risks since even if somebody sends random messages, it seems like the worst that could happen is a session gets invalidated by the receiving node if somebody starts sending garbage data.

Copy link
Member

@wemeetagain wemeetagain left a comment

Choose a reason for hiding this comment

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

Awesome! this will be a nice feature

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants