lwresutil.c

来自「非常好的dns解析软件」· C语言 代码 · 共 577 行

C
577
字号
/* * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000, 2001  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. *//* $Id: lwresutil.c,v 1.30.18.2 2005/04/29 00:17:20 marka Exp $ *//*! \file *//** *    lwres_string_parse() retrieves a DNS-encoded string starting the *    current pointer of lightweight resolver buffer b: i.e. b->current. *    When the function returns, the address of the first byte of the *    encoded string is returned via *c and the length of that string is *    given by *len. The buffer's current pointer is advanced to point at *    the character following the string length, the encoded string, and *    the trailing NULL character. *  *    lwres_addr_parse() extracts an address from the buffer b. The *    buffer's current pointer b->current is presumed to point at an *    encoded address: the address preceded by a 32-bit protocol family *    identifier and a 16-bit length field. The encoded address is copied *    to addr->address and addr->length indicates the size in bytes of *    the address that was copied. b->current is advanced to point at the *  next byte of available data in the buffer following the encoded *    address. *  *    lwres_getaddrsbyname() and lwres_getnamebyaddr() use the *    lwres_gnbaresponse_t structure defined below: *  * \code * typedef struct { *         lwres_uint32_t          flags; *         lwres_uint16_t          naliases; *         lwres_uint16_t          naddrs; *         char                   *realname; *         char                  **aliases; *         lwres_uint16_t          realnamelen; *         lwres_uint16_t         *aliaslen; *         lwres_addrlist_t        addrs; *         void                   *base; *         size_t                  baselen; * } lwres_gabnresponse_t; * \endcode *  *    The contents of this structure are not manipulated directly but *    they are controlled through the \link lwres_gabn.c lwres_gabn*\endlink functions.   *  *    The lightweight resolver uses lwres_getaddrsbyname() to perform *    foward lookups. Hostname name is looked up using the resolver *    context ctx for memory allocation. addrtypes is a bitmask       *    indicating which type of addresses are to be looked up. Current *    values for this bitmask are #LWRES_ADDRTYPE_V4 for IPv4 addresses *    and #LWRES_ADDRTYPE_V6 for IPv6 addresses. Results of the lookup are *    returned in *structp. *  *    lwres_getnamebyaddr() performs reverse lookups. Resolver context   *    ctx is used for memory allocation. The address type is indicated by *    addrtype: #LWRES_ADDRTYPE_V4 or #LWRES_ADDRTYPE_V6. The address to be *    looked up is given by addr and its length is addrlen bytes. The     *    result of the function call is made available through *structp.    *  * \section lwresutil_return Return Values *  *    Successful calls to lwres_string_parse() and lwres_addr_parse() *    return #LWRES_R_SUCCESS. Both functions return #LWRES_R_FAILURE if  *    the buffer is corrupt or #LWRES_R_UNEXPECTEDEND if the buffer has    *    less space than expected for the components of the encoded string *    or address. *  * lwres_getaddrsbyname() returns #LWRES_R_SUCCESS on success and it *    returns #LWRES_R_NOTFOUND if the hostname name could not be found. *  *    #LWRES_R_SUCCESS is returned by a successful call to *    lwres_getnamebyaddr(). *  *    Both lwres_getaddrsbyname() and lwres_getnamebyaddr() return *    #LWRES_R_NOMEMORY when memory allocation requests fail and *    #LWRES_R_UNEXPECTEDEND if the buffers used for sending queries and *    receiving replies are too small.      *  * \section lwresutil_see See Also *  *    lwbuffer.c, lwres_gabn.c */#include <config.h>#include <assert.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <lwres/lwbuffer.h>#include <lwres/lwres.h>#include <lwres/result.h>#include "assert_p.h"#include "context_p.h"/*% Parse data. *//*! * Requires: * *	The "current" pointer in "b" points to encoded raw data. * * Ensures: * *	The address of the first byte of the data is returned via "p", *	and the length is returned via "len".  If NULL, they are not *	set. * *	On return, the current pointer of "b" will point to the character *	following the data length and the data. * */lwres_result_tlwres_data_parse(lwres_buffer_t *b, unsigned char **p, lwres_uint16_t *len){	lwres_uint16_t datalen;	unsigned char *data;	REQUIRE(b != NULL);	/*	 * Pull off the length (2 bytes)	 */	if (!SPACE_REMAINING(b, 2))		return (LWRES_R_UNEXPECTEDEND);	datalen = lwres_buffer_getuint16(b);	/*	 * Set the pointer to this string to the right place, then	 * advance the buffer pointer.	 */	if (!SPACE_REMAINING(b, datalen))		return (LWRES_R_UNEXPECTEDEND);	data = b->base + b->current;	lwres_buffer_forward(b, datalen);	if (len != NULL)		*len = datalen;	if (p != NULL)		*p = data;	return (LWRES_R_SUCCESS);}/*% Retrieves a DNS-encoded string. *//*! * Requires: * *	The "current" pointer in "b" point to an encoded string. * * Ensures: * *	The address of the first byte of the string is returned via "c", *	and the length is returned via "len".  If NULL, they are not *	set. * *	On return, the current pointer of "b" will point to the character *	following the string length, the string, and the trailing NULL. * */lwres_result_tlwres_string_parse(lwres_buffer_t *b, char **c, lwres_uint16_t *len){	lwres_uint16_t datalen;	char *string;	REQUIRE(b != NULL);	/*	 * Pull off the length (2 bytes)	 */	if (!SPACE_REMAINING(b, 2))		return (LWRES_R_UNEXPECTEDEND);	datalen = lwres_buffer_getuint16(b);	/*	 * Set the pointer to this string to the right place, then	 * advance the buffer pointer.	 */	if (!SPACE_REMAINING(b, datalen))		return (LWRES_R_UNEXPECTEDEND);	string = (char *)b->base + b->current;	lwres_buffer_forward(b, datalen);	/*	 * Skip the "must be zero" byte.	 */	if (!SPACE_REMAINING(b, 1))		return (LWRES_R_UNEXPECTEDEND);	if (0 != lwres_buffer_getuint8(b))		return (LWRES_R_FAILURE);	if (len != NULL)		*len = datalen;	if (c != NULL)		*c = string;	return (LWRES_R_SUCCESS);}/*% Extracts an address from the buffer b. */lwres_result_tlwres_addr_parse(lwres_buffer_t *b, lwres_addr_t *addr){	REQUIRE(addr != NULL);	if (!SPACE_REMAINING(b, 6))		return (LWRES_R_UNEXPECTEDEND);	addr->family = lwres_buffer_getuint32(b);	addr->length = lwres_buffer_getuint16(b);	if (!SPACE_REMAINING(b, addr->length))		return (LWRES_R_UNEXPECTEDEND);	if (addr->length > LWRES_ADDR_MAXLEN)		return (LWRES_R_FAILURE);	lwres_buffer_getmem(b, addr->address, addr->length);	return (LWRES_R_SUCCESS);}/*% Used to perform forward lookups. */lwres_result_tlwres_getaddrsbyname(lwres_context_t *ctx, const char *name,		     lwres_uint32_t addrtypes, lwres_gabnresponse_t **structp){	lwres_gabnrequest_t request;	lwres_gabnresponse_t *response;	int ret;	int recvlen;	lwres_buffer_t b_in, b_out;	lwres_lwpacket_t pkt;	lwres_uint32_t serial;	char *buffer;	char target_name[1024];	unsigned int target_length;	REQUIRE(ctx != NULL);	REQUIRE(name != NULL);	REQUIRE(addrtypes != 0);	REQUIRE(structp != NULL && *structp == NULL);	b_in.base = NULL;	b_out.base = NULL;	response = NULL;	buffer = NULL;	serial = lwres_context_nextserial(ctx);	buffer = CTXMALLOC(LWRES_RECVLENGTH);	if (buffer == NULL) {		ret = LWRES_R_NOMEMORY;		goto out;	}	target_length = strlen(name);	if (target_length >= sizeof(target_name))		return (LWRES_R_FAILURE);	strcpy(target_name, name); /* strcpy is safe */	/*	 * Set up our request and render it to a buffer.	 */	request.flags = 0;	request.addrtypes = addrtypes;	request.name = target_name;	request.namelen = target_length;	pkt.pktflags = 0;	pkt.serial = serial;	pkt.result = 0;	pkt.recvlength = LWRES_RECVLENGTH; again:	ret = lwres_gabnrequest_render(ctx, &request, &pkt, &b_out);	if (ret != LWRES_R_SUCCESS)		goto out;	ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,				     LWRES_RECVLENGTH, &recvlen);	if (ret != LWRES_R_SUCCESS)		goto out;	lwres_buffer_init(&b_in, buffer, recvlen);	b_in.used = recvlen;	/*	 * Parse the packet header.	 */	ret = lwres_lwpacket_parseheader(&b_in, &pkt);	if (ret != LWRES_R_SUCCESS)		goto out;	/*	 * Sanity check.	 */	if (pkt.serial != serial)		goto again;	if (pkt.opcode != LWRES_OPCODE_GETADDRSBYNAME)		goto again;	/*	 * Free what we've transmitted	 */	CTXFREE(b_out.base, b_out.length);	b_out.base = NULL;	b_out.length = 0;	if (pkt.result != LWRES_R_SUCCESS) {		ret = pkt.result;		goto out;	}	/*	 * Parse the response.	 */	ret = lwres_gabnresponse_parse(ctx, &b_in, &pkt, &response);	if (ret != LWRES_R_SUCCESS)		goto out;	response->base = buffer;	response->baselen = LWRES_RECVLENGTH;	buffer = NULL; /* don't free this below */	*structp = response;	return (LWRES_R_SUCCESS); out:	if (b_out.base != NULL)		CTXFREE(b_out.base, b_out.length);	if (buffer != NULL)		CTXFREE(buffer, LWRES_RECVLENGTH);	if (response != NULL)		lwres_gabnresponse_free(ctx, &response);	return (ret);}/*% Used to perform reverse lookups. */lwres_result_tlwres_getnamebyaddr(lwres_context_t *ctx, lwres_uint32_t addrtype,		    lwres_uint16_t addrlen, const unsigned char *addr,		    lwres_gnbaresponse_t **structp){	lwres_gnbarequest_t request;	lwres_gnbaresponse_t *response;	int ret;	int recvlen;	lwres_buffer_t b_in, b_out;	lwres_lwpacket_t pkt;	lwres_uint32_t serial;	char *buffer;	REQUIRE(ctx != NULL);	REQUIRE(addrtype != 0);	REQUIRE(addrlen != 0);	REQUIRE(addr != NULL);	REQUIRE(structp != NULL && *structp == NULL);	b_in.base = NULL;	b_out.base = NULL;	response = NULL;	buffer = NULL;	serial = lwres_context_nextserial(ctx);	buffer = CTXMALLOC(LWRES_RECVLENGTH);	if (buffer == NULL) {		ret = LWRES_R_NOMEMORY;		goto out;	}	/*	 * Set up our request and render it to a buffer.	 */	request.flags = 0;	request.addr.family = addrtype;	request.addr.length = addrlen;	memcpy(request.addr.address, addr, addrlen);	pkt.pktflags = 0;	pkt.serial = serial;	pkt.result = 0;	pkt.recvlength = LWRES_RECVLENGTH; again:	ret = lwres_gnbarequest_render(ctx, &request, &pkt, &b_out);	if (ret != LWRES_R_SUCCESS)		goto out;	ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,				     LWRES_RECVLENGTH, &recvlen);	if (ret != LWRES_R_SUCCESS)		goto out;	lwres_buffer_init(&b_in, buffer, recvlen);	b_in.used = recvlen;	/*	 * Parse the packet header.	 */	ret = lwres_lwpacket_parseheader(&b_in, &pkt);	if (ret != LWRES_R_SUCCESS)		goto out;	/*	 * Sanity check.	 */	if (pkt.serial != serial)		goto again;	if (pkt.opcode != LWRES_OPCODE_GETNAMEBYADDR)		goto again;	/*	 * Free what we've transmitted	 */	CTXFREE(b_out.base, b_out.length);	b_out.base = NULL;	b_out.length = 0;	if (pkt.result != LWRES_R_SUCCESS) {		ret = pkt.result;		goto out;	}	/*	 * Parse the response.	 */	ret = lwres_gnbaresponse_parse(ctx, &b_in, &pkt, &response);	if (ret != LWRES_R_SUCCESS)		goto out;	response->base = buffer;	response->baselen = LWRES_RECVLENGTH;	buffer = NULL; /* don't free this below */	*structp = response;	return (LWRES_R_SUCCESS); out:	if (b_out.base != NULL)		CTXFREE(b_out.base, b_out.length);	if (buffer != NULL)		CTXFREE(buffer, LWRES_RECVLENGTH);	if (response != NULL)		lwres_gnbaresponse_free(ctx, &response);	return (ret);}/*% Get rdata by name. */lwres_result_tlwres_getrdatabyname(lwres_context_t *ctx, const char *name,		     lwres_uint16_t rdclass, lwres_uint16_t rdtype,		     lwres_uint32_t flags, lwres_grbnresponse_t **structp){	int ret;	int recvlen;	lwres_buffer_t b_in, b_out;	lwres_lwpacket_t pkt;	lwres_uint32_t serial;	char *buffer;	lwres_grbnrequest_t request;	lwres_grbnresponse_t *response;	char target_name[1024];	unsigned int target_length;	REQUIRE(ctx != NULL);	REQUIRE(name != NULL);	REQUIRE(structp != NULL && *structp == NULL);	b_in.base = NULL;	b_out.base = NULL;	response = NULL;	buffer = NULL;	serial = lwres_context_nextserial(ctx);	buffer = CTXMALLOC(LWRES_RECVLENGTH);	if (buffer == NULL) {		ret = LWRES_R_NOMEMORY;		goto out;	}	target_length = strlen(name);	if (target_length >= sizeof(target_name))		return (LWRES_R_FAILURE);	strcpy(target_name, name); /* strcpy is safe */	/*	 * Set up our request and render it to a buffer.	 */	request.rdclass = rdclass;	request.rdtype = rdtype;	request.flags = flags;	request.name = target_name;	request.namelen = target_length;	pkt.pktflags = 0;	pkt.serial = serial;	pkt.result = 0;	pkt.recvlength = LWRES_RECVLENGTH; again:	ret = lwres_grbnrequest_render(ctx, &request, &pkt, &b_out);	if (ret != LWRES_R_SUCCESS)		goto out;	ret = lwres_context_sendrecv(ctx, b_out.base, b_out.length, buffer,				     LWRES_RECVLENGTH, &recvlen);	if (ret != LWRES_R_SUCCESS)		goto out;	lwres_buffer_init(&b_in, buffer, recvlen);	b_in.used = recvlen;	/*	 * Parse the packet header.	 */	ret = lwres_lwpacket_parseheader(&b_in, &pkt);	if (ret != LWRES_R_SUCCESS)		goto out;	/*	 * Sanity check.	 */	if (pkt.serial != serial)		goto again;	if (pkt.opcode != LWRES_OPCODE_GETRDATABYNAME)		goto again;	/*	 * Free what we've transmitted	 */	CTXFREE(b_out.base, b_out.length);	b_out.base = NULL;	b_out.length = 0;	if (pkt.result != LWRES_R_SUCCESS) {		ret = pkt.result;		goto out;	}	/*	 * Parse the response.	 */	ret = lwres_grbnresponse_parse(ctx, &b_in, &pkt, &response);	if (ret != LWRES_R_SUCCESS)		goto out;	response->base = buffer;	response->baselen = LWRES_RECVLENGTH;	buffer = NULL; /* don't free this below */	*structp = response;	return (LWRES_R_SUCCESS); out:	if (b_out.base != NULL)		CTXFREE(b_out.base, b_out.length);	if (buffer != NULL)		CTXFREE(buffer, LWRES_RECVLENGTH);	if (response != NULL)		lwres_grbnresponse_free(ctx, &response);	return (ret);}

⌨️ 快捷键说明

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