X Tutup
Skip to content

Commit b914e21

Browse files
committed
resolved: when resolving an address PTR record via llmnr, make a tcp connection by default
1 parent 623a4c9 commit b914e21

File tree

11 files changed

+354
-132
lines changed

11 files changed

+354
-132
lines changed

src/resolve/resolved-dns-domain.c

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,93 @@ int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
360360
return 0;
361361
}
362362

363+
int dns_name_address(const char *p, int *family, union in_addr_union *address) {
364+
int r;
365+
366+
assert(p);
367+
assert(family);
368+
assert(address);
369+
370+
r = dns_name_endswith(p, "in-addr.arpa");
371+
if (r < 0)
372+
return r;
373+
if (r > 0) {
374+
uint8_t a[4];
375+
unsigned i;
376+
377+
for (i = 0; i < ELEMENTSOF(a); i++) {
378+
char label[DNS_LABEL_MAX+1];
379+
380+
r = dns_label_unescape(&p, label, sizeof(label));
381+
if (r < 0)
382+
return r;
383+
if (r == 0)
384+
return -EINVAL;
385+
if (r > 3)
386+
return -EINVAL;
387+
388+
r = safe_atou8(label, &a[i]);
389+
if (r < 0)
390+
return r;
391+
}
392+
393+
r = dns_name_equal(p, "in-addr.arpa");
394+
if (r <= 0)
395+
return r;
396+
397+
*family = AF_INET;
398+
address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
399+
((uint32_t) a[2] << 16) |
400+
((uint32_t) a[1] << 8) |
401+
(uint32_t) a[0]);
402+
403+
return 1;
404+
}
405+
406+
r = dns_name_endswith(p, "ip6.arpa");
407+
if (r < 0)
408+
return r;
409+
if (r > 0) {
410+
struct in6_addr a;
411+
unsigned i;
412+
413+
for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
414+
char label[DNS_LABEL_MAX+1];
415+
int x, y;
416+
417+
r = dns_label_unescape(&p, label, sizeof(label));
418+
if (r <= 0)
419+
return r;
420+
if (r != 1)
421+
return -EINVAL;
422+
x = unhexchar(label[0]);
423+
if (x < 0)
424+
return -EINVAL;
425+
426+
r = dns_label_unescape(&p, label, sizeof(label));
427+
if (r <= 0)
428+
return r;
429+
if (r != 1)
430+
return -EINVAL;
431+
y = unhexchar(label[0]);
432+
if (y < 0)
433+
return -EINVAL;
434+
435+
a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x;
436+
}
437+
438+
r = dns_name_equal(p, "ip6.arpa");
439+
if (r <= 0)
440+
return r;
441+
442+
*family = AF_INET6;
443+
address->in6 = a;
444+
return 1;
445+
}
446+
447+
return 0;
448+
}
449+
363450
int dns_name_root(const char *name) {
364451
char label[DNS_LABEL_MAX+1];
365452
int r;
@@ -382,7 +469,6 @@ int dns_name_single_label(const char *name) {
382469
r = dns_label_unescape(&name, label, sizeof(label));
383470
if (r < 0)
384471
return r;
385-
386472
if (r == 0)
387473
return 0;
388474

src/resolve/resolved-dns-domain.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ int dns_name_equal(const char *x, const char *y);
3939
int dns_name_endswith(const char *name, const char *suffix);
4040

4141
int dns_name_reverse(int family, const union in_addr_union *a, char **ret);
42+
int dns_name_address(const char *p, int *family, union in_addr_union *a);
4243

4344
int dns_name_root(const char *name);
4445
int dns_name_single_label(const char *name);

src/resolve/resolved-dns-query.c

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,14 @@ static int on_stream_complete(DnsStream *s, int error) {
165165
return 0;
166166
}
167167

168+
t->block_gc++;
168169
dns_query_transaction_process_reply(t, p);
170+
t->block_gc--;
171+
172+
/* If the response wasn't useful, then complete the transition now */
173+
if (t->state == DNS_QUERY_PENDING)
174+
dns_query_transaction_complete(t, DNS_QUERY_INVALID_REPLY);
175+
169176
return 0;
170177
}
171178

@@ -181,10 +188,25 @@ static int dns_query_transaction_open_tcp(DnsQueryTransaction *t) {
181188
if (t->scope->protocol == DNS_PROTOCOL_DNS)
182189
fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53);
183190
else if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {
184-
if (!t->received)
185-
return -EINVAL;
186191

187-
fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
192+
/* When we already received a query to this (but it was truncated), send to its sender address */
193+
if (t->received)
194+
fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port);
195+
else {
196+
union in_addr_union address;
197+
int family;
198+
199+
/* Otherwise, try to talk to the owner of a
200+
* the IP address, in case this is a reverse
201+
* PTR lookup */
202+
r = dns_question_extract_reverse_address(t->question, &family, &address);
203+
if (r < 0)
204+
return r;
205+
if (r == 0)
206+
return -EINVAL;
207+
208+
fd = dns_scope_tcp_socket(t->scope, family, &address, 5355);
209+
}
188210
} else
189211
return -EAFNOSUPPORT;
190212

