Skip to content
This repository has been archived by the owner on Aug 30, 2024. It is now read-only.

Commit

Permalink
Merge pull request #27 from polnico/cookie-client
Browse files Browse the repository at this point in the history
libconvert: send cookie TLV on client side
  • Loading branch information
matttbe authored Jan 11, 2022
2 parents 8209672 + a4cf9ba commit 948053c
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 7 deletions.
19 changes: 16 additions & 3 deletions convert_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ static LIST_HEAD(socket_htbl_t, socket_state) _socket_htable[NUM_BUCKETS];
static pthread_mutex_t _socket_htable_mutex = PTHREAD_MUTEX_INITIALIZER;

static struct addrinfo *_converter_addr;
static const char * _convert_port = CONVERT_PORT;
static const char * _convert_port = CONVERT_PORT;
static const char * _convert_cookie = NULL;

static FILE * _log;
static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
Expand Down Expand Up @@ -175,6 +176,12 @@ _redirect_connect_tlv(uint8_t *buf, size_t buf_len, struct sockaddr *addr)

opts.flags = CONVERT_F_CONNECT;

if (_convert_cookie) {
opts.flags |= CONVERT_F_COOKIE;
opts.cookie_len = strlen(_convert_cookie);
opts.cookie_data = (uint8_t *)_convert_cookie;
}

