Skip to content

Commit 29198f7

Browse files
yuwatakeszybz
authored andcommitted
resolve/mdns: split out mdns_make_dummy_packet()
Then, this fixes the following issues: - if dns_packet_append_zone() for other transaction is failed with EMSGSIZE, the previously added key was not removed, - if dns_transaction_prepare() for other transaction returns 0, then we restated the loop without dropping previously appended keys, which might not be necessary any more. (cherry picked from commit 7645e5a) (cherry picked from commit a63ed22)
1 parent 58e329a commit 29198f7

File tree

1 file changed

+88
-70
lines changed

1 file changed

+88
-70
lines changed

src/resolve/resolved-dns-transaction.c

Lines changed: 88 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,21 +1795,20 @@ static int dns_packet_append_zone(DnsPacket *p, DnsTransaction *t, DnsResourceKe
17951795
return dns_packet_append_answer(p, answer, nscount);
17961796
}
17971797

1798-
static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
1798+
static int mdns_make_dummy_packet(DnsTransaction *t, DnsPacket **ret_packet, Set **ret_keys) {
17991799
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
18001800
_cleanup_set_free_ Set *keys = NULL;
1801-
unsigned qdcount, ancount = 0 /* avoid false maybe-uninitialized warning */, nscount;
18021801
bool add_known_answers = false;
1802+
unsigned qdcount;
18031803
usec_t ts;
18041804
int r;
18051805

18061806
assert(t);
1807+
assert(t->scope);
18071808
assert(t->scope->protocol == DNS_PROTOCOL_MDNS);
1809+
assert(ret_packet);
1810+
assert(ret_keys);
18081811

1809-
/* Discard any previously prepared packet, so we can start over and coalesce again */
1810-
t->sent = dns_packet_unref(t->sent);
1811-
1812-
/* First, create a dummy packet to calculate packet size. */
18131812
r = dns_packet_new_query(&p, t->scope->protocol, 0, false);
18141813
if (r < 0)
18151814
return r;
@@ -1832,120 +1831,139 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
18321831
if (r < 0)
18331832
return r;
18341833

1835-
/*
1836-
* For mDNS, we want to coalesce as many open queries in pending transactions into one single
1837-
* query packet on the wire as possible. To achieve that, we iterate through all pending transactions
1838-
* in our current scope, and see whether their timing constraints allow them to be sent.
1839-
*/
1840-
18411834
assert_se(sd_event_now(t->scope->manager->event, CLOCK_BOOTTIME, &ts) >= 0);
18421835

1843-
for (bool restart = true; restart;) {
1844-
restart = false;
1845-
LIST_FOREACH(transactions_by_scope, other, t->scope->transactions) {
1846-
size_t saved_packet_size;
1847-
bool append = false;
1836+
LIST_FOREACH(transactions_by_scope, other, t->scope->transactions) {
18481837

1849-
/* Skip ourselves */
1850-
if (other == t)
1851-
continue;
1852-
1853-
if (other->state != DNS_TRANSACTION_PENDING)
1854-
continue;
1855-
1856-
if (other->next_attempt_after > ts)
1857-
continue;
1838+
/* Skip ourselves */
1839+
if (other == t)
1840+
continue;
18581841

1859-
if (!set_contains(keys, dns_transaction_key(other))) {
1860-
r = dns_packet_append_key(p, dns_transaction_key(other), 0, &saved_packet_size);
1861-
/* If we can't stuff more questions into the packet, just give up.
1862-
* One of the 'other' transactions will fire later and take care of the rest. */
1863-
if (r == -EMSGSIZE)
1864-
break;
1865-
if (r < 0)
1866-
return r;
1842+
if (other->state != DNS_TRANSACTION_PENDING)
1843+
continue;
18671844

1868-
r = dns_packet_append_zone(p, t, dns_transaction_key(other), NULL);
1869-
if (r == -EMSGSIZE)
1870-
break;
1871-
if (r < 0)
1872-
return r;
1845+
if (other->next_attempt_after > ts)
1846+
continue;
18731847

1874-
append = true;
1875-
}
1848+
if (!set_contains(keys, dns_transaction_key(other))) {
1849+
size_t saved_packet_size;
18761850

1877-
r = dns_transaction_prepare(other, ts);
1851+
r = dns_packet_append_key(p, dns_transaction_key(other), 0, &saved_packet_size);
1852+
/* If we can't stuff more questions into the packet, just give up.
1853+
* One of the 'other' transactions will fire later and take care of the rest. */
1854+
if (r == -EMSGSIZE)
1855+
break;
18781856
if (r < 0)
18791857
return r;
1880-
if (r == 0) {
1881-
if (append)
1882-
dns_packet_truncate(p, saved_packet_size);
18831858

1884-
/* In this case, not only this transaction, but multiple transactions may be
1885-
* freed. Hence, we need to restart the loop. */
1886-
restart = true;
1859+
r = dns_packet_append_zone(p, t, dns_transaction_key(other), NULL);
1860+
if (r == -EMSGSIZE) {
1861+
dns_packet_truncate(p, saved_packet_size);
18871862
break;
18881863
}
1864+
if (r < 0)
1865+
return r;
18891866

1890-
usec_t timeout = transaction_get_resend_timeout(other);
1891-
r = dns_transaction_setup_timeout(other, timeout, usec_add(ts, timeout));
1867+
r = set_ensure_put(&keys, &dns_resource_key_hash_ops, dns_transaction_key(other));
18921868
if (r < 0)
18931869
return r;
1870+
}
18941871

1895-
if (dns_key_is_shared(dns_transaction_key(other)))
1896-
add_known_answers = true;
1872+
r = dns_transaction_prepare(other, ts);
1873+
if (r < 0)
1874+
return r;
1875+
if (r == 0)
1876+
/* In this case, not only this transaction, but multiple transactions may be
1877+
* freed. Hence, we need to restart the loop. */
1878+
return -EAGAIN;
18971879

1898-
if (append) {
1899-
r = set_ensure_put(&keys, &dns_resource_key_hash_ops, dns_transaction_key(other));
1900-
if (r < 0)
1901-
return r;
1902-
}
1880+
usec_t timeout = transaction_get_resend_timeout(other);
1881+
r = dns_transaction_setup_timeout(other, timeout, usec_add(ts, timeout));
1882+
if (r < 0)
1883+
return r;
19031884

1904-
qdcount++;
1905-
if (qdcount >= UINT16_MAX)
1906-
break;
1907-
}
1885+
if (dns_key_is_shared(dns_transaction_key(other)))
1886+
add_known_answers = true;
1887+
1888+
qdcount++;
1889+
if (qdcount >= UINT16_MAX)
1890+
break;
19081891
}
19091892

1910-
/* Append known answer section if we're asking for any shared record */
1893+
DNS_PACKET_HEADER(p)->qdcount = htobe16(qdcount);
1894+
1895+
/* Append known answers section if we're asking for any shared record */
19111896
if (add_known_answers) {
19121897
r = dns_cache_export_shared_to_packet(&t->scope->cache, p, ts, 0);
19131898
if (r < 0)
19141899
return r;
1900+
}
1901+
1902+
*ret_packet = TAKE_PTR(p);
1903+
*ret_keys = TAKE_PTR(keys);
1904+
return add_known_answers;
1905+
}
1906+
1907+
static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
1908+
_cleanup_(dns_packet_unrefp) DnsPacket *p = NULL, *dummy = NULL;
1909+
_cleanup_set_free_ Set *keys = NULL;
1910+
bool add_known_answers;
1911+
DnsResourceKey *k;
1912+
unsigned c;
1913+
int r;
1914+
1915+
assert(t);
1916+
assert(t->scope->protocol == DNS_PROTOCOL_MDNS);
1917+
1918+
/* Discard any previously prepared packet, so we can start over and coalesce again */
1919+
t->sent = dns_packet_unref(t->sent);
1920+
1921+
/* First, create a dummy packet to calculate the number of known answers to be appended in the first packet. */
1922+
for (;;) {
1923+
r = mdns_make_dummy_packet(t, &dummy, &keys);
1924+
if (r == -EAGAIN)
1925+
continue;
1926+
if (r < 0)
1927+
return r;
19151928

1916-
ancount = be16toh(DNS_PACKET_HEADER(p)->ancount);
1929+
add_known_answers = r;
1930+
break;
19171931
}
19181932

19191933
/* Then, create actual packet. */
1920-
p = dns_packet_unref(p);
19211934
r = dns_packet_new_query(&p, t->scope->protocol, 0, false);
19221935
if (r < 0)
19231936
return r;
19241937

19251938
/* Questions */
1926-
DnsResourceKey *k;
1939+
c = 0;
19271940
SET_FOREACH(k, keys) {
19281941
r = dns_packet_append_key(p, k, 0, NULL);
19291942
if (r < 0)
19301943
return r;
1944+
c++;
19311945
}
1932-
DNS_PACKET_HEADER(p)->qdcount = htobe16(qdcount);
1946+
DNS_PACKET_HEADER(p)->qdcount = htobe16(c);
19331947

19341948
/* Known answers */
19351949
if (add_known_answers) {
1936-
r = dns_cache_export_shared_to_packet(&t->scope->cache, p, ts, ancount);
1950+
usec_t ts;
1951+
1952+
assert_se(sd_event_now(t->scope->manager->event, CLOCK_BOOTTIME, &ts) >= 0);
1953+
1954+
r = dns_cache_export_shared_to_packet(&t->scope->cache, p, ts, be16toh(DNS_PACKET_HEADER(dummy)->ancount));
19371955
if (r < 0)
19381956
return r;
19391957
}
19401958

19411959
/* Authorities */
1942-
nscount = 0;
1960+
c = 0;
19431961
SET_FOREACH(k, keys) {
1944-
r = dns_packet_append_zone(p, t, k, &nscount);
1962+
r = dns_packet_append_zone(p, t, k, &c);
19451963
if (r < 0)
19461964
return r;
19471965
}
1948-
DNS_PACKET_HEADER(p)->nscount = htobe16(nscount);
1966+
DNS_PACKET_HEADER(p)->nscount = htobe16(c);
19491967

19501968
t->sent = TAKE_PTR(p);
19511969
return 0;

0 commit comments

Comments
 (0)