librats 1.0.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -331
- package/binding.gyp +16 -3
- package/lib/index.d.ts +288 -696
- package/lib/index.js +407 -44
- package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
- package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
- package/native-src/CMakeLists.txt +404 -179
- package/native-src/LICENSE +1 -1
- package/native-src/src/librats/bindings/rats.cpp +762 -0
- package/native-src/src/librats/bindings/rats.h +380 -0
- package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
- package/native-src/src/librats/bittorrent/bencode.h +176 -0
- package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
- package/native-src/src/librats/bittorrent/bitfield.h +76 -0
- package/native-src/src/librats/bittorrent/byte_io.h +58 -0
- package/native-src/src/librats/bittorrent/choker.cpp +25 -0
- package/native-src/src/librats/bittorrent/choker.h +46 -0
- package/native-src/src/librats/bittorrent/client.cpp +413 -0
- package/native-src/src/librats/bittorrent/client.h +227 -0
- package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
- package/native-src/src/librats/bittorrent/disk_io.h +150 -0
- package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
- package/native-src/src/librats/bittorrent/extensions.h +94 -0
- package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
- package/native-src/src/librats/bittorrent/file_storage.h +79 -0
- package/native-src/src/librats/bittorrent/log.h +42 -0
- package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
- package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
- package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
- package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
- package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
- package/native-src/src/librats/bittorrent/peer_list.h +75 -0
- package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
- package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
- package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
- package/native-src/src/librats/bittorrent/reactor.h +89 -0
- package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
- package/native-src/src/librats/bittorrent/resume_data.h +41 -0
- package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
- package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
- package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
- package/native-src/src/librats/bittorrent/torrent.h +260 -0
- package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
- package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
- package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
- package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
- package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
- package/native-src/src/librats/bittorrent/tracker.h +108 -0
- package/native-src/src/librats/bittorrent/types.cpp +206 -0
- package/native-src/src/librats/bittorrent/types.h +86 -0
- package/native-src/src/librats/core/address.cpp +35 -0
- package/native-src/src/librats/core/address.h +78 -0
- package/native-src/src/librats/core/bytes.h +69 -0
- package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
- package/native-src/src/librats/core/chained_send_buffer.h +183 -0
- package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
- package/native-src/src/librats/core/endpoint_parse.h +31 -0
- package/native-src/src/librats/core/event_bus.h +70 -0
- package/native-src/src/librats/core/host_endpoint.h +56 -0
- package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
- package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
- package/native-src/src/librats/core/ip_address.cpp +120 -0
- package/native-src/src/librats/core/ip_address.h +109 -0
- package/native-src/src/librats/core/mpsc_queue.h +47 -0
- package/native-src/src/librats/core/notifier.h +74 -0
- package/native-src/src/librats/core/receive_buffer.cpp +219 -0
- package/native-src/src/librats/core/receive_buffer.h +171 -0
- package/native-src/src/librats/core/service_registry.h +58 -0
- package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
- package/native-src/src/librats/core/socket.h +496 -0
- package/native-src/src/librats/core/timer_queue.h +105 -0
- package/native-src/src/librats/core/types.cpp +43 -0
- package/native-src/src/librats/core/types.h +103 -0
- package/native-src/src/librats/core/wakeup_pipe.h +83 -0
- package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
- package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
- package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
- package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
- package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
- package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
- package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
- package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
- package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
- package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
- package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
- package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
- package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
- package/native-src/src/librats/crypto/hkdf.c +266 -0
- package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
- package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
- package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
- package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
- package/native-src/src/librats/crypto/poly1305.h +37 -0
- package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
- package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
- package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
- package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
- package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
- package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
- package/native-src/src/librats/dht/announce.cpp +37 -0
- package/native-src/src/librats/dht/announce.h +41 -0
- package/native-src/src/librats/dht/bep42.cpp +109 -0
- package/native-src/src/librats/dht/bep42.h +48 -0
- package/native-src/src/librats/dht/dht.cpp +501 -0
- package/native-src/src/librats/dht/dht.h +119 -0
- package/native-src/src/librats/dht/dht_runner.cpp +103 -0
- package/native-src/src/librats/dht/dht_runner.h +71 -0
- package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
- package/native-src/src/librats/dht/dos_blocker.h +47 -0
- package/native-src/src/librats/dht/find_peers.cpp +52 -0
- package/native-src/src/librats/dht/find_peers.h +73 -0
- package/native-src/src/librats/dht/id.h +167 -0
- package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
- package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
- package/native-src/src/librats/dht/log.h +38 -0
- package/native-src/src/librats/dht/node.cpp +473 -0
- package/native-src/src/librats/dht/node.h +164 -0
- package/native-src/src/librats/dht/node_entry.h +81 -0
- package/native-src/src/librats/dht/observer.h +72 -0
- package/native-src/src/librats/dht/persistence.cpp +90 -0
- package/native-src/src/librats/dht/persistence.h +32 -0
- package/native-src/src/librats/dht/routing_table.cpp +559 -0
- package/native-src/src/librats/dht/routing_table.h +185 -0
- package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
- package/native-src/src/librats/dht/rpc_manager.h +77 -0
- package/native-src/src/librats/dht/storage.cpp +92 -0
- package/native-src/src/librats/dht/storage.h +74 -0
- package/native-src/src/librats/dht/transport.h +27 -0
- package/native-src/src/librats/dht/traversal.cpp +326 -0
- package/native-src/src/librats/dht/traversal.h +120 -0
- package/native-src/src/librats/dht/udp_transport.cpp +49 -0
- package/native-src/src/librats/dht/udp_transport.h +51 -0
- package/native-src/src/librats/mdns/log.h +22 -0
- package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
- package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
- package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
- package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
- package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
- package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
- package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
- package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
- package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
- package/native-src/src/librats/node/circuit_service.h +84 -0
- package/native-src/src/librats/node/config.h +110 -0
- package/native-src/src/librats/node/dial_service.h +54 -0
- package/native-src/src/librats/node/dialer.cpp +264 -0
- package/native-src/src/librats/node/dialer.h +188 -0
- package/native-src/src/librats/node/host_events.h +26 -0
- package/native-src/src/librats/node/identify.cpp +130 -0
- package/native-src/src/librats/node/identify.h +71 -0
- package/native-src/src/librats/node/nat_status.cpp +103 -0
- package/native-src/src/librats/node/nat_status.h +118 -0
- package/native-src/src/librats/node/node.cpp +865 -0
- package/native-src/src/librats/node/node.h +344 -0
- package/native-src/src/librats/node/node_context.h +33 -0
- package/native-src/src/librats/node/peer_network.h +91 -0
- package/native-src/src/librats/peer/peer.h +49 -0
- package/native-src/src/librats/peer/peer_book.cpp +181 -0
- package/native-src/src/librats/peer/peer_book.h +88 -0
- package/native-src/src/librats/peer/peer_id.cpp +72 -0
- package/native-src/src/librats/peer/peer_id.h +62 -0
- package/native-src/src/librats/peer/peer_info.h +37 -0
- package/native-src/src/librats/peer/peer_table.cpp +170 -0
- package/native-src/src/librats/peer/peer_table.h +148 -0
- package/native-src/src/librats/security/handshaker.h +66 -0
- package/native-src/src/librats/security/identity.h +43 -0
- package/native-src/src/librats/security/noise_security.cpp +122 -0
- package/native-src/src/librats/security/noise_security.h +37 -0
- package/native-src/src/librats/security/plaintext_security.h +106 -0
- package/native-src/src/librats/security/session.h +37 -0
- package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
- package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
- package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
- package/native-src/src/librats/subsystems/bittorrent.h +136 -0
- package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
- package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
- package/native-src/src/librats/subsystems/dht_service.h +36 -0
- package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
- package/native-src/src/librats/subsystems/file_transfer.h +367 -0
- package/native-src/src/librats/subsystems/hole_punch.cpp +605 -0
- package/native-src/src/librats/subsystems/hole_punch.h +290 -0
- package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
- package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
- package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
- package/native-src/src/librats/subsystems/message_json.cpp +112 -0
- package/native-src/src/librats/subsystems/message_json.h +88 -0
- package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
- package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
- package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
- package/native-src/src/librats/subsystems/ping_service.h +66 -0
- package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
- package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
- package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
- package/native-src/src/librats/subsystems/pubsub.h +175 -0
- package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
- package/native-src/src/librats/subsystems/reconnection.h +126 -0
- package/native-src/src/librats/subsystems/relay.cpp +1142 -0
- package/native-src/src/librats/subsystems/relay.h +211 -0
- package/native-src/src/librats/subsystems/relay_service.h +46 -0
- package/native-src/src/librats/transport/connection.cpp +343 -0
- package/native-src/src/librats/transport/connection.h +283 -0
- package/native-src/src/librats/transport/link.h +96 -0
- package/native-src/src/librats/transport/reactor.cpp +588 -0
- package/native-src/src/librats/transport/reactor.h +262 -0
- package/native-src/src/librats/transport/reactor_pool.h +81 -0
- package/native-src/src/librats/transport/relay_link.cpp +208 -0
- package/native-src/src/librats/transport/relay_link.h +303 -0
- package/native-src/src/librats/transport/tcp_link.cpp +49 -0
- package/native-src/src/librats/transport/tcp_link.h +43 -0
- package/native-src/src/librats/transport/udp_mux.cpp +617 -0
- package/native-src/src/librats/transport/udp_mux.h +363 -0
- package/native-src/src/librats/transport/udp_packet.cpp +121 -0
- package/native-src/src/librats/transport/udp_packet.h +190 -0
- package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
- package/native-src/src/librats/transport/udp_stream.h +614 -0
- package/native-src/src/librats/util/features.h.in +51 -0
- package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
- package/native-src/src/librats/util/fs.h +136 -0
- package/native-src/src/librats/util/json.cpp +1002 -0
- package/native-src/src/librats/util/json.h +444 -0
- package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
- package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
- package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
- package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
- package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
- package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
- package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
- package/native-src/src/librats/util/rats_export.h +69 -0
- package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
- package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
- package/native-src/src/librats/wire/frame.cpp +76 -0
- package/native-src/src/librats/wire/frame.h +111 -0
- package/native-src/src/librats/wire/message_router.cpp +45 -0
- package/native-src/src/librats/wire/message_router.h +47 -0
- package/package.json +5 -4
- package/scripts/build-librats.js +1 -0
- package/scripts/postinstall.js +3 -3
- package/scripts/prepare-package.js +4 -4
- package/scripts/verify-installation.js +63 -105
- package/src/librats_node.cpp +1067 -1323
- package/native-src/src/bencode.cpp +0 -485
- package/native-src/src/bencode.h +0 -145
- package/native-src/src/bittorrent.cpp +0 -14
- package/native-src/src/bittorrent.h +0 -74
- package/native-src/src/bt_bitfield.cpp +0 -372
- package/native-src/src/bt_bitfield.h +0 -316
- package/native-src/src/bt_choker.cpp +0 -228
- package/native-src/src/bt_choker.h +0 -147
- package/native-src/src/bt_client.cpp +0 -1047
- package/native-src/src/bt_client.h +0 -445
- package/native-src/src/bt_create_torrent.cpp +0 -677
- package/native-src/src/bt_create_torrent.h +0 -473
- package/native-src/src/bt_extension.cpp +0 -469
- package/native-src/src/bt_extension.h +0 -309
- package/native-src/src/bt_file_storage.cpp +0 -261
- package/native-src/src/bt_file_storage.h +0 -298
- package/native-src/src/bt_handshake.cpp +0 -134
- package/native-src/src/bt_handshake.h +0 -157
- package/native-src/src/bt_messages.cpp +0 -364
- package/native-src/src/bt_messages.h +0 -324
- package/native-src/src/bt_network.cpp +0 -1007
- package/native-src/src/bt_network.h +0 -417
- package/native-src/src/bt_peer_connection.cpp +0 -742
- package/native-src/src/bt_peer_connection.h +0 -592
- package/native-src/src/bt_piece_picker.cpp +0 -786
- package/native-src/src/bt_piece_picker.h +0 -473
- package/native-src/src/bt_resume_data.cpp +0 -410
- package/native-src/src/bt_resume_data.h +0 -249
- package/native-src/src/bt_torrent.cpp +0 -2120
- package/native-src/src/bt_torrent.h +0 -641
- package/native-src/src/bt_torrent_info.cpp +0 -659
- package/native-src/src/bt_torrent_info.h +0 -418
- package/native-src/src/bt_types.h +0 -621
- package/native-src/src/chained_send_buffer.cpp +0 -75
- package/native-src/src/chained_send_buffer.h +0 -137
- package/native-src/src/crypto/hkdf.c +0 -266
- package/native-src/src/crypto/poly1305.h +0 -36
- package/native-src/src/dht.cpp +0 -3311
- package/native-src/src/dht.h +0 -717
- package/native-src/src/disk_io.cpp +0 -632
- package/native-src/src/disk_io.h +0 -315
- package/native-src/src/file_transfer.cpp +0 -1415
- package/native-src/src/file_transfer.h +0 -286
- package/native-src/src/fs.h +0 -108
- package/native-src/src/gossipsub.cpp +0 -1139
- package/native-src/src/gossipsub.h +0 -403
- package/native-src/src/ice.cpp +0 -893
- package/native-src/src/ice.h +0 -559
- package/native-src/src/json.hpp +0 -25526
- package/native-src/src/librats.cpp +0 -2378
- package/native-src/src/librats.h +0 -2324
- package/native-src/src/librats_bittorrent.cpp +0 -601
- package/native-src/src/librats_c.cpp +0 -1557
- package/native-src/src/librats_c.h +0 -323
- package/native-src/src/librats_discovery.cpp +0 -402
- package/native-src/src/librats_encryption.cpp +0 -275
- package/native-src/src/librats_file_transfer.cpp +0 -144
- package/native-src/src/librats_gossipsub.cpp +0 -289
- package/native-src/src/librats_ice.cpp +0 -213
- package/native-src/src/librats_log_macros.h +0 -36
- package/native-src/src/librats_logging.cpp +0 -173
- package/native-src/src/librats_mdns.cpp +0 -166
- package/native-src/src/librats_persistence.cpp +0 -796
- package/native-src/src/librats_portmap.cpp +0 -419
- package/native-src/src/librats_reconnection.cpp +0 -218
- package/native-src/src/librats_statistic.cpp +0 -105
- package/native-src/src/librats_storage.cpp +0 -189
- package/native-src/src/rats_export.h +0 -17
- package/native-src/src/receive_buffer.cpp +0 -82
- package/native-src/src/receive_buffer.h +0 -127
- package/native-src/src/socket.h +0 -228
- package/native-src/src/threadmanager.cpp +0 -105
- package/native-src/src/threadmanager.h +0 -53
- package/native-src/src/tracker.cpp +0 -1264
- package/native-src/src/tracker.h +0 -319
- package/native-src/src/turn.cpp +0 -762
- package/native-src/src/turn.h +0 -460
- package/native-src/src/wakeup_pipe.h +0 -60
- /package/native-src/src/{os.h → librats/util/os.h} +0 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file peer_table.h
|
|
5
|
+
* @brief Control-plane registry: PeerId → route + metadata.
|
|
6
|
+
*
|
|
7
|
+
* This is the only shared peer structure in the redesign, and it is deliberately
|
|
8
|
+
* **off the per-byte data path**: it is touched on connect/disconnect and on
|
|
9
|
+
* explicit by-id lookups (send-by-id, peers()), never per inbound/outbound frame
|
|
10
|
+
* (those use the route carried in the Connection/Peer handle). It is therefore
|
|
11
|
+
* read-mostly and guarded by a shared_mutex with short critical sections — a
|
|
12
|
+
* world away from the old global peers_mutex_ held across recv/send.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
#include "librats/util/rats_export.h"
|
|
16
|
+
#include "librats/core/types.h" // ConnId
|
|
17
|
+
#include "librats/peer/peer_id.h"
|
|
18
|
+
#include "librats/peer/peer_info.h"
|
|
19
|
+
|
|
20
|
+
#include <atomic>
|
|
21
|
+
#include <cstdint>
|
|
22
|
+
#include <memory>
|
|
23
|
+
#include <optional>
|
|
24
|
+
#include <shared_mutex>
|
|
25
|
+
#include <unordered_map>
|
|
26
|
+
#include <vector>
|
|
27
|
+
|
|
28
|
+
namespace librats {
|
|
29
|
+
|
|
30
|
+
/// Where a peer's live connection lives: which reactor owns it, and its ConnId.
|
|
31
|
+
/// (reactor, conn) identifies a connection globally and is never reused while it
|
|
32
|
+
/// is alive, so it is the stable key for matching a teardown to a directory entry.
|
|
33
|
+
struct PeerRoute {
|
|
34
|
+
uint8_t reactor = 0;
|
|
35
|
+
ConnId conn = kInvalidConnId;
|
|
36
|
+
|
|
37
|
+
bool operator==(const PeerRoute& o) const noexcept { return reactor == o.reactor && conn == o.conn; }
|
|
38
|
+
bool operator!=(const PeerRoute& o) const noexcept { return !(*this == o); }
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
class RATS_API PeerTable {
|
|
42
|
+
public:
|
|
43
|
+
enum class AddResult {
|
|
44
|
+
NewPeer, ///< First connection to this peer — caller should fire "connected".
|
|
45
|
+
Updated, ///< Same connection re-registered; metadata refreshed only.
|
|
46
|
+
Replaced, ///< A previous connection was superseded (`close` holds its route).
|
|
47
|
+
Rejected, ///< An existing connection was kept; the new one (`close`) must close.
|
|
48
|
+
};
|
|
49
|
+
struct AddOutcome {
|
|
50
|
+
AddResult result = AddResult::NewPeer;
|
|
51
|
+
std::optional<PeerRoute> close; ///< Loser of a duplicate race; tear it down.
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/// Register a connection for a peer, resolving duplicates deterministically.
|
|
55
|
+
/// Both ends resolve the same pair of connections independently, so each rule
|
|
56
|
+
/// reads only what looks identical from either side — never arrival order:
|
|
57
|
+
/// - opposite roles ⇒ a simultaneous cross-connect. `prefer_outbound` (which
|
|
58
|
+
/// BOTH peers compute identically from a symmetric rule over their ids)
|
|
59
|
+
/// picks the surviving link, so both converge on the same one.
|
|
60
|
+
/// - same role, different transports ⇒ a dial race whose attempts both got
|
|
61
|
+
/// through; the datagram link wins at both ends.
|
|
62
|
+
/// - same role and transport ⇒ a reconnect, so the newcomer wins.
|
|
63
|
+
/// Taken together these are a total order, mirrored at the two ends, which is
|
|
64
|
+
/// what makes the verdict independent of the order connections arrive in. See
|
|
65
|
+
/// peer_table.cpp for why each rule is the one it is.
|
|
66
|
+
/// The loser's route is returned in `close`. Write lock.
|
|
67
|
+
AddOutcome add(const PeerInfo& info, PeerRoute route, bool prefer_outbound);
|
|
68
|
+
|
|
69
|
+
/// Drop a peer, but only if its current route matches `route` — so a stale
|
|
70
|
+
/// connection's teardown cannot evict a newer one that replaced it. Write lock.
|
|
71
|
+
/// Returns true iff an entry was actually removed.
|
|
72
|
+
bool remove(const PeerId& id, PeerRoute route);
|
|
73
|
+
|
|
74
|
+
/// Route to a peer's live connection, if connected. Read lock.
|
|
75
|
+
std::optional<PeerRoute> route(const PeerId& id) const;
|
|
76
|
+
|
|
77
|
+
/// Merge dialable addresses into a peer's metadata, de-duplicated and bounded
|
|
78
|
+
/// to kMaxAddressesPerPeer. Applies only if `route` is still the peer's live
|
|
79
|
+
/// route (a stale connection's late identify cannot mutate a newer link).
|
|
80
|
+
/// Returns the addresses actually added (i.e. not already known). Write lock.
|
|
81
|
+
std::vector<Address> add_addresses(const PeerId& id, PeerRoute route,
|
|
82
|
+
const std::vector<Address>& addresses);
|
|
83
|
+
|
|
84
|
+
/// Record which transports a peer advertised in its identify message. Applies
|
|
85
|
+
/// only while `route` is still the peer's live route. Write lock.
|
|
86
|
+
void set_supported_transports(const PeerId& id, PeerRoute route, uint8_t mask);
|
|
87
|
+
|
|
88
|
+
/// A peer's live route together with whether its send queue has room, in one
|
|
89
|
+
/// lookup — the send path needs both and should not pay for two.
|
|
90
|
+
struct Destination {
|
|
91
|
+
PeerRoute route;
|
|
92
|
+
bool writable = true;
|
|
93
|
+
/// The peer's in-transit counter (see Entry::owed). Shared, not copied,
|
|
94
|
+
/// so the caller charges the same counter the reactor task discharges.
|
|
95
|
+
std::shared_ptr<std::atomic<size_t>> owed;
|
|
96
|
+
};
|
|
97
|
+
std::optional<Destination> destination(const PeerId& id) const;
|
|
98
|
+
|
|
99
|
+
/// Whether every connected peer's send queue has room — what broadcast()
|
|
100
|
+
/// answers, since "may I send more?" to a fan-out is only usefully answered
|
|
101
|
+
/// by its slowest recipient.
|
|
102
|
+
bool all_writable() const;
|
|
103
|
+
|
|
104
|
+
/// Record that a peer's send queue filled up or drained. Applies only while
|
|
105
|
+
/// `route` is still the peer's live route. Write lock, but only ever taken
|
|
106
|
+
/// when the mark is actually crossed, which is rare.
|
|
107
|
+
void set_writable(const PeerId& id, PeerRoute route, bool writable);
|
|
108
|
+
|
|
109
|
+
/// Upper bound on stored addresses per peer — caps memory and stops a peer
|
|
110
|
+
/// from flooding us with bogus addresses via the identify/PEX path.
|
|
111
|
+
static constexpr size_t kMaxAddressesPerPeer = 32;
|
|
112
|
+
|
|
113
|
+
/// Metadata snapshot for a peer. Read lock.
|
|
114
|
+
std::optional<PeerInfo> info(const PeerId& id) const;
|
|
115
|
+
|
|
116
|
+
bool contains(const PeerId& id) const;
|
|
117
|
+
|
|
118
|
+
/// Snapshot of all known peers (for the public API / persistence). Read lock.
|
|
119
|
+
std::vector<PeerInfo> snapshot() const;
|
|
120
|
+
|
|
121
|
+
size_t size() const noexcept { return count_.load(std::memory_order_relaxed); }
|
|
122
|
+
|
|
123
|
+
private:
|
|
124
|
+
struct Entry {
|
|
125
|
+
PeerInfo info;
|
|
126
|
+
PeerRoute route;
|
|
127
|
+
/// Whether this peer's send queue has room. Maintained by the reactor as
|
|
128
|
+
/// the queue crosses its low-water mark, read by send() so a caller on
|
|
129
|
+
/// any thread gets an answer without having to reach into a connection it
|
|
130
|
+
/// does not own. Advisory by nature — it is a snapshot of a queue that is
|
|
131
|
+
/// draining as it is read, which is exactly what a backpressure hint is.
|
|
132
|
+
bool writable = true;
|
|
133
|
+
/// Bytes handed to the owning reactor by send() that it has not taken up
|
|
134
|
+
/// yet. The queue itself lives on the reactor thread and `writable` above
|
|
135
|
+
/// only ever reports what the reactor has already seen — so a caller in a
|
|
136
|
+
/// tight loop could hand over megabytes before a single one of them was
|
|
137
|
+
/// counted. This is that backlog, incremented by the caller and decremented
|
|
138
|
+
/// by the reactor task, so the answer covers both halves.
|
|
139
|
+
std::shared_ptr<std::atomic<size_t>> owed =
|
|
140
|
+
std::make_shared<std::atomic<size_t>>(0);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
mutable std::shared_mutex mutex_;
|
|
144
|
+
std::unordered_map<PeerId, Entry, PeerId::Hash> peers_;
|
|
145
|
+
std::atomic<size_t> count_{0};
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
} // namespace librats
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file handshaker.h
|
|
5
|
+
* @brief Secure-channel handshake driver and the provider that creates one.
|
|
6
|
+
*
|
|
7
|
+
* A Handshaker is fed handshake messages until it yields a Session and the
|
|
8
|
+
* remote PeerId (or fails). It is transport-agnostic: the Connection frames its
|
|
9
|
+
* `out` bytes as Handshake frames and feeds inbound Handshake payloads back in.
|
|
10
|
+
*
|
|
11
|
+
* A SecurityProvider configures the whole node (one keypair / policy) and mints
|
|
12
|
+
* a fresh Handshaker per connection. Swapping NoiseSecurity ⇄ PlaintextSecurity
|
|
13
|
+
* changes the entire security posture without touching the transport.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#include "librats/util/rats_export.h"
|
|
17
|
+
#include "librats/core/bytes.h"
|
|
18
|
+
#include "librats/core/types.h" // ConnRole
|
|
19
|
+
#include "librats/peer/peer_id.h"
|
|
20
|
+
#include "librats/security/session.h"
|
|
21
|
+
|
|
22
|
+
#include <memory>
|
|
23
|
+
#include <string>
|
|
24
|
+
|
|
25
|
+
namespace librats {
|
|
26
|
+
|
|
27
|
+
/// Canonical bytes identifying an application protocol. Bound into the handshake
|
|
28
|
+
/// — as the Noise prologue, or exchanged-and-checked in the plaintext handshake —
|
|
29
|
+
/// so peers whose protocol differs cannot connect. The protocol string is an
|
|
30
|
+
/// opaque identity compared for exact equality; by convention it is "<name>/
|
|
31
|
+
/// <version>" (e.g. "librats/1.0"), but any difference at all is a distinct
|
|
32
|
+
/// protocol. A fixed context tag namespaces it away from other prologue uses.
|
|
33
|
+
inline std::string protocol_id(const std::string& protocol) {
|
|
34
|
+
return std::string("librats-proto\x1f", 14) + protocol; // tag + opaque id
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class RATS_API Handshaker {
|
|
38
|
+
public:
|
|
39
|
+
struct Outcome {
|
|
40
|
+
enum Status { NeedMore, Done, Failed } status = NeedMore;
|
|
41
|
+
std::unique_ptr<Session> session; ///< valid iff status == Done
|
|
42
|
+
PeerId remote_id; ///< valid iff status == Done
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
virtual ~Handshaker() = default;
|
|
46
|
+
|
|
47
|
+
/// Called once when the transport is up. Appends the initial message, if
|
|
48
|
+
/// any (e.g. the initiator's first Noise message), to `out`. False on error.
|
|
49
|
+
virtual bool start(Bytes& out) = 0;
|
|
50
|
+
|
|
51
|
+
/// Consume one received handshake message; append any reply to `out`.
|
|
52
|
+
virtual Outcome consume(ByteView incoming, Bytes& out) = 0;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
class RATS_API SecurityProvider {
|
|
56
|
+
public:
|
|
57
|
+
virtual ~SecurityProvider() = default;
|
|
58
|
+
|
|
59
|
+
/// Create a handshaker for a new connection in the given role.
|
|
60
|
+
virtual std::unique_ptr<Handshaker> create(ConnRole role) = 0;
|
|
61
|
+
|
|
62
|
+
/// This node's own identity.
|
|
63
|
+
virtual const PeerId& local_id() const = 0;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
} // namespace librats
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file identity.h
|
|
5
|
+
* @brief A node's cryptographic identity: a static keypair and its derived PeerId.
|
|
6
|
+
*
|
|
7
|
+
* The PeerId is SHA-256 of the static public key, so identity travels with the
|
|
8
|
+
* key. Generate a fresh identity for an ephemeral node, or rebuild one from a
|
|
9
|
+
* persisted private key to keep a stable PeerId across restarts.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#include "librats/util/rats_export.h"
|
|
13
|
+
#include "librats/peer/peer_id.h"
|
|
14
|
+
#include "librats/crypto/noise.h"
|
|
15
|
+
|
|
16
|
+
#include <cstring>
|
|
17
|
+
|
|
18
|
+
namespace librats {
|
|
19
|
+
|
|
20
|
+
struct RATS_API Identity {
|
|
21
|
+
librats::NoiseKeyPair static_keypair;
|
|
22
|
+
PeerId id;
|
|
23
|
+
|
|
24
|
+
/// Create a brand-new random identity.
|
|
25
|
+
static Identity generate() {
|
|
26
|
+
Identity ident;
|
|
27
|
+
librats::noise_generate_keypair(ident.static_keypair);
|
|
28
|
+
ident.id = PeerId::from_public_key(ident.static_keypair.public_key, librats::NOISE_DH_SIZE);
|
|
29
|
+
return ident;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Rebuild a stable identity from a persisted 32-byte private key.
|
|
33
|
+
static Identity from_private_key(const uint8_t private_key[librats::NOISE_DH_SIZE]) {
|
|
34
|
+
Identity ident;
|
|
35
|
+
std::memcpy(ident.static_keypair.private_key, private_key, librats::NOISE_DH_SIZE);
|
|
36
|
+
librats::noise_derive_public_key(private_key, ident.static_keypair.public_key);
|
|
37
|
+
ident.static_keypair.has_keys = true;
|
|
38
|
+
ident.id = PeerId::from_public_key(ident.static_keypair.public_key, librats::NOISE_DH_SIZE);
|
|
39
|
+
return ident;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
} // namespace librats
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#include "librats/security/noise_security.h"
|
|
2
|
+
#include "librats/crypto/noise.h"
|
|
3
|
+
#include "librats/util/logger.h"
|
|
4
|
+
|
|
5
|
+
namespace librats {
|
|
6
|
+
namespace {
|
|
7
|
+
|
|
8
|
+
// Human-readable Noise failure reason for handshake diagnostics. Kept local: the
|
|
9
|
+
// crypto layer deliberately exposes only the enum, and this is its sole logger.
|
|
10
|
+
const char* noise_error_name(librats::NoiseError e) {
|
|
11
|
+
switch (e) {
|
|
12
|
+
case librats::NoiseError::OK: return "ok";
|
|
13
|
+
case librats::NoiseError::INVALID_STATE: return "invalid-state";
|
|
14
|
+
case librats::NoiseError::DECRYPT_FAILED: return "decrypt-failed";
|
|
15
|
+
case librats::NoiseError::MESSAGE_TOO_LARGE: return "message-too-large";
|
|
16
|
+
case librats::NoiseError::HANDSHAKE_NOT_COMPLETE: return "handshake-not-complete";
|
|
17
|
+
case librats::NoiseError::HANDSHAKE_ALREADY_COMPLETE: return "handshake-already-complete";
|
|
18
|
+
case librats::NoiseError::INVALID_KEY: return "invalid-key";
|
|
19
|
+
case librats::NoiseError::INTERNAL_ERROR: return "internal-error";
|
|
20
|
+
}
|
|
21
|
+
return "unknown";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// Session backed by a completed librats::NoiseSession (owns its transport ciphers).
|
|
25
|
+
class NoiseSessionAdapter final : public Session {
|
|
26
|
+
public:
|
|
27
|
+
NoiseSessionAdapter(std::unique_ptr<librats::NoiseSession> session, PeerId remote)
|
|
28
|
+
: session_(std::move(session)), remote_id_(remote) {}
|
|
29
|
+
|
|
30
|
+
bool encrypt(ByteView plain, Bytes& out) override {
|
|
31
|
+
out.resize(plain.size() + librats::NOISE_TAG_SIZE);
|
|
32
|
+
const size_t n = session_->encrypt(plain.data(), plain.size(), out.data());
|
|
33
|
+
if (n == 0 && plain.size() != 0) return false;
|
|
34
|
+
out.resize(n);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
bool decrypt(ByteView cipher, Bytes& out) override {
|
|
39
|
+
if (cipher.size() < librats::NOISE_TAG_SIZE) return false;
|
|
40
|
+
out.resize(cipher.size()); // plaintext is always shorter than ciphertext
|
|
41
|
+
const size_t n = session_->decrypt(cipher.data(), cipher.size(), out.data());
|
|
42
|
+
if (n == librats::NOISE_DECRYPT_FAILED) return false; // 0 is a valid (empty) frame
|
|
43
|
+
out.resize(n);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const PeerId& remote_id() const override { return remote_id_; }
|
|
48
|
+
bool is_secure() const override { return true; }
|
|
49
|
+
|
|
50
|
+
private:
|
|
51
|
+
std::unique_ptr<librats::NoiseSession> session_;
|
|
52
|
+
PeerId remote_id_;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/// Drives the Noise XX message exchange via librats::NoiseSession::handshake_step.
|
|
56
|
+
class NoiseHandshaker final : public Handshaker {
|
|
57
|
+
public:
|
|
58
|
+
NoiseHandshaker(const Identity& identity, bool initiator, ByteView prologue)
|
|
59
|
+
: session_(std::make_unique<librats::NoiseSession>()), initiator_(initiator) {
|
|
60
|
+
session_->start(initiator, &identity.static_keypair,
|
|
61
|
+
prologue.empty() ? nullptr : prologue.data(), prologue.size());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
bool start(Bytes& out) override {
|
|
65
|
+
if (!initiator_) return true; // responder waits for the first message
|
|
66
|
+
return step(nullptr, 0, out);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Outcome consume(ByteView incoming, Bytes& out) override {
|
|
70
|
+
Outcome oc;
|
|
71
|
+
if (!step(incoming.data(), incoming.size(), out)) {
|
|
72
|
+
oc.status = Outcome::Failed;
|
|
73
|
+
return oc;
|
|
74
|
+
}
|
|
75
|
+
if (session_->is_handshake_complete()) {
|
|
76
|
+
oc.remote_id = PeerId::from_public_key(session_->get_remote_static_public(),
|
|
77
|
+
librats::NOISE_DH_SIZE);
|
|
78
|
+
oc.session = std::make_unique<NoiseSessionAdapter>(std::move(session_), oc.remote_id);
|
|
79
|
+
oc.status = Outcome::Done;
|
|
80
|
+
}
|
|
81
|
+
return oc;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private:
|
|
85
|
+
// Run one handshake step; append the outgoing message (if any) to `out`.
|
|
86
|
+
bool step(const uint8_t* received, size_t received_len, Bytes& out) {
|
|
87
|
+
// A Noise transport message is capped at 65535 bytes; reject anything
|
|
88
|
+
// larger before it reaches the state machine. Defense in depth: the
|
|
89
|
+
// block layer admits frames up to kMaxBlockSize (64 MB), so without
|
|
90
|
+
// this an oversized handshake frame would be fed straight in.
|
|
91
|
+
if (received_len > librats::NOISE_MAX_MESSAGE_SIZE) {
|
|
92
|
+
LOG_DEBUG("noise", "Rejecting oversized handshake message (" << received_len << " B)");
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
uint8_t buffer[librats::NOISE_MAX_MESSAGE_SIZE];
|
|
97
|
+
size_t len = sizeof(buffer);
|
|
98
|
+
bool need_to_send = false;
|
|
99
|
+
const auto err = session_->handshake_step(received, received_len, buffer, &len, &need_to_send);
|
|
100
|
+
if (err != librats::NoiseError::OK) {
|
|
101
|
+
LOG_DEBUG("noise", "Handshake step failed: " << noise_error_name(err)
|
|
102
|
+
<< " (" << (initiator_ ? "initiator" : "responder") << ")");
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
if (need_to_send) out.insert(out.end(), buffer, buffer + len);
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
std::unique_ptr<librats::NoiseSession> session_;
|
|
110
|
+
bool initiator_;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
} // namespace
|
|
114
|
+
|
|
115
|
+
NoiseSecurity::NoiseSecurity(Identity identity, std::string protocol)
|
|
116
|
+
: identity_(identity), prologue_(protocol_id(protocol)) {}
|
|
117
|
+
|
|
118
|
+
std::unique_ptr<Handshaker> NoiseSecurity::create(ConnRole role) {
|
|
119
|
+
return std::make_unique<NoiseHandshaker>(identity_, role == ConnRole::Outbound, ByteView(prologue_));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
} // namespace librats
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file noise_security.h
|
|
5
|
+
* @brief Noise_XX_25519_ChaChaPoly_SHA256 secure channel with self-certifying ids.
|
|
6
|
+
*
|
|
7
|
+
* Wraps the existing librats::NoiseSession (src/noise.h) behind the
|
|
8
|
+
* SecurityProvider/Handshaker/Session contract. The XX pattern mutually
|
|
9
|
+
* authenticates both static keys, and each side derives the other's PeerId from
|
|
10
|
+
* the static key it proved — so a completed handshake is also identity proof.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
#include "librats/util/rats_export.h"
|
|
14
|
+
#include "librats/security/handshaker.h"
|
|
15
|
+
#include "librats/security/identity.h"
|
|
16
|
+
|
|
17
|
+
#include <memory>
|
|
18
|
+
#include <string>
|
|
19
|
+
|
|
20
|
+
namespace librats {
|
|
21
|
+
|
|
22
|
+
class RATS_API NoiseSecurity final : public SecurityProvider {
|
|
23
|
+
public:
|
|
24
|
+
/// @param protocol Application protocol id, bound into the Noise handshake
|
|
25
|
+
/// prologue. Peers whose protocol differs cannot complete a handshake
|
|
26
|
+
/// — cross-application isolation, enforced cryptographically (a
|
|
27
|
+
/// mismatch fails the handshake MAC). By convention "<name>/<version>".
|
|
28
|
+
explicit NoiseSecurity(Identity identity, std::string protocol = "librats/1.0");
|
|
29
|
+
std::unique_ptr<Handshaker> create(ConnRole role) override;
|
|
30
|
+
const PeerId& local_id() const override { return identity_.id; }
|
|
31
|
+
|
|
32
|
+
private:
|
|
33
|
+
Identity identity_;
|
|
34
|
+
std::string prologue_; ///< length-prefixed name+version, mixed into every handshake
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} // namespace librats
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file plaintext_security.h
|
|
5
|
+
* @brief Unencrypted "secure channel": exchanges PeerIds, encrypts nothing.
|
|
6
|
+
*
|
|
7
|
+
* Useful for local/testing setups and as the trivial reference implementation
|
|
8
|
+
* of the SecurityProvider/Handshaker/Session contract. The handshake exchanges
|
|
9
|
+
* one message each way carrying the protocol id and the PeerId; the resulting
|
|
10
|
+
* Session is a passthrough. Note the identity here is NOT authenticated (no key
|
|
11
|
+
* proof) — that is the inherent trade-off of running without encryption.
|
|
12
|
+
*
|
|
13
|
+
* The protocol id is still checked (so two apps with different protocol can't
|
|
14
|
+
* cross-connect even unencrypted), but unlike the Noise prologue it is not
|
|
15
|
+
* cryptographically bound — a plaintext peer can claim any protocol. That is
|
|
16
|
+
* acceptable for the plaintext mode's trusted/testing use cases.
|
|
17
|
+
*
|
|
18
|
+
* Handshake message: [proto_len:u16][protocol id][peer id: 32 bytes].
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
#include "librats/security/handshaker.h"
|
|
22
|
+
#include "librats/security/identity.h"
|
|
23
|
+
|
|
24
|
+
#include <cstring>
|
|
25
|
+
#include <memory>
|
|
26
|
+
#include <string>
|
|
27
|
+
|
|
28
|
+
namespace librats {
|
|
29
|
+
|
|
30
|
+
/// Passthrough session: encrypt/decrypt just copy the bytes.
|
|
31
|
+
class PlaintextSession final : public Session {
|
|
32
|
+
public:
|
|
33
|
+
explicit PlaintextSession(PeerId remote) : remote_id_(remote) {}
|
|
34
|
+
bool encrypt(ByteView plain, Bytes& out) override { out.assign(plain.begin(), plain.end()); return true; }
|
|
35
|
+
bool decrypt(ByteView cipher, Bytes& out) override { out.assign(cipher.begin(), cipher.end()); return true; }
|
|
36
|
+
const PeerId& remote_id() const override { return remote_id_; }
|
|
37
|
+
bool is_secure() const override { return false; }
|
|
38
|
+
private:
|
|
39
|
+
PeerId remote_id_;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/// One-message-each exchange of [protocol id][PeerId].
|
|
43
|
+
class PlaintextHandshaker final : public Handshaker {
|
|
44
|
+
public:
|
|
45
|
+
PlaintextHandshaker(PeerId local, bool initiator, std::string proto)
|
|
46
|
+
: local_(local), proto_(std::move(proto)), initiator_(initiator) {}
|
|
47
|
+
|
|
48
|
+
bool start(Bytes& out) override {
|
|
49
|
+
if (initiator_) append_message(out); // initiator announces first
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
Outcome consume(ByteView incoming, Bytes& out) override {
|
|
54
|
+
Outcome oc;
|
|
55
|
+
const uint8_t* p = incoming.data();
|
|
56
|
+
const size_t n = incoming.size();
|
|
57
|
+
if (n < 2) { oc.status = Outcome::Failed; return oc; }
|
|
58
|
+
|
|
59
|
+
const size_t proto_len = (static_cast<size_t>(p[0]) << 8) | p[1];
|
|
60
|
+
if (n < 2 + proto_len + PeerId::kSize) { oc.status = Outcome::Failed; return oc; }
|
|
61
|
+
|
|
62
|
+
// Reject a peer announcing a different protocol id.
|
|
63
|
+
if (proto_len != proto_.size() ||
|
|
64
|
+
std::memcmp(p + 2, proto_.data(), proto_len) != 0) {
|
|
65
|
+
oc.status = Outcome::Failed;
|
|
66
|
+
return oc;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
auto remote = PeerId::from_bytes(ByteView(p + 2 + proto_len, PeerId::kSize));
|
|
70
|
+
if (!remote) { oc.status = Outcome::Failed; return oc; }
|
|
71
|
+
|
|
72
|
+
if (!initiator_) append_message(out); // responder replies
|
|
73
|
+
oc.status = Outcome::Done;
|
|
74
|
+
oc.remote_id = *remote;
|
|
75
|
+
oc.session = std::make_unique<PlaintextSession>(*remote);
|
|
76
|
+
return oc;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private:
|
|
80
|
+
void append_message(Bytes& out) {
|
|
81
|
+
out.push_back(static_cast<uint8_t>((proto_.size() >> 8) & 0xFF));
|
|
82
|
+
out.push_back(static_cast<uint8_t>(proto_.size() & 0xFF));
|
|
83
|
+
out.insert(out.end(), proto_.begin(), proto_.end());
|
|
84
|
+
const auto& b = local_.bytes();
|
|
85
|
+
out.insert(out.end(), b.begin(), b.end());
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
PeerId local_;
|
|
89
|
+
std::string proto_;
|
|
90
|
+
bool initiator_;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
class PlaintextSecurity final : public SecurityProvider {
|
|
94
|
+
public:
|
|
95
|
+
explicit PlaintextSecurity(Identity identity, std::string protocol = "librats/1.0")
|
|
96
|
+
: identity_(identity), proto_(protocol_id(protocol)) {}
|
|
97
|
+
std::unique_ptr<Handshaker> create(ConnRole role) override {
|
|
98
|
+
return std::make_unique<PlaintextHandshaker>(identity_.id, role == ConnRole::Outbound, proto_);
|
|
99
|
+
}
|
|
100
|
+
const PeerId& local_id() const override { return identity_.id; }
|
|
101
|
+
private:
|
|
102
|
+
Identity identity_;
|
|
103
|
+
std::string proto_;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
} // namespace librats
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file session.h
|
|
5
|
+
* @brief Post-handshake symmetric session: encrypts/decrypts transport frames.
|
|
6
|
+
*
|
|
7
|
+
* A Session is produced by a Handshaker once the secure channel is established.
|
|
8
|
+
* The Connection holds it and runs every outbound frame through encrypt() and
|
|
9
|
+
* every inbound frame through decrypt(). The plaintext mode supplies a
|
|
10
|
+
* passthrough Session so the Connection code path is identical with or without
|
|
11
|
+
* encryption — no `if (encrypted)` scattered through the hot path.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#include "librats/util/rats_export.h"
|
|
15
|
+
#include "librats/core/bytes.h"
|
|
16
|
+
#include "librats/peer/peer_id.h"
|
|
17
|
+
|
|
18
|
+
namespace librats {
|
|
19
|
+
|
|
20
|
+
class RATS_API Session {
|
|
21
|
+
public:
|
|
22
|
+
virtual ~Session() = default;
|
|
23
|
+
|
|
24
|
+
/// Encrypt `plain` into `out` (resized to fit). Returns false on failure.
|
|
25
|
+
virtual bool encrypt(ByteView plain, Bytes& out) = 0;
|
|
26
|
+
|
|
27
|
+
/// Decrypt `cipher` into `out` (resized to fit). Returns false on failure.
|
|
28
|
+
virtual bool decrypt(ByteView cipher, Bytes& out) = 0;
|
|
29
|
+
|
|
30
|
+
/// The remote peer's identity, proven during the handshake.
|
|
31
|
+
virtual const PeerId& remote_id() const = 0;
|
|
32
|
+
|
|
33
|
+
/// True if traffic is actually encrypted (false for the plaintext passthrough).
|
|
34
|
+
virtual bool is_secure() const = 0;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} // namespace librats
|