diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2012-10-09 16:13:58 +0900 |
---|---|---|
committer | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2012-10-11 14:23:15 +0900 |
commit | c0685f7a05d11b25fd63e2296f07d2143bba5224 (patch) | |
tree | 07d771b3c8fb36df0cd13165a6e323f70b4878a5 /ninfod | |
parent | a11165d8082213bf96e986e1aaecf841e084c8df (diff) | |
download | iputils-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/COPYING | 26 | ||||
-rw-r--r-- | ninfod/Makefile.in | 78 | ||||
-rw-r--r-- | ninfod/config.h.in | 107 | ||||
-rw-r--r-- | ninfod/configure.in | 133 | ||||
-rw-r--r-- | ninfod/icmp6_nodeinfo.h | 97 | ||||
-rwxr-xr-x | ninfod/install-sh | 251 | ||||
-rw-r--r-- | ninfod/ni_ifaddrs.c | 541 | ||||
-rw-r--r-- | ninfod/ni_ifaddrs.h | 45 | ||||
-rw-r--r-- | ninfod/ninfod.c | 522 | ||||
-rw-r--r-- | ninfod/ninfod.h | 135 | ||||
-rw-r--r-- | ninfod/ninfod.sh.in | 37 | ||||
-rw-r--r-- | ninfod/ninfod_addrs.c | 469 | ||||
-rw-r--r-- | ninfod/ninfod_core.c | 641 | ||||
-rw-r--r-- | ninfod/ninfod_name.c | 381 |
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; +} + |