Skip to content

Commit 0bf903a

Browse files
committed
async-dns-tcp-fallback
1 parent f1db404 commit 0bf903a

4 files changed

Lines changed: 183 additions & 10 deletions

File tree

lib/system/async-dns/async-dns-parse.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ lws_adns_parse_label(const uint8_t *pkt, int len, const uint8_t *ls, int budget,
3737
int n, readsize = 0, consumed = -1;
3838
uint8_t ll;
3939

40-
if (len < DHO_SIZEOF || len > 1500)
40+
if (len < DHO_SIZEOF || len > LWS_ADNS_MAX_PAYLOAD)
4141
return -1;
4242

4343
if (budget < 1)
@@ -184,7 +184,7 @@ lws_adns_iterate(lws_adns_q_t *q, const uint8_t *pkt, int len,
184184
char *sp, inq;
185185
uint32_t ttl;
186186

187-
if (len < DHO_SIZEOF || len > 1500)
187+
if (len < DHO_SIZEOF || len > LWS_ADNS_MAX_PAYLOAD)
188188
return -1;
189189

190190
lws_strncpy(stack[0].name, expname, sizeof(stack[0].name));
@@ -570,7 +570,7 @@ lws_adns_parse_udp(lws_async_dns_t *dns, const uint8_t *pkt, size_t len)
570570

571571
/* we have to at least have the header */
572572

573-
if (len < DHO_SIZEOF || len > 1500)
573+
if (len < DHO_SIZEOF || len > LWS_ADNS_MAX_PAYLOAD)
574574
return;
575575

576576
/* we asked with one query, so anything else is bogus */
@@ -605,6 +605,25 @@ lws_adns_parse_udp(lws_async_dns_t *dns, const uint8_t *pkt, size_t len)
605605

606606
q->responded = (uint8_t)(q->responded | n);
607607

608+
/* did we get truncated? */
609+
if ((lws_ser_ru16be(pkt + DHO_FLAGS) & 0x0200) && !q->is_tcp) {
610+
lwsl_notice("%s: ADNS truncated, falling back to TCP for %s\n",
611+
__func__, ((const char *)&q[1]) + DNS_MAX);
612+
613+
q->responded = (uint8_t)(q->responded & ~n);
614+
q->asked = 0;
615+
q->sent[0] = 0;
616+
#if defined(LWS_WITH_IPV6)
617+
q->sent[1] = 0;
618+
#endif
619+
if (lws_async_dns_create_tcp_wsi(q)) {
620+
q->go_nogo = METRES_NOGO;
621+
goto fail_out;
622+
}
623+
624+
return;
625+
}
626+
608627
/* we want to confirm the results against what we last requested... */
609628

610629
nmcname = ((const char *)&q[1]);

lib/system/async-dns/async-dns.c

Lines changed: 128 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ lws_adns_q_destroy(lws_adns_q_t *q)
3939
lws_sul_cancel(&q->sul);
4040
lws_sul_cancel(&q->write_sul);
4141
lws_dll2_remove(&q->list);
42+
43+
if (q->wsi_tcp) {
44+
q->wsi_tcp->a.opaque_user_data = NULL;
45+
lws_set_timeout(q->wsi_tcp, 1, LWS_TO_KILL_ASYNC);
46+
q->wsi_tcp = NULL;
47+
}
48+
49+
if (q->tcp_rx_buf) {
50+
lws_free(q->tcp_rx_buf);
51+
q->tcp_rx_buf = NULL;
52+
}
53+
4254
if (q->firstcache) {
4355
q->firstcache->refcount--;
4456
q->firstcache = NULL;
@@ -268,8 +280,13 @@ lws_async_dns_writeable(struct lws *wsi, lws_adns_q_t *q)
268280
assert(p < pkt + sizeof(pkt) - LWS_PRE);
269281
n = lws_ptr_diff(p, pkt + LWS_PRE);
270282

271-
m = lws_write(wsi, pkt + LWS_PRE, (unsigned int)n, 0);
272-
if (m != n) {
283+
if (!wsi->udp) {
284+
lws_ser_wu16be(pkt + LWS_PRE - 2, (uint16_t)n);
285+
m = lws_write(wsi, pkt + LWS_PRE - 2, (unsigned int)n + 2, 0);
286+
} else
287+
m = lws_write(wsi, pkt + LWS_PRE, (unsigned int)n, 0);
288+
289+
if (m != (wsi->udp ? n : n + 2)) {
273290
lwsl_wsi_notice(wsi, "dns write failed %d %d errno %d",
274291
m, n, errno);
275292
goto qfail;
@@ -305,6 +322,81 @@ callback_async_dns(struct lws *wsi, enum lws_callback_reasons reason,
305322
void *user, void *in, size_t len)
306323
{
307324
struct lws_async_dns *dns = &(lws_get_context(wsi)->async_dns);
325+
326+
if (!wsi->udp) {
327+
lws_adns_q_t *q = (lws_adns_q_t *)wsi->a.opaque_user_data;
328+
329+
if (!q)
330+
return 0;
331+
332+
switch (reason) {
333+
case LWS_CALLBACK_RAW_CONNECTED:
334+
lws_callback_on_writable(wsi);
335+
break;
336+
case LWS_CALLBACK_RAW_CLOSE:
337+
q->wsi_tcp = NULL;
338+
if (q->go_nogo != METRES_GO) {
339+
lws_async_dns_complete(q, NULL);
340+
lws_adns_q_destroy(q);
341+
}
342+
break;
343+
case LWS_CALLBACK_RAW_RX:
344+
/* accumulate bytes */
345+
if (!q->has_tcp_len) {
346+
const uint8_t *in8 = (const uint8_t *)in;
347+
348+
while (len && !q->has_tcp_len) {
349+
q->tcp_rx_len = (uint16_t)((q->tcp_rx_len << 8) | *in8++);
350+
q->tcp_rx_pos++;
351+
len--;
352+
if (q->tcp_rx_pos == 2) {
353+
if (q->tcp_rx_len < DHO_SIZEOF ||
354+
q->tcp_rx_len > LWS_ADNS_MAX_PAYLOAD) {
355+
lwsl_wsi_notice(wsi, "adns tcp len bad");
356+
return -1;
357+
}
358+
q->has_tcp_len = 1;
359+
q->tcp_rx_pos = 0;
360+
q->tcp_rx_buf = lws_malloc(q->tcp_rx_len + 1, "adns tcp");
361+
if (!q->tcp_rx_buf) {
362+
lwsl_wsi_err(wsi, "OOM");
363+
return -1;
364+
}
365+
}
366+
}
367+
in = (void *)in8;
368+
}
369+
370+
if (q->has_tcp_len && len) {
371+
size_t chunk = len;
372+
if (q->tcp_rx_pos + chunk > (size_t)q->tcp_rx_len)
373+
chunk = (size_t)(q->tcp_rx_len - q->tcp_rx_pos);
374+
memcpy(q->tcp_rx_buf + q->tcp_rx_pos, in, chunk);
375+
q->tcp_rx_pos = (uint16_t)(q->tcp_rx_pos + chunk);
376+
377+
if (q->tcp_rx_pos == q->tcp_rx_len) {
378+
/* we have the whole message */
379+
lws_adns_parse_udp(dns, q->tcp_rx_buf, q->tcp_rx_len);
380+
/* TCP connection is done */
381+
return -1;
382+
}
383+
}
384+
break;
385+
case LWS_CALLBACK_RAW_WRITEABLE:
386+
if (!q->is_retry && q->sent[0]
387+
#if defined(LWS_WITH_IPV6)
388+
&& q->sent[0] == q->sent[1]
389+
#endif
390+
)
391+
break;
392+
lws_async_dns_writeable(wsi, q);
393+
break;
394+
default:
395+
break;
396+
}
397+
return 0;
398+
}
399+
308400
lws_async_dns_server_t *dsrv =
309401
(lws_async_dns_server_t *)wsi->a.opaque_user_data;
310402

@@ -335,7 +427,7 @@ callback_async_dns(struct lws *wsi, enum lws_callback_reasons reason,
335427

336428
if (//lws_dll2_is_detached(&q->sul.list) &&
337429
!q->is_synthetic &&
338-
(!q->asked || q->responded != q->asked))
430+
(!q->asked || q->responded != q->asked) && !q->is_tcp)
339431
lws_async_dns_writeable(wsi, q);
340432
} lws_end_foreach_dll_safe(d, d1);
341433
break;
@@ -1221,3 +1313,36 @@ lws_async_dns_query(struct lws_context *context, int tsi, const char *name,
12211313

12221314
return LADNS_RET_FAILED;
12231315
}
1316+
1317+
int
1318+
lws_async_dns_create_tcp_wsi(lws_adns_q_t *q)
1319+
{
1320+
struct lws_client_connect_info i;
1321+
char ads[48];
1322+
1323+
if (q->wsi_tcp)
1324+
return 0;
1325+
1326+
memset(&i, 0, sizeof(i));
1327+
i.context = q->context;
1328+
1329+
lws_sa46_write_numeric_address(&q->dsrv->sa46, ads, sizeof(ads));
1330+
i.address = ads;
1331+
i.port = 53;
1332+
i.ssl_connection = 0;
1333+
i.method = "RAW";
1334+
i.local_protocol_name = lws_async_dns_protocol.name;
1335+
i.opaque_user_data = q;
1336+
1337+
q->is_tcp = 1;
1338+
q->has_tcp_len = 0;
1339+
q->tcp_rx_pos = 0;
1340+
1341+
q->wsi_tcp = lws_client_connect_via_info(&i);
1342+
if (!q->wsi_tcp) {
1343+
lwsl_cx_err(q->context, "adns tcp connect fail");
1344+
return 1;
1345+
}
1346+
1347+
return 0;
1348+
}

lib/system/async-dns/private-lib-async-dns.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#define DNS_PACKET_LEN 1400 /* Buffer size for DNS packet */
2929
#define MAX_CACHE_ENTRIES 10 /* Dont cache more than that */
3030
#define DNS_QUERY_TIMEOUT 30 /* Query timeout, seconds */
31+
#define LWS_ADNS_MAX_PAYLOAD 1500 /* Maximum TCP payload size */
3132

3233
#if defined(LWS_WITH_SYS_ASYNC_DNS)
3334

@@ -92,6 +93,13 @@ typedef struct lws_adns_q {
9293

9394
uint8_t is_retry:1;
9495
uint8_t is_synthetic:1; /* test will deliver canned */
96+
uint8_t is_tcp:1;
97+
uint8_t has_tcp_len:1;
98+
99+
struct lws *wsi_tcp;
100+
uint8_t *tcp_rx_buf;
101+
uint16_t tcp_rx_len;
102+
uint16_t tcp_rx_pos;
95103

96104
/* name overallocated here */
97105
} lws_adns_q_t;
@@ -139,6 +147,9 @@ lws_async_dns_trim_cache(lws_async_dns_t *dns);
139147
int
140148
lws_async_dns_get_new_tid(struct lws_context *context, lws_adns_q_t *q);
141149

150+
int
151+
lws_async_dns_create_tcp_wsi(lws_adns_q_t *q);
152+
142153

143154

144155
/* require: context lock on this set */

minimal-examples-lowlevel/api-tests/api-test-async-dns/main.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include <libwebsockets.h>
1313
#include <signal.h>
1414

15-
static int interrupted, dtest, ok, fail, _exp = 37;
15+
static int interrupted, dtest, ok, fail, _exp = 38;
1616
struct lws_context *context;
1717

1818
/*
@@ -113,9 +113,8 @@ static struct async_dns_tests {
113113
// { "c-msn-com-europe-vip.trafficmanager.net", TEST_FLAG_NOCHECK_RESULT_IP |
114114
// LWS_ADNS_SYNTHETIC | LWS_ADNS_RECORD_A, 0,
115115
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
116-
// { "c-msn-com-europe-vip.trafficmanager.net", TEST_FLAG_NOCHECK_RESULT_IP |
117-
// LWS_ADNS_SYNTHETIC | LWS_ADNS_RECORD_A, 0,
118-
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
116+
{ "tcp-fallback.libwebsockets.org", LWS_ADNS_SYNTHETIC | LWS_ADNS_RECORD_A, 0,
117+
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
119118
{ "mudpuddle.shwaine.com", LWS_ADNS_RECORD_A, 4,
120119
{ 174, 134, 58, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } },
121120
{ "awsrealm.majicrealm.com", LWS_ADNS_RECORD_A, 4,
@@ -182,6 +181,18 @@ static uint8_t canned_c_msn_com[] = {
182181
49,3,116,109,49,6,100,110,115,45,116,109,3,99,111,109,0,10,104,111,115,
183182
116,109,97,115,116,101,114,192,33,7,11,234,133,0,0,3,132,0,0,1,44,0,36,
184183
234,0,0,0,0,30,
184+
}, canned_tc_libwebsockets_org[] = {
185+
0x00, 0x00,
186+
0x83, 0x80,
187+
0x00, 0x01,
188+
0x00, 0x00,
189+
0x00, 0x00,
190+
0x00, 0x00,
191+
12, 't', 'c', 'p', '-', 'f', 'a', 'l', 'l', 'b', 'a', 'c', 'k',
192+
13, 'l', 'i', 'b', 'w', 'e', 'b', 's', 'o', 'c', 'k', 'e', 't', 's',
193+
3, 'o', 'r', 'g', 0,
194+
0x00, 0x01,
195+
0x00, 0x01
185196
};
186197

187198
static lws_sorted_usec_list_t sul, sul_timeout;
@@ -261,6 +272,13 @@ next_test_cb(lws_sorted_usec_list_t *sul)
261272
canned_c_msn_com_europe_vip_trafficmanager_net,
262273
sizeof(canned_c_msn_com_europe_vip_trafficmanager_net));
263274
}
275+
if (!strcmp(adt[dtest].dns_name, "tcp-fallback.libwebsockets.org")) {
276+
canned_tc_libwebsockets_org[0] = (uint8_t)(lws_adns_get_tid(q) >> 8);
277+
canned_tc_libwebsockets_org[1] = (uint8_t)lws_adns_get_tid(q);
278+
lws_adns_parse_udp(lws_adns_get_async_dns(q),
279+
canned_tc_libwebsockets_org,
280+
sizeof(canned_tc_libwebsockets_org));
281+
}
264282
}
265283
}
266284

0 commit comments

Comments
 (0)