Skip to content

Commit

Permalink
lightning_websocketd: simple proxy for websockets.
Browse files Browse the repository at this point in the history
WebSocket is a bit weird:
1. It starts like an HTTP connection, but they send special headers.
2. We reply with special headers, one of which involves SHA1 of one of theirs.
3. We are then in WebSocket mode, where each frame starts with a 2-20 byte
   header.

We relay data in a simplistic way: if either side sends something, we
read it and relay it synchronously.  That avoids any gratuitous
buffering.

Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
rustyrussell authored and cdecker committed Oct 22, 2021
1 parent f78184c commit 80a47f1
Show file tree
Hide file tree
Showing 7 changed files with 741 additions and 4 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@ PKGLIBEXEC_PROGRAMS = \
lightningd/lightning_gossipd \
lightningd/lightning_hsmd \
lightningd/lightning_onchaind \
lightningd/lightning_openingd
lightningd/lightning_openingd \
lightningd/lightning_websocketd

# Don't delete these intermediaries.
.PRECIOUS: $(ALL_GEN_HEADERS) $(ALL_GEN_SOURCES)
Expand Down
13 changes: 11 additions & 2 deletions connectd/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@ CONNECTD_SRC := $(CONNECTD_HEADERS:.h=.c) connectd/connectd.c
CONNECTD_OBJS := $(CONNECTD_SRC:.c=.o)
$(CONNECTD_OBJS): $(CONNECTD_HEADERS)

WEBSOCKETD_HEADERS := connectd/sha1.h
WEBSOCKETD_SRC := $(WEBSOCKETD_HEADERS:.h=.c) connectd/websocketd.c

WEBSOCKETD_OBJS := $(WEBSOCKETD_SRC:.c=.o)
$(WEBSOCKETD_OBJS): $(WEBSOCKETD_HEADERS)

# Make sure these depend on everything.
ALL_C_SOURCES += $(CONNECTD_SRC)
ALL_C_HEADERS += $(CONNECTD_HEADERS)
ALL_C_SOURCES += $(CONNECTD_SRC) $(WEBSOCKETD_SRC)
ALL_C_HEADERS += $(CONNECTD_HEADERS) $(WEBSOCKETD_HEADERS)
ALL_PROGRAMS += lightningd/lightning_connectd
ALL_PROGRAMS += lightningd/lightning_websocketd

# Here's what lightningd depends on
LIGHTNINGD_CONTROL_HEADERS += connectd/connectd_wiregen.h
Expand Down Expand Up @@ -69,4 +76,6 @@ CONNECTD_COMMON_OBJS := \

