sip-dig.c 20 KB

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