@@ -205,6 +227,13 @@ static int dns_query_transaction_open_tcp(DnsQueryTransaction *t) {
205227

206228
t->received = dns_packet_unref(t->received);
207229
t->stream->complete = on_stream_complete;
230+
t->stream->transaction = t;
231+
232+
/* The interface index is difficult to determine if we are
233+
* connecting to the local host, hence fill this in right away
234+
* instead of determining it from the socket */
235+
if (t->scope->link)
236+
t->stream->ifindex = t->scope->link->ifindex;
208237

209238
return 0;
210239
}
@@ -416,10 +445,19 @@ static int dns_query_transaction_go(DnsQueryTransaction *t) {
416445
if (r < 0)
417446
return r;
418447

419-
/* Try via UDP, and if that fails due to large size try via TCP */
420-
r = dns_scope_send(t->scope, t->sent);
421-
if (r == -EMSGSIZE)
448+
if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
449+
(dns_question_endswith(t->question, "in-addr.arpa") > 0 ||
450+
dns_question_endswith(t->question, "ip6.arpa") > 0)) {
451+
452+
/* RFC 4795, Section 2.4. says reverse lookups shall
453+
* always be made via TCP on LLMNR */
422454
r = dns_query_transaction_open_tcp(t);
455+
} else {
456+
/* Try via UDP, and if that fails due to large size try via TCP */
457+
r = dns_scope_send(t->scope, t->sent);
458+
if (r == -EMSGSIZE)
459+
r = dns_query_transaction_open_tcp(t);
460+
}
423461
if (r == -ESRCH) {
424462
/* No servers to send this to? */
425463
dns_query_transaction_complete(t, DNS_QUERY_NO_SERVERS);

src/resolve/resolved-dns-question.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,3 +235,38 @@ int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **
235235

236236
return 1;
237237
}
238+
239+
int dns_question_endswith(DnsQuestion *q, const char *suffix) {
240+
unsigned i;
241+
242+
assert(q);
243+
assert(suffix);
244+
245+
for (i = 0; i < q->n_keys; i++) {
246+
int k;
247+
248+
k = dns_name_endswith(DNS_RESOURCE_KEY_NAME(q->keys[i]), suffix);
249+
if (k <= 0)
250+
return k;
251+
}
252+
253+
return 1;
254+
}
255+
256+
int dns_question_extract_reverse_address(DnsQuestion *q, int *family, union in_addr_union *address) {
257+
unsigned i;
258+
259+
assert(q);
260+
assert(family);
261+
assert(address);
262+
263+
for (i = 0; i < q->n_keys; i++) {
264+
int k;
265+
266+
k = dns_name_address(DNS_RESOURCE_KEY_NAME(q->keys[i]), family, address);
267+
if (k != 0)
268+
return k;
269+
}
270+
271+
return 0;
272+
}

src/resolve/resolved-dns-question.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,7 @@ int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other);
4646

4747
int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret);
4848

49+
int dns_question_endswith(DnsQuestion *q, const char *suffix);
50+
int dns_question_extract_reverse_address(DnsQuestion *q, int *family, union in_addr_union *address);
51+
4952
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuestion*, dns_question_unref);

src/resolve/resolved-dns-scope.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, const char *domain) {
312312
}
313313

314314
if (s->protocol == DNS_PROTOCOL_LLMNR) {
315-
if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0 ||
316-
dns_name_endswith(domain, "0.8.e.f.ip6.arpa") > 0 ||
315+
if (dns_name_endswith(domain, "in-addr.arpa") > 0 ||
316+
dns_name_endswith(domain, "ip6.arpa") > 0 ||
317317
dns_name_single_label(domain) > 0)
318318
return DNS_SCOPE_MAYBE;
319319

0 commit comments

Comments
 (0)
X Tutup