Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

srv.c

Go to the documentation of this file.
00001 /*
00002  * ENUM Support for Asterisk
00003  *
00004  * Copyright (C) 2003 Digium
00005  *
00006  * Written by Mark Spencer <markster@digium.com>
00007  *
00008  * Funding provided by nic.at
00009  *
00010  * Distributed under the terms of the GNU GPL
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;     /* query identification number */
00035 #if BYTE_ORDER == BIG_ENDIAN
00036          /* fields in third byte */
00037    unsigned qr: 1;      /* response flag */
00038    unsigned opcode: 4;  /* purpose of message */
00039    unsigned aa: 1;      /* authoritive answer */
00040    unsigned tc: 1;      /* truncated message */
00041    unsigned rd: 1;      /* recursion desired */
00042          /* fields in fourth byte */
00043    unsigned ra: 1;      /* recursion available */
00044    unsigned unused :1;  /* unused bits (MBZ as of 4.9.3a3) */
00045    unsigned ad: 1;      /* authentic data from named */
00046    unsigned cd: 1;      /* checking disabled by resolver */
00047    unsigned rcode :4;   /* response code */
00048 #endif
00049 #if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
00050          /* fields in third byte */
00051    unsigned rd :1;      /* recursion desired */
00052    unsigned tc :1;      /* truncated message */
00053    unsigned aa :1;      /* authoritive answer */
00054    unsigned opcode :4;  /* purpose of message */
00055    unsigned qr :1;      /* response flag */
00056          /* fields in fourth byte */
00057    unsigned rcode :4;   /* response code */
00058    unsigned cd: 1;      /* checking disabled by resolver */
00059    unsigned ad: 1;      /* authentic data from named */
00060    unsigned unused :1;  /* unused bits (MBZ as of 4.9.3a3) */
00061    unsigned ra :1;      /* recursion available */
00062 #endif
00063          /* remaining bytes */
00064    unsigned qdcount :16;   /* number of question entries */
00065    unsigned ancount :16;   /* number of answer entries */
00066    unsigned nscount :16;   /* number of authority entries */
00067    unsigned arcount :16;   /* number of resource entries */
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    /* Shamelessly take from SER */
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     * This function is influenced by "ser" the SIP router.
00156     */
00157    int x;
00158    int res;
00159    dns_HEADER *h;
00160    struct dn_answer *ans;
00161 /* int lastlit = 1; */
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    /* Skip over DNS header */
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;   /* Skip QCODE / QCLASS */
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 }

Generated on Fri Oct 31 07:05:08 2003 for Asterisk by doxygen 1.3.4