Home | History | Annotate | Download | only in ninfod
      1 /* $USAGI: ninfod_name.c,v 1.15 2003-01-11 14:33:28 yoshfuji Exp $ */
      2 /*
      3  * Copyright (C) 2002 USAGI/WIDE Project.
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. Neither the name of the project nor the names of its contributors
     15  *    may be used to endorse or promote products derived from this software
     16  *    without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 /*
     31  * Author:
     32  * 	YOSHIFUJI Hideaki <yoshfuji (at) linux-ipv6.org>
     33  */
     34 
     35 #if HAVE_CONFIG_H
     36 #include "config.h"
     37 #endif
     38 
     39 #if HAVE_SYS_TYPES_H
     40 # include <sys/types.h>
     41 #endif
     42 #if STDC_HEADERS
     43 # include <stdio.h>
     44 # include <stdlib.h>
     45 # include <stddef.h>
     46 # include <ctype.h>
     47 #else
     48 # if HAVE_STDLIB_H
     49 #  include <stdlib.h>
     50 # endif
     51 #endif
     52 #if HAVE_STRING_H
     53 # if !STDC_HEADERS && HAVE_MEMORY_H
     54 #  include <memory.h>
     55 # endif
     56 # include <string.h>
     57 #endif
     58 #if HAVE_STRINGS_H
     59 # include <strings.h>
     60 #endif
     61 #if HAVE_INTTYPES_H
     62 # include <inttypes.h>
     63 #else
     64 # if HAVE_STDINT_H
     65 #  include <stdint.h>
     66 # endif
     67 #endif
     68 #if HAVE_UNISTD_H
     69 # include <unistd.h>
     70 #endif
     71 
     72 #if TIME_WITH_SYS_TIME
     73 # include <sys/time.h>
     74 # include <time.h>
     75 #else
     76 # if HAVE_SYS_TIME_H
     77 #  include <sys/time.h>
     78 # else
     79 #  include <time.h>
     80 # endif
     81 #endif
     82 
     83 #if HAVE_SYS_UIO_H
     84 #include <sys/uio.h>
     85 #endif
     86 
     87 #include <sys/socket.h>
     88 
     89 #if HAVE_NETINET_IN_H
     90 # include <netinet/in.h>
     91 #endif
     92 
     93 #if HAVE_NETINET_ICMP6_H
     94 # include <netinet/icmp6.h>
     95 #endif
     96 #ifndef HAVE_STRUCT_ICMP6_NODEINFO
     97 # include "icmp6_nodeinfo.h"
     98 #endif
     99 
    100 #include <arpa/inet.h>
    101 
    102 #if defined(HAVE_GNUTLS_OPENSSL_H)
    103 # include <gnutls/openssl.h>
    104 #elif defined(HAVE_OPENSSL_MD5_H)
    105 # include <openssl/md5.h>
    106 #endif
    107 
    108 #if HAVE_SYS_UTSNAME_H
    109 # include <sys/utsname.h>
    110 #endif
    111 #if HAVE_NETDB_H
    112 # include <netdb.h>
    113 #endif
    114 #include <errno.h>
    115 
    116 #if HAVE_SYSLOG_H
    117 # include <syslog.h>
    118 #endif
    119 
    120 #include "ninfod.h"
    121 
    122 #ifndef offsetof
    123 # define offsetof(aggregate,member)	((size_t)&((aggregate *)0)->member)
    124 #endif
    125 
    126 /* Hmm,,, */
    127 #ifndef IPV6_JOIN_GROUP
    128 # define IPV6_JOIN_GROUP	IPV6_ADD_MEMBERSHIP
    129 # define IPV6_LEAVE_GROUP	IPV6_DROP_MEMBERSHIP
    130 #endif
    131 
    132 /* ---------- */
    133 /* ID */
    134 static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_name.c,v 1.15 2003-01-11 14:33:28 yoshfuji Exp $";
    135 
    136 /* Variables */
    137 static struct utsname utsname;
    138 static char *uts_nodename = utsname.nodename;
    139 
    140 char nodename[MAX_DNSNAME_SIZE];
    141 static size_t nodenamelen;
    142 
    143 static struct ipv6_mreq nigroup;
    144 
    145 /* ---------- */
    146 /* Functions */
    147 int check_nigroup(const struct in6_addr *addr)
    148 {
    149 	return IN6_IS_ADDR_MULTICAST(&nigroup.ipv6mr_multiaddr) &&
    150 	       IN6_ARE_ADDR_EQUAL(&nigroup.ipv6mr_multiaddr, addr);
    151 }
    152 
    153 static int encode_dnsname(const char *name,
    154 			  char *buf, size_t buflen,
    155 			  int fqdn)
    156 {
    157 	size_t namelen;
    158 	int i;
    159 
    160 	if (buflen < 0)
    161 		return -1;
    162 
    163 	namelen = strlen(name);
    164 	if (namelen == 0)
    165 		return 0;
    166 	if (namelen > 255 || buflen < namelen+1)
    167 		return -1;
    168 
    169 	i = 0;
    170 	while(i <= namelen) {
    171 		const char *e;
    172 		int llen, ii;
    173 
    174 		e = strchr(&name[i], '.');
    175 		if (e == NULL)
    176 			e = name + namelen;
    177 		llen = e - &name[i];
    178 		if (llen == 0) {
    179 			if (*e)
    180 				return -1;
    181 			if (fqdn < 0)
    182 				return -1;
    183 			fqdn = 1;
    184 			break;
    185 		}
    186 		if (llen >= 0x40)
    187 			return -1;
    188 		buf[i] = llen;
    189 		for (ii = 0; ii < llen; ii++) {
    190 			if (!isascii(name[i+ii]))
    191 				return -1;
    192 			if (ii == 0 || ii == llen-1) {
    193 				if (!isalpha(name[i+ii]) && !isdigit(name[i+ii]))
    194 					return -1;
    195 			} else if (!isalnum(name[i+ii]) && name[i+ii] != '-')
    196 				return -1;
    197 			buf[i+ii+1] = isupper(name[i+ii]) ? tolower(name[i+ii]) : name[i+ii];
    198 		}
    199 		i += llen + 1;
    200 	}
    201 	if (buflen < i + 1 + !(fqdn > 0))
    202 		return -1;
    203 	buf[i++] = 0;
    204 	if (!(fqdn > 0))
    205 		buf[i++] = 0;
    206 	return i;
    207 }
    208 
    209 static int compare_dnsname(const char *s, size_t slen,
    210 			   const char *n, size_t nlen)
    211 {
    212 	const char *s0 = s, *n0 = n;
    213 	int done = 0, retcode = 0;
    214 	if (slen < 1 || nlen < 1)
    215 		return -1;	/* invalid length */
    216 	/* simple case */
    217 	if (slen == nlen && memcmp(s, n, slen) == 0)
    218 		return 0;
    219 	if (*(s0 + slen - 1) || *(n0 + nlen - 1))
    220 		return -1;	/* invalid termination */
    221 	while (s < s0 + slen && n < n0 + nlen) {
    222 		if (*s >= 0x40 || *n >= 0x40)
    223 			return -1;	/* DNS compression is not allowed here */
    224 		if (s + *s + 1 > s0 + slen || n + *n + 1 > n0 + nlen)
    225 			return -1;	/* overrun */
    226 		if (*s == '\0') {
    227 			if (s == s0 + slen - 1)
    228 				break;	/* FQDN */
    229 			else if (s + 1 == s0 + slen - 1)
    230 				return retcode;	/* truncated */
    231 			else
    232 				return -1;	/* more than one subject */
    233 		}
    234 		if (!done) {
    235 			if (*n == '\0') {
    236 				if (n == n0 + nlen - 1) {
    237 					done = 1;	/* FQDN */
    238 				} else if (n + 1 == n0 + nlen - 1) {
    239 					retcode = 1;	// trunc
    240 					done = 1;
    241 				} else
    242 					return -1;
    243 			} else {
    244 				if (*s != *n) {
    245 					done = 1;
    246 					retcode = 1;
    247 				} else {
    248 					if (memcmp(s+1, n+1, *s)) {
    249 						done = 1;
    250 						retcode = 1;
    251 					}
    252 				}
    253 			}
    254 		}
    255 		s += *s + 1;
    256 		n += done ? 0 : (*n + 1);
    257 	}
    258 	return retcode;
    259 }
    260 
    261 static int nodeinfo_group(const char *dnsname, int namelen,
    262 			  struct in6_addr *nigroup)
    263 {
    264 	MD5_CTX ctxt;
    265 	unsigned char digest[16];
    266 
    267 	if (!dnsname || !nigroup)
    268 		return -1;
    269 
    270 	MD5_Init(&ctxt);
    271 	MD5_Update(&ctxt, dnsname, *dnsname);
    272 	MD5_Final(digest, &ctxt);
    273 
    274 #ifdef s6_addr32
    275 	nigroup->s6_addr32[0] = htonl(0xff020000);
    276 	nigroup->s6_addr32[1] = 0;
    277 	nigroup->s6_addr32[2] = htonl(0x00000002);
    278 #else
    279 	memset(nigroup, 0, sizeof(*nigroup));
    280 	nigroup->s6_addr[ 0] = 0xff;
    281 	nigroup->s6_addr[ 1] = 0x02;
    282 	nigroup->s6_addr[11] = 0x02;
    283 #endif
    284 	memcpy(&nigroup->s6_addr[12], digest, 4);
    285 
    286 	return 0;
    287 }
    288 
    289 /* ---------- */
    290 void init_nodeinfo_nodename(int forced)
    291 {
    292 	struct utsname newname;
    293 	int len;
    294 	int changed = 0;
    295 
    296 	DEBUG(LOG_DEBUG, "%s()\n", __func__);
    297 
    298 	uname(&newname);
    299 	changed = strcmp(newname.nodename, utsname.nodename);
    300 
    301 	if (!changed && !forced)
    302 		return;
    303 
    304 	memcpy(&utsname, &newname, sizeof(newname));
    305 
    306 	/* leave old group */
    307 	if ((changed || forced) && !IN6_IS_ADDR_UNSPECIFIED(&nigroup.ipv6mr_multiaddr)) {
    308 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &nigroup, sizeof(nigroup)) < 0) {
    309 #if ENABLE_DEBUG
    310 			char niaddrbuf[INET6_ADDRSTRLEN];
    311 			if (inet_ntop(AF_INET6, &nigroup, niaddrbuf, sizeof(niaddrbuf)) == NULL)
    312 				strcpy(niaddrbuf, "???");
    313 #endif
    314 			DEBUG(LOG_WARNING,
    315 			      "%s(): failed to leave group %s.\n",
    316 			      __func__, niaddrbuf);
    317 			memset(&nigroup, 0, sizeof(nigroup));
    318 		}
    319 	}
    320 
    321 	len = encode_dnsname(uts_nodename,
    322 			     nodename,
    323 			     sizeof(nodename),
    324 			     0);
    325 
    326 	/* setup ni reply */
    327 	nodenamelen = len > 0 ? len : 0;
    328 
    329 	/* setup ni group */
    330 	if (changed || forced) {
    331 		if (nodenamelen) {
    332 			memset(&nigroup, 0, sizeof(nigroup));
    333 			nodeinfo_group(nodename, len, &nigroup.ipv6mr_multiaddr);
    334 			nigroup.ipv6mr_interface = 0;
    335 			if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &nigroup, sizeof(nigroup)) < 0) {
    336 #if ENABLE_DEBUG
    337 				char niaddrbuf[INET6_ADDRSTRLEN];
    338 				if (inet_ntop(AF_INET6, &nigroup, niaddrbuf, sizeof(niaddrbuf)) == NULL)
    339 					strcpy(niaddrbuf, "???");
    340 #endif
    341 				DEBUG(LOG_WARNING,
    342 				      "%s(): failed to join group %s.\n",
    343 				      __func__, niaddrbuf);
    344 				memset(&nigroup, 0, sizeof(nigroup));
    345 			}
    346 		} else {
    347 			memset(&nigroup, 0, sizeof(nigroup));
    348 		}
    349 	}
    350 
    351 	return;
    352 }
    353 
    354 /* ---------- */
    355 /* nodename */
    356 int pr_nodeinfo_nodename(CHECKANDFILL_ARGS)
    357 {
    358 	DEBUG(LOG_DEBUG, "%s()\n", __func__);
    359 
    360 	if (subject) {
    361 		if (!nodenamelen ||
    362 		    compare_dnsname(subject, subjlen,
    363 				    nodename,
    364 				    nodenamelen))
    365 			return 1;
    366 		if (subj_if)
    367 			*subj_if = p->pktinfo.ipi6_ifindex;
    368 	}
    369 
    370 	if (reply) {
    371 		uint32_t ttl = 0;
    372 
    373 		p->reply.ni_type = ICMP6_NI_REPLY;
    374 		p->reply.ni_code = ICMP6_NI_SUCCESS;
    375 		p->reply.ni_cksum = 0;
    376 		p->reply.ni_qtype = htons(NI_QTYPE_DNSNAME);
    377 		p->reply.ni_flags = 0;
    378 
    379 		p->replydatalen = nodenamelen ? sizeof(ttl)+nodenamelen : 0;
    380 		p->replydata = nodenamelen ? ni_malloc(p->replydatalen) : NULL;
    381 		if (p->replydata) {
    382 			memcpy(p->replydata, &ttl, sizeof(ttl));
    383 			memcpy(p->replydata + sizeof(ttl), &nodename, nodenamelen);
    384 		}
    385 	}
    386 
    387 	return 0;
    388 }
    389 
    390