switch (addr->sa_family) {
case AF_INET: {
struct sockaddr_in *in = (struct sockaddr_in *)addr;
Expand Down Expand Up @@ -543,6 +550,7 @@ _validate_parameters(char *err_buf, size_t len)
{
const char * convert_addr = getenv("CONVERT_ADDR");
const char * convert_port = getenv("CONVERT_PORT");
const char * convert_cookie = getenv("CONVERT_COOKIE");

if (!convert_addr) {
snprintf(err_buf, len,
Expand All @@ -565,15 +573,20 @@ _validate_parameters(char *err_buf, size_t len)
_convert_port = convert_port;
}

if (convert_cookie)
_convert_cookie = convert_cookie;

/* resolve address */
if (getaddrinfo(convert_addr, _convert_port, NULL,
&_converter_addr) != 0) {
snprintf(err_buf, len, "unable to resolve '%s'", convert_addr);
return -1;
}

log_info("connecting to convert service at %s:%s",
convert_addr, _convert_port);
log_info("connecting to convert service at %s:%s%s%s",
convert_addr, _convert_port,
_convert_cookie ? " with cookie: " : "",
_convert_cookie ? : "");

return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ add_test(NAME check_convert_util
set(TEST_WRAPPER "${PROJECT_SOURCE_DIR}/tests/test-wrapper")

foreach(TEST_CMD "curl" "wget")
foreach(TEST_TYPE "test_ok" "test_error")
foreach(TEST_TYPE "test_ok" "test_error" "test_cookie_ok" "test_cookie_error")
set (test_name "${TEST_CMD}-${TEST_TYPE}")

add_test(NAME "${test_name}"
Expand Down
2 changes: 1 addition & 1 deletion tests/check_convert_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ START_TEST (test_convert_parse_tlvs_cookie) {

for (i = 0; i < cookie_len; ++i)
ck_assert_msg(opts->cookie_data[i] == cookie->opaque[i],
"Should return exact copy TCP options");
"Should return exact cookie value");

convert_free_opts(opts);
free(buff);
Expand Down
37 changes: 36 additions & 1 deletion tests/converter_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,30 @@ def run(self, converter):
converter.recv_end_seq += 1
payload = pkt.getlayer(Raw)
if payload:
converter.recv_end_seq += len(payload.load)
payload = payload.load

converter.recv_end_seq += len(payload)

# For the moment, we assume the TLV connect contains the header (4 bytes)
# and the TLV Connect (4 + 16 bytes). The cookie is then at the offset 24.
cookie_flag_offset = 24

# The cookie will only be received in the syn pkt.
if tcp.flags.S and len(payload) > cookie_flag_offset and bytes(payload)[cookie_flag_offset] == 0x16:

# The cookie TLV is as follows: 1 byte flag + 1 byte TLV length
# + 2 byte zeros, then Cookie data
cookie_size_offset = cookie_flag_offset + 1
cookie_data_offset = cookie_flag_offset + 4

# Length is given in 32-bit words, and includes flag byte + length
# byte and the 2 bytes of zeros.
cookie_data_size = (bytes(payload)[cookie_size_offset] - 1) * 4

cookie_data_offset_end = cookie_data_offset + cookie_data_size

cookie_bytes = bytes(payload)[cookie_data_offset:cookie_data_offset_end]
converter.cookie = cookie_bytes.decode('utf-8').rstrip('\x00')


class RecvSyn(RecvPkt):
Expand Down Expand Up @@ -98,6 +121,18 @@ def run(self, converter):
super(SendSynAck, self).run(converter)


class SendSynAckCheckCookie(SendSynAck):
def __init__(self, payload, cookie):
SendSynAck.__init__(self, payload=payload)
self.cookie = cookie

def run(self, converter):
# Check cookie value
if self.cookie != converter.cookie:
raise Exception("Wrong cookie '{}' instead of '{}'".format(converter.cookie, self.cookie))
super(SendSynAckCheckCookie, self).run(converter)


class SendHTTPResp(SendPkt):
def __init__(self, data):
payload = "HTTP/1.1 200 OK\r\n"
Expand Down
7 changes: 6 additions & 1 deletion tests/test-wrapper
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export TEST_CONVERT_LOG=convert.log
export TEST_OUTPUT_LOG=output.log
export TEST_CONVERT_MOCK_LOG=convert_mock.log
export TEST_VALIDATE_LOG=validate.log
export TEST_CONVERT_COOKIE="cookie"

SCAPY_PID=

Expand Down Expand Up @@ -60,7 +61,11 @@ sleep 1


COMMAND=$(test_step run_cmd)
CONVERT_LOG=${TEST_CONVERT_LOG} CONVERT_ADDR=127.0.0.1 LD_PRELOAD="../libconvert_client.so" ${COMMAND} > ${TEST_OUTPUT_LOG} 2>&1 || true
CONVERT_LOG=${TEST_CONVERT_LOG} \
CONVERT_ADDR=127.0.0.1 \
CONVERT_COOKIE=${TEST_CONVERT_COOKIE} \
LD_PRELOAD="../libconvert_client.so" \
${COMMAND} > ${TEST_OUTPUT_LOG} 2>&1 || true

ret=$(test_step validate 2>&1 | tee ${TEST_VALIDATE_LOG})
[ "${ret}" == "" ] && RETURN_CODE=0
Expand Down
21 changes: 21 additions & 0 deletions tests/test_cookie_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env python3

from converter_mock import *
from test_lib import *


class TestCookieError(TestInstance):
def run(self):
converter = Convert(tlvs=[ConvertTLV_Error(error_code=3)])
print(converter.build())
cookie = self.get_cookie()

class MockConverterCookieError(MockConverter):
actions = [RecvSyn(), SendSynAckCheckCookie(converter.build(), cookie), Wait(1), SendPkt(flags='R')]
MockConverterCookieError()

def validate(self):
self.assert_log_contains("received TLV error: 3")


TestCookieError()
19 changes: 19 additions & 0 deletions tests/test_cookie_ok.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python3

from converter_mock import *
from test_lib import *


class TestCookieOK(TestInstance):
def run(self):
cookie = self.get_cookie()
class MockConverterCookieOK(MockConverter):
actions = [RecvSyn(), SendSynAckCheckCookie(Convert().build(), cookie), RecvHTTPGet(
), SendHTTPResp("HELLO, WORLD!"), SendPkt(flags='RA')]
MockConverterCookieOK()

def validate(self):
self.assert_result("HELLO, WORLD!")


TestCookieOK()
3 changes: 3 additions & 0 deletions tests/test_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ def _get_log(self):
with open(os.environ["TEST_CONVERT_LOG"]) as f:
return f.read()

def get_cookie(self):
return os.environ["TEST_CONVERT_COOKIE"]

def assert_result(self, result):
assert result in self._get_result(), "Couldn't find '{}' in output".format(result)

Expand Down

0 comments on commit 948053c

Please sign in to comment.