task.c
来自「此dns服务器是在mydns基础上改写」· C语言 代码 · 共 615 行 · 第 1/2 页
C
615 行
/************************************************************************************************** $Id: task.c,v 1.86 2006/01/18 20:50:39 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_TASK 1extern void server_status(void);extern void named_cleanup(int);/************************************************************************************************** NEW_TASK Given a request (TCP or UDP), populates task structure. 'socktype' should be either SOCK_STREAM or SOCK_DGRAM. Returns 0 on success, -1 on error, -2 if the task is now invalid.**************************************************************************************************/intnew_task(TASK *t, unsigned char *data, size_t len){ unsigned char qname[DNS_MAXNAMELEN+1], *src, *qdtop;#if DEBUG_ENABLED && DEBUG_TASK Debug("new_task(%p, %p, %u)", t, data, len);#endif /* Query needs to at least contain a proper header */ if (len < DNS_HEADERSIZE) return formerr(t, DNS_RCODE_FORMERR, ERR_MALFORMED_REQUEST, _("query so small it has no header")); /* Refuse queries that are too long */ if (len > (t->protocol == SOCK_STREAM ? DNS_MAXPACKETLEN_TCP : DNS_MAXPACKETLEN_UDP)) return formerr(t, DNS_RCODE_FORMERR, ERR_MALFORMED_REQUEST, _("query too large")); /* Parse query header data */ src = data; DNS_GET16(t->id, src); memcpy(&t->hdr, src, SIZE16); src += SIZE16; DNS_GET16(t->qdcount, src); DNS_GET16(t->ancount, src); DNS_GET16(t->nscount, src); DNS_GET16(t->arcount, src); /* Discard queries where the response bit is set; it might be a spoofed packet asking us to talk to ourselves */ if (t->hdr.qr) { formerr(t, DNS_RCODE_FORMERR, ERR_RESPONSE_BIT_SET, _("response bit set on query")); if (t->protocol == SOCK_STREAM) sockclose(t->fd); dequeue(Tasks, t); return -2; }#if DEBUG_ENABLED && DEBUG_TASK Debug("%s: id=%u qr=%u opcode=%s aa=%u tc=%u rd=%u ra=%u z=%u rcode=%u", desctask(t), t->id, t->hdr.qr, mydns_opcode_str(t->hdr.opcode), t->hdr.aa, t->hdr.tc, t->hdr.rd, t->hdr.ra, t->hdr.z, t->hdr.rcode); Debug("%s: qd=%u an=%u ns=%u ar=%u", desctask(t), t->qdcount, t->ancount, t->nscount, t->arcount);#endif /* If 'query' isn't set and this is an UPDATE query, save a copy of the whole query for parsing */ if (!t->query && t->hdr.opcode == DNS_OPCODE_UPDATE) { t->len = len; if (!(t->query = malloc(t->len))) Err(_("out of memory")); memcpy(t->query, data, t->len); } task_init_header(t); /* Initialize header fields for reply */ t->qdlen = len - DNS_HEADERSIZE; /* Fill in question data */ if (t->qdlen <= 0) return formerr(t, DNS_RCODE_FORMERR, ERR_MALFORMED_REQUEST, _("question has zero length")); if (!(t->qd = malloc(t->qdlen))) Err(_("out of memory")); memcpy(t->qd, src, t->qdlen); qdtop = src; /* Get query name */ if (!(src = name_unencode(t->qd, t->qdlen, src, qname, sizeof(qname)))) { Warnx("%s: FORMERR in query", desctask(t)); return formerr(t, DNS_RCODE_FORMERR, (task_error_t)qname[0], NULL); } strncpy(t->qname, qname, sizeof(t->qname)-1); /* Now we have question data, so initialize encoding */ if (reply_init(t) < 0) return Warnx("%s: %s", desctask(t), _("failed to initialize reply")); /* Get query type */ if (src + SIZE16 > data + len) return formerr(t, DNS_RCODE_FORMERR, ERR_MALFORMED_REQUEST, _("query too short; no qtype")); DNS_GET16(t->qtype, src); /* If this request is TCP and TCP is disabled, refuse the request */ if (t->protocol == SOCK_STREAM && !tcp_enabled && (t->qtype != DNS_QTYPE_AXFR || !axfr_enabled)) return formerr(t, DNS_RCODE_REFUSED, ERR_TCP_NOT_ENABLED, NULL); /* Get query class */ if (src + SIZE16 > data + len) return formerr(t, DNS_RCODE_FORMERR, ERR_MALFORMED_REQUEST, _("query too short; no qclass")); DNS_GET16(t->qclass, src); t->qdlen = src - qdtop; /* Request must have at least one question */ if (!t->qdcount) return formerr(t, DNS_RCODE_FORMERR, ERR_NO_QUESTION, _("query contains no questions")); /* Server can't handle more than 1 question per packet */ if (t->qdcount > 1) return formerr(t, DNS_RCODE_FORMERR, ERR_MULTI_QUESTIONS, _("query contains more than one question")); /* Server won't accept truncated query */ if (t->hdr.tc) return formerr(t, DNS_RCODE_FORMERR, ERR_QUESTION_TRUNCATED, _("query is truncated")); /* If DNS updates are enabled and the opcode is UPDATE, do the update */ if (dns_update_enabled && t->hdr.opcode == DNS_OPCODE_UPDATE) return dns_update(t); /* Server only handles QUERY opcode */ if (t->hdr.opcode != DNS_OPCODE_QUERY) return formerr(t, DNS_RCODE_NOTIMP, ERR_UNSUPPORTED_OPCODE, NULL); /* Check class (only IN or ANY are allowed unless status is enabled) */ if ((t->qclass != DNS_CLASS_IN) && (t->qclass != DNS_CLASS_ANY)#if STATUS_ENABLED && (t->qclass != DNS_CLASS_CHAOS)#endif ) return formerr(t, DNS_RCODE_NOTIMP, ERR_NO_CLASS, NULL); /* If AXFR is requested, it must be TCP, and AXFR must be enabled */ if (t->qtype == DNS_QTYPE_AXFR && (!axfr_enabled || t->protocol != SOCK_STREAM)) return formerr(t, DNS_RCODE_REFUSED, ERR_NO_AXFR, NULL); /* If this is AXFR, fork to handle it so that other requests don't block */ if (t->protocol == SOCK_STREAM && t->qtype == DNS_QTYPE_AXFR) { int pfd[2]; /* Parent/child pipe descriptors */ pid_t pid, parent; if (pipe(pfd)) Err("pipe"); parent = getpid(); if ((pid = fork()) < 0) { close(pfd[0]); close(pfd[1]); return Warn("%s: fork", clientaddr(t)); } if (!pid) /* Child: Let parent know I have started */ { close(pfd[0]); if (write(pfd[1], "OK", 2) != 2) Warn(_("error writing startup notification")); close(pfd[1]); axfr(t); } else /* Parent */ { char buf[5] = "\0\0\0\0\0"; int errct = 0; close(pfd[1]); for (errct = 0; errct < 5; errct++) { if (read(pfd[0], &buf, 4) != 2) Warn("%s (%d of 5)", _("error reading startup notification"), errct+1); else break; } close(pfd[0]);#if DEBUG_ENABLED && DEBUG_TASK Debug("AXFR: process started on pid %d for TCP fd %d, task ID %lu", pid, t->fd, t->internal_id);#endif } return (0); } t->status = NEED_ANSWER; return (0);}/*--- new_task() --------------------------------------------------------------------------------*//************************************************************************************************** CLIENTADDR Given a task, returns the client's IP address in printable format.**************************************************************************************************/char *clientaddr(TASK *t){ static char buf[256]; buf[0] = '\0';#if HAVE_IPV6 if (t->family == AF_INET6) inet_ntop(AF_INET6, &t->addr6.sin6_addr, buf, sizeof(buf) - 1); else#endif inet_ntop(AF_INET, &t->addr4.sin_addr, buf, sizeof(buf) - 1); return (buf);}/*--- clientaddr() ------------------------------------------------------------------------------*//************************************************************************************************** DESCTASK Describe a task; used by error/warning/debug output.**************************************************************************************************/char *desctask(TASK *t){ static char desc[1024]; snprintf(desc, sizeof(desc), "%s: %s %s", clientaddr(t), mydns_qtype_str(t->qtype), t->qname ? (char *)t->qname : "<NONE>"); return (desc);}/*--- desctask() --------------------------------------------------------------------------------*//************************************************************************************************** _TASK_INIT Allocates and initializes a new task, and returns a pointer to it. t = task_init(NEED_ZONE, SOCK_DGRAM, fd, &addr);**************************************************************************************************/TASK *_task_init( taskstat_t status, /* Initial status */ int fd, /* Associated file descriptor for socket */ int protocol, /* Protocol (SOCK_DGRAM or SOCK_STREAM) */ int family, /* Protocol (SOCK_DGRAM or SOCK_STREAM) */ void *addr, /* Remote address */ const char *file, int line){ TASK *new; if (!(new = calloc(1, sizeof(TASK)))) Err(_("out of memory")); new->status = status; new->fd = fd; new->recursive_fd = -1; new->protocol = protocol; new->family = family;#if HAVE_IPV6 if (new->family == AF_INET6) memcpy(&new->addr6, addr, sizeof(struct sockaddr_in6)); else#endif memcpy(&new->addr4, addr, sizeof(struct sockaddr_in)); new->internal_id = Status.udp_requests + Status.tcp_requests; new->timeout = current_time + task_timeout; new->minimum_ttl = DNS_MINIMUM_TTL; new->reply_cache_ok = 1;#if DEBUG_ENABLED && DEBUG_TASK Debug("%s: task_init(%p) from %s:%d", desctask(new), new, file, line);#endif if (enqueue(Tasks, new) < 0) { task_free(new); return (NULL); } return (new);}/*--- _task_init() -------------------------------------------------------------------------------*//************************************************************************************************** _TASK_FREE Free the memory used by a task.**************************************************************************************************/void
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?