laminar icon indicating copy to clipboard operation
laminar copied to clipboard

Implement handshake between server and client

Open daxpedda opened this issue 6 years ago • 3 comments

After a discussion in Discord about questioning the point of sending the protocol version with every package, some people (including me) pointed out that the issue could be resolved by putting it into a handshake process. Additionally "packet defense mechanism" came up. So I'm just going to put out ideas here, I'm still new to laminar, so I don't know whats on the roadmap or if some of these ideas don't work with the current implementation, please bear with me:

Ideas that could be included into a Handshake

  1. Determine valid protocol version (so we can remove it from the current standard header)
  2. Encryption handshake, if we are going to use TLS or similar (#41)
  3. Expose an API for handling new connections
    1. Could be used for the following things
      • Banning IPs
      • Timeout configuration for too many unsuccessful handshakes
      • Any other ideas?
    2. A list of open connections with API for:
      • Dropping a connection
      • Querying metrics
      • Any other ideas?
    3. Seperate event channel for accepting/declining connection in the handshake process
      • Defense mechanism: determines if packets are DoS if they are sent before acceptance of the handshake
      • A seperate channel gives the user the ability to communicate handshake failure with laminar (ie. login)
      • Any other ideas?

Points 1. and 2. I think are reasonable and are not really out of scope. Point 3. could be completly out of scope for laminar, I don't know, but I don't see a proper way how to handle packet defense without the ability to let the user determine if an incoming connection is valid or not, laminar itself can only determine it by invalid protocol version or failed TLS handshake. A user can determine through things like login or whitelisting IPs through an external authorization process.

daxpedda avatar Mar 14 '19 12:03 daxpedda

2: "Encryption handshake, if we are going to use TLS or similar (#41)" I left a comment there, we should figure out which encryption techniques we could use. I propose to go with symmetric encryption.

3: Expose an API for handling new connections

Yea, I am wondering if this is in the scope of laminar, we have two factors here connection management by the user and connection management for laminar.

Laminar We keep track of those connections for internal use like fragmentation, reliability handling, acknowledgement handling, congestion handling. We need to cache things for each connection.

Lets first define what we currently do to manage connections and how we notify the user of this. ActiveConnections; this is responsible for keeping track of active connections. When a connection sends something we update the last heard, if the client does not exists yet we create it. We check at some interval for idling connections and if it is then we notify the user via an event channel that a connection has disconnected. This way, users can already keep track of idling connections, however, we don't yet send a SocketEvent::Connected when a user connects.

User As we spoke about previously, we send a SocketEvents to the user that could be a connection, disconnecting, idling connection. Dissconnect is kind of vague, we don't really have a forced disconnect, We see this as an idling connection. We haven't implemented an incomming connection yet.

Because we send those events back to the user is able to interpret on that. We could use a similar way to update the client information, like SocketEvent::ClientMetrics(), we could have something in the config that decides how often we send information in an event form.

client metrics could be

  • Metrics; RTT, network quality etc.
  • Last Heard
  • cached packets

If we would go for this method we wouldn't be able to drop the connection, refuse connections, accept connections yet. The points that fall within the scope of laminar are:

  • Wrong Protocol Id
  • not sure of any other ones.

Laminar should almost accept all packets from everyone and accept all connections, and it should be up to the user of laminar to decide if wants to remove or ban a connection based on its behaviour seen from the metrics gotten from the metrics. The user should and can maintain the connections itself based on SocketEvent::Connect , SocketEvent::Disconnect, SocketEvent::Timeout. However, the user should be able to tell laminar to stop accepting packets from a certain connection. That could be done via the Socket type which owns the connections.

TimonPost avatar Mar 15 '19 13:03 TimonPost

Interesting read: https://github.com/networkprotocol/netcode.io/blob/master/STANDARD.md

TimonPost avatar Mar 26 '19 22:03 TimonPost

I am going to work on this, currently looking into various resources in order to get a good implementation:

gaffer: http://web.archive.org/web/20181107181442/https://gafferongames.com/post/client_server_connection/ paper: https://pdfs.semanticscholar.org/9e70/3b9646c7e622b27feddcbfb1e114e69021af.pdf dtls: https://tools.ietf.org/id/draft-ietf-tls-dtls13-01.html#rfc.section.3.1 netcode: https://github.com/networkprotocol/netcode.io/blob/master/STANDARD.md

open beta bool: http://ithare.com/udp-for-games-security-encryption-and-ddos-protection/

TimonPost avatar Aug 22 '19 17:08 TimonPost