⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 update.c

📁 此dns服务器是在mydns基础上改写
💻 C
📖 第 1 页 / 共 4 页
字号:
/**************************************************************************************************	$Id: update.c,v 1.10 2005/12/18 19:16:41 bboy Exp $	update.c: Code to implement RFC 2136 (DNS UPDATE)	Copyright (C) 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_UPDATE	1#define	DEBUG_UPDATE_SQL	0typedef struct _update_query_rr{	char				name[DNS_MAXNAMELEN];	dns_qtype_t		type;	dns_class_t		class;	uint32_t			ttl;	uint16_t			rdlength;	unsigned char	rdata[DNS_MAXPACKETLEN_UDP + 1];} UQRR;/* This is the temporary RRset described in RFC 2136, 3.2.3 */typedef struct _update_temp_rrset{	char			name[DNS_MAXNAMELEN];	dns_qtype_t	type;	char			data[DNS_MAXPACKETLEN_UDP + 1];	uint32_t		aux;	int			checked;											/* Have we checked this unique name/type? */} TMPRR;typedef struct _update_query{	/* Zone section */	char			name[DNS_MAXNAMELEN];						/* The zone name */	dns_qtype_t	type;												/* Must be DNS_QTYPE_SOA */	dns_class_t	class;											/* The zone's class */	UQRR			*PR;												/* Prerequisite section RRs */	int			numPR;											/* Number of items in 'PR' */	UQRR			*UP;												/* Update section RRs */	int			numUP;											/* Number of items in 'UP' */	UQRR			*AD;												/* Additional data section RRs */	int			numAD;											/* Number of items in 'AD' */	TMPRR			**tmprr;											/* Temporary RR list for prerequisite */	int			num_tmprr;										/* Number of items in "tmprr" */} UQ;/**************************************************************************************************	FREE_UQ	Frees a 'UQ' structure.**************************************************************************************************/static voidfree_uq(UQ *uq){	Free(uq->PR);	Free(uq->UP);	Free(uq->AD);	if (uq->num_tmprr)	{		int n;		for (n = 0; n < uq->num_tmprr; n++)			Free(uq->tmprr[n]);		Free(uq->tmprr);	}	Free(uq);}/*--- free_uq() ---------------------------------------------------------------------------------*//**************************************************************************************************	UPDATE_TRANSACTION	Start/commit/rollback a transaction for the UPDATE queries.	Returns 0 on success, -1 on failure.**************************************************************************************************/static intupdate_transaction(TASK *t, const char *query){	if (sql_nrquery(sql, query, strlen(query)) != 0)	{		WarnSQL(sql, "%s: %s", desctask(t), _("error deleting all RRsets via DNS UPDATE"));		return dnserror(t, DNS_RCODE_SERVFAIL, ERR_DB_ERROR);	}	return 0;}/*--- update_transaction() ----------------------------------------------------------------------*//**************************************************************************************************	CHECK_UPDATE	If the "update" column exists in the soa table, it should contain a list of wildcards separated	by commas.  In order for the DNS UPDATE to continue, one of the wildcards must match the	client's IP address.  Returns 0 if okay, -1 if denied.**************************************************************************************************/static intcheck_update(TASK *t, MYDNS_SOA *soa){	SQL_RES	*res = NULL;	SQL_ROW	row;	char		ip[256];	char		query[512];	size_t	querylen;	int		ok = 0;	/* If the 'soa' table does not have an 'update' column, listing access rules, allow		DNS UPDATE only from 127.0.0.1 */	/* TODO: Allow from all listening addresses */	if (!mydns_soa_use_update_acl)	{		strncpy(ip, clientaddr(t), sizeof(ip)-1);		if (!strcmp(ip, "127.0.0.1"))							/* OK from localhost */			return 0;		return dnserror(t, DNS_RCODE_REFUSED, ERR_NO_UPDATE);	}	strncpy(ip, clientaddr(t), sizeof(ip)-1);	querylen = snprintf(query, sizeof(query), "SELECT update_acl FROM %s WHERE id=%u%s",		mydns_soa_table_name, soa->id, mydns_rr_use_active ? " AND active=1" : "");#if DEBUG_UPDATE_SQL	Verbose("%s: DNS UPDATE: %s", desctask(t), query);#endif	if (!(res = sql_query(sql, query, querylen)))		ErrSQL(sql, "%s: %s", desctask(t), _("error loading DNS UPDATE access rules"));	if ((row = sql_getrow(res)))	{		char *wild, *r;#if DEBUG_ENABLED && DEBUG_UPDATE		Debug("%s: checking DNS UPDATE access rule '%s'", desctask(t), row[0]);#endif		for (r = row[0]; !ok && (wild = strsep(&r, ",")); )		{			if (strchr(wild, '/'))			{				if (t->family == AF_INET)					ok = in_cidr(wild, t->addr4.sin_addr);			}			else if (wildcard_match(wild, ip))				ok = 1;		}	}	sql_free(res);	if (!ok)		return dnserror(t, DNS_RCODE_REFUSED, ERR_NO_UPDATE);	return 0;}/*--- check_update() ----------------------------------------------------------------------------*/#if DEBUG_ENABLED && DEBUG_UPDATE/**************************************************************************************************	UPDATE_RRDUMP**************************************************************************************************/static voidupdate_rrdump(TASK *t, char *section, int which, UQRR *rr){	char buf[BUFSIZ] = "", *b = buf;	int n;	for (n = 0; n < rr->rdlength; n++)	{		if (isalnum(rr->rdata[n]))			b += sprintf(b, "%c", rr->rdata[n]);		else			b += sprintf(b, "<%d>", rr->rdata[n]);	}	Debug("%s: DNS UPDATE: >>> %s %d: name=[%s] type=%s class=%s ttl=%u rdlength=%u rdata=[%s]",			desctask(t), section, which, rr->name,			mydns_qtype_str(rr->type), mydns_class_str(rr->class),			rr->ttl, rr->rdlength, buf);}/*--- update_rrdump() ---------------------------------------------------------------------------*/#endif/**************************************************************************************************	UPDATE_GOBBLE_RR	Reads the next RR from the query.  Returns the new source or NULL on error.**************************************************************************************************/static char *update_gobble_rr(TASK *t, MYDNS_SOA *soa, char *query, size_t querylen, char *current, UQRR *rr){	char *src = current;	if (!(src = name_unencode(query, querylen, src, rr->name, sizeof(rr->name))))	{		formerr(t, DNS_RCODE_FORMERR, (task_error_t)rr->name[0], NULL);		return NULL;	}	DNS_GET16(rr->type, src);	DNS_GET16(rr->class, src);	DNS_GET32(rr->ttl, src);	DNS_GET16(rr->rdlength, src);	memcpy(rr->rdata, src, rr->rdlength);	src += rr->rdlength;	return src;}/*--- update_gobble_rr() ------------------------------------------------------------------------*//**************************************************************************************************	PARSE_UPDATE_QUERY	Parses the various sections of the update query.	Returns 0 on success, -1 on error.**************************************************************************************************/static intparse_update_query(TASK *t, MYDNS_SOA *soa, UQ *q){	char	*query = t->query;									/* Start of query section */	int	querylen = t->len;									/* Length of 'query' */	char	*src = query + DNS_HEADERSIZE;					/* Current position in 'query' */	int	n;	/*	**  Zone section (RFC 2136 2.3)	*/	if (!(src = name_unencode(query, querylen, src, q->name, sizeof(q->name))))		return formerr(t, DNS_RCODE_FORMERR, (task_error_t)q->name[0], NULL);	DNS_GET16(q->type, src);	DNS_GET16(q->class, src);#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s:   ZONE: name=[%s]  type=%s  class=%s", desctask(t), q->name, mydns_qtype_str(q->type), mydns_class_str(q->class));#endif	/* ZONE: Must contain exactly one RR with type SOA (RFC 2136 3.1.1) */	if (t->qdcount != 1)		return dnserror(t, DNS_RCODE_FORMERR, ERR_MULTI_QUESTIONS);	if (q->type != DNS_QTYPE_SOA)		return dnserror(t, DNS_RCODE_FORMERR, ERR_INVALID_TYPE);	/*	**  Prerequisite section (RFC 2136 2.4)	**  These records are in normal RR format (RFC 1035 4.1.3)	*/	q->numPR = t->ancount;	if (!(q->PR = calloc(q->numPR, sizeof(UQRR))))		Err(_("out of memory"));	for (n = 0; n < q->numPR; n++)		if (!(src = update_gobble_rr(t, soa, query, querylen, src, &q->PR[n])))			return -1;#if DEBUG_ENABLED && DEBUG_UPDATE	for (n = 0; n < q->numPR; n++)		update_rrdump(t, "PREREQ", n, &q->PR[n]);#endif	/*	**  Update section (RFC 2136 2.5)	**  These records are in normal RR format (RFC 1035 4.1.3)	*/	q->numUP = t->nscount;	if (!(q->UP = calloc(q->numUP, sizeof(UQRR))))		Err(_("out of memory"));	for (n = 0; n < q->numUP; n++)		if (!(src = update_gobble_rr(t, soa, query, querylen, src, &q->UP[n])))			return -1;#if DEBUG_ENABLED && DEBUG_UPDATE	for (n = 0; n < q->numUP; n++)		update_rrdump(t, "UPDATE", n, &q->UP[n]);#endif	/*	**  Additional data section (RFC 2136 2.6)	**  These records are in normal RR format (RFC 1035 4.1.3)	*/	q->numAD = t->arcount;	if (!(q->AD = calloc(q->numAD, sizeof(UQRR))))		Err(_("out of memory"));	for (n = 0; n < q->numAD; n++)		if (!(src = update_gobble_rr(t, soa, query, querylen, src, &q->AD[n])))			return -1;#if DEBUG_ENABLED && DEBUG_UPDATE	for (n = 0; n < q->numAD; n++)		update_rrdump(t, " ADD'L", n, &q->AD[n]);#endif	return 0;}/*--- parse_update_query() ----------------------------------------------------------------------*//**************************************************************************************************	TEXT_RETRIEVE	Retrieve a name from the source without end-dot encoding.**************************************************************************************************/static char *text_retrieve(char *src, char *end, char *data, size_t datalen, int one_word_only){	int n, x;														/* Offset in 'data' */	for (n = 0; src < end && n < datalen; )	{		int len = *src++;		if (n)			data[n++] = ' ';		for (x = 0; x < len && src < end && n < datalen; x++)			data[n++] = *src++;		if (one_word_only)		{			data[n] = '\0';			return (src);		}	}	data[n] = '\0';	return (src);}/*--- text_retrieve() ---------------------------------------------------------------------------*//**************************************************************************************************	UPDATE_GET_RR_DATA	Sets 'data' and 'aux'.	Returns 0 on success, -1 on error.**************************************************************************************************/static intupdate_get_rr_data(TASK *t, MYDNS_SOA *soa, UQ *q, UQRR *rr, char *data, size_t datalen, uint32_t *aux){	char	*src = rr->rdata;	char	*end = rr->rdata + rr->rdlength;	memset(data, 0, datalen);	*aux = 0;	if (!rr->rdlength)		return -1;	switch (rr->type)	{		case DNS_QTYPE_A:			if (rr->rdlength != 4)				return -1;			snprintf(data, datalen, "%d.%d.%d.%d", rr->rdata[0], rr->rdata[1], rr->rdata[2], rr->rdata[3]);			return 0;		case DNS_QTYPE_AAAA:			if (rr->rdlength != 16)				return -1;			if (!(inet_ntop(AF_INET6, &rr->rdata, data, datalen - 1)))				return dnserror(t, DNS_RCODE_FORMERR, ERR_INVALID_ADDRESS);			return 0;		case DNS_QTYPE_CNAME:			if (!(src = name_unencode(t->query, t->len, src, data, datalen)))				return formerr(t, DNS_RCODE_FORMERR, (task_error_t)data[0], NULL);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -