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@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 */
check_nigroup(const struct in6_addr * addr)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
encode_dnsname(const char * name,char * buf,size_t buflen,int fqdn)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
compare_dnsname(const char * s,size_t slen,const char * n,size_t nlen)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
nodeinfo_group(const char * dnsname,int namelen,struct in6_addr * nigroup)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 /* ---------- */
init_nodeinfo_nodename(int forced)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 */
pr_nodeinfo_nodename(CHECKANDFILL_ARGS)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