00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 40722 $")
00035
00036 #include <sys/types.h>
00037 #include <netinet/in.h>
00038 #include <arpa/nameser.h>
00039 #if __APPLE_CC__ >= 1495
00040 #include <arpa/nameser_compat.h>
00041 #endif
00042 #include <resolv.h>
00043 #include <stdio.h>
00044 #include <string.h>
00045 #include <unistd.h>
00046
00047 #include "asterisk/channel.h"
00048 #include "asterisk/logger.h"
00049 #include "asterisk/srv.h"
00050 #include "asterisk/dns.h"
00051 #include "asterisk/options.h"
00052 #include "asterisk/utils.h"
00053
00054 #ifdef __APPLE__
00055 #undef T_SRV
00056 #define T_SRV 33
00057 #endif
00058
00059 struct srv {
00060 unsigned short priority;
00061 unsigned short weight;
00062 unsigned short portnum;
00063 } __attribute__ ((__packed__));
00064
00065 static int parse_srv(char *host, int hostlen, int *portno, unsigned char *answer, int len, unsigned char *msg)
00066 {
00067 int res = 0;
00068 struct srv *srv = (struct srv *)answer;
00069 char repl[256] = "";
00070
00071 if (len < sizeof(struct srv)) {
00072 printf("Length too short\n");
00073 return -1;
00074 }
00075 answer += sizeof(struct srv);
00076 len -= sizeof(struct srv);
00077
00078 if ((res = dn_expand(msg, answer + len, answer, repl, sizeof(repl) - 1)) < 0) {
00079 ast_log(LOG_WARNING, "Failed to expand hostname\n");
00080 return -1;
00081 }
00082 if (res && strcmp(repl, ".")) {
00083 if (option_verbose > 3)
00084 ast_verbose( VERBOSE_PREFIX_3 "parse_srv: SRV mapped to host %s, port %d\n", repl, ntohs(srv->portnum));
00085 if (host) {
00086 ast_copy_string(host, repl, hostlen);
00087 host[hostlen-1] = '\0';
00088 }
00089 if (portno)
00090 *portno = ntohs(srv->portnum);
00091 return 0;
00092 }
00093 return -1;
00094 }
00095
00096 struct srv_context {
00097 char *host;
00098 int hostlen;
00099 int *port;
00100 };
00101
00102 static int srv_callback(void *context, unsigned char *answer, int len, unsigned char *fullanswer)
00103 {
00104 struct srv_context *c = (struct srv_context *)context;
00105
00106 if (parse_srv(c->host, c->hostlen, c->port, answer, len, fullanswer)) {
00107 ast_log(LOG_WARNING, "Failed to parse srv\n");
00108 return -1;
00109 }
00110
00111 if (!ast_strlen_zero(c->host))
00112 return 1;
00113
00114 return 0;
00115 }
00116
00117 int ast_get_srv(struct ast_channel *chan, char *host, int hostlen, int *port, const char *service)
00118 {
00119 struct srv_context context;
00120 int ret;
00121
00122 context.host = host;
00123 context.hostlen = hostlen;
00124 context.port = port;
00125
00126 if (chan && ast_autoservice_start(chan) < 0)
00127 return -1;
00128
00129 ret = ast_search_dns(&context, service, C_IN, T_SRV, srv_callback);
00130
00131 if (chan)
00132 ret |= ast_autoservice_stop(chan);
00133
00134 if (ret <= 0) {
00135 host[0] = '\0';
00136 *port = -1;
00137 return ret;
00138 }
00139 return ret;
00140 }