srv.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * ENUM Support for Asterisk
  3. *
  4. * Copyright (C) 2003 Digium
  5. *
  6. * Written by Mark Spencer <markster@digium.com>
  7. *
  8. * Funding provided by nic.at
  9. *
  10. * Distributed under the terms of the GNU GPL
  11. *
  12. */
  13. #include <sys/types.h>
  14. #include <netinet/in.h>
  15. #include <arpa/nameser.h>
  16. #if __APPLE_CC__ >= 1495
  17. #include <arpa/nameser_compat.h>
  18. #endif
  19. #include <resolv.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <asterisk/channel.h>
  24. #include <asterisk/logger.h>
  25. #include <asterisk/srv.h>
  26. #include <asterisk/dns.h>
  27. #include <asterisk/options.h>
  28. #include <asterisk/utils.h>
  29. #ifdef __APPLE__
  30. #undef T_SRV
  31. #define T_SRV 33
  32. #endif
  33. struct srv {
  34. unsigned short priority;
  35. unsigned short weight;
  36. unsigned short portnum;
  37. } __attribute__ ((__packed__));
  38. static int parse_srv(unsigned char *host, int hostlen, int *portno, unsigned char *answer, int len, unsigned char *msg)
  39. {
  40. int res = 0;
  41. struct srv *srv = (struct srv *)answer;
  42. char repl[256] = "";
  43. if (len < sizeof(struct srv)) {
  44. printf("Length too short\n");
  45. return -1;
  46. }
  47. answer += sizeof(struct srv);
  48. len -= sizeof(struct srv);
  49. if ((res = dn_expand(msg,answer + len,answer, repl, sizeof(repl) - 1)) < 0) {
  50. ast_log(LOG_WARNING, "Failed to expand hostname\n");
  51. return -1;
  52. }
  53. if (res && strcmp(repl, ".")) {
  54. if (option_verbose > 3)
  55. ast_verbose( VERBOSE_PREFIX_3 "parse_srv: SRV mapped to host %s, port %d\n", repl, ntohs(srv->portnum));
  56. if (host) {
  57. strncpy(host, repl, hostlen - 1);
  58. host[hostlen-1] = '\0';
  59. }
  60. if (portno)
  61. *portno = ntohs(srv->portnum);
  62. return(0);
  63. }
  64. return(-1);
  65. }
  66. struct srv_context {
  67. char *host;
  68. int hostlen;
  69. int *port;
  70. };
  71. static int srv_callback(void *context, u_char *answer, int len, u_char *fullanswer)
  72. {
  73. struct srv_context *c = (struct srv_context *)context;
  74. if (parse_srv(c->host, c->hostlen, c->port, answer, len, fullanswer)) {
  75. ast_log(LOG_WARNING, "Failed to parse srv\n");
  76. return -1;
  77. }
  78. if (!ast_strlen_zero(c->host))
  79. return 1;
  80. return 0;
  81. }
  82. int ast_get_srv(struct ast_channel *chan, char *host, int hostlen, int *port, const char *service)
  83. {
  84. struct srv_context context;
  85. int ret;
  86. context.host = host;
  87. context.hostlen = hostlen;
  88. context.port = port;
  89. if (chan && ast_autoservice_start(chan) < 0)
  90. return -1;
  91. ret = ast_search_dns(&context, service, C_IN, T_SRV, srv_callback);
  92. if (chan)
  93. ret |= ast_autoservice_stop(chan);
  94. if (ret <= 0) {
  95. host[0] = '\0';
  96. *port = -1;
  97. return ret;
  98. }
  99. return ret;
  100. }