00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <string.h>
00015 #include <fcntl.h>
00016 #include <unistd.h>
00017 #include <stdlib.h>
00018 #include <sys/types.h>
00019 #include <sys/socket.h>
00020 #include <netinet/in.h>
00021 #include <arpa/nameser.h>
00022 #include <resolv.h>
00023 #include <errno.h>
00024
00025 #include <asterisk/logger.h>
00026 #include <asterisk/options.h>
00027 #include <asterisk/srv.h>
00028 #include <asterisk/channel.h>
00029 #include <asterisk/config.h>
00030
00031 #define MAX_SIZE 4096
00032
00033 typedef struct {
00034 unsigned id :16;
00035 #if BYTE_ORDER == BIG_ENDIAN
00036
00037 unsigned qr: 1;
00038 unsigned opcode: 4;
00039 unsigned aa: 1;
00040 unsigned tc: 1;
00041 unsigned rd: 1;
00042
00043 unsigned ra: 1;
00044 unsigned unused :1;
00045 unsigned ad: 1;
00046 unsigned cd: 1;
00047 unsigned rcode :4;
00048 #endif
00049 #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
00050
00051 unsigned rd :1;
00052 unsigned tc :1;
00053 unsigned aa :1;
00054 unsigned opcode :4;
00055 unsigned qr :1;
00056
00057 unsigned rcode :4;
00058 unsigned cd: 1;
00059 unsigned ad: 1;
00060 unsigned unused :1;
00061 unsigned ra :1;
00062 #endif
00063
00064 unsigned qdcount :16;
00065 unsigned ancount :16;
00066 unsigned nscount :16;
00067 unsigned arcount :16;
00068 } dns_HEADER;
00069
00070 struct dn_answer {
00071 unsigned short rtype;
00072 unsigned short class;
00073 unsigned int ttl;
00074 unsigned short size;
00075 } __attribute__ ((__packed__));
00076
00077 struct srv {
00078 unsigned short priority;
00079 unsigned short weight;
00080 unsigned short portnum;
00081 } __attribute__ ((__packed__));
00082
00083 static int skip_name(unsigned char *s, int len)
00084 {
00085
00086 int x = 0;
00087 while(x < len) {
00088 if (!*s) {
00089 s++;
00090 x++;
00091 break;
00092 }
00093 if (((*s) & 0xc0) == 0xc0) {
00094 s += 2;
00095 x += 2;
00096 break;
00097 }
00098 x += *s + 1;
00099 s += *s + 1;
00100 }
00101 if (x >= len)
00102 return -1;
00103 return x;
00104 }
00105
00106 static int parse_ie(unsigned char *data, int maxdatalen, unsigned char *src, int srclen)
00107 {
00108 int len, olen;
00109 len = olen = (int)src[0];
00110 src++;
00111 srclen--;
00112 if (len > srclen) {
00113 ast_log(LOG_WARNING, "Want %d, got %d\n", len, srclen);
00114 return -1;
00115 }
00116 if (len > maxdatalen)
00117 len = maxdatalen;
00118 memcpy(data, src, len);
00119 return olen + 1;
00120 }
00121
00122 static int parse_srv(unsigned char *host, int hostlen, int *portno, unsigned char *answer, int len, unsigned char *msg)
00123 {
00124 int res = 0;
00125 struct srv *srv = (struct srv *)answer;
00126 char repl[256] = "";
00127
00128 if (len < sizeof(struct srv)) {
00129 printf("Length too short\n");
00130 return -1;
00131 }
00132 answer += sizeof(struct srv);
00133 len -= sizeof(struct srv);
00134
00135 if ((res = dn_expand(msg,answer + len,answer, repl, sizeof(repl) - 1)) < 0) {
00136 ast_log(LOG_WARNING, "Failed to expand hostname\n");
00137 return -1;
00138 }
00139 if (res && strcmp(repl, ".")) {
00140 ast_verbose( VERBOSE_PREFIX_3 "parse_srv: SRV mapped to host %s, port %d\n", repl, ntohs(srv->portnum));
00141 if (host) {
00142 strncpy(host, repl, hostlen - 2);
00143 host[hostlen-1] = '\0';
00144 }
00145 if (portno)
00146 *portno = ntohs(srv->portnum);
00147 return(0);
00148 }
00149 return(-1);
00150 }
00151
00152 static int parse_answer(unsigned char *host, int hostlen, int *port, char *answer, int len)
00153 {
00154
00155
00156
00157 int x;
00158 int res;
00159 dns_HEADER *h;
00160 struct dn_answer *ans;
00161
00162 char *oanswer = answer;
00163 host[0] = '\0';
00164 *port = 0;
00165
00166 #if 0
00167 for (x=0;x<len;x++) {
00168 if ((answer[x] < 32) || (answer[x] > 127)) {
00169 if (lastlit)
00170 printf("\"");
00171 printf(" 0x%02x", answer[x]);
00172 lastlit = 0;
00173 } else {
00174 if (!lastlit)
00175 printf(" \"");
00176 printf("%c", answer[x]);
00177 lastlit = 1;
00178 }
00179 }
00180 printf("\n");
00181 #endif
00182 h = (dns_HEADER *)answer;
00183
00184 answer += sizeof(dns_HEADER);
00185 len -= sizeof(dns_HEADER);
00186 #if 0
00187 printf("Query count: %d\n", ntohs(h->qdcount));
00188 #endif
00189 for (x=0;x<ntohs(h->qdcount);x++) {
00190 if ((res = skip_name(answer, len)) < 0) {
00191 ast_log(LOG_WARNING, "Couldn't skip over name\n");
00192 return -1;
00193 }
00194 answer += res;
00195 len -= res;
00196 answer += 4;
00197 len -= 4;
00198 if (len < 0) {
00199 ast_log(LOG_WARNING, "Strange query size\n");
00200 return -1;
00201 }
00202 }
00203 #if 0
00204 printf("Length remaining: %d, already at %04x\n", len, 0x2a + (answer - oanswer));
00205 printf("Answer count: %d\n", ntohs(h->ancount));
00206 printf("Looking for %d/%d\n", C_IN, T_SRV);
00207 printf("Answer so far: %02x %02x %02x %02x %02x %02x\n", answer[0], answer[1], answer[2], answer[3], answer[4], answer[5]);
00208 #endif
00209 for (x=0;x<ntohs(h->ancount);x++) {
00210 if ((res = skip_name(answer, len)) < 0) {
00211 ast_log(LOG_WARNING, "Failed to skip name :(\n");
00212 return -1;
00213 }
00214 answer += res;
00215 len -= res;
00216 ans = (struct dn_answer *)answer;
00217 answer += sizeof(struct dn_answer);
00218 len -= sizeof(struct dn_answer);
00219 if (len < 0)
00220 return -1;
00221 #if 0
00222 printf("Type: %d (%04x), class: %d (%04x), ttl: %d (%08x), length: %d (%04x)\n", ntohs(ans->rtype), ntohs(ans->rtype), ntohs(ans->class), ntohs(ans->class),
00223 ntohl(ans->ttl), ntohl(ans->ttl), ntohs(ans->size), ntohs(ans->size));
00224 #endif
00225 len -= ntohs(ans->size);
00226 if (len < 0) {
00227 ast_log(LOG_WARNING, "Length exceeds frame by %d\n", -len);
00228 return -1;
00229 }
00230 if ((ntohs(ans->class) == C_IN) && (ntohs(ans->rtype) == T_SRV)) {
00231
00232 if (parse_srv(host, hostlen, port, answer, ntohs(ans->size),oanswer))
00233 ast_log(LOG_WARNING, "Failed to parse srv :(\n");
00234
00235 if (strlen(host))
00236 return 0;
00237 }
00238 answer += ntohs(ans->size);
00239 }
00240 return 0;
00241 }
00242
00243 int ast_get_srv(struct ast_channel *chan, char *host, int hostlen, int *port, const char *service)
00244 {
00245 int res;
00246 int ret = -1;
00247 struct __res_state srvstate;
00248 char answer[MAX_SIZE];
00249
00250 if (*port)
00251 *port = 0;
00252 res_ninit(&srvstate);
00253 if (chan && ast_autoservice_start(chan) < 0)
00254 return -1;
00255 res = res_nsearch(&srvstate, service, C_IN, T_SRV, answer, sizeof(answer));
00256 if (res > 0) {
00257 if ((res = parse_answer(host, hostlen, port, answer, res))) {
00258 ast_log(LOG_WARNING, "Parse error returned %d\n", res);
00259 ret = 0;
00260 } else {
00261 ast_log(LOG_DEBUG, "Found host '%s', port '%d'\n", host, *port);
00262 ret = 1;
00263 }
00264 } else {
00265 ast_log(LOG_DEBUG, "No such service found: %s (%s)\n", service, strerror(errno));
00266 ret = 0;
00267 }
00268 if (chan)
00269 ret |= ast_autoservice_stop(chan);
00270 res_nclose(&srvstate);
00271 return ret;
00272 }