update.c

来自「此dns服务器是在mydns基础上改写」· C语言 代码 · 共 1,538 行 · 第 1/4 页

C
1,538
字号
/**************************************************************************************************	UPDATE_RRTYPE_OK	Is this RR type okay with MyDNS?  RFC 2136 3.4.1.2 specifically prohibigs ANY, AXFR, MAILA,	MAILB, or "any other QUERY metatype" or "any unrecognized type".	Returns 1 if OK, 0 if not OK.**************************************************************************************************/static inline intupdate_rrtype_ok(dns_qtype_t type){	switch (type)	{		/* We support UPDATEs of these types: */		case DNS_QTYPE_A:		case DNS_QTYPE_AAAA:		case DNS_QTYPE_CNAME:		case DNS_QTYPE_HINFO:		case DNS_QTYPE_MX:		case DNS_QTYPE_NS:		case DNS_QTYPE_TXT:		case DNS_QTYPE_PTR:		case DNS_QTYPE_RP:		case DNS_QTYPE_SRV:			return 1;		default:			return 0;	}	return 0;}/*--- update_rrtype_ok() ------------------------------------------------------------------------*//**************************************************************************************************	PRESCAN_UPDATE	Prescan the specified update section record (RFC 2136 3.4.1).	Returns 0 on success, -1 on error.**************************************************************************************************/static intprescan_update(TASK *t, MYDNS_SOA *soa, UQ *q, UQRR *rr){	/* Class must be ANY, NONE, or the same as the zone's class */	if ((rr->class != DNS_CLASS_ANY) && (rr->class != DNS_CLASS_NONE) && (rr->class != q->class))	{#if DEBUG_ENABLED && DEBUG_UPDATE		Debug("%s: DNS UPDATE: prescan_update failed test 1 (check class)", desctask(t));#endif		return dnserror(t, DNS_RCODE_FORMERR, ERR_DB_ERROR);	}	/* "Using the definitions in Section 1.2, each RR's NAME must be in the zone specified by the		Zone Section, else signal NOTZONE to the requestor. */	/* XXX WTF? */	/* "For RRs whose CLASS is not ANY, check the TYPE and if it is ANY, AXFR, MAILA, MAILB, or		any other QUERY metatype, or any unrecognized type, then signal FORMERR to the requestor. */	if ((rr->class != DNS_CLASS_ANY) && !update_rrtype_ok(rr->type))	{#if DEBUG_ENABLED && DEBUG_UPDATE		Debug("%s: DNS UPDATE: prescan_update failed test 2 (check RR types)", desctask(t));#endif		return dnserror(t, DNS_RCODE_FORMERR, ERR_INVALID_TYPE);	}	/* "For RRs whose CLASS is ANY or NONE, check the TTL to see that it is zero (0), else signal		a FORMERR to the requestor." */	if (((rr->class == DNS_CLASS_ANY) || (rr->class == DNS_CLASS_NONE)) && (rr->ttl != 0))	{#if DEBUG_ENABLED && DEBUG_UPDATE		Debug("%s: DNS UPDATE: prescan_update failed test 3 (check TTL)", desctask(t));#endif		return dnserror(t, DNS_RCODE_FORMERR, ERR_INVALID_TTL);	}	/* "For any RR whose CLASS is ANY, check the RDLENGTH to make sure that it is zero (0) (that		is, the RDATA field is empty), and that the TYPE is not AXFR, MAILA, MAILB, or any other		QUERY metatype besides ANY, or any unrecognized type, else signal FORMERR to the		requestor." */	if ((rr->class == DNS_CLASS_ANY) && (rr->rdlength != 0))	{#if DEBUG_ENABLED && DEBUG_UPDATE		Debug("%s: DNS UPDATE: prescan_update failed test 4 (check RDLENGTH)", desctask(t));#endif		return dnserror(t, DNS_RCODE_FORMERR, ERR_INVALID_DATA);	}	if ((rr->class == DNS_CLASS_ANY) && (!update_rrtype_ok(rr->type) && rr->type != DNS_QTYPE_ANY))	{#if DEBUG_ENABLED && DEBUG_UPDATE		Debug("%s: DNS UPDATE: prescan_update failed test 5 (rr->type is %s)", desctask(t), mydns_qtype_str(rr->type));#endif		return dnserror(t, DNS_RCODE_FORMERR, ERR_INVALID_TYPE);	}	return 0;}/*--- prescan_update() --------------------------------------------------------------------------*//**************************************************************************************************	UPDATE_ADD_RR	Add an RR to the zone.	Returns 0 on success, -1 on failure.**************************************************************************************************/static intupdate_add_rr(TASK *t, MYDNS_SOA *soa, UQ *q, UQRR *rr){	static char data[DNS_MAXPACKETLEN_UDP];	uint32_t	aux;	char		*xname = NULL, *xdata = NULL;	SQL_RES	*res = NULL;	SQL_ROW	row;	char		query[512];	size_t	querylen = 0;	int		duplicate = 0;	if (update_get_rr_data(t, soa, q, rr, data, sizeof(data), &aux) != 0)	{#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: update_get_rr_data failed", desctask(t));#endif		return dnserror(t, DNS_RCODE_FORMERR, ERR_INVALID_DATA);	}#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: UPDATE_ADD_RR: %s %u %s %s %u %s", desctask(t),			rr->name, rr->ttl, mydns_class_str(rr->class), mydns_qtype_str(rr->type), aux, data);#endif	/* Construct query */   if (!(xname = calloc(strlen(rr->name) * 2 + 1, sizeof(char))))      Err(_("out of memory"));	sql_escstr(sql, xname, rr->name, strlen(rr->name));   if (!(xdata = calloc(strlen(data) * 2 + 1, sizeof(char))))      Err(_("out of memory"));	sql_escstr(sql, xdata, data, strlen(data));	/* First we have to see if this record exists.  If it does, we should "silently ignore" it. */#if USE_PGSQL	/* This is only necessary for Postgres, we can use "INSERT IGNORE" with MySQL */	querylen = snprintf(query, sizeof(query),		"SELECT id FROM %s WHERE zone=%u AND name='%s' AND type='%s' AND data='%s' LIMIT 1",		mydns_rr_table_name, soa->id, xname, mydns_qtype_str(rr->type), xdata);#if DEBUG_UPDATE_SQL	Verbose("%s: DNS UPDATE: %s", desctask(t), query);#endif#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: UPDATE_ADD_RR: %s", desctask(t), query);#endif	if (!(res = sql_query(sql, query, querylen)))	{		WarnSQL(sql, "%s: %s", desctask(t), _("error searching duplicate for DNS UPDATE"));		return dnserror(t, DNS_RCODE_SERVFAIL, ERR_DB_ERROR);	}	if (sql_num_rows(res) > 0)		duplicate = 1;	sql_free(res);#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: UPDATE_ADD_RR: duplicate=%d", desctask(t), duplicate);#endif#endif	if (!duplicate)	{		querylen = snprintf(query, sizeof(query),#if USE_PGSQL			"INSERT INTO %s"#else			"INSERT IGNORE INTO %s"#endif			" (zone,name,type,data,aux,ttl%s)"			" VALUES (%u,'%s','%s','%s',%u,%u%s%s%s)",			mydns_rr_table_name,			mydns_rr_use_active ? ",active" : "",			soa->id, xname, mydns_qtype_str(rr->type), xdata, aux, rr->ttl,			mydns_rr_use_active ? ",'" : "",			mydns_rr_use_active ? "Y" : "",			mydns_rr_use_active ? "'" : ""		);#if DEBUG_UPDATE_SQL		Verbose("%s: DNS UPDATE: %s", desctask(t), query);#endif	}	Free(xname);	Free(xdata);#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: DNS UPDATE: ADD RR: %s", desctask(t), query);#endif	/* Execute the query */	if (!duplicate)	{		if (sql_nrquery(sql, query, querylen) != 0)		{			WarnSQL(sql, "%s: %s", desctask(t), _("error adding RR via DNS UPDATE"));			return dnserror(t, DNS_RCODE_SERVFAIL, ERR_DB_ERROR);		}		sql_free(res);	}	/* Output info to verbose log */	snprintf(query, sizeof(query), "ADD %s %u IN %s %u %s",				rr->name, rr->ttl, mydns_qtype_str(rr->type), aux, data);	task_output_info(t, query);	t->update_done++;	return 0;}/*--- update_add_rr() ---------------------------------------------------------------------------*//**************************************************************************************************	UPDATE_DELETE_RRSET_ALL	Deletes all RRsets from the zone for a specified name.	Returns 0 on success, -1 on failure.**************************************************************************************************/static intupdate_delete_rrset_all(TASK *t, MYDNS_SOA *soa, UQ *q, UQRR *rr){	char		*xname = NULL, *xhost = NULL;	char		query[512];	size_t	querylen;	SQL_RES	*res = NULL;	SQL_ROW	row;#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: UPDATE_DELETE_RRSET_ALL: %s %u %s %s", desctask(t),			rr->name, rr->ttl, mydns_class_str(rr->class), mydns_qtype_str(rr->type));#endif#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: DNS UPDATE: DELETE ALL RRSETS: %s", desctask(t), rr->name);#endif	/* Delete rrset - check both the FQDN and the hostname without trailing dot */   if (!(xname = calloc(strlen(rr->name) * 2 + 1, sizeof(char))))      Err(_("out of memory"));	sql_escstr(sql, xname, rr->name, strlen(rr->name));   if (!(xhost = calloc(strlen(rr->name) * 2 + 1, sizeof(char))))      Err(_("out of memory"));	querylen = snprintf(query, sizeof(query), "%.*s", strlen(rr->name) - strlen(soa->origin) - 1, rr->name);	sql_escstr(sql, xhost, query, querylen);	querylen = snprintf(query, sizeof(query), "DELETE FROM %s WHERE zone=%u AND (name='%s' OR name='%s')",							  mydns_rr_table_name, soa->id, xname, xhost);#if DEBUG_UPDATE_SQL	Verbose("%s: DNS UPDATE: %s", desctask(t), query);#endif#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: DNS UPDATE: DELETE RRSET_ALL: %s", desctask(t), query);#endif	Free(xname);	Free(xhost);	/* Execute the query */	if (sql_nrquery(sql, query, querylen) != 0)	{		WarnSQL(sql, "%s: %s", desctask(t), _("error deleting all RRsets via DNS UPDATE"));		return dnserror(t, DNS_RCODE_SERVFAIL, ERR_DB_ERROR);	}	sql_free(res);	/* Output info to verbose log */	snprintf(query, sizeof(query), "DELETE_ALL_RRSET %s", rr->name);	task_output_info(t, query);	t->update_done++;	return 0;}/*--- update_delete_rrset_all() -----------------------------------------------------------------*//**************************************************************************************************	UPDATE_DELETE_RR	Deletes an RR from the zone for a specified name.	Returns 0 on success, -1 on failure.**************************************************************************************************/static intupdate_delete_rr(TASK *t, MYDNS_SOA *soa, UQ *q, UQRR *rr){	static char data[DNS_MAXPACKETLEN_UDP];	uint32_t	aux;	char		*xname = NULL, *xhost = NULL, *xdata = NULL;	char		query[512];	size_t	querylen;	SQL_RES	*res = NULL;	SQL_ROW	row;#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: UPDATE_DELETE_RR: %s %u %s %s", desctask(t),			rr->name, rr->ttl, mydns_class_str(rr->class), mydns_qtype_str(rr->type));#endif	if (update_get_rr_data(t, soa, q, rr, data, sizeof(data), &aux) != 0)	{#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: update_get_rr_data failed", desctask(t));#endif		return dnserror(t, DNS_RCODE_FORMERR, ERR_INVALID_DATA);	}#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: DNS UPDATE: DELETE RR: %s IN %s %s", desctask(t), rr->name, mydns_qtype_str(rr->type), data);#endif	/* Delete rr - check both the FQDN and the hostname without trailing dot */   if (!(xname = calloc(strlen(rr->name) * 2 + 1, sizeof(char))))      Err(_("out of memory"));	sql_escstr(sql, xname, rr->name, strlen(rr->name));   if (!(xhost = calloc(strlen(rr->name) * 2 + 1, sizeof(char))))      Err(_("out of memory"));	querylen = snprintf(query, sizeof(query), "%.*s", strlen(rr->name) - strlen(soa->origin) - 1, rr->name);	sql_escstr(sql, xhost, query, querylen);   if (!(xdata = calloc(strlen(data) * 2 + 1, sizeof(char))))      Err(_("out of memory"));	sql_escstr(sql, xdata, data, strlen(data));	querylen = snprintf(query, sizeof(query),		"DELETE FROM %s WHERE zone=%u AND (name='%s' OR name='%s') AND type='%s' AND data='%s'",							  mydns_rr_table_name, soa->id, xname, xhost, mydns_qtype_str(rr->type), xdata);#if DEBUG_UPDATE_SQL	Verbose("%s: DNS UPDATE: %s", desctask(t), query);#endif#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: DNS UPDATE: DELETE RR: %s", desctask(t), query);#endif	Free(xname);	Free(xhost);	Free(xdata);	/* Execute the query */	if (sql_nrquery(sql, query, querylen) != 0)	{		WarnSQL(sql, "%s: %s", desctask(t), _("error deleting RR via DNS UPDATE"));		return dnserror(t, DNS_RCODE_SERVFAIL, ERR_DB_ERROR);	}	sql_free(res);	/* Output info to verbose log */	snprintf(query, sizeof(query), "DELETE %s IN %s %s", rr->name, mydns_qtype_str(rr->type), data);	task_output_info(t, query);	t->update_done++;	return 0;}/*--- update_delete_rr() ------------------------------------------------------------------------*//**************************************************************************************************	UPDATE_DELETE_RRSET	Deletes an RRset from the zone for a specified name.	Returns 0 on success, -1 on failure.**************************************************************************************************/static intupdate_delete_rrset(TASK *t, MYDNS_SOA *soa, UQ *q, UQRR *rr){	char		*xname = NULL, *xhost = NULL;	char		query[512];	size_t	querylen;	SQL_RES	*res = NULL;	SQL_ROW	row;#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: UPDATE_DELETE_RRSET: %s %u %s %s", desctask(t),			rr->name, rr->ttl, mydns_class_str(rr->class), mydns_qtype_str(rr->type));#endif#if DEBUG_ENABLED && DEBUG_UPDATE	Debug("%s: DNS UPDATE: DELETE RRSET: %s IN %s", desctask(t), rr->name, mydns_qtype_str(rr->type));#endif	/* Delete rr - check both the FQDN and the hostname without trailing dot */   if (!(xname = calloc(strlen(rr->name) * 2 + 1, sizeof(char))))      Err(_("out of memory"));	sql_escstr(sql, xname, rr->name, strlen(rr->name));   if (!(xhost = calloc(strlen(rr->name) * 2 + 1, sizeof(char))))      Err(_("out of memory"));	querylen = snprintf(query, sizeof(query), "%.*s", strlen(rr->name) - strlen(soa->origin) - 1, rr->name);	sql_escstr(sql, xhost, query, querylen);

⌨️ 快捷键说明

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