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

Commit

Permalink
libconvert: send cookie TLV on client side
Browse files Browse the repository at this point in the history
It is now possible to send a cookie TLV from the client using libconvert.
New tests have been added to check that the expected Cookie message is
sent and the Cookie TLV error is properly received and understood.

Signed-off-by: Pol Nicolaï <[email protected]>
Change-Id: I51fe5dce0bc1d24c10808b44d906224a91a82bab
  • Loading branch information
polnicoTessares committed Dec 30, 2021
1 parent 8209672 commit a4cf9ba
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 a4cf9ba

Please sign in to comment.