Changeset 1356


Ignore:
Timestamp:
Jun 11, 2007 4:47:51 PM (17 years ago)
Author:
bennylp
Message:

Ticket #329: Added utility function to parse DNS A response in PJLIB-UTIL

Location:
pjproject/trunk/pjlib-util
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjlib-util/include/pjlib-util/errno.h

    r1037 r1356  
    175175 */ 
    176176#define PJLIB_UTIL_EDNSNOANSWERREC  (PJLIB_UTIL_ERRNO_START+47) /* 320047 */ 
     177/** 
     178 * @hideinitializer 
     179 * Invalid DNS answer. This error is raised for example when the DNS 
     180 * answer does not have a query section, or the type of RR in the answer 
     181 * doesn't match the query. 
     182 */ 
     183#define PJLIB_UTIL_EDNSINANSWER     (PJLIB_UTIL_ERRNO_START+48) /* 320048 */ 
    177184 
    178185 
  • pjproject/trunk/pjlib-util/include/pjlib-util/resolver.h

    r1346 r1356  
    197197    unsigned    bad_ns_ttl;     /**< See #PJ_DNS_RESOLVER_BAD_NS_TTL        */ 
    198198} pj_dns_settings; 
     199 
     200 
     201/** 
     202 * This structure represents DNS A record, as the result of parsing 
     203 * DNS response packet using #pj_dns_parse_a_response(). 
     204 */ 
     205typedef struct pj_dns_a_record 
     206{ 
     207    /** The target name being queried.   */ 
     208    pj_str_t            name; 
     209 
     210    /** If target name corresponds to a CNAME entry, the alias contains 
     211     *  the value of the CNAME entry, otherwise it will be empty. 
     212     */ 
     213    pj_str_t            alias; 
     214 
     215    /** Number of IP addresses. */ 
     216    unsigned            addr_count; 
     217 
     218    /** IP addresses of the host found in the response */ 
     219    pj_in_addr          addr[PJ_DNS_MAX_IP_IN_A_REC]; 
     220 
     221    /** Internal buffer for hostname and alias. */ 
     222    char                buf_[128]; 
     223 
     224} pj_dns_a_record; 
     225 
    199226 
    200227/** 
     
    366393                                                  pj_bool_t notify); 
    367394 
     395/** 
     396 * A utility function to parse a DNS response containing A records into  
     397 * DNS A record. 
     398 * 
     399 * @param pkt       The DNS response packet. 
     400 * @param rec       The structure to be initialized with the parsed 
     401 *                  DNS A record from the packet. 
     402 * 
     403 * @return          PJ_SUCCESS if response can be parsed successfully. 
     404 */ 
     405PJ_DECL(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt, 
     406                                             pj_dns_a_record *rec); 
     407 
    368408 
    369409/** 
  • pjproject/trunk/pjlib-util/src/pjlib-util/errno.c

    r1242 r1356  
    5959    PJ_BUILD_ERR( PJLIB_UTIL_EDNSNOWORKINGNS,   "No working DNS nameserver"), 
    6060    PJ_BUILD_ERR( PJLIB_UTIL_EDNSNOANSWERREC,   "No answer record in the DNS response"), 
     61    PJ_BUILD_ERR( PJLIB_UTIL_EDNSINANSWER,      "Invalid DNS answer"), 
    6162 
    6263    PJ_BUILD_ERR( PJLIB_UTIL_EDNS_FORMERR,      "DNS \"Format error\""), 
  • pjproject/trunk/pjlib-util/src/pjlib-util/resolver.c

    r1348 r1356  
    425425 
    426426    PJ_ASSERT_RETURN(resolver && count && servers, PJ_EINVAL); 
     427    PJ_ASSERT_RETURN(count < PJ_DNS_RESOLVER_MAX_NS, PJ_EINVAL); 
    427428 
    428429    pj_mutex_lock(resolver->mutex); 
     
    801802} 
    802803 
     804 
     805/*  
     806 * DNS response containing A packet.  
     807 */ 
     808PJ_DEF(pj_status_t) pj_dns_parse_a_response(const pj_dns_parsed_packet *pkt, 
     809                                            pj_dns_a_record *rec) 
     810{ 
     811    pj_str_t hostname, alias, *res_name; 
     812    unsigned bufstart = 0; 
     813    unsigned bufleft = sizeof(rec->buf_); 
     814    unsigned i, ansidx; 
     815 
     816    PJ_ASSERT_RETURN(pkt && rec, PJ_EINVAL); 
     817 
     818    /* Init the record */ 
     819    pj_bzero(rec, sizeof(pj_dns_a_record)); 
     820 
     821    /* Return error if there's error in the packet. */ 
     822    if (PJ_DNS_GET_RCODE(pkt->hdr.flags)) 
     823        return PJ_STATUS_FROM_DNS_RCODE(PJ_DNS_GET_RCODE(pkt->hdr.flags)); 
     824 
     825    /* Return error if there's no query section */ 
     826    if (pkt->hdr.qdcount == 0) 
     827        return PJLIB_UTIL_EDNSINANSWER; 
     828 
     829    /* Return error if there's no answer */ 
     830    if (pkt->hdr.anscount == 0) 
     831        return PJLIB_UTIL_EDNSNOANSWERREC; 
     832 
     833    /* Get the hostname from the query. */ 
     834    hostname = pkt->q[0].name; 
     835 
     836    /* Copy hostname to the record */ 
     837    if (hostname.slen > (int)bufleft) { 
     838        return PJ_ENAMETOOLONG; 
     839    } 
     840 
     841    pj_memcpy(&rec->buf_[bufstart], hostname.ptr, hostname.slen); 
     842    rec->name.ptr = &rec->buf_[bufstart]; 
     843    rec->name.slen = hostname.slen; 
     844 
     845    bufstart += hostname.slen; 
     846    bufleft -= hostname.slen; 
     847 
     848    /* Find the first RR which name matches the hostname */ 
     849    for (ansidx=0; ansidx < pkt->hdr.anscount; ++ansidx) { 
     850        if (pj_stricmp(&pkt->ans[ansidx].name, &hostname)==0) 
     851            break; 
     852    } 
     853 
     854    if (ansidx == pkt->hdr.anscount) 
     855        return PJLIB_UTIL_EDNSNOANSWERREC; 
     856 
     857    /* If hostname is a CNAME, get the alias. */ 
     858    if (pkt->ans[ansidx].type == PJ_DNS_TYPE_CNAME) { 
     859        alias = pkt->ans[ansidx].rdata.cname.name; 
     860        res_name = &alias; 
     861    } else if (pkt->ans[ansidx].type == PJ_DNS_TYPE_A) { 
     862        alias.ptr = NULL; 
     863        alias.slen = 0; 
     864        res_name = &hostname; 
     865    } else { 
     866        return PJLIB_UTIL_EDNSINANSWER; 
     867    } 
     868 
     869    /* Copy alias to the record, if present. */ 
     870    if (alias.slen) { 
     871        if (alias.slen > (int)bufleft) 
     872            return PJ_ENAMETOOLONG; 
     873 
     874        pj_memcpy(&rec->buf_[bufstart], alias.ptr, alias.slen); 
     875        rec->alias.ptr = &rec->buf_[bufstart]; 
     876        rec->alias.slen = alias.slen; 
     877 
     878        bufstart += alias.slen; 
     879        bufleft -= alias.slen; 
     880    } 
     881 
     882    /* Now scan the answer for all type A RRs where the name matches 
     883     * hostname or alias. 
     884     */ 
     885    for (i=0; i<pkt->hdr.anscount; ++i) { 
     886        if (pkt->ans[i].type == PJ_DNS_TYPE_A && 
     887            pj_stricmp(&pkt->ans[i].name, res_name)==0 && 
     888            rec->addr_count < PJ_DNS_MAX_IP_IN_A_REC) 
     889        { 
     890            rec->addr[rec->addr_count].s_addr =  
     891                pkt->ans[i].rdata.a.ip_addr.s_addr; 
     892            ++rec->addr_count; 
     893        } 
     894    } 
     895 
     896    if (rec->addr_count == 0) 
     897        return PJLIB_UTIL_EDNSNOANSWERREC; 
     898 
     899    return PJ_SUCCESS; 
     900} 
    803901 
    804902 
     
    10311129 
    10321130    /* Duplicate the packet. 
    1033      * We don't need to keep the query, NS, and AR sections from the packet, 
    1034      * so exclude from duplication. 
     1131     * We don't need to keep the NS and AR sections from the packet, 
     1132     * so exclude from duplication. We do need to keep the Query 
     1133     * section since DNS A parser needs the query section to know 
     1134     * the name being requested. 
    10351135     */ 
    10361136    res_pool = pj_pool_create_on_buf("respool", cache->buf, sizeof(cache->buf)); 
     
    10381138        cache->pkt = NULL; 
    10391139        pj_dns_packet_dup(res_pool, pkt,  
    1040                           PJ_DNS_NO_QD | PJ_DNS_NO_NS | PJ_DNS_NO_AR, 
     1140                          PJ_DNS_NO_NS | PJ_DNS_NO_AR, 
    10411141                          &cache->pkt); 
    10421142    } 
Note: See TracChangeset for help on using the changeset viewer.