blob: 6d7e92bfdc2da550842410dceb37ee335466d47e [file] [log] [blame]
Lorenzo Colitti313379e2013-07-11 01:07:11 +09001/* $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@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 */
134static char *RCSID __attribute__ ((unused)) = "$USAGI: ninfod_name.c,v 1.15 2003-01-11 14:33:28 yoshfuji Exp $";
135
136/* Variables */
137static struct utsname utsname;
138static char *uts_nodename = utsname.nodename;
139
140char nodename[MAX_DNSNAME_SIZE];
141static size_t nodenamelen;
142
143static struct ipv6_mreq nigroup;
144
145/* ---------- */
146/* Functions */
147int 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
153static 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
209static 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
261static 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/* ---------- */
290void 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 */
356int 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