1 /*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2006 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library 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.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25 /**
26 * This is an example program for @b sresolv library in synchronous mode.
27 *
28 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
29 *
30 * @date Original Created: Tue Jul 16 18:50:14 2002 ppessi
31 */
32
33 /**@page sip-dig Resolve SIP URIs.
34 *
35 * @section sip_dig_synopsis Synopsis
36 * <tt>sip-dig [OPTIONS] uri...</tt>
37 *
38 * @section sip_dig_description Description
39 * The @em sip-dig utility resolves SIP URIs as described in @RFC3263. It
40 * queries NAPTR, SRV and A/AAAA records and prints out the resulting
41 * transport addresses.
42 *
43 * The default transports are: UDP, TCP, SCTP, TLS and TLS-SCTP. The SIPS
44 * URIs are resolved using only TLS transports, TLS and TLS-SCTP. If not
45 * otherwise indicated by NAPTR or SRV records, the sip-dig uses UDP and TCP
46 * as transports for SIP and TLS for SIPS URIs.
47 *
48 * The results are printed intended, with a preference followed by weight,
49 * then protocol name, port number and IP address in numeric format.
50 *
51 * @section sip_dig_options Command Line Options
52 * The @e sip-dig utility accepts following command line options:
53 * <dl>
54 * <dt>-p <em>protoname</em></dt>
55 * <dd>Use named transport protocol. The <em>protoname</em> can be either
56 * well-known, e.g., "udp", or it can specify NAPTR service and SRV
57 * identifier, e.g., "tls-udp/SIPS+D2U/_sips._udp.".
58 * </dd>
59 * <dt>--udp</dt>
60 * <dd>Use UDP transport protocol.
61 * </dd>
62 * <dt>--tcp</dt>
63 * <dd>Use TCP transport protocol.
64 * </dd>
65 * <dt>--tls</dt>
66 * <dd>Use TLS over TCP transport protocol.
67 * </dd>
68 * <dt>--sctp</dt>
69 * <dd>Use SCTP transport protocol.
70 * </dd>
71 * <dt>--tls-sctp</dt>
72 * <dd>Use TLS over SCTP transport protocol.
73 * </dd>
74 * <dt>--no-sctp</dt>
75 * <dd>Ignore SCTP or TLS-SCTP records in the list of default transports.
76 * This option has no effect if transport protocols has been explicitly
77 * listed.
78 * </dd>
79 * <dt>-4</dt>
80 * <dd>Query IP4 addresses (A records)
81 * </dd>
82 * <dt>-6</dt>
83 * <dd>Query IP6 addresses (AAAA records).
84 * </dd>
85 * <dt>-v</dt>
86 * <dd>Be verbatim.
87 * </dd>
88 * <dt></dt>
89 * <dd>
90 * </dd>
91 * </dl>
92 *
93 * @section sip_dig_return Return Codes
94 * <table>
95 * <tr><td>0<td>when successful (a 2XX-series response is received)
96 * <tr><td>1<td>when unsuccessful (a 3XX..6XX-series response is received)
97 * <tr><td>2<td>initialization failure
98 * </table>
99 *
100 * @section sip_dig_examples Examples
101 *
102 * Resolve sip:openlaboratory.net, prefer TLS over TCP, TCP over UDP:
103 * @code
104 * $ sip-dig --tls --tcp --udp sip:openlaboratory.net
105 * 1 0.333 tls 5061 212.213.221.127
106 * 2 0.333 tcp 5060 212.213.221.127
107 * 3 0.333 udp 5060 212.213.221.127
108 * @endcode
109 *
110 * Resolve sips:example.net with TLS over SCTP (TLS-SCTP) and TLS:
111 * @code
112 * $ sip-dig -p tls-sctp --tls sips:example.net
113 * 1 0.500 tls-udp 5061 172.21.55.26
114 * 2 0.500 tls 5061 172.21.55.26
115 * @endcode
116 *
117 * @section sip_dig_environment Environment
118 * #SRESOLV_DEBUG, SRESOLV_CONF
119 *
120 * @section sip_dig_bugs Reporting Bugs
121 * Report bugs to <sofia-sip-devel@lists.sourceforge.net>.
122 *
123 * @section sip_dig_author Author
124 * Written by Pekka Pessi <pekka -dot pessi -at- nokia -dot- com>
125 *
126 * @section sip_dig_copyright Copyright
127 * Copyright (C) 2006 Nokia Corporation.
128 *
129 * This program is free software; see the source for copying conditions.
130 * There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
131 * PARTICULAR PURPOSE.
132 */
133
134 #include "config.h"
135
136 #include "sofia-sip/su.h"
137
138 #include "sofia-resolv/sres.h"
139 #include "sofia-resolv/sres_record.h"
140
141 #include "sofia-sip/url.h"
142 #include "sofia-sip/su_alloc.h"
143 #include "sofia-sip/su_string.h"
144 #include "sofia-sip/hostdomain.h"
145
146 char const name[] = "sip-dig";
147
148 #include <assert.h>
149 #include <stdlib.h>
150 #include <string.h>
151 #include <stdio.h>
152
153 enum { N_TPORT = 16 };
154
155 struct transport { char const *name, *service, *srv; };
156
157 struct dig {
158 sres_resolver_t *sres;
159
160 unsigned preference, ip4, ip6, sips, print;
161
162 struct transport tports[N_TPORT + 1];
163 };
164
165 int dig_naptr(struct dig *dig, char const *host, double weight);
166
167 int dig_all_srvs(struct dig *dig, char const *tport, char const *host,
168 double weight);
169
170 int dig_srv(struct dig *dig, char const *tport, char const *host,
171 double weight);
172
173 int dig_srv_at(struct dig *dig,
174 char const *tport, sres_record_t **answers,
175 double weight, int pweight,
176 int priority);
177
178 int dig_addr(struct dig *dig,
179 char const *tport, char const *host, char const *port,
180 double weight);
181
182 void print_addr_results(struct transport const *tports,
183 char const *tport, char const *tport2,
184 sres_record_t **answers, int type, int af,
185 char const *port,
186 double weight, int preference);
187
188 void print_result(char const *addr, char const *port, char const *tport,
189 double weight,
190 unsigned preference);
191
192 int prepare_transport(struct dig *dig, char const *tport);
193
194 int count_transports(struct dig *dig,
195 char const *tp1,
196 char const *tp2);
197
usage(int exitcode)198 void usage(int exitcode)
199 {
200 fprintf(stderr, "usage: %s [OPTIONS] [@dnsserver] uri\n", name);
201 exit(exitcode);
202 }
203
main(int argc,char * argv[])204 int main(int argc, char *argv[])
205 {
206 int exitcode = 0;
207 int o_sctp = 1, o_tls_sctp = 1, o_verbatim = 1;
208 int family = 0, multiple = 0;
209 /*
210 char const *dnsserver = NULL;
211 */
212 char const *string;
213 url_t *uri = NULL;
214
215 char const *host;
216 char const *port;
217 char *transport = NULL, tport[32];
218
219 struct dig dig[1] = {{ NULL }};
220
221 if (su_init() != 0)
222 return -1;
223
224 while (argv[1] && argv[1][0] == '-') {
225 if (strcmp(argv[1], "-v") == 0)
226 o_verbatim++;
227 else if (strcmp(argv[1], "-6") == 0)
228 dig->ip6 = ++family;
229 else if (strcmp(argv[1], "-4") == 0)
230 dig->ip4 = ++family;
231 else if (strncmp(argv[1], "-p", 2) == 0) {
232 char const *proto;
233
234 if (argv[1][2] == '=')
235 proto = argv[1] + 3;
236 else if (argv[1][2])
237 proto = argv[1] + 2;
238 else
239 proto = argv++[2];
240
241 if (proto == NULL)
242 usage(2);
243
244 if (prepare_transport(dig, proto) < 0)
245 exit(2);
246 }
247 else if (strcmp(argv[1], "--udp") == 0)
248 prepare_transport(dig, "udp");
249 else if (strcmp(argv[1], "--tcp") == 0)
250 prepare_transport(dig, "tcp");
251 else if (strcmp(argv[1], "--tls") == 0)
252 prepare_transport(dig, "tls");
253 else if (strcmp(argv[1], "--sctp") == 0)
254 prepare_transport(dig, "sctp");
255 else if (strcmp(argv[1], "--tls-sctp") == 0)
256 prepare_transport(dig, "tls-sctp");
257 else if (strcmp(argv[1], "--tls-udp") == 0)
258 prepare_transport(dig, "tls-udp");
259 else if (strcmp(argv[1], "--no-sctp") == 0)
260 o_sctp = 0, o_tls_sctp = 0;
261 else if (strcmp(argv[1], "--help") == 0)
262 usage(0);
263 else if (strcmp(argv[1], "-h") == 0)
264 usage(0);
265 else if (strcmp(argv[1], "-?") == 0)
266 usage(0);
267 else if (strcmp(argv++[1], "-") == 0)
268 break;
269 else
270 usage(2);
271 argv++;
272 }
273
274 if (!family)
275 dig->ip4 = 1, dig->ip6 = 2;
276
277 /*
278 if (argv[1] && argv[1][0] == '@')
279 dnsserver = argv++[1] + 1;
280 */
281
282 if (!argv[1])
283 usage(2);
284
285 multiple = argv[1] && argv[2];
286
287 if (!count_transports(dig, NULL, NULL)) {
288 prepare_transport(dig, "udp");
289 prepare_transport(dig, "tcp");
290 if (o_sctp)
291 prepare_transport(dig, "sctp");
292 prepare_transport(dig, "tls");
293 if (o_tls_sctp)
294 prepare_transport(dig, "tls-sctp");
295 }
296
297 dig->sres = sres_resolver_new(getenv("SRESOLV_CONF"));
298 if (!dig->sres)
299 perror("sres_resolver_new"), exit(1);
300
301 for (; (string = argv[1]); argv++) {
302 if (multiple)
303 puts(string);
304
305 uri = url_hdup(NULL, (void *)string);
306
307 if (uri && uri->url_type == url_unknown)
308 url_sanitize(uri);
309
310 if (uri && uri->url_type == url_any)
311 continue;
312
313 if (!uri || (uri->url_type != url_sip && uri->url_type != url_sips)) {
314 fprintf(stderr, "%s: invalid uri\n", string);
315 exitcode = 1;
316 continue;
317 }
318
319 port = url_port(uri);
320 if (port && !port[0]) port = NULL;
321 if (url_param(uri->url_params, "transport=", tport, sizeof tport) > 0)
322 transport = tport;
323
324 host = uri->url_host;
325
326 if (host_is_ip_address(host)) {
327 if (transport) {
328 print_result(host, port, transport, 1.0, 1);
329 }
330 else if (uri->url_type == url_sips) {
331 print_result(host, port, "tls", 1.0, 1);
332 }
333 else {
334 print_result(host, port, "udp", 1.0, 1);
335 print_result(host, port, "tcp", 1.0, 2);
336 }
337 continue;
338 }
339
340 if (!host_is_domain(host)) {
341 fprintf(stderr, "%s: invalid host\n", string);
342 exitcode = 1;
343 continue;
344 }
345
346 dig->sips = uri->url_type == url_sips;
347 dig->preference = 1;
348
349 if (!port && !transport && dig_naptr(dig, host, 1.0))
350 continue /* resolved naptr */;
351 else if (!port && dig_all_srvs(dig, transport, host, 1.0))
352 continue /* resolved srv */;
353 else if (dig_addr(dig, transport, host, port, 1.0))
354 continue /* resolved a/aaaa */;
355
356 fprintf(stderr, "%s: not found\n", string);
357 exitcode = 1;
358 }
359
360 sres_resolver_unref(dig->sres);
361
362 return exitcode;
363 }
364
365
transport_is_secure(char const * tportname)366 int transport_is_secure(char const *tportname)
367 {
368 return su_casenmatch(tportname, "tls", 3);
369 }
370
prepare_transport(struct dig * dig,char const * tport)371 int prepare_transport(struct dig *dig, char const *tport)
372 {
373 struct transport *tports = dig->tports;
374 int j;
375
376 for (j = 0; j < N_TPORT; j++) {
377 if (!tports[j].name)
378 break;
379 if (su_casematch(tports[j].name, tport))
380 return 1;
381 }
382
383 if (j == N_TPORT)
384 return 0;
385
386 if (strchr(tport, '/')) {
387 char *service = strchr(tport, '/');
388 char *srv = strchr(service + 1, '/');
389
390 if (!srv || srv[strlen(srv) - 1] != '.') {
391 fprintf(stderr, "%s: invalid transport specifier \"%s\"\n", name, tport);
392 fputs(
393 "\tspecifier should have name/service/srv-id\n"
394 "\twhere name is protocol name (e.g, \"tls-udp\")\n"
395 "\t service specifies service as per RFC 2915 (e.g., \"SIPS+D2U\")\n"
396 "\t srv-id is prefix for SRV lookup (e.g., \"_sips._udp.\")\n",
397 stderr);
398 if (srv)
399 fputs("\t and it should end with a dot \".\"\n", stderr);
400 return -1;
401 }
402
403 *service++ = '\0', *srv++ = '\0';
404
405 tports[j].name = tport,
406 tports[j].service = service;
407 tports[j].srv = srv;
408 }
409 else if (su_casematch(tport, "udp")) {
410 tports[j].name = "udp";
411 tports[j].service = "SIP+D2U";
412 tports[j].srv = "_sip._udp.";
413 }
414 else if (su_casematch(tport, "tcp")) {
415 tports[j].name = "tcp";
416 tports[j].service = "SIP+D2T";
417 tports[j].srv = "_sip._tcp.";
418 }
419 else if (su_casematch(tport, "tls")) {
420 tports[j].name = "tls";
421 tports[j].service = "SIPS+D2T";
422 tports[j].srv = "_sips._tcp.";
423 }
424 else if (su_casematch(tport, "sctp")) {
425 tports[j].name = "sctp";
426 tports[j].service = "SIP+D2S";
427 tports[j].srv = "_sip._sctp.";
428 }
429 else if (su_casematch(tport, "tls-sctp")) {
430 tports[j].name = "tls-sctp";
431 tports[j].service = "SIPS+D2S";
432 tports[j].srv = "_sips._sctp.";
433 }
434 else {
435 fprintf(stderr, "%s: unknown transport \"%s\"\n", name, tport);
436 return -1;
437 }
438
439 j++;
440
441 tports[j].service = tports[j].srv = tports[j].name = NULL;
442
443 return 1;
444 }
445
446 int
count_transports(struct dig * dig,char const * tport,char const * tport2)447 count_transports(struct dig *dig,
448 char const *tport,
449 char const *tport2)
450 {
451
452 int i, tcount = 0;
453 struct transport const *tports = dig->tports;
454
455 for (i = 0; tports[i].name; i++) {
456 if (dig->sips && !transport_is_secure(tports[i].name))
457 continue;
458 if (!tport || su_casematch(tport, tports[i].name))
459 tcount++;
460 else if (tport2 && su_casematch(tport2, tports[i].name))
461 tcount++;
462 }
463
464 return tcount;
465 }
466
467 struct transport const *
transport_by_service(struct transport const * tports,char const * s)468 transport_by_service(struct transport const *tports, char const *s)
469 {
470 int i;
471
472 for (i = 0; tports[i].name; i++) {
473 if (su_casematch(tports[i].service, s))
474 return tports + i;
475 }
476
477 return NULL;
478 }
479
dig_naptr(struct dig * dig,char const * host,double weight)480 int dig_naptr(struct dig *dig,
481 char const *host,
482 double weight)
483 {
484 sres_record_t **answers = NULL;
485 struct transport const *tp;
486 int i, error;
487 int order = 0, count = 0, nacount = 0, scount = 0;
488
489 error = sres_blocking_query(dig->sres, sres_type_naptr, host, 0, &answers);
490 if (error < 0)
491 return 0;
492
493 /* Sort by priority */
494 sres_sort_answers(dig->sres, answers);
495
496 /* Count number of matching naptrs */
497 for (i = 0; answers[i]; i++) {
498 sres_naptr_record_t const *na = answers[i]->sr_naptr;
499
500 if (na->na_record->r_type != sres_type_naptr || na->na_record->r_status)
501 continue;
502
503 if (dig->print)
504 printf("%s\n\t%d IN NAPTR %u %u \"%s\" \"%s\" \"%s\" %s\n",
505 na->na_record->r_name, na->na_record->r_ttl,
506 na->na_order, na->na_prefer,
507 na->na_flags, na->na_services,
508 na->na_regexp, na->na_replace);
509
510 if (!su_casematch(na->na_flags, "s") && !su_casematch(na->na_flags, "a"))
511 continue;
512
513 if (nacount && order != na->na_order)
514 continue;
515
516 if (dig->sips && !su_casenmatch(na->na_services, "SIPS+", 5))
517 continue;
518
519 if (!transport_by_service(dig->tports, na->na_services))
520 continue;
521
522 order = na->na_order, nacount++;
523 }
524
525 if (nacount == 0) {
526 sres_free_answers(dig->sres, answers);
527 return 0;
528 }
529
530 for (i = 0; answers[i]; i++) {
531 sres_naptr_record_t const *na = answers[i]->sr_naptr;
532
533 if (na->na_record->r_type != sres_type_naptr || na->na_record->r_status)
534 continue;
535 if (order != na->na_order)
536 continue;
537 if (!su_casematch(na->na_flags, "s") && !su_casematch(na->na_flags, "a"))
538 continue;
539 if (dig->sips && !su_casenmatch(na->na_services, "SIPS+", 5))
540 continue;
541
542 tp = transport_by_service(dig->tports, na->na_services);
543 if (!tp)
544 continue;
545
546 if (su_casematch(na->na_flags, "s")) {
547 scount = dig_srv(dig, tp->name, na->na_replace, weight / nacount);
548 }
549 else if (su_casematch(na->na_flags, "a")) {
550 scount = dig_addr(dig, tp->name, na->na_replace, NULL, weight / nacount);
551 }
552 else
553 scount = 0;
554
555 count += scount;
556 }
557
558 return count;
559 }
560
dig_all_srvs(struct dig * dig,char const * tport,char const * host,double weight)561 int dig_all_srvs(struct dig *dig,
562 char const *tport,
563 char const *host,
564 double weight)
565 {
566 int i, j, n;
567 int tcount, count = 0, scount;
568 char *domain;
569
570 struct {
571 char const *proto; sres_record_t **answers;
572 } srvs[N_TPORT + 1] = {{ NULL }};
573
574 tcount = count_transports(dig, tport, NULL);
575 if (!tcount)
576 return 0;
577
578 for (i = 0, n = 0; dig->tports[i].name; i++) {
579 if (tport && !su_casematch(dig->tports[i].name, tport))
580 continue;
581
582 if (dig->sips && !transport_is_secure(dig->tports[i].name))
583 continue;
584
585 domain = su_strcat(NULL, dig->tports[i].srv, host);
586
587 if (domain) {
588 if (sres_blocking_query(dig->sres, sres_type_srv, domain, 0,
589 &srvs[n].answers) >= 0) {
590 srvs[n++].proto = dig->tports[i].name;
591 }
592 free(domain);
593 }
594 }
595
596 if (n == 0)
597 return 0;
598
599 for (i = 0; i < n; i++) {
600 unsigned priority = 0, pweight = 0, m = 0;
601 sres_record_t **answers = srvs[i].answers;
602 char const *tport = srvs[i].proto;
603
604 for (j = 0; answers[j]; j++) {
605 sres_srv_record_t const *srv = answers[j]->sr_srv;
606
607 if (srv->srv_record->r_type != sres_type_srv)
608 continue;
609 if (srv->srv_record->r_status != 0)
610 continue;
611
612 if (srv->srv_priority != priority && pweight != 0) {
613 scount = dig_srv_at(dig, tport, answers, weight / n, pweight,
614 priority);
615 if (scount) dig->preference++;
616 count += scount;
617 pweight = 0, m = 0;
618 }
619
620 priority = srv->srv_priority, pweight += srv->srv_weight, m++;
621 }
622
623 if (m) {
624 scount = dig_srv_at(dig, tport, answers, weight / n, pweight, priority);
625 if (scount)
626 dig->preference++;
627 count += scount;
628 }
629 }
630
631 return count;
632 }
633
dig_srv(struct dig * dig,char const * tport,char const * domain,double weight)634 int dig_srv(struct dig *dig,
635 char const *tport,
636 char const *domain,
637 double weight)
638 {
639 sres_record_t **answers = NULL;
640 int j, n, error;
641 int count = 0, scount = 0;
642
643 uint32_t priority, pweight;
644
645 assert(tport && domain);
646
647 error = sres_blocking_query(dig->sres, sres_type_srv, domain, 0, &answers);
648 if (error < 0)
649 return 0;
650
651 /* Sort by priority */
652 sres_sort_answers(dig->sres, answers);
653
654 priority = 0; pweight = 0; n = 0;
655
656 for (j = 0; answers[j]; j++) {
657 sres_srv_record_t const *srv = answers[j]->sr_srv;
658
659 if (srv->srv_record->r_type != sres_type_srv)
660 continue;
661 if (srv->srv_record->r_status != 0)
662 continue;
663
664 if (srv->srv_priority != priority && pweight != 0) {
665 scount = dig_srv_at(dig, tport, answers, weight, pweight,
666 priority);
667 if (scount) dig->preference++;
668 count += scount;
669 pweight = 0, n = 0;
670 }
671
672 priority = srv->srv_priority, pweight += srv->srv_weight, n++;
673 }
674
675 if (n) {
676 scount = dig_srv_at(dig, tport, answers, weight, pweight, priority);
677 if (scount) dig->preference++;
678 count += scount;
679 }
680
681 sres_free_answers(dig->sres, answers);
682
683 return count;
684 }
685
dig_srv_at(struct dig * dig,char const * tport,sres_record_t ** answers,double weight,int pweight,int priority)686 int dig_srv_at(struct dig *dig,
687 char const *tport,
688 sres_record_t **answers,
689 double weight, int pweight,
690 int priority)
691 {
692 int count = 0;
693 int i;
694 char port[8];
695
696 if (pweight == 0)
697 pweight = 1;
698
699 for (i = 0; answers[i]; i++) {
700 sres_srv_record_t const *srv = answers[i]->sr_srv;
701 if (srv->srv_record->r_type != sres_type_srv)
702 continue;
703 if (srv->srv_record->r_status != 0)
704 continue;
705 if (srv->srv_priority != priority)
706 continue;
707 snprintf(port, sizeof port, "%u", srv->srv_port);
708
709 count += dig_addr(dig, tport, srv->srv_target, port,
710 weight * srv->srv_weight / pweight);
711 }
712
713 return count;
714 }
715
dig_addr(struct dig * dig,char const * tport,char const * host,char const * port,double weight)716 int dig_addr(struct dig *dig,
717 char const *tport,
718 char const *host,
719 char const *port,
720 double weight)
721 {
722 int error, i;
723 char const *tport2 = NULL;
724 sres_record_t **answers1 = NULL, **answers2 = NULL;
725 unsigned count1 = 0, count2 = 0, tcount = 0;
726 int type1 = 0, type2 = 0, family1 = 0, family2 = 0;
727
728 if (dig->ip6 > dig->ip4) {
729 type1 = sres_type_aaaa, family1 = AF_INET6;
730 if (dig->ip4)
731 type2 = sres_type_a, family2 = AF_INET;
732 }
733 else {
734 type1 = sres_type_a, family1 = AF_INET;
735 if (dig->ip6)
736 type2 = sres_type_aaaa, family2 = AF_INET6;
737 }
738
739 if (tport == NULL) {
740 if (dig->sips)
741 tport = "tls";
742 else
743 tport = "udp", tport2 = "tcp";
744 }
745
746 tcount = count_transports(dig, tport, tport2);
747 if (!tcount)
748 return 0;
749
750 if (type1) {
751 error = sres_blocking_query(dig->sres, type1, host, 0, &answers1);
752 if (error >= 0)
753 for (i = 0; answers1[i]; i++) {
754 sres_common_t *r = answers1[i]->sr_record;
755 count1 += r->r_type == type1 && r->r_status == 0;
756 }
757 }
758
759 if (type2) {
760 error = sres_blocking_query(dig->sres, type2, host, 0, &answers2);
761 if (error >= 0)
762 for (i = 0; answers2[i]; i++) {
763 sres_common_t *r = answers2[i]->sr_record;
764 count2 += r->r_type == type2 && r->r_status == 0;
765 }
766 }
767
768 if (count1 + count2) {
769 double w = weight / (count1 + count2) / tcount;
770
771 if (count1)
772 print_addr_results(dig->tports, tport, tport2,
773 answers1, type1, family1, port,
774 w, dig->preference);
775 if (count2)
776 print_addr_results(dig->tports, tport, tport2,
777 answers2, type2, family2, port,
778 w, dig->preference);
779 }
780
781 sres_free_answers(dig->sres, answers1);
782 sres_free_answers(dig->sres, answers2);
783
784 return count1 + count2;
785 }
786
787 void
print_addr_results(struct transport const * tports,char const * tport,char const * tport2,sres_record_t ** answers,int type,int af,char const * port,double weight,int preference)788 print_addr_results(struct transport const *tports,
789 char const *tport, char const *tport2,
790 sres_record_t **answers, int type, int af,
791 char const *port,
792 double weight, int preference)
793 {
794 int i, j;
795 char addr[64];
796
797 for (i = 0; answers[i]; i++) {
798 if (answers[i]->sr_record->r_type != type)
799 continue;
800 if (answers[i]->sr_record->r_status != 0)
801 continue;
802
803 su_inet_ntop(af, &answers[i]->sr_a->a_addr, addr, sizeof addr);
804
805 for (j = 0; tports[j].name; j++) {
806 if (su_casematch(tport, tports[j].name))
807 print_result(addr, port, tport, weight, preference);
808 if (su_casematch(tport2, tports[j].name))
809 print_result(addr, port, tport2, weight, preference);
810 }
811 }
812 }
813
print_result(char const * addr,char const * port,char const * tport,double weight,unsigned preference)814 void print_result(char const *addr,
815 char const *port,
816 char const *tport,
817 double weight,
818 unsigned preference)
819 {
820 if (!port || !port[0])
821 port = transport_is_secure(tport) ? "5061" : "5060";
822
823 printf("\t%u %.3f %s %s %s\n", preference, weight, tport, port, addr);
824 }
825