mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
dnssd: support service subtypes
A service subtype is used for selective enumeration of services.
This commit is contained in:
parent
15d4bedf3d
commit
88123aa21c
@ -118,6 +118,16 @@
|
||||
<xi:include href="version-info.xml" xpointer="v236"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>SubType=</varname></term>
|
||||
<listitem>
|
||||
<para>A subtype of the network service as defined in the section 7.1 of <ulink
|
||||
url="https://tools.ietf.org/html/rfc6763">RFC 6763</ulink>, e.g. <literal>_printer</literal>.
|
||||
</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>Port=</varname></term>
|
||||
<listitem>
|
||||
|
@ -299,6 +299,37 @@ int config_parse_dnssd_service_type(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_dnssd_service_subtype(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
DnssdService *s = ASSERT_PTR(userdata);
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
s->subtype = mfree(s->subtype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dns_subtype_name_is_valid(rvalue)) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Service subtype is invalid. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return free_and_strdup_warn(&s->subtype, rvalue);
|
||||
}
|
||||
|
||||
int config_parse_dnssd_txt(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
|
@ -17,6 +17,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dns_servers);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_search_domains);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dns_stub_listener_mode);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_name);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_subtype);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_service_type);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dnssd_txt);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dns_stub_listener_extra);
|
||||
|
@ -1614,6 +1614,12 @@ int dns_scope_add_dnssd_services(DnsScope *scope) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to add PTR record to MDNS zone: %m");
|
||||
|
||||
if (service->sub_ptr_rr) {
|
||||
r = dns_zone_put(&scope->zone, scope, service->sub_ptr_rr, false);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to add selective PTR record to MDNS zone: %m");
|
||||
}
|
||||
|
||||
r = dns_zone_put(&scope->zone, scope, service->srv_rr, true);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to add SRV record to MDNS zone: %m");
|
||||
@ -1646,6 +1652,7 @@ int dns_scope_remove_dnssd_services(DnsScope *scope) {
|
||||
|
||||
HASHMAP_FOREACH(service, scope->manager->dnssd_services) {
|
||||
dns_zone_remove_rr(&scope->zone, service->ptr_rr);
|
||||
dns_zone_remove_rr(&scope->zone, service->sub_ptr_rr);
|
||||
dns_zone_remove_rr(&scope->zone, service->srv_rr);
|
||||
LIST_FOREACH(items, txt_data, service->txt_data_items)
|
||||
dns_zone_remove_rr(&scope->zone, txt_data->rr);
|
||||
|
@ -40,6 +40,7 @@ int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_
|
||||
log_warning_errno(r, "Failed to send goodbye messages in IPv4 scope: %m");
|
||||
|
||||
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, s->ptr_rr);
|
||||
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, s->sub_ptr_rr);
|
||||
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, s->srv_rr);
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items)
|
||||
dns_zone_remove_rr(&l->mdns_ipv4_scope->zone, txt_data->rr);
|
||||
@ -51,6 +52,7 @@ int bus_dnssd_method_unregister(sd_bus_message *message, void *userdata, sd_bus_
|
||||
log_warning_errno(r, "Failed to send goodbye messages in IPv6 scope: %m");
|
||||
|
||||
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, s->ptr_rr);
|
||||
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, s->sub_ptr_rr);
|
||||
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, s->srv_rr);
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items)
|
||||
dns_zone_remove_rr(&l->mdns_ipv6_scope->zone, txt_data->rr);
|
||||
|
@ -16,10 +16,11 @@ struct ConfigPerfItem;
|
||||
%struct-type
|
||||
%includes
|
||||
%%
|
||||
Service.Name, config_parse_dnssd_service_name, 0, 0
|
||||
Service.Type, config_parse_dnssd_service_type, 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.TxtText, config_parse_dnssd_txt, DNS_TXT_ITEM_TEXT, 0
|
||||
Service.TxtData, config_parse_dnssd_txt, DNS_TXT_ITEM_DATA, 0
|
||||
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.TxtText, config_parse_dnssd_txt, DNS_TXT_ITEM_TEXT, 0
|
||||
Service.TxtData, config_parse_dnssd_txt, DNS_TXT_ITEM_DATA, 0
|
||||
|
@ -43,6 +43,7 @@ DnssdService *dnssd_service_free(DnssdService *service) {
|
||||
hashmap_remove(service->manager->dnssd_services, service->name);
|
||||
|
||||
dns_resource_record_unref(service->ptr_rr);
|
||||
dns_resource_record_unref(service->sub_ptr_rr);
|
||||
dns_resource_record_unref(service->srv_rr);
|
||||
|
||||
dnssd_txtdata_free_all(service->txt_data_items);
|
||||
@ -50,6 +51,7 @@ DnssdService *dnssd_service_free(DnssdService *service) {
|
||||
free(service->filename);
|
||||
free(service->name);
|
||||
free(service->type);
|
||||
free(service->subtype);
|
||||
free(service->name_template);
|
||||
|
||||
return mfree(service);
|
||||
@ -208,7 +210,7 @@ int dnssd_load(Manager *manager) {
|
||||
}
|
||||
|
||||
int dnssd_update_rrs(DnssdService *s) {
|
||||
_cleanup_free_ char *n = NULL, *service_name = NULL, *full_name = NULL;
|
||||
_cleanup_free_ char *n = NULL, *service_name = NULL, *full_name = NULL, *sub_name = NULL, *selective_name = NULL;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
@ -216,6 +218,7 @@ int dnssd_update_rrs(DnssdService *s) {
|
||||
assert(s->manager);
|
||||
|
||||
s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
|
||||
s->sub_ptr_rr = dns_resource_record_unref(s->sub_ptr_rr);
|
||||
s->srv_rr = dns_resource_record_unref(s->srv_rr);
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items)
|
||||
txt_data->rr = dns_resource_record_unref(txt_data->rr);
|
||||
@ -230,6 +233,14 @@ int dnssd_update_rrs(DnssdService *s) {
|
||||
r = dns_name_concat(n, service_name, 0, &full_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (s->subtype) {
|
||||
r = dns_name_concat("_sub", service_name, 0, &sub_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = dns_name_concat(s->subtype, sub_name, 0, &selective_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items) {
|
||||
txt_data->rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_TXT,
|
||||
@ -253,6 +264,17 @@ int dnssd_update_rrs(DnssdService *s) {
|
||||
if (!s->ptr_rr->ptr.name)
|
||||
goto oom;
|
||||
|
||||
if (selective_name) {
|
||||
s->sub_ptr_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, selective_name);
|
||||
if (!s->sub_ptr_rr)
|
||||
goto oom;
|
||||
|
||||
s->sub_ptr_rr->ttl = MDNS_DEFAULT_TTL;
|
||||
s->sub_ptr_rr->ptr.name = strdup(full_name);
|
||||
if (!s->sub_ptr_rr->ptr.name)
|
||||
goto oom;
|
||||
}
|
||||
|
||||
s->srv_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SRV,
|
||||
full_name);
|
||||
if (!s->srv_rr)
|
||||
@ -272,6 +294,7 @@ oom:
|
||||
LIST_FOREACH(items, txt_data, s->txt_data_items)
|
||||
txt_data->rr = dns_resource_record_unref(txt_data->rr);
|
||||
s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
|
||||
s->sub_ptr_rr = dns_resource_record_unref(s->sub_ptr_rr);
|
||||
s->srv_rr = dns_resource_record_unref(s->srv_rr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -29,11 +29,13 @@ struct DnssdService {
|
||||
char *name;
|
||||
char *name_template;
|
||||
char *type;
|
||||
char *subtype;
|
||||
uint16_t port;
|
||||
uint16_t priority;
|
||||
uint16_t weight;
|
||||
|
||||
DnsResourceRecord *ptr_rr;
|
||||
DnsResourceRecord *sub_ptr_rr;
|
||||
DnsResourceRecord *srv_rr;
|
||||
|
||||
/* Section 6.8 of RFC 6763 allows having service
|
||||
|
@ -980,6 +980,29 @@ bool dns_service_name_is_valid(const char *name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dns_subtype_name_is_valid(const char *name) {
|
||||
size_t l;
|
||||
|
||||
/* This more or less implements RFC 6763, Section 7.2 */
|
||||
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
if (!utf8_is_valid(name))
|
||||
return false;
|
||||
|
||||
if (string_has_cc(name, NULL))
|
||||
return false;
|
||||
|
||||
l = strlen(name);
|
||||
if (l <= 0)
|
||||
return false;
|
||||
if (l > DNS_LABEL_MAX)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int dns_service_join(const char *name, const char *type, const char *domain, char **ret) {
|
||||
char escaped[DNS_LABEL_ESCAPED_MAX];
|
||||
_cleanup_free_ char *n = NULL;
|
||||
|
@ -83,6 +83,7 @@ int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, boo
|
||||
bool dns_srv_type_is_valid(const char *name);
|
||||
bool dnssd_srv_type_is_valid(const char *name);
|
||||
bool dns_service_name_is_valid(const char *name);
|
||||
bool dns_subtype_name_is_valid(const char *name);
|
||||
|
||||
int dns_service_join(const char *name, const char *type, const char *domain, char **ret);
|
||||
int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain);
|
||||
|
Loading…
Reference in New Issue
Block a user