1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "alloc-util.h"
23 #include "dns-domain.h"
24 #include "hostname-util.h"
25 #include "local-addresses.h"
26 #include "resolved-dns-query.h"
28 /* How long to wait for the query in total */
29 #define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC)
32 #define QUERIES_MAX 2048
33 #define AUXILIARY_QUERIES_MAX 64
35 static void dns_query_stop(DnsQuery
*q
) {
40 q
->timeout_event_source
= sd_event_source_unref(q
->timeout_event_source
);
42 while ((t
= set_steal_first(q
->transactions
))) {
43 set_remove(t
->queries
, q
);
44 dns_transaction_gc(t
);
48 DnsQuery
*dns_query_free(DnsQuery
*q
) {
52 while (q
->auxiliary_queries
)
53 dns_query_free(q
->auxiliary_queries
);
55 if (q
->auxiliary_for
) {
56 assert(q
->auxiliary_for
->n_auxiliary_queries
> 0);
57 q
->auxiliary_for
->n_auxiliary_queries
--;
58 LIST_REMOVE(auxiliary_queries
, q
->auxiliary_for
->auxiliary_queries
, q
);
62 set_free(q
->transactions
);
64 dns_question_unref(q
->question
);
65 dns_answer_unref(q
->answer
);
67 sd_bus_message_unref(q
->request
);
68 sd_bus_track_unref(q
->bus_track
);
71 LIST_REMOVE(queries
, q
->manager
->dns_queries
, q
);
72 q
->manager
->n_dns_queries
--;
80 int dns_query_new(Manager
*m
, DnsQuery
**ret
, DnsQuestion
*question
, int ifindex
, uint64_t flags
) {
81 _cleanup_(dns_query_freep
) DnsQuery
*q
= NULL
;
88 r
= dns_question_is_valid_for_query(question
);
92 if (m
->n_dns_queries
>= QUERIES_MAX
)
95 q
= new0(DnsQuery
, 1);
99 q
->question
= dns_question_ref(question
);
100 q
->ifindex
= ifindex
;
103 for (i
= 0; i
< question
->n_keys
; i
++) {
104 _cleanup_free_
char *p
;
106 r
= dns_resource_key_to_string(question
->keys
[i
], &p
);
110 log_debug("Looking up RR for %s", p
);
113 LIST_PREPEND(queries
, m
->dns_queries
, q
);
124 int dns_query_make_auxiliary(DnsQuery
*q
, DnsQuery
*auxiliary_for
) {
126 assert(auxiliary_for
);
128 /* Ensure that that the query is not auxiliary yet, and
129 * nothing else is auxiliary to it either */
130 assert(!q
->auxiliary_for
);
131 assert(!q
->auxiliary_queries
);
133 /* Ensure that the unit we shall be made auxiliary for isn't
134 * auxiliary itself */
135 assert(!auxiliary_for
->auxiliary_for
);
137 if (auxiliary_for
->n_auxiliary_queries
>= AUXILIARY_QUERIES_MAX
)
140 LIST_PREPEND(auxiliary_queries
, auxiliary_for
->auxiliary_queries
, q
);
141 q
->auxiliary_for
= auxiliary_for
;
143 auxiliary_for
->n_auxiliary_queries
++;
147 static void dns_query_complete(DnsQuery
*q
, DnsTransactionState state
) {
149 assert(!IN_SET(state
, DNS_TRANSACTION_NULL
, DNS_TRANSACTION_PENDING
));
150 assert(IN_SET(q
->state
, DNS_TRANSACTION_NULL
, DNS_TRANSACTION_PENDING
));
152 /* Note that this call might invalidate the query. Callers
153 * should hence not attempt to access the query or transaction
154 * after calling this function. */
163 static int on_query_timeout(sd_event_source
*s
, usec_t usec
, void *userdata
) {
164 DnsQuery
*q
= userdata
;
169 dns_query_complete(q
, DNS_TRANSACTION_TIMEOUT
);
173 static int dns_query_add_transaction(DnsQuery
*q
, DnsScope
*s
, DnsResourceKey
*key
) {
181 r
= set_ensure_allocated(&q
->transactions
, NULL
);
185 t
= dns_scope_find_transaction(s
, key
, true);
187 r
= dns_transaction_new(&t
, s
, key
);
192 r
= set_ensure_allocated(&t
->queries
, NULL
);
196 r
= set_put(t
->queries
, q
);
200 r
= set_put(q
->transactions
, t
);
202 set_remove(t
->queries
, q
);
209 dns_transaction_gc(t
);
213 static int dns_query_add_transaction_split(DnsQuery
*q
, DnsScope
*s
) {
220 /* Create one transaction per question key */
222 for (i
= 0; i
< q
->question
->n_keys
; i
++) {
223 r
= dns_query_add_transaction(q
, s
, q
->question
->keys
[i
]);
231 static int SYNTHESIZE_IFINDEX(int ifindex
) {
233 /* When the caller asked for resolving on a specific
234 * interface, we synthesize the answer for that
235 * interface. However, if nothing specific was claimed and we
236 * only return localhost RRs, we synthesize the answer for
242 return LOOPBACK_IFINDEX
;
245 static int SYNTHESIZE_FAMILY(uint64_t flags
) {
247 /* Picks an address family depending on set flags. This is
248 * purely for synthesized answers, where the family we return
249 * for the reply should match what was requested in the
250 * question, even though we are synthesizing the answer
253 if (!(flags
& SD_RESOLVED_DNS
)) {
254 if (flags
& SD_RESOLVED_LLMNR_IPV4
)
256 if (flags
& SD_RESOLVED_LLMNR_IPV6
)
263 static DnsProtocol
SYNTHESIZE_PROTOCOL(uint64_t flags
) {
265 /* Similar as SYNTHESIZE_FAMILY() but does this for the
266 * protocol. If resolving via DNS was requested, we claim it
267 * was DNS. Similar, if nothing specific was
268 * requested. However, if only resolving via LLMNR was
269 * requested we return that. */
271 if (flags
& SD_RESOLVED_DNS
)
272 return DNS_PROTOCOL_DNS
;
273 if (flags
& SD_RESOLVED_LLMNR
)
274 return DNS_PROTOCOL_LLMNR
;
276 return DNS_PROTOCOL_DNS
;
279 static int dns_type_to_af(uint16_t t
) {
296 static int synthesize_localhost_rr(DnsQuery
*q
, DnsResourceKey
*key
, DnsAnswer
**answer
) {
303 r
= dns_answer_reserve(answer
, 2);
307 if (IN_SET(key
->type
, DNS_TYPE_A
, DNS_TYPE_ANY
)) {
308 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
310 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_A
, DNS_RESOURCE_KEY_NAME(key
));
314 rr
->a
.in_addr
.s_addr
= htobe32(INADDR_LOOPBACK
);
316 r
= dns_answer_add(*answer
, rr
, SYNTHESIZE_IFINDEX(q
->ifindex
));
321 if (IN_SET(key
->type
, DNS_TYPE_AAAA
, DNS_TYPE_ANY
)) {
322 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
324 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_AAAA
, DNS_RESOURCE_KEY_NAME(key
));
328 rr
->aaaa
.in6_addr
= in6addr_loopback
;
330 r
= dns_answer_add(*answer
, rr
, SYNTHESIZE_IFINDEX(q
->ifindex
));
338 static int answer_add_ptr(DnsAnswer
**answer
, const char *from
, const char *to
, int ifindex
) {
339 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
341 rr
= dns_resource_record_new_full(DNS_CLASS_IN
, DNS_TYPE_PTR
, from
);
345 rr
->ptr
.name
= strdup(to
);
349 return dns_answer_add(*answer
, rr
, ifindex
);
352 static int synthesize_localhost_ptr(DnsQuery
*q
, DnsResourceKey
*key
, DnsAnswer
**answer
) {
359 r
= dns_answer_reserve(answer
, 1);
363 if (IN_SET(key
->type
, DNS_TYPE_PTR
, DNS_TYPE_ANY
)) {
364 r
= answer_add_ptr(answer
, DNS_RESOURCE_KEY_NAME(key
), "localhost", SYNTHESIZE_IFINDEX(q
->ifindex
));
372 static int answer_add_addresses_rr(
375 struct local_address
*addresses
,
376 unsigned n_addresses
) {
384 r
= dns_answer_reserve(answer
, n_addresses
);
388 for (j
= 0; j
< n_addresses
; j
++) {
389 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
391 r
= dns_resource_record_new_address(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
395 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
);
403 static int answer_add_addresses_ptr(
406 struct local_address
*addresses
,
407 unsigned n_addresses
,
408 int af
, const union in_addr_union
*match
) {
416 for (j
= 0; j
< n_addresses
; j
++) {
417 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
419 if (af
!= AF_UNSPEC
) {
421 if (addresses
[j
].family
!= af
)
424 if (match
&& !in_addr_equal(af
, match
, &addresses
[j
].address
))
428 r
= dns_answer_reserve(answer
, 1);
432 r
= dns_resource_record_new_reverse(&rr
, addresses
[j
].family
, &addresses
[j
].address
, name
);
436 r
= dns_answer_add(*answer
, rr
, addresses
[j
].ifindex
);
444 static int synthesize_system_hostname_rr(DnsQuery
*q
, DnsResourceKey
*key
, DnsAnswer
**answer
) {
445 _cleanup_free_
struct local_address
*addresses
= NULL
;
452 af
= dns_type_to_af(key
->type
);
454 n
= local_addresses(q
->manager
->rtnl
, q
->ifindex
, af
, &addresses
);
459 struct local_address buffer
[2];
461 /* If we have no local addresses then use ::1
462 * and 127.0.0.2 as local ones. */
464 if (af
== AF_INET
|| af
== AF_UNSPEC
)
465 buffer
[n
++] = (struct local_address
) {
467 .ifindex
= SYNTHESIZE_IFINDEX(q
->ifindex
),
468 .address
.in
.s_addr
= htobe32(0x7F000002),
471 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
472 buffer
[n
++] = (struct local_address
) {
474 .ifindex
= SYNTHESIZE_IFINDEX(q
->ifindex
),
475 .address
.in6
= in6addr_loopback
,
478 return answer_add_addresses_rr(answer
, DNS_RESOURCE_KEY_NAME(key
), buffer
, n
);
482 return answer_add_addresses_rr(answer
, DNS_RESOURCE_KEY_NAME(key
), addresses
, n
);
485 static int synthesize_system_hostname_ptr(DnsQuery
*q
, int af
, const union in_addr_union
*address
, DnsAnswer
**answer
) {
486 _cleanup_free_
struct local_address
*addresses
= NULL
;
493 if (af
== AF_INET
&& address
->in
.s_addr
== htobe32(0x7F000002)) {
495 /* Always map the IPv4 address 127.0.0.2 to the local
496 * hostname, in addition to "localhost": */
498 r
= dns_answer_reserve(answer
, 3);
502 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", q
->manager
->llmnr_hostname
, SYNTHESIZE_IFINDEX(q
->ifindex
));
506 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", q
->manager
->mdns_hostname
, SYNTHESIZE_IFINDEX(q
->ifindex
));
510 r
= answer_add_ptr(answer
, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q
->ifindex
));
517 n
= local_addresses(q
->manager
->rtnl
, q
->ifindex
, af
, &addresses
);
521 r
= answer_add_addresses_ptr(answer
, q
->manager
->llmnr_hostname
, addresses
, n
, af
, address
);
525 return answer_add_addresses_ptr(answer
, q
->manager
->mdns_hostname
, addresses
, n
, af
, address
);
528 static int synthesize_gateway_rr(DnsQuery
*q
, DnsResourceKey
*key
, DnsAnswer
**answer
) {
529 _cleanup_free_
struct local_address
*addresses
= NULL
;
536 af
= dns_type_to_af(key
->type
);
538 n
= local_gateways(q
->manager
->rtnl
, q
->ifindex
, af
, &addresses
);
543 return answer_add_addresses_rr(answer
, DNS_RESOURCE_KEY_NAME(key
), addresses
, n
);
546 static int synthesize_gateway_ptr(DnsQuery
*q
, int af
, const union in_addr_union
*address
, DnsAnswer
**answer
) {
547 _cleanup_free_
struct local_address
*addresses
= NULL
;
554 n
= local_gateways(q
->manager
->rtnl
, q
->ifindex
, af
, &addresses
);
558 return answer_add_addresses_ptr(answer
, "gateway", addresses
, n
, af
, address
);
561 static int dns_query_synthesize_reply(DnsQuery
*q
, DnsTransactionState
*state
) {
562 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
569 /* Tries to synthesize localhost RR replies where appropriate */
572 DNS_TRANSACTION_FAILURE
,
573 DNS_TRANSACTION_NO_SERVERS
,
574 DNS_TRANSACTION_TIMEOUT
,
575 DNS_TRANSACTION_ATTEMPTS_MAX_REACHED
))
578 for (i
= 0; i
< q
->question
->n_keys
; i
++) {
579 union in_addr_union address
;
583 if (q
->question
->keys
[i
]->class != DNS_CLASS_IN
&&
584 q
->question
->keys
[i
]->class != DNS_CLASS_ANY
)
587 name
= DNS_RESOURCE_KEY_NAME(q
->question
->keys
[i
]);
589 if (is_localhost(name
)) {
591 r
= synthesize_localhost_rr(q
, q
->question
->keys
[i
], &answer
);
593 return log_error_errno(r
, "Failed to synthesize localhost RRs: %m");
595 } else if (manager_is_own_hostname(q
->manager
, name
)) {
597 r
= synthesize_system_hostname_rr(q
, q
->question
->keys
[i
], &answer
);
599 return log_error_errno(r
, "Failed to synthesize system hostname RRs: %m");
601 } else if (is_gateway_hostname(name
)) {
603 r
= synthesize_gateway_rr(q
, q
->question
->keys
[i
], &answer
);
605 return log_error_errno(r
, "Failed to synthesize gateway RRs: %m");
607 } else if ((dns_name_endswith(name
, "127.in-addr.arpa") > 0 && dns_name_equal(name
, "2.0.0.127.in-addr.arpa") == 0) ||
608 dns_name_equal(name
, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) {
610 r
= synthesize_localhost_ptr(q
, q
->question
->keys
[i
], &answer
);
612 return log_error_errno(r
, "Failed to synthesize localhost PTR RRs: %m");
614 } else if (dns_name_address(name
, &af
, &address
) > 0) {
616 r
= synthesize_system_hostname_ptr(q
, af
, &address
, &answer
);
618 return log_error_errno(r
, "Failed to synthesize system hostname PTR RR: %m");
620 r
= synthesize_gateway_ptr(q
, af
, &address
, &answer
);
622 return log_error_errno(r
, "Failed to synthesize gateway hostname PTR RR: %m");
629 dns_answer_unref(q
->answer
);
633 q
->answer_family
= SYNTHESIZE_FAMILY(q
->flags
);
634 q
->answer_protocol
= SYNTHESIZE_PROTOCOL(q
->flags
);
635 q
->answer_rcode
= DNS_RCODE_SUCCESS
;
637 *state
= DNS_TRANSACTION_SUCCESS
;
642 int dns_query_go(DnsQuery
*q
) {
643 DnsScopeMatch found
= DNS_SCOPE_NO
;
644 DnsScope
*s
, *first
= NULL
;
652 if (q
->state
!= DNS_TRANSACTION_NULL
)
656 assert(q
->question
->n_keys
> 0);
658 name
= dns_question_first_name(q
->question
);
660 LIST_FOREACH(scopes
, s
, q
->manager
->dns_scopes
) {
663 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
667 if (match
== DNS_SCOPE_NO
)
672 if (match
== DNS_SCOPE_YES
) {
676 assert(match
== DNS_SCOPE_MAYBE
);
683 if (found
== DNS_SCOPE_NO
) {
684 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
686 dns_query_synthesize_reply(q
, &state
);
687 dns_query_complete(q
, state
);
691 r
= dns_query_add_transaction_split(q
, first
);
695 LIST_FOREACH(scopes
, s
, first
->scopes_next
) {
698 match
= dns_scope_good_domain(s
, q
->ifindex
, q
->flags
, name
);
705 r
= dns_query_add_transaction_split(q
, s
);
710 q
->answer
= dns_answer_unref(q
->answer
);
712 q
->answer_family
= AF_UNSPEC
;
713 q
->answer_protocol
= _DNS_PROTOCOL_INVALID
;
715 r
= sd_event_add_time(
717 &q
->timeout_event_source
,
718 clock_boottime_or_monotonic(),
719 now(clock_boottime_or_monotonic()) + QUERY_TIMEOUT_USEC
, 0,
720 on_query_timeout
, q
);
724 q
->state
= DNS_TRANSACTION_PENDING
;
727 /* Start the transactions that are not started yet */
728 SET_FOREACH(t
, q
->transactions
, i
) {
729 if (t
->state
!= DNS_TRANSACTION_NULL
)
732 r
= dns_transaction_go(t
);
747 void dns_query_ready(DnsQuery
*q
) {
749 DnsTransactionState state
= DNS_TRANSACTION_NO_SERVERS
;
750 _cleanup_(dns_answer_unrefp
) DnsAnswer
*answer
= NULL
;
752 DnsScope
*scope
= NULL
;
753 bool pending
= false;
757 assert(IN_SET(q
->state
, DNS_TRANSACTION_NULL
, DNS_TRANSACTION_PENDING
));
759 /* Note that this call might invalidate the query. Callers
760 * should hence not attempt to access the query or transaction
761 * after calling this function, unless the block_ready
762 * counter was explicitly bumped before doing so. */
764 if (q
->block_ready
> 0)
767 SET_FOREACH(t
, q
->transactions
, i
) {
769 /* If we found a successful answer, ignore all answers from other scopes */
770 if (state
== DNS_TRANSACTION_SUCCESS
&& t
->scope
!= scope
)
773 /* One of the transactions is still going on, let's maybe wait for it */
774 if (IN_SET(t
->state
, DNS_TRANSACTION_PENDING
, DNS_TRANSACTION_NULL
)) {
779 /* One of the transactions is successful, let's use
780 * it, and copy its data out */
781 if (t
->state
== DNS_TRANSACTION_SUCCESS
) {
785 rcode
= DNS_PACKET_RCODE(t
->received
);
786 a
= t
->received
->answer
;
788 rcode
= t
->cached_rcode
;
792 if (state
== DNS_TRANSACTION_SUCCESS
) {
795 merged
= dns_answer_merge(answer
, a
);
797 dns_query_complete(q
, DNS_TRANSACTION_RESOURCES
);
801 dns_answer_unref(answer
);
804 dns_answer_unref(answer
);
805 answer
= dns_answer_ref(a
);
809 state
= DNS_TRANSACTION_SUCCESS
;
813 /* One of the transactions has failed, let's see
814 * whether we find anything better, but if not, return
815 * its response data */
816 if (state
!= DNS_TRANSACTION_SUCCESS
&& t
->state
== DNS_TRANSACTION_FAILURE
) {
820 rcode
= DNS_PACKET_RCODE(t
->received
);
821 a
= t
->received
->answer
;
823 rcode
= t
->cached_rcode
;
827 dns_answer_unref(answer
);
828 answer
= dns_answer_ref(a
);
831 state
= DNS_TRANSACTION_FAILURE
;
835 if (state
== DNS_TRANSACTION_NO_SERVERS
&& t
->state
!= DNS_TRANSACTION_NO_SERVERS
)
841 /* If so far we weren't successful, and there's
842 * something still pending, then wait for it */
843 if (state
!= DNS_TRANSACTION_SUCCESS
)
846 /* If we already were successful, then only wait for
847 * other transactions on the same scope to finish. */
848 SET_FOREACH(t
, q
->transactions
, i
) {
849 if (t
->scope
== scope
&& IN_SET(t
->state
, DNS_TRANSACTION_PENDING
, DNS_TRANSACTION_NULL
))
854 if (IN_SET(state
, DNS_TRANSACTION_SUCCESS
, DNS_TRANSACTION_FAILURE
)) {
855 q
->answer
= dns_answer_ref(answer
);
856 q
->answer_rcode
= rcode
;
857 q
->answer_protocol
= scope
? scope
->protocol
: _DNS_PROTOCOL_INVALID
;
858 q
->answer_family
= scope
? scope
->family
: AF_UNSPEC
;
861 /* Try to synthesize a reply if we couldn't resolve something. */
862 dns_query_synthesize_reply(q
, &state
);
864 dns_query_complete(q
, state
);
867 static int dns_query_cname_redirect(DnsQuery
*q
, const DnsResourceRecord
*cname
) {
868 _cleanup_(dns_question_unrefp
) DnsQuestion
*nq
= NULL
;
873 q
->n_cname_redirects
++;
874 if (q
->n_cname_redirects
> CNAME_MAX
)
877 r
= dns_question_cname_redirect(q
->question
, cname
, &nq
);
881 dns_question_unref(q
->question
);
886 q
->state
= DNS_TRANSACTION_NULL
;
891 int dns_query_process_cname(DnsQuery
*q
) {
892 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*cname
= NULL
;
893 DnsResourceRecord
*rr
;
898 if (q
->state
!= DNS_TRANSACTION_SUCCESS
)
901 DNS_ANSWER_FOREACH(rr
, q
->answer
) {
903 r
= dns_question_matches_rr(q
->question
, rr
);
907 return 0; /* The answer matches directly, no need to follow cnames */
909 r
= dns_question_matches_cname(q
->question
, rr
);
913 cname
= dns_resource_record_ref(rr
);
917 return 0; /* No cname to follow */
919 if (q
->flags
& SD_RESOLVED_NO_CNAME
)
922 /* OK, let's actually follow the CNAME */
923 r
= dns_query_cname_redirect(q
, cname
);
927 /* Let's see if the answer can already answer the new
928 * redirected question */
929 DNS_ANSWER_FOREACH(rr
, q
->answer
) {
930 r
= dns_question_matches_rr(q
->question
, rr
);
934 return 0; /* It can answer it, yay! */
937 /* OK, it cannot, let's begin with the new query */
942 return 1; /* We return > 0, if we restarted the query for a new cname */
945 static int on_bus_track(sd_bus_track
*t
, void *userdata
) {
946 DnsQuery
*q
= userdata
;
951 log_debug("Client of active query vanished, aborting query.");
952 dns_query_complete(q
, DNS_TRANSACTION_ABORTED
);
956 int dns_query_bus_track(DnsQuery
*q
, sd_bus_message
*m
) {
963 r
= sd_bus_track_new(sd_bus_message_get_bus(m
), &q
->bus_track
, on_bus_track
, q
);
968 r
= sd_bus_track_add_sender(q
->bus_track
, m
);