diff --git a/.aspell.en.pws b/.aspell.en.pws
index 2c0d09fdf..3fc6da7c4 100644
--- a/.aspell.en.pws
+++ b/.aspell.en.pws
@@ -387,3 +387,5 @@ CHECKSIGVERIFY
IFDUP
sats
anysegwit
+WebSocket
+websocket
diff --git a/07-routing-gossip.md b/07-routing-gossip.md
index b89c3d222..a8b35e60c 100644
--- a/07-routing-gossip.md
+++ b/07-routing-gossip.md
@@ -285,6 +285,7 @@ The following `address descriptor` types are defined:
onion service addresses; Encodes:
`[32:32_byte_ed25519_pubkey] || [2:checksum] || [1:version]`, where
`checksum = sha3(".onion checksum" | pubkey || version)[:2]`.
+ * `6`: WebSocket port; data = `[2:port]` (length 2)
### Requirements
@@ -306,12 +307,16 @@ The origin node:
- MUST place address descriptors in ascending order.
- SHOULD NOT place any zero-typed address descriptors anywhere.
- SHOULD use placement only for aligning fields that follow `addresses`.
- - MUST NOT create a `type 1` OR `type 2` address descriptor with `port` equal
+ - MUST NOT create a `type 1`, `type 2` or `type 6` address descriptor with `port` equal
to 0.
- SHOULD ensure `ipv4_addr` AND `ipv6_addr` are routable addresses.
- MUST set `features` according to [BOLT #9](09-features.md#assigned-features-flags)
- SHOULD set `flen` to the minimum length required to hold the `features`
bits it sets.
+ - MUST NOT add a `type 6` address unless there is also at least one address of different type.
+ - if it adds a type 6 address:
+ - MUST allow unencrypted RFC6455[3](#reference-3) as a transport when a connection is made to at least one of the other addresses, with the type 6 `port` substituted for that address's `port`
+ - SHOULD allow this on ALL of the other addresses.
The receiving node:
- if `node_id` is NOT a valid compressed public key:
@@ -359,6 +364,12 @@ to be ordered in ascending order, unknown ones can be safely ignored.
Additional fields beyond `addresses` may also be added in the future—with
optional padding within `addresses`, if they require certain alignment.
+Websockets generally are run on adjacent ports (or even overloaded on
+the same port) as existing "raw" transports, so including just the
+port is a compromise which avoids replacating all the addresses. It's
+ideal if all addresses support this, but it's not a hard requirement:
+at least one must.
+
### Security Considerations for Node Aliases
Node aliases are user-defined and provide a potential avenue for injection
@@ -1123,6 +1134,7 @@ above.
1. [RFC 1950 "ZLIB Compressed Data Format Specification version 3.3](https://www.ietf.org/rfc/rfc1950.txt)
2. [Maximum Compression Factor](https://zlib.net/zlib_tech.html)
+3. [RFC 6455 "The WebSocket Protocol"](https://datatracker.ietf.org/doc/html/rfc6455)

diff --git a/08-transport.md b/08-transport.md
index 49ca45e05..6c654533d 100644
--- a/08-transport.md
+++ b/08-transport.md
@@ -18,6 +18,7 @@ of a node.
* [Handshake State](#handshake-state)
* [Handshake State Initialization](#handshake-state-initialization)
* [Handshake Exchange](#handshake-exchange)
+ * [Alternate Transport Layers: WebSocket](#websocket)
* [Lightning Message Specification](#lightning-message-specification)
* [Encrypting and Sending Messages](#encrypting-and-sending-messages)
* [Receiving and Decrypting Messages](#receiving-and-decrypting-messages)
@@ -402,6 +403,36 @@ construction, and 16 bytes for a final authenticating tag.
10. `rn = 0, sn = 0`
* The sending and receiving nonces are initialized to 0.
+## Alternate Transport Layers: WebSocket
+
+Normally the transport protocol defined here is performed over TCP/IP,
+but it can also be performed over other underlying transports, such as
+the WebSocket protocol as specified in
+RFC6455[4](#reference-4) on ports so-advertized (in the
+[node_announcement message](07-routing-gossip.md#the-node_announcement-message).
+
+A client may connect to this port node and initiate a WebSocket; and
+operate the protocol over binary WebSocket frames instead of raw TCP/IP.
+
+
+### Requirements
+
+The initiator:
+- MAY attempt to initiate an unencrypted WebSocket as specified in RFC6455[4](#reference-4):
+ - MUST abort the connection attempt if WebSocket upgrade fails.
+ - MUST begin the [Handshake Exchange](#handshake-exchange) as initiator
+ as soon as upgrade succeeds.
+
+The responder:
+- if it supports WebSocket connections on a port:
+ - SHOULD advertize it using a type 5 address its node announcement.
+ - MUST abort the connection attempt if WebSocket upgrade fails.
+
+Both nodes, after upgrade:
+ - MUST use binary frames to send and receive messages.
+ - MUST NOT rely on WebSocket framing for message semantics.
+
+
## Lightning Message Specification
At the conclusion of Act Three, both sides have derived the encryption keys, which
@@ -779,6 +810,7 @@ TODO(roasbeef); fin
1. https://tools.ietf.org/html/rfc8439
2. http://noiseprotocol.org/noise.html
3. https://tools.ietf.org/html/rfc5869
+4. https://tools.ietf.org/html/rfc6455
# Authors
diff --git a/09-features.md b/09-features.md
index b508bac70..29949e191 100644
--- a/09-features.md
+++ b/09-features.md
@@ -88,4 +88,5 @@ This work is licensed under a [Creative Commons Attribution 4.0 International Li
[bolt07-sync]: 07-routing-gossip.md#initial-sync
[bolt07-query]: 07-routing-gossip.md#query-messages
[bolt04-mpp]: 04-onion-routing.md#basic-multi-part-payments
+[bolt08-websocket]: 08-transport.md#websocket
[ml-sighash-single-harmful]: https://lists.linuxfoundation.org/pipermail/lightning-dev/2020-September/002796.html