📄 reply.c
字号:
/************************************************************************************************** $Id: reply.c,v 1.65 2006/01/18 20:46:47 bboy Exp $ Copyright (C) 2002-2005 Don Moore <bboy@bboy.net> 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 "named.h"/* Make this nonzero to enable debugging for this source file */#define DEBUG_REPLY 1#if DEBUG_ENABLED && DEBUG_REPLY/* Strings describing the datasections */char *reply_datasection_str[] = { "QUESTION", "ANSWER", "AUTHORITY", "ADDITIONAL" };#endif/************************************************************************************************** REPLY_INIT Examines the question data, storing the name offsets (from DNS_HEADERSIZE) for compression.**************************************************************************************************/intreply_init(TASK *t){ register char *c; /* Current character in name */ /* Examine question data, save labels found therein. The question data should begin with the name we've already parsed into t->qname. I believe it is safe to assume that no compression will be possible in the question. */ for (c = t->qname; *c; c++) if ((c == t->qname || *c == '.') && c[1]) if (name_remember(t, (c == t->qname) ? c : (c+1), (((c == t->qname) ? c : (c+1)) - t->qname) + DNS_HEADERSIZE) < -1) return (-1); return (0);}/*--- reply_init() ------------------------------------------------------------------------------*//************************************************************************************************** REPLY_ADD_ADDITIONAL Add ADDITIONAL for each item in the provided list.**************************************************************************************************/static voidreply_add_additional(TASK *t, RRLIST *rrlist, datasection_t section){ register RR *p; if (!rrlist) return; /* Examine each RR in the rrlist */ for (p = rrlist->head; p; p = p->next) { if (p->rrtype == DNS_RRTYPE_RR) { MYDNS_RR *rr = (MYDNS_RR *)p->rr; if (rr->type == DNS_QTYPE_NS || rr->type == DNS_QTYPE_MX || rr->type == DNS_QTYPE_SRV) {#if DEBUG_ENABLED && DEBUG_REPLY Debug("%s: resolving `%s' (A) for ADDITIONAL data", desctask(t), rr->data);#endif (void)resolve(t, ADDITIONAL, DNS_QTYPE_A, rr->data, 0); } else if (rr->type == DNS_QTYPE_CNAME) {#if DEBUG_ENABLED && DEBUG_REPLY Debug("%s: resolving `%s' (CNAME) for ADDITIONAL data", desctask(t), rr->data);#endif /* Don't do this */ (void)resolve(t, ADDITIONAL, DNS_QTYPE_CNAME, rr->data, 0); } } t->sort_level++; }}/*--- reply_add_additional() --------------------------------------------------------------------*//************************************************************************************************** RDATA_ENLARGE Expands t->rdata by `size' bytes. Returns a pointer to the destination.**************************************************************************************************/static inline char *rdata_enlarge(TASK *t, size_t size){ if (!size) return (NULL); t->rdlen += size; if (!t->rdata) { if (!(t->rdata = malloc(t->rdlen))) Err(_("out of memory")); } else { if (!(t->rdata = realloc(t->rdata, t->rdlen))) Err(_("out of memory")); } return (t->rdata + t->rdlen - size);}/*--- rdata_enlarge() ---------------------------------------------------------------------------*//************************************************************************************************** REPLY_START_RR Begins an RR. Appends to t->rdata all the header fields prior to rdlength. Returns the numeric offset of the start of this record within the reply, or -1 on error.**************************************************************************************************/static inline intreply_start_rr(TASK *t, RR *r, char *name, dns_qtype_t type, uint32_t ttl, char *desc){ char enc[DNS_MAXNAMELEN+1]; char *dest; int enclen; /* name_encode returns dnserror() */ if ((enclen = name_encode(t, enc, name, t->replylen + t->rdlen, 1)) < 0) return rr_error(r->id, "rr %u: %s (%s %s) (name=\"%s\")", r->id, _("invalid name in \"name\""), desc, _("record"), name); r->length = enclen + SIZE16 + SIZE16 + SIZE32; if (!(dest = rdata_enlarge(t, r->length))) return dnserror(t, DNS_RCODE_SERVFAIL, ERR_INTERNAL); r->offset = dest - t->rdata + DNS_HEADERSIZE + t->qdlen; DNS_PUT(dest, enc, enclen); DNS_PUT16(dest, type);#if STATUS_ENABLED if (r->rrtype == DNS_RRTYPE_RR && r->rr) DNS_PUT16(dest, ((MYDNS_RR *)(r->rr))->class) else#endif DNS_PUT16(dest, DNS_CLASS_IN); DNS_PUT32(dest, ttl); return (0);}/*--- reply_start_rr() --------------------------------------------------------------------------*//************************************************************************************************** REPLY_ADD_GENERIC_RR Adds a generic resource record whose sole piece of data is a domain-name, or a 16-bit value plus a domain-name. Returns the numeric offset of the start of this record within the reply, or -1 on error.**************************************************************************************************/static inline intreply_add_generic_rr(TASK *t, RR *r, char *desc){ char enc[DNS_MAXNAMELEN+1], *dest; int size, enclen; MYDNS_RR *rr = (MYDNS_RR *)r->rr;#if DEBUG_ENABLED && DEBUG_REPLY Debug("%s: REPLY_ADD: `%s' IN %s `%s'", desctask(t), r->name, mydns_qtype_str(rr->type), rr->data);#endif if (reply_start_rr(t, r, r->name, rr->type, rr->ttl, desc) < 0) return (-1); if ((enclen = name_encode(t, enc, rr->data, CUROFFSET(t), 1)) < 0) return rr_error(r->id, "rr %u: %s (%s) (data=\"%s\")", r->id, _("invalid name in \"data\""), desc, rr->data); size = enclen; r->length += SIZE16 + size; if (!(dest = rdata_enlarge(t, SIZE16 + size))) return dnserror(t, DNS_RCODE_SERVFAIL, ERR_INTERNAL); DNS_PUT16(dest, size); DNS_PUT(dest, enc, enclen); return (0);}/*--- reply_add_generic_rr() --------------------------------------------------------------------*//************************************************************************************************** REPLY_ADD_A Adds an A record to the reply. Returns the numeric offset of the start of this record within the reply, or -1 on error.**************************************************************************************************/static inline intreply_add_a(TASK *t, RR *r){ char *dest; int size; MYDNS_RR *rr = (MYDNS_RR *)r->rr; struct in_addr addr; uint32_t ip; if (inet_pton(AF_INET, rr->data, (void *)&addr) <= 0) { dnserror(t, DNS_RCODE_SERVFAIL, ERR_INVALID_ADDRESS); return rr_error(r->id, "rr %u: %s (A %s) (address=\"%s\")", r->id, _("invalid address in \"data\""), _("record"), rr->data); } ip = ntohl(addr.s_addr);#if DEBUG_ENABLED && DEBUG_REPLY Debug("%s: REPLY_ADD: `%s' IN A %s", desctask(t), r->name, inet_ntoa(addr));#endif if (reply_start_rr(t, r, r->name, DNS_QTYPE_A, rr->ttl, "A") < 0) return (-1); size = SIZE32; r->length += SIZE16 + size; if (!(dest = rdata_enlarge(t, SIZE16 + size))) return dnserror(t, DNS_RCODE_SERVFAIL, ERR_INTERNAL); DNS_PUT16(dest, size); DNS_PUT32(dest, ip); return (0);}/*--- reply_add_a() -----------------------------------------------------------------------------*//************************************************************************************************** REPLY_ADD_AAAA Adds an AAAA record to the reply. Returns the numeric offset of the start of this record within the reply, or -1 on error.**************************************************************************************************/static inline intreply_add_aaaa(TASK *t, RR *r){ char *dest; int size; MYDNS_RR *rr = (MYDNS_RR *)r->rr; uint8_t addr[16];#if DEBUG_ENABLED && DEBUG_REPLY Debug("%s: REPLY_ADD: `%s' IN AAAA %s", desctask(t), r->name, rr->data);#endif if (inet_pton(AF_INET6, rr->data, (void *)&addr) <= 0) { dnserror(t, DNS_RCODE_SERVFAIL, ERR_INVALID_ADDRESS); return rr_error(r->id, "rr %u: %s (AAAA %s) (address=\"%s\")", r->id, _("invalid address in \"data\""), _("record"), rr->data); } if (reply_start_rr(t, r, r->name, DNS_QTYPE_AAAA, rr->ttl, "AAAA") < 0) return (-1); size = sizeof(uint8_t) * 16; r->length += SIZE16 + size; if (!(dest = rdata_enlarge(t, SIZE16 + size))) return dnserror(t, DNS_RCODE_SERVFAIL, ERR_INTERNAL); DNS_PUT16(dest, size); memcpy(dest, &addr, size); dest += size; return (0);}/*--- reply_add_aaaa() --------------------------------------------------------------------------*//************************************************************************************************** REPLY_ADD_HINFO Adds an HINFO record to the reply. Returns the numeric offset of the start of this record within the reply, or -1 on error.**************************************************************************************************/static inline intreply_add_hinfo(TASK *t, RR *r){ char *dest; size_t oslen, cpulen; MYDNS_RR *rr = (MYDNS_RR *)r->rr; char os[DNS_MAXNAMELEN + 1] = "", cpu[DNS_MAXNAMELEN + 1] = ""; if (hinfo_parse(rr->data, cpu, os, DNS_MAXNAMELEN) < 0) { dnserror(t, DNS_RCODE_SERVFAIL, ERR_RR_NAME_TOO_LONG); return rr_error(r->id, "rr %u: %s (HINFO %s) (data=\"%s\")", r->id, _("name too long in \"data\""), _("record"), rr->data); }#if DEBUG_ENABLED && DEBUG_REPLY Debug("%s: REPLY_ADD: `%s' IN HINFO `%s %s'", desctask(t), r->name, cpu, os);#endif cpulen = strlen(cpu); oslen = strlen(os); if (reply_start_rr(t, r, r->name, DNS_QTYPE_HINFO, rr->ttl, "HINFO") < 0) return (-1); r->length += SIZE16 + cpulen + oslen + 2; if (!(dest = rdata_enlarge(t, SIZE16 + cpulen + SIZE16 + oslen))) return dnserror(t, DNS_RCODE_SERVFAIL, ERR_INTERNAL); DNS_PUT16(dest, cpulen + oslen + 2); *dest++ = cpulen; memcpy(dest, cpu, cpulen); dest += cpulen; *dest++ = oslen; memcpy(dest, os, oslen); dest += oslen; return (0);}/*--- reply_add_hinfo() -------------------------------------------------------------------------*//************************************************************************************************** REPLY_ADD_MX Adds an MX record to the reply. Returns the numeric offset of the start of this record within the reply, or -1 on error.**************************************************************************************************/static inline intreply_add_mx(TASK *t, RR *r){ char enc[DNS_MAXNAMELEN+1], *dest; int size, enclen; MYDNS_RR *rr = (MYDNS_RR *)r->rr;#if DEBUG_ENABLED && DEBUG_REPLY Debug("%s: REPLY_ADD: `%s' IN MX `%u %s'", desctask(t), r->name, (uint16_t)rr->aux, rr->data);#endif if (reply_start_rr(t, r, r->name, DNS_QTYPE_MX, rr->ttl, "MX") < 0) return (-1); if ((enclen = name_encode(t, enc, rr->data, CUROFFSET(t) + SIZE16, 1)) < 0) return rr_error(r->id, "rr %u: %s (MX %s) (data=\"%s\")", r->id, _("invalid name in \"data\""), _("record"), rr->data); size = SIZE16 + enclen; r->length += SIZE16 + size; if (!(dest = rdata_enlarge(t, SIZE16 + size))) return dnserror(t, DNS_RCODE_SERVFAIL, ERR_INTERNAL); DNS_PUT16(dest, size); DNS_PUT16(dest, (uint16_t)rr->aux); DNS_PUT(dest, enc, enclen); return (0);}/*--- reply_add_mx() ----------------------------------------------------------------------------*//************************************************************************************************** REPLY_ADD_NAPTR Adds an NAPTR record to the reply. Returns the numeric offset of the start of this record within the reply, or -1 on error.**************************************************************************************************/static inline intreply_add_naptr(TASK *t, RR *r){ MYDNS_RR *rr = (MYDNS_RR *)r->rr; size_t flags_len, service_len, regex_len; char enc[DNS_MAXNAMELEN+1], *dest; int size, enclen, offset;#if DEBUG_ENABLED && DEBUG_REPLY Debug("%s: REPLY_ADD: `%s' IN NAPTR `%u %u \"%s\" \"%s\" \"%s\" \"%s\"'", desctask(t), r->name, rr->naptr_order, rr->naptr_pref, rr->naptr_flags, rr->naptr_service, rr->naptr_regex, rr->naptr_replacement);#endif flags_len = strlen(rr->naptr_flags); service_len = strlen(rr->naptr_service); regex_len = strlen(rr->naptr_regex); if (reply_start_rr(t, r, r->name, DNS_QTYPE_NAPTR, rr->ttl, "NAPTR") < 0) return (-1); /* We are going to write "something else" and then a name, just like an MX record or something. In this case, though, the "something else" is lots of data. Calculate the size of "something else" in 'offset' */ offset = SIZE16 + SIZE16 + 1 + flags_len + 1 + service_len + 1 + regex_len; /* Encode the name at the offset */ if ((enclen = name_encode(t, enc, rr->naptr_replacement, CUROFFSET(t) + offset, 1)) < 0) return rr_error(r->id, "rr %u: %s (NAPTR %s) (%s=\"%s\")", r->id, _("invalid name in \"replacement\""), _("record"), _("replacement"), rr->naptr_replacement); size = offset + enclen; r->length += SIZE16 + size; if (!(dest = rdata_enlarge(t, SIZE16 + size))) return dnserror(t, DNS_RCODE_SERVFAIL, ERR_INTERNAL); DNS_PUT16(dest, size); DNS_PUT16(dest, (uint16_t)rr->naptr_order); DNS_PUT16(dest, (uint16_t)rr->naptr_pref); *dest++ = flags_len; memcpy(dest, rr->naptr_flags, flags_len); dest += flags_len; *dest++ = service_len; memcpy(dest, rr->naptr_service, service_len); dest += service_len; *dest++ = regex_len; memcpy(dest, rr->naptr_regex, regex_len); dest += regex_len; DNS_PUT(dest, enc, enclen); return (0);}/*--- reply_add_naptr() -------------------------------------------------------------------------*//************************************************************************************************** REPLY_ADD_RP Adds an RP record to the reply.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -