Small fun project implementing a Peer-to-Peer chat application
  • Elixir 52.7%
  • Rust 42.6%
  • Nix 4.7%
Find a file
2026-05-22 15:38:14 +02:00
lib implement a bunch of utility functions on tun device primitive 2026-05-21 17:02:21 +02:00
native/p2pchat_transport_prim_tun enif_select() shenanigans 2026-05-22 15:38:14 +02:00
priv/native implement minimal NIF to create and read from a TUN device 2026-05-20 18:01:19 +02:00
test initi elixir project 2026-05-19 19:38:40 +02:00
.envrc initi elixir project 2026-05-19 19:38:40 +02:00
.formatter.exs initi elixir project 2026-05-19 19:38:40 +02:00
.gitignore implement minimal NIF to create and read from a TUN device 2026-05-20 18:01:19 +02:00
Cargo.lock enif_select() shenanigans 2026-05-22 15:38:14 +02:00
Cargo.toml enif_select() shenanigans 2026-05-22 15:38:14 +02:00
flake.lock initi elixir project 2026-05-19 19:38:40 +02:00
flake.nix implement automatic receiving of tun messages from elixir code 2026-05-21 14:38:06 +02:00
mix.exs implement minimal NIF to create and read from a TUN device 2026-05-20 18:01:19 +02:00
mix.lock implement minimal NIF to create and read from a TUN device 2026-05-20 18:01:19 +02:00
README.md specify ipv4-mapped ipv6 address usage 2026-05-20 14:14:01 +02:00

P2pChat

Wire-Protocol

The protocol is separated into two parts. The lower layer takes care of p2p coordination while the upper chat layer sits on top of it.

P2P

This protocol layer takes care of establishing a coherent Peer-to-Peer network over which arbitrary data can be transported from one node to another without regard to the underlying network topology.

It requires datagram transport from the IP layer between nodes full messh reachability is not required. To upper layers (e.g. the chat protocol) it offers unreliable transport between arbitrary nodes of the network and addressing by node IDs instead of IP addresses.

Concepts

  • netid: A unique 32bit identifier of each node
  • local neighbor: A local neighbor of node A is another node B that can be directly contacted by node A without NAT or firewalling.
  • remote neighbor: A remote neighbor of node A is another node B that is part of the same P2P network but which cannot be reached directly via UDP datagrams and only through traversing the P2P network.

General Protocol Provisions

The protocol is encoded in binary and uses the following common header:

0          7 8        15 16       23 24        31 
+-----------+-----------+-----------+------------+
|  magic    |  version  | message   |   flags    |
|           |           |  type     |            |
+-----------+-----------+-----------+------------+
|                   nonce                        |
|                                                |
+-----------+-----------+-----------+------------+
|                 src netid                      |
|                                                |
+-----------+-----------+-----------+------------+
|                 dst netid                      |
|                                                |
+-----------+-----------+-----------+------------+
  • magic: The 8 bit constant value 0xAC. It identifies this message as a P2P message.
  • version: 8 bit unsigned integer denoting the protocol version. In this spec always 0x01.
  • message type: 8 bit identifying the type of payload this message carries.
  • nonce: A 32 bit, randomly generated, unique number associated with each packet.
  • src netid: The unique identifier of the node who originated this message.
  • dst netidc: The unique identifier of the node who this message is intended for.
Flag Bit Name Description
10000000 NO_FORWARD This message should not be forwarded even if the recipient is not the target node
01000000 reserved
00100000 reserved
00010000 reserved
00001000 reserved
00000100 reserved
00000010 reserved
00000001 reserved

If a node receives a message without the NO_FORWARD flag set, and its own netid is not the dst netid, then it SHOULD forward the message unaltered to all its connected neighbors. To prevent packet loops, all participating nodes MUST store a hash of each received packet and not forward packets again that it has already processed. The local hash table SHOULD NOT be cleared more often than every 5 minutes.

Special netids

The following special netids are defined:

netid name description
0 any node For message forwarding, all nodes consider this dst netid their own and do not forward the message
0xFFFFFFFF all nodes For message forwarding, all nodes consider dst netid their own and forward the message to all their neighbors

Message Type Hello

  • Message Type: 0x01

This message is the introductory message that a new node sends to any node of the network it can reach and which identifies the new one. It has no payload.

Any node which receives a Hello message SHOULD add the sending node to it's local neighbor table and associate the src IP address of the packet with that sending node.

Message Type Goodbye

  • Message Type: 0x02

This message type MAY be sent by a node who is going offline or which is intending to leave the network. It has no payload.

Message Type Ping

  • Message Type 0x03

A message which MAY be originated by a node to check for reachability of other nodes in the network. Nodes which receive this message SHOULD respond with a Pong message. It has no payload.

Message Type Pong

  • Message Type 0x04

A message which MUST ONLY be originated by a node in response to a previous Ping message. It has no payload.

Message Type Inform

  • Message Type 0x05

This message may be sent by a node to inform it's neighbors about other neighbors.

For example, if Node A is a local neighbor of Node B, Node B could use this message to signal a third Node C that Node A exists. Node C could then try to reach Node A on it's own and/or add it to it's remote neighbor table.

It has the following payload:

0          7 8        15 16       23 24        31 
+-----------+-----------+-----------+------------+
|                subject netid                   |
|                                                |
+-----------+-----------+-----------+------------+
|             subject ip address                 |
|                                                |
+           +           +           +            +
|                                                |
|                                                |
+           +           +           +            +
|                                                |
|                                                |
+           +           +           +            +
|                                                |
|                                                |
+-----------+-----------+-----------+------------+
|      subject port     |
|                       |
+-----------+-----------+
  • subject netid: The netid of the third node which is being informed about (Node A in the example above).
  • subject ip address: The IP Address at which the third node was reachable for the node which originated this message. It is always assumed to be an IPv6 address by default but the special IPv4-mapped address space ::ffff:0:0/96 may be used to encode an IPv4 address in the last 32 bits.
  • subject port: The port at which the third node was reachable for the node with originated this message.

Message Type Data

  • Message Type 0x10

This message is used for actual data transfer between nodes. It's payload makes up the remainder of the UDP datagram and the content is up to the upper protocol to decide.

Chat

TODO

Installation

If available in Hex, the package can be installed by adding p2p_chat to your list of dependencies in mix.exs:

def deps do
  [
    {:p2p_chat, "~> 0.1.0"}
  ]
end

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/p2p_chat.