Compare commits

..

4 Commits

Author SHA1 Message Date
Vishal Chillara cf72f7f116
Merge e9cfc2bd94 into 321c202e7c 2024-11-25 16:09:53 +01:00
Frantisek Sumsal e9cfc2bd94 varlinkctl: flush stdout after each record in --more mode
So things work correctly even if varlinkctl's output is redirected to a
file.
2024-10-29 22:44:13 +05:30
Vishal Chillara Srinivas 08860aa147 test: resolve: add testing for mDNS browse
Co-authored-by: Frantisek Sumsal <frantisek@sumsal.cz>
Co-authored-by: Vishwanath Chandapur <vishwanath.chandapur@philips.com>
2024-10-29 22:43:02 +05:30
Vishal Chillara Srinivas 2e5bf2774e resolved: Implement continuous mDNS querying as per RFC6762 5.2
Allow for mDNS service/domain/types browsing.
A client can connect to the backend via varlink and receive updates as the
requested service becomes available.
The interval between the first two queries MUST be at least one second,
the intervals between successive queries MUST increase by at least a factor of two.
When the interval between queries reaches or exceeds 60 minutes, a querier MAY cap
the interval to a maximum of 60 minutes, and perform subsequent queries at a
steady-state rate of one query per hour.
Delete expired cache entries one second after goodbye packet received
as per RFC6762 Section 10.1

Cache maintenance:
The querier should plan to issue a query at 80% of the record lifetime, and
then if no answer is received, at 85%, 90%, and 95%.
If an answer is received, then the remaining TTL is reset to the value given
in the answer, and this process repeats for as long as the Multicast DNS querier
has an ongoing interest in the record.
If no answer is received after four queries, the record is deleted when it
reaches 100% of its lifetime.

Co-authored-by: Vishwanath Chandapur <vishwanath.chandapur@philips.com>
2024-10-29 22:38:48 +05:30
25 changed files with 399 additions and 513 deletions

View File

@ -684,15 +684,6 @@ fi</programlisting>
<citerefentry><refentrytitle>file-hierarchy</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para> <citerefentry><refentrytitle>file-hierarchy</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
</refsect1> </refsect1>
<refsect1>
<title>Notes</title>
<para>
All example codes in this page are licensed under <literal>MIT No Attribution</literal>
(SPDX-License-Identifier: MIT-0).
</para>
</refsect1>
<refsect1> <refsect1>
<title>See Also</title> <title>See Also</title>
<para><simplelist type="inline"> <para><simplelist type="inline">

View File

@ -302,7 +302,7 @@
and running in an initrd equivalent to true, otherwise false. This implements a restricted subset of and running in an initrd equivalent to true, otherwise false. This implements a restricted subset of
the per-unit setting of the same name, see the per-unit setting of the same name, see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details: currently, the <literal>full</literal> or <literal>strict</literal> values are not details: currently, the <literal>full</literal> or <literal>struct</literal> values are not
supported.</para> supported.</para>
<xi:include href="version-info.xml" xpointer="v256"/></listitem> <xi:include href="version-info.xml" xpointer="v256"/></listitem>

View File

