Blame ninfod/ninfod_core.c

Packit 1034e0
/* $USAGI: ninfod_core.c,v 1.29 2003-07-16 09:49:01 yoshfuji Exp $ */
Packit 1034e0
/*
Packit 1034e0
 * Copyright (C) 2002 USAGI/WIDE Project.
Packit 1034e0
 * All rights reserved.
Packit 1034e0
 * 
Packit 1034e0
 * Redistribution and use in source and binary forms, with or without
Packit 1034e0
 * modification, are permitted provided that the following conditions
Packit 1034e0
 * are met:
Packit 1034e0
 * 1. Redistributions of source code must retain the above copyright
Packit 1034e0
 *    notice, this list of conditions and the following disclaimer.
Packit 1034e0
 * 2. Redistributions in binary form must reproduce the above copyright
Packit 1034e0
 *    notice, this list of conditions and the following disclaimer in the
Packit 1034e0
 *    documentation and/or other materials provided with the distribution.
Packit 1034e0
 * 3. Neither the name of the project nor the names of its contributors
Packit 1034e0
 *    may be used to endorse or promote products derived from this software
Packit 1034e0
 *    without specific prior written permission.
Packit 1034e0
 * 
Packit 1034e0
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
Packit 1034e0
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit 1034e0
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit 1034e0
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
Packit 1034e0
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit 1034e0
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit 1034e0
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit 1034e0
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit 1034e0
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit 1034e0
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit 1034e0
 * SUCH DAMAGE.
Packit 1034e0
 */
Packit 1034e0
/*
Packit 1034e0
 * Author:
Packit 1034e0
 * 	YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Packit 1034e0
 */
