📄 dns.c
字号:
/* $Id: dns.c 1033 2007-03-02 14:51:03Z bennylp $ *//* * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <pjlib-util/dns.h>#include <pjlib-util/errno.h>#include <pj/assert.h>#include <pj/errno.h>#include <pj/pool.h>#include <pj/sock.h>#include <pj/string.h>PJ_DEF(const char *) pj_dns_get_type_name(int type){ switch (type) { case PJ_DNS_TYPE_A: return "A"; case PJ_DNS_TYPE_SRV: return "SRV"; case PJ_DNS_TYPE_NS: return "NS"; case PJ_DNS_TYPE_CNAME: return "CNAME"; case PJ_DNS_TYPE_PTR: return "PTR"; case PJ_DNS_TYPE_MX: return "MX"; case PJ_DNS_TYPE_TXT: return "TXT"; case PJ_DNS_TYPE_NAPTR: return "NAPTR"; } return "(Unknown)";}/** * Initialize a DNS query transaction. */PJ_DEF(pj_status_t) pj_dns_make_query( void *packet, unsigned *size, pj_uint16_t id, int qtype, const pj_str_t *name){ pj_dns_hdr *hdr; char *query, *p; const char *startlabel, *endlabel, *endname; pj_uint16_t tmp; unsigned d; /* Sanity check */ PJ_ASSERT_RETURN(packet && size && qtype && name, PJ_EINVAL); /* Calculate total number of bytes required. */ d = sizeof(pj_dns_hdr) + name->slen + 4; /* Check that size is sufficient. */ PJ_ASSERT_RETURN(*size >= d, PJLIB_UTIL_EDNSQRYTOOSMALL); /* Initialize header */ hdr = packet; pj_bzero(hdr, sizeof(struct pj_dns_hdr)); hdr->id = pj_htons(id); hdr->flags = pj_htons(PJ_DNS_SET_RD(1)); hdr->qdcount = pj_htons(1); /* Initialize query */ query = p = (char*)(hdr+1); /* Tokenize name */ startlabel = endlabel = name->ptr; endname = name->ptr + name->slen; while (endlabel != endname) { while (endlabel != endname && *endlabel != '.') ++endlabel; *p++ = (char)(endlabel - startlabel); pj_memcpy(p, startlabel, endlabel-startlabel); p += (endlabel-startlabel); if (endlabel != endname && *endlabel == '.') ++endlabel; startlabel = endlabel; } *p++ = '\0'; /* Set type */ tmp = pj_htons((pj_uint16_t)(qtype)); pj_memcpy(p, &tmp, 2); p += 2; /* Set class (IN=1) */ tmp = pj_htons(1); pj_memcpy(p, &tmp, 2); p += 2; /* Done, calculate length */ *size = p - (char*)packet; return 0;}/* Get a name length (note: name consists of multiple labels and * it may contain pointers when name compression is applied) */static pj_status_t get_name_len(int rec_counter, const char *pkt, const char *start, const char *max, int *parsed_len, int *name_len){ const char *p; pj_status_t status; /* Limit the number of recursion */ if (rec_counter > 10) { /* Too many name recursion */ return PJLIB_UTIL_EDNSINNAMEPTR; } *name_len = *parsed_len = 0; p = start; while (*p) { if ((*p & 0xc0) == 0xc0) { /* Compression is found! */ int ptr_len = 0; int dummy; pj_uint16_t offset; /* Get the 14bit offset */ pj_memcpy(&offset, p, 2); offset ^= pj_htons((pj_uint16_t)(0xc0 << 8)); offset = pj_ntohs(offset); /* Check that offset is valid */ if (offset >= max - pkt) return PJLIB_UTIL_EDNSINNAMEPTR; /* Get the name length from that offset. */ status = get_name_len(rec_counter+1, pkt, pkt + offset, max, &dummy, &ptr_len); if (status != PJ_SUCCESS) return status; *parsed_len += 2; *name_len += ptr_len; return PJ_SUCCESS; } else { unsigned label_len = *p; /* Check that label length is valid */ if (pkt+label_len > max) return PJLIB_UTIL_EDNSINNAMEPTR; p += (label_len + 1); *parsed_len += (label_len + 1); if (*p != 0) ++label_len; *name_len += label_len; if (p >= max) return PJLIB_UTIL_EDNSINSIZE; } } ++p; (*parsed_len)++; return PJ_SUCCESS;}/* Parse and copy name (note: name consists of multiple labels and * it may contain pointers when compression is applied). */static pj_status_t get_name(int rec_counter, const char *pkt, const char *start, const char *max, pj_str_t *name){ const char *p; pj_status_t status; /* Limit the number of recursion */ if (rec_counter > 10) { /* Too many name recursion */ return PJLIB_UTIL_EDNSINNAMEPTR; } p = start; while (*p) { if ((*p & 0xc0) == 0xc0) { /* Compression is found! */ pj_uint16_t offset; /* Get the 14bit offset */ pj_memcpy(&offset, p, 2); offset ^= pj_htons((pj_uint16_t)(0xc0 << 8)); offset = pj_ntohs(offset); /* Check that offset is valid */ if (offset >= max - pkt) return PJLIB_UTIL_EDNSINNAMEPTR; /* Retrieve the name from that offset. */ status = get_name(rec_counter+1, pkt, pkt + offset, max, name); if (status != PJ_SUCCESS) return status; return PJ_SUCCESS; } else { unsigned label_len = *p; /* Check that label length is valid */ if (pkt+label_len > max) return PJLIB_UTIL_EDNSINNAMEPTR; pj_memcpy(name->ptr + name->slen, p+1, label_len); name->slen += label_len; p += label_len + 1; if (*p != 0) { *(name->ptr + name->slen) = '.'; ++name->slen; } if (p >= max) return PJLIB_UTIL_EDNSINSIZE; } } return PJ_SUCCESS;}/* Skip query records. */static pj_status_t parse_query(pj_dns_parsed_query *q, pj_pool_t *pool, const char *pkt, const char *start, const char *max, int *parsed_len){ const char *p = start; int name_len, name_part_len; pj_status_t status; /* Get the length of the name */ status = get_name_len(0, pkt, start, max, &name_part_len, &name_len); if (status != PJ_SUCCESS) return status; /* Allocate memory for the name */ q->name.ptr = pj_pool_alloc(pool, name_len+4); q->name.slen = 0; /* Get the name */ status = get_name(0, pkt, start, max, &q->name); if (status != PJ_SUCCESS) return status; p = (start + name_part_len); /* Get the type */ pj_memcpy(&q->type, p, 2); q->type = pj_ntohs(q->type); p += 2; /* Get the class */ pj_memcpy(&q->dnsclass, p, 2); q->dnsclass = pj_ntohs(q->dnsclass); p += 2; *parsed_len = (int)(p - start); return PJ_SUCCESS;}/* Parse RR records */static pj_status_t parse_rr(pj_dns_parsed_rr *rr, pj_pool_t *pool, const char *pkt, const char *start, const char *max, int *parsed_len){ const char *p = start; int name_len, name_part_len; pj_status_t status; /* Get the length of the name */ status = get_name_len(0, pkt, start, max, &name_part_len, &name_len); if (status != PJ_SUCCESS) return status; /* Allocate memory for the name */ rr->name.ptr = pj_pool_alloc(pool, name_len+4); rr->name.slen = 0; /* Get the name */ status = get_name(0, pkt, start, max, &rr->name); if (status != PJ_SUCCESS) return status; p = (start + name_part_len); /* Check the size can accomodate next few fields. */ if (p+10 > max) return PJLIB_UTIL_EDNSINSIZE; /* Get the type */ pj_memcpy(&rr->type, p, 2); rr->type = pj_ntohs(rr->type); p += 2; /* Get the class */ pj_memcpy(&rr->dnsclass, p, 2); rr->dnsclass = pj_ntohs(rr->dnsclass); p += 2; /* Class MUST be IN */ if (rr->dnsclass != 1) return PJLIB_UTIL_EDNSINCLASS; /* Get TTL */ pj_memcpy(&rr->ttl, p, 4); rr->ttl = pj_htonl(rr->ttl); p += 4; /* Get rdlength */ pj_memcpy(&rr->rdlength, p, 2); rr->rdlength = pj_htons(rr->rdlength); p += 2; /* Check that length is valid */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -