listen.c

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

C
724
字号
/**************************************************************************************************	$Id: listen.c,v 1.42 2006/01/18 20:46:47 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_LISTEN	1#if HAVE_NET_IF_H#  include <net/if.h>#endif#  include <sys/ioctl.h>int *udp4_fd = (int *)NULL;									/* Listening socket: UDP, IPv4 */int *tcp4_fd = (int *)NULL;									/* Listening socket: TCP, IPv4 */int num_udp4_fd = 0;												/* Number of items in 'udp4_fd' */int num_tcp4_fd = 0;												/* Number of items in 'tcp4_fd' */#if HAVE_IPV6int *udp6_fd = (int *)NULL;									/* Listening socket: UDP, IPv6 */int *tcp6_fd = (int *)NULL;									/* Listening socket: TCP, IPv6 */int num_udp6_fd = 0;												/* Number of items in 'udp6_fd' */int num_tcp6_fd = 0;												/* Number of items in 'tcp6_fd' */#endifextern char	*opt_conf;extern uint32_t answer_then_quit;static void server_greeting(void);typedef struct _addrlist{	int					family;									/* AF_INET or AF_INET6 */	struct in_addr		addr4;									/* Address if IPv4 */#if HAVE_IPV6	struct in6_addr	addr6;									/* Address if IPv6 */#endif	int					port;										/* Port number */	int					ok;										/* OK to use this address? */	struct _addrlist *next;										/* Next address */} ADDRLIST;static ADDRLIST *FirstAddr, *LastAddr;						/* Current address list *//**************************************************************************************************	ADDRLIST_ADD	Adds the specified address to the current list, checking for duplicates, etc.**************************************************************************************************/static voidaddrlist_add(int family, void *address, int port){	ADDRLIST *A;	struct in_addr addr4;#if HAVE_IPV6	struct in6_addr addr6;#endif	/* Copy address into struct and make sure it's not the "catch-all" address */	if (family == AF_INET)	{		memcpy(&addr4, address, sizeof(struct in_addr));		if (addr4.s_addr == INADDR_ANY)			return;	}#if HAVE_IPV6	else if (family == AF_INET6)	{		memcpy(&addr6, address, sizeof(struct in6_addr));		if (!memcmp(&addr6, &in6addr_any, sizeof(struct in6_addr)))			return;	}#endif	else return;	/* Invalid family */	/* Check for duplicate */	for (A = FirstAddr; A; A = A->next)		switch (family)		{			case AF_INET:				if ((A->port == port) && !memcmp(&addr4, &A->addr4, sizeof(struct in_addr)))					return;				break;#if HAVE_IPV6			case AF_INET6:				if ((A->port == port) && !memcmp(&addr6, &A->addr6, sizeof(struct in6_addr)))					return;				break;#endif		}	/* Not a duplicate; add new interface */	if (!(A = calloc(1, sizeof(ADDRLIST))))		Err(_("out of memory"));	switch ((A->family = family))	{		case AF_INET: memcpy(&A->addr4, &addr4, sizeof(struct in_addr)); break;#if HAVE_IPV6		case AF_INET6: memcpy(&A->addr6, &addr6, sizeof(struct in6_addr)); break;#endif	}	A->port = port;	A->ok = 1;	/* Add new interface to list */	if (!LastAddr)		FirstAddr = LastAddr = A;	else	{		LastAddr->next = A;		LastAddr = A;	}}/*--- addrlist_add() ----------------------------------------------------------------------------*/#if DEBUG_ENABLED && DEBUG_LISTEN && HAVE_IPV6/**************************************************************************************************	IP6_EXTRA**************************************************************************************************/char *ip6_extra(const struct in6_addr *a){	static char buf[2048];	char *b = buf;	*b = '\0';	if (IN6_IS_ADDR_UNSPECIFIED(a)) b += snprintf(b, sizeof(buf)-(b-buf), "UNSPECIFIED ");	if (IN6_IS_ADDR_LOOPBACK(a)) b += snprintf(b, sizeof(buf)-(b-buf), "LOOPBACK ");	if (IN6_IS_ADDR_MULTICAST(a)) b += snprintf(b, sizeof(buf)-(b-buf), "MULTICAST ");	if (IN6_IS_ADDR_LINKLOCAL(a)) b += snprintf(b, sizeof(buf)-(b-buf), "LINKLOCAL ");	if (IN6_IS_ADDR_SITELOCAL(a)) b += snprintf(b, sizeof(buf)-(b-buf), "SITELOCAL ");	if (IN6_IS_ADDR_V4MAPPED(a)) b += snprintf(b, sizeof(buf)-(b-buf), "V4MAPPED ");	if (IN6_IS_ADDR_V4COMPAT(a)) b += snprintf(b, sizeof(buf)-(b-buf), "V4COMPAT ");	if (IN6_IS_ADDR_MULTICAST(a))	{		if (IN6_IS_ADDR_MC_NODELOCAL(a)) b += snprintf(b, sizeof(buf)-(b-buf), "MC_NODELOCAL ");		if (IN6_IS_ADDR_MC_LINKLOCAL(a)) b += snprintf(b, sizeof(buf)-(b-buf), "MC_LINKLOCAL ");		if (IN6_IS_ADDR_MC_SITELOCAL(a)) b += snprintf(b, sizeof(buf)-(b-buf), "MC_SITELOCAL ");		if (IN6_IS_ADDR_MC_ORGLOCAL(a)) b += snprintf(b, sizeof(buf)-(b-buf), "MC_ORGLOCAL ");		if (IN6_IS_ADDR_MC_GLOBAL(a)) b += snprintf(b, sizeof(buf)-(b-buf), "MC_GLOBAL ");	}	return buf;}/*--- ip6_extra() -------------------------------------------------------------------------------*/#endif/**************************************************************************************************	LINUX_LOAD_IP6	Linux does not return IPv6 interfaces via SIOCGIFCONF, so we load them from	/proc/net/if_inet6.	See http://tldp.org/HOWTO/Linux+IPv6-HOWTO/proc-net.html for file format.**************************************************************************************************/#ifdef __linux__#if HAVE_IPV6static voidlinux_load_ip6(int port){	FILE *fp;	char line[512];	if ((fp = fopen("/proc/net/if_inet6", "r")))	{		while (fgets(line, sizeof(line), fp))		{			int n;			char *l, *hex, *device_number, *prefix_length, *scope_value, *if_flags;			char buf[sizeof("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX\0")];			struct in6_addr addr;			l = line;			if (!(hex = strsep(&l, " "))) continue;			if (!(device_number = strsep(&l, " "))) continue;			if (!(prefix_length = strsep(&l, " "))) continue;			if (!(scope_value = strsep(&l, " "))) continue;			if (!(if_flags = strsep(&l, " "))) continue;			strtrim(l);			/* Convert hex address into 'addr' */			for (n = 0; n < 8; n++)			{				memcpy(buf + (4 * n) + (n * 1), hex + (4 * n), 4);				buf[(4 * n) + (n * 1) + 4] = ':';			}			buf[39] = '\0';#if DEBUG_ENABLED && DEBUG_LISTEN			{				uint16_t dn, pl, sv, f;				dn = (uint16_t)strtoul(device_number, NULL, 16);				pl = (uint16_t)strtoul(prefix_length, NULL, 16);				sv = (uint16_t)strtoul(scope_value, NULL, 16);				f = (uint16_t)strtoul(if_flags, NULL, 16);				Debug("IPv6 %s: device_number=%u prefix_length=%u scope_value=%u if_flags=%u", buf, dn, pl, sv, f);			}#endif			if (inet_pton(AF_INET6, buf, &addr) > 0)			{				/* I am not at all sure which of these scopes from RFC 2553 we should NOT try to					bind to..  LINKLOCAL for sure doesn't work if you try it */				if (IN6_IS_ADDR_LINKLOCAL(&addr))					continue;#if DEBUG_ENABLED && DEBUG_LISTEN				Debug("  extra: %s", ip6_extra(&addr));#endif				addrlist_add(AF_INET6, &addr, port);			}		}		fclose(fp);	}}#endif#endif/*--- linux_load_ip6() --------------------------------------------------------------------------*//**************************************************************************************************	ADDRLIST_LOAD	Gets the IP addresses for all interfaces on the system.	Returns the interface list, or NULL on error.**************************************************************************************************/static ADDRLIST *addrlist_load(int port){	struct ifconf ifc;	struct ifreq *ifr;	int sockfd, buflen = 8192, n;	unsigned char *buf;	FirstAddr = LastAddr = NULL;	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)	{		Warn("error creating socket for interface scan");		return NULL;	}	for (;;)															/* Allocate buffer space */	{		if (!(buf = malloc(buflen)))			Err(_("out of memory"));		ifc.ifc_len = buflen;		ifc.ifc_buf = buf;		if ((n = ioctl(sockfd, SIOCGIFCONF, (char *)&ifc)) != -1)		{			if (ifc.ifc_len + 2 * sizeof(struct ifreq) < buflen)				break;		}		if ((n == -1) && errno != EINVAL)		{			Err("error setting SIOCGIFCONF for interface scan");			return NULL;		}		free(buf);		buflen += 4096;	}	for (n = 0; n < ifc.ifc_len;)								/* Scan interfaces */	{		struct in_addr addr4;#if HAVE_IPV6		struct in6_addr addr6;#endif		ifr = (struct ifreq *)((char *)ifc.ifc_req + n);#ifdef HAVE_SOCKADDR_SA_LEN		n += sizeof(ifr->ifr_name) + (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)												? ifr->ifr_addr.sa_len : sizeof(struct sockaddr));#else		n += sizeof(struct ifreq);#endif /* HAVE_SOCKADDR_SA_LEN */		if (ifr->ifr_flags & IFF_UP)							/* Must be up */			continue;		if (ioctl(sockfd, SIOCGIFADDR, ifr) < 0)			/* Get address */			continue;		switch (ifr->ifr_addr.sa_family)		{			case AF_INET:				memcpy(&addr4, &((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr, sizeof(struct in_addr));				addrlist_add(AF_INET, &addr4, port);				break;#if HAVE_IPV6			case AF_INET6:				memcpy(&addr6, &((struct sockaddr_in6 *)&ifr->ifr_addr)->sin6_addr, sizeof(struct in6_addr));				addrlist_add(AF_INET, &addr4, port);				break;#endif			default:				continue;		}	}	close(sockfd);	free(buf);#ifdef __linux__#if HAVE_IPV6	linux_load_ip6(port);#endif#endif	return (FirstAddr);}/*--- addrlist_load() ---------------------------------------------------------------------------*//**************************************************************************************************	ADDRLIST_FREE**************************************************************************************************/voidaddrlist_free(ADDRLIST *Addresses){	ADDRLIST *A, *tmp;	for (A = Addresses; A; A = tmp)	{		tmp = A->next;		free(A);	}}/*--- addrlist_free() ---------------------------------------------------------------------------*//**************************************************************************************************	GET_OPT_ADDRLIST	Examines the provided configuration option string and returns an ADDRLIST structure containing	the addresses.**************************************************************************************************/static ADDRLIST *get_opt_addrlist(ADDRLIST *Addresses, const char *opt, int default_port, char *desc){	int family;														/* Protocol family (AF_INET/AF_INET6) */	struct in_addr addr4;										/* IPv4 address buffer */#if HAVE_IPV6	struct in6_addr addr6;										/* IPv6 address buffer */

⌨️ 快捷键说明

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