Packit 1034e0
Packit 1034e0
#if HAVE_CONFIG_H
Packit 1034e0
#include "config.h"
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
#if HAVE_SYS_TYPES_H
Packit 1034e0
# include <sys/types.h>
Packit 1034e0
#endif
Packit 1034e0
#if STDC_HEADERS
Packit 1034e0
# include <stdio.h>
Packit 1034e0
# include <stdlib.h>
Packit 1034e0
# include <stddef.h>
Packit 1034e0
#else
Packit 1034e0
# if HAVE_STDLIB_H
Packit 1034e0
#  include <stdlib.h>
Packit 1034e0
# endif
Packit 1034e0
#endif
Packit 1034e0
#if ENABLE_THREADS && HAVE_PTHREAD_H
Packit 1034e0
# include <pthread.h>
Packit 1034e0
#endif
Packit 1034e0
#if HAVE_STRING_H
Packit 1034e0
# if !STDC_HEADERS && HAVE_MEMORY_H
Packit 1034e0
#  include <memory.h>
Packit 1034e0
# endif
Packit 1034e0
# include <string.h>
Packit 1034e0
#endif
Packit 1034e0
#if HAVE_STRINGS_H
Packit 1034e0
# include <strings.h>
Packit 1034e0
#endif
Packit 1034e0
#if HAVE_INTTYPES_H
Packit 1034e0
# include <inttypes.h>
Packit 1034e0
#else
Packit 1034e0
# if HAVE_STDINT_H
Packit 1034e0
#  include <stdint.h>
Packit 1034e0
# endif
Packit 1034e0
#endif
Packit 1034e0
#if HAVE_UNISTD_H
Packit 1034e0
# include <unistd.h>
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
#if TIME_WITH_SYS_TIME   
Packit 1034e0
# include <sys/time.h>  
Packit 1034e0
# include <time.h>
Packit 1034e0
#else
Packit 1034e0
# if HAVE_SYS_TIME_H     
Packit 1034e0
#  include <sys/time.h>
Packit 1034e0
# else                
Packit 1034e0
#  include <time.h>
Packit 1034e0
# endif                  
Packit 1034e0
#endif                   
Packit 1034e0
Packit 1034e0
#if HAVE_SYS_UIO_H
Packit 1034e0
#include <sys/uio.h>
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
#if HAVE_NETINET_IN_H
Packit 1034e0
# include <netinet/in.h>
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
#if HAVE_NETINET_ICMP6_H
Packit 1034e0
# include <netinet/icmp6.h>
Packit 1034e0
#endif
Packit 1034e0
#ifndef HAVE_STRUCT_ICMP6_NODEINFO
Packit 1034e0
# include "icmp6_nodeinfo.h"
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
#if HAVE_NETDB_H
Packit 1034e0
# include <netdb.h>
Packit 1034e0
#endif
Packit 1034e0
#include <errno.h>
Packit 1034e0
Packit 1034e0
#if HAVE_SYSLOG_H
Packit 1034e0
# include <syslog.h>
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
#include "ninfod.h"
Packit 1034e0
Packit 1034e0
#ifndef offsetof
Packit 1034e0
# define offsetof(aggregate,member)	((size_t)&((aggregate *)0)->member)
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
#define ARRAY_SIZE(a)		(sizeof(a) / sizeof(a[0]))
Packit 1034e0
Packit 1034e0
/* ---------- */
Packit 1034e0
/* ID */
Packit 1034e0
static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_core.c,v 1.29 2003-07-16 09:49:01 yoshfuji Exp $";
Packit 1034e0
Packit 1034e0
/* Variables */
Packit 1034e0
int initialized = 0;
Packit 1034e0
Packit 1034e0
#if ENABLE_THREADS && HAVE_LIBPTHREAD
Packit 1034e0
pthread_attr_t pattr;
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
static uint32_t suptypes[(MAX_SUPTYPES+31)>>5];
Packit 1034e0
static size_t suptypes_len;
Packit 1034e0
Packit 1034e0
/* ---------- */
Packit 1034e0
struct subjinfo {
Packit 1034e0
	uint8_t	code;
Packit 1034e0
	char	*name;
Packit 1034e0
	int	(*checksubj)(CHECKANDFILL_ARGS);
Packit 1034e0
	int	(*init)(INIT_ARGS);
Packit 1034e0
};
Packit 1034e0
Packit 1034e0
static struct subjinfo subjinfo_table [] = {
Packit 1034e0
	[ICMP6_NI_SUBJ_IPV6] = {
Packit 1034e0
		.code = ICMP6_NI_SUBJ_IPV6,
Packit 1034e0
		.name = "IPv6",
Packit 1034e0
		//.init = init_nodeinfo_ipv6addr,
Packit 1034e0
		.checksubj = pr_nodeinfo_ipv6addr,
Packit 1034e0
	},
Packit 1034e0
	[ICMP6_NI_SUBJ_FQDN] = {
Packit 1034e0
		.code = ICMP6_NI_SUBJ_FQDN,
Packit 1034e0
		.name = "FQDN",
Packit 1034e0
		//.init = init_nodeinfo_nodename,
Packit 1034e0
		.checksubj = pr_nodeinfo_nodename,
Packit 1034e0
	},
Packit 1034e0
	[ICMP6_NI_SUBJ_IPV4] = {
Packit 1034e0
		.code = ICMP6_NI_SUBJ_IPV4,
Packit 1034e0
		.name = "IPv4",
Packit 1034e0
		//.init = init_nodeinfo_ipv4addr,
Packit 1034e0
		.checksubj = pr_nodeinfo_ipv4addr,
Packit 1034e0
	},
Packit 1034e0
};
Packit 1034e0
Packit 1034e0
static struct subjinfo subjinfo_null = {
Packit 1034e0
	.name = "null",
Packit 1034e0
	.checksubj = pr_nodeinfo_noop,
Packit 1034e0
};
Packit 1034e0
Packit 1034e0
static __inline__ struct subjinfo *subjinfo_lookup(int code)
Packit 1034e0
{
Packit 1034e0
	if (code >= ARRAY_SIZE(subjinfo_table))
Packit 1034e0
		return NULL;
Packit 1034e0
	if (subjinfo_table[code].name == NULL)
Packit 1034e0
		return NULL;
Packit 1034e0
	return &subjinfo_table[code];
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
/* ---------- */
Packit 1034e0
#define QTYPEINFO_F_RATELIMIT	0x1
Packit 1034e0
Packit 1034e0
struct qtypeinfo {
Packit 1034e0
	uint16_t qtype;
Packit 1034e0
	char	*name;
Packit 1034e0
	int	(*getreply)(CHECKANDFILL_ARGS);
Packit 1034e0
	void	(*init)(INIT_ARGS);
Packit 1034e0
	int	flags;
Packit 1034e0
};
Packit 1034e0
Packit 1034e0
static struct qtypeinfo qtypeinfo_table[] = {
Packit 1034e0
	[NI_QTYPE_NOOP]		= {
Packit 1034e0
		.qtype = NI_QTYPE_NOOP,
Packit 1034e0
		.name = "NOOP",
Packit 1034e0
		.getreply = pr_nodeinfo_noop,
Packit 1034e0
	},
Packit 1034e0
#if ENABLE_SUPTYPES
Packit 1034e0
	[NI_QTYPE_SUPTYPES]	= {
Packit 1034e0
		.qtype = NI_QTYPE_SUPTYPES,
Packit 1034e0
		.name = "SupTypes",
Packit 1034e0
		.getreply = pr_nodeinfo_suptypes,
Packit 1034e0
		.init = init_nodeinfo_suptypes,
Packit 1034e0
	},
Packit 1034e0
#endif
Packit 1034e0
	[NI_QTYPE_DNSNAME]	= {
Packit 1034e0
		.qtype = NI_QTYPE_DNSNAME,
Packit 1034e0
		.name = "DnsName",
Packit 1034e0
		.getreply = pr_nodeinfo_nodename,
Packit 1034e0
		.init = init_nodeinfo_nodename,
Packit 1034e0
	},
Packit 1034e0
	[NI_QTYPE_NODEADDR]	= {
Packit 1034e0
		.qtype = NI_QTYPE_NODEADDR,
Packit 1034e0
		.name = "NodeAddr",
Packit 1034e0
		.getreply = pr_nodeinfo_ipv6addr,
Packit 1034e0
		.init = init_nodeinfo_ipv6addr,
Packit 1034e0
	},
Packit 1034e0
	[NI_QTYPE_IPV4ADDR]	= {
Packit 1034e0
		.qtype = NI_QTYPE_IPV4ADDR,
Packit 1034e0
		.name = "IPv4Addr",
Packit 1034e0
		.getreply = pr_nodeinfo_ipv4addr,
Packit 1034e0
		.init = init_nodeinfo_ipv4addr,
Packit 1034e0
	},
Packit 1034e0
};
Packit 1034e0
Packit 1034e0
static struct qtypeinfo qtypeinfo_unknown = {
Packit 1034e0
	.name = "unknown",
Packit 1034e0
	.getreply = pr_nodeinfo_unknown,
Packit 1034e0
	.flags = QTYPEINFO_F_RATELIMIT,
Packit 1034e0
};
Packit 1034e0
Packit 1034e0
static struct qtypeinfo qtypeinfo_refused = {
Packit 1034e0
	.name = "refused",
Packit 1034e0
	.getreply = pr_nodeinfo_refused,
Packit 1034e0
	.flags = QTYPEINFO_F_RATELIMIT,
Packit 1034e0
};
Packit 1034e0
Packit 1034e0
static __inline__ struct qtypeinfo *qtypeinfo_lookup(int qtype)
Packit 1034e0
{
Packit 1034e0
	if (qtype >= ARRAY_SIZE(qtypeinfo_table))
Packit 1034e0
		return &qtypeinfo_unknown;
Packit 1034e0
	if (qtypeinfo_table[qtype].name == NULL)
Packit 1034e0
		return &qtypeinfo_unknown;
Packit 1034e0
	return &qtypeinfo_table[qtype];
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
/* ---------- */
Packit 1034e0
/* noop */
Packit 1034e0
int pr_nodeinfo_noop(CHECKANDFILL_ARGS)
Packit 1034e0
{
Packit 1034e0
	DEBUG(LOG_DEBUG, "%s()\n", __func__);
Packit 1034e0
Packit 1034e0
	if (subjlen) {
Packit 1034e0
		DEBUG(LOG_WARNING,
Packit 1034e0
		      "%s(): invalid subject length(%zu)\n",
Packit 1034e0
		      __func__, subjlen);
Packit 1034e0
		return 1;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	if (reply) {
Packit 1034e0
		p->reply.ni_type = ICMP6_NI_REPLY;
Packit 1034e0
		p->reply.ni_code = ICMP6_NI_SUCCESS;
Packit 1034e0
		p->reply.ni_cksum = 0;
Packit 1034e0
		p->reply.ni_qtype = htons(NI_QTYPE_NOOP);
Packit 1034e0
		p->reply.ni_flags = flags;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	if (subj_if)
Packit 1034e0
		*subj_if = 0;
Packit 1034e0
Packit 1034e0
	return 0;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
#if ENABLE_SUPTYPES
Packit 1034e0
/* suptypes */
Packit 1034e0
int pr_nodeinfo_suptypes(CHECKANDFILL_ARGS)
Packit 1034e0
{
Packit 1034e0
	DEBUG(LOG_DEBUG, "%s()\n", __func__);
Packit 1034e0
Packit 1034e0
	if (subjlen) {
Packit 1034e0
		DEBUG(LOG_WARNING, "%s(): invalid subject length(%zu)\n",
Packit 1034e0
		      __func__, subjlen);
Packit 1034e0
		return 1;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	if (reply) {
Packit 1034e0
		p->reply.ni_type = ICMP6_NI_REPLY;
Packit 1034e0
		p->reply.ni_code = ICMP6_NI_SUCCESS;
Packit 1034e0
		p->reply.ni_cksum = 0;
Packit 1034e0
		p->reply.ni_qtype = htons(NI_QTYPE_SUPTYPES);
Packit 1034e0
		p->reply.ni_flags = flags&~NI_SUPTYPE_FLAG_COMPRESS;
Packit 1034e0
		
Packit 1034e0
		p->replydatalen = suptypes_len<<2;
Packit 1034e0
		p->replydata = ni_malloc(p->replydatalen);
Packit 1034e0
		if (p->replydata == NULL) {
Packit 1034e0
			p->replydatalen = -1;
Packit 1034e0
			return -1;	/*XXX*/
Packit 1034e0
		}
Packit 1034e0
Packit 1034e0
		memcpy(p->replydata, suptypes, p->replydatalen);
Packit 1034e0
	}
Packit 1034e0
	return 0;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
void init_nodeinfo_suptypes(INIT_ARGS)
Packit 1034e0
{
Packit 1034e0
	size_t w, b;
Packit 1034e0
	int i;
Packit 1034e0
Packit 1034e0
	if (!forced && initialized)
Packit 1034e0
		return;
Packit 1034e0
Packit 1034e0
	memset(suptypes, 0, sizeof(suptypes));
Packit 1034e0
	suptypes_len = 0;
Packit 1034e0
Packit 1034e0
	for (i=0; i < ARRAY_SIZE(qtypeinfo_table); i++) {
Packit 1034e0
		unsigned short qtype;
Packit 1034e0
Packit 1034e0
		if (qtypeinfo_table[i].name == NULL)
Packit 1034e0
			continue;
Packit 1034e0
		qtype = qtypeinfo_table[i].qtype;
Packit 1034e0
		w = qtype>>5;
Packit 1034e0
		b = qtype&0x1f;
Packit 1034e0
		if (w >= ARRAY_SIZE(suptypes)) {
Packit 1034e0
			/* This is programming error. */
Packit 1034e0
			DEBUG(LOG_ERR, "Warning: Too Large Supported Types\n");
Packit 1034e0
			exit(1);
Packit 1034e0
		}
Packit 1034e0
		suptypes[w] |= htonl(1<
Packit 1034e0
Packit 1034e0
		if (suptypes_len < w)
Packit 1034e0
			suptypes_len = w;
Packit 1034e0
	}
Packit 1034e0
	suptypes_len++;
Packit 1034e0
}
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
/* ---------- */
Packit 1034e0
/* unknown qtype response */
Packit 1034e0
int pr_nodeinfo_unknown(CHECKANDFILL_ARGS)
Packit 1034e0
{
Packit 1034e0
	if (!reply)
Packit 1034e0
		return -1;	/*???*/
Packit 1034e0
Packit 1034e0
	p->reply.ni_type = ICMP6_NI_REPLY;
Packit 1034e0
	p->reply.ni_code = ICMP6_NI_UNKNOWN;
Packit 1034e0
	p->reply.ni_cksum = 0;
Packit 1034e0
	//p->reply.ni_qtype = 0;
Packit 1034e0
	p->reply.ni_flags = flags;
Packit 1034e0
Packit 1034e0
	p->replydata = NULL;
Packit 1034e0
	p->replydatalen = 0;
Packit 1034e0
Packit 1034e0
	return 0;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
/* refused response */
Packit 1034e0
int pr_nodeinfo_refused(CHECKANDFILL_ARGS)
Packit 1034e0
{
Packit 1034e0
	if (!reply)
Packit 1034e0
		return -1;	/*???*/
Packit 1034e0
Packit 1034e0
	p->reply.ni_type = ICMP6_NI_REPLY;
Packit 1034e0
	p->reply.ni_code = ICMP6_NI_REFUSED;
Packit 1034e0
	p->reply.ni_cksum = 0;
Packit 1034e0
	//p->reply.ni_qtype = 0;
Packit 1034e0
	p->reply.ni_flags = flags;
Packit 1034e0
Packit 1034e0
	p->replydata = NULL;
Packit 1034e0
	p->replydatalen = 0;
Packit 1034e0
Packit 1034e0
	return 0;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
/* ---------- */
Packit 1034e0
/* Policy */
Packit 1034e0
static int ni_policy(struct packetcontext *p)
Packit 1034e0
{
Packit 1034e0
	const struct in6_addr *saddr = &((const struct sockaddr_in6 *)&p->addr)->sin6_addr;
Packit 1034e0
Packit 1034e0
	/*
Packit 1034e0
	 * >0: reply
Packit 1034e0
	 *  0: refused
Packit 1034e0
	 * <0: discard
Packit 1034e0
	 */
Packit 1034e0
Packit 1034e0
	/* Default policy is to refuse queries from
Packit 1034e0
	 * non-local addresses; loopback, link-local or
Packit 1034e0
	 * site-local are okay
Packit 1034e0
	 */
Packit 1034e0
	if (!(IN6_IS_ADDR_LINKLOCAL(saddr) ||
Packit 1034e0
	      IN6_IS_ADDR_SITELOCAL(saddr) ||
Packit 1034e0
	      IN6_IS_ADDR_LOOPBACK(saddr)))
Packit 1034e0
		return 0;
Packit 1034e0
	return 1;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
/* ---------- */
Packit 1034e0
void init_core(int forced)
Packit 1034e0
{
Packit 1034e0
	int i;
Packit 1034e0
Packit 1034e0
	DEBUG(LOG_DEBUG, "%s()\n", __func__);
Packit 1034e0
Packit 1034e0
	if (!initialized || forced) {
Packit 1034e0
		struct timeval tv;
Packit 1034e0
		unsigned int seed = 0;
Packit 1034e0
		pid_t pid;
Packit 1034e0
Packit 1034e0
		if (gettimeofday(&tv, NULL) < 0) {
Packit 1034e0
			DEBUG(LOG_WARNING, "%s(): failed to gettimeofday()\n", __func__);
Packit 1034e0
		} else {
Packit 1034e0
			seed = (tv.tv_usec & 0xffffffff);
Packit 1034e0
		}
Packit 1034e0
Packit 1034e0
		pid = getpid();
Packit 1034e0
		seed ^= (((unsigned long)pid) & 0xffffffff);
Packit 1034e0
Packit 1034e0
		srand(seed);
Packit 1034e0
Packit 1034e0
#if ENABLE_THREADS && HAVE_LIBPTHREAD
Packit 1034e0
		if (initialized)
Packit 1034e0
			pthread_attr_destroy(&pattr);
Packit 1034e0
Packit 1034e0
		pthread_attr_init(&pattr);
Packit 1034e0
		pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
Packit 1034e0
#endif
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	for (i=0; i < ARRAY_SIZE(subjinfo_table); i++) {
Packit 1034e0
		if (subjinfo_table[i].name == NULL)
Packit 1034e0
			continue;
Packit 1034e0
		if (subjinfo_table[i].init)
Packit 1034e0
			subjinfo_table[i].init(forced);
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	for (i=0; i < ARRAY_SIZE(qtypeinfo_table); i++) {
Packit 1034e0
		if (qtypeinfo_table[i].name == NULL)
Packit 1034e0
			continue;
Packit 1034e0
		if (qtypeinfo_table[i].init)
Packit 1034e0
			qtypeinfo_table[i].init(forced);
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	initialized = 1;
Packit 1034e0
Packit 1034e0
	return;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
#if ENABLE_THREADS && HAVE_LIBPTHREAD
Packit 1034e0
static void *ni_send_thread(void *data)
Packit 1034e0
{
Packit 1034e0
	int ret;
Packit 1034e0
	DEBUG(LOG_DEBUG, "%s(): thread=%ld\n", __func__, pthread_self());
Packit 1034e0
	ret = ni_send(data);
Packit 1034e0
	DEBUG(LOG_DEBUG, "%s(): thread=%ld => %d\n", __func__, pthread_self(), ret);
Packit 1034e0
	return NULL;
Packit 1034e0
}
Packit 1034e0
#else
Packit 1034e0
static int ni_send_fork(struct packetcontext *p)
Packit 1034e0
{
Packit 1034e0
	pid_t child = fork();
Packit 1034e0
	if (child < 0)
Packit 1034e0
		return -1;
Packit 1034e0
	if (child == 0) {
Packit 1034e0
		pid_t grandchild = fork();
Packit 1034e0
		if (grandchild < 0)
Packit 1034e0
			exit(1);
Packit 1034e0
		if (grandchild == 0) {
Packit 1034e0
			int ret;
Packit 1034e0
			DEBUG(LOG_DEBUG, "%s(): worker=%d\n",
Packit 1034e0
			      __func__, getpid());
Packit 1034e0
			ret = ni_send(p);
Packit 1034e0
			DEBUG(LOG_DEBUG, "%s(): worker=%d => %d\n",
Packit 1034e0
			      __func__, getpid(), ret);
Packit 1034e0
			exit(ret > 0 ? 1 : 0);
Packit 1034e0
		}
Packit 1034e0
		ni_free(p->replydata);
Packit 1034e0
		ni_free(p);
Packit 1034e0
		exit(0);
Packit 1034e0
	} else {
Packit 1034e0
		waitpid(child, NULL, 0);
Packit 1034e0
		ni_free(p->replydata);
Packit 1034e0
		ni_free(p);
Packit 1034e0
	}
Packit 1034e0
	return 0;
Packit 1034e0
}
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
static int ni_ratelimit(void)
Packit 1034e0
{
Packit 1034e0
	static struct timeval last;
Packit 1034e0
	struct timeval tv, sub;
Packit 1034e0
Packit 1034e0
	if (gettimeofday(&tv, NULL) < 0) {
Packit 1034e0
		DEBUG(LOG_WARNING, "%s(): gettimeofday(): %s\n",
Packit 1034e0
		      __func__, strerror(errno));
Packit 1034e0
		return -1;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	if (!timerisset(&last)) {
Packit 1034e0
		last = tv;
Packit 1034e0
		return 0;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	timersub(&tv, &last, &sub);
Packit 1034e0
Packit 1034e0
	if (sub.tv_sec < 1)
Packit 1034e0
		return 1;
Packit 1034e0
Packit 1034e0
	last = tv;
Packit 1034e0
	return 0;
Packit 1034e0
}
Packit 1034e0
Packit 1034e0
int pr_nodeinfo(struct packetcontext *p)
Packit 1034e0
{
Packit 1034e0
	struct icmp6_nodeinfo *query = (struct icmp6_nodeinfo *)p->query;
Packit 1034e0
Packit 1034e0
	char *subject = (char *)(query + 1);
Packit 1034e0
	size_t subjlen;
Packit 1034e0
	struct subjinfo *subjinfo;
Packit 1034e0
	struct qtypeinfo *qtypeinfo;
Packit 1034e0
	int replyonsubjcheck = 0;
Packit 1034e0
	unsigned int subj_if;
Packit 1034e0
#if ENABLE_DEBUG
Packit 1034e0
	char printbuf[128];
Packit 1034e0
	int i;
Packit 1034e0
	char *cp;
Packit 1034e0
#endif
Packit 1034e0
#if ENABLE_THREADS && HAVE_PTHREAD_H
Packit 1034e0
	pthread_t thread;
Packit 1034e0
#endif
Packit 1034e0
	int rc;
Packit 1034e0
Packit 1034e0
	/* Step 0: Check destination address
Packit 1034e0
	 *		discard non-linklocal multicast
Packit 1034e0
	 *		discard non-nigroup multicast address(?)
Packit 1034e0
	 */
Packit 1034e0
	if (IN6_IS_ADDR_MULTICAST(&p->pktinfo.ipi6_addr)) {
Packit 1034e0
		if (!IN6_IS_ADDR_MC_LINKLOCAL(&p->pktinfo.ipi6_addr)) {
Packit 1034e0
			DEBUG(LOG_WARNING,
Packit 1034e0
			      "Destination is non-link-local multicast address.\n");
Packit 1034e0
			ni_free(p);
Packit 1034e0
			return -1;
Packit 1034e0
		}
Packit 1034e0
#if 0
Packit 1034e0
		/* Do not discard NI Queries to multicast address
Packit 1034e0
		 * other than its own NI Group Address(es) by default.
Packit 1034e0
		 */
Packit 1034e0
		if (!check_nigroup(&p->pktinfo.ipi6_addr)) {
Packit 1034e0
			DEBUG(LOG_WARNING,
Packit 1034e0
			      "Destination is link-local multicast address other than "
Packit 1034e0
			      "NI Group address.\n");
Packit 1034e0
			ni_free(p);
Packit 1034e0
			return -1;
Packit 1034e0
		}
Packit 1034e0
#endif
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	/* Step 1: Check length */
Packit 1034e0
	if (p->querylen < sizeof(struct icmp6_nodeinfo)) {
Packit 1034e0
		DEBUG(LOG_WARNING, "Query too short\n");
Packit 1034e0
		ni_free(p);
Packit 1034e0
		return -1;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
#if ENABLE_DEBUG
Packit 1034e0
	cp = printbuf;
Packit 1034e0
	for (i = 0; i < sizeof(query->icmp6_ni_nonce); i++) {
Packit 1034e0
		cp += sprintf(cp, " %02x", query->icmp6_ni_nonce[i]);
Packit 1034e0
	}
Packit 1034e0
	DEBUG(LOG_DEBUG, "%s(): qtype=%d, flags=0x%04x, nonce[] = {%s }\n",
Packit 1034e0
	      __func__,
Packit 1034e0
	      ntohs(query->ni_qtype), ntohs(query->ni_flags), printbuf);
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
	subjlen = p->querylen - sizeof(struct icmp6_nodeinfo);
Packit 1034e0
Packit 1034e0
	/* Step 2: Check Subject Code */
Packit 1034e0
	switch(htons(query->ni_qtype)) {
Packit 1034e0
	case NI_QTYPE_NOOP:
Packit 1034e0
	case NI_QTYPE_SUPTYPES:
Packit 1034e0
		if (query->ni_code != ICMP6_NI_SUBJ_FQDN) {
Packit 1034e0
			DEBUG(LOG_WARNING,
Packit 1034e0
			      "%s(): invalid/unknown code %u\n",
Packit 1034e0
			      __func__, query->ni_code);
Packit 1034e0
			subjlen = 0;
Packit 1034e0
		}
Packit 1034e0
		subjinfo = &subjinfo_null;
Packit 1034e0
		break;
Packit 1034e0
	default:
Packit 1034e0
		subjinfo = subjinfo_lookup(query->ni_code);
Packit 1034e0
		if (!subjinfo) {
Packit 1034e0
			DEBUG(LOG_WARNING,
Packit 1034e0
			      "%s(): unknown code %u\n",
Packit 1034e0
			      __func__, query->ni_code);
Packit 1034e0
			ni_free(p);
Packit 1034e0
			return -1;
Packit 1034e0
		}
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	/* Step 3: Lookup Qtype */
Packit 1034e0
	qtypeinfo = qtypeinfo_lookup(ntohs(query->ni_qtype));
Packit 1034e0
Packit 1034e0
	/* Step 4: Check Subject
Packit 1034e0
	 *         (And fill reply if it is available now)
Packit 1034e0
	 */
Packit 1034e0
	if (qtypeinfo->getreply == subjinfo->checksubj)
Packit 1034e0
		replyonsubjcheck = 1;
Packit 1034e0
Packit 1034e0
	if (subjinfo->checksubj(p,
Packit 1034e0
				subject, subjlen,
Packit 1034e0
				query->ni_flags,
Packit 1034e0
				replyonsubjcheck ? NULL : &subj_if,
Packit 1034e0
				replyonsubjcheck)) {
Packit 1034e0
		if (p->replydatalen < 0) {
Packit 1034e0
			DEBUG(LOG_WARNING,
Packit 1034e0
			      "failed to make reply: %s\n",
Packit 1034e0
			      strerror(errno));
Packit 1034e0
		}
Packit 1034e0
		ni_free(p);
Packit 1034e0
		return -1;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	/* XXX: Step 5: Check the policy */
Packit 1034e0
	rc = ni_policy(p);
Packit 1034e0
	if (rc <= 0) {
Packit 1034e0
		ni_free(p->replydata);
Packit 1034e0
		p->replydata = NULL;
Packit 1034e0
		p->replydatalen = 0;
Packit 1034e0
		if (rc < 0) {
Packit 1034e0
			DEBUG(LOG_WARNING, "Ignored by policy.\n");
Packit 1034e0
			ni_free(p);
Packit 1034e0
			return -1;
Packit 1034e0
		}
Packit 1034e0
		DEBUG(LOG_WARNING, "Refused by policy.\n");
Packit 1034e0
		replyonsubjcheck = 0;
Packit 1034e0
		qtypeinfo = &qtypeinfo_refused;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	/* Step 6: Fill the reply if not yet done */
Packit 1034e0
	if (!replyonsubjcheck) {
Packit 1034e0
		if (qtypeinfo->getreply(p,
Packit 1034e0
					NULL, 0,
Packit 1034e0
					query->ni_flags,
Packit 1034e0
					&subj_if,
Packit 1034e0
					1)) {
Packit 1034e0
			if (p->replydatalen) {
Packit 1034e0
				DEBUG(LOG_WARNING,
Packit 1034e0
				      "failed to make reply: %s\n",
Packit 1034e0
				      strerror(errno));
Packit 1034e0
			}
Packit 1034e0
			ni_free(p);
Packit 1034e0
			return -1;
Packit 1034e0
		}
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	/* Step 7: Rate Limit */
Packit 1034e0
	if (qtypeinfo->flags&QTYPEINFO_F_RATELIMIT &&
Packit 1034e0
	    ni_ratelimit()) {
Packit 1034e0
		ni_free(p->replydata);
Packit 1034e0
		ni_free(p);
Packit 1034e0
		return -1;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	/* Step 8: Fill Qtype / Nonce */
Packit 1034e0
	p->reply.ni_qtype = query->ni_qtype;
Packit 1034e0
	memcpy(p->reply.icmp6_ni_nonce, query->icmp6_ni_nonce, sizeof(p->reply.icmp6_ni_nonce));
Packit 1034e0
Packit 1034e0
	/* Step 9: Source address selection */
Packit 1034e0
	if (IN6_IS_ADDR_MULTICAST(&p->pktinfo.ipi6_addr)) {
Packit 1034e0
		/* if query was sent to multicast address,
Packit 1034e0
		 * use source address selection in kernel.
Packit 1034e0
		 * XXX: anycast?
Packit 1034e0
		 */
Packit 1034e0
		memset(&p->pktinfo.ipi6_addr, 0, sizeof(p->pktinfo.ipi6_addr));
Packit 1034e0
Packit 1034e0
	 	/* Random Delay between zero and MAX_ANYCAST_DELAY_TIME is
Packit 1034e0
		 * required if query was sent to anycast or multicast address.
Packit 1034e0
		 */
Packit 1034e0
		p->delay = (int) (MAX_ANYCAST_DELAY_TIME*rand()/(RAND_MAX+1.0));
Packit 1034e0
	} else {
Packit 1034e0
		p->delay = 0;
Packit 1034e0
	}
Packit 1034e0
Packit 1034e0
	/* Step 10: Send the reply
Packit 1034e0
	 * XXX: with possible random delay */
Packit 1034e0
#if ENABLE_THREADS && HAVE_LIBPTHREAD
Packit 1034e0
	/* ni_send_thread() frees p */
Packit 1034e0
	if (pthread_create(&thread, &pattr, ni_send_thread, p)) {
Packit 1034e0
		ni_free(p->replydata);
Packit 1034e0
		ni_free(p);
Packit 1034e0
		return -1;
Packit 1034e0
	}
Packit 1034e0
#else
Packit 1034e0
	/* ni_send_fork() frees p */
Packit 1034e0
	if (ni_send_fork(p)) {
Packit 1034e0
		ni_free(p->replydata);
Packit 1034e0
		ni_free(p);
Packit 1034e0
		return -1;
Packit 1034e0
	}
Packit 1034e0
#endif
Packit 1034e0
Packit 1034e0
	return 0;
Packit 1034e0
}
Packit 1034e0