blob: 65ed350e4f36481f63c9c7e7c78180598e65731a [file] [log] [blame]
James Kuszmaul4a42b182021-01-17 11:32:46 -08001#include "resolver.h"
2#include "address.h"
3#include "server.h"
4#include <rawrtc/config.h>
5#include <rawrtcc/code.h>
6#include <rawrtcc/utils.h>
7#include <re.h>
8
9#define DEBUG_MODULE "ice-server-url-resolver"
10//#define RAWRTC_DEBUG_MODULE_LEVEL 7 // Note: Uncomment this to debug this module only
11#include <rawrtcc/debug.h>
12
13/*
14 * DNS A or AAAA record handler.
15 */
16static bool dns_record_result_handler(struct dnsrr* resource_record, void* arg) {
17 struct rawrtc_ice_server_url_resolver* const resolver = arg;
18 struct rawrtc_ice_server_url* const url = resolver->url;
19 struct sa address;
20 enum rawrtc_code error;
21 struct rawrtc_ice_server_url_address* url_address;
22 bool stop;
23 DEBUG_PRINTF("DNS resource record: %H\n", dns_rr_print, resource_record);
24
25 // Set IP address
26 sa_cpy(&address, &url->resolved_address);
27 switch (resource_record->type) {
28 case DNS_TYPE_A:
29 // Set IPv4 address
30 sa_set_in(&address, resource_record->rdata.a.addr, sa_port(&address));
31 break;
32
33 case DNS_TYPE_AAAA:
34 // Set IPv6 address
35 sa_set_in6(&address, resource_record->rdata.aaaa.addr, sa_port(&address));
36 break;
37
38 default:
39 DEBUG_WARNING(
40 "Invalid DNS resource record, expected A/AAAA record, got: %H\n", dns_rr_print,
41 resource_record);
42 return true; // stop traversing
43 }
44
45 // Create URL address
46 error = rawrtc_ice_server_url_address_create(&url_address, url, &address);
47 if (error) {
48 DEBUG_WARNING(
49 "Unable to create ICE server URL address, reason: %s\n", rawrtc_code_to_str(error));
50 return true; // stop traversing
51 }
52
53 // Announce resolved IP address
54 stop = resolver->address_handler(url_address, resolver->arg);
55
56 // Un-reference
57 mem_deref(url_address);
58
59 // Done (continue or stop traversing)
60 return stop;
61}
62
63/*
64 * DNS query result handler.
65 */
66static void dns_query_handler(
67 int err,
68 struct dnshdr const* header,
69 struct list* answer_records,
70 struct list* authoritive_records,
71 struct list* additional_records,
72 void* arg) {
73 struct rawrtc_ice_server_url_resolver* const resolver = arg;
74 (void) header;
75 (void) authoritive_records;
76 (void) additional_records;
77
78 // Handle error (if any)
79 if (err) {
80 DEBUG_WARNING("Could not query DNS record for '%r', reason: %m\n", &resolver->url->host);
81 goto out;
82 } else if (header->rcode != 0) {
83 DEBUG_NOTICE(
84 "DNS record query for '%r' unsuccessful: %s (%" PRIu8 ")\n", &resolver->url->host,
85 dns_hdr_rcodename(header->rcode), header->rcode);
86 goto out;
87 }
88
89 // Unlink self from any list
90 list_unlink(&resolver->le);
91
92 // Handle A or AAAA record
93 dns_rrlist_apply2(
94 answer_records, NULL, DNS_TYPE_A, DNS_TYPE_AAAA, DNS_CLASS_IN, true,
95 dns_record_result_handler, resolver);
96
97out:
98 // Unlink & un-reference self
99 // Note: We're unlinking twice here since the above unlink may be skipped in an error case.
100 // This is perfectly safe.
101 list_unlink(&resolver->le);
102 mem_deref(resolver);
103}
104
105/*
106 * Destructor for an ICE server URL.
107 */
108static void rawrtc_ice_server_url_resolver_destroy(void* arg) {
109 struct rawrtc_ice_server_url_resolver* const resolver = arg;
110
111 // Remove from list
112 list_unlink(&resolver->le);
113
114 // Un-reference
115 mem_deref(resolver->dns_query);
116 mem_deref(resolver->url);
117}
118
119/*
120 * Create an ICE server URL resolver.
121 *
122 * Important: Once the handler has been called, the resolver will unlink
123 * from an associated list and un-reference itself.
124 */
125enum rawrtc_code rawrtc_ice_server_url_resolver_create(
126 struct rawrtc_ice_server_url_resolver** const resolverp, // de-referenced
127 struct dnsc* const dns_client,
128 uint_fast16_t const dns_type,
129 struct rawrtc_ice_server_url* const url, // referenced
130 rawrtc_ice_server_url_address_resolved_handler address_handler,
131 void* const arg) {
132 enum rawrtc_code error;
133 struct rawrtc_ice_server_url_resolver* resolver;
134 char* host_str;
135
136 // Check arguments
137 if (!resolverp || !dns_client || !url || !address_handler) {
138 return RAWRTC_CODE_INVALID_ARGUMENT;
139 }
140
141 // Allocate
142 resolver = mem_zalloc(sizeof(*resolver), rawrtc_ice_server_url_resolver_destroy);
143 if (!resolver) {
144 return RAWRTC_CODE_NO_MEMORY;
145 }
146
147 // Set fields/reference
148 resolver->url = mem_ref(url);
149 resolver->address_handler = address_handler;
150 resolver->arg = arg;
151 resolver->dns_type = dns_type;
152
153 // Copy URL to str
154 error = rawrtc_error_to_code(pl_strdup(&host_str, &url->host));
155 if (error) {
156 goto out;
157 }
158
159 // Query A or AAAA record
160 error = rawrtc_error_to_code(dnsc_query(
161 &resolver->dns_query, dns_client, host_str, (uint16_t) dns_type, DNS_CLASS_IN, true,
162 dns_query_handler, resolver));
163 if (error) {
164 goto out;
165 }
166
167 // Done
168 error = RAWRTC_CODE_SUCCESS;
169
170out:
171 // Un-reference
172 mem_deref(host_str);
173
174 if (error) {
175 mem_deref(resolver);
176 } else {
177 // Set pointer & done
178 *resolverp = resolver;
179 }
180
181 return error;
182}