Skip to content

Commit 1def3ad

Browse files
committed
Split multi_get_create_instance_udp into data and control parts
This currently leads to a bit of code duplication but this refactoring will make the follow up patches cleaner and better to understand when the control channel lookup will be changed to use session ids instead of IP addresses. Change-Id: I8e9923b51b77f184c7d49d697004cb02d2b5cfc3 Signed-off-by: Arne Schwabe <arne@rfc2549.org>
1 parent 3cc0eca commit 1def3ad

File tree

1 file changed

+104
-51
lines changed

1 file changed

+104
-51
lines changed

src/openvpn/mudp.c

Lines changed: 104 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,14 @@ do_pre_decrypt_check(struct multi_context *m, struct tls_pre_decrypt_state *stat
188188
struct multi_instance *
189189
handle_connection_attempt(struct multi_context *m,
190190
struct link_socket *sock,
191-
struct mroute_addr *real,
192-
const uint64_t hv,
193-
struct hash_bucket *bucket)
191+
struct mroute_addr *real)
194192
{
195193
struct hash *hash = m->hash;
196194
struct tls_pre_decrypt_state state = { 0 };
197195
struct multi_instance *mi = NULL;
198196
struct gc_arena gc = gc_new();
199197

198+
200199
if (m->deferred_shutdown_signal.signal_received)
201200
{
202201
msg(D_MULTI_ERRORS,
@@ -220,7 +219,10 @@ handle_connection_attempt(struct multi_context *m,
220219
mi = multi_create_instance(m, real, sock);
221220
if (mi)
222221
{
222+
const uint64_t hv = hash_value(hash, real);
223+
struct hash_bucket *bucket = hash_bucket(hash, hv);
223224
hash_add_fast(hash, bucket, &mi->real, hv, mi);
225+
224226
mi->did_real_hash = true;
225227
multi_assign_peer_id(m, mi);
226228

@@ -249,88 +251,139 @@ handle_connection_attempt(struct multi_context *m,
249251
return mi;
250252
}
251253

252-
/**
253-
* Get a client instance based on real address. If
254-
* the instance doesn't exist, create it while
255-
* maintaining real address hash table atomicity.
256-
*/
257254
struct multi_instance *
258-
multi_get_create_instance_udp(struct multi_context *m, bool *floated, struct link_socket *sock)
255+
multi_get_instance_udp_control(struct multi_context *m, struct link_socket *sock)
259256
{
260-
struct gc_arena gc = gc_new();
261257
struct mroute_addr real = { 0 };
262-
struct multi_instance *mi = NULL;
263258
struct hash *hash = m->hash;
264259
real.proto = sock->info.proto;
265-
m->hmac_reply_ls = sock;
266260

267261
if (mroute_extract_openvpn_sockaddr(&real, &m->top.c2.from.dest, true) && m->top.c2.buf.len > 0)
268262
{
269263
struct hash_element *he;
270264
const uint64_t hv = hash_value(hash, &real);
271265
struct hash_bucket *bucket = hash_bucket(hash, hv);
272-
uint8_t *ptr = BPTR(&m->top.c2.buf);
273-
uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
274-
bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3));
275-
bool peer_id_disabled = false;
276266

277-
/* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */
278-
if (v2)
267+
he = hash_lookup_fast(hash, bucket, &real, hv);
268+
if (he)
279269
{
280-
uint32_t peer_id = ((uint32_t)ptr[1] << 16) | ((uint32_t)ptr[2] << 8) | ((uint32_t)ptr[3]);
281-
peer_id_disabled = (peer_id == MAX_PEER_ID);
270+
return he->value;
271+
}
272+
}
273+
274+
return NULL;
275+
}
276+
277+
/**
278+
* Get a client instance based on real address. If
279+
* the instance doesn't exist, create it while
280+
* maintaining real address hash table atomicity.
281+
*/
282+
struct multi_instance *
283+
multi_get_instance_udp_data(struct multi_context *m, bool *floated, struct mroute_addr *real, struct link_socket *sock)
284+
{
285+
struct multi_instance *mi = NULL;
286+
struct hash *hash = m->hash;
282287

283-
if (!peer_id_disabled && (peer_id < m->max_clients) && (m->instances[peer_id]))
288+
struct hash_element *he;
289+
const uint64_t hv = hash_value(hash, real);
290+
struct hash_bucket *bucket = hash_bucket(hash, hv);
291+
uint8_t *ptr = BPTR(&m->top.c2.buf);
292+
uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
293+
bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3));
294+
bool peer_id_disabled = false;
295+
296+
/* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */
297+
if (v2)
298+
{
299+
uint32_t peer_id = ((uint32_t)ptr[1] << 16) | ((uint32_t)ptr[2] << 8) | ((uint32_t)ptr[3]);
300+
peer_id_disabled = (peer_id == MAX_PEER_ID);
301+
302+
if (!peer_id_disabled && (peer_id < m->max_clients) && (m->instances[peer_id]))
303+
{
304+
/* Floating on TCP will never be possible, so ensure we only process
305+
* UDP clients */
306+
if (m->instances[peer_id]->context.c2.link_sockets[0]->info.proto
307+
== sock->info.proto)
284308
{
285-
/* Floating on TCP will never be possible, so ensure we only process
286-
* UDP clients */
287-
if (m->instances[peer_id]->context.c2.link_sockets[0]->info.proto
288-
== sock->info.proto)
309+
mi = m->instances[peer_id];
310+
*floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from);
311+
312+
if (*floated)
289313
{
290-
mi = m->instances[peer_id];
291-
*floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from);
292-
293-
if (*floated)
294-
{
295-
/* reset prefix, since here we are not sure peer is the one it claims to be
296-
*/
297-
ungenerate_prefix(mi);
298-
msg(D_MULTI_MEDIUM, "Float requested for peer %" PRIu32 " to %s", peer_id,
299-
mroute_addr_print(&real, &gc));
300-
}
314+
/* reset prefix, since here we are not sure peer is the one it claims to be
315+
*/
316+
ungenerate_prefix(mi);
317+
struct gc_arena gc = gc_new();
318+
msg(D_MULTI_MEDIUM, "Float requested for peer %" PRIu32 " to %s", peer_id,
319+
mroute_addr_print(real, &gc));
320+
gc_free(&gc);
301321
}
322+
return mi;
302323
}
303324
}
304-
if (!v2 || peer_id_disabled)
325+
}
326+
if (!v2 || peer_id_disabled)
327+
{
328+
he = hash_lookup_fast(hash, bucket, real, hv);
329+
if (he)
305330
{
306-
he = hash_lookup_fast(hash, bucket, &real, hv);
307-
if (he)
308-
{
309-
mi = (struct multi_instance *)he->value;
310-
}
331+
return he->value;
311332
}
333+
}
334+
335+
return NULL;
336+
}
337+
338+
339+
struct multi_instance *
340+
multi_get_create_instance_udp(struct multi_context *m, bool *floated, struct link_socket *sock)
341+
{
342+
uint8_t *ptr = BPTR(&m->top.c2.buf);
343+
uint8_t op = ptr[0] >> P_OPCODE_SHIFT;
344+
345+
struct mroute_addr real = { 0 };
346+
real.proto = sock->info.proto;
312347

313-
/* we have no existing multi instance for this connection */
348+
if (!mroute_extract_openvpn_sockaddr(&real, &m->top.c2.from.dest, true) || m->top.c2.buf.len == 0)
349+
{
350+
return NULL;
351+
}
352+
353+
struct multi_instance *mi = NULL;
354+
if (op == P_DATA_V1 || op == P_DATA_V2)
355+
{
356+
mi = multi_get_instance_udp_data(m, floated, &real, sock);
357+
}
358+
else
359+
{
360+
mi = multi_get_instance_udp_control(m, sock);
361+
362+
/* we have no existing multi instance for this connection, control
363+
* packets can create a session. Data packets cannot */
314364
if (!mi)
315365
{
316-
mi = handle_connection_attempt(m, sock, &real, hv, bucket);
366+
m->hmac_reply_ls = sock;
367+
mi = handle_connection_attempt(m, sock, &real);
317368
}
369+
}
318370

319371
#ifdef ENABLE_DEBUG
320-
if (check_debug_level(D_MULTI_DEBUG))
321-
{
322-
const char *status = mi ? "[ok]" : "[failed]";
372+
if (check_debug_level(D_MULTI_DEBUG))
373+
{
374+
struct gc_arena gc = gc_new();
375+
const char *status = mi ? "[ok]" : "[failed]";
323376

324-
dmsg(D_MULTI_DEBUG, "GET INST BY REAL: %s %s", mroute_addr_print(&real, &gc), status);
325-
}
326-
#endif
377+
dmsg(D_MULTI_DEBUG, "GET INST BY REAL: %s %s", mroute_addr_print(&real, &gc), status);
378+
gc_free(&gc);
327379
}
380+
#endif
328381

329-
gc_free(&gc);
330382
ASSERT(!(mi && mi->halt));
331383
return mi;
332384
}
333385

386+
334387
/*
335388
* Send a packet to UDP socket.
336389
*/

0 commit comments

Comments
 (0)