Compare commits
11 Commits
cf72f7f116
...
a15e7eb9e0
Author | SHA1 | Date |
---|---|---|
Vishal Chillara | a15e7eb9e0 | |
Winterhuman | 5bed97dd57 | |
Luca Boccassi | c4d7a13c06 | |
Abderrahim Kitouni | 0ae6f4843e | |
Frantisek Sumsal | c922c19d0e | |
Vishal Chillara Srinivas | 49c4cc2b8f | |
Vishal Chillara Srinivas | 28efd46614 | |
Vishal Chillara Srinivas | dfcc54ac15 | |
Yu Watanabe | 1ea1a79aa1 | |
Luca Boccassi | 7a9d0abe4d | |
Yu Watanabe | 6046cc3660 |
|
@ -684,6 +684,15 @@ fi</programlisting>
|
|||
<citerefentry><refentrytitle>file-hierarchy</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
||||
</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>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
|
|
|
@ -302,7 +302,7 @@
|
|||
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
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details: currently, the <literal>full</literal> or <literal>struct</literal> values are not
|
||||
details: currently, the <literal>full</literal> or <literal>strict</literal> values are not
|
||||
supported.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "iovec-util.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "parse-util.h"
|
||||
|
@ -31,8 +32,7 @@ int decrypt_pkcs11_key(
|
|||
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data, /* … or key_data and key_data_size (for literal keys) */
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data, /* … or literal keys via key_data */
|
||||
usec_t until,
|
||||
AskPasswordFlags askpw_flags,
|
||||
void **ret_decrypted_key,
|
||||
|
@ -47,15 +47,15 @@ int decrypt_pkcs11_key(
|
|||
|
||||
assert(friendly_name);
|
||||
assert(pkcs11_uri);
|
||||
assert(key_file || key_data);
|
||||
assert(key_file || iovec_is_set(key_data));
|
||||
assert(ret_decrypted_key);
|
||||
assert(ret_decrypted_key_size);
|
||||
|
||||
/* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
|
||||
|
||||
if (key_data) {
|
||||
data.encrypted_key = (void*) key_data;
|
||||
data.encrypted_key_size = key_data_size;
|
||||
if (iovec_is_set(key_data)) {
|
||||
data.encrypted_key = (void*) key_data->iov_base;
|
||||
data.encrypted_key_size = key_data->iov_len;
|
||||
|
||||
data.free_encrypted_key = false;
|
||||
} else {
|
||||
|
|
|
@ -16,8 +16,7 @@ int decrypt_pkcs11_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
AskPasswordFlags askpw_flags,
|
||||
void **ret_decrypted_key,
|
||||
|
@ -39,8 +38,7 @@ static inline int decrypt_pkcs11_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
AskPasswordFlags askpw_flags,
|
||||
void **ret_decrypted_key,
|
||||
|
|
|
@ -1471,8 +1471,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||
struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *key_file,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
uint32_t flags,
|
||||
bool pass_volume_key) {
|
||||
|
@ -1489,7 +1488,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||
assert(name);
|
||||
assert(arg_fido2_device || arg_fido2_device_auto);
|
||||
|
||||
if (arg_fido2_cid && !key_file && !key_data)
|
||||
if (arg_fido2_cid && !key_file && !iovec_is_set(key_data))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"FIDO2 mode with manual parameters selected, but no keyfile specified, refusing.");
|
||||
|
||||
|
@ -1513,7 +1512,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||
arg_fido2_rp_id,
|
||||
arg_fido2_cid, arg_fido2_cid_size,
|
||||
key_file, arg_keyfile_size, arg_keyfile_offset,
|
||||
key_data, key_data_size,
|
||||
key_data,
|
||||
until,
|
||||
arg_fido2_manual_flags,
|
||||
"cryptsetup.fido2-pin",
|
||||
|
@ -1623,8 +1622,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||
struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *key_file,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
uint32_t flags,
|
||||
bool pass_volume_key) {
|
||||
|
@ -1635,6 +1633,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
_cleanup_free_ void *discovered_key = NULL;
|
||||
struct iovec discovered_key_data = {};
|
||||
int keyslot = arg_key_slot, r;
|
||||
const char *uri = NULL;
|
||||
bool use_libcryptsetup_plugin = use_token_plugins();
|
||||
|
@ -1653,13 +1652,13 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||
return r;
|
||||
|
||||
uri = discovered_uri;
|
||||
key_data = discovered_key;
|
||||
key_data_size = discovered_key_size;
|
||||
discovered_key_data = IOVEC_MAKE(discovered_key, discovered_key_size);
|
||||
key_data = &discovered_key_data;
|
||||
}
|
||||
} else {
|
||||
uri = arg_pkcs11_uri;
|
||||
|
||||
if (!key_file && !key_data)
|
||||
if (!key_file && !iovec_is_set(key_data))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
|
||||
}
|
||||
|
||||
|
@ -1682,7 +1681,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||
friendly,
|
||||
uri,
|
||||
key_file, arg_keyfile_size, arg_keyfile_offset,
|
||||
key_data, key_data_size,
|
||||
key_data,
|
||||
until,
|
||||
arg_ask_password_flags,
|
||||
&decrypted_key, &decrypted_key_size);
|
||||
|
@ -2231,9 +2230,9 @@ static int attach_luks_or_plain_or_bitlk(
|
|||
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);
|
||||
if (token_type == TOKEN_FIDO2)
|
||||
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);
|
||||
return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data, until, flags, pass_volume_key);
|
||||
if (token_type == TOKEN_PKCS11)
|
||||
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);
|
||||
return attach_luks_or_plain_or_bitlk_by_pkcs11(cd, name, key_file, key_data, until, flags, pass_volume_key);
|
||||
if (key_data)
|
||||
return attach_luks_or_plain_or_bitlk_by_key_data(cd, name, key_data, flags, pass_volume_key);
|
||||
if (key_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) {
|
||||
DnssdService *s = ASSERT_PTR(userdata);
|
||||
DnssdRegisteredService *s = ASSERT_PTR(userdata);
|
||||
|
||||
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) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
_cleanup_(dnssd_service_freep) DnssdService *service = NULL;
|
||||
_cleanup_(dnssd_service_freep) DnssdRegisteredService *service = NULL;
|
||||
_cleanup_(sd_bus_track_unrefp) sd_bus_track *bus_track = NULL;
|
||||
const char *id, *name_template, *type;
|
||||
_cleanup_free_ char *path = NULL;
|
||||
DnssdService *s = NULL;
|
||||
DnssdRegisteredService *s = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
uid_t euid;
|
||||
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)
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for MulticastDNS is disabled");
|
||||
|
||||
service = new0(DnssdService, 1);
|
||||
service = new0(DnssdRegisteredService, 1);
|
||||
if (!service)
|
||||
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) {
|
||||
_cleanup_free_ char *name = NULL;
|
||||
DnssdService *s = NULL;
|
||||
DnssdRegisteredService *s = NULL;
|
||||
const char *path;
|
||||
int r;
|
||||
|
||||
|
|
|
@ -1,76 +1,81 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "resolved-dns-browse-services.h"
|
||||
#include "af-list.h"
|
||||
#include "event-util.h"
|
||||
#include "json-util.h"
|
||||
#include "random-util.h"
|
||||
#include "resolved-dns-browse-services.h"
|
||||
#include "resolved-dns-cache.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
|
||||
* 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) {
|
||||
* 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, 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);
|
||||
}
|
||||
|
||||
/* RFC 6762 section 5.2 - A random variation of 2% of the record TTL should
|
||||
* be added to maintenance queries. */
|
||||
static usec_t mdns_maintenance_jitter(uint32_t ttl) {
|
||||
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;
|
||||
return random_u64_range(2 * ttl * USEC_PER_SEC / 100);
|
||||
}
|
||||
|
||||
static void mdns_maintenance_query_complete(DnsQuery *q) {
|
||||
_cleanup_(dns_service_browser_unrefp) DnsServiceBrowser *sb = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *query = q;
|
||||
DnsService *service = NULL;
|
||||
DnssdDiscoveredService *service = NULL;
|
||||
int r;
|
||||
|
||||
assert(query);
|
||||
assert(query->manager);
|
||||
|
||||
sb = dns_service_browser_ref(hashmap_get(query->manager->dns_service_browsers, query->varlink_request));
|
||||
if (query->state != DNS_TRANSACTION_SUCCESS)
|
||||
return;
|
||||
|
||||
service = dns_service_ref(query->dnsservice_request);
|
||||
|
||||
if (!service)
|
||||
return;
|
||||
|
||||
sb = dns_service_browser_ref(service->service_browser);
|
||||
|
||||
if (!sb)
|
||||
return;
|
||||
|
||||
if (query->state != DNS_TRANSACTION_SUCCESS) {
|
||||
r = 0;
|
||||
goto finish;
|
||||
r = dns_answer_match_key(query->answer, sb->key, NULL);
|
||||
if (r <= 0) {
|
||||
log_error_errno(r, "mDNS answer does not match service browser key: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
r = dns_answer_match_key(query->answer, sb->key, NULL);
|
||||
if (r <= 0)
|
||||
goto finish;
|
||||
|
||||
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;
|
||||
r = mdns_browser_revisit_cache(sb, query->answer_family);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to mDNS revisit cache for family %d: %m", query->answer_family);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int mdns_maintenance_query(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
DnsService *service = NULL;
|
||||
DnssdDiscoveredService *service = NULL;
|
||||
_cleanup_(dns_query_freep) DnsQuery *q = NULL;
|
||||
int r;
|
||||
|
||||
|
@ -78,108 +83,132 @@ static int mdns_maintenance_query(sd_event_source *s, uint64_t usec, void *userd
|
|||
|
||||
service = userdata;
|
||||
|
||||
if (service->rr_ttl_state++ == MDNS_TTL_100_PERCENT)
|
||||
return mdns_browser_lookup_cache(service->sb, service->family);
|
||||
/* Check if the TTL state has reached the maximum value, then revisit
|
||||
* cache */
|
||||
if (service->rr_ttl_state++ == _DNS_RECORD_TTL_STATE_MAX)
|
||||
return mdns_browser_revisit_cache(service->service_browser, service->family);
|
||||
|
||||
r = dns_query_new(service->sb->m, &q, service->sb->question_utf8, service->sb->question_idna, NULL, service->sb->ifindex, service->sb->flags);
|
||||
/* Create a new DNS query */
|
||||
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)
|
||||
goto finish;
|
||||
return log_error_errno(r, "Failed to create mDNS query for maintenance: %m");
|
||||
|
||||
q->complete = mdns_maintenance_query_complete;
|
||||
q->varlink_request = sd_varlink_ref(service->sb->link);
|
||||
service->query = TAKE_PTR(q);
|
||||
q->varlink_request = sd_varlink_ref(service->service_browser->link);
|
||||
q->dnsservice_request = dns_service_ref(service);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Schedule next maintenance query for service */
|
||||
r = event_reset_time(
|
||||
service->sb->m->event, &service->schedule_event,
|
||||
CLOCK_BOOTTIME, next_time, 0, mdns_maintenance_query,
|
||||
service, 0, "mdns-next-query-schedule", true);
|
||||
service->service_browser->manager->event,
|
||||
&service->schedule_event,
|
||||
CLOCK_BOOTTIME,
|
||||
next_time,
|
||||
/* accuracy= */ 0,
|
||||
mdns_maintenance_query,
|
||||
service,
|
||||
/* priority= */ 0,
|
||||
"mdns-next-query-schedule",
|
||||
/* force_reset= */ true);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
return log_error_errno(r, "Failed to schedule next mDNS maintenance query: %m");
|
||||
|
||||
r = dns_query_go(service->query);
|
||||
/* Perform the query */
|
||||
r = dns_query_go(q);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
return log_error_errno(r, "Failed to send mDNS maintenance query: %m");
|
||||
|
||||
TAKE_PTR(q);
|
||||
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) {
|
||||
_cleanup_(dns_service_unrefp) DnsService *s = NULL;
|
||||
_cleanup_(dns_service_unrefp) DnssdDiscoveredService *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(sb);
|
||||
assert(rr);
|
||||
|
||||
s = new(DnsService, 1);
|
||||
if (!s)
|
||||
return log_oom();
|
||||
s = new (DnssdDiscoveredService, 1);
|
||||
if (!s) {
|
||||
log_oom();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
usec_t usec = now(CLOCK_BOOTTIME);
|
||||
|
||||
*s = (DnsService) {
|
||||
*s = (DnssdDiscoveredService) {
|
||||
.n_ref = 1,
|
||||
.sb = dns_service_browser_ref(sb),
|
||||
.service_browser = sb,
|
||||
.rr = dns_resource_record_copy(rr),
|
||||
.family = owner_family,
|
||||
.until = rr->until,
|
||||
.query = NULL,
|
||||
.rr_ttl_state = MDNS_TTL_80_PERCENT,
|
||||
.rr_ttl_state = DNS_RECORD_TTL_STATE_80_PERCENT,
|
||||
};
|
||||
|
||||
LIST_PREPEND(dns_services, sb->dns_services, s);
|
||||
|
||||
/* Schedule the first cache maintenance query at 80% of the record's TTL.
|
||||
* Subsequent queries issued at 5% increments until 100% of the TTL. RFC 6762 section 5.2.
|
||||
* If service is being added after 80% of the TTL has already elapsed,
|
||||
* schedule the next query at the next 5% increment. */
|
||||
/* Schedule the first cache maintenance query at 80% of the record's
|
||||
* TTL. Subsequent queries issued at 5% increments until 100% of the
|
||||
* TTL. RFC 6762 section 5.2. If service is being added after 80% of the
|
||||
* TTL has already elapsed, schedule the next query at the next 5%
|
||||
* increment. */
|
||||
usec_t next_time = 0;
|
||||
while (s->rr_ttl_state <= MDNS_TTL_100_PERCENT) {
|
||||
while (s->rr_ttl_state >= DNS_RECORD_TTL_STATE_80_PERCENT &&
|
||||
s->rr_ttl_state <= _DNS_RECORD_TTL_STATE_MAX) {
|
||||
next_time = mdns_maintenance_next_time(rr->until, rr->ttl, s->rr_ttl_state);
|
||||
if (next_time >= usec)
|
||||
break;
|
||||
|
||||
s->rr_ttl_state++;
|
||||
}
|
||||
|
||||
if (next_time < usec) {
|
||||
/* If next_time is still in the past, the service is being added after it has already expired.
|
||||
* Just schedule a 100% maintenance query */
|
||||
/* If next_time is still in the past, the service is being added
|
||||
* after it has already expired. Just schedule a 100%
|
||||
* maintenance query */
|
||||
next_time = usec + USEC_PER_SEC;
|
||||
s->rr_ttl_state = MDNS_TTL_100_PERCENT;
|
||||
s->rr_ttl_state = _DNS_RECORD_TTL_STATE_MAX;
|
||||
}
|
||||
|
||||
usec_t jitter = mdns_maintenance_jitter(rr->ttl);
|
||||
|
||||
r = sd_event_add_time(
|
||||
sb->m->event,
|
||||
sb->manager->event,
|
||||
&s->schedule_event,
|
||||
CLOCK_BOOTTIME,
|
||||
usec_add(next_time, jitter),
|
||||
0,
|
||||
/* accuracy= */ 0,
|
||||
mdns_maintenance_query,
|
||||
s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r < 0) {
|
||||
return log_error_errno(
|
||||
r,
|
||||
"Failed to schedule mDNS maintenance query "
|
||||
"for DNS service: %m");
|
||||
}
|
||||
TAKE_PTR(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dns_remove_service(DnsServiceBrowser *sb, DnsService *service) {
|
||||
void dns_remove_service(DnsServiceBrowser *sb, DnssdDiscoveredService *service) {
|
||||
assert(sb);
|
||||
assert(service);
|
||||
|
||||
LIST_REMOVE(dns_services, sb->dns_services, service);
|
||||
dns_service_free(service);
|
||||
dns_service_unref(service);
|
||||
}
|
||||
|
||||
DnsService *dns_service_free(DnsService *service) {
|
||||
DnssdDiscoveredService *dns_service_free(DnssdDiscoveredService *service) {
|
||||
if (!service)
|
||||
return NULL;
|
||||
|
||||
|
@ -188,22 +217,21 @@ DnsService *dns_service_free(DnsService *service) {
|
|||
if (service->query && DNS_TRANSACTION_IS_LIVE(service->query->state))
|
||||
dns_query_complete(service->query, DNS_TRANSACTION_ABORTED);
|
||||
|
||||
dns_service_browser_unref(service->sb);
|
||||
|
||||
dns_resource_record_unref(service->rr);
|
||||
|
||||
return mfree(service);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsService, dns_service, dns_service_free);
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(DnssdDiscoveredService, dns_service, dns_service_free);
|
||||
|
||||
int mdns_service_update(DnsService *service, DnsResourceRecord *rr, usec_t t) {
|
||||
int mdns_service_update(DnssdDiscoveredService *service, DnsResourceRecord *rr, usec_t t) {
|
||||
service->until = rr->until;
|
||||
service->rr->ttl = rr->ttl;
|
||||
|
||||
/* Update the 80% TTL maintenance event based on new record received from the network.
|
||||
* RFC 6762 section 5.2 */
|
||||
usec_t next_time = mdns_maintenance_next_time(service->until, service->rr->ttl, MDNS_TTL_80_PERCENT);
|
||||
/* Update the 80% TTL maintenance event based on new record received
|
||||
* from the network. RFC 6762 section 5.2 */
|
||||
usec_t next_time = mdns_maintenance_next_time(
|
||||
service->until, service->rr->ttl, DNS_RECORD_TTL_STATE_80_PERCENT);
|
||||
usec_t jitter = mdns_maintenance_jitter(service->rr->ttl);
|
||||
|
||||
if (service->schedule_event)
|
||||
|
@ -212,7 +240,7 @@ int mdns_service_update(DnsService *service, DnsResourceRecord *rr, usec_t t) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool dns_service_contains(DnsService *services, DnsResourceRecord *rr, int owner_family) {
|
||||
bool dns_service_contains(DnssdDiscoveredService *services, DnsResourceRecord *rr, int owner_family) {
|
||||
usec_t t = now(CLOCK_BOOTTIME);
|
||||
|
||||
LIST_FOREACH(dns_services, service, services)
|
||||
|
@ -232,7 +260,7 @@ bool dns_service_contains(DnsService *services, DnsResourceRecord *rr, int owner
|
|||
void dns_browse_services_purge(Manager *m, int family) {
|
||||
int r = 0;
|
||||
|
||||
/* Called after caches are flused.
|
||||
/* Called after caches are flushed.
|
||||
* Clear local service records and notify varlink client. */
|
||||
if (!(m && m->dns_service_browsers))
|
||||
return;
|
||||
|
@ -240,29 +268,32 @@ void dns_browse_services_purge(Manager *m, int family) {
|
|||
DnsServiceBrowser *sb;
|
||||
HASHMAP_FOREACH(sb, m->dns_service_browsers) {
|
||||
r = sd_event_source_set_enabled(sb->schedule_event, SD_EVENT_OFF);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to disable event source for service browser: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
if (family == AF_UNSPEC) {
|
||||
r = mdns_browser_lookup_cache(sb, AF_INET);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
r = mdns_browser_lookup_cache(sb, AF_INET6);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
r = mdns_browser_revisit_cache(sb, AF_INET);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to revisit cache for IPv4: %m");
|
||||
return;
|
||||
}
|
||||
r = mdns_browser_revisit_cache(sb, AF_INET6);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to revisit cache for IPv6: %m");
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
r = mdns_browser_lookup_cache(sb, family);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (r < 0)
|
||||
log_error_errno(r, "mdns browse services purge failed: %m");
|
||||
r = mdns_browser_revisit_cache(sb, family);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to revisit cache for family %d: %m", family);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int owner_family) {
|
||||
DnsResourceRecord *i;
|
||||
|
@ -280,23 +311,29 @@ int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int ow
|
|||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
type = mfree(type);
|
||||
domain = mfree(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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!type)
|
||||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
log_debug("Add into the list %s, %s, %s, %s, %d",
|
||||
strna(name),
|
||||
|
@ -305,20 +342,31 @@ int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int ow
|
|||
strna(af_to_ipv4_ipv6(owner_family)),
|
||||
sb->ifindex);
|
||||
|
||||
r = sd_json_buildo(&entry,
|
||||
SD_JSON_BUILD_PAIR("add_flag", SD_JSON_BUILD_BOOLEAN(true)),
|
||||
r = sd_json_buildo(
|
||||
&entry,
|
||||
SD_JSON_BUILD_PAIR(
|
||||
"updateFlag",
|
||||
SD_JSON_BUILD_STRING(browse_service_update_flag_to_string(
|
||||
BROWSE_SERVICE_UPDATE_ADDED))),
|
||||
SD_JSON_BUILD_PAIR("family", SD_JSON_BUILD_INTEGER(owner_family)),
|
||||
SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(name?: "")),
|
||||
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(type?: "")),
|
||||
SD_JSON_BUILD_PAIR("domain", SD_JSON_BUILD_STRING(domain?: "")),
|
||||
SD_JSON_BUILD_PAIR("interface", SD_JSON_BUILD_INTEGER(sb->ifindex)));
|
||||
if (r < 0)
|
||||
SD_JSON_BUILD_PAIR_CONDITION(
|
||||
!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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for services removed */
|
||||
LIST_FOREACH(dns_services, service, sb->dns_services) {
|
||||
|
@ -332,16 +380,21 @@ int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int ow
|
|||
continue;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
type = mfree(type);
|
||||
domain = mfree(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;
|
||||
}
|
||||
}
|
||||
|
||||
dns_remove_service(sb, service);
|
||||
|
||||
|
@ -352,33 +405,46 @@ int mdns_manage_services_answer(DnsServiceBrowser *sb, DnsAnswer *answer, int ow
|
|||
strna(af_to_ipv4_ipv6(owner_family)),
|
||||
sb->ifindex);
|
||||
|
||||
r = sd_json_buildo(&entry,
|
||||
SD_JSON_BUILD_PAIR("add_flag", SD_JSON_BUILD_BOOLEAN(false)),
|
||||
r = sd_json_buildo(
|
||||
&entry,
|
||||
SD_JSON_BUILD_PAIR(
|
||||
"updateFlag",
|
||||
SD_JSON_BUILD_STRING(browse_service_update_flag_to_string(
|
||||
BROWSE_SERVICE_UPDATE_REMOVED))),
|
||||
SD_JSON_BUILD_PAIR("family", SD_JSON_BUILD_INTEGER(owner_family)),
|
||||
SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(name ?: "")),
|
||||
SD_JSON_BUILD_PAIR("type", SD_JSON_BUILD_STRING(type ?: "")),
|
||||
SD_JSON_BUILD_PAIR("domain", SD_JSON_BUILD_STRING(domain ?: "")),
|
||||
SD_JSON_BUILD_PAIR("interface", SD_JSON_BUILD_INTEGER(sb->ifindex)));
|
||||
if (r < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_blank_array(array)) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *vm = NULL;
|
||||
|
||||
r = sd_json_buildo(&vm,
|
||||
SD_JSON_BUILD_PAIR("browser_service_data", SD_JSON_BUILD_VARIANT(array)));
|
||||
if (r < 0)
|
||||
r = sd_json_buildo(&vm, SD_JSON_BUILD_PAIR("browserServiceData", SD_JSON_BUILD_VARIANT(array)));
|
||||
if (r < 0) {
|
||||
log_error_errno(r,
|
||||
"Failed to build JSON object for "
|
||||
"browser service data: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -387,33 +453,29 @@ finish:
|
|||
return sd_varlink_error_errno(sb->link, r);
|
||||
}
|
||||
|
||||
int mdns_browser_lookup_cache(DnsServiceBrowser *sb, int owner_family) {
|
||||
int mdns_browser_revisit_cache(DnsServiceBrowser *sb, int owner_family) {
|
||||
_cleanup_(dns_answer_unrefp) DnsAnswer *lookup_ret_answer = NULL;
|
||||
DnsScope *scope;
|
||||
int r;
|
||||
|
||||
assert(sb);
|
||||
assert(sb->m);
|
||||
assert(sb->manager);
|
||||
|
||||
scope = manager_find_scope_from_protocol(sb->m, sb->ifindex, DNS_PROTOCOL_MDNS, owner_family);
|
||||
scope = manager_find_scope_from_protocol(sb->manager, sb->ifindex, DNS_PROTOCOL_MDNS, owner_family);
|
||||
if (!scope)
|
||||
return 0;
|
||||
|
||||
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)
|
||||
return r;
|
||||
return log_error_errno(r, "Failed to look up DNS cache for service browser key: %m");
|
||||
|
||||
return mdns_manage_services_answer(sb, lookup_ret_answer, owner_family);
|
||||
r = 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) {
|
||||
|
@ -424,15 +486,16 @@ int mdns_notify_browsers_goodbye(DnsScope *scope) {
|
|||
return 0;
|
||||
|
||||
HASHMAP_FOREACH(sb, scope->manager->dns_service_browsers) {
|
||||
r = mdns_browser_lookup_cache(sb, scope->family);
|
||||
r = mdns_browser_revisit_cache(sb, scope->family);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
return log_error_errno(
|
||||
r,
|
||||
"Failed to revisit cache for service "
|
||||
"browser with family %d: %m",
|
||||
scope->family);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
finish:
|
||||
return r;
|
||||
}
|
||||
|
||||
int mdns_notify_browsers_unsolicited_updates(Manager *m, DnsAnswer *answer, int owner_family) {
|
||||
|
@ -448,21 +511,23 @@ int mdns_notify_browsers_unsolicited_updates(Manager *m, DnsAnswer *answer, int
|
|||
return 0;
|
||||
|
||||
HASHMAP_FOREACH(sb, m->dns_service_browsers) {
|
||||
|
||||
r = dns_answer_match_key(answer, sb->key, NULL);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r == 0)
|
||||
if (r < 0) {
|
||||
return log_error_errno(
|
||||
r,
|
||||
"Failed to match answer key with "
|
||||
"service browser's key: %m");
|
||||
}
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
r = mdns_browser_lookup_cache(sb, owner_family);
|
||||
r = mdns_browser_revisit_cache(sb, owner_family);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
return log_error_errno(r, "Failed to revisit cache for service browser: %m");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
finish:
|
||||
return log_error_errno(r, "Failed to notify mDNS service subscribers, %m");
|
||||
}
|
||||
|
||||
static void mdns_browse_service_query_complete(DnsQuery *q) {
|
||||
|
@ -476,32 +541,37 @@ static void mdns_browse_service_query_complete(DnsQuery *q) {
|
|||
if (query->state != DNS_TRANSACTION_SUCCESS)
|
||||
return;
|
||||
|
||||
sb = dns_service_browser_ref(hashmap_get(query->manager->dns_service_browsers, query->varlink_request));
|
||||
sb = dns_service_browser_ref(query->service_browser_request);
|
||||
if (!sb)
|
||||
return;
|
||||
|
||||
r = dns_answer_match_key(query->answer, sb->key, NULL);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
else if (r == 0)
|
||||
if (r < 0) {
|
||||
log_error_errno(r,
|
||||
"Failed to match answer key with service "
|
||||
"browser's key: %m");
|
||||
return;
|
||||
|
||||
r = mdns_browser_lookup_cache(sb, query->answer_family);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
/* When the query is answered from cache, we only get answers for one answer_family
|
||||
* i.e. either ipv4 or ipv6.
|
||||
* We need to perform another cache lookup for the other answer_family */
|
||||
if (query->answer_query_flags == SD_RESOLVED_FROM_CACHE) {
|
||||
r = mdns_browser_lookup_cache(sb, query->answer_family == AF_INET? AF_INET6 : AF_INET);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (r == 0)
|
||||
return;
|
||||
finish:
|
||||
log_error_errno(r, "mDNS browse query complete failed, %m");
|
||||
|
||||
r = mdns_browser_revisit_cache(sb, query->answer_family);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to revisit cache for service browser: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
/* When the query is answered from cache, we only get answers for one
|
||||
* answer_family i.e. either ipv4 or ipv6. We need to perform another
|
||||
* cache lookup for the other answer_family */
|
||||
if (query->answer_query_flags == SD_RESOLVED_FROM_CACHE) {
|
||||
r = mdns_browser_revisit_cache(sb, query->answer_family == AF_INET ? AF_INET6 : AF_INET);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to revisit cache for service browser: %m");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int mdns_next_query_schedule(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
|
@ -512,49 +582,65 @@ static int mdns_next_query_schedule(sd_event_source *s, uint64_t usec, void *use
|
|||
assert(userdata);
|
||||
|
||||
sb = dns_service_browser_ref(userdata);
|
||||
if (!sb)
|
||||
return log_error_errno(0, "Failed to reference service browser: %m");
|
||||
|
||||
r = dns_query_new(sb->m, &q, sb->question_utf8, sb->question_idna, NULL, sb->ifindex, sb->flags);
|
||||
/* Enable the answer from the cache for the very first query */
|
||||
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)
|
||||
goto finish;
|
||||
return log_error_errno(r, "Failed to create new DNS query: %m");
|
||||
|
||||
q->complete = mdns_browse_service_query_complete;
|
||||
q->service_browser_request = dns_service_browser_ref(sb);
|
||||
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);
|
||||
|
||||
r = dns_query_go(q);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
return log_error_errno(r, "Failed to send DNS query: %m");
|
||||
|
||||
/* RFC6762 5.2
|
||||
* The intervals between successive queries MUST increase by at least a factor of two.
|
||||
* When the interval between queries reaches or exceeds 60 minutes,perform
|
||||
* subsequent queries at a steady-state rate of one query per hour */
|
||||
if (sb->delay == 0) {
|
||||
sb->delay++;
|
||||
/* 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. */
|
||||
sb->flags |= SD_RESOLVED_NO_CACHE;
|
||||
}
|
||||
else
|
||||
* The intervals between successive queries MUST increase by at least a
|
||||
* factor of two. When the interval between queries reaches or exceeds
|
||||
* 60 minutes,perform subsequent queries at a steady-state rate of one
|
||||
* query per hour */
|
||||
|
||||
sb->delay = sb->delay < 2048 ? sb->delay * 2 : 3600;
|
||||
|
||||
SET_FLAG(sb->flags, SD_RESOLVED_NO_CACHE, true);
|
||||
|
||||
r = event_reset_time_relative(
|
||||
sb->m->event, &sb->schedule_event,
|
||||
CLOCK_BOOTTIME, (sb->delay * USEC_PER_SEC),
|
||||
0, mdns_next_query_schedule,
|
||||
sb, 0, "mdns-next-query-schedule", true);
|
||||
sb->manager->event,
|
||||
&sb->schedule_event,
|
||||
CLOCK_BOOTTIME,
|
||||
(sb->delay * USEC_PER_SEC),
|
||||
/* accuracy= */ 0,
|
||||
mdns_next_query_schedule,
|
||||
sb,
|
||||
/* priority= */ 0,
|
||||
"mdns-next-query-schedule",
|
||||
/* force_reset= */ true);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
return log_error_errno(r, "Failed to reset event time for next query schedule: %m");
|
||||
|
||||
TAKE_PTR(q);
|
||||
|
||||
return 0;
|
||||
|
||||
finish:
|
||||
return log_error_errno(r, "Failed to schedule mDNS query, %m");
|
||||
}
|
||||
|
||||
void dns_service_browser_reset(Manager *m) {
|
||||
void dns_browse_services_restart(Manager *m) {
|
||||
int r;
|
||||
|
||||
if (!(m && m->dns_service_browsers))
|
||||
|
@ -566,25 +652,27 @@ void dns_service_browser_reset(Manager *m) {
|
|||
sb->delay = 0;
|
||||
|
||||
r = event_reset_time_relative(
|
||||
sb->m->event, &sb->schedule_event,
|
||||
CLOCK_BOOTTIME, (sb->delay * USEC_PER_SEC),
|
||||
0, mdns_next_query_schedule,
|
||||
sb, 0, "mdns-next-query-schedule", true);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to reset mdns service subscriber, %m");
|
||||
}
|
||||
sb->manager->event,
|
||||
&sb->schedule_event,
|
||||
CLOCK_BOOTTIME,
|
||||
(sb->delay * USEC_PER_SEC),
|
||||
/* accuracy= */ 0,
|
||||
mdns_next_query_schedule,
|
||||
sb,
|
||||
/* priority= */ 0,
|
||||
"mdns-next-query-schedule",
|
||||
/* force_reset= */ true);
|
||||
|
||||
return;
|
||||
if (r < 0) {
|
||||
log_error_errno(r,
|
||||
"Failed to reset mDNS service subscriber event "
|
||||
"for service browser: %m");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int dns_subscribe_browse_service(
|
||||
Manager *m,
|
||||
sd_varlink *link,
|
||||
const char *domain,
|
||||
const char *name,
|
||||
const char *type,
|
||||
int ifindex,
|
||||
uint64_t flags) {
|
||||
Manager *m, sd_varlink *link, const char *domain, const char *type, int ifindex, uint64_t flags) {
|
||||
|
||||
_cleanup_(dns_service_browser_unrefp) DnsServiceBrowser *sb = NULL;
|
||||
_cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
|
||||
|
@ -593,32 +681,32 @@ int dns_subscribe_browse_service(
|
|||
assert(m);
|
||||
assert(link);
|
||||
|
||||
if (ifindex <= 0)
|
||||
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 (ifindex < 0)
|
||||
return sd_varlink_error_invalid_parameter_name(link, "ifindex");
|
||||
|
||||
if (isempty(type))
|
||||
type = NULL;
|
||||
else if (!dnssd_srv_type_is_valid(type))
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("type"));
|
||||
return sd_varlink_error_invalid_parameter_name(link, "type");
|
||||
|
||||
if (isempty(domain))
|
||||
domain = "local";
|
||||
|
||||
r = dns_name_is_valid(domain);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("domain"));
|
||||
return sd_varlink_error_invalid_parameter_name(link, "domain");
|
||||
|
||||
r = dns_question_new_service_type(&question_utf8, name, type, domain, false, DNS_TYPE_PTR);
|
||||
r = dns_question_new_service_type(
|
||||
&question_utf8, /* name= */ NULL, type, domain, /* convert_idna= */ false, DNS_TYPE_PTR);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_error_errno(r, "Failed to create DNS question for UTF8 version: %m");
|
||||
|
||||
r = dns_question_new_service_type(&question_idna, name, type, domain, true, DNS_TYPE_PTR);
|
||||
r = dns_question_new_service_type(
|
||||
&question_idna, /* name= */ NULL, type, domain, /* convert_idna= */ true, DNS_TYPE_PTR);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_error_errno(r, "Failed to create DNS question for IDNA version: %m");
|
||||
|
||||
sb = new (DnsServiceBrowser, 1);
|
||||
if (!sb)
|
||||
|
@ -626,7 +714,7 @@ int dns_subscribe_browse_service(
|
|||
|
||||
*sb = (DnsServiceBrowser) {
|
||||
.n_ref = 1,
|
||||
.m = m,
|
||||
.manager = m,
|
||||
.link = sd_varlink_ref(link),
|
||||
.question_utf8 = dns_question_ref(question_utf8),
|
||||
.question_idna = dns_question_ref(question_idna),
|
||||
|
@ -638,11 +726,12 @@ int dns_subscribe_browse_service(
|
|||
/* Only mDNS continuous querying is currently supported. See RFC 6762 */
|
||||
switch (flags & SD_RESOLVED_PROTOCOLS_ALL) {
|
||||
case SD_RESOLVED_MDNS:
|
||||
r = sd_event_add_time(m->event,
|
||||
r = sd_event_add_time_relative(
|
||||
m->event,
|
||||
&sb->schedule_event,
|
||||
CLOCK_BOOTTIME,
|
||||
usec_add(now(CLOCK_BOOTTIME), (sb->delay * USEC_PER_SEC)),
|
||||
0,
|
||||
(sb->delay * USEC_PER_SEC),
|
||||
/* accuracy= */ 0,
|
||||
mdns_next_query_schedule,
|
||||
sb);
|
||||
if (r < 0)
|
||||
|
@ -654,7 +743,7 @@ int dns_subscribe_browse_service(
|
|||
|
||||
r = hashmap_ensure_put(&m->dns_service_browsers, NULL, link, sb);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_error_errno(r, "Failed to add service browser to the hashmap: %m");
|
||||
|
||||
TAKE_PTR(sb);
|
||||
|
||||
|
@ -667,8 +756,8 @@ DnsServiceBrowser *dns_service_browser_free(DnsServiceBrowser *sb) {
|
|||
if (!sb)
|
||||
return NULL;
|
||||
|
||||
LIST_FOREACH(dns_services, service, sb->dns_services)
|
||||
dns_remove_service(sb, service);
|
||||
while (sb->dns_services)
|
||||
dns_remove_service(sb, sb->dns_services);
|
||||
|
||||
sd_event_source_disable_unref(sb->schedule_event);
|
||||
|
||||
|
|
|
@ -3,38 +3,39 @@
|
|||
#pragma once
|
||||
|
||||
typedef struct DnsServiceBrowser DnsServiceBrowser;
|
||||
typedef struct DnssdDiscoveredService DnssdDiscoveredService;
|
||||
|
||||
#include "sd-varlink.h"
|
||||
#include "resolved-dns-query.h"
|
||||
#include "resolved-manager.h"
|
||||
#include "sd-varlink.h"
|
||||
|
||||
typedef struct DnsService DnsService;
|
||||
|
||||
typedef enum DnsRecordTTLState DnsRecordTTLState;
|
||||
|
||||
enum DnsRecordTTLState {
|
||||
MDNS_TTL_80_PERCENT,
|
||||
MDNS_TTL_85_PERCENT,
|
||||
MDNS_TTL_90_PERCENT,
|
||||
MDNS_TTL_95_PERCENT,
|
||||
MDNS_TTL_100_PERCENT
|
||||
DNS_RECORD_TTL_STATE_80_PERCENT,
|
||||
DNS_RECORD_TTL_STATE_85_PERCENT,
|
||||
DNS_RECORD_TTL_STATE_90_PERCENT,
|
||||
DNS_RECORD_TTL_STATE_95_PERCENT,
|
||||
_DNS_RECORD_TTL_STATE_MAX,
|
||||
_DNS_RECORD_TTL_STATE_MAX_INVALID = -EINVAL
|
||||
};
|
||||
|
||||
struct DnsService {
|
||||
struct DnssdDiscoveredService {
|
||||
unsigned n_ref;
|
||||
DnsServiceBrowser *sb;
|
||||
DnsServiceBrowser *service_browser;
|
||||
sd_event_source *schedule_event;
|
||||
DnsResourceRecord *rr;
|
||||
int family;
|
||||
usec_t until;
|
||||
DnsRecordTTLState rr_ttl_state;
|
||||
DnsQuery *query;
|
||||
LIST_FIELDS(DnsService, dns_services);
|
||||
LIST_FIELDS(DnssdDiscoveredService, dns_services);
|
||||
};
|
||||
|
||||
struct DnsServiceBrowser {
|
||||
unsigned n_ref;
|
||||
Manager *m;
|
||||
Manager *manager;
|
||||
sd_varlink *link;
|
||||
DnsQuestion *question_idna;
|
||||
DnsQuestion *question_utf8;
|
||||
|
@ -44,34 +45,34 @@ struct DnsServiceBrowser {
|
|||
DnsResourceKey *key;
|
||||
int ifindex;
|
||||
uint64_t token;
|
||||
LIST_HEAD(DnsService, dns_services);
|
||||
LIST_HEAD(DnssdDiscoveredService, dns_services);
|
||||
};
|
||||
|
||||
DnsServiceBrowser *dns_service_browser_free(DnsServiceBrowser *sb);
|
||||
void dns_remove_service(DnsServiceBrowser *sb, DnsService *service);
|
||||
DnsService *dns_service_free(DnsService *service);
|
||||
void dns_remove_service(DnsServiceBrowser *sb, DnssdDiscoveredService *service);
|
||||
DnssdDiscoveredService *dns_service_free(DnssdDiscoveredService *service);
|
||||
|
||||
DnsServiceBrowser *dns_service_browser_ref(DnsServiceBrowser *sb);
|
||||
DnsServiceBrowser *dns_service_browser_unref(DnsServiceBrowser *sb);
|
||||
|
||||
DnsService* dns_service_ref(DnsService *service);
|
||||
DnsService* dns_service_unref(DnsService *service);
|
||||
DnssdDiscoveredService *dns_service_ref(DnssdDiscoveredService *service);
|
||||
DnssdDiscoveredService *dns_service_unref(DnssdDiscoveredService *service);
|
||||
|
||||
void dns_browse_services_purge(Manager *m, int family);
|
||||
void dns_service_browser_reset(Manager *m);
|
||||
void dns_browse_services_restart(Manager *m);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServiceBrowser *, dns_service_browser_unref);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsService*, dns_service_unref);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdDiscoveredService *, dns_service_unref);
|
||||
|
||||
bool dns_service_contains(DnsService *services, DnsResourceRecord *rr, int owner_family);
|
||||
bool dns_service_contains(DnssdDiscoveredService *services, DnsResourceRecord *rr, 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 mdns_service_update(DnsService *service, DnsResourceRecord *rr, usec_t t);
|
||||
int mdns_browser_lookup_cache(DnsServiceBrowser *sb, int owner_family);
|
||||
int dns_subscribe_browse_service(Manager *m,
|
||||
int mdns_service_update(DnssdDiscoveredService *service, DnsResourceRecord *rr, usec_t t);
|
||||
int mdns_browser_revisit_cache(DnsServiceBrowser *sb, int owner_family);
|
||||
int dns_subscribe_browse_service(
|
||||
Manager *m,
|
||||
sd_varlink *link,
|
||||
const char *domain,
|
||||
const char * name,
|
||||
const char *type,
|
||||
int ifindex,
|
||||
uint64_t flags);
|
||||
|
|
|
@ -456,6 +456,12 @@ DnsQuery *dns_query_free(DnsQuery *q) {
|
|||
|
||||
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) {
|
||||
LIST_REMOVE(queries, q->manager->dns_queries, q);
|
||||
q->manager->n_dns_queries--;
|
||||
|
|
|
@ -11,6 +11,7 @@ typedef struct DnsQuery DnsQuery;
|
|||
typedef struct DnsStubListenerExtra DnsStubListenerExtra;
|
||||
|
||||
#include "resolved-dns-answer.h"
|
||||
#include "resolved-dns-browse-services.h"
|
||||
#include "resolved-dns-question.h"
|
||||
#include "resolved-dns-search-domain.h"
|
||||
#include "resolved-dns-transaction.h"
|
||||
|
@ -111,6 +112,10 @@ struct DnsQuery {
|
|||
DnsAnswer *reply_additional;
|
||||
DnsStubListenerExtra *stub_listener_extra;
|
||||
|
||||
/* Browser Service and Dnssd Discovered Service Information */
|
||||
DnssdDiscoveredService *dnsservice_request;
|
||||
DnsServiceBrowser *service_browser_request;
|
||||
|
||||
/* Completion callback */
|
||||
void (*complete)(DnsQuery* q);
|
||||
|
||||
|
|
|
@ -1606,7 +1606,7 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) {
|
|||
}
|
||||
|
||||
int dns_scope_add_dnssd_services(DnsScope *scope) {
|
||||
DnssdService *service;
|
||||
DnssdRegisteredService *service;
|
||||
int r;
|
||||
|
||||
assert(scope);
|
||||
|
@ -1645,7 +1645,7 @@ int dns_scope_add_dnssd_services(DnsScope *scope) {
|
|||
|
||||
int dns_scope_remove_dnssd_services(DnsScope *scope) {
|
||||
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
|
||||
DnssdService *service;
|
||||
DnssdRegisteredService *service;
|
||||
int r;
|
||||
|
||||
assert(scope);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "user-util.h"
|
||||
|
||||
int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
DnssdService *s = ASSERT_PTR(userdata);
|
||||
DnssdRegisteredService *s = ASSERT_PTR(userdata);
|
||||
Manager *m;
|
||||
Link *l;
|
||||
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) {
|
||||
_cleanup_free_ char *name = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
DnssdService *service;
|
||||
DnssdRegisteredService *service;
|
||||
int r;
|
||||
|
||||
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) {
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
DnssdService *service;
|
||||
DnssdRegisteredService *service;
|
||||
unsigned c = 0;
|
||||
int r;
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ struct ConfigPerfItem;
|
|||
Service.Name, config_parse_dnssd_service_name, 0, 0
|
||||
Service.Type, config_parse_dnssd_service_type, 0, 0
|
||||
Service.SubType, config_parse_dnssd_service_subtype, 0, 0
|
||||
Service.Port, config_parse_ip_port, 0, offsetof(DnssdService, port)
|
||||
Service.Priority, config_parse_uint16, 0, offsetof(DnssdService, priority)
|
||||
Service.Weight, config_parse_uint16, 0, offsetof(DnssdService, weight)
|
||||
Service.Port, config_parse_ip_port, 0, offsetof(DnssdRegisteredService, port)
|
||||
Service.Priority, config_parse_uint16, 0, offsetof(DnssdRegisteredService, priority)
|
||||
Service.Weight, config_parse_uint16, 0, offsetof(DnssdRegisteredService, weight)
|
||||
Service.TxtText, config_parse_dnssd_txt, DNS_TXT_ITEM_TEXT, 0
|
||||
Service.TxtData, config_parse_dnssd_txt, DNS_TXT_ITEM_DATA, 0
|
||||
|
|
|
@ -37,7 +37,7 @@ DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data) {
|
|||
return dnssd_txtdata_free_all(next);
|
||||
}
|
||||
|
||||
DnssdService *dnssd_service_free(DnssdService *service) {
|
||||
DnssdRegisteredService *dnssd_service_free(DnssdRegisteredService *service) {
|
||||
if (!service)
|
||||
return NULL;
|
||||
|
||||
|
@ -60,7 +60,7 @@ DnssdService *dnssd_service_free(DnssdService *service) {
|
|||
}
|
||||
|
||||
void dnssd_service_clear_on_reload(Hashmap *services) {
|
||||
DnssdService *service;
|
||||
DnssdRegisteredService *service;
|
||||
|
||||
HASHMAP_FOREACH(service, services)
|
||||
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) {
|
||||
_cleanup_(dnssd_service_freep) DnssdService *service = NULL;
|
||||
_cleanup_(dnssd_service_freep) DnssdRegisteredService *service = NULL;
|
||||
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
|
||||
_cleanup_free_ char *dropin_dirname = NULL;
|
||||
int r;
|
||||
|
@ -99,7 +99,7 @@ static int dnssd_service_load(Manager *manager, const char *path) {
|
|||
assert(manager);
|
||||
assert(path);
|
||||
|
||||
service = new0(DnssdService, 1);
|
||||
service = new0(DnssdRegisteredService, 1);
|
||||
if (!service)
|
||||
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);
|
||||
}
|
||||
|
||||
int dnssd_render_instance_name(Manager *m, DnssdService *s, char **ret) {
|
||||
int dnssd_render_instance_name(Manager *m, DnssdRegisteredService *s, char **ret) {
|
||||
static const Specifier specifier_table[] = {
|
||||
{ 'a', specifier_architecture, NULL },
|
||||
{ 'b', specifier_boot_id, NULL },
|
||||
|
@ -229,7 +229,7 @@ int dnssd_load(Manager *manager) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dnssd_update_rrs(DnssdService *s) {
|
||||
int dnssd_update_rrs(DnssdRegisteredService *s) {
|
||||
_cleanup_free_ char *n = NULL, *service_name = NULL, *full_name = NULL, *sub_name = NULL, *selective_name = NULL;
|
||||
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) {
|
||||
DnssdService *s;
|
||||
DnssdRegisteredService *s;
|
||||
int r;
|
||||
|
||||
if (sd_bus_is_ready(manager->bus) <= 0)
|
||||
|
@ -428,7 +428,7 @@ int config_parse_dnssd_service_name(
|
|||
{ 'W', specifier_os_variant_id, NULL },
|
||||
{}
|
||||
};
|
||||
DnssdService *s = ASSERT_PTR(userdata);
|
||||
DnssdRegisteredService *s = ASSERT_PTR(userdata);
|
||||
_cleanup_free_ char *name = NULL;
|
||||
int r;
|
||||
|
||||
|
@ -470,7 +470,7 @@ int config_parse_dnssd_service_type(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
DnssdService *s = ASSERT_PTR(userdata);
|
||||
DnssdRegisteredService *s = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
|
@ -506,7 +506,7 @@ int config_parse_dnssd_service_subtype(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
DnssdService *s = ASSERT_PTR(userdata);
|
||||
DnssdRegisteredService *s = ASSERT_PTR(userdata);
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
|
@ -538,7 +538,7 @@ int config_parse_dnssd_txt(
|
|||
void *userdata) {
|
||||
|
||||
_cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
|
||||
DnssdService *s = ASSERT_PTR(userdata);
|
||||
DnssdRegisteredService *s = ASSERT_PTR(userdata);
|
||||
DnsTxtItem *last = NULL;
|
||||
|
||||
assert(filename);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "list.h"
|
||||
#include "resolved-conf.h"
|
||||
|
||||
typedef struct DnssdService DnssdService;
|
||||
typedef struct DnssdRegisteredService DnssdRegisteredService;
|
||||
typedef struct DnssdTxtData DnssdTxtData;
|
||||
|
||||
typedef struct Manager Manager;
|
||||
|
@ -25,7 +25,7 @@ struct DnssdTxtData {
|
|||
LIST_FIELDS(DnssdTxtData, items);
|
||||
};
|
||||
|
||||
struct DnssdService {
|
||||
struct DnssdRegisteredService {
|
||||
char *path;
|
||||
char *id;
|
||||
char *name_template;
|
||||
|
@ -52,19 +52,19 @@ struct DnssdService {
|
|||
uid_t originator;
|
||||
};
|
||||
|
||||
DnssdService *dnssd_service_free(DnssdService *service);
|
||||
DnssdRegisteredService *dnssd_service_free(DnssdRegisteredService *service);
|
||||
DnssdTxtData *dnssd_txtdata_free(DnssdTxtData *txt_data);
|
||||
DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data);
|
||||
void dnssd_service_clear_on_reload(Hashmap *services);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdService*, dnssd_service_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdRegisteredService*, dnssd_service_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DnssdTxtData*, dnssd_txtdata_free);
|
||||
|
||||
int dnssd_render_instance_name(Manager *m, DnssdService *s, char **ret);
|
||||
int dnssd_render_instance_name(Manager *m, DnssdRegisteredService *s, char **ret);
|
||||
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_data(const char *key, const void *value, const size_t size, DnsTxtItem **ret_item);
|
||||
int dnssd_update_rrs(DnssdService *s);
|
||||
int dnssd_update_rrs(DnssdRegisteredService *s);
|
||||
int dnssd_signal_conflict(Manager *manager, const char *name);
|
||||
|
||||
const struct ConfigPerfItem* resolved_dnssd_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||
|
|
|
@ -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);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate mDNS IPv4 scope, ignoring: %m");
|
||||
dns_service_browser_reset(l->manager);
|
||||
dns_browse_services_restart(l->manager);
|
||||
}
|
||||
} else
|
||||
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);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(l, r, "Failed to allocate mDNS IPv6 scope, ignoring: %m");
|
||||
dns_service_browser_reset(l->manager);
|
||||
dns_browse_services_restart(l->manager);
|
||||
}
|
||||
} else
|
||||
l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope);
|
||||
|
|
|
@ -768,7 +768,7 @@ int manager_start(Manager *m) {
|
|||
|
||||
Manager *manager_free(Manager *m) {
|
||||
Link *l;
|
||||
DnssdService *s;
|
||||
DnssdRegisteredService *s;
|
||||
DnsServiceBrowser *sb;
|
||||
|
||||
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) {
|
||||
Link *l;
|
||||
DnssdService *s;
|
||||
DnssdRegisteredService *s;
|
||||
|
||||
assert(m);
|
||||
|
||||
|
@ -1711,7 +1711,7 @@ void manager_flush_caches(Manager *m, int log_level) {
|
|||
dns_cache_flush(&scope->cache);
|
||||
|
||||
dns_browse_services_purge(m, AF_UNSPEC); /* Clear records of DNS service browse subscriber, since caches are flushed */
|
||||
dns_service_browser_reset(m);
|
||||
dns_browse_services_restart(m);
|
||||
|
||||
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) {
|
||||
DnssdService *s;
|
||||
DnssdRegisteredService *s;
|
||||
bool tried = false;
|
||||
int r;
|
||||
|
||||
|
|
|
@ -361,7 +361,7 @@ static int mdns_goodbye_callback(sd_event_source *s, uint64_t usec, void *userda
|
|||
|
||||
r = mdns_notify_browsers_goodbye(scope);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "mDNS: Failed to notify service subscribers of goodbyes, %m");
|
||||
log_warning_errno(r, "mDNS: Failed to notify service subscribers of goodbyes, ignoring: %m");
|
||||
|
||||
if (dns_cache_expiry_in_one_second(&scope->cache, usec)) {
|
||||
r = sd_event_add_time_relative(
|
||||
|
@ -369,11 +369,11 @@ static int mdns_goodbye_callback(sd_event_source *s, uint64_t usec, void *userda
|
|||
&scope->mdns_goodbye_event_source,
|
||||
CLOCK_BOOTTIME,
|
||||
USEC_PER_SEC,
|
||||
0,
|
||||
/* accuracy= */ 0,
|
||||
mdns_goodbye_callback,
|
||||
scope);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "mDNS: Failed to re-schedule goodbye callback: %m");
|
||||
return log_warning_errno(r, "mDNS: Failed to re-schedule goodbye callback, ignoring: %m");
|
||||
}
|
||||
|
||||
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,
|
||||
CLOCK_BOOTTIME,
|
||||
USEC_PER_SEC,
|
||||
0,
|
||||
/* accuracy= */ 0,
|
||||
mdns_goodbye_callback,
|
||||
scope);
|
||||
if (r < 0)
|
||||
|
@ -464,13 +464,13 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
|
|||
&scope->cache,
|
||||
scope->manager->enable_cache,
|
||||
DNS_PROTOCOL_MDNS,
|
||||
NULL,
|
||||
/* key= */ NULL,
|
||||
DNS_PACKET_RCODE(p),
|
||||
p->answer,
|
||||
NULL,
|
||||
false,
|
||||
/* full_packet= */ NULL,
|
||||
/* query_flags= */ false,
|
||||
_DNSSEC_RESULT_INVALID,
|
||||
UINT32_MAX,
|
||||
/* nsec_ttl= */ UINT32_MAX,
|
||||
p->family,
|
||||
&p->sender,
|
||||
scope->manager->stale_retention_usec);
|
||||
|
@ -500,7 +500,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
|
|||
}
|
||||
}
|
||||
|
||||
/* Check incoming packet key matches with active clients if yes update the same */
|
||||
/* Check if incoming packet key matches with active browse clients. If yes, update the same */
|
||||
if (unsolicited_packet)
|
||||
mdns_notify_browsers_unsolicited_updates(m, p->answer, p->family);
|
||||
|
||||
|
|
|
@ -31,26 +31,18 @@ typedef struct LookupParametersResolveService {
|
|||
uint64_t flags;
|
||||
} LookupParametersResolveService;
|
||||
|
||||
typedef struct LookupParametersMdnsBrowse {
|
||||
char *domainName;
|
||||
char *name;
|
||||
char *type;
|
||||
typedef struct LookupParametersBrowse {
|
||||
const char *domain;
|
||||
const char *type;
|
||||
int ifindex;
|
||||
uint64_t flags;
|
||||
} LookupParametersMdnsBrowse;
|
||||
} LookupParametersBrowse;
|
||||
|
||||
static void lookup_parameters_destroy(LookupParameters *p) {
|
||||
assert(p);
|
||||
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) {
|
||||
|
||||
assert(q);
|
||||
|
@ -134,7 +126,7 @@ static void vl_on_disconnect(sd_varlink_server *s, sd_varlink *link, void *userd
|
|||
return;
|
||||
|
||||
DnsServiceBrowser *sb = hashmap_remove(m->dns_service_browsers, link);
|
||||
dns_service_browser_free(sb);
|
||||
dns_service_browser_unref(sb);
|
||||
|
||||
q = sd_varlink_get_userdata(link);
|
||||
if (!q)
|
||||
|
@ -1233,17 +1225,16 @@ static int verify_polkit(sd_varlink *link, sd_json_variant *parameters, const ch
|
|||
&m->polkit_registry);
|
||||
}
|
||||
|
||||
static int vl_method_start_browse(sd_varlink* link, sd_json_variant* parameters, sd_varlink_method_flags_t flags, void* userdata) {
|
||||
static int vl_method_browse_services(sd_varlink* link, sd_json_variant* parameters, sd_varlink_method_flags_t flags, void* userdata) {
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "domainName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(LookupParametersMdnsBrowse, domainName), SD_JSON_MANDATORY },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(LookupParametersMdnsBrowse, name), 0 },
|
||||
{ "type", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(LookupParametersMdnsBrowse, type), 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 },
|
||||
{ "domain", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParametersBrowse, domain), 0 },
|
||||
{ "type", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParametersBrowse, type), 0 },
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(LookupParametersBrowse, ifindex), 0 },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LookupParametersBrowse, flags), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(lookup_parameters_mdns_destroy) LookupParametersMdnsBrowse p = {};
|
||||
LookupParametersBrowse p = {};
|
||||
Manager *m;
|
||||
int r = 0;
|
||||
|
||||
|
@ -1258,12 +1249,12 @@ static int vl_method_start_browse(sd_varlink* link, sd_json_variant* parameters,
|
|||
|
||||
r = sd_varlink_dispatch(link, parameters, dispatch_table, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "vl_method_start_browse json_dispatch fail: %m");
|
||||
return log_error_errno(r, "Failed vl_method_browse_services json dispatch: %m");
|
||||
|
||||
if (!validate_and_mangle_flags(NULL, &p.flags, 0))
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
|
||||
return sd_varlink_error_invalid_parameter_name(link, "flags");
|
||||
|
||||
r = dns_subscribe_browse_service(m, link, p.domainName, p.name, p.type, p.ifindex, p.flags);
|
||||
r = dns_subscribe_browse_service(m, link, p.domain, p.type, p.ifindex, p.flags);
|
||||
if (r < 0)
|
||||
return sd_varlink_error_errno(link, r);
|
||||
|
||||
|
@ -1484,7 +1475,7 @@ static int varlink_main_server_init(Manager *m) {
|
|||
"io.systemd.Resolve.ResolveAddress", vl_method_resolve_address,
|
||||
"io.systemd.Resolve.ResolveService", vl_method_resolve_service,
|
||||
"io.systemd.Resolve.ResolveRecord", vl_method_resolve_record,
|
||||
"io.systemd.Resolve.StartBrowse", vl_method_start_browse);
|
||||
"io.systemd.Resolve.BrowseServices", vl_method_browse_services);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register varlink methods: %m");
|
||||
|
||||
|
|
|
@ -24,8 +24,7 @@ int acquire_fido2_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
Fido2EnrollFlags required,
|
||||
const char *askpw_credential,
|
||||
|
@ -45,10 +44,10 @@ int acquire_fido2_key(
|
|||
"Local verification is required to unlock this volume, but the 'headless' parameter was set.");
|
||||
|
||||
assert(cid);
|
||||
assert(key_file || key_data);
|
||||
assert(key_file || iovec_is_set(key_data));
|
||||
|
||||
if (key_data)
|
||||
salt = IOVEC_MAKE(key_data, key_data_size);
|
||||
if (iovec_is_set(key_data))
|
||||
salt = *key_data;
|
||||
else {
|
||||
if (key_file_size > 0)
|
||||
log_debug("Ignoring 'keyfile-size=' option for a FIDO2 salt file.");
|
||||
|
@ -252,7 +251,7 @@ int acquire_fido2_key_auto(
|
|||
/* key_file= */ NULL, /* salt is read from LUKS header instead of key_file */
|
||||
/* key_file_size= */ 0,
|
||||
/* key_file_offset= */ 0,
|
||||
salt, salt_size,
|
||||
&IOVEC_MAKE(salt, salt_size),
|
||||
until,
|
||||
required,
|
||||
"cryptsetup.fido2-pin",
|
||||
|
|
|
@ -20,8 +20,7 @@ int acquire_fido2_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
Fido2EnrollFlags required,
|
||||
const char *askpw_credential,
|
||||
|
@ -52,8 +51,7 @@ static inline int acquire_fido2_key(
|
|||
const char *key_file,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const void *key_data,
|
||||
size_t key_data_size,
|
||||
const struct iovec *key_data,
|
||||
usec_t until,
|
||||
Fido2EnrollFlags required,
|
||||
const char *askpw_credential,
|
||||
|
|
|
@ -102,14 +102,26 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
|||
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
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(
|
||||
ServiceData,
|
||||
SD_VARLINK_DEFINE_FIELD(add_flag, SD_VARLINK_BOOL, 0),
|
||||
SD_VARLINK_DEFINE_FIELD_BY_TYPE(updateFlag, BrowseServiceUpdateFlag, 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_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_FIELD_COMMENT("The type of service, e.g., '_http._tcp'."),
|
||||
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(interface, SD_VARLINK_INT, 0));
|
||||
SD_VARLINK_FIELD_COMMENT("The Linux interface index for the network interface associated with this service."),
|
||||
SD_VARLINK_DEFINE_FIELD(ifindex, SD_VARLINK_INT, 0));
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
ResolveAddress,
|
||||
|
@ -168,14 +180,19 @@ static SD_VARLINK_DEFINE_METHOD(
|
|||
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(rrs, ResolvedRecord, SD_VARLINK_ARRAY),
|
||||
SD_VARLINK_DEFINE_OUTPUT(flags, SD_VARLINK_INT, 0));
|
||||
|
||||
static SD_VARLINK_DEFINE_METHOD(
|
||||
StartBrowse,
|
||||
SD_VARLINK_DEFINE_INPUT(domainName, SD_VARLINK_STRING, 0),
|
||||
SD_VARLINK_DEFINE_INPUT(name, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
|
||||
static SD_VARLINK_DEFINE_METHOD_FULL(
|
||||
BrowseServices,
|
||||
SD_VARLINK_SUPPORTS_MORE,
|
||||
SD_VARLINK_FIELD_COMMENT("The domain to browse for services. If null, the default browsing domain local is used."),
|
||||
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(ifindex, SD_VARLINK_INT, 0),
|
||||
SD_VARLINK_DEFINE_INPUT(flags, SD_VARLINK_INT, 0),
|
||||
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(browser_service_data, ServiceData, SD_VARLINK_ARRAY));
|
||||
SD_VARLINK_FIELD_COMMENT("The Linux interface index for the network interface to search on."),
|
||||
SD_VARLINK_DEFINE_INPUT(ifindex, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||
SD_VARLINK_FIELD_COMMENT("Various browsing flags to modify the operation."),
|
||||
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(NoSuchResourceRecord);
|
||||
|
@ -216,8 +233,8 @@ SD_VARLINK_DEFINE_INTERFACE(
|
|||
&vl_method_ResolveService,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Resolves a domain name to one or more DNS resource records."),
|
||||
&vl_method_ResolveRecord,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Starts browsing for mDNS services of specified type."),
|
||||
&vl_method_StartBrowse,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Starts browsing for DNS-SD services of specified type."),
|
||||
&vl_method_BrowseServices,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved address."),
|
||||
&vl_type_ResolvedAddress,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Encapsulates a resolved host name."),
|
||||
|
@ -232,6 +249,9 @@ SD_VARLINK_DEFINE_INTERFACE(
|
|||
&vl_type_ResourceRecord,
|
||||
SD_VARLINK_SYMBOL_COMMENT("Encapsulates information about a resolved DNS resource record "),
|
||||
&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_error_NoNameServers,
|
||||
&vl_error_NoSuchResourceRecord,
|
||||
|
|
|
@ -1414,7 +1414,7 @@ static int verb_enable(int argc, char **argv, void *userdata) {
|
|||
"SetFeatureEnabled",
|
||||
&error,
|
||||
/* reply= */ NULL,
|
||||
"sbt",
|
||||
"sit",
|
||||
*feature,
|
||||
(int) enable,
|
||||
UINT64_C(0));
|
||||
|
|
|
@ -80,7 +80,6 @@ show_journal = True # When true, show journal on stopping networkd.
|
|||
|
||||
active_units = []
|
||||
protected_links = {
|
||||
'br0',
|
||||
'erspan0',
|
||||
'gre0',
|
||||
'gretap0',
|
||||
|
|
|
@ -114,10 +114,10 @@ run_and_check_services() {
|
|||
error_file="$(mktemp)"
|
||||
tmp_file="$(mktemp)"
|
||||
service_type="_testService$service_id._udp"
|
||||
parameters="{ \"domainName\": \"$service_type.local\", \"name\": \"\", \"type\": \"\", \"ifindex\": ${BRIDGE_INDEX:?}, \"flags\": 16785432 }"
|
||||
parameters="{ \"domain\": \"$service_type.local\", \"type\": \"\", \"ifindex\": ${BRIDGE_INDEX:?}, \"flags\": 16785432 }"
|
||||
|
||||
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.StartBrowse "$parameters"
|
||||
varlinkctl call --more /run/systemd/resolve/io.systemd.Resolve io.systemd.Resolve.BrowseServices "$parameters"
|
||||
|
||||
# shellcheck disable=SC2064
|
||||
# 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": [
|
||||
# {
|
||||
# "add_flag": true,
|
||||
# "updateFlag": true,
|
||||
# "family": 10,
|
||||
# "name": "Test Service 13 on test-mdns-1",
|
||||
# "type": "_testService0._udp",
|
||||
|
@ -144,7 +144,7 @@ run_and_check_services() {
|
|||
if [[ -s "$out_file" ]]; then
|
||||
# Extract the service name from each valid record...
|
||||
# jq --slurp --raw-output \
|
||||
# ".[].browser_service_data[] | select(.add_flag == true and .type == \"$service_type\" and .family == 10).name" "$out_file" | sort | tee "$tmp_file"
|
||||
# ".[].browser_service_data[] | select(.updateFlag == 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"
|
||||
# ...and compare them with what we expect
|
||||
if "$check_func" "$service_id" "$tmp_file"; then
|
||||
|
|
Loading…
Reference in New Issue