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

📄 dns.c

📁 DHCP服务器源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* dns.c   Domain Name Service subroutines. *//* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 2001-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * *   Internet Systems Consortium, Inc. *   950 Charter Street *   Redwood City, CA 94063 *   <info@isc.org> *   http://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``http://www.isc.org/''.  To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */#ifndef lintstatic char copyright[] ="$Id: dns.c,v 1.35.2.16 2004/06/17 20:54:38 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";#endif /* not lint */#include "dhcpd.h"#include "arpa/nameser.h"#include "dst/md5.h"/* This file is kind of a crutch for the BIND 8 nsupdate code, which has * itself been cruelly hacked from its original state.   What this code * does is twofold: first, it maintains a database of zone cuts that can * be used to figure out which server should be contacted to update any * given domain name.   Secondly, it maintains a set of named TSIG keys, * and associates those keys with zones.   When an update is requested for * a particular zone, the key associated with that zone is used for the * update. * * The way this works is that you define the domain name to which an * SOA corresponds, and the addresses of some primaries for that domain name: * *	zone FOO.COM { *	  primary 10.0.17.1; *	  secondary 10.0.22.1, 10.0.23.1; *	  key "FOO.COM Key"; * 	} * * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM", * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*, * looks for "FOO.COM", finds it. So it * attempts the update to the primary for FOO.COM.   If that times out, it * tries the secondaries.   You can list multiple primaries if you have some * kind of magic name server that supports that.   You shouldn't list * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't * support update forwarding, AFAIK).   If no TSIG key is listed, the update * is attempted without TSIG. * * The DHCP server tries to find an existing zone for any given name by * trying to look up a local zone structure for each domain containing * that name, all the way up to '.'.   If it finds one cached, it tries * to use that one to do the update.   That's why it tries to update * "FOO.COM" above, even though theoretically it should try GAZANGA... * and TOPANGA... first. * * If the update fails with a predefined or cached zone (we'll get to * those in a second), then it tries to find a more specific zone.   This * is done by looking first for an SOA for GAZANGA.TOPANGA.FOO.COM.   Then * an SOA for TOPANGA.FOO.COM is sought.   If during this search a predefined * or cached zone is found, the update fails - there's something wrong * somewhere. * * If a more specific zone _is_ found, that zone is cached for the length of * its TTL in the same database as that described above.   TSIG updates are * never done for cached zones - if you want TSIG updates you _must_ * write a zone definition linking the key to the zone.   In cases where you * know for sure what the key is but do not want to hardcode the IP addresses * of the primary or secondaries, a zone declaration can be made that doesn't * include any primary or secondary declarations.   When the DHCP server * encounters this while hunting up a matching zone for a name, it looks up * the SOA, fills in the IP addresses, and uses that record for the update. * If the SOA lookup returns NXRRSET, a warning is printed and the zone is * discarded, TSIG key and all.   The search for the zone then continues as if * the zone record hadn't been found.   Zones without IP addresses don't * match when initially hunting for a predefined or cached zone to update. * * When an update is attempted and no predefined or cached zone is found * that matches any enclosing domain of the domain being updated, the DHCP * server goes through the same process that is done when the update to a * predefined or cached zone fails - starting with the most specific domain * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root), * it tries to look up an SOA record.   When it finds one, it creates a cached * zone and attempts an update, and gives up if the update fails. * * TSIG keys are defined like this: * *	key "FOO.COM Key" { *		algorithm HMAC-MD5.SIG-ALG.REG.INT; *		secret <Base64>; *	} * * <Base64> is a number expressed in base64 that represents the key. * It's also permissible to use a quoted string here - this will be * translated as the ASCII bytes making up the string, and will not * include any NUL termination.  The key name can be any text string, * and the key type must be one of the key types defined in the draft * or by the IANA.  Currently only the HMAC-MD5... key type is * supported. */dns_zone_hash_t *dns_zone_hash;#if defined (NSUPDATE)isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname,			    struct dns_zone *zone){	isc_result_t status;	ns_tsig_key *tkey;	if (!zone)		return ISC_R_NOTFOUND;	if (!zone -> key) {		return ISC_R_KEY_UNKNOWN;	}		if ((!zone -> key -> name ||	     strlen (zone -> key -> name) > NS_MAXDNAME) ||	    (!zone -> key -> algorithm ||	     strlen (zone -> key -> algorithm) > NS_MAXDNAME) ||	    (!zone -> key) ||	    (!zone -> key -> key) ||	    (zone -> key -> key -> len == 0)) {		return ISC_R_INVALIDKEY;	}	tkey = dmalloc (sizeof *tkey, MDL);	if (!tkey) {	      nomem:		return ISC_R_NOMEMORY;	}	memset (tkey, 0, sizeof *tkey);	tkey -> data = dmalloc (zone -> key -> key -> len, MDL);	if (!tkey -> data) {		dfree (tkey, MDL);		goto nomem;	}	strcpy (tkey -> name, zone -> key -> name);	strcpy (tkey -> alg, zone -> key -> algorithm);	memcpy (tkey -> data,		zone -> key -> key -> value, zone -> key -> key -> len);	tkey -> len = zone -> key -> key -> len;	*key = tkey;	return ISC_R_SUCCESS;}void tkey_free (ns_tsig_key **key){	if ((*key) -> data)		dfree ((*key) -> data, MDL);	dfree ((*key), MDL);	*key = (ns_tsig_key *)0;}#endifisc_result_t enter_dns_zone (struct dns_zone *zone){	struct dns_zone *tz = (struct dns_zone *)0;	if (dns_zone_hash) {		dns_zone_hash_lookup (&tz,				      dns_zone_hash, zone -> name, 0, MDL);		if (tz == zone) {			dns_zone_dereference (&tz, MDL);			return ISC_R_SUCCESS;		}		if (tz) {			dns_zone_hash_delete (dns_zone_hash,					      zone -> name, 0, MDL);			dns_zone_dereference (&tz, MDL);		}	} else {		if (!dns_zone_new_hash (&dns_zone_hash, 1, MDL))			return ISC_R_NOMEMORY;	}	dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL);	return ISC_R_SUCCESS;}isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name){	struct dns_zone *tz = (struct dns_zone *)0;	int len;	char *tname = (char *)0;	isc_result_t status;	if (!dns_zone_hash)		return ISC_R_NOTFOUND;	len = strlen (name);	if (name [len - 1] != '.') {		tname = dmalloc ((unsigned)len + 2, MDL);		if (!tname)			return ISC_R_NOMEMORY;;		strcpy (tname, name);		tname [len] = '.';		tname [len + 1] = 0;		name = tname;	}	if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL))		status = ISC_R_NOTFOUND;	else		status = ISC_R_SUCCESS;	if (tname)		dfree (tname, MDL);	return status;}int dns_zone_dereference (ptr, file, line)	struct dns_zone **ptr;	const char *file;	int line;{	int i;	struct dns_zone *dns_zone;	if (!ptr || !*ptr) {		log_error ("%s(%d): null pointer", file, line);#if defined (POINTER_DEBUG)		abort ();#else		return 0;#endif	}	dns_zone = *ptr;	*ptr = (struct dns_zone *)0;	--dns_zone -> refcnt;	rc_register (file, line, ptr, dns_zone, dns_zone -> refcnt, 1, RC_MISC);	if (dns_zone -> refcnt > 0)		return 1;	if (dns_zone -> refcnt < 0) {		log_error ("%s(%d): negative refcnt!", file, line);#if defined (DEBUG_RC_HISTORY)		dump_rc_history (dns_zone);#endif#if defined (POINTER_DEBUG)		abort ();#else		return 0;#endif	}	if (dns_zone -> name)		dfree (dns_zone -> name, file, line);	if (dns_zone -> key)		omapi_auth_key_dereference (&dns_zone -> key, file, line);	if (dns_zone -> primary)		option_cache_dereference (&dns_zone -> primary, file, line);	if (dns_zone -> secondary)		option_cache_dereference (&dns_zone -> secondary, file, line);	dfree (dns_zone, file, line);	return 1;}#if defined (NSUPDATE)isc_result_t find_cached_zone (const char *dname, ns_class class,			       char *zname, size_t zsize,			       struct in_addr *addrs,			       int naddrs, int *naddrout,			       struct dns_zone **zcookie){	isc_result_t status = ISC_R_NOTFOUND;	const char *np;	struct dns_zone *zone = (struct dns_zone *)0;	struct data_string nsaddrs;	int ix;	/* The absence of the zcookie pointer indicates that we	   succeeded previously, but the update itself failed, meaning	   that we shouldn't use the cached zone. */	if (!zcookie)		return ISC_R_NOTFOUND;	/* We can't look up a null zone. */	if (!dname || !*dname)		return ISC_R_INVALIDARG;	/* For each subzone, try to find a cached zone. */	for (np = dname; np; np = strchr (np, '.')) {		np++;		status = dns_zone_lookup (&zone, np);		if (status == ISC_R_SUCCESS)			break;	}	if (status != ISC_R_SUCCESS)		return status;	/* Make sure the zone is valid. */	if (zone -> timeout && zone -> timeout < cur_time) {		dns_zone_dereference (&zone, MDL);		return ISC_R_CANCELED;	}	/* Make sure the zone name will fit. */	if (strlen (zone -> name) > zsize) {		dns_zone_dereference (&zone, MDL);		return ISC_R_NOSPACE;	}	strcpy (zname, zone -> name);	memset (&nsaddrs, 0, sizeof nsaddrs);	ix = 0;	if (zone -> primary) {		if (evaluate_option_cache (&nsaddrs, (struct packet *)0,					   (struct lease *)0,					   (struct client_state *)0,					   (struct option_state *)0,					   (struct option_state *)0,					   &global_scope,					   zone -> primary, MDL)) {			int ip = 0;			while (ix < naddrs) {				if (ip + 4 > nsaddrs.len)					break;				memcpy (&addrs [ix], &nsaddrs.data [ip], 4);				ip += 4;				ix++;			}			data_string_forget (&nsaddrs, MDL);		}	}	if (zone -> secondary) {		if (evaluate_option_cache (&nsaddrs, (struct packet *)0,					   (struct lease *)0,					   (struct client_state *)0,					   (struct option_state *)0,					   (struct option_state *)0,					   &global_scope,					   zone -> secondary, MDL)) {			int ip = 0;			while (ix < naddrs) {				if (ip + 4 > nsaddrs.len)					break;				memcpy (&addrs [ix], &nsaddrs.data [ip], 4);				ip += 4;				ix++;			}			data_string_forget (&nsaddrs, MDL);		}	}	/* It's not an error for zcookie to have a value here - actually,	   it's quite likely, because res_nupdate cycles through all the	   names in the update looking for their zones. */	if (!*zcookie)		dns_zone_reference (zcookie, zone, MDL);	dns_zone_dereference (&zone, MDL);	if (naddrout)		*naddrout = ix;	return ISC_R_SUCCESS;}void forget_zone (struct dns_zone **zone){	dns_zone_dereference (zone, MDL);}void repudiate_zone (struct dns_zone **zone){	/* XXX Currently we're not differentiating between a cached	   XXX zone and a zone that's been repudiated, which means	   XXX that if we reap cached zones, we blow away repudiated	   XXX zones.   This isn't a big problem since we're not yet	   XXX caching zones... :'} */	(*zone) -> timeout = cur_time - 1;	dns_zone_dereference (zone, MDL);}void cache_found_zone (ns_class class,		       char *zname, struct in_addr *addrs, int naddrs){	isc_result_t status = ISC_R_NOTFOUND;	struct dns_zone *zone = (struct dns_zone *)0;	struct data_string nsaddrs;	int ix = strlen (zname);	if (zname [ix - 1] == '.')		ix = 0;	/* See if there's already such a zone. */	if (dns_zone_lookup (&zone, zname) == ISC_R_SUCCESS) {		/* If it's not a dynamic zone, leave it alone. */		if (!zone -> timeout)			return;		/* Address may have changed, so just blow it away. */		if (zone -> primary)			option_cache_dereference (&zone -> primary, MDL);		if (zone -> secondary)			option_cache_dereference (&zone -> secondary, MDL);	} else if (!dns_zone_allocate (&zone, MDL))		return;	if (!zone -> name) {		zone -> name =			dmalloc (strlen (zname) + 1 + (ix != 0), MDL);		if (!zone -> name) {			dns_zone_dereference (&zone, MDL);			return;		}		strcpy (zone -> name, zname);		/* Add a trailing '.' if it was missing. */		if (ix) {			zone -> name [ix] = '.';			zone -> name [ix + 1] = 0;		}	}	/* XXX Need to get the lower-level code to push the actual zone	   XXX TTL up to us. */	zone -> timeout = cur_time + 1800;		if (!option_cache_allocate (&zone -> primary, MDL)) {		dns_zone_dereference (&zone, MDL);		return;	}	if (!buffer_allocate (&zone -> primary -> data.buffer,			      naddrs * sizeof (struct in_addr), MDL)) {		dns_zone_dereference (&zone, MDL);		return;	}	memcpy (zone -> primary -> data.buffer -> data,		addrs, naddrs * sizeof *addrs);	zone -> primary -> data.data =		&zone -> primary -> data.buffer -> data [0];	zone -> primary -> data.len = naddrs * sizeof *addrs;	enter_dns_zone (zone);}/* Have to use TXT records for now. */#define T_DHCID T_TXTint get_dhcid (struct data_string *id,	       int type, const u_int8_t *data, unsigned len){	unsigned char buf[MD5_DIGEST_LENGTH];	MD5_CTX md5;	int i;	/* Types can only be 0..(2^16)-1. */	if (type < 0 || type > 65535)		return 0;	/* Hexadecimal MD5 digest plus two byte type and NUL. */	if (!buffer_allocate (&id -> buffer,			      (MD5_DIGEST_LENGTH * 2) + 3, MDL))		return 0;	id -> data = id -> buffer -> data;

⌨️ 快捷键说明

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