2
0

sip-dig.c 20 KB

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