@ -16,7 +16,6 @@
#include "fileio.h" #include "fileio.h"
#include "format-util.h" #include "format-util.h"
#include "hexdecoct.h" #include "hexdecoct.h"
#include "iovec-util.h"
#include "macro.h" #include "macro.h"
#include "memory-util.h" #include "memory-util.h"
#include "parse-util.h" #include "parse-util.h"
@ -32,7 +31,8 @@ int decrypt_pkcs11_key(
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */ const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
size_t key_file_size, size_t key_file_size,
uint64_t key_file_offset, uint64_t key_file_offset,
const struct iovec *key_data, /* … or literal keys via key_data */ const void *key_data, /* … or key_data and key_data_size (for literal keys) */
size_t key_data_size,
usec_t until, usec_t until,
AskPasswordFlags askpw_flags, AskPasswordFlags askpw_flags,
void **ret_decrypted_key, void **ret_decrypted_key,
@ -47,15 +47,15 @@ int decrypt_pkcs11_key(
assert(friendly_name); assert(friendly_name);
assert(pkcs11_uri); assert(pkcs11_uri);
assert(key_file || iovec_is_set(key_data)); assert(key_file || key_data);
assert(ret_decrypted_key); assert(ret_decrypted_key);
assert(ret_decrypted_key_size); assert(ret_decrypted_key_size);
/* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */ /* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
if (iovec_is_set(key_data)) { if (key_data) {
data.encrypted_key = (void*) key_data->iov_base; data.encrypted_key = (void*) key_data;
data.encrypted_key_size = key_data->iov_len; data.encrypted_key_size = key_data_size;
data.free_encrypted_key = false; data.free_encrypted_key = false;
} else { } else {

View File

@ -16,7 +16,8 @@ int decrypt_pkcs11_key(
const char *key_file, const char *key_file,
size_t key_file_size, size_t key_file_size,
uint64_t key_file_offset, uint64_t key_file_offset,
const struct iovec *key_data, const void *key_data,
size_t key_data_size,
usec_t until, usec_t until,
AskPasswordFlags askpw_flags, AskPasswordFlags askpw_flags,
void **ret_decrypted_key, void **ret_decrypted_key,
@ -38,7 +39,8 @@ static inline int decrypt_pkcs11_key(
const char *key_file, const char *key_file,
size_t key_file_size, size_t key_file_size,
uint64_t key_file_offset, uint64_t key_file_offset,
const struct iovec *key_data, const void *key_data,
size_t key_data_size,
usec_t until, usec_t until,
AskPasswordFlags askpw_flags, AskPasswordFlags askpw_flags,
void **ret_decrypted_key, void **ret_decrypted_key,

View File

@ -1471,7 +1471,8 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
struct crypt_device *cd, struct crypt_device *cd,
const char *name, const char *name,
const char *key_file, const char *key_file,
const struct iovec *key_data, const void *key_data,
size_t key_data_size,
usec_t until, usec_t until,
uint32_t flags, uint32_t flags,
bool pass_volume_key) { bool pass_volume_key) {
@ -1488,7 +1489,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
assert(name); assert(name);
assert(arg_fido2_device || arg_fido2_device_auto); assert(arg_fido2_device || arg_fido2_device_auto);
if (arg_fido2_cid && !key_file && !iovec_is_set(key_data)) if (arg_fido2_cid && !key_file && !key_data)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"FIDO2 mode with manual parameters selected, but no keyfile specified, refusing."); "FIDO2 mode with manual parameters selected, but no keyfile specified, refusing.");
@ -1512,7 +1513,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
arg_fido2_rp_id, arg_fido2_rp_id,
arg_fido2_cid, arg_fido2_cid_size, arg_fido2_cid, arg_fido2_cid_size,
key_file, arg_keyfile_size, arg_keyfile_offset, key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data, key_data_size,
until, until,
arg_fido2_manual_flags, arg_fido2_manual_flags,
"cryptsetup.fido2-pin", "cryptsetup.fido2-pin",
@ -1622,7 +1623,8 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
struct crypt_device *cd, struct crypt_device *cd,
const char *name, const char *name,
const char *key_file, const char *key_file,
const struct iovec *key_data, const void *key_data,
size_t key_data_size,
usec_t until, usec_t until,
uint32_t flags, uint32_t flags,
bool pass_volume_key) { bool pass_volume_key) {
@ -1633,7 +1635,6 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
_cleanup_(erase_and_freep) void *decrypted_key = NULL; _cleanup_(erase_and_freep) void *decrypted_key = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_free_ void *discovered_key = NULL; _cleanup_free_ void *discovered_key = NULL;
struct iovec discovered_key_data = {};
int keyslot = arg_key_slot, r; int keyslot = arg_key_slot, r;
const char *uri = NULL; const char *uri = NULL;
bool use_libcryptsetup_plugin = use_token_plugins(); bool use_libcryptsetup_plugin = use_token_plugins();
@ -1652,13 +1653,13 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
return r; return r;
uri = discovered_uri; uri = discovered_uri;
discovered_key_data = IOVEC_MAKE(discovered_key, discovered_key_size); key_data = discovered_key;
key_data = &discovered_key_data; key_data_size = discovered_key_size;
} }
} else { } else {
uri = arg_pkcs11_uri; uri = arg_pkcs11_uri;
if (!key_file && !iovec_is_set(key_data)) if (!key_file && !key_data)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
} }
@ -1681,7 +1682,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
friendly, friendly,
uri, uri,
key_file, arg_keyfile_size, arg_keyfile_offset, key_file, arg_keyfile_size, arg_keyfile_offset,
key_data, key_data, key_data_size,
until, until,
arg_ask_password_flags, arg_ask_password_flags,
&decrypted_key, &decrypted_key_size); &decrypted_key, &decrypted_key_size);
@ -2230,9 +2231,9 @@ static int attach_luks_or_plain_or_bitlk(
if (token_type == TOKEN_TPM2) if (token_type == TOKEN_TPM2)
return attach_luks_or_plain_or_bitlk_by_tpm2(cd, name, key_file, key_data, until, flags, pass_volume_key); return attach_luks_or_plain_or_bitlk_by_tpm2(cd, name, key_file, key_data, until, flags, pass_volume_key);
if (token_type == TOKEN_FIDO2) if (token_type == TOKEN_FIDO2)
return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data, until, flags, pass_volume_key); return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data->iov_base, key_data->iov_len, until, flags, pass_volume_key);
if (token_type == TOKEN_PKCS11) if (token_type == TOKEN_PKCS11)
return attach_luks_or_plain_or_bitlk_by_pkcs11(cd, name, key_file, key_data, until, flags, pass_volume_key); return attach_luks_or_plain_or_bitlk_by_pkcs11(cd, name, key_file, key_data->iov_base, key_data->iov_len, until, flags, pass_volume_key);
if (key_data) if (key_data)
return attach_luks_or_plain_or_bitlk_by_key_data(cd, name, key_data, flags, pass_volume_key); return attach_luks_or_plain_or_bitlk_by_key_data(cd, name, key_data, flags, pass_volume_key);
if (key_file) if (key_file)

View File

@ -1858,7 +1858,7 @@ static int bus_method_reset_server_features(sd_bus_message *message, void *userd
} }
static int dnssd_service_on_bus_track(sd_bus_track *t, void *userdata) { static int dnssd_service_on_bus_track(sd_bus_track *t, void *userdata) {
DnssdRegisteredService *s = ASSERT_PTR(userdata); DnssdService *s = ASSERT_PTR(userdata);
assert(t); assert(t);
@ -1870,11 +1870,11 @@ static int dnssd_service_on_bus_track(sd_bus_track *t, void *userdata) {
static int bus_method_register_service(sd_bus_message *message, void *userdata, sd_bus_error *error) { static int bus_method_register_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
_cleanup_(dnssd_service_freep) DnssdRegisteredService *service = NULL; _cleanup_(dnssd_service_freep) DnssdService *service = NULL;
_cleanup_(sd_bus_track_unrefp) sd_bus_track *bus_track = NULL; _cleanup_(sd_bus_track_unrefp) sd_bus_track *bus_track = NULL;
const char *id, *name_template, *type; const char *id, *name_template, *type;
_cleanup_free_ char *path = NULL; _cleanup_free_ char *path = NULL;
DnssdRegisteredService *s = NULL; DnssdService *s = NULL;
Manager *m = ASSERT_PTR(userdata); Manager *m = ASSERT_PTR(userdata);
uid_t euid; uid_t euid;
int r; int r;
@ -1884,7 +1884,7 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
if (m->mdns_support != RESOLVE_SUPPORT_YES) if (m->mdns_support != RESOLVE_SUPPORT_YES)
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for MulticastDNS is disabled"); return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for MulticastDNS is disabled");
service = new0(DnssdRegisteredService, 1); service = new0(DnssdService, 1);
if (!service) if (!service)
return log_oom(); return log_oom();
@ -2046,7 +2046,7 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata,
static int call_dnssd_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) { static int call_dnssd_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
_cleanup_free_ char *name = NULL; _cleanup_free_ char *name = NULL;
DnssdRegisteredService *s = NULL; DnssdService *s = NULL;
const char *path; const char *path;
int r; int r;

View File

@ -1,81 +1,76 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "resolved-dns-browse-services.h"
#include "af-list.h" #include "af-list.h"
#include "event-util.h" #include "event-util.h"
#include "json-util.h" #include "json-util.h"
#include "random-util.h" #include "random-util.h"
#include "resolved-dns-browse-services.h"
#include "resolved-dns-cache.h" #include "resolved-dns-cache.h"
#include "resolved-varlink.h" #include "resolved-varlink.h"
#include "string-table.h"
typedef enum BrowseServiceUpdateFlag {
BROWSE_SERVICE_UPDATE_ADDED,
BROWSE_SERVICE_UPDATE_REMOVED,
_BROWSE_SERVICE_UPDATE_MAX,
_BROWSE_SERVICE_UPDATE_INVALID = -EINVAL,
} BrowseServiceUpdateFlag;
static const char * const browse_service_update_flag_table[_BROWSE_SERVICE_UPDATE_MAX] = {
[BROWSE_SERVICE_UPDATE_ADDED] = "added",
[BROWSE_SERVICE_UPDATE_REMOVED] = "removed",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(browse_service_update_flag, BrowseServiceUpdateFlag);
/* RFC 6762 section 5.2 - The querier should plan to issue a query at 80% of /* RFC 6762 section 5.2 - The querier should plan to issue a query at 80% of
* the record lifetime, and then if no answer is received, at 85%, 90%, and 95%. * the record lifetime, and then if no answer is received, at 85%, 90%, and 95%. */
*/ static usec_t mdns_maintenance_next_time(usec_t until, uint32_t ttl, int ttl_state) {
static usec_t mdns_maintenance_next_time(usec_t until, uint32_t ttl, DnsRecordTTLState ttl_state) {
assert(ttl_state >= DNS_RECORD_TTL_STATE_80_PERCENT);
assert(ttl_state <= _DNS_RECORD_TTL_STATE_MAX);
return usec_sub_unsigned(until, (20 - ttl_state * 5) * ttl * USEC_PER_SEC / 100); return usec_sub_unsigned(until, (20 - ttl_state * 5) * ttl * USEC_PER_SEC / 100);
} }
/* RFC 6762 section 5.2 - A random variation of 2% of the record TTL should /* RFC 6762 section 5.2 - A random variation of 2% of the record TTL should
* be added to maintenance queries. */ * be added to maintenance queries. */
static usec_t mdns_maintenance_jitter(uint32_t ttl) { static usec_t mdns_maintenance_jitter(uint32_t ttl) {
return random_u64_range(2 * ttl * USEC_PER_SEC / 100); return random_u64_range(100) * 2 * ttl * USEC_PER_SEC / 10000;
}
#define MDNS_80_PERCENT 80
#define MDNS_5_PERCENT 5
static void mdns_find_service_from_query(DnsService **service, DnsServiceBrowser *sb, DnsQuery *q) {
assert(sb);
/* Find the service that owns the query. */
LIST_FOREACH(dns_services, s, sb->dns_services) {
if (s->query == q) {
*service = s;
return;
}
}
*service = NULL;
} }
static void mdns_maintenance_query_complete(DnsQuery *q) { static void mdns_maintenance_query_complete(DnsQuery *q) {
_cleanup_(dns_service_browser_unrefp) DnsServiceBrowser *sb = NULL; _cleanup_(dns_service_browser_unrefp) DnsServiceBrowser *sb = NULL;
_cleanup_(dns_query_freep) DnsQuery *query = q; _cleanup_(dns_query_freep) DnsQuery *query = q;
DnssdDiscoveredService *service = NULL; DnsService *service = NULL;
int r; int r;
assert(query); assert(query);
assert(query->manager); assert(query->manager);
if (query->state != DNS_TRANSACTION_SUCCESS) sb = dns_service_browser_ref(hashmap_get(query->manager->dns_service_browsers, query->varlink_request));
return;
service = dns_service_ref(query->dnsservice_request);
if (!service)
return;
sb = dns_service_browser_ref(service->service_browser);
if (!sb) if (!sb)
return; return;
r = dns_answer_match_key(query->answer, sb->key, NULL); if (query->state != DNS_TRANSACTION_SUCCESS) {
if (r <= 0) { r = 0;
log_error_errno(r, "mDNS answer does not match service browser key: %m"); goto finish;
return;
} }
r = mdns_browser_revisit_cache(sb, query->answer_family); r = dns_answer_match_key(query->answer, sb->key, NULL);
if (r < 0) { if (r <= 0)
log_error_errno(r, "Failed to mDNS revisit cache for family %d: %m", query->answer_family); goto finish;
return;
} r = mdns_browser_lookup_cache(sb, query->answer_family);
finish:
if (r < 0)
log_error_errno(r, "mDNS maintenance query complete failed: %m");
mdns_find_service_from_query(&service, sb, query);
if (service)
service->query = NULL;
} }
static int mdns_maintenance_query(sd_event_source *s, uint64_t usec, void *userdata) { static int mdns_maintenance_query(sd_event_source *s, uint64_t usec, void *userdata) {
DnssdDiscoveredService *service = NULL; DnsService *service = NULL;
_cleanup_(dns_query_freep) DnsQuery *q = NULL; _cleanup_(dns_query_freep) DnsQuery *q = NULL;
int r; int r;
@ -83,155 +78,132 @@ static int mdns_maintenance_query(sd_event_source *s, uint64_t usec, void *userd
service = userdata; service = userdata;
/* Check if the TTL state has reached the maximum value, then revisit if (service->rr_ttl_state++ == MDNS_TTL_100_PERCENT)
* cache */ return mdns_browser_lookup_cache(service->sb, service->family);
if (service->rr_ttl_state++ == _DNS_RECORD_TTL_STATE_MAX)
return mdns_browser_revisit_cache(service->service_browser, service->family);
/* Create a new DNS query */ r = dns_query_new(service->sb->m, &q, service->sb->question_utf8, service->sb->question_idna, NULL, service->sb->ifindex, service->sb->flags);
r = dns_query_new(
service->service_browser->manager,
&q,
service->service_browser->question_utf8,
service->service_browser->question_idna,
/* question_bypass= */ NULL,
service->service_browser->ifindex,
service->service_browser->flags);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create mDNS query for maintenance: %m"); goto finish;
q->complete = mdns_maintenance_query_complete; q->complete = mdns_maintenance_query_complete;
q->varlink_request = sd_varlink_ref(service->service_browser->link); q->varlink_request = sd_varlink_ref(service->sb->link);
q->dnsservice_request = dns_service_ref(service); service->query = TAKE_PTR(q);
/* Schedule the next maintenance query based on the TTL */
usec_t next_time = mdns_maintenance_next_time(service->until, service->rr->ttl, service->rr_ttl_state); usec_t next_time = mdns_maintenance_next_time(service->until, service->rr->ttl, service->rr_ttl_state);
/* Schedule next maintenance query for service */
r = event_reset_time( r = event_reset_time(
service->service_browser->manager->event, service->sb->m->event, &service->schedule_event,
&service->schedule_event, CLOCK_BOOTTIME, next_time, 0, mdns_maintenance_query,
CLOCK_BOOTTIME, service, 0, "mdns-next-query-schedule", true);
next_time,
/* accuracy= */ 0,
mdns_maintenance_query,
service,
/* priority= */ 0,
"mdns-next-query-schedule",
/* force_reset= */ true);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to schedule next mDNS maintenance query: %m"); goto finish;
/* Perform the query */ r = dns_query_go(service->query);
r = dns_query_go(q);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to send mDNS maintenance query: %m"); goto finish;
TAKE_PTR(q);
return 0; return 0;
finish:
dns_query_free(service->query);
return log_error_errno(r, "Failed mdns maintenance query: %m");
} }
int dns_add_new_service(DnsServiceBrowser *sb, DnsResourceRecord *rr, int owner_family) { int dns_add_new_service(DnsServiceBrowser *sb, DnsResourceRecord *rr, int owner_family) {
_cleanup_(dns_service_unrefp) DnssdDiscoveredService *s = NULL; _cleanup_(dns_service_unrefp) DnsService *s = NULL;
int r; int r;
assert(sb); assert(sb);
assert(rr); assert(rr);
s = new (DnssdDiscoveredService, 1); s = new(DnsService, 1);
if (!s) { if (!s)
log_oom(); return log_oom();
return -ENOMEM;
}
usec_t usec = now(CLOCK_BOOTTIME); usec_t usec = now(CLOCK_BOOTTIME);
*s = (DnssdDiscoveredService) { *s = (DnsService) {
.n_ref = 1, .n_ref = 1,
.service_browser = sb, .sb = dns_service_browser_ref(sb),
.rr = dns_resource_record_copy(rr), .rr = dns_resource_record_copy(rr),
.family = owner_family, .family = owner_family,
.until = rr->until, .until = rr->until,
.query = NULL, .query = NULL,
.rr_ttl_state = DNS_RECORD_TTL_STATE_80_PERCENT, .rr_ttl_state = MDNS_TTL_80_PERCENT,
}; };
LIST_PREPEND(dns_services, sb->dns_services, s); LIST_PREPEND(dns_services, sb->dns_services, s);
/* Schedule the first cache maintenance query at 80% of the record's /* Schedule the first cache maintenance query at 80% of the record's TTL.
* TTL. Subsequent queries issued at 5% increments until 100% of the * Subsequent queries issued at 5% increments until 100% of the TTL. RFC 6762 section 5.2.
* TTL. RFC 6762 section 5.2. If service is being added after 80% of the * If service is being added after 80% of the TTL has already elapsed,
* TTL has already elapsed, schedule the next query at the next 5% * schedule the next query at the next 5% increment. */
* increment. */
usec_t next_time = 0; usec_t next_time = 0;
while (s->rr_ttl_state >= DNS_RECORD_TTL_STATE_80_PERCENT && while (s->rr_ttl_state <= MDNS_TTL_100_PERCENT) {
s->rr_ttl_state <= _DNS_RECORD_TTL_STATE_MAX) {
next_time = mdns_maintenance_next_time(rr->until, rr->ttl, s->rr_ttl_state); next_time = mdns_maintenance_next_time(rr->until, rr->ttl, s->rr_ttl_state);
if (next_time >= usec) if (next_time >= usec)
break; break;
s->rr_ttl_state++; s->rr_ttl_state++;
} }
if (next_time < usec) { if (next_time < usec) {
/* If next_time is still in the past, the service is being added /* If next_time is still in the past, the service is being added after it has already expired.
* after it has already expired. Just schedule a 100% * Just schedule a 100% maintenance query */
* maintenance query */
next_time = usec + USEC_PER_SEC; next_time = usec + USEC_PER_SEC;
s->rr_ttl_state = _DNS_RECORD_TTL_STATE_MAX; s->rr_ttl_state = MDNS_TTL_100_PERCENT;
} }
usec_t jitter = mdns_maintenance_jitter(rr->ttl); usec_t jitter = mdns_maintenance_jitter(rr->ttl);
r = sd_event_add_time( r = sd_event_add_time(
sb->manager->event, sb->m->event,
&s->schedule_event, &s->schedule_event,
CLOCK_BOOTTIME, CLOCK_BOOTTIME,
usec_add(next_time, jitter), usec_add(next_time, jitter),
/* accuracy= */ 0, 0,
mdns_maintenance_query, mdns_maintenance_query,
s); s);
if (r < 0) { if (r < 0)
return log_error_errno( return r;
r,
"Failed to schedule mDNS maintenance query "
"for DNS service: %m");
}
TAKE_PTR(s); TAKE_PTR(s);
return 0; return 0;
} }
void dns_remove_service(DnsServiceBrowser *sb, DnssdDiscoveredService *service) { void dns_remove_service(DnsServiceBrowser *sb, DnsService *service) {
assert(sb); assert(sb);
assert(service); assert(service);
LIST_REMOVE(dns_services, sb->dns_services, service); LIST_REMOVE(dns_services, sb->dns_services, service);
dns_service_unref(service); dns_service_free(service);
} }
DnssdDiscoveredService *dns_service_free(DnssdDiscoveredService *service) { DnsService *dns_service_free(DnsService *service) {
if (!service) if (!service)
return NULL; return NULL;
sd_event_source_disable_unref(service->schedule_event); sd_event_source_disable_unref(service->schedule_event);
if (service->query && DNS_TRANSACTION_IS_LIVE(service->query->state)) if (service->query && DNS_TRANSACTION_IS_LIVE(service->query->state))
dns_query_complete(service->query, DNS_TRANSACTION_ABORTED); dns_query_complete(service->query, DNS_TRANSACTION_ABORTED);
dns_service_browser_unref(service->sb);
dns_resource_record_unref(service->rr); dns_resource_record_unref(service->rr);
return mfree(service); return mfree(service);
} }
DEFINE_TRIVIAL_REF_UNREF_FUNC(DnssdDiscoveredService, dns_service, dns_service_free); DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsService, dns_service, dns_service_free);
int mdns_service_update(DnssdDiscoveredService *service, DnsResourceRecord *rr, usec_t t) { int mdns_service_update(DnsService *service, DnsResourceRecord *rr, usec_t t) {
service->until = rr->until; service->until = rr->until;
service->rr->ttl = rr->ttl; service->rr->ttl = rr->ttl;
/* Update the 80% TTL maintenance event based on new record received /* Update the 80% TTL maintenance event based on new record received from the network.
* from the network. RFC 6762 section 5.2 */ * RFC 6762 section 5.2 */
usec_t next_time = mdns_maintenance_next_time( usec_t next_time = mdns_maintenance_next_time(service->until, service->rr->ttl, MDNS_TTL_80_PERCENT);
service->until, service->rr->ttl, DNS_RECORD_TTL_STATE_80_PERCENT);
usec_t jitter = mdns_maintenance_jitter(service->rr->ttl); usec_t jitter = mdns_maintenance_jitter(service->rr->ttl);
if (service->schedule_event) if (service->schedule_event)
@ -240,7 +212,7 @@ int mdns_service_update(DnssdDiscoveredService *service, DnsResourceRecord *rr,
return 0; return 0;
} }
bool dns_service_contains(DnssdDiscoveredService *services, DnsResourceRecord *rr, int owner_family) { bool dns_service_contains(DnsService *services, DnsResourceRecord *rr, int owner_family) {
usec_t t = now(CLOCK_BOOTTIME); usec_t t = now(CLOCK_BOOTTIME);
LIST_FOREACH(dns_services, service, services) LIST_FOREACH(dns_services, service, services)
@ -260,7 +232,7 @@ bool dns_service_contains(DnssdDiscoveredService *services, DnsResourceRecord *r
void dns_browse_services_purge(Manager *m, int family) { void dns_browse_services_purge(Manager *m, int family) {
int r = 0; int r = 0;
/* Called after caches are flushed. /* Called after caches are flused.
* Clear local service records and notify varlink client. */ * Clear local service records and notify varlink client. */
if (!(m && m->dns_service_browsers)) if (!(m && m->dns_service_browsers))
return; return;
@ -268,31 +240,28 @@ void dns_browse_services_purge(Manager *m, int family) {
DnsServiceBrowser *sb; DnsServiceBrowser *sb;
HASHMAP_FOREACH(sb, m->dns_service_browsers) { HASHMAP_FOREACH(sb, m->dns_service_browsers) {
r = sd_event_source_set_enabled(sb->schedule_event, SD_EVENT_OFF); r = sd_event_source_set_enabled(sb->schedule_event, SD_EVENT_OFF);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to disable event source for service browser: %m"); goto finish;
return;
}
if (family == AF_UNSPEC) { if (family == AF_UNSPEC) {
r = mdns_browser_revisit_cache(sb, AF_INET); r = mdns_browser_lookup_cache(sb, AF_INET);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to revisit cache for IPv4: %m"); goto finish;
return; r = mdns_browser_lookup_cache(sb, AF_INET6);
} if (r < 0)
r = mdns_browser_revisit_cache(sb, AF_INET6); goto finish;
if (r < 0) {
log_error_errno(r, "Failed to revisit cache for IPv6: %m");
return;
}
return; return;
} }
r = mdns_browser_revisit_cache(sb, family); r = mdns_browser_lookup_cache(sb, family);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to revisit cache for family %d: %m", family); goto finish;
return;
}
} }
finish:
if (r < 0)
log_error_errno(r, "mdns browse services purge failed: %m");
return;
} }
int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int owner_family) { int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int owner_family) {
@ -311,61 +280,44 @@ int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int ow
continue; continue;
r = dns_service_split(i->ptr.name, &name, &type, &domain); r = dns_service_split(i->ptr.name, &name, &type, &domain);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to split DNS service name: %m");
goto finish; goto finish;
}
if (!name) { if (!name) {
type = mfree(type); type = mfree(type);
domain = mfree(domain); domain = mfree(domain);
r = dns_service_split(dns_resource_key_name(i->key), &name, &type, &domain); r = dns_service_split(dns_resource_key_name(i->key), &name, &type, &domain);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to split DNS service name (fallback): %m");
goto finish; goto finish;
}
} }
if (!type) if (!type)
continue; continue;
r = dns_add_new_service(sb, i, owner_family); r = dns_add_new_service(sb, i, owner_family);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to add new DNS service: %m");
goto finish; goto finish;
}
log_debug("Add into the list %s, %s, %s, %s, %d", log_debug("Add into the list %s, %s, %s, %s, %d",
strna(name), strna(name),
strna(type), strna(type),
strna(domain), strna(domain),
strna(af_to_ipv4_ipv6(owner_family)), strna(af_to_ipv4_ipv6(owner_family)),
sb->ifindex); sb->ifindex);
r = sd_json_buildo( r = sd_json_buildo(&entry,
&entry, SD_JSON_BUILD_PAIR("add_flag", SD_JSON_BUILD_BOOLEAN(true)),
SD_JSON_BUILD_PAIR( SD_JSON_BUILD_PAIR("family", SD_JSON_BUILD_INTEGER(owner_family)),
"updateFlag", SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(name?: "")),
SD_JSON_BUILD_STRING(browse_service_update_flag_to_string( SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(type?: "")),
BROWSE_SERVICE_UPDATE_ADDED))), SD_JSON_BUILD_PAIR("domain", SD_JSON_BUILD_STRING(domain?: "")),
SD_JSON_BUILD_PAIR("family", SD_JSON_BUILD_INTEGER(owner_family)), SD_JSON_BUILD_PAIR("interface", SD_JSON_BUILD_INTEGER(sb->ifindex)));
SD_JSON_BUILD_PAIR_CONDITION( if (r < 0)
!isempty(name), "name", SD_JSON_BUILD_STRING(name)),
SD_JSON_BUILD_PAIR_CONDITION(
!isempty(type), "type", SD_JSON_BUILD_STRING(type)),
SD_JSON_BUILD_PAIR_CONDITION(
!isempty(domain), "domain", SD_JSON_BUILD_STRING(domain)),
SD_JSON_BUILD_PAIR("ifindex", SD_JSON_BUILD_INTEGER(sb->ifindex)));
if (r < 0) {
log_error_errno(r, "Failed to build JSON for new service: %m");
goto finish; goto finish;
}
r = sd_json_variant_append_array(&array, entry); r = sd_json_variant_append_array(&array, entry);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to append JSON entry to array: %m");
goto finish; goto finish;
}
} }
/* Check for services removed */ /* Check for services removed */
@ -380,70 +332,52 @@ int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int ow
continue; continue;
r = dns_service_split(service->rr->ptr.name, &name, &type, &domain); r = dns_service_split(service->rr->ptr.name, &name, &type, &domain);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to split DNS service name from list: %m");
goto finish; goto finish;
}
if (!name) { if (!name) {
type = mfree(type); type = mfree(type);
domain = mfree(domain); domain = mfree(domain);
r = dns_service_split(dns_resource_key_name(service->rr->key), &name, &type, &domain); r = dns_service_split(dns_resource_key_name(service->rr->key), &name, &type, &domain);
if (r < 0) { if (r < 0)
log_error_errno(r,
"Failed to split DNS service name (fallback) from list: %m");
goto finish; goto finish;
}
} }
dns_remove_service(sb, service); dns_remove_service(sb, service);
log_debug("Remove from the list %s, %s, %s, %s, %d", log_debug("Remove from the list %s, %s, %s, %s, %d",
strna(name), strna(name),
strna(type), strna(type),
strna(domain), strna(domain),
strna(af_to_ipv4_ipv6(owner_family)), strna(af_to_ipv4_ipv6(owner_family)),
sb->ifindex); sb->ifindex);
r = sd_json_buildo( r = sd_json_buildo(&entry,
&entry, SD_JSON_BUILD_PAIR("add_flag", SD_JSON_BUILD_BOOLEAN(false)),
SD_JSON_BUILD_PAIR( SD_JSON_BUILD_PAIR("family", SD_JSON_BUILD_INTEGER(owner_family)),
"updateFlag", SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(name?: "")),
SD_JSON_BUILD_STRING(browse_service_update_flag_to_string( SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(type?: "")),
BROWSE_SERVICE_UPDATE_REMOVED))), SD_JSON_BUILD_PAIR("domain", SD_JSON_BUILD_STRING(domain?: "")),
SD_JSON_BUILD_PAIR("family", SD_JSON_BUILD_INTEGER(owner_family)), SD_JSON_BUILD_PAIR("interface", SD_JSON_BUILD_INTEGER(sb->ifindex)));
SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(name ?: "")), if (r < 0)
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(type ?: "")),
SD_JSON_BUILD_PAIR("domain", SD_JSON_BUILD_STRING(domain ?: "")),
SD_JSON_BUILD_PAIR("ifindex", SD_JSON_BUILD_INTEGER(sb->ifindex)));
if (r < 0) {
log_error_errno(r, "Failed to build JSON for removed service: %m");
goto finish; goto finish;
}
r = sd_json_variant_append_array(&array, entry); r = sd_json_variant_append_array(&array, entry);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to append JSON entry to array: %m");
goto finish; goto finish;
}
} }
if (!sd_json_variant_is_blank_array(array)) { if (!sd_json_variant_is_blank_array(array)) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *vm = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *vm = NULL;
r = sd_json_buildo(&vm, SD_JSON_BUILD_PAIR("browserServiceData", SD_JSON_BUILD_VARIANT(array))); r = sd_json_buildo(&vm,
if (r < 0) { SD_JSON_BUILD_PAIR("browser_service_data", SD_JSON_BUILD_VARIANT(array)));
log_error_errno(r, if (r < 0)
"Failed to build JSON object for "
"browser service data: %m");
goto finish; goto finish;
}
r = sd_varlink_notify(sb->link, vm); r = sd_varlink_notify(sb->link, vm);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to notify via varlink: %m");
goto finish; goto finish;
}
} }
return 0; return 0;
@ -453,29 +387,33 @@ finish:
return sd_varlink_error_errno(sb->link, r); return sd_varlink_error_errno(sb->link, r);
} }
int mdns_browser_revisit_cache(DnsServiceBrowser *sb, int owner_family) { int mdns_browser_lookup_cache(DnsServiceBrowser *sb, int owner_family) {
_cleanup_(dns_answer_unrefp) DnsAnswer *lookup_ret_answer = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *lookup_ret_answer = NULL;
DnsScope *scope; DnsScope *scope;
int r; int r;
assert(sb); assert(sb);
assert(sb->manager); assert(sb->m);
scope = manager_find_scope_from_protocol(sb->manager, sb->ifindex, DNS_PROTOCOL_MDNS, owner_family); scope = manager_find_scope_from_protocol(sb->m, sb->ifindex, DNS_PROTOCOL_MDNS, owner_family);
if (!scope) if (!scope)
return 0; return 0;
dns_cache_prune(&scope->cache); dns_cache_prune(&scope->cache);
r = dns_cache_lookup(&scope->cache, sb->key, sb->flags, NULL, &lookup_ret_answer, NULL, NULL, NULL); r = dns_cache_lookup(
&scope->cache,
sb->key,
sb->flags,
NULL,
&lookup_ret_answer,
NULL,
NULL,
NULL);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to look up DNS cache for service browser key: %m"); return r;
r = mdns_manage_services_answer(sb, lookup_ret_answer, owner_family); return mdns_manage_services_answer(sb, lookup_ret_answer, owner_family);
if (r < 0)
return log_error_errno(r, "Failed to manage mDNS services after cache lookup: %m");
return 0;
} }
int mdns_notify_browsers_goodbye(DnsScope *scope) { int mdns_notify_browsers_goodbye(DnsScope *scope) {
@ -486,16 +424,15 @@ int mdns_notify_browsers_goodbye(DnsScope *scope) {
return 0; return 0;
HASHMAP_FOREACH(sb, scope->manager->dns_service_browsers) { HASHMAP_FOREACH(sb, scope->manager->dns_service_browsers) {
r = mdns_browser_revisit_cache(sb, scope->family); r = mdns_browser_lookup_cache(sb, scope->family);
if (r < 0) if (r < 0)
return log_error_errno( goto finish;
r,
"Failed to revisit cache for service "
"browser with family %d: %m",
scope->family);
} }
return 0; return 0;
finish:
return r;
} }
int mdns_notify_browsers_unsolicited_updates(Manager *m, DnsAnswer *answer, int owner_family) { int mdns_notify_browsers_unsolicited_updates(Manager *m, DnsAnswer *answer, int owner_family) {
@ -511,23 +448,21 @@ int mdns_notify_browsers_unsolicited_updates(Manager *m, DnsAnswer *answer, int
return 0; return 0;
HASHMAP_FOREACH(sb, m->dns_service_browsers) { HASHMAP_FOREACH(sb, m->dns_service_browsers) {
r = dns_answer_match_key(answer, sb->key, NULL); r = dns_answer_match_key(answer, sb->key, NULL);
if (r < 0) { if (r < 0)
return log_error_errno( goto finish;
r, else if (r == 0)
"Failed to match answer key with "
"service browser's key: %m");
}
if (r == 0)
continue; continue;
r = mdns_browser_revisit_cache(sb, owner_family); r = mdns_browser_lookup_cache(sb, owner_family);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to revisit cache for service browser: %m"); goto finish;
} }
return 0; return 0;
finish:
return log_error_errno(r, "Failed to notify mDNS service subscribers, %m");
} }
static void mdns_browse_service_query_complete(DnsQuery *q) { static void mdns_browse_service_query_complete(DnsQuery *q) {
@ -541,37 +476,32 @@ static void mdns_browse_service_query_complete(DnsQuery *q) {
if (query->state != DNS_TRANSACTION_SUCCESS) if (query->state != DNS_TRANSACTION_SUCCESS)
return; return;
sb = dns_service_browser_ref(query->service_browser_request); sb = dns_service_browser_ref(hashmap_get(query->manager->dns_service_browsers, query->varlink_request));
if (!sb) if (!sb)
return; return;
r = dns_answer_match_key(query->answer, sb->key, NULL); r = dns_answer_match_key(query->answer, sb->key, NULL);
if (r < 0) { if (r < 0)
log_error_errno(r, goto finish;
"Failed to match answer key with service " else if (r == 0)
"browser's key: %m");
return;
}
if (r == 0)
return; return;
r = mdns_browser_revisit_cache(sb, query->answer_family); r = mdns_browser_lookup_cache(sb, query->answer_family);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to revisit cache for service browser: %m"); goto finish;
return;
}
/* When the query is answered from cache, we only get answers for one /* When the query is answered from cache, we only get answers for one answer_family
* answer_family i.e. either ipv4 or ipv6. We need to perform another * i.e. either ipv4 or ipv6.
* cache lookup for the other answer_family */ * We need to perform another cache lookup for the other answer_family */
if (query->answer_query_flags == SD_RESOLVED_FROM_CACHE) { if (query->answer_query_flags == SD_RESOLVED_FROM_CACHE) {
r = mdns_browser_revisit_cache(sb, query->answer_family == AF_INET ? AF_INET6 : AF_INET); r = mdns_browser_lookup_cache(sb, query->answer_family == AF_INET? AF_INET6 : AF_INET);
if (r < 0) { if (r < 0)
log_error_errno(r, "Failed to revisit cache for service browser: %m"); goto finish;
return;
}
} }
return;
finish:
log_error_errno(r, "mDNS browse query complete failed, %m");
} }
static int mdns_next_query_schedule(sd_event_source *s, uint64_t usec, void *userdata) { static int mdns_next_query_schedule(sd_event_source *s, uint64_t usec, void *userdata) {
@ -582,65 +512,49 @@ static int mdns_next_query_schedule(sd_event_source *s, uint64_t usec, void *use
assert(userdata); assert(userdata);
sb = dns_service_browser_ref(userdata); sb = dns_service_browser_ref(userdata);
if (!sb)
return log_error_errno(0, "Failed to reference service browser: %m");
/* Enable the answer from the cache for the very first query */ r = dns_query_new(sb->m, &q, sb->question_utf8, sb->question_idna, NULL, sb->ifindex, sb->flags);
if (sb->delay == 0) {
SET_FLAG(sb->flags, SD_RESOLVED_NO_CACHE, false);
sb->delay++;
}
r = dns_query_new(sb->manager, &q, sb->question_utf8, sb->question_idna, NULL, sb->ifindex, sb->flags);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create new DNS query: %m"); goto finish;
q->complete = mdns_browse_service_query_complete; q->complete = mdns_browse_service_query_complete;
q->service_browser_request = dns_service_browser_ref(sb);
q->varlink_request = sd_varlink_ref(sb->link); q->varlink_request = sd_varlink_ref(sb->link);
if (!q->varlink_request) {
log_error_errno(0, "Failed to reference varlink request: %m");
dns_query_free(q);
return -ENOMEM;
}
sd_varlink_set_userdata(sb->link, q); sd_varlink_set_userdata(sb->link, q);
r = dns_query_go(q); r = dns_query_go(q);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to send DNS query: %m"); goto finish;
/* RFC6762 5.2 /* RFC6762 5.2
* The intervals between successive queries MUST increase by at least a * The intervals between successive queries MUST increase by at least a factor of two.
* factor of two. When the interval between queries reaches or exceeds * When the interval between queries reaches or exceeds 60 minutes,perform
* 60 minutes,perform subsequent queries at a steady-state rate of one * subsequent queries at a steady-state rate of one query per hour */
* query per hour */ if (sb->delay == 0) {
sb->delay++;
sb->delay = sb->delay < 2048 ? sb->delay * 2 : 3600; /* First query is sent wihtout SD_RESOLVED_NO_CACHE to fetch answers already in cache.
* Set SD_RESOLVED_NO_CACHE to make all subsequent queries go to the network. */
SET_FLAG(sb->flags, SD_RESOLVED_NO_CACHE, true); sb->flags |= SD_RESOLVED_NO_CACHE;
}
else
sb->delay = sb->delay < 2048 ? sb->delay * 2 : 3600;
r = event_reset_time_relative( r = event_reset_time_relative(
sb->manager->event, sb->m->event, &sb->schedule_event,
&sb->schedule_event, CLOCK_BOOTTIME, (sb->delay * USEC_PER_SEC),
CLOCK_BOOTTIME, 0, mdns_next_query_schedule,
(sb->delay * USEC_PER_SEC), sb, 0, "mdns-next-query-schedule", true);
/* accuracy= */ 0,
mdns_next_query_schedule,
sb,
/* priority= */ 0,
"mdns-next-query-schedule",
/* force_reset= */ true);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to reset event time for next query schedule: %m"); goto finish;
TAKE_PTR(q); TAKE_PTR(q);
return 0; return 0;
finish:
return log_error_errno(r, "Failed to schedule mDNS query, %m");
} }
void dns_browse_services_restart(Manager *m) { void dns_service_browser_reset(Manager *m) {
int r; int r;
if (!(m && m->dns_service_browsers)) if (!(m && m->dns_service_browsers))
@ -652,27 +566,25 @@ void dns_browse_services_restart(Manager *m) {
sb->delay = 0; sb->delay = 0;
r = event_reset_time_relative( r = event_reset_time_relative(
sb->manager->event, sb->m->event, &sb->schedule_event,
&sb->schedule_event, CLOCK_BOOTTIME, (sb->delay * USEC_PER_SEC),
CLOCK_BOOTTIME, 0, mdns_next_query_schedule,
(sb->delay * USEC_PER_SEC), sb, 0, "mdns-next-query-schedule", true);
/* accuracy= */ 0, if (r < 0)
mdns_next_query_schedule, log_error_errno(r, "Failed to reset mdns service subscriber, %m");
sb,
/* priority= */ 0,
"mdns-next-query-schedule",
/* force_reset= */ true);
if (r < 0) {
log_error_errno(r,
"Failed to reset mDNS service subscriber event "
"for service browser: %m");
}
} }
return;
} }
int dns_subscribe_browse_service( int dns_subscribe_browse_service(
Manager *m, sd_varlink *link, const char *domain, const char *type, int ifindex, uint64_t flags) { Manager *m,
sd_varlink *link,
const char *domain,
const char *name,
const char *type,
int ifindex,
uint64_t flags) {
_cleanup_(dns_service_browser_unrefp) DnsServiceBrowser *sb = NULL; _cleanup_(dns_service_browser_unrefp) DnsServiceBrowser *sb = NULL;
_cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL; _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
@ -681,40 +593,40 @@ int dns_subscribe_browse_service(
assert(m); assert(m);
assert(link); assert(link);
if (ifindex < 0) if (ifindex <= 0)
return sd_varlink_error_invalid_parameter_name(link, "ifindex"); return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("ifindex"));
if (isempty(name))
name = NULL;
else if (!dns_service_name_is_valid(name))
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("name"));
if (isempty(type)) if (isempty(type))
type = NULL; type = NULL;
else if (!dnssd_srv_type_is_valid(type)) else if (!dnssd_srv_type_is_valid(type))
return sd_varlink_error_invalid_parameter_name(link, "type"); return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("type"));
if (isempty(domain))
domain = "local";
r = dns_name_is_valid(domain); r = dns_name_is_valid(domain);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0) if (r == 0)
return sd_varlink_error_invalid_parameter_name(link, "domain"); return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("domain"));
r = dns_question_new_service_type( r = dns_question_new_service_type(&question_utf8, name, type, domain, false, DNS_TYPE_PTR);
&question_utf8, /* name= */ NULL, type, domain, /* convert_idna= */ false, DNS_TYPE_PTR);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create DNS question for UTF8 version: %m"); return r;
r = dns_question_new_service_type( r = dns_question_new_service_type(&question_idna, name, type, domain, true, DNS_TYPE_PTR);
&question_idna, /* name= */ NULL, type, domain, /* convert_idna= */ true, DNS_TYPE_PTR);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to create DNS question for IDNA version: %m"); return r;
sb = new (DnsServiceBrowser, 1); sb = new(DnsServiceBrowser, 1);
if (!sb) if (!sb)
return log_oom(); return log_oom();
*sb = (DnsServiceBrowser) { *sb = (DnsServiceBrowser) {
.n_ref = 1, .n_ref = 1,
.manager = m, .m = m,
.link = sd_varlink_ref(link), .link = sd_varlink_ref(link),
.question_utf8 = dns_question_ref(question_utf8), .question_utf8 = dns_question_ref(question_utf8),
.question_idna = dns_question_ref(question_idna), .question_idna = dns_question_ref(question_idna),
@ -726,12 +638,11 @@ int dns_subscribe_browse_service(
/* Only mDNS continuous querying is currently supported. See RFC 6762 */ /* Only mDNS continuous querying is currently supported. See RFC 6762 */
switch (flags & SD_RESOLVED_PROTOCOLS_ALL) { switch (flags & SD_RESOLVED_PROTOCOLS_ALL) {
case SD_RESOLVED_MDNS: case SD_RESOLVED_MDNS:
r = sd_event_add_time_relative( r = sd_event_add_time(m->event,
m->event,
&sb->schedule_event, &sb->schedule_event,
CLOCK_BOOTTIME, CLOCK_BOOTTIME,
(sb->delay * USEC_PER_SEC), usec_add(now(CLOCK_BOOTTIME), (sb->delay * USEC_PER_SEC)),
/* accuracy= */ 0, 0,
mdns_next_query_schedule, mdns_next_query_schedule,
sb); sb);
if (r < 0) if (r < 0)
@ -743,7 +654,7 @@ int dns_subscribe_browse_service(
r = hashmap_ensure_put(&m->dns_service_browsers, NULL, link, sb); r = hashmap_ensure_put(&m->dns_service_browsers, NULL, link, sb);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to add service browser to the hashmap: %m"); return r;
TAKE_PTR(sb); TAKE_PTR(sb);
@ -756,8 +667,8 @@ DnsServiceBrowser *dns_service_browser_free(DnsServiceBrowser *sb) {
if (!sb) if (!sb)
return NULL; return NULL;
while (sb->dns_services) LIST_FOREACH(dns_services, service, sb->dns_services)
dns_remove_service(sb, sb->dns_services); dns_remove_service(sb, service);
sd_event_source_disable_unref(sb->schedule_event); sd_event_source_disable_unref(sb->schedule_event);

View File

@ -3,39 +3,38 @@
#pragma once #pragma once
typedef struct DnsServiceBrowser DnsServiceBrowser; typedef struct DnsServiceBrowser DnsServiceBrowser;
typedef struct DnssdDiscoveredService DnssdDiscoveredService;
#include "sd-varlink.h"
#include "resolved-dns-query.h" #include "resolved-dns-query.h"
#include "resolved-manager.h" #include "resolved-manager.h"
#include "sd-varlink.h"
typedef struct DnsService DnsService;
typedef enum DnsRecordTTLState DnsRecordTTLState; typedef enum DnsRecordTTLState DnsRecordTTLState;
enum DnsRecordTTLState { enum DnsRecordTTLState {
DNS_RECORD_TTL_STATE_80_PERCENT, MDNS_TTL_80_PERCENT,
DNS_RECORD_TTL_STATE_85_PERCENT, MDNS_TTL_85_PERCENT,
DNS_RECORD_TTL_STATE_90_PERCENT, MDNS_TTL_90_PERCENT,
DNS_RECORD_TTL_STATE_95_PERCENT, MDNS_TTL_95_PERCENT,
_DNS_RECORD_TTL_STATE_MAX, MDNS_TTL_100_PERCENT
_DNS_RECORD_TTL_STATE_MAX_INVALID = -EINVAL
}; };
struct DnssdDiscoveredService { struct DnsService {
unsigned n_ref; unsigned n_ref;
DnsServiceBrowser *service_browser; DnsServiceBrowser *sb;
sd_event_source *schedule_event; sd_event_source *schedule_event;
DnsResourceRecord *rr; DnsResourceRecord *rr;
int family; int family;
usec_t until; usec_t until;
DnsRecordTTLState rr_ttl_state; DnsRecordTTLState rr_ttl_state;
DnsQuery *query; DnsQuery *query;
LIST_FIELDS(DnssdDiscoveredService, dns_services); LIST_FIELDS(DnsService, dns_services);
}; };
struct DnsServiceBrowser { struct DnsServiceBrowser {
unsigned n_ref; unsigned n_ref;
Manager *manager; Manager *m;
sd_varlink *link; sd_varlink *link;
DnsQuestion *question_idna; DnsQuestion *question_idna;
DnsQuestion *question_utf8; DnsQuestion *question_utf8;
@ -45,35 +44,35 @@ struct DnsServiceBrowser {
DnsResourceKey *key; DnsResourceKey *key;
int ifindex; int ifindex;
uint64_t token; uint64_t token;
LIST_HEAD(DnssdDiscoveredService, dns_services); LIST_HEAD(DnsService, dns_services);
}; };
DnsServiceBrowser *dns_service_browser_free(DnsServiceBrowser *sb); DnsServiceBrowser *dns_service_browser_free(DnsServiceBrowser *sb);
void dns_remove_service(DnsServiceBrowser *sb, DnssdDiscoveredService *service); void dns_remove_service(DnsServiceBrowser *sb, DnsService *service);
DnssdDiscoveredService *dns_service_free(DnssdDiscoveredService *service); DnsService *dns_service_free(DnsService *service);
DnsServiceBrowser *dns_service_browser_ref(DnsServiceBrowser *sb); DnsServiceBrowser* dns_service_browser_ref(DnsServiceBrowser *sb);
DnsServiceBrowser *dns_service_browser_unref(DnsServiceBrowser *sb); DnsServiceBrowser* dns_service_browser_unref(DnsServiceBrowser *sb);
DnssdDiscoveredService *dns_service_ref(DnssdDiscoveredService *service); DnsService* dns_service_ref(DnsService *service);
DnssdDiscoveredService *dns_service_unref(DnssdDiscoveredService *service); DnsService* dns_service_unref(DnsService *service);
void dns_browse_services_purge(Manager *m, int family); void dns_browse_services_purge(Manager *m, int family);
void dns_browse_services_restart(Manager *m); void dns_service_browser_reset(Manager *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServiceBrowser *, dns_service_browser_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServiceBrowser*, dns_service_browser_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdDiscoveredService *, dns_service_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsService*, dns_service_unref);
bool dns_service_contains(DnssdDiscoveredService *services, DnsResourceRecord *rr, int owner_family); bool dns_service_contains(DnsService *services, DnsResourceRecord *rr, int owner_family);
int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int owner_family); int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int owner_family);
int dns_add_new_service(DnsServiceBrowser *sb, DnsResourceRecord *rr, int owner_family); int dns_add_new_service(DnsServiceBrowser *sb, DnsResourceRecord *rr, int owner_family);
int mdns_service_update(DnssdDiscoveredService *service, DnsResourceRecord *rr, usec_t t); int mdns_service_update(DnsService *service, DnsResourceRecord *rr, usec_t t);
int mdns_browser_revisit_cache(DnsServiceBrowser *sb, int owner_family); int mdns_browser_lookup_cache(DnsServiceBrowser *sb, int owner_family);
int dns_subscribe_browse_service( int dns_subscribe_browse_service(Manager *m,
Manager *m,
sd_varlink *link, sd_varlink *link,
const char *domain, const char *domain,
const char *type, const char * name,
const char * type,
int ifindex, int ifindex,
uint64_t flags); uint64_t flags);
int mdns_notify_browsers_unsolicited_updates(Manager *m, DnsAnswer *answer, int owner_family); int mdns_notify_browsers_unsolicited_updates(Manager *m, DnsAnswer *answer, int owner_family);

View File

@ -456,12 +456,6 @@ DnsQuery *dns_query_free(DnsQuery *q) {
free(q->request_address_string); free(q->request_address_string);
if (q->dnsservice_request)
dns_service_unref(q->dnsservice_request);
if (q->service_browser_request)
dns_service_browser_unref(q->service_browser_request);
if (q->manager) { if (q->manager) {
LIST_REMOVE(queries, q->manager->dns_queries, q); LIST_REMOVE(queries, q->manager->dns_queries, q);
q->manager->n_dns_queries--; q->manager->n_dns_queries--;

View File

@ -11,7 +11,6 @@ typedef struct DnsQuery DnsQuery;
typedef struct DnsStubListenerExtra DnsStubListenerExtra; typedef struct DnsStubListenerExtra DnsStubListenerExtra;
#include "resolved-dns-answer.h" #include "resolved-dns-answer.h"
#include "resolved-dns-browse-services.h"
#include "resolved-dns-question.h" #include "resolved-dns-question.h"
#include "resolved-dns-search-domain.h" #include "resolved-dns-search-domain.h"
#include "resolved-dns-transaction.h" #include "resolved-dns-transaction.h"
@ -112,10 +111,6 @@ struct DnsQuery {
DnsAnswer *reply_additional; DnsAnswer *reply_additional;
DnsStubListenerExtra *stub_listener_extra; DnsStubListenerExtra *stub_listener_extra;
/* Browser Service and Dnssd Discovered Service Information */
DnssdDiscoveredService *dnsservice_request;
DnsServiceBrowser *service_browser_request;
/* Completion callback */ /* Completion callback */
void (*complete)(DnsQuery* q); void (*complete)(DnsQuery* q);

View File

@ -1606,7 +1606,7 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
} }
int dns_scope_add_dnssd_services(DnsScope *scope) { int dns_scope_add_dnssd_services(DnsScope *scope) {
DnssdRegisteredService *service; DnssdService *service;
int r; int r;
assert(scope); assert(scope);
@ -1645,7 +1645,7 @@ int dns_scope_add_dnssd_services(DnsScope *scope) {
int dns_scope_remove_dnssd_services(DnsScope *scope) { int dns_scope_remove_dnssd_services(DnsScope *scope) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
DnssdRegisteredService *service; DnssdService *service;
int r; int r;
assert(scope); assert(scope);

View File

@ -11,7 +11,7 @@
#include "user-util.h" #include "user-util.h"
int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error) { int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error) {
DnssdRegisteredService *s = ASSERT_PTR(userdata); DnssdService *s = ASSERT_PTR(userdata);
Manager *m; Manager *m;
Link *l; Link *l;
int r; int r;
@ -69,7 +69,7 @@ int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_
static int dnssd_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { static int dnssd_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
_cleanup_free_ char *name = NULL; _cleanup_free_ char *name = NULL;
Manager *m = ASSERT_PTR(userdata); Manager *m = ASSERT_PTR(userdata);
DnssdRegisteredService *service; DnssdService *service;
int r; int r;
assert(bus); assert(bus);
@ -92,7 +92,7 @@ static int dnssd_object_find(sd_bus *bus, const char *path, const char *interfac
static int dnssd_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { static int dnssd_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
Manager *m = ASSERT_PTR(userdata); Manager *m = ASSERT_PTR(userdata);
DnssdRegisteredService *service; DnssdService *service;
unsigned c = 0; unsigned c = 0;
int r; int r;

View File

@ -18,8 +18,8 @@ struct ConfigPerfItem;
Service.Name, config_parse_dnssd_service_name, 0, 0 Service.Name, config_parse_dnssd_service_name, 0, 0
Service.Type, config_parse_dnssd_service_type, 0, 0 Service.Type, config_parse_dnssd_service_type, 0, 0
Service.SubType, config_parse_dnssd_service_subtype, 0, 0 Service.SubType, config_parse_dnssd_service_subtype, 0, 0
Service.Port, config_parse_ip_port, 0, offsetof(DnssdRegisteredService, port) Service.Port, config_parse_ip_port, 0, offsetof(DnssdService, port)
Service.Priority, config_parse_uint16, 0, offsetof(DnssdRegisteredService, priority) Service.Priority, config_parse_uint16, 0, offsetof(DnssdService, priority)
Service.Weight, config_parse_uint16, 0, offsetof(DnssdRegisteredService, weight) Service.Weight, config_parse_uint16, 0, offsetof(DnssdService, weight)
Service.TxtText, config_parse_dnssd_txt, DNS_TXT_ITEM_TEXT, 0 Service.TxtText, config_parse_dnssd_txt, DNS_TXT_ITEM_TEXT, 0
Service.TxtData, config_parse_dnssd_txt, DNS_TXT_ITEM_DATA, 0 Service.TxtData, config_parse_dnssd_txt, DNS_TXT_ITEM_DATA, 0

View File

@ -37,7 +37,7 @@ DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data) {
return dnssd_txtdata_free_all(next); return dnssd_txtdata_free_all(next);
} }
DnssdRegisteredService *dnssd_service_free(DnssdRegisteredService *service) { DnssdService *dnssd_service_free(DnssdService *service) {
if (!service) if (!service)
return NULL; return NULL;
@ -60,7 +60,7 @@ DnssdRegisteredService *dnssd_service_free(DnssdRegisteredService *service) {
} }
void dnssd_service_clear_on_reload(Hashmap *services) { void dnssd_service_clear_on_reload(Hashmap *services) {
DnssdRegisteredService *service; DnssdService *service;
HASHMAP_FOREACH(service, services) HASHMAP_FOREACH(service, services)
if (service->config_source == RESOLVE_CONFIG_SOURCE_FILE) { if (service->config_source == RESOLVE_CONFIG_SOURCE_FILE) {
@ -91,7 +91,7 @@ static int dnssd_id_from_path(const char *path, char **ret_id) {
} }
static int dnssd_service_load(Manager *manager, const char *path) { static int dnssd_service_load(Manager *manager, const char *path) {
_cleanup_(dnssd_service_freep) DnssdRegisteredService *service = NULL; _cleanup_(dnssd_service_freep) DnssdService *service = NULL;
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL; _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
_cleanup_free_ char *dropin_dirname = NULL; _cleanup_free_ char *dropin_dirname = NULL;
int r; int r;
@ -99,7 +99,7 @@ static int dnssd_service_load(Manager *manager, const char *path) {
assert(manager); assert(manager);
assert(path); assert(path);
service = new0(DnssdRegisteredService, 1); service = new0(DnssdService, 1);
if (!service) if (!service)
return log_oom(); return log_oom();
@ -172,7 +172,7 @@ static int specifier_dnssd_hostname(char specifier, const void *data, const char
return strdup_to(ret, m->llmnr_hostname); return strdup_to(ret, m->llmnr_hostname);
} }
int dnssd_render_instance_name(Manager *m, DnssdRegisteredService *s, char **ret) { int dnssd_render_instance_name(Manager *m, DnssdService *s, char **ret) {
static const Specifier specifier_table[] = { static const Specifier specifier_table[] = {
{ 'a', specifier_architecture, NULL }, { 'a', specifier_architecture, NULL },
{ 'b', specifier_boot_id, NULL }, { 'b', specifier_boot_id, NULL },
@ -229,7 +229,7 @@ int dnssd_load(Manager *manager) {
return 0; return 0;
} }
int dnssd_update_rrs(DnssdRegisteredService *s) { int dnssd_update_rrs(DnssdService *s) {
_cleanup_free_ char *n = NULL, *service_name = NULL, *full_name = NULL, *sub_name = NULL, *selective_name = NULL; _cleanup_free_ char *n = NULL, *service_name = NULL, *full_name = NULL, *sub_name = NULL, *selective_name = NULL;
int r; int r;
@ -370,7 +370,7 @@ int dnssd_txt_item_new_from_data(const char *key, const void *data, const size_t
} }
int dnssd_signal_conflict(Manager *manager, const char *name) { int dnssd_signal_conflict(Manager *manager, const char *name) {
DnssdRegisteredService *s; DnssdService *s;
int r; int r;
if (sd_bus_is_ready(manager->bus) <= 0) if (sd_bus_is_ready(manager->bus) <= 0)
@ -428,7 +428,7 @@ int config_parse_dnssd_service_name(
{ 'W', specifier_os_variant_id, NULL }, { 'W', specifier_os_variant_id, NULL },
{} {}
}; };
DnssdRegisteredService *s = ASSERT_PTR(userdata); DnssdService *s = ASSERT_PTR(userdata);
_cleanup_free_ char *name = NULL; _cleanup_free_ char *name = NULL;
int r; int r;
@ -470,7 +470,7 @@ int config_parse_dnssd_service_type(
void *data, void *data,
void *userdata) { void *userdata) {
DnssdRegisteredService *s = ASSERT_PTR(userdata); DnssdService *s = ASSERT_PTR(userdata);
int r; int r;
assert(filename); assert(filename);
@ -506,7 +506,7 @@ int config_parse_dnssd_service_subtype(
void *data, void *data,
void *userdata) { void *userdata) {
DnssdRegisteredService *s = ASSERT_PTR(userdata); DnssdService *s = ASSERT_PTR(userdata);
assert(filename); assert(filename);
assert(lvalue); assert(lvalue);
@ -538,7 +538,7 @@ int config_parse_dnssd_txt(
void *userdata) { void *userdata) {
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL; _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
DnssdRegisteredService *s = ASSERT_PTR(userdata); DnssdService *s = ASSERT_PTR(userdata);
DnsTxtItem *last = NULL; DnsTxtItem *last = NULL;
assert(filename); assert(filename);

View File

@ -5,7 +5,7 @@
#include "list.h" #include "list.h"
#include "resolved-conf.h" #include "resolved-conf.h"
typedef struct DnssdRegisteredService DnssdRegisteredService; typedef struct DnssdService DnssdService;
typedef struct DnssdTxtData DnssdTxtData; typedef struct DnssdTxtData DnssdTxtData;
typedef struct Manager Manager; typedef struct Manager Manager;
@ -25,7 +25,7 @@ struct DnssdTxtData {
LIST_FIELDS(DnssdTxtData, items); LIST_FIELDS(DnssdTxtData, items);
}; };
struct DnssdRegisteredService { struct DnssdService {
char *path; char *path;
char *id; char *id;
char *name_template; char *name_template;
@ -52,19 +52,19 @@ struct DnssdRegisteredService {
uid_t originator; uid_t originator;
}; };
DnssdRegisteredService *dnssd_service_free(DnssdRegisteredService *service); DnssdService *dnssd_service_free(DnssdService *service);
DnssdTxtData *dnssd_txtdata_free(DnssdTxtData *txt_data); DnssdTxtData *dnssd_txtdata_free(DnssdTxtData *txt_data);
DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data); DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data);
void dnssd_service_clear_on_reload(Hashmap *services); void dnssd_service_clear_on_reload(Hashmap *services);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdRegisteredService*, dnssd_service_free); DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdService*, dnssd_service_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdTxtData*, dnssd_txtdata_free); DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdTxtData*, dnssd_txtdata_free);
int dnssd_render_instance_name(Manager *m, DnssdRegisteredService *s, char **ret); int dnssd_render_instance_name(Manager *m, DnssdService *s, char **ret);
int dnssd_load(Manager *manager); int dnssd_load(Manager *manager);
int dnssd_txt_item_new_from_string(const char *key, const char *value, DnsTxtItem **ret_item); int dnssd_txt_item_new_from_string(const char *key, const char *value, DnsTxtItem **ret_item);
int dnssd_txt_item_new_from_data(const char *key, const void *value, const size_t size, DnsTxtItem **ret_item); int dnssd_txt_item_new_from_data(const char *key, const void *value, const size_t size, DnsTxtItem **ret_item);
int dnssd_update_rrs(DnssdRegisteredService *s); int dnssd_update_rrs(DnssdService *s);
int dnssd_signal_conflict(Manager *manager, const char *name); int dnssd_signal_conflict(Manager *manager, const char *name);
const struct ConfigPerfItem* resolved_dnssd_gperf_lookup(const char *key, GPERF_LEN_TYPE length); const struct ConfigPerfItem* resolved_dnssd_gperf_lookup(const char *key, GPERF_LEN_TYPE length);

View File

@ -167,7 +167,7 @@ void link_allocate_scopes(Link *l) {
r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET); r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
if (r < 0) if (r < 0)
log_link_warning_errno(l, r, "Failed to allocate mDNS IPv4 scope, ignoring: %m"); log_link_warning_errno(l, r, "Failed to allocate mDNS IPv4 scope, ignoring: %m");
dns_browse_services_restart(l->manager); dns_service_browser_reset(l->manager);
} }
} else } else
l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope); l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope);
@ -178,7 +178,7 @@ void link_allocate_scopes(Link *l) {
r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6); r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
if (r < 0) if (r < 0)
log_link_warning_errno(l, r, "Failed to allocate mDNS IPv6 scope, ignoring: %m"); log_link_warning_errno(l, r, "Failed to allocate mDNS IPv6 scope, ignoring: %m");
dns_browse_services_restart(l->manager); dns_service_browser_reset(l->manager);
} }
} else } else
l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope); l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope);

View File

@ -768,7 +768,7 @@ int manager_start(Manager *m) {
Manager *manager_free(Manager *m) { Manager *manager_free(Manager *m) {
Link *l; Link *l;
DnssdRegisteredService *s; DnssdService *s;
DnsServiceBrowser *sb; DnsServiceBrowser *sb;
if (!m) if (!m)
@ -1350,7 +1350,7 @@ int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_a
void manager_refresh_rrs(Manager *m) { void manager_refresh_rrs(Manager *m) {
Link *l; Link *l;
DnssdRegisteredService *s; DnssdService *s;
assert(m); assert(m);
@ -1711,7 +1711,7 @@ void manager_flush_caches(Manager *m, int log_level) {
dns_cache_flush(&scope->cache); dns_cache_flush(&scope->cache);
dns_browse_services_purge(m, AF_UNSPEC); /* Clear records of DNS service browse subscriber, since caches are flushed */ dns_browse_services_purge(m, AF_UNSPEC); /* Clear records of DNS service browse subscriber, since caches are flushed */
dns_browse_services_restart(m); dns_service_browser_reset(m);
log_full(log_level, "Flushed all caches."); log_full(log_level, "Flushed all caches.");
} }
@ -1776,7 +1776,7 @@ void manager_cleanup_saved_user(Manager *m) {
} }
bool manager_next_dnssd_names(Manager *m) { bool manager_next_dnssd_names(Manager *m) {
DnssdRegisteredService *s; DnssdService *s;
bool tried = false; bool tried = false;
int r; int r;

View File

@ -361,19 +361,19 @@ static int mdns_goodbye_callback(sd_event_source *s, uint64_t usec, void *userda
r = mdns_notify_browsers_goodbye(scope); r = mdns_notify_browsers_goodbye(scope);
if (r < 0) if (r < 0)
log_warning_errno(r, "mDNS: Failed to notify service subscribers of goodbyes, ignoring: %m"); log_error_errno(r, "mDNS: Failed to notify service subscribers of goodbyes, %m");
if (dns_cache_expiry_in_one_second(&scope->cache, usec)) { if (dns_cache_expiry_in_one_second(&scope->cache, usec)) {
r = sd_event_add_time_relative( r = sd_event_add_time_relative(
scope->manager->event, scope->manager->event,
&scope->mdns_goodbye_event_source, &scope->mdns_goodbye_event_source,
CLOCK_BOOTTIME, CLOCK_BOOTTIME,
USEC_PER_SEC, USEC_PER_SEC,
/* accuracy= */ 0, 0,
mdns_goodbye_callback, mdns_goodbye_callback,
scope); scope);
if (r < 0) if (r < 0)
return log_warning_errno(r, "mDNS: Failed to re-schedule goodbye callback, ignoring: %m"); return log_error_errno(r, "mDNS: Failed to re-schedule goodbye callback: %m");
} }
return 0; return 0;
@ -451,7 +451,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
&scope->mdns_goodbye_event_source, &scope->mdns_goodbye_event_source,
CLOCK_BOOTTIME, CLOCK_BOOTTIME,
USEC_PER_SEC, USEC_PER_SEC,
/* accuracy= */ 0, 0,
mdns_goodbye_callback, mdns_goodbye_callback,
scope); scope);
if (r < 0) if (r < 0)
@ -461,19 +461,19 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
} }
dns_cache_put( dns_cache_put(
&scope->cache, &scope->cache,
scope->manager->enable_cache, scope->manager->enable_cache,
DNS_PROTOCOL_MDNS, DNS_PROTOCOL_MDNS,
/* key= */ NULL, NULL,
DNS_PACKET_RCODE(p), DNS_PACKET_RCODE(p),
p->answer, p->answer,
/* full_packet= */ NULL, NULL,
/* query_flags= */ false, false,
_DNSSEC_RESULT_INVALID, _DNSSEC_RESULT_INVALID,
/* nsec_ttl= */ UINT32_MAX, UINT32_MAX,
p->family, p->family,
&p->sender, &p->sender,
scope->manager->stale_retention_usec); scope->manager->stale_retention_usec);
for (bool match = true; match;) { for (bool match = true; match;) {
match = false; match = false;
@ -500,7 +500,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
} }
} }
/* Check if incoming packet key matches with active browse clients. If yes, update the same */ /* Check incoming packet key matches with active clients if yes update the same */
if (unsolicited_packet) if (unsolicited_packet)
mdns_notify_browsers_unsolicited_updates(m, p->answer, p->family); mdns_notify_browsers_unsolicited_updates(m, p->answer, p->family);

View File

@ -31,18 +31,26 @@ typedef struct LookupParametersResolveService {
uint64_t flags; uint64_t flags;
} LookupParametersResolveService; } LookupParametersResolveService;
typedef struct LookupParametersBrowse { typedef struct LookupParametersMdnsBrowse {
const char *domain; char *domainName;
const char *type; char *name;
char *type;
int ifindex; int ifindex;
uint64_t flags; uint64_t flags;
} LookupParametersBrowse; } LookupParametersMdnsBrowse;
static void lookup_parameters_destroy(LookupParameters *p) { static void lookup_parameters_destroy(LookupParameters *p) {
assert(p); assert(p);
free(p->name); free(p->name);
} }
static void lookup_parameters_mdns_destroy(LookupParametersMdnsBrowse *p) {
assert(p);
free(p->domainName);
free(p->name);
free(p->type);
}
static int reply_query_state(DnsQuery *q) { static int reply_query_state(DnsQuery *q) {
assert(q); assert(q);
@ -126,7 +134,7 @@ static void vl_on_disconnect(sd_varlink_server *s, sd_varlink *link, void *userd
return; return;
DnsServiceBrowser *sb = hashmap_remove(m->dns_service_browsers, link); DnsServiceBrowser *sb = hashmap_remove(m->dns_service_browsers, link);
dns_service_browser_unref(sb); dns_service_browser_free(sb);
q = sd_varlink_get_userdata(link); q = sd_varlink_get_userdata(link);
if (!q) if (!q)
@ -1225,16 +1233,17 @@ static int verify_polkit(sd_varlink *link, sd_json_variant *parameters, const ch
&m->polkit_registry); &m->polkit_registry);
} }
static int vl_method_browse_services(sd_varlink* link, sd_json_variant* parameters, sd_varlink_method_flags_t flags, void* userdata) { static int vl_method_start_browse(sd_varlink* link, sd_json_variant* parameters, sd_varlink_method_flags_t flags, void* userdata) {
static const sd_json_dispatch_field dispatch_table[] = { static const sd_json_dispatch_field dispatch_table[] = {
{ "domain", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParametersBrowse, domain), 0 }, { "domainName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(LookupParametersMdnsBrowse, domainName), SD_JSON_MANDATORY },
{ "type", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParametersBrowse, type), 0 }, { "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(LookupParametersMdnsBrowse, name), 0 },
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(LookupParametersBrowse, ifindex), 0 }, { "type", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(LookupParametersMdnsBrowse, type), 0 },
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LookupParametersBrowse, flags), 0 }, { "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(LookupParametersMdnsBrowse, ifindex), SD_JSON_MANDATORY },
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LookupParametersMdnsBrowse, flags), SD_JSON_MANDATORY },
{} {}
}; };
LookupParametersBrowse p = {}; _cleanup_(lookup_parameters_mdns_destroy) LookupParametersMdnsBrowse p = {};
Manager *m; Manager *m;
int r = 0; int r = 0;
@ -1249,12 +1258,12 @@ static int vl_method_browse_services(sd_varlink* link, sd_json_variant* paramete
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p); r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed vl_method_browse_services json dispatch: %m"); return log_error_errno(r, "vl_method_start_browse json_dispatch fail: %m");
if (!validate_and_mangle_flags(NULL, &p.flags, 0)) if (!validate_and_mangle_flags(NULL, &p.flags, 0))
return sd_varlink_error_invalid_parameter_name(link, "flags"); return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
r = dns_subscribe_browse_service(m, link, p.domain, p.type, p.ifindex, p.flags); r = dns_subscribe_browse_service(m, link, p.domainName, p.name, p.type, p.ifindex, p.flags);
if (r < 0) if (r < 0)
return sd_varlink_error_errno(link, r); return sd_varlink_error_errno(link, r);
@ -1475,7 +1484,7 @@ static int varlink_main_server_init(Manager *m) {
"io.systemd.Resolve.ResolveAddress", vl_method_resolve_address, "io.systemd.Resolve.ResolveAddress", vl_method_resolve_address,
"io.systemd.Resolve.ResolveService", vl_method_resolve_service, "io.systemd.Resolve.ResolveService", vl_method_resolve_service,
"io.systemd.Resolve.ResolveRecord", vl_method_resolve_record, "io.systemd.Resolve.ResolveRecord", vl_method_resolve_record,
"io.systemd.Resolve.BrowseServices", vl_method_browse_services); "io.systemd.Resolve.StartBrowse", vl_method_start_browse);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to register varlink methods: %m"); return log_error_errno(r, "Failed to register varlink methods: %m");

View File

@ -24,7 +24,8 @@ int acquire_fido2_key(
const char *key_file, const char *key_file,
size_t key_file_size, size_t key_file_size,
uint64_t key_file_offset, uint64_t key_file_offset,
const struct iovec *key_data, const void *key_data,
size_t key_data_size,
usec_t until, usec_t until,
Fido2EnrollFlags required, Fido2EnrollFlags required,
const char *askpw_credential, const char *askpw_credential,
@ -44,10 +45,10 @@ int acquire_fido2_key(
"Local verification is required to unlock this volume, but the 'headless' parameter was set."); "Local verification is required to unlock this volume, but the 'headless' parameter was set.");
assert(cid); assert(cid);
assert(key_file || iovec_is_set(key_data)); assert(key_file || key_data);
if (iovec_is_set(key_data)) if (key_data)
salt = *key_data; salt = IOVEC_MAKE(key_data, key_data_size);
else { else {
if (key_file_size > 0) if (key_file_size > 0)
log_debug("Ignoring 'keyfile-size=' option for a FIDO2 salt file."); log_debug("Ignoring 'keyfile-size=' option for a FIDO2 salt file.");
@ -251,7 +252,7 @@ int acquire_fido2_key_auto(
/* key_file= */ NULL, /* salt is read from LUKS header instead of key_file */ /* key_file= */ NULL, /* salt is read from LUKS header instead of key_file */
/* key_file_size= */ 0, /* key_file_size= */ 0,
/* key_file_offset= */ 0, /* key_file_offset= */ 0,
&IOVEC_MAKE(salt, salt_size), salt, salt_size,
until, until,
required, required,
"cryptsetup.fido2-pin", "cryptsetup.fido2-pin",

View File

@ -20,7 +20,8 @@ int acquire_fido2_key(
const char *key_file, const char *key_file,
size_t key_file_size, size_t key_file_size,
uint64_t key_file_offset, uint64_t key_file_offset,
const struct iovec *key_data, const void *key_data,
size_t key_data_size,
usec_t until, usec_t until,
Fido2EnrollFlags required, Fido2EnrollFlags required,
const char *askpw_credential, const char *askpw_credential,
@ -51,7 +52,8 @@ static inline int acquire_fido2_key(
const char *key_file, const char *key_file,
size_t key_file_size, size_t key_file_size,
uint64_t key_file_offset, uint64_t key_file_offset,
const struct iovec *key_data, const void *key_data,
size_t key_data_size,
usec_t until, usec_t until,
Fido2EnrollFlags required, Fido2EnrollFlags required,
const char *askpw_credential, const char *askpw_credential,

View File

@ -102,26 +102,14 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, 0)); SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, 0));
static SD_VARLINK_DEFINE_ENUM_TYPE(
BrowseServiceUpdateFlag,
SD_VARLINK_FIELD_COMMENT("Indicates that the service was added."),
SD_VARLINK_DEFINE_ENUM_VALUE(added),
SD_VARLINK_FIELD_COMMENT("Indicates that the service was removed."),
SD_VARLINK_DEFINE_ENUM_VALUE(removed));
static SD_VARLINK_DEFINE_STRUCT_TYPE( static SD_VARLINK_DEFINE_STRUCT_TYPE(
ServiceData, ServiceData,
SD_VARLINK_DEFINE_FIELD_BY_TYPE(updateFlag, BrowseServiceUpdateFlag, 0), SD_VARLINK_DEFINE_FIELD(add_flag, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("The address family of the service, one of AF_INET or AF_INET6."),
SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, 0), SD_VARLINK_DEFINE_FIELD(family, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("The name of the service, e.g., 'My Service'. May be null if not specified."),
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The type of service, e.g., '_http._tcp'."),
SD_VARLINK_DEFINE_FIELD(type, SD_VARLINK_STRING, 0), SD_VARLINK_DEFINE_FIELD(type, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("The domain in which the service resides, e.g., 'local'."),
SD_VARLINK_DEFINE_FIELD(domain, SD_VARLINK_STRING, 0), SD_VARLINK_DEFINE_FIELD(domain, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("The Linux interface index for the network interface associated with this service."), SD_VARLINK_DEFINE_FIELD(interface, SD_VARLINK_INT, 0));
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, 0));
static SD_VARLINK_DEFINE_METHOD( static SD_VARLINK_DEFINE_METHOD(
ResolveAddress, ResolveAddress,
@ -180,19 +168,14 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(rrs, ResolvedRecord, SD_VARLINK_ARRAY), SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(rrs, ResolvedRecord, SD_VARLINK_ARRAY),
SD_VARLINK_DEFINE_OUTPUT(flags, SD_VARLINK_INT, 0)); SD_VARLINK_DEFINE_OUTPUT(flags, SD_VARLINK_INT, 0));
static SD_VARLINK_DEFINE_METHOD_FULL( static SD_VARLINK_DEFINE_METHOD(
BrowseServices, StartBrowse,
SD_VARLINK_SUPPORTS_MORE, SD_VARLINK_DEFINE_INPUT(domainName, SD_VARLINK_STRING, 0),
SD_VARLINK_FIELD_COMMENT("The domain to browse for services. If null, the default browsing domain local is used."), SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_DEFINE_INPUT(domain, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The service type to browse for (e.g., '_http._tcp')."),
SD_VARLINK_DEFINE_INPUT(type, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_INPUT(type, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The Linux interface index for the network interface to search on."), SD_VARLINK_DEFINE_INPUT(ifindex, SD_VARLINK_INT, 0),
SD_VARLINK_DEFINE_INPUT(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_INPUT(flags, SD_VARLINK_INT, 0),
SD_VARLINK_FIELD_COMMENT("Various browsing flags to modify the operation."), SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(browser_service_data, ServiceData, SD_VARLINK_ARRAY));
SD_VARLINK_DEFINE_INPUT(flags, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("An array of service data containing information about discovered services."),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(browserServiceData, ServiceData, SD_VARLINK_ARRAY));
static SD_VARLINK_DEFINE_ERROR(NoNameServers); static SD_VARLINK_DEFINE_ERROR(NoNameServers);
static SD_VARLINK_DEFINE_ERROR(NoSuchResourceRecord); static SD_VARLINK_DEFINE_ERROR(NoSuchResourceRecord);
@ -233,8 +216,8 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_method_ResolveService, &vl_method_ResolveService,
SD_VARLINK_SYMBOL_COMMENT("Resolves a domain name to one or more DNS resource records."), SD_VARLINK_SYMBOL_COMMENT("Resolves a domain name to one or more DNS resource records."),
&vl_method_ResolveRecord, &vl_method_ResolveRecord,
SD_VARLINK_SYMBOL_COMMENT("Starts browsing for DNS-SD services of specified type."), SD_VARLINK_SYMBOL_COMMENT("Starts browsing for mDNS services of specified type."),
&vl_method_BrowseServices, &vl_method_StartBrowse,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved address."), SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved address."),
&vl_type_ResolvedAddress, &vl_type_ResolvedAddress,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved host name."), SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved host name."),
@ -249,9 +232,6 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_type_ResourceRecord, &vl_type_ResourceRecord,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates information about a resolved DNS resource record "), SD_VARLINK_SYMBOL_COMMENT("Encapsulates information about a resolved DNS resource record "),
&vl_type_ResolvedRecord, &vl_type_ResolvedRecord,
SD_VARLINK_SYMBOL_COMMENT("Describes the update flag for browsing services, indicating whether a service was added or removed during browsing."),
&vl_type_BrowseServiceUpdateFlag,
SD_VARLINK_SYMBOL_COMMENT("Encapsulates the service data obtained from browsing."),
&vl_type_ServiceData, &vl_type_ServiceData,
&vl_error_NoNameServers, &vl_error_NoNameServers,
&vl_error_NoSuchResourceRecord, &vl_error_NoSuchResourceRecord,

View File

@ -1414,7 +1414,7 @@ static int verb_enable(int argc, char **argv, void *userdata) {
"SetFeatureEnabled", "SetFeatureEnabled",
&error, &error,
/* reply= */ NULL, /* reply= */ NULL,
"sit", "sbt",
*feature, *feature,
(int) enable, (int) enable,
UINT64_C(0)); UINT64_C(0));

View File

@ -80,6 +80,7 @@ show_journal = True # When true, show journal on stopping networkd.
active_units = [] active_units = []
protected_links = { protected_links = {
'br0',
'erspan0', 'erspan0',
'gre0', 'gre0',
'gretap0', 'gretap0',

View File

@ -114,10 +114,10 @@ run_and_check_services() {
error_file="$(mktemp)" error_file="$(mktemp)"
tmp_file="$(mktemp)" tmp_file="$(mktemp)"
service_type="_testService$service_id._udp" service_type="_testService$service_id._udp"
parameters="{ \"domain\": \"$service_type.local\", \"type\": \"\", \"ifindex\": ${BRIDGE_INDEX:?}, \"flags\": 16785432 }" parameters="{ \"domainName\": \"$service_type.local\", \"name\": \"\", \"type\": \"\", \"ifindex\": ${BRIDGE_INDEX:?}, \"flags\": 16785432 }"
systemd-run --unit="$unit_name" --service-type=exec -p StandardOutput="file:$out_file" -p StandardError="file:$error_file" \ systemd-run --unit="$unit_name" --service-type=exec -p StandardOutput="file:$out_file" -p StandardError="file:$error_file" \
varlinkctl call --more /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.BrowseServices "$parameters" varlinkctl call --more /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.StartBrowse "$parameters"
# shellcheck disable=SC2064 # shellcheck disable=SC2064
# Note: unregister the trap once it's fired, otherwise it'll get propagated to functions that call this # Note: unregister the trap once it's fired, otherwise it'll get propagated to functions that call this
@ -131,7 +131,7 @@ run_and_check_services() {
# { # {
# "browser_service_data": [ # "browser_service_data": [
# { # {
# "updateFlag": true, # "add_flag": true,
# "family": 10, # "family": 10,
# "name": "Test Service 13 on test-mdns-1", # "name": "Test Service 13 on test-mdns-1",
# "type": "_testService0._udp", # "type": "_testService0._udp",
@ -144,7 +144,7 @@ run_and_check_services() {
if [[ -s "$out_file" ]]; then if [[ -s "$out_file" ]]; then
# Extract the service name from each valid record... # Extract the service name from each valid record...
# jq --slurp --raw-output \ # jq --slurp --raw-output \
# ".[].browser_service_data[] | select(.updateFlag == true and .type == \"$service_type\" and .family == 10).name" "$out_file" | sort | tee "$tmp_file" # ".[].browser_service_data[] | select(.add_flag == true and .type == \"$service_type\" and .family == 10).name" "$out_file" | sort | tee "$tmp_file"
grep -o '"name":"[^"]*"' "$out_file" | sed 's/"name":"//;s/"//g' | sort | tee "$tmp_file" grep -o '"name":"[^"]*"' "$out_file" | sed 's/"name":"//;s/"//g' | sort | tee "$tmp_file"
# ...and compare them with what we expect # ...and compare them with what we expect
if "$check_func" "$service_id" "$tmp_file"; then if "$check_func" "$service_id" "$tmp_file"; then