lightningd/lightning_connectd: $(CONNECTD_OBJS) $(CONNECTD_COMMON_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(HSMD_CLIENT_OBJS)

lightningd/lightning_websocketd: $(WEBSOCKETD_OBJS) common/setup.o common/utils.o

include connectd/test/Makefile
190 changes: 190 additions & 0 deletions connectd/sha1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/* hex variants removed -- RR */
#include <connectd/sha1.h>

/*******************************************************************************
* Teeny SHA-1
*
* The below sha1digest() calculates a SHA-1 hash value for a
* specified data buffer and generates a hex representation of the
* result. This implementation is a re-forming of the SHA-1 code at
* https://github.com/jinqiangshou/EncryptionLibrary.
*
* Copyright (c) 2017 CTrabant
*
* License: MIT, see included LICENSE file for details.
*
* To use the sha1digest() function either copy it into an existing
* project source code file or include this file in a project and put
* the declaration (example below) in the sources files where needed.
******************************************************************************/

#include <string.h>

/* Declaration:
extern int sha1digest(uint8_t *digest, const uint8_t *data, size_t databytes);
*/

/*******************************************************************************
* sha1digest: https://github.com/CTrabant/teeny-sha1
*
* Calculate the SHA-1 value for supplied data buffer and generate a
* text representation in hexadecimal.
*
* Based on https://github.com/jinqiangshou/EncryptionLibrary, credit
* goes to @jinqiangshou, all new bugs are mine.
*
* @input:
* data -- data to be hashed
* databytes -- bytes in data buffer to be hashed
*
* @output:
* digest -- the result, MUST be at least 20 bytes
*
* @return: 0 on success and non-zero on error.
******************************************************************************/
int
sha1digest(uint8_t *digest, const uint8_t *data, size_t databytes)
{
#define SHA1ROTATELEFT(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))

uint32_t W[80];
uint32_t H[] = {0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
0xC3D2E1F0};
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
uint32_t e;
uint32_t f = 0;
uint32_t k = 0;

uint32_t idx;
uint32_t lidx;
uint32_t widx;
uint32_t didx = 0;

int32_t wcount;
uint32_t temp;
uint64_t databits = ((uint64_t)databytes) * 8;
uint32_t loopcount = (databytes + 8) / 64 + 1;
uint32_t tailbytes = 64 * loopcount - databytes;
uint8_t datatail[128] = {0};

if (!digest)
return -1;

if (!data)
return -1;

/* Pre-processing of data tail (includes padding to fill out 512-bit chunk):
Add bit '1' to end of message (big-endian)
Add 64-bit message length in bits at very end (big-endian) */
datatail[0] = 0x80;
datatail[tailbytes - 8] = (uint8_t) (databits >> 56 & 0xFF);
datatail[tailbytes - 7] = (uint8_t) (databits >> 48 & 0xFF);
datatail[tailbytes - 6] = (uint8_t) (databits >> 40 & 0xFF);
datatail[tailbytes - 5] = (uint8_t) (databits >> 32 & 0xFF);
datatail[tailbytes - 4] = (uint8_t) (databits >> 24 & 0xFF);
datatail[tailbytes - 3] = (uint8_t) (databits >> 16 & 0xFF);
datatail[tailbytes - 2] = (uint8_t) (databits >> 8 & 0xFF);
datatail[tailbytes - 1] = (uint8_t) (databits >> 0 & 0xFF);

/* Process each 512-bit chunk */
for (lidx = 0; lidx < loopcount; lidx++)
{
/* Compute all elements in W */
memset (W, 0, 80 * sizeof (uint32_t));

/* Break 512-bit chunk into sixteen 32-bit, big endian words */
for (widx = 0; widx <= 15; widx++)
{
wcount = 24;

/* Copy byte-per byte from specified buffer */
while (didx < databytes && wcount >= 0)
{
W[widx] += (((uint32_t)data[didx]) << wcount);
didx++;
wcount -= 8;
}
/* Fill out W with padding as needed */
while (wcount >= 0)
{
W[widx] += (((uint32_t)datatail[didx - databytes]) << wcount);
didx++;
wcount -= 8;
}
}

/* Extend the sixteen 32-bit words into eighty 32-bit words, with potential optimization from:
"Improving the Performance of the Secure Hash Algorithm (SHA-1)" by Max Locktyukhin */
for (widx = 16; widx <= 31; widx++)
{
W[widx] = SHA1ROTATELEFT ((W[widx - 3] ^ W[widx - 8] ^ W[widx - 14] ^ W[widx - 16]), 1);
}
for (widx = 32; widx <= 79; widx++)
{
W[widx] = SHA1ROTATELEFT ((W[widx - 6] ^ W[widx - 16] ^ W[widx - 28] ^ W[widx - 32]), 2);
}

/* Main loop */
a = H[0];
b = H[1];
c = H[2];
d = H[3];
e = H[4];

for (idx = 0; idx <= 79; idx++)
{
if (idx <= 19)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if (idx >= 20 && idx <= 39)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if (idx >= 40 && idx <= 59)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else if (idx >= 60 && idx <= 79)
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = SHA1ROTATELEFT (a, 5) + f + e + k + W[idx];
e = d;
d = c;
c = SHA1ROTATELEFT (b, 30);
b = a;
a = temp;
}

H[0] += a;
H[1] += b;
H[2] += c;
H[3] += d;
H[4] += e;
}

/* Store binary digest in supplied buffer */
if (digest)
{
for (idx = 0; idx < 5; idx++)
{
digest[idx * 4 + 0] = (uint8_t) (H[idx] >> 24);
digest[idx * 4 + 1] = (uint8_t) (H[idx] >> 16);
digest[idx * 4 + 2] = (uint8_t) (H[idx] >> 8);
digest[idx * 4 + 3] = (uint8_t) (H[idx]);
}
}

return 0;
} /* End of sha1digest() */
9 changes: 9 additions & 0 deletions connectd/sha1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef LIGHTNING_CONNECTD_SHA1_H
#define LIGHTNING_CONNECTD_SHA1_H
#include "config.h"
#include <stdint.h>
#include <stdlib.h>

extern int sha1digest(uint8_t *digest, const uint8_t *data, size_t databytes);

#endif /* LIGHTNING_CONNECTD_SHA1_H */
2 changes: 1 addition & 1 deletion connectd/test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ALL_TEST_PROGRAMS += $(CONNECTD_TEST_PROGRAMS)
$(CONNECTD_TEST_PROGRAMS): $(CONNECTD_TEST_COMMON_OBJS) $(BITCOIN_OBJS)

# Test objects depend on ../ src and headers.
$(CONNECTD_TEST_OBJS): $(CONNECTD_HEADERS) $(CONNECTD_SRC)
$(CONNECTD_TEST_OBJS): $(CONNECTD_HEADERS) $(CONNECTD_SRC) $(WEBSOCKETD_HEADERS) $(WEBSOCKETD_SRC)

check-units: $(CONNECTD_TEST_PROGRAMS:%=unittest/%)

Loading

0 comments on commit 80a47f1

Please sign in to comment.