summaryrefslogtreecommitdiff
path: root/ninfod
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2012-10-09 16:13:58 +0900
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2012-10-11 14:23:15 +0900
commitc0685f7a05d11b25fd63e2296f07d2143bba5224 (patch)
tree07d771b3c8fb36df0cd13165a6e323f70b4878a5 /ninfod
parenta11165d8082213bf96e986e1aaecf841e084c8df (diff)
downloadiputils-c0685f7a05d11b25fd63e2296f07d2143bba5224.tar.gz
ninfod: Node Information Query (RFC4620) daemon from USAGI Project.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'ninfod')
-rw-r--r--ninfod/COPYING26
-rw-r--r--ninfod/Makefile.in78
-rw-r--r--ninfod/config.h.in107
-rw-r--r--ninfod/configure.in133
-rw-r--r--ninfod/icmp6_nodeinfo.h97
-rwxr-xr-xninfod/install-sh251
-rw-r--r--ninfod/ni_ifaddrs.c541
-rw-r--r--ninfod/ni_ifaddrs.h45
-rw-r--r--ninfod/ninfod.c522
-rw-r--r--ninfod/ninfod.h135
-rw-r--r--ninfod/ninfod.sh.in37
-rw-r--r--ninfod/ninfod_addrs.c469
-rw-r--r--ninfod/ninfod_core.c641
-rw-r--r--ninfod/ninfod_name.c381
14 files changed, 3463 insertions, 0 deletions
diff --git a/ninfod/COPYING b/ninfod/COPYING
new file mode 100644
index 0000000..30df58e
--- /dev/null
+++ b/ninfod/COPYING
@@ -0,0 +1,26 @@
+Copyright (C) 2002 USAGI/WIDE Project.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the project nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/ninfod/Makefile.in b/ninfod/Makefile.in
new file mode 100644
index 0000000..3cbdddf
--- /dev/null
+++ b/ninfod/Makefile.in
@@ -0,0 +1,78 @@
+# $USAGI: Makefile.in,v 1.6 2003-01-15 06:41:23 mk Exp $
+#
+# Copyright (C)2002 USAGI/WIDE Project.
+# Copyright (C)2000-2001 Hideaki YOSHIFUJI and USAGI Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the project nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+# $Id: Makefile.in,v 1.2 2000/06/10 05:45:14 yoshfuji Exp yoshfuji $
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+
+INSTALL = @INSTALL@
+
+CC = @CC@
+CFLAGS=@CFLAGS@
+DEFS=@DEFS@
+LIBS=@LIBS@
+LDFLAGS=@LDFLAGS@
+INSTALL = @INSTALL@
+
+# ----------------
+all: ninfod
+clean:
+ -rm -f *.o ninfod ninfod.sh
+distclean: clean
+ -rm -f *~ *.bak #*
+ -rm -fr autom4te.cache
+ -rm -f Makefile config.h config.cache config.status config.log
+install: all
+ @INSTALL_DIR@ @sbindir@
+ @INSTALL@ ninfod -o root @sbindir@
+ @INSTALL@ ninfod.sh -o root -m 755 @sysconfdir@/init.d/ninfod
+
+# ----------------
+ninfod: ninfod_addrs.o ni_ifaddrs.o ninfod_name.o ninfod_core.o ninfod.o
+ $(CC) $(LDFLAGS) $^ $(LIBS) -o $@
+.c.o:
+ $(CC) $(CFLAGS) -c $(DEFS) -o $@ $^
diff --git a/ninfod/config.h.in b/ninfod/config.h.in
new file mode 100644
index 0000000..9bb24bc
--- /dev/null
+++ b/ninfod/config.h.in
@@ -0,0 +1,107 @@
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Enable debugging */
+#undef ENABLE_DEBUG
+
+/* Enable threads */
+#undef ENABLE_THREADS
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the <linux/rtnetlink.h> header file. */
+#undef HAVE_LINUX_RTNETLINK_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `nanosleep' function. */
+#undef HAVE_NANOSLEEP
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/icmp6.h> header file. */
+#undef HAVE_NETINET_ICMP6_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/ip6.h> header file. */
+#undef HAVE_NETINET_IP6_H
+
+/* Define to 1 if you have the <openssl/md5.h> header file. */
+#undef HAVE_OPENSSL_MD5_H
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have struct icmp6_nodeinfo */
+#undef HAVE_STRUCT_ICMP6_NODEINFO
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#undef HAVE_SYSLOG_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define to 1 if you have the <sys/utsname.h> header file. */
+#undef HAVE_SYS_UTSNAME_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
diff --git a/ninfod/configure.in b/ninfod/configure.in
new file mode 100644
index 0000000..ab49dfe
--- /dev/null
+++ b/ninfod/configure.in
@@ -0,0 +1,133 @@
+dnl $USAGI: configure.in,v 1.12 2003-07-16 09:49:01 yoshfuji Exp $
+
+dnl Copyright (C) 2002 USAGI/WIDE Project.
+dnl All rights reserved.
+dnl
+dnl Redistribution and use in source and binary forms, with or without
+dnl modification, are permitted provided that the following conditions
+dnl are met:
+dnl 1. Redistributions of source code must retain the above copyright
+dnl notice, this list of conditions and the following disclaimer.
+dnl 2. Redistributions in binary form must reproduce the above copyright
+dnl notice, this list of conditions and the following disclaimer in the
+dnl documentation and/or other materials provided with the distribution.
+dnl 3. Neither the name of the project nor the names of its contributors
+dnl may be used to endorse or promote products derived from this software
+dnl without specific prior written permission.
+dnl
+dnl THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+dnl ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+dnl IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+dnl ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+dnl FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+dnl DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+dnl OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+dnl HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+dnl LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+dnl OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+dnl SUCH DAMAGE.
+
+AC_PREREQ(2.53)
+AC_INIT(ninfod.c)
+AC_CONFIG_HEADER(config.h)
+AC_PREFIX_DEFAULT(/usr/local/v6)
+
+AC_COPYRIGHT([Copyright (C)2002 USAGI/WIDE Project. All Rights Reserved.])
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+INSTALL_LIB="\${INSTALL_DATA}"
+AC_SUBST(INSTALL_LIB)
+INSTALL_DIR="\${INSTALL} -d"
+AC_SUBST(INSTALL_DIR)
+
+dnl Checks for Enable/With
+AC_ARG_ENABLE(debug,
+[ --enable-debug Enable debugging])
+if test x"$enableval" != x"no"; then
+ AC_DEFINE(ENABLE_DEBUG, 1,
+ [Enable debugging])
+fi
+
+AC_ARG_ENABLE(threads,
+[ --disable-threads Disable threads (and random delay)],,enable_threads=no)
+if test x"$enableval" != x"no"; then
+ AC_DEFINE(ENABLE_THREADS, 1,
+ [Enable threads])
+fi
+
+AC_ARG_ENABLE(suptypes,
+[ --enable-suptypes Enable suptypes qtype (deprecated)])
+if test x"$enableval" != x"no"; then
+ AC_DEFINE(ENABLE_SUPTYPES, 1,
+ [Enable suptypes (deprecated)])
+fi
+
+AC_ARG_ENABLE(suptypes,
+[ --enable-ttl Enable ttl support for qtypes (deprecated)])
+if test x"$enableval" != x"no"; then
+ AC_DEFINE(ENABLE_SUPTYPES, 1,
+ [Enable ttl support for qtypes (deprecated)])
+fi
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_CHECK_HEADERS(openssl/md5.h)
+AC_CHECK_HEADERS(sys/uio.h)
+AC_CHECK_HEADERS(sys/utsname.h arpa/inet.h netdb.h syslog.h)
+AC_CHECK_HEADERS(netinet/in.h)
+AC_CHECK_HEADERS(netinet/ip6.h netinet/icmp6.h,,,[
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+])
+AC_CHECK_HEADERS(linux/rtnetlink.h,,,[
+#include <asm/types.h>
+#include <sys/socket.h>
+])
+AC_CHECK_HEADERS(pthread.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_BIGENDIAN
+AC_C_CONST
+AC_TYPE_SIZE_T
+
+AC_MSG_CHECKING([for struct icmp6_nodeinfo])
+AC_TRY_COMPILE([
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+],[
+struct icmp6_nodeinfo nodeinfo;
+],[
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_STRUCT_ICMP6_NODEINFO], 1,
+ [Define to 1 if you have struct icmp6_nodeinfo])
+],[
+ AC_MSG_RESULT([no])
+])
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(nanosleep)
+AC_CHECK_LIB(pthread, pthread_create)
+
+dnl AC_CHECK_LIB(crypto, MD5_Init,
+dnl AC_DEFINE(HAVE_MD5_INIT)
+dnl LIBS="-lcrypto $LIBS",
+dnl )
+dnl AC_CHECK_LIB(crypto, MD5Init,
+dnl AC_DEFINE(HAVE_MD5INIT)
+dnl LIBS="-lcrypto $LIBS",
+dnl)
+LIBS="-lcrypto $LIBS"
+
+dnl AC_SUBST(DEFS)
+
+AC_OUTPUT(Makefile ninfod.sh)
diff --git a/ninfod/icmp6_nodeinfo.h b/ninfod/icmp6_nodeinfo.h
new file mode 100644
index 0000000..5c6e741
--- /dev/null
+++ b/ninfod/icmp6_nodeinfo.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef ICMP6_NODEINFO_H
+#define ICMP6_NODEINFO_H
+
+struct icmp6_nodeinfo {
+ struct icmp6_hdr icmp6_ni_hdr;
+ uint8_t icmp6_ni_nonce[8];
+ /* could be followed by reply data */
+};
+
+#define ni_type icmp6_ni_hdr.icmp6_type
+#define ni_code icmp6_ni_hdr.icmp6_code
+#define ni_cksum icmp6_ni_hdr.icmp6_cksum
+#define ni_qtype icmp6_ni_hdr.icmp6_data16[0]
+#define ni_flags icmp6_ni_hdr.icmp6_data16[1]
+#define ni_nonce icmp6_ni_nonce
+
+/* ICMP6 types */
+#define ICMP6_NI_QUERY 139
+#define ICMP6_NI_REPLY 140
+
+/* ICMP6 codes for NI Query */
+#define ICMP6_NI_SUBJ_IPV6 0 /* Query Subject is an ipv6 address */
+#define ICMP6_NI_SUBJ_FQDN 1 /* Query Subject is a Domain name */
+#define ICMP6_NI_SUBJ_IPV4 2 /* Query Subject is an ipv4 address */
+
+/* ICMP6 codes for NI Reply */
+#define ICMP6_NI_SUCCESS 0 /* NI successful reply */
+#define ICMP6_NI_REFUSED 1 /* NI request is refused */
+#define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */
+
+/* NI Codes */
+#define NI_QTYPE_NOOP 0 /* NOOP */
+#define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */
+#define NI_QTYPE_DNSNAME 2 /* DNS Name */
+#define NI_QTYPE_NODEADDR 3 /* Node Addresses */
+#define NI_QTYPE_IPV4ADDR 4 /* IPv4 Addresses */
+
+/* NI Flags */
+#if WORDS_BIGENDIAN
+#define NI_SUPTYPE_FLAG_COMPRESS 0x1
+#define NI_FQDN_FLAG_VALIDTTL 0x1
+#else
+#define NI_SUPTYPE_FLAG_COMPRESS 0x0100
+#define NI_FQDN_FLAG_VALIDTTL 0x0100
+#endif
+
+#if WORDS_BIGENDIAN
+#define NI_NODEADDR_FLAG_TRUNCATE 0x1
+#define NI_NODEADDR_FLAG_ALL 0x2
+#define NI_NODEADDR_FLAG_COMPAT 0x4
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x8
+#define NI_NODEADDR_FLAG_SITELOCAL 0x10
+#define NI_NODEADDR_FLAG_GLOBAL 0x20
+#else
+#define NI_NODEADDR_FLAG_TRUNCATE 0x0100
+#define NI_NODEADDR_FLAG_ALL 0x0200
+#define NI_NODEADDR_FLAG_COMPAT 0x0400
+#define NI_NODEADDR_FLAG_LINKLOCAL 0x0800
+#define NI_NODEADDR_FLAG_SITELOCAL 0x1000
+#define NI_NODEADDR_FLAG_GLOBAL 0x2000
+#endif
+
+#define NI_IPV4ADDR_FLAG_TRUNCATE NI_NODEADDR_FLAG_TRUNCATE
+#define NI_IPV4ADDR_FLAG_ALL NI_NODEADDR_FLAG_ALL
+
+#endif
+
diff --git a/ninfod/install-sh b/ninfod/install-sh
new file mode 100755
index 0000000..e9de238
--- /dev/null
+++ b/ninfod/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/ninfod/ni_ifaddrs.c b/ninfod/ni_ifaddrs.c
new file mode 100644
index 0000000..4225a5a
--- /dev/null
+++ b/ninfod/ni_ifaddrs.c
@@ -0,0 +1,541 @@
+/* $USAGI: ni_ifaddrs.c,v 1.8 2007-10-11 06:25:21 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* reformatted by indent -kr -i8 -l 1000 */
+/* USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp */
+
+/**************************************************************************
+ * ifaddrs.c
+ * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <time.h>
+#include <malloc.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h> /* the L2 protocols */
+#include <sys/uio.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include "ni_ifaddrs.h"
+#include <netinet/in.h>
+
+#ifdef _USAGI_LIBINET6
+#include "libc-compat.h"
+#endif
+
+//#define IFA_LOCAL IFA_LOCAL
+
+static const char *RCSID __attribute__ ((unused)) = "$USAGI: ni_ifaddrs.c,v 1.8 2007-10-11 06:25:21 yoshfuji Exp $ based on USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp";
+
+/* ====================================================================== */
+struct nlmsg_list {
+ struct nlmsg_list *nlm_next;
+ struct nlmsghdr *nlh;
+ int size;
+ time_t seq;
+};
+
+#ifndef IFA_LOCAL
+struct rtmaddr_ifamap {
+ void *address;
+ void *local;
+ void *broadcast;
+ int address_len;
+ int local_len;
+ int broadcast_len;
+};
+#endif
+
+/* ====================================================================== */
+static int nl_sendreq(int sd, int request, int flags, int *seq)
+{
+ char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
+ struct sockaddr_nl nladdr;
+ struct nlmsghdr *req_hdr;
+ struct rtgenmsg *req_msg;
+ time_t t = time(NULL);
+
+ if (seq)
+ *seq = t;
+ memset(&reqbuf, 0, sizeof(reqbuf));
+ req_hdr = (struct nlmsghdr *) reqbuf;
+ req_msg = (struct rtgenmsg *) NLMSG_DATA(req_hdr);
+ req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg));
+ req_hdr->nlmsg_type = request;
+ req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
+ req_hdr->nlmsg_pid = 0;
+ req_hdr->nlmsg_seq = t;
+ req_msg->rtgen_family = AF_UNSPEC;
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ return (sendto(sd, (void *) req_hdr, req_hdr->nlmsg_len, 0, (struct sockaddr *) &nladdr, sizeof(nladdr)));
+}
+
+static int nl_recvmsg(int sd, int request, int seq, void *buf, size_t buflen, int *flags)
+{
+ struct msghdr msg;
+ struct iovec iov = { buf, buflen };
+ struct sockaddr_nl nladdr;
+ int read_len;
+
+ for (;;) {
+ msg.msg_name = (void *) &nladdr;
+ msg.msg_namelen = sizeof(nladdr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+ read_len = recvmsg(sd, &msg, 0);
+ if ((read_len < 0 && errno == EINTR)
+ || (msg.msg_flags & MSG_TRUNC))
+ continue;
+ if (flags)
+ *flags = msg.msg_flags;
+ break;
+ }
+ return read_len;
+}
+
+static int nl_getmsg(int sd, int request, int seq, struct nlmsghdr **nlhp, int *done)
+{
+ struct nlmsghdr *nh;
+ size_t bufsize = 65536, lastbufsize = 0;
+ void *buff = NULL;
+ int result = 0, read_size;
+ int msg_flags;
+ pid_t pid = getpid();
+ for (;;) {
+ void *newbuff = realloc(buff, bufsize);
+ if (newbuff == NULL || bufsize < lastbufsize) {
+ result = -1;
+ break;
+ }
+ buff = newbuff;
+ result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags);
+ if (read_size < 0 || (msg_flags & MSG_TRUNC)) {
+ lastbufsize = bufsize;
+ bufsize *= 2;
+ continue;
+ }
+ if (read_size == 0)
+ break;
+ nh = (struct nlmsghdr *) buff;
+ for (nh = (struct nlmsghdr *) buff; NLMSG_OK(nh, read_size); nh = (struct nlmsghdr *) NLMSG_NEXT(nh, read_size)) {
+ if (nh->nlmsg_pid != pid || nh->nlmsg_seq != seq)
+ continue;
+ if (nh->nlmsg_type == NLMSG_DONE) {
+ (*done)++;
+ break; /* ok */
+ }
+ if (nh->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA(nh);
+ result = -1;
+ if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+ errno = EIO;
+ else
+ errno = -nlerr->error;
+ break;
+ }
+ }
+ break;
+ }
+ if (result < 0)
+ if (buff) {
+ int saved_errno = errno;
+ free(buff);
+ errno = saved_errno;
+ }
+ *nlhp = (struct nlmsghdr *) buff;
+ return result;
+}
+
+static int nl_getlist(int sd, int seq, int request, struct nlmsg_list **nlm_list, struct nlmsg_list **nlm_end)
+{
+ struct nlmsghdr *nlh = NULL;
+ int status;
+ int done = 0;
+
+ status = nl_sendreq(sd, request, NLM_F_ROOT | NLM_F_MATCH, &seq);
+ if (status < 0)
+ return status;
+ if (seq == 0)
+ seq = (int) time(NULL);
+ while (!done) {
+ status = nl_getmsg(sd, request, seq, &nlh, &done);
+ if (status < 0)
+ return status;
+ if (nlh) {
+ struct nlmsg_list *nlm_next = (struct nlmsg_list *) malloc(sizeof(struct nlmsg_list));
+ if (nlm_next == NULL) {
+ int saved_errno = errno;
+ free(nlh);
+ errno = saved_errno;
+ status = -1;
+ } else {
+ nlm_next->nlm_next = NULL;
+ nlm_next->nlh = (struct nlmsghdr *) nlh;
+ nlm_next->size = status;
+ nlm_next->seq = seq;
+ if (*nlm_list == NULL) {
+ *nlm_list = nlm_next;
+ *nlm_end = nlm_next;
+ } else {
+ (*nlm_end)->nlm_next = nlm_next;
+ *nlm_end = nlm_next;
+ }
+ }
+ }
+ }
+ return status >= 0 ? seq : status;
+}
+
+/* ---------------------------------------------------------------------- */
+static void free_nlmsglist(struct nlmsg_list *nlm0)
+{
+ struct nlmsg_list *nlm, *nlm_next;
+ int saved_errno;
+ if (!nlm0)
+ return;
+ saved_errno = errno;
+ nlm = nlm0;
+ while(nlm) {
+ if(nlm->nlh)
+ free(nlm->nlh);
+ nlm_next = nlm->nlm_next;
+ free(nlm);
+ nlm = nlm_next;
+ }
+ errno = saved_errno;
+}
+
+static void free_data(void *data)
+{
+ int saved_errno = errno;
+ if (data != NULL)
+ free(data);
+ errno = saved_errno;
+}
+
+/* ---------------------------------------------------------------------- */
+static void nl_close(int sd)
+{
+ int saved_errno = errno;
+ if (sd >= 0)
+ close(sd);
+ errno = saved_errno;
+}
+
+/* ---------------------------------------------------------------------- */
+static int nl_open(void)
+{
+ struct sockaddr_nl nladdr;
+ int sd;
+
+ sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sd < 0)
+ return -1;
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ if (bind(sd, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) {
+ nl_close(sd);
+ return -1;
+ }
+ return sd;
+}
+
+/* ====================================================================== */
+int ni_ifaddrs(struct ni_ifaddrs **ifap, sa_family_t family)
+{
+ int sd;
+ struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
+ /* - - - - - - - - - - - - - - - */
+ int icnt;
+ size_t dlen, xlen;
+ uint32_t max_ifindex = 0;
+
+ pid_t pid = getpid();
+ int seq = 0;
+ int result;
+ int build; /* 0 or 1 */
+
+/* ---------------------------------- */
+ /* initialize */
+ icnt = dlen = xlen = 0;
+ nlmsg_list = nlmsg_end = NULL;
+
+ if (ifap)
+ *ifap = NULL;
+
+/* ---------------------------------- */
+ /* open socket and bind */
+ sd = nl_open();
+ if (sd < 0)
+ return -1;
+
+/* ---------------------------------- */
+ /* gather info */
+ if ((seq = nl_getlist(sd, seq + 1, RTM_GETADDR, &nlmsg_list, &nlmsg_end)) < 0) {
+ free_nlmsglist(nlmsg_list);
+ nl_close(sd);
+ return -1;
+ }
+
+/* ---------------------------------- */
+ /* Estimate size of result buffer and fill it */
+ for (build = 0; build <= 1; build++) {
+ struct ni_ifaddrs *ifl = NULL, *ifa = NULL;
+ struct nlmsghdr *nlh, *nlh0;
+ void *data = NULL, *xdata = NULL;
+ uint16_t *ifflist = NULL;
+#ifndef IFA_LOCAL
+ struct rtmaddr_ifamap ifamap;
+#endif
+
+ if (build) {
+ ifa = data = calloc(1, NLMSG_ALIGN(sizeof(struct ni_ifaddrs[icnt]))
+ + dlen + xlen);
+ if (ifap != NULL)
+ *ifap = ifa;
+ else {
+ free_data(data);
+ result = 0;
+ break;
+ }
+ if (data == NULL) {
+ free_data(data);
+ result = -1;
+ break;
+ }
+ ifl = NULL;
+ data += NLMSG_ALIGN(sizeof(struct ni_ifaddrs)) * icnt;
+ xdata = data + dlen;
+ ifflist = xdata + xlen;
+ }
+
+ for (nlm = nlmsg_list; nlm; nlm = nlm->nlm_next) {
+ int nlmlen = nlm->size;
+ if (!(nlh0 = nlm->nlh))
+ continue;
+ for (nlh = nlh0; NLMSG_OK(nlh, nlmlen); nlh = NLMSG_NEXT(nlh, nlmlen)) {
+ struct ifaddrmsg *ifam = NULL;
+ struct rtattr *rta;
+
+ size_t nlm_struct_size = 0;
+ sa_family_t nlm_family = 0;
+ uint32_t nlm_scope = 0, nlm_index = 0;
+ unsigned int nlm_flags;
+ size_t rtasize;
+
+#ifndef IFA_LOCAL
+ memset(&ifamap, 0, sizeof(ifamap));
+#endif
+
+ /* check if the message is what we want */
+ if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq)
+ continue;
+ if (nlh->nlmsg_type == NLMSG_DONE) {
+ break; /* ok */
+ }
+ switch (nlh->nlmsg_type) {
+ case RTM_NEWADDR:
+ ifam = (struct ifaddrmsg *) NLMSG_DATA(nlh);
+ nlm_struct_size = sizeof(*ifam);
+ nlm_family = ifam->ifa_family;
+ nlm_scope = ifam->ifa_scope;
+ nlm_index = ifam->ifa_index;
+ nlm_flags = ifam->ifa_flags;
+ if (family && nlm_family != family)
+ continue;
+ if (build) {
+ ifa->ifa_ifindex = nlm_index;
+ ifa->ifa_flags = nlm_flags;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ if (!build) {
+ if (max_ifindex < nlm_index)
+ max_ifindex = nlm_index;
+ } else {
+ if (ifl != NULL)
+ ifl->ifa_next = ifa;
+ }
+
+ rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
+ for (rta = (struct rtattr *) (((char *) NLMSG_DATA(nlh)) +
+ NLMSG_ALIGN(nlm_struct_size));
+ RTA_OK(rta, rtasize);
+ rta = RTA_NEXT(rta, rtasize)) {
+ void *rtadata = RTA_DATA(rta);
+ size_t rtapayload = RTA_PAYLOAD(rta);
+
+ switch (nlh->nlmsg_type) {
+ case RTM_NEWADDR:
+ if (nlm_family == AF_PACKET)
+ break;
+ switch (rta->rta_type) {
+#ifndef IFA_LOCAL
+ case IFA_ADDRESS:
+ ifamap.address = rtadata;
+ ifamap.address_len = rtapayload;
+ break;
+ case IFA_LOCAL:
+ ifamap.local = rtadata;
+ ifamap.local_len = rtapayload;
+ break;
+ case IFA_BROADCAST:
+ ifamap.broadcast = rtadata;
+ ifamap.broadcast_len = rtapayload;
+ break;
+ case IFA_LABEL:
+ break;
+ case IFA_UNSPEC:
+ break;
+#else
+ case IFA_LOCAL:
+ if (!build)
+ dlen += NLMSG_ALIGN(rtapayload);
+ else {
+ memcpy(data, rtadata, rtapayload);
+ ifa->ifa_addr = data;
+ data += NLMSG_ALIGN(rtapayload);
+ }
+ break;
+#endif
+ case IFA_CACHEINFO:
+ if (!build)
+ xlen += NLMSG_ALIGN(rtapayload);
+ else {
+ memcpy(xdata, rtadata, rtapayload);
+ ifa->ifa_cacheinfo = xdata;
+ xdata += NLMSG_ALIGN(rtapayload);
+ }
+ break;
+ }
+ }
+ }
+#ifndef IFA_LOCAL
+ if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET) {
+ if (!ifamap.local) {
+ ifamap.local = ifamap.address;
+ ifamap.local_len = ifamap.address_len;
+ }
+ if (!ifamap.address) {
+ ifamap.address = ifamap.local;
+ ifamap.address_len = ifamap.local_len;
+ }
+ if (ifamap.address_len != ifamap.local_len ||
+ (ifamap.address != NULL &&
+ memcmp(ifamap.address, ifamap.local, ifamap.address_len))) {
+ /* p2p; address is peer and local is ours */
+ ifamap.broadcast = ifamap.address;
+ ifamap.broadcast_len = ifamap.address_len;
+ ifamap.address = ifamap.local;
+ ifamap.address_len = ifamap.local_len;
+ }
+ if (ifamap.address) {
+ if (!build)
+ dlen += NLMSG_ALIGN(ifamap.address_len);
+ else {
+ ifa->ifa_addr = (struct sockaddr *) data;
+ memcpy(ifa->ifa_addr, ifamap.address, ifamap.address_len);
+ data += NLMSG_ALIGN(ifamap.address_len);
+ }
+ }
+ }
+#endif
+ if (!build) {
+ icnt++;
+ } else {
+ ifl = ifa++;
+ }
+ }
+ }
+ if (!build) {
+ if (icnt == 0 && (dlen + xlen == 0)) {
+ if (ifap != NULL)
+ *ifap = NULL;
+ break; /* cannot found any addresses */
+ }
+ }
+ }
+
+/* ---------------------------------- */
+ /* Finalize */
+ free_nlmsglist(nlmsg_list);
+ nl_close(sd);
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+void ni_freeifaddrs(struct ni_ifaddrs *ifa)
+{
+ free(ifa);
+}
+
diff --git a/ninfod/ni_ifaddrs.h b/ninfod/ni_ifaddrs.h
new file mode 100644
index 0000000..e164a8b
--- /dev/null
+++ b/ninfod/ni_ifaddrs.h
@@ -0,0 +1,45 @@
+/* $USAGI: ni_ifaddrs.h,v 1.1 2002-12-03 17:48:53 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef NODEINFO_IFADDRS_H
+#define NODEINFO_IFADDRS_H
+
+struct ni_ifaddrs {
+ struct ni_ifaddrs *ifa_next;
+ unsigned int ifa_ifindex;
+ unsigned short ifa_flags;
+ void *ifa_addr;
+ struct ifa_cacheinfo *ifa_cacheinfo;
+};
+
+int ni_ifaddrs(struct ni_ifaddrs **ifap, sa_family_t family);
+void ni_freeifaddrs(struct ni_ifaddrs *ifa);
+
+#endif
+
diff --git a/ninfod/ninfod.c b/ninfod/ninfod.c
new file mode 100644
index 0000000..d2d37da
--- /dev/null
+++ b/ninfod/ninfod.c
@@ -0,0 +1,522 @@
+/* $USAGI: ninfod.c,v 1.34 2003-01-15 06:41:23 mk Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if STDC_HEADERS
+# include <stdio.h>
+# include <stdlib.h>
+# include <stddef.h>
+# include <stdarg.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#include <sys/socket.h>
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#if HAVE_NETINET_ICMP6_H
+# include <netinet/icmp6.h>
+#endif
+#ifndef HAVE_STRUCT_ICMP6_NODEINFO
+# include "icmp6_nodeinfo.h"
+#endif
+
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#include <errno.h>
+
+#include <signal.h>
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include "ninfod.h"
+
+#ifndef offsetof
+# define offsetof(aggregate,member) ((size_t)&((aggregate *)0)->member)
+#endif
+
+/* --------- */
+/* ID */
+static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod.c,v 1.34 2003-01-15 06:41:23 mk Exp $";
+
+/* Variables */
+int sock;
+int daemonized;
+
+char *appname;
+static int opt_d = 0; /* debug */
+static int opt_h = 0; /* help */
+static char *opt_p = NINFOD_PIDFILE; /* pidfile */
+int opt_v = 0; /* verbose */
+
+/* --------- */
+#if ENABLE_DEBUG
+static const __inline__ char * log_level(int priority) {
+ switch(priority) {
+ case LOG_EMERG: return "EMERG";
+ case LOG_ALERT: return "ALERT";
+ case LOG_CRIT: return "CRIT";
+ case LOG_ERR: return "ERR";
+ case LOG_WARNING: return "WARNING";
+ case LOG_NOTICE: return "NOTICE";
+ case LOG_INFO: return "INFO";
+ case LOG_DEBUG: return "DEBUG";
+ default: return "???";
+ }
+}
+
+void stderrlog(int pri, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "[%s] ", log_level(pri));
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+#endif
+
+/* --------- */
+static int __inline__ open_sock(void)
+{
+ return socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+}
+
+static int __inline__ init_sock(int sock)
+{
+ struct icmp6_filter filter;
+ int i;
+
+#if NEED_IPV6CHECKSUM
+ i = offsetof(struct icmp6_nodeinfo, ni_cksum);
+ if (setsockopt(sock,
+ IPPROTO_IPV6, IPV6_CHECKSUM,
+ &i, sizeof(i)) < 0) {
+ DEBUG(LOG_ERR, "setsockopt(IPV6_CHECKSUM): %s\n",
+ strerror(errno));
+ return -1;
+ }
+#endif
+
+ ICMP6_FILTER_SETBLOCKALL(&filter);
+ ICMP6_FILTER_SETPASS(ICMP6_NI_QUERY, &filter);
+ if (setsockopt(sock,
+ IPPROTO_ICMPV6, ICMP6_FILTER,
+ &filter, sizeof(filter)) < 0) {
+ DEBUG(LOG_ERR, "setsockopt(ICMP6_FILTER): %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ i = 1;
+ if (setsockopt(sock,
+ IPPROTO_IPV6, IPV6_PKTINFO,
+ &i, sizeof(i)) < 0) {
+ DEBUG(LOG_ERR, "setsockopt(IPV6_PKTINFO): %s\n",
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* --------- */
+int ni_recv(struct packetcontext *p)
+{
+ int sock = p->sock;
+ struct iovec iov[1];
+ struct msghdr msgh;
+ char recvcbuf[CMSG_SPACE(sizeof(p->pktinfo))];
+ struct cmsghdr *cmsg;
+ int cc;
+
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+
+ memset(&iov, 0, sizeof(iov));
+ iov[0].iov_base = p->query;
+ iov[0].iov_len = sizeof(p->query);
+
+ memset(&msgh, 0, sizeof(msgh));
+ msgh.msg_name = (struct sockaddr *)&p->addr;
+ msgh.msg_namelen = sizeof(p->addr);
+ msgh.msg_iov = iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = recvcbuf;
+ msgh.msg_controllen = sizeof(recvcbuf);
+
+ if ((cc = recvmsg(sock, &msgh, 0)) < 0)
+ return -1;
+
+ p->querylen = cc;
+
+ memcpy(&p->addr, msgh.msg_name, msgh.msg_namelen);
+ p->addrlen = msgh.msg_namelen;
+
+ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
+ cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
+ if (cmsg->cmsg_level == IPPROTO_IPV6 &&
+ cmsg->cmsg_type == IPV6_PKTINFO) {
+ memcpy(&p->pktinfo, CMSG_DATA(cmsg), sizeof(p->pktinfo));
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int ni_send(struct packetcontext *p)
+{
+ int sock = p->sock;
+ struct iovec iov[2];
+ char cbuf[CMSG_SPACE(sizeof(p->pktinfo))];
+ struct msghdr msgh;
+ struct cmsghdr *cmsg;
+ int cc;
+
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+
+ memset(&iov, 0, sizeof(iov));
+ iov[0].iov_base = &p->reply;
+ iov[0].iov_len = sizeof(p->reply);
+ iov[1].iov_base = p->replydata;
+ iov[1].iov_len = p->replydatalen;
+
+ memset(&msgh, 0, sizeof(msgh));
+ msgh.msg_name = (struct sockaddr *)&p->addr;
+ msgh.msg_namelen = p->addrlen;
+ msgh.msg_iov = iov;
+ msgh.msg_iovlen = p->replydata ? 2 : 1;
+
+ msgh.msg_control = cbuf;
+ msgh.msg_controllen = sizeof(cbuf);
+
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(p->pktinfo));
+ memcpy(CMSG_DATA(cmsg), &p->pktinfo, sizeof(p->pktinfo));
+
+ msgh.msg_controllen = cmsg->cmsg_len;
+
+ if (p->delay) {
+#if HAVE_NANOSLEEP
+ struct timespec ts, rts;
+ int err = 0;
+
+ rts.tv_sec = 0;
+ rts.tv_nsec = (long)p->delay * 1000;
+
+ do {
+ ts = rts;
+ err = nanosleep(&ts, &rts);
+ } while(err < 0);
+#else
+ usleep(p->delay); /*XXX: signal*/
+#endif
+ }
+
+ cc = sendmsg(sock, &msgh, 0);
+ if (cc < 0)
+ DEBUG(LOG_DEBUG, "sendmsg(): %s\n", strerror(errno));
+
+ ni_free(p->replydata);
+ ni_free(p);
+
+ return cc;
+}
+
+/* --------- */
+static void sig_handler(int sig)
+{
+ int err;
+
+ DEBUG(LOG_INFO, "singnal(%d) received, quit.\n", sig);
+ err = unlink(opt_p);
+ if (err < 0) {
+ DEBUG(LOG_ERR, "failed to unlink file '%s' : %d\n",
+ opt_p, strerror(errno));
+ exit(1);
+ }
+ /* closelog() */
+
+ exit(0);
+}
+
+static void do_daemonize(void)
+{
+ FILE *fp = NULL;
+ struct sigaction act;
+ sigset_t smask;
+ pid_t pid;
+
+ if (opt_p) {
+ if (!access(opt_p, R_OK)) {
+ if ((fp = fopen(opt_p, "r"))) {
+ fscanf(fp, "%d", &pid);
+ fclose(fp);
+ DEBUG(LOG_ERR, "pid file '%s' exists : %d\n",
+ opt_p, pid);
+ exit(1);
+ }
+ }
+
+ sigemptyset(&smask);
+ sigaddset(&smask, SIGHUP);
+ sigaddset(&smask, SIGINT);
+ sigaddset(&smask, SIGQUIT);
+ sigaddset(&smask, SIGTERM);
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = sig_handler;
+ act.sa_mask = smask;
+
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGQUIT, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+
+ fp = fopen(opt_p, "w+");
+ if (!fp) {
+ DEBUG(LOG_ERR, "failed to open file '%s': %s\n",
+ opt_p, strerror(errno));
+ exit(1);
+ }
+ }
+
+ if (daemon(0, 0) < 0) {
+ DEBUG(LOG_ERR, "failed to daemon(): %s\n", strerror(errno));
+ unlink(opt_p);
+ exit(1);
+ }
+#if ENABLE_DEBUG
+ openlog(NINFOD, 0, LOG_USER);
+#endif
+ daemonized = 1;
+
+ if (fp) {
+ fprintf(fp, "%d\n", getpid());
+ fclose(fp);
+ }
+}
+
+/* --------- */
+static void parse_args(int argc, char **argv)
+{
+ int c;
+
+ /* parse options */
+ while ((c = getopt(argc, argv, "dhvp:")) != -1) {
+ switch(c) {
+ case 'd': /* debug */
+ opt_d = 1;
+ break;
+ case 'v': /* verbose */
+ opt_v = 1;
+ break;
+ case 'p':
+ opt_p = optarg;
+ break;
+ case 'h': /* help */
+ default:
+ opt_h = 1;
+ break;
+ }
+ }
+
+ argc -= optind;
+#if 0
+ argv += optind;
+#endif
+
+ if (argc)
+ opt_h = 1;
+}
+
+static void print_copying(void) {
+ fprintf(stderr,
+ "Node Information Daemon\n"
+ "Copyright (C)2002 USAGI/WIDE Project. All Rights Reserved.\n"
+ "\n"
+ );
+}
+
+static void print_usage(void) {
+ fprintf(stderr,
+ "Usage: %s [-d [-p pidfile]] [-h] [-v]\n\n",
+ appname
+ );
+}
+
+/* --------- */
+int main (int argc, char **argv)
+{
+ int sock_errno = 0;
+ int c;
+
+ appname = argv[0];
+
+ sock = open_sock();
+ if (sock < 0)
+ sock_errno = errno;
+
+ parse_args(argc, argv);
+
+ if (opt_h || opt_v)
+ print_copying();
+ if (opt_h) {
+ print_usage();
+ exit(1);
+ }
+
+ if (sock_errno) {
+ DEBUG(LOG_ERR, "%s\n", strerror(sock_errno));
+ exit(1);
+ }
+
+ if (!opt_d)
+ do_daemonize();
+
+ setuid(getuid());
+
+ /* initialize */
+ if (init_sock(sock) < 0)
+ exit(1);
+
+ init_core(1);
+
+ /* main loop */
+ while(1) {
+ struct packetcontext *p;
+ struct icmp6_hdr *icmph;
+#if ENABLE_DEBUG
+ char saddrbuf[NI_MAXHOST];
+ int gni;
+#endif
+
+ init_core(0);
+
+ p = ni_malloc(sizeof(*p));
+ if (!p) {
+ DEBUG(LOG_WARNING, "%s(): failed to allocate packet context; sleep 1 sec.\n",
+ __FUNCTION__);
+ sleep(1);
+ continue;
+ }
+
+ while (1) {
+ memset(p, 0, sizeof(*p));
+ p->sock = sock;
+
+ if (ni_recv(p) < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ /* XXX: syslog */
+ continue;
+ }
+ break;
+ }
+
+#if ENABLE_DEBUG
+ gni = getnameinfo((struct sockaddr *)&p->addr,
+ p->addrlen,
+ saddrbuf, sizeof(saddrbuf),
+ NULL, 0,
+ NI_NUMERICHOST);
+ if (gni)
+ sprintf(saddrbuf, "???");
+#endif
+ init_core(0);
+
+ if (p->querylen < sizeof(struct icmp6_hdr)) {
+ ni_free(p);
+ DEBUG(LOG_WARNING, "Too short icmp message from %s\n", saddrbuf);
+ continue;
+ }
+
+ icmph = (struct icmp6_hdr *)p->query;
+
+ DEBUG(LOG_DEBUG,
+ "type=%d, code=%d, cksum=0x%04x\n",
+ icmph->icmp6_type, icmph->icmp6_code,
+ ntohs(icmph->icmp6_cksum));
+
+ if (icmph->icmp6_type != ICMP6_NI_QUERY) {
+ DEBUG(LOG_WARNING,
+ "Strange icmp type %d from %s\n",
+ icmph->icmp6_type, saddrbuf);
+ ni_free(p);
+ continue;
+ }
+
+ pr_nodeinfo(p); /* this frees p */
+ }
+}
+
diff --git a/ninfod/ninfod.h b/ninfod/ninfod.h
new file mode 100644
index 0000000..2de9dbc
--- /dev/null
+++ b/ninfod/ninfod.h
@@ -0,0 +1,135 @@
+/* $USAGI: ninfod.h,v 1.20 2002-12-19 15:51:16 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+/* definitions */
+#define NINFOD "ninfod"
+#define NINFOD_PIDFILE "/var/run/ninfod.pid"
+
+#define MAX_ANYCAST_DELAY_TIME 1000000.0 /* 1 sec */
+
+#define MAX_DNSLABEL_SIZE 63
+#define MAX_DNSNAME_SIZE 255
+#define MAX_QUERY_SIZE (sizeof(struct icmp6_nodeinfo)+MAX_DNSNAME_SIZE+2)
+#define MAX_REPLY_SIZE 1280-sizeof(struct ip6_hdr)
+
+#define MAX_SUPTYPES 32
+
+#define CHECKANDFILL_ARGS struct packetcontext *p,\
+ char *subject, size_t subjlen, \
+ unsigned int flags, \
+ unsigned int *subj_if, \
+ int reply
+#define INIT_ARGS \
+ int forced
+
+struct packetcontext {
+ /* socket */
+ int sock;
+
+ /* query info */
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ struct in6_pktinfo pktinfo;
+ char query[MAX_QUERY_SIZE];
+ int querylen;
+
+ /* reply info */
+ struct icmp6_nodeinfo reply; /* common */
+ char *replydata; /* data */
+ int replydatalen;
+
+ unsigned int delay; /* (random) delay */
+};
+
+/* variables */
+extern int opt_v; /* ninfod.c */
+extern int daemonized; /* ninfod.c */
+extern int sock; /* ninfod.c */
+extern int initialized; /* ninfod_core.c */
+
+/* ninfod.c* */
+int ni_recv(struct packetcontext *p);
+int ni_send(struct packetcontext *p);
+
+/* ninfod_core.c */
+#if ENABLE_DEBUG
+void stderrlog(int priority, char *format, ...);
+# define DEBUG(pri, fmt, args...) do { \
+ int saved_errno = errno; \
+ if (opt_v || pri != LOG_DEBUG) { \
+ if (daemonized) { \
+ syslog(pri, fmt, ## args); \
+ } else { \
+ stderrlog(pri, fmt, ## args); \
+ } \
+ } \
+ errno = saved_errno; \
+ } while(0)
+#else
+# define DEBUG(pri, fmt, args...) do { ; } while(0)
+#endif
+
+#define ni_malloc(size) ({ \
+ size_t _size = (size); \
+ void *p = malloc(_size); \
+ DEBUG(LOG_DEBUG, "%s(): malloc(%d) = %p\n", __FUNCTION__, _size, p); \
+ p; \
+ })
+#define ni_free(p) ({ \
+ void *_p = (p); \
+ int saved_errno = errno; \
+ DEBUG(LOG_DEBUG, "%s(): free(%p)\n", __FUNCTION__, _p); \
+ free(_p); \
+ errno = saved_errno; \
+ })
+
+void init_core(int forced);
+int pr_nodeinfo(struct packetcontext *p);
+
+int pr_nodeinfo_unknown(CHECKANDFILL_ARGS);
+int pr_nodeinfo_refused(CHECKANDFILL_ARGS);
+int pr_nodeinfo_noop(CHECKANDFILL_ARGS);
+void init_nodeinfo_suptypes(INIT_ARGS);
+int pr_nodeinfo_suptypes(CHECKANDFILL_ARGS);
+
+/* ninfod_addrs.c */
+void init_nodeinfo_ipv6addr(INIT_ARGS);
+int pr_nodeinfo_ipv6addr(CHECKANDFILL_ARGS);
+void init_nodeinfo_ipv4addr(INIT_ARGS);
+int pr_nodeinfo_ipv4addr(CHECKANDFILL_ARGS);
+
+/* ninfod_name.c */
+void init_nodeinfo_nodename(INIT_ARGS);
+int pr_nodeinfo_nodename(CHECKANDFILL_ARGS);
+
diff --git a/ninfod/ninfod.sh.in b/ninfod/ninfod.sh.in
new file mode 100644
index 0000000..4c5e6b5
--- /dev/null
+++ b/ninfod/ninfod.sh.in
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+NINFOD=@prefix@/sbin/ninfod
+PID=/var/run/ninfod.pid
+
+if ! [ -x $NINFOD ]; then
+ exit 0
+fi
+
+case "$1" in
+ start)
+ echo -n "Starting node infomation daemon:"
+ echo -n " ninfod" ;
+ $NINFOD
+ echo "."
+ ;;
+ stop)
+ echo -n "Stopping node infomation daemon:"
+ echo -n " ninfod" ;
+ kill `cat $PID`
+ echo "."
+ ;;
+ restart)
+ echo -n "Restarting node information daemon:"
+ echo -n " ninfod"
+ kill `cat $PID`
+ $NINFOD
+ echo "."
+ ;;
+ *)
+ echo "Usage: /etc/init.d/ninfod {start|stop|restart}"
+ exit 1
+ ;;
+esac
+
+exit 0
+
diff --git a/ninfod/ninfod_addrs.c b/ninfod/ninfod_addrs.c
new file mode 100644
index 0000000..9668a0d
--- /dev/null
+++ b/ninfod/ninfod_addrs.c
@@ -0,0 +1,469 @@
+/* $USAGI: ninfod_addrs.c,v 1.18 2003-07-16 09:49:01 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if STDC_HEADERS
+# include <stdio.h>
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#include <sys/socket.h>
+#if HAVE_LINUX_RTNETLINK_H
+#include <asm/types.h>
+#include <linux/rtnetlink.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#if HAVE_NETINET_IP6_H
+# include <netinet/ip6.h>
+#endif
+
+#if HAVE_NETINET_ICMP6_H
+# include <netinet/icmp6.h>
+#endif
+#ifndef HAVE_STRUCT_ICMP6_NODEINFO
+# include "icmp6_nodeinfo.h"
+#endif
+
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#include <errno.h>
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include "ninfod.h"
+#include "ni_ifaddrs.h"
+
+#ifndef offsetof
+# define offsetof(aggregate,member) ((size_t)&((aggregate *)0)->member)
+#endif
+
+/* ---------- */
+/* ID */
+static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_addrs.c,v 1.18 2003-07-16 09:49:01 yoshfuji Exp $";
+
+/* ---------- */
+/* ipv6 address */
+void init_nodeinfo_ipv6addr(INIT_ARGS)
+{
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+ return;
+}
+
+int filter_ipv6addr(const struct in6_addr *ifaddr, unsigned int flags)
+{
+ if (IN6_IS_ADDR_UNSPECIFIED(ifaddr) ||
+ IN6_IS_ADDR_LOOPBACK(ifaddr)) {
+ return 1;
+ } else if (IN6_IS_ADDR_V4COMPAT(ifaddr) ||
+ IN6_IS_ADDR_V4MAPPED(ifaddr)) {
+ return !(flags & NI_NODEADDR_FLAG_COMPAT);
+ } else if (IN6_IS_ADDR_LINKLOCAL(ifaddr)) {
+ return !(flags & NI_NODEADDR_FLAG_LINKLOCAL);
+ } else if (IN6_IS_ADDR_SITELOCAL(ifaddr)) {
+ return !(flags & NI_NODEADDR_FLAG_SITELOCAL);
+ }
+ return !(flags & NI_NODEADDR_FLAG_GLOBAL);
+}
+
+int pr_nodeinfo_ipv6addr(CHECKANDFILL_ARGS)
+{
+ struct ni_ifaddrs *ifa0;
+ unsigned int ifindex = 0;
+
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+
+ if (subject && subjlen != sizeof(struct in6_addr)) {
+ DEBUG(LOG_INFO,
+ "%s(): invalid subject length %u for IPv6 Address Subject\n",
+ __FUNCTION__, subjlen);
+ return 1;
+ }
+ if (ni_ifaddrs(&ifa0, AF_INET6))
+ return -1; /* failed to get addresses */
+
+ /* pass 0: consider subject and determine subjected interface */
+ if (subject) {
+ struct ni_ifaddrs *ifa;
+
+ for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr)
+ continue;
+ if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
+ continue;
+ if (!ifindex &&
+ IN6_ARE_ADDR_EQUAL(&p->pktinfo.ipi6_addr,
+ (struct in6_addr *)subject)) {
+ /*
+ * if subject is equal to destination
+ * address, receiving interface is
+ * the candidate subject interface.
+ */
+ ifindex = p->pktinfo.ipi6_ifindex;
+ }
+ if (!IN6_IS_ADDR_LOOPBACK((struct in6_addr *)subject) &&
+ IN6_ARE_ADDR_EQUAL((struct in6_addr *)ifa->ifa_addr,
+ (struct in6_addr *)subject)) {
+ /*
+ * address is assigned on some interface.
+ * if multiple interfaces have the same interface,
+ * 1) prefer receiving interface
+ * 2) use first found one
+ */
+ if (!ifindex ||
+ (p->pktinfo.ipi6_ifindex == ifindex))
+ ifindex = ifa->ifa_ifindex;
+ }
+ }
+ if (!ifindex) {
+ ni_freeifaddrs(ifa0);
+ return 1; /* subject not found */
+ }
+ if (subj_if)
+ *subj_if = ifindex;
+ } else {
+ ifindex = subj_if ? *subj_if : 0;
+ if (ifindex == 0)
+ ifindex = p->pktinfo.ipi6_ifindex;
+ if (ifindex == 0) {
+ ni_freeifaddrs(ifa0);
+ return 1; /* XXX */
+ }
+ }
+
+ if (reply) {
+ struct ni_ifaddrs *ifa;
+ unsigned int addrs0 = 0, paddrs0 = 0;
+ unsigned int addrs, paddrs = 0, daddrs = 0;
+
+ flags &= ~NI_NODEADDR_FLAG_TRUNCATE;
+
+ /* pass 1: count addresses and preferred addresses to be returned */
+ for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr)
+ continue;
+ if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
+ continue;
+ if (!(flags & NI_NODEADDR_FLAG_ALL) &&
+ ifa->ifa_ifindex != ifindex)
+ continue;
+ if (filter_ipv6addr((struct in6_addr *)ifa->ifa_addr, flags))
+ continue;
+
+ if (addrs0 + 1 >= ((MAX_REPLY_SIZE - sizeof(struct icmp6_nodeinfo)) / (sizeof(uint32_t) + sizeof(struct in6_addr)))) {
+ flags |= ~NI_NODEADDR_FLAG_TRUNCATE;
+ break;
+ }
+
+ addrs0++;
+ if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
+ paddrs0++;
+ }
+
+ p->reply.ni_type = ICMP6_NI_REPLY;
+ p->reply.ni_code = ICMP6_NI_SUCCESS;
+ p->reply.ni_cksum = 0;
+ p->reply.ni_qtype = htons(NI_QTYPE_NODEADDR);
+ p->reply.ni_flags = flags&(NI_NODEADDR_FLAG_COMPAT|
+ NI_NODEADDR_FLAG_LINKLOCAL|
+ NI_NODEADDR_FLAG_SITELOCAL|
+ NI_NODEADDR_FLAG_GLOBAL);
+
+ /* pass 2: store addresses */
+ p->replydatalen = (sizeof(uint32_t)+sizeof(struct in6_addr)) * addrs0;
+ p->replydata = p->replydatalen ? ni_malloc(p->replydatalen) : NULL;
+
+ if (p->replydatalen && !p->replydata) {
+ p->reply.ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
+ addrs0 = paddrs0 = 0;
+ }
+
+ for (ifa = ifa0, addrs = 0;
+ ifa && addrs < addrs0;
+ ifa = ifa->ifa_next) {
+ char *cp;
+ uint32_t ttl;
+
+ if (!ifa->ifa_addr)
+ continue;
+ if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
+ continue;
+ if (!(flags & NI_NODEADDR_FLAG_ALL) &&
+ ((subj_if && *subj_if) ? (ifa->ifa_ifindex != *subj_if) :
+ (ifa->ifa_ifindex != p->pktinfo.ipi6_ifindex)))
+ continue;
+ if (filter_ipv6addr((struct in6_addr *)ifa->ifa_addr, flags))
+ continue;
+
+#if ENABLE_TTL
+ if (ifa->ifa_cacheinfo) {
+ ttl = ifa->ifa_cacheinfo->ifa_valid > 0x7fffffff ?
+ htonl(0x7fffffff) : htonl(ifa->ifa_cacheinfo->ifa_valid);
+ } else {
+ ttl = (ifa->ifa_flags & IFA_F_PERMANENT) ? htonl(0x7fffffff) : 0;
+ }
+#else
+ ttl = 0;
+#endif
+
+ cp = p->replydata +
+ (sizeof(uint32_t)+sizeof(struct in6_addr)) * (ifa->ifa_flags & IFA_F_DEPRECATED ? paddrs0+daddrs : paddrs);
+ memcpy(cp, &ttl, sizeof(ttl));
+ memcpy(cp + sizeof(ttl), ifa->ifa_addr, sizeof(struct in6_addr));
+
+ addrs++;
+ if (ifa->ifa_flags & IFA_F_DEPRECATED)
+ daddrs++;
+ else
+ paddrs++;
+ }
+ }
+
+ ni_freeifaddrs(ifa0);
+ return 0;
+}
+
+/* ipv4 address */
+void init_nodeinfo_ipv4addr(INIT_ARGS)
+{
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+ return;
+}
+
+int filter_ipv4addr(const struct in_addr *ifaddr, unsigned int flags)
+{
+ return 0;
+}
+
+int pr_nodeinfo_ipv4addr(CHECKANDFILL_ARGS)
+{
+ struct ni_ifaddrs *ifa0;
+ unsigned int ifindex = 0;
+
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+
+ if (subject && subjlen != sizeof(struct in_addr)) {
+ DEBUG(LOG_INFO,
+ "%s(): invalid subject length %u for IPv4 Address Subject\n",
+ __FUNCTION__, subjlen);
+ return 1;
+ }
+ if (ni_ifaddrs(&ifa0, AF_INET))
+ return -1; /* failed to get addresses */
+
+ /* pass 0: consider subject and determine subjected interface */
+ if (subject) {
+ struct ni_ifaddrs *ifa;
+
+ for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr)
+ continue;
+ if (ifa->ifa_flags & (IFA_F_TENTATIVE|IFA_F_SECONDARY))
+ continue;
+ if ((((struct in_addr *)subject)->s_addr != htonl(INADDR_LOOPBACK)) &&
+ memcmp((struct in_addr *)ifa->ifa_addr,
+ (struct in_addr *)subject,
+ sizeof(struct in_addr)) == 0) {
+ /*
+ * address is assigned on some interface.
+ * if multiple interfaces have the same interface,
+ * 1) prefer receiving interface
+ * 2) use first found one
+ */
+ if (!ifindex ||
+ (p->pktinfo.ipi6_ifindex == ifindex))
+ ifindex = ifa->ifa_ifindex;
+ }
+ }
+ if (!ifindex) {
+ ni_freeifaddrs(ifa0);
+ return 1; /* subject not found */
+ }
+ if (subj_if)
+ *subj_if = ifindex;
+ } else {
+ ifindex = subj_if ? *subj_if : 0;
+ if (ifindex == 0)
+ ifindex = p->pktinfo.ipi6_ifindex;
+ if (ifindex == 0) {
+ ni_freeifaddrs(ifa0);
+ return 1; /* XXX */
+ }
+ }
+
+ if (reply) {
+ struct ni_ifaddrs *ifa;
+ unsigned int addrs0 = 0, paddrs0 = 0;
+ unsigned int addrs, paddrs = 0, daddrs = 0;
+
+ flags &= ~NI_IPV4ADDR_FLAG_TRUNCATE;
+
+ /* pass 1: count addresses and preferred addresses to be returned */
+ for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr)
+ continue;
+#if 1 /* not used in kernel */
+ if (ifa->ifa_flags & (IFA_F_TENTATIVE))
+ continue;
+#endif
+ if (!(flags & NI_NODEADDR_FLAG_ALL) &&
+ ((subj_if && *subj_if) ? (ifa->ifa_ifindex != *subj_if) :
+ (ifa->ifa_ifindex != p->pktinfo.ipi6_ifindex)))
+ continue;
+ if (filter_ipv4addr((struct in_addr *)ifa->ifa_addr, flags))
+ continue;
+
+ if (addrs0 + 1 >= ((MAX_REPLY_SIZE - sizeof(struct icmp6_nodeinfo)) / (sizeof(uint32_t) + sizeof(struct in_addr)))) {
+ flags |= NI_IPV4ADDR_FLAG_TRUNCATE;
+ break;
+ }
+
+ addrs0++;
+ if (!(ifa->ifa_flags & IFA_F_DEPRECATED))
+ paddrs0++;
+ }
+
+ p->reply.ni_type = ICMP6_NI_REPLY;
+ p->reply.ni_code = ICMP6_NI_SUCCESS;
+ p->reply.ni_cksum = 0;
+ p->reply.ni_qtype = htons(NI_QTYPE_IPV4ADDR);
+ p->reply.ni_flags = flags & NI_IPV4ADDR_FLAG_ALL;
+
+ /* pass 2: store addresses */
+ p->replydatalen = (sizeof(uint32_t)+sizeof(struct in_addr)) * addrs0;
+ p->replydata = addrs0 ? ni_malloc(p->replydatalen) : NULL;
+
+ if (p->replydatalen && !p->replydata) {
+ p->reply.ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
+ addrs0 = paddrs0 = 0;
+ }
+
+ for (ifa = ifa0, addrs = 0;
+ ifa && addrs < addrs0;
+ ifa = ifa->ifa_next) {
+ char *cp;
+ uint32_t ttl;
+
+ if (!ifa->ifa_addr)
+ continue;
+#if 1 /* not used in kernel */
+ if (ifa->ifa_flags & (IFA_F_TENTATIVE))
+ continue;
+#endif
+ if (!(flags & NI_NODEADDR_FLAG_ALL) &&
+ (ifa->ifa_ifindex != ifindex))
+ continue;
+ if (filter_ipv4addr((struct in_addr *)ifa->ifa_addr, flags))
+ continue;
+
+#if ENABLE_TTL
+ if (ifa->ifa_cacheinfo) {
+ ttl = ifa->ifa_cacheinfo->ifa_valid > 0x7fffffff ?
+ htonl(0x7fffffff) : htonl(ifa->ifa_cacheinfo->ifa_valid);
+ } else {
+ ttl = 0; /*XXX*/
+ }
+#else
+ ttl = 0;
+#endif
+
+ cp = (p->replydata +
+ (sizeof(uint32_t)+sizeof(struct in_addr)) * (ifa->ifa_flags & IFA_F_DEPRECATED ? paddrs0+daddrs : paddrs));
+ memcpy(cp, &ttl, sizeof(ttl));
+ memcpy(cp + sizeof(ttl), ifa->ifa_addr, sizeof(struct in_addr));
+
+ addrs++;
+ if (ifa->ifa_flags & IFA_F_DEPRECATED)
+ daddrs++;
+ else
+ paddrs++;
+ }
+ }
+
+ ni_freeifaddrs(ifa0);
+ return 0;
+}
+
diff --git a/ninfod/ninfod_core.c b/ninfod/ninfod_core.c
new file mode 100644
index 0000000..d2ce923
--- /dev/null
+++ b/ninfod/ninfod_core.c
@@ -0,0 +1,641 @@
+/* $USAGI: ninfod_core.c,v 1.29 2003-07-16 09:49:01 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if STDC_HEADERS
+# include <stdio.h>
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if ENABLE_THREADS && HAVE_PTHREAD_H
+# include <pthread.h>
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#if HAVE_NETINET_ICMP6_H
+# include <netinet/icmp6.h>
+#endif
+#ifndef HAVE_STRUCT_ICMP6_NODEINFO
+# include "icmp6_nodeinfo.h"
+#endif
+
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#include <errno.h>
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include "ninfod.h"
+
+#ifndef offsetof
+# define offsetof(aggregate,member) ((size_t)&((aggregate *)0)->member)
+#endif
+
+/* ---------- */
+/* ID */
+static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_core.c,v 1.29 2003-07-16 09:49:01 yoshfuji Exp $";
+
+/* Variables */
+int initialized = 0;
+
+#if ENABLE_THREADS && HAVE_LIBPTHREAD
+pthread_attr_t pattr;
+#endif
+
+static uint32_t suptypes[(MAX_SUPTYPES+31)>>5];
+static size_t suptypes_len;
+
+/* ---------- */
+struct subjinfo {
+ uint8_t code;
+ char *name;
+ int (*checksubj)(CHECKANDFILL_ARGS);
+ int (*init)(INIT_ARGS);
+};
+
+static struct subjinfo subjinfo_table [] = {
+ [ICMP6_NI_SUBJ_IPV6] = {
+ .code = ICMP6_NI_SUBJ_IPV6,
+ .name = "IPv6",
+ //.init = init_nodeinfo_ipv6addr,
+ .checksubj = pr_nodeinfo_ipv6addr,
+ },
+ [ICMP6_NI_SUBJ_FQDN] = {
+ .code = ICMP6_NI_SUBJ_FQDN,
+ .name = "FQDN",
+ //.init = init_nodeinfo_nodename,
+ .checksubj = pr_nodeinfo_nodename,
+ },
+ [ICMP6_NI_SUBJ_IPV4] = {
+ .code = ICMP6_NI_SUBJ_IPV4,
+ .name = "IPv4",
+ //.init = init_nodeinfo_ipv4addr,
+ .checksubj = pr_nodeinfo_ipv4addr,
+ },
+};
+
+static struct subjinfo subjinfo_null = {
+ .name = "null",
+ .checksubj = pr_nodeinfo_noop,
+};
+
+static __inline__ struct subjinfo *subjinfo_lookup(int code)
+{
+ if (code >= sizeof(subjinfo_table)/sizeof(subjinfo_table[0]))
+ return NULL;
+ if (subjinfo_table[code].name == NULL)
+ return NULL;
+ return &subjinfo_table[code];
+}
+
+/* ---------- */
+#define QTYPEINFO_F_RATELIMIT 0x1
+
+struct qtypeinfo {
+ uint16_t qtype;
+ char *name;
+ int (*getreply)(CHECKANDFILL_ARGS);
+ void (*init)(INIT_ARGS);
+ int flags;
+};
+
+static struct qtypeinfo qtypeinfo_table[] = {
+ [NI_QTYPE_NOOP] = {
+ .qtype = NI_QTYPE_NOOP,
+ .name = "NOOP",
+ .getreply = pr_nodeinfo_noop,
+ },
+#if ENABLE_SUPTYPES
+ [NI_QTYPE_SUPTYPES] = {
+ .qtype = NI_QTYPE_SUPTYPES,
+ .name = "SupTypes",
+ .getreply = pr_nodeinfo_suptypes,
+ .init = init_nodeinfo_suptypes,
+ },
+#endif
+ [NI_QTYPE_DNSNAME] = {
+ .qtype = NI_QTYPE_DNSNAME,
+ .name = "DnsName",
+ .getreply = pr_nodeinfo_nodename,
+ .init = init_nodeinfo_nodename,
+ },
+ [NI_QTYPE_NODEADDR] = {
+ .qtype = NI_QTYPE_NODEADDR,
+ .name = "NodeAddr",
+ .getreply = pr_nodeinfo_ipv6addr,
+ .init = init_nodeinfo_ipv6addr,
+ },
+ [NI_QTYPE_IPV4ADDR] = {
+ .qtype = NI_QTYPE_IPV4ADDR,
+ .name = "IPv4Addr",
+ .getreply = pr_nodeinfo_ipv4addr,
+ .init = init_nodeinfo_ipv4addr,
+ },
+};
+
+static struct qtypeinfo qtypeinfo_unknown = {
+ .name = "unknown",
+ .getreply = pr_nodeinfo_unknown,
+ .flags = QTYPEINFO_F_RATELIMIT,
+};
+
+static struct qtypeinfo qtypeinfo_refused = {
+ .name = "refused",
+ .getreply = pr_nodeinfo_refused,
+ .flags = QTYPEINFO_F_RATELIMIT,
+};
+
+static __inline__ struct qtypeinfo *qtypeinfo_lookup(int qtype)
+{
+ if (qtype >= sizeof(qtypeinfo_table)/sizeof(qtypeinfo_table[0]))
+ return &qtypeinfo_unknown;
+ if (qtypeinfo_table[qtype].name == NULL)
+ return &qtypeinfo_unknown;
+ return &qtypeinfo_table[qtype];
+}
+
+/* ---------- */
+/* noop */
+int pr_nodeinfo_noop(CHECKANDFILL_ARGS)
+{
+ struct icmp6_nodeinfo *replybuf = NULL;
+
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+
+ if (subjlen) {
+ DEBUG(LOG_WARNING,
+ "%s(): invalid subject length(%d)\n",
+ __FUNCTION__, subjlen);
+ return 1;
+ }
+
+ if (reply) {
+ p->reply.ni_type = ICMP6_NI_REPLY;
+ p->reply.ni_code = ICMP6_NI_SUCCESS;
+ p->reply.ni_cksum = 0;
+ p->reply.ni_qtype = htons(NI_QTYPE_NOOP);
+ p->reply.ni_flags = flags;
+ }
+
+ if (subj_if)
+ *subj_if = 0;
+
+ return 0;
+}
+
+#if ENABLE_SUPTYPES
+/* suptypes */
+int pr_nodeinfo_suptypes(CHECKANDFILL_ARGS)
+{
+ size_t replylen = sizeof(struct icmp6_nodeinfo) + (suptypes_len<<2);
+
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+
+ if (subjlen) {
+ DEBUG(LOG_WARNING, "%s(): invalid subject length(%d)\n",
+ __FUNCTION__, subjlen);
+ return 1;
+ }
+
+ if (reply) {
+ p->reply.ni_type = ICMP6_NI_REPLY;
+ p->reply.ni_code = ICMP6_NI_SUCCESS;
+ p->reply.ni_cksum = 0;
+ p->reply.ni_qtype = htons(NI_QTYPE_SUPTYPES);
+ p->reply.ni_flags = flags&~NI_SUPTYPE_FLAG_COMPRESS;
+
+ p->replydatalen = suptypes_len<<2;
+ p->replydata = ni_malloc(p->replydatalen);
+ if (p->replydata == NULL) {
+ p->replydatalen = -1;
+ return -1; /*XXX*/
+ }
+
+ memcpy(p->replydata, suptypes, p->replydatalen);
+ }
+ return 0;
+}
+
+void init_nodeinfo_suptypes(INIT_ARGS)
+{
+ size_t w, b;
+ int i;
+
+ if (!forced && initialized)
+ return;
+
+ memset(suptypes, 0, sizeof(suptypes));
+ suptypes_len = 0;
+
+ for (i=0; i<sizeof(qtypeinfo_table)/sizeof(qtypeinfo_table[0]); i++) {
+ unsigned short qtype;
+
+ if (qtypeinfo_table[i].name == NULL)
+ continue;
+ qtype = qtypeinfo_table[i].qtype;
+ w = qtype>>5;
+ b = qtype&0x1f;
+ if (w > sizeof(suptypes)/sizeof(suptypes[0])) {
+ DEBUG(LOG_ERR, "Warning: Too Large Supported Types\n");
+ exit(1);
+ }
+ suptypes[w] |= htonl(1<<b);
+
+ if (suptypes_len < w)
+ suptypes_len = w;
+ }
+ suptypes_len++;
+}
+#endif
+
+/* ---------- */
+/* unknown qtype response */
+int pr_nodeinfo_unknown(CHECKANDFILL_ARGS)
+{
+ if (!reply)
+ return -1; /*???*/
+
+ p->reply.ni_type = ICMP6_NI_REPLY;
+ p->reply.ni_code = ICMP6_NI_UNKNOWN;
+ p->reply.ni_cksum = 0;
+ //p->reply.ni_qtype = 0;
+ p->reply.ni_flags = flags;
+
+ p->replydata = NULL;
+ p->replydatalen = 0;
+
+ return 0;
+}
+
+/* refused response */
+int pr_nodeinfo_refused(CHECKANDFILL_ARGS)
+{
+ if (!reply)
+ return -1; /*???*/
+
+ p->reply.ni_type = ICMP6_NI_REPLY;
+ p->reply.ni_code = ICMP6_NI_REFUSED;
+ p->reply.ni_cksum = 0;
+ //p->reply.ni_qtype = 0;
+ p->reply.ni_flags = flags;
+
+ p->replydata = NULL;
+ p->replydatalen = 0;
+
+ return 0;
+}
+
+/* ---------- */
+void init_core(int forced)
+{
+ int i;
+
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+
+ if (!initialized || forced) {
+ struct timeval tv;
+ unsigned int seed = 0;
+ pid_t pid;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ DEBUG(LOG_WARNING, "%s(): failed to gettimeofday()\n", __FUNCTION__);
+ } else {
+ seed = (tv.tv_usec & 0xffffffff);
+ }
+
+ pid = getpid();
+ seed ^= (((unsigned long)pid) & 0xffffffff);
+
+ srand(seed);
+
+#if ENABLE_THREADS && HAVE_LIBPTHREAD
+ if (initialized)
+ pthread_attr_destroy(&pattr);
+
+ pthread_attr_init(&pattr);
+ pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
+#endif
+ }
+
+ for (i=0; i<sizeof(subjinfo_table)/sizeof(subjinfo_table[0]); i++) {
+ if (subjinfo_table[i].name == NULL)
+ continue;
+ if (subjinfo_table[i].init)
+ subjinfo_table[i].init(forced);
+ }
+
+ for (i=0; i<sizeof(qtypeinfo_table)/sizeof(qtypeinfo_table[0]); i++) {
+ if (qtypeinfo_table[i].name == NULL)
+ continue;
+ if (qtypeinfo_table[i].init)
+ qtypeinfo_table[i].init(forced);
+ }
+
+ initialized = 1;
+
+ return;
+}
+
+#if ENABLE_THREADS && HAVE_LIBPTHREAD
+static void *ni_send_thread(void *data)
+{
+ int ret;
+ DEBUG(LOG_DEBUG, "%s(): thread=%ld\n", __FUNCTION__, pthread_self());
+ ret = ni_send(data);
+ DEBUG(LOG_DEBUG, "%s(): thread=%ld => %d\n", __FUNCTION__, pthread_self(), ret);
+ return NULL;
+}
+#else
+static int ni_send_fork(struct packetcontext *p)
+{
+ pid_t child = fork();
+ if (child < 0)
+ return -1;
+ if (child == 0) {
+ pid_t grandchild = fork();
+ if (grandchild < 0)
+ exit(1);
+ if (grandchild == 0) {
+ int ret;
+ DEBUG(LOG_DEBUG, "%s(): worker=%d\n",
+ __FUNCTION__, getpid());
+ ret = ni_send(p);
+ DEBUG(LOG_DEBUG, "%s(): worker=%d => %d\n",
+ __FUNCTION__, getpid(), ret);
+ }
+ ni_free(p->replydata);
+ ni_free(p);
+ exit(0);
+ } else {
+ waitpid(child, NULL, 0);
+ ni_free(p->replydata);
+ ni_free(p);
+ }
+ return 0;
+}
+#endif
+
+static int ni_ratelimit(void)
+{
+ static struct timeval last;
+ struct timeval tv, sub;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ DEBUG(LOG_WARNING, "%s(): gettimeofday(): %s\n",
+ __FUNCTION__, strerror(errno));
+ return -1;
+ }
+
+ if (!timerisset(&last)) {
+ last = tv;
+ return 0;
+ }
+
+ timersub(&tv, &last, &sub);
+
+ if (sub.tv_sec < 1)
+ return 1;
+
+ last = tv;
+ return 0;
+}
+
+int pr_nodeinfo(struct packetcontext *p)
+{
+ struct icmp6_nodeinfo *query = (struct icmp6_nodeinfo *)p->query;
+
+ char *subject = (char *)(query + 1);
+ size_t subjlen;
+ struct subjinfo *subjinfo;
+ struct qtypeinfo *qtypeinfo;
+ int replyonsubjcheck = 0;
+ unsigned int subj_if;
+#if ENABLE_DEBUG
+ char printbuf[128];
+ int i;
+ char *cp;
+#endif
+#if ENABLE_THREADS && HAVE_PTHREAD_H
+ pthread_t thread;
+#endif
+
+ /* Step 1: Check length */
+ if (p->querylen < sizeof(struct icmp6_nodeinfo)) {
+ DEBUG(LOG_WARNING, "Query too short\n");
+ ni_free(p);
+ return -1;
+ }
+
+#if ENABLE_DEBUG
+ cp = printbuf;
+ for (i = 0; i < sizeof(query->icmp6_ni_nonce); i++) {
+ cp += sprintf(cp, " %02x", query->icmp6_ni_nonce[i]);
+ }
+ DEBUG(LOG_DEBUG, "%s(): qtype=%d, flags=0x%04x, nonce[] = {%s }\n",
+ __FUNCTION__,
+ ntohs(query->ni_qtype), ntohs(query->ni_flags), printbuf);
+#endif
+
+ subjlen = p->querylen - sizeof(struct icmp6_nodeinfo);
+
+ /* Step 2: Check Subject Code */
+ switch(htons(query->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ case NI_QTYPE_SUPTYPES:
+ if (query->ni_code != ICMP6_NI_SUBJ_FQDN) {
+ DEBUG(LOG_WARNING,
+ "%s(): invalid/unknown code %u\n",
+ __FUNCTION__, query->ni_code);
+ subjlen = 0;
+ }
+ subjinfo = &subjinfo_null;
+ break;
+ default:
+ subjinfo = subjinfo_lookup(query->ni_code);
+ if (!subjinfo) {
+ DEBUG(LOG_WARNING,
+ "%s(): unknown code %u\n",
+ __FUNCTION__, query->ni_code);
+ ni_free(p);
+ return -1;
+ }
+ }
+
+ /* Step 3: Lookup Qtype */
+ qtypeinfo = qtypeinfo_lookup(ntohs(query->ni_qtype));
+
+ /* Step 4: Check Subject
+ * (And fill reply if it is available now)
+ */
+ if (qtypeinfo->getreply == subjinfo->checksubj)
+ replyonsubjcheck = 1;
+
+ if (subjinfo->checksubj(p,
+ subject, subjlen,
+ query->ni_flags,
+ replyonsubjcheck ? NULL : &subj_if,
+ replyonsubjcheck)) {
+ if (p->replydatalen < 0) {
+ DEBUG(LOG_WARNING,
+ "failed to make reply: %s\n",
+ strerror(errno));
+ }
+ ni_free(p);
+ return -1;
+ }
+
+ /* XXX: Step 5: Check the policy */
+ if (0) {
+ ni_free(p->replydata);
+ p->replydata = NULL;
+ replyonsubjcheck = 0;
+ qtypeinfo = &qtypeinfo_refused;
+ }
+
+ /* Step 6: Fill the reply if not yet done */
+ if (!replyonsubjcheck) {
+ if (qtypeinfo->getreply(p,
+ NULL, 0,
+ query->ni_flags,
+ &subj_if,
+ 1)) {
+ if (p->replydatalen) {
+ DEBUG(LOG_WARNING,
+ "failed to make reply: %s\n",
+ strerror(errno));
+ }
+ ni_free(p);
+ return -1;
+ }
+ }
+
+ /* Step 7: Rate Limit */
+ if (qtypeinfo->flags&QTYPEINFO_F_RATELIMIT &&
+ ni_ratelimit()) {
+ ni_free(p->replydata);
+ ni_free(p);
+ return -1;
+ }
+
+ /* Step 8: Fill Qtype / Nonce */
+ p->reply.ni_qtype = query->ni_qtype;
+ memcpy(p->reply.icmp6_ni_nonce, query->icmp6_ni_nonce, sizeof(p->reply.icmp6_ni_nonce));
+
+ /* Step 9: Source address selection */
+ if (IN6_IS_ADDR_MULTICAST(&p->pktinfo.ipi6_addr)) {
+ /* if query was sent to multicast address,
+ * use source address selection in kernel.
+ * XXX: anycast?
+ */
+ memset(&p->pktinfo.ipi6_addr, 0, sizeof(p->pktinfo.ipi6_addr));
+
+ /* Random Delay between zero and MAX_ANYCAST_DELAY_TIME is
+ * required if query was sent to anycast or multicast address.
+ */
+ p->delay = (int) (MAX_ANYCAST_DELAY_TIME*rand()/(RAND_MAX+1.0));
+ } else {
+ p->delay = 0;
+ }
+
+ /* Step 10: Send the reply
+ * XXX: with possible random delay */
+#if ENABLE_THREADS && HAVE_LIBPTHREAD
+ /* ni_send_thread() frees p */
+ if (pthread_create(&thread, &pattr, ni_send_thread, p)) {
+ ni_free(p->replydata);
+ ni_free(p);
+ return -1;
+ }
+#else
+ /* ni_send_fork() frees p */
+ if (ni_send_fork(p)) {
+ ni_free(p->replydata);
+ ni_free(p);
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
diff --git a/ninfod/ninfod_name.c b/ninfod/ninfod_name.c
new file mode 100644
index 0000000..6a97fbd
--- /dev/null
+++ b/ninfod/ninfod_name.c
@@ -0,0 +1,381 @@
+/* $USAGI: ninfod_name.c,v 1.15 2003-01-11 14:33:28 yoshfuji Exp $ */
+/*
+ * Copyright (C) 2002 USAGI/WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Author:
+ * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if STDC_HEADERS
+# include <stdio.h>
+# include <stdlib.h>
+# include <stddef.h>
+# include <ctype.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#if HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#include <sys/socket.h>
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#if HAVE_NETINET_ICMP6_H
+# include <netinet/icmp6.h>
+#endif
+#ifndef HAVE_STRUCT_ICMP6_NODEINFO
+# include "icmp6_nodeinfo.h"
+#endif
+
+#include <arpa/inet.h>
+
+#ifdef HAVE_OPENSSL_MD5_H
+#include <openssl/md5.h>
+#endif
+
+#if HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>
+#endif
+#if HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#include <errno.h>
+
+#if HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#include "ninfod.h"
+
+#ifndef offsetof
+# define offsetof(aggregate,member) ((size_t)&((aggregate *)0)->member)
+#endif
+
+/* Hmm,,, */
+#ifndef IPV6_JOIN_GROUP
+# define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
+# define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
+#endif
+
+/* ---------- */
+/* ID */
+static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_name.c,v 1.15 2003-01-11 14:33:28 yoshfuji Exp $";
+
+/* Variables */
+static struct utsname utsname;
+static char *uts_nodename = utsname.nodename;
+
+char nodename[MAX_DNSNAME_SIZE];
+static size_t nodenamelen;
+
+static struct ipv6_mreq nigroup;
+
+/* ---------- */
+/* Functions */
+static int encode_dnsname(const char *name,
+ char *buf, size_t buflen,
+ int fqdn)
+{
+ size_t namelen;
+ int i;
+
+ if (buflen < 0)
+ return -1;
+
+ namelen = strlen(name);
+ if (namelen == 0)
+ return 0;
+ if (namelen > 255 || buflen < namelen+1)
+ return -1;
+
+ i = 0;
+ while(i <= namelen) {
+ const char *e;
+ int llen, ii;
+
+ e = strchr(&name[i], '.');
+ if (e == NULL)
+ e = name + namelen;
+ llen = e - &name[i];
+ if (llen == 0) {
+ if (*e)
+ return -1;
+ if (fqdn < 0)
+ return -1;
+ fqdn = 1;
+ break;
+ }
+ if (llen >= 0x40)
+ return -1;
+ buf[i] = llen;
+ for (ii = 0; ii < llen; ii++) {
+ if (!isascii(name[i+ii]))
+ return -1;
+ if (ii == 0 || ii == llen-1) {
+ if (!isalpha(name[i+ii]) && !isdigit(name[i+ii]))
+ return -1;
+ } else if (!isalnum(name[i+ii]) && name[i+ii] != '-')
+ return -1;
+ buf[i+ii+1] = isupper(name[i+ii]) ? tolower(name[i+ii]) : name[i+ii];
+ }
+ i += llen + 1;
+ }
+ if (buflen < i + 1 + !(fqdn > 0))
+ return -1;
+ buf[i++] = 0;
+ if (!(fqdn > 0))
+ buf[i++] = 0;
+ return i;
+}
+
+static int compare_dnsname(const char *s, size_t slen,
+ const char *n, size_t nlen)
+{
+ const char *s0 = s, *n0 = n;
+ int done = 0, retcode = 0;
+ if (slen < 1 || nlen < 1)
+ return -1; /* invalid length */
+ /* simple case */
+ if (slen == nlen && memcmp(s, n, slen) == 0)
+ return 0;
+ if (*(s0 + slen - 1) || *(n0 + nlen - 1))
+ return -1; /* invalid termination */
+ while (s < s0 + slen && n < n0 + nlen) {
+ if (*s >= 0x40 || *n >= 0x40)
+ return -1; /* DNS compression is not allowed here */
+ if (s + *s + 1 > s0 + slen || n + *n + 1 > n0 + nlen)
+ return -1; /* overrun */
+ if (*s == '\0') {
+ if (s == s0 + slen - 1)
+ break; /* FQDN */
+ else if (s + 1 == s0 + slen - 1)
+ return retcode; /* truncated */
+ else
+ return -1; /* more than one subject */
+ }
+ if (!done) {
+ if (*n == '\0') {
+ if (n == n0 + nlen - 1) {
+ done = 1; /* FQDN */
+ } else if (n + 1 == n0 + nlen - 1) {
+ retcode = 1; // trunc
+ done = 1;
+ } else
+ return -1;
+ } else {
+ if (*s != *n) {
+ done = 1;
+ retcode = 1;
+ } else {
+ if (memcmp(s+1, n+1, *s)) {
+ done = 1;
+ retcode = 1;
+ }
+ }
+ }
+ }
+ s += *s + 1;
+ n += done ? 0 : (*n + 1);
+ }
+ return retcode;
+}
+
+static int nodeinfo_group(const char *dnsname, int namelen,
+ struct in6_addr *nigroup)
+{
+ MD5_CTX ctxt;
+ char digest[16];
+
+ if (!dnsname || !nigroup)
+ return -1;
+
+ MD5_Init(&ctxt);
+ MD5_Update(&ctxt, dnsname, *dnsname);
+ MD5_Final(digest, &ctxt);
+
+#ifdef s6_addr32
+ nigroup->s6_addr32[0] = htonl(0xff020000);
+ nigroup->s6_addr32[1] = 0;
+ nigroup->s6_addr32[2] = htonl(0x00000002);
+#else
+ memset(nigroup, 0, sizeof(*nigroup));
+ nigroup->s6_addr[ 0] = 0xff;
+ nigroup->s6_addr[ 1] = 0x02;
+ nigroup->s6_addr[11] = 0x02;
+#endif
+ memcpy(&nigroup->s6_addr[12], digest, 4);
+
+ return 0;
+}
+
+/* ---------- */
+void init_nodeinfo_nodename(int forced)
+{
+ struct utsname newname;
+ int len;
+ int changed = 0;
+
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+
+ uname(&newname);
+ changed = strcmp(newname.nodename, utsname.nodename);
+
+ if (!changed && !forced)
+ return;
+
+ memcpy(&utsname, &newname, sizeof(newname));
+
+ /* leave old group */
+ if ((changed || forced) && !IN6_IS_ADDR_UNSPECIFIED(&nigroup.ipv6mr_multiaddr)) {
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &nigroup, sizeof(nigroup)) < 0) {
+#if ENABLE_DEBUG
+ char niaddrbuf[INET6_ADDRSTRLEN];
+ if (inet_ntop(AF_INET6, &nigroup, niaddrbuf, sizeof(niaddrbuf)) == NULL)
+ strcpy(niaddrbuf, "???");
+#endif
+ DEBUG(LOG_WARNING,
+ "%s(): failed to leave group %s.\n",
+ __FUNCTION__, niaddrbuf);
+ memset(&nigroup, 0, sizeof(nigroup));
+ }
+ }
+
+ len = encode_dnsname(uts_nodename,
+ nodename,
+ sizeof(nodename),
+ 0);
+
+ /* setup ni reply */
+ nodenamelen = len > 0 ? len : 0;
+
+ /* setup ni group */
+ if (changed || forced) {
+ if (nodenamelen) {
+ memset(&nigroup, 0, sizeof(nigroup));
+ nodeinfo_group(nodename, len, &nigroup.ipv6mr_multiaddr);
+ nigroup.ipv6mr_interface = 0;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &nigroup, sizeof(nigroup)) < 0) {
+#if ENABLE_DEBUG
+ char niaddrbuf[INET6_ADDRSTRLEN];
+ if (inet_ntop(AF_INET6, &nigroup, niaddrbuf, sizeof(niaddrbuf)) == NULL)
+ strcpy(niaddrbuf, "???");
+#endif
+ DEBUG(LOG_WARNING,
+ "%s(): failed to join group %s.\n",
+ __FUNCTION__, niaddrbuf);
+ memset(&nigroup, 0, sizeof(nigroup));
+ }
+ } else {
+ memset(&nigroup, 0, sizeof(nigroup));
+ }
+ }
+
+ return;
+}
+
+/* ---------- */
+/* nodename */
+int pr_nodeinfo_nodename(CHECKANDFILL_ARGS)
+{
+ DEBUG(LOG_DEBUG, "%s()\n", __FUNCTION__);
+
+ if (subject) {
+ if (!nodenamelen ||
+ compare_dnsname(subject, subjlen,
+ nodename,
+ nodenamelen))
+ return 1;
+ if (subj_if)
+ *subj_if = p->pktinfo.ipi6_ifindex;
+ }
+
+ if (reply) {
+ uint32_t ttl = 0;
+
+ p->reply.ni_type = ICMP6_NI_REPLY;
+ p->reply.ni_code = ICMP6_NI_SUCCESS;
+ p->reply.ni_cksum = 0;
+ p->reply.ni_qtype = htons(NI_QTYPE_DNSNAME);
+ p->reply.ni_flags = 0;
+
+ p->replydatalen = nodenamelen ? sizeof(ttl)+nodenamelen : 0;
+ p->replydata = nodenamelen ? ni_malloc(p->replydatalen) : NULL;
+ if (p->replydata) {
+ memcpy(p->replydata, &ttl, sizeof(ttl));
+ memcpy(p->replydata + sizeof(ttl), &nodename, nodenamelen);
+ }
+ }
+
+ return 0;
+}
+