Attention is currently required from: plaisthos.
Hello plaisthos,
I'd like you to do a code review.
Please visit
http://gerrit.openvpn.net/c/openvpn/+/1745?usp=email
to review the following change.
Change subject: oob: Add client PROBE_REPLY parser
......................................................................
oob: Add client PROBE_REPLY parser
Add oob_client_reply_read(), the client-side counterpart of
oob_server_probe_read(): it scans the TLV payload of a received PROBE_REPLY
for the probe_reply TLV, skipping other/future TLV types.
Factor the shared TLV scan used by both into a static oob_find_tlv() helper
so the two readers no longer duplicate the loop.
Change-Id: If04ce09d4c353f5384c0c48f48f63e05869a373f
Signed-off-by: Lev Stipakov <[email protected]>
---
M src/openvpn/oob.c
M src/openvpn/oob.h
M tests/unit_tests/openvpn/test_oob.c
3 files changed, 130 insertions(+), 15 deletions(-)
git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/45/1745/1
diff --git a/src/openvpn/oob.c b/src/openvpn/oob.c
index f7af0ef..9cc7c42 100644
--- a/src/openvpn/oob.c
+++ b/src/openvpn/oob.c
@@ -160,31 +160,28 @@
&& oob_probe_parameter_write(buf, param);
}
-bool
-oob_server_probe_read(struct buffer *payload, struct oob_probe_parameter
*param)
+/* Scan @p payload for the first TLV of type @p wanted_type, skipping any other
+ * (e.g. future) TLV types. On success @p payload is left positioned at that
+ * TLV's value and *value_len is its declared length. Returns false if the TLV
+ * is not found or a header/length is malformed. */
+static bool
+oob_find_tlv(struct buffer *payload, uint16_t wanted_type, uint16_t *value_len)
{
- if (!oob_msg_read_header(payload, OOB_MSG_SERVER_PROBE))
- {
- return false;
- }
-
- /* A TLV header is 4 bytes (type + length). Loop until we either find the
- * probe_parameter or run out of well-formed TLVs. */
+ /* A TLV header is 4 bytes (type + length). */
while (BLEN(payload) >= 4)
{
uint16_t type;
bool optional;
- uint16_t value_len;
- if (!oob_tlv_read_header(payload, &type, &optional, &value_len))
+ if (!oob_tlv_read_header(payload, &type, &optional, value_len))
{
return false;
}
- if (type == OOB_TLV_PROBE_PARAMETER)
+ if (type == wanted_type)
{
- return oob_probe_parameter_read(payload, param, value_len);
+ return true;
}
- /* not the TLV we are looking for: skip its value and keep scanning */
- if (!buf_advance(payload, value_len))
+ /* not the TLV we want: skip its value and keep scanning */
+ if (!buf_advance(payload, *value_len))
{
return false;
}
@@ -193,12 +190,30 @@
}
bool
+oob_server_probe_read(struct buffer *payload, struct oob_probe_parameter
*param)
+{
+ uint16_t value_len;
+ return oob_msg_read_header(payload, OOB_MSG_SERVER_PROBE)
+ && oob_find_tlv(payload, OOB_TLV_PROBE_PARAMETER, &value_len)
+ && oob_probe_parameter_read(payload, param, value_len);
+}
+
+bool
oob_client_reply_write(struct buffer *buf, const struct oob_probe_reply *reply)
{
return oob_msg_write_header(buf, OOB_MSG_PROBE_REPLY) &&
oob_probe_reply_write(buf, reply);
}
bool
+oob_client_reply_read(struct buffer *payload, struct oob_probe_reply *reply)
+{
+ uint16_t value_len;
+ return oob_msg_read_header(payload, OOB_MSG_PROBE_REPLY)
+ && oob_find_tlv(payload, OOB_TLV_PROBE_REPLY, &value_len)
+ && oob_probe_reply_read(payload, reply, value_len);
+}
+
+bool
oob_timestamp_in_window(uint64_t probe_ts, uint64_t now, uint64_t window_secs)
{
uint64_t diff = (now > probe_ts) ? (now - probe_ts) : (probe_ts - now);
diff --git a/src/openvpn/oob.h b/src/openvpn/oob.h
index 93c44b0..9040416 100644
--- a/src/openvpn/oob.h
+++ b/src/openvpn/oob.h
@@ -170,6 +170,19 @@
bool oob_client_reply_write(struct buffer *buf, const struct oob_probe_reply
*reply);
/**
+ * Read a received OOB PROBE_REPLY: verify its message-type header, then scan
+ * for the probe_reply TLV; the client-side counterpart of
+ * oob_server_probe_read(). TLV types other than probe_reply are skipped.
+ * @p payload is consumed as it is read.
+ *
+ * @param payload buffer positioned at the start of the OOB message payload
+ * @param reply filled with the parsed probe_reply on success
+ * @return true if the header matched and a well-formed probe_reply was found,
+ * false otherwise
+ */
+bool oob_client_reply_read(struct buffer *payload, struct oob_probe_reply
*reply);
+
+/**
* Check whether a probe timestamp is within an acceptable window around the
* current time. Used to cheaply drop replayed or implausibly-timed probes
* before doing any further work (see the probe_parameter timestamp rationale
diff --git a/tests/unit_tests/openvpn/test_oob.c
b/tests/unit_tests/openvpn/test_oob.c
index a9998d2..1029399 100644
--- a/tests/unit_tests/openvpn/test_oob.c
+++ b/tests/unit_tests/openvpn/test_oob.c
@@ -346,6 +346,89 @@
gc_free(&gc);
}
+/* A PROBE_REPLY carrying a probe_reply is found by the client scan, with all
+ * fields surviving. */
+static void
+test_client_reply_read_finds_reply(void **state)
+{
+ struct gc_arena gc = gc_new();
+ struct buffer buf = alloc_buf_gc(128, &gc);
+
+ struct oob_probe_reply in = {
+ .priority = 5,
+ .weight = 50,
+ .connect_lifetime = 120,
+ .flags = 1,
+ };
+ memcpy(in.peer_session_id.id, "SRVREPLY", SID_SIZE);
+ assert_true(oob_client_reply_write(&buf, &in));
+
+ struct oob_probe_reply out = { 0 };
+ assert_true(oob_client_reply_read(&buf, &out));
+ assert_memory_equal(out.peer_session_id.id, in.peer_session_id.id,
SID_SIZE);
+ assert_int_equal(out.priority, in.priority);
+ assert_int_equal(out.weight, in.weight);
+ assert_int_equal(out.connect_lifetime, in.connect_lifetime);
+ assert_int_equal(out.flags, in.flags);
+
+ gc_free(&gc);
+}
+
+/* TLVs other than probe_reply are skipped. */
+static void
+test_client_reply_read_skips_unknown(void **state)
+{
+ struct gc_arena gc = gc_new();
+ struct buffer buf = alloc_buf_gc(128, &gc);
+
+ assert_true(oob_msg_write_header(&buf, OOB_MSG_PROBE_REPLY));
+ assert_true(oob_tlv_write_header(&buf, 0x7ff, false, 4));
+ assert_true(buf_write_u32(&buf, 0xabad1dea));
+ struct oob_probe_reply in = { .priority = 7 };
+ assert_true(oob_probe_reply_write(&buf, &in));
+
+ struct oob_probe_reply out = { 0 };
+ assert_true(oob_client_reply_read(&buf, &out));
+ assert_int_equal(out.priority, 7);
+
+ gc_free(&gc);
+}
+
+/* A payload with no probe_reply is rejected. */
+static void
+test_client_reply_read_missing(void **state)
+{
+ struct gc_arena gc = gc_new();
+ struct buffer buf = alloc_buf_gc(128, &gc);
+
+ assert_true(oob_msg_write_header(&buf, OOB_MSG_PROBE_REPLY));
+ assert_true(oob_tlv_write_header(&buf, 0x7ff, false, 4));
+ assert_true(buf_write_u32(&buf, 0));
+
+ struct oob_probe_reply out = { 0 };
+ assert_false(oob_client_reply_read(&buf, &out));
+
+ gc_free(&gc);
+}
+
+/* Likewise, a PROBE_REPLY reader rejects a payload with the wrong message
+ * type even when a valid probe_reply TLV follows. */
+static void
+test_client_reply_read_wrong_msg_type(void **state)
+{
+ struct gc_arena gc = gc_new();
+ struct buffer buf = alloc_buf_gc(128, &gc);
+
+ assert_true(oob_msg_write_header(&buf, OOB_MSG_SERVER_PROBE));
+ struct oob_probe_reply in = { .priority = 7 };
+ assert_true(oob_probe_reply_write(&buf, &in));
+
+ struct oob_probe_reply out = { 0 };
+ assert_false(oob_client_reply_read(&buf, &out));
+
+ gc_free(&gc);
+}
+
int
main(void)
{
@@ -365,6 +448,10 @@
cmocka_unit_test(test_build_probe_reply_valid),
cmocka_unit_test(test_build_probe_reply_stale),
cmocka_unit_test(test_build_probe_reply_no_parameter),
+ cmocka_unit_test(test_client_reply_read_finds_reply),
+ cmocka_unit_test(test_client_reply_read_skips_unknown),
+ cmocka_unit_test(test_client_reply_read_missing),
+ cmocka_unit_test(test_client_reply_read_wrong_msg_type),
};
return cmocka_run_group_tests_name("oob tests", tests, NULL, NULL);
--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1745?usp=email
To unsubscribe, or for help writing mail filters, visit
http://gerrit.openvpn.net/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: If04ce09d4c353f5384c0c48f48f63e05869a373f
Gerrit-Change-Number: 1745
Gerrit-PatchSet: 1
Gerrit-Owner: stipa <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: plaisthos <[email protected]>
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel