- Implement RDNSS and DNSSL options (RFC 6106, IPv6 Router Advertisement

Options for DNS Configuration) into rtadvd(8) and rtsold(8).  DNS
  information received by rtsold(8) will go to resolv.conf(5) by
  resolvconf(8) script.  This is based on work by J.R. Oldroyd (kern/156259)
  but revised extensively[1].

- rtadvd(8) now supports "noifprefix" to disable gathering on-link prefixes
  from interfaces when no "addr" is specified[2].  An entry in rtadvd.conf
  with "noifprefix" + no "addr" generates an RA message with no prefix
  information option.

- rtadvd(8) now supports RTM_IFANNOUNCE message to fix crashes when an
  interface is added or removed.

- Correct bogus ND_OPT_ROUTE_INFO value to one in RFC 4191.

Reviewed by:	bz[1]
PR:		kern/156259 [1]
PR:		bin/152458 [2]
This commit is contained in:
Hiroki Sato 2011-06-06 03:06:43 +00:00
parent 77bc49858c
commit db82af41db
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=222732
28 changed files with 2862 additions and 1715 deletions

View File

@ -297,8 +297,9 @@ struct nd_opt_hdr { /* Neighbor discovery option header */
#define ND_OPT_PREFIX_INFORMATION 3
#define ND_OPT_REDIRECTED_HEADER 4
#define ND_OPT_MTU 5
#define ND_OPT_ROUTE_INFO 200 /* draft-ietf-ipngwg-router-preference, not officially assigned yet */
#define ND_OPT_ROUTE_INFO 24 /* RFC 4191 */
#define ND_OPT_RDNSS 25 /* RFC 6016 */
#define ND_OPT_DNSSL 31 /* RFC 6016 */
struct nd_opt_prefix_info { /* prefix information */
u_int8_t nd_opt_pi_type;
@ -338,6 +339,22 @@ struct nd_opt_route_info { /* route info */
/* prefix follows */
} __packed;
struct nd_opt_rdnss { /* RDNSS option (RFC 6106) */
u_int8_t nd_opt_rdnss_type;
u_int8_t nd_opt_rdnss_len;
u_int16_t nd_opt_rdnss_reserved;
u_int32_t nd_opt_rdnss_lifetime;
/* followed by list of recursive DNS servers */
} __packed;
struct nd_opt_dnssl { /* DNSSL option (RFC 6106) */
u_int8_t nd_opt_dnssl_type;
u_int8_t nd_opt_dnssl_len;
u_int16_t nd_opt_dnssl_reserved;
u_int32_t nd_opt_dnssl_lifetime;
/* followed by list of DNS search domains */
} __packed;
/*
* icmp6 namelookup
*/

View File

@ -23,6 +23,6 @@ LDADD= -lutil
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO
WARNS?= 1
WARNS?= 6
.include <bsd.prog.mk>

View File

@ -64,8 +64,6 @@
#define V_TERM "HOST"
#endif
char *RM;
/*
* termcap - routines for dealing with the terminal capability data base
*
@ -83,12 +81,11 @@ char *RM;
static char *tbuf;
static int hopcount; /* detect infinite loops in termcap, init 0 */
static char *remotefile;
extern char *conffile;
static const char *remotefile;
extern const char *conffile;
int tgetent(char *, char *);
int getent(char *, char *, char *);
int getent(char *, char *, const char *);
int tnchktc(void);
int tnamatch(char *);
static char *tskip(char *);
@ -103,22 +100,18 @@ static char *tdecode(char *, char **);
* we just notice escaped newlines.
*/
int
tgetent(bp, name)
char *bp, *name;
tgetent(char *bp, char *name)
{
char *cp;
remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF;
return (getent(bp, name, cp));
return (getent(bp, name, conffile));
}
int
getent(bp, name, cp)
char *bp, *name, *cp;
getent(char *bp, char *name, const char *cfile)
{
int c;
int i = 0, cnt = 0;
char ibuf[BUFSIZ];
char *cp;
int tf;
tbuf = bp;
@ -130,9 +123,9 @@ getent(bp, name, cp)
* use so we don't have to read the file. In this case it
* has to already have the newlines crunched out.
*/
if (cp && *cp) {
tf = open(RM = cp, O_RDONLY);
}
if (cfile && *cfile)
tf = open(cfile, O_RDONLY);
if (tf < 0) {
syslog(LOG_INFO,
"<%s> open: %s", __func__, strerror(errno));
@ -184,7 +177,7 @@ getent(bp, name, cp)
* Note that this works because of the left to right scan.
*/
int
tnchktc()
tnchktc(void)
{
char *p, *q;
char tcname[16]; /* name of similar terminal */
@ -233,8 +226,7 @@ tnchktc()
* name (before the first field) stops us.
*/
int
tnamatch(np)
char *np;
tnamatch(char *np)
{
char *Np, *Bp;
@ -260,8 +252,7 @@ tnamatch(np)
* into the termcap file in octal.
*/
static char *
tskip(bp)
char *bp;
tskip(char *bp)
{
int dquote;
@ -305,8 +296,7 @@ breakbreak:
* Note that we handle octal numbers beginning with 0.
*/
int64_t
tgetnum(id)
char *id;
tgetnum(char *id)
{
int64_t i;
int base;
@ -341,8 +331,7 @@ tgetnum(id)
* not given.
*/
int
tgetflag(id)
char *id;
tgetflag(char *id)
{
char *bp = tbuf;
@ -369,8 +358,7 @@ tgetflag(id)
* No checking on area overflow.
*/
char *
tgetstr(id, area)
char *id, **area;
tgetstr(char *id, char **area)
{
char *bp = tbuf;
@ -395,13 +383,11 @@ tgetstr(id, area)
* string capability escapes.
*/
static char *
tdecode(str, area)
char *str;
char **area;
tdecode(char *str, char **area)
{
char *cp;
int c;
char *dp;
const char *dp;
int i;
char term;

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 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:
@ -16,7 +16,7 @@
* 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
@ -30,7 +30,8 @@
* SUCH DAMAGE.
*/
extern void getconfig(char *);
extern int getconfig(int);
extern int rmconfig(int);
extern void delete_prefix(struct prefix *);
extern void invalidate_prefix(struct prefix *);
extern void update_prefix(struct prefix *);
@ -45,3 +46,5 @@ extern void get_prefix(struct rainfo *);
*/
#define MAXPREFIX 100
#define MAXROUTE 100
#define MAXRDNSSENT 100
#define MAXDNSSLENT 100

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 2000 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:
@ -16,7 +16,7 @@
* 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
@ -45,6 +45,7 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
@ -63,8 +64,9 @@ extern struct rainfo *ralist;
static char *ether_str(struct sockaddr_dl *);
static void if_dump(void);
static size_t dname_labeldec(char *, size_t, const char *);
static char *rtpref_str[] = {
static const char *rtpref_str[] = {
"medium", /* 00 */
"high", /* 01 */
"rsv", /* 10 */
@ -72,8 +74,7 @@ static char *rtpref_str[] = {
};
static char *
ether_str(sdl)
struct sockaddr_dl *sdl;
ether_str(struct sockaddr_dl *sdl)
{
static char hbuf[32];
u_char *cp;
@ -85,84 +86,86 @@ ether_str(sdl)
} else
snprintf(hbuf, sizeof(hbuf), "NONE");
return(hbuf);
return (hbuf);
}
static void
if_dump()
if_dump(void)
{
struct rainfo *rai;
struct prefix *pfx;
#ifdef ROUTEINFO
struct rtinfo *rti;
#endif
struct rdnss *rdn;
struct dnssl *dns;
char prefixbuf[INET6_ADDRSTRLEN];
int first;
struct timeval now;
gettimeofday(&now, NULL); /* XXX: unused in most cases */
for (rai = ralist; rai; rai = rai->next) {
fprintf(fp, "%s:\n", rai->ifname);
TAILQ_FOREACH(rai, &railist, rai_next) {
fprintf(fp, "%s:\n", rai->rai_ifname);
fprintf(fp, " Status: %s\n",
(iflist[rai->ifindex]->ifm_flags & IFF_UP) ? "UP" :
"DOWN");
(iflist[rai->rai_ifindex]->ifm_flags & IFF_UP) ? "UP" :
"DOWN");
/* control information */
if (rai->lastsent.tv_sec) {
if (rai->rai_lastsent.tv_sec) {
/* note that ctime() appends CR by itself */
fprintf(fp, " Last RA sent: %s",
ctime((time_t *)&rai->lastsent.tv_sec));
ctime((time_t *)&rai->rai_lastsent.tv_sec));
}
if (rai->timer) {
if (rai->rai_timer)
fprintf(fp, " Next RA will be sent: %s",
ctime((time_t *)&rai->timer->tm.tv_sec));
}
ctime((time_t *)&rai->rai_timer->rat_tm.tv_sec));
else
fprintf(fp, " RA timer is stopped");
fprintf(fp, " waits: %d, initcount: %d\n",
rai->waiting, rai->initcounter);
rai->rai_waiting, rai->rai_initcounter);
/* statistics */
fprintf(fp, " statistics: RA(out/in/inconsistent): "
"%llu/%llu/%llu, ",
(unsigned long long)rai->raoutput,
(unsigned long long)rai->rainput,
(unsigned long long)rai->rainconsistent);
(unsigned long long)rai->rai_raoutput,
(unsigned long long)rai->rai_rainput,
(unsigned long long)rai->rai_rainconsistent);
fprintf(fp, "RS(input): %llu\n",
(unsigned long long)rai->rsinput);
(unsigned long long)rai->rai_rsinput);
/* interface information */
if (rai->advlinkopt)
if (rai->rai_advlinkopt)
fprintf(fp, " Link-layer address: %s\n",
ether_str(rai->sdl));
fprintf(fp, " MTU: %d\n", rai->phymtu);
ether_str(rai->rai_sdl));
fprintf(fp, " MTU: %d\n", rai->rai_phymtu);
/* Router configuration variables */
fprintf(fp, " DefaultLifetime: %d, MaxAdvInterval: %d, "
"MinAdvInterval: %d\n", rai->lifetime, rai->maxinterval,
rai->mininterval);
fprintf(fp, " Flags: %s%s%s, ",
rai->managedflg ? "M" : "", rai->otherflg ? "O" : "", "");
"MinAdvInterval: %d\n", rai->rai_lifetime,
rai->rai_maxinterval, rai->rai_mininterval);
fprintf(fp, " Flags: ");
if (rai->rai_managedflg || rai->rai_otherflg) {
fprintf(fp, "%s", rai->rai_managedflg ? "M" : "");
fprintf(fp, "%s", rai->rai_otherflg ? "O" : "");
} else
fprintf(fp, "<none>");
fprintf(fp, ", ");
fprintf(fp, "Preference: %s, ",
rtpref_str[(rai->rtpref >> 3) & 0xff]);
fprintf(fp, "MTU: %d\n", rai->linkmtu);
rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
fprintf(fp, "MTU: %d\n", rai->rai_linkmtu);
fprintf(fp, " ReachableTime: %d, RetransTimer: %d, "
"CurHopLimit: %d\n", rai->reachabletime,
rai->retranstimer, rai->hoplimit);
if (rai->clockskew)
"CurHopLimit: %d\n", rai->rai_reachabletime,
rai->rai_retranstimer, rai->rai_hoplimit);
if (rai->rai_clockskew)
fprintf(fp, " Clock skew: %ldsec\n",
rai->clockskew);
for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix;
pfx = pfx->next) {
if (first) {
rai->rai_clockskew);
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
if (pfx == TAILQ_FIRST(&rai->rai_prefix))
fprintf(fp, " Prefixes:\n");
first = 0;
}
fprintf(fp, " %s/%d(",
inet_ntop(AF_INET6, &pfx->prefix, prefixbuf,
sizeof(prefixbuf)), pfx->prefixlen);
switch (pfx->origin) {
inet_ntop(AF_INET6, &pfx->pfx_prefix, prefixbuf,
sizeof(prefixbuf)), pfx->pfx_prefixlen);
switch (pfx->pfx_origin) {
case PREFIX_FROM_KERNEL:
fprintf(fp, "KERNEL, ");
break;
@ -173,36 +176,42 @@ if_dump()
fprintf(fp, "DYNAMIC, ");
break;
}
if (pfx->validlifetime == ND6_INFINITE_LIFETIME)
if (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME)
fprintf(fp, "vltime: infinity");
else
fprintf(fp, "vltime: %ld",
(long)pfx->validlifetime);
if (pfx->vltimeexpire != 0)
fprintf(fp, "(decr,expire %ld), ", (long)
pfx->vltimeexpire > now.tv_sec ?
pfx->vltimeexpire - now.tv_sec : 0);
(long)pfx->pfx_validlifetime);
if (pfx->pfx_vltimeexpire != 0)
fprintf(fp, "(decr,expire %ld), ",
(long)pfx->pfx_vltimeexpire > now.tv_sec ?
(long)pfx->pfx_vltimeexpire - now.tv_sec :
0);
else
fprintf(fp, ", ");
if (pfx->preflifetime == ND6_INFINITE_LIFETIME)
if (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME)
fprintf(fp, "pltime: infinity");
else
fprintf(fp, "pltime: %ld",
(long)pfx->preflifetime);
if (pfx->pltimeexpire != 0)
fprintf(fp, "(decr,expire %ld), ", (long)
pfx->pltimeexpire > now.tv_sec ?
pfx->pltimeexpire - now.tv_sec : 0);
(long)pfx->pfx_preflifetime);
if (pfx->pfx_pltimeexpire != 0)
fprintf(fp, "(decr,expire %ld), ",
(long)pfx->pfx_pltimeexpire > now.tv_sec ?
(long)pfx->pfx_pltimeexpire - now.tv_sec :
0);
else
fprintf(fp, ", ");
fprintf(fp, "flags: %s%s%s",
pfx->onlinkflg ? "L" : "",
pfx->autoconfflg ? "A" : "",
"");
if (pfx->timer) {
fprintf(fp, "flags: ");
if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
fprintf(fp, "%s",
pfx->pfx_onlinkflg ? "L" : "");
fprintf(fp, "%s",
pfx->pfx_autoconfflg ? "A" : "");
} else
fprintf(fp, "<none>");
if (pfx->pfx_timer) {
struct timeval *rest;
rest = rtadvd_timer_rest(pfx->timer);
rest = rtadvd_timer_rest(pfx->pfx_timer);
if (rest) { /* XXX: what if not? */
fprintf(fp, ", expire in: %ld",
(long)rest->tv_sec);
@ -211,31 +220,64 @@ if_dump()
fprintf(fp, ")\n");
}
#ifdef ROUTEINFO
for (first = 1, rti = rai->route.next; rti != &rai->route;
rti = rti->next) {
if (first) {
TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
if (rti == TAILQ_FIRST(&rai->rai_route))
fprintf(fp, " Route Information:\n");
first = 0;
}
fprintf(fp, " %s/%d (",
inet_ntop(AF_INET6, &rti->prefix,
prefixbuf, sizeof(prefixbuf)),
rti->prefixlen);
inet_ntop(AF_INET6, &rti->rti_prefix,
prefixbuf, sizeof(prefixbuf)),
rti->rti_prefixlen);
fprintf(fp, "preference: %s, ",
rtpref_str[0xff & (rti->rtpref >> 3)]);
if (rti->ltime == ND6_INFINITE_LIFETIME)
rtpref_str[0xff & (rti->rti_rtpref >> 3)]);
if (rti->rti_ltime == ND6_INFINITE_LIFETIME)
fprintf(fp, "lifetime: infinity");
else
fprintf(fp, "lifetime: %ld", (long)rti->ltime);
fprintf(fp, "lifetime: %ld",
(long)rti->rti_ltime);
fprintf(fp, ")\n");
}
#endif
TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
struct rdnss_addr *rdna;
if (rdn == TAILQ_FIRST(&rai->rai_rdnss))
fprintf(fp, " Recursive DNS servers:\n"
" Lifetime\tServers\n");
fprintf(fp, " %8u\t", rdn->rd_ltime);
TAILQ_FOREACH(rdna, &rdn->rd_list, ra_next) {
inet_ntop(AF_INET6, &rdna->ra_dns,
prefixbuf, sizeof(prefixbuf));
if (rdna != TAILQ_FIRST(&rdn->rd_list))
fprintf(fp, " \t");
fprintf(fp, "%s\n", prefixbuf);
}
fprintf(fp, "\n");
}
TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
struct dnssl_addr *dnsa;
char buf[NI_MAXHOST];
if (dns == TAILQ_FIRST(&rai->rai_dnssl))
fprintf(fp, " DNS search list:\n"
" Lifetime\tDomains\n");
fprintf(fp, " %8u\t", dns->dn_ltime);
TAILQ_FOREACH(dnsa, &dns->dn_list, da_next) {
dname_labeldec(buf, sizeof(buf), dnsa->da_dom);
if (dnsa != TAILQ_FIRST(&dns->dn_list))
fprintf(fp, " \t");
fprintf(fp, "%s(%d)\n", buf, dnsa->da_len);
}
fprintf(fp, "\n");
}
}
}
void
rtadvd_dump_file(dumpfile)
char *dumpfile;
rtadvd_dump_file(const char *dumpfile)
{
syslog(LOG_DEBUG, "<%s> dump current status to %s", __func__,
dumpfile);
@ -250,3 +292,30 @@ rtadvd_dump_file(dumpfile)
fclose(fp);
}
/* Decode domain name label encoding in RFC 1035 Section 3.1 */
static size_t
dname_labeldec(char *dst, size_t dlen, const char *src)
{
size_t len;
const char *src_origin;
const char *src_last;
const char *dst_origin;
src_origin = src;
src_last = strchr(src, '\0');
dst_origin = dst;
memset(dst, '\0', dlen);
while (src && (len = (uint8_t)(*src++) & 0x3f) &&
(src + len) <= src_last) {
if (dst != dst_origin)
*dst++ = '.';
syslog(LOG_DEBUG, "<%s> labellen = %d", __func__, len);
memcpy(dst, src, len);
src += len;
dst += len;
}
*dst = '\0';
return (src - src_origin);
}

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 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:
@ -16,7 +16,7 @@
* 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
@ -30,4 +30,4 @@
* SUCH DAMAGE.
*/
extern void rtadvd_dump_file(char *);
extern void rtadvd_dump_file(const char *);

View File

@ -4,7 +4,7 @@
/*
* 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:
@ -16,7 +16,7 @@
* 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
@ -44,34 +44,35 @@
#include <netinet/icmp6.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "rtadvd.h"
#include "if.h"
#define ROUNDUP(a, size) \
#define ROUNDUP(a, size) \
(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
sizeof(u_long)) :\
sizeof(u_long)))
#define NEXT_SA(ap) \
(ap) = (struct sockaddr *)((caddr_t)(ap) + \
((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(u_long)) : \
sizeof(u_long)))
struct if_msghdr **iflist;
int iflist_init_ok;
size_t ifblock_size;
char *ifblock;
static void get_iflist(char **buf, size_t *size);
static void parse_iflist(struct if_msghdr ***ifmlist_p, char *buf,
size_t bufsize);
static void get_iflist(char **buf, size_t *size);
static void parse_iflist(struct if_msghdr ***ifmlist_p,
char *buf, size_t bufsize);
static void
get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
{
int i;
for (i = 0; i < RTAX_MAX; i++) {
if (addrs & (1 << i)) {
rti_info[i] = sa;
@ -93,12 +94,12 @@ if_nametosdl(char *name)
struct sockaddr_dl *sdl = NULL, *ret_sdl;
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
return(NULL);
return (NULL);
if ((buf = malloc(len)) == NULL)
return(NULL);
return (NULL);
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
free(buf);
return(NULL);
return (NULL);
}
lim = buf + len;
@ -124,7 +125,7 @@ if_nametosdl(char *name)
if (next == lim) {
/* search failed */
free(buf);
return(NULL);
return (NULL);
}
if ((ret_sdl = malloc(sdl->sdl_len)) == NULL)
@ -133,7 +134,7 @@ if_nametosdl(char *name)
end:
free(buf);
return(ret_sdl);
return (ret_sdl);
}
int
@ -144,7 +145,7 @@ if_getmtu(char *name)
u_long mtu = 0;
if (getifaddrs(&ifap) < 0)
return(0);
return (0);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (strcmp(ifa->ifa_name, name) == 0) {
ifd = ifa->ifa_data;
@ -161,14 +162,14 @@ if_getmtu(char *name)
int s;
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
return(0);
return (0);
ifr.ifr_addr.sa_family = AF_INET6;
strncpy(ifr.ifr_name, name,
sizeof(ifr.ifr_name));
if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) {
close(s);
return(0);
return (0);
}
close(s);
@ -176,7 +177,7 @@ if_getmtu(char *name)
}
#endif
return(mtu);
return (mtu);
}
/* give interface index and its old flags, then new flags returned */
@ -188,14 +189,14 @@ if_getflags(int ifindex, int oifflags)
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "<%s> socket: %s", __func__,
strerror(errno));
strerror(errno));
return (oifflags & ~IFF_UP);
}
if_indextoname(ifindex, ifr.ifr_name);
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
syslog(LOG_ERR, "<%s> ioctl:SIOCGIFFLAGS: failed for %s",
__func__, ifr.ifr_name);
__func__, ifr.ifr_name);
close(s);
return (oifflags & ~IFF_UP);
}
@ -209,9 +210,9 @@ lladdropt_length(struct sockaddr_dl *sdl)
{
switch (sdl->sdl_type) {
case IFT_ETHER:
return(ROUNDUP8(ETHER_ADDR_LEN + 2));
return (ROUNDUP8(ETHER_ADDR_LEN + 2));
default:
return(0);
return (0);
}
}
@ -238,16 +239,15 @@ lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
}
int
rtbuf_len()
rtbuf_len(void)
{
size_t len;
int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
return(-1);
return (-1);
return(len);
return (len);
}
#define FILTER_MATCH(type, filter) ((0x1 << type) & filter)
@ -267,14 +267,21 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
/* just for safety */
if (!rtm->rtm_msglen) {
syslog(LOG_WARNING, "<%s> rtm_msglen is 0 "
"(buf=%p lim=%p rtm=%p)", __func__,
buf, lim, rtm);
"(buf=%p lim=%p rtm=%p)", __func__,
buf, lim, rtm);
break;
}
if (FILTER_MATCH(rtm->rtm_type, filter) == 0) {
if (((struct rt_msghdr *)buf)->rtm_version != RTM_VERSION) {
syslog(LOG_WARNING,
"<%s> routing message version mismatch "
"(buf=%p lim=%p rtm=%p)", __func__,
buf, lim, rtm);
continue;
}
if (FILTER_MATCH(rtm->rtm_type, filter) == 0)
continue;
switch (rtm->rtm_type) {
case RTM_GET:
case RTM_ADD:
@ -328,6 +335,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
return (char *)rtm;
/* NOTREACHED */
case RTM_IFINFO:
case RTM_IFANNOUNCE:
/* found */
*lenp = rtm->rtm_msglen;
return (char *)rtm;
@ -335,7 +343,7 @@ get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
}
}
return (char *)rtm;
return ((char *)rtm);
}
#undef FILTER_MATCH
@ -348,7 +356,7 @@ get_addr(char *buf)
sa = (struct sockaddr *)(rtm + 1);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
return(&SIN6(rti_info[RTAX_DST])->sin6_addr);
return (&SIN6(rti_info[RTAX_DST])->sin6_addr);
}
int
@ -360,7 +368,7 @@ get_rtm_ifindex(char *buf)
sa = (struct sockaddr *)(rtm + 1);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
return (((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
}
int
@ -393,7 +401,7 @@ get_prefixlen(char *buf)
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
struct sockaddr *sa, *rti_info[RTAX_MAX];
u_char *p, *lim;
sa = (struct sockaddr *)(rtm + 1);
get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
sa = rti_info[RTAX_NETMASK];
@ -437,11 +445,11 @@ prefixlen(u_char *p, u_char *lim)
case 0x00:
break;
default:
return(-1);
return (-1);
}
}
return(masklen);
return (masklen);
}
int
@ -449,7 +457,7 @@ rtmsg_type(char *buf)
{
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
return(rtm->rtm_type);
return (rtm->rtm_type);
}
int
@ -457,7 +465,7 @@ rtmsg_len(char *buf)
{
struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
return(rtm->rtm_msglen);
return (rtm->rtm_msglen);
}
int
@ -465,7 +473,7 @@ ifmsg_len(char *buf)
{
struct if_msghdr *ifm = (struct if_msghdr *)buf;
return(ifm->ifm_msglen);
return (ifm->ifm_msglen);
}
/*
@ -486,7 +494,7 @@ get_iflist(char **buf, size_t *size)
if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) {
syslog(LOG_ERR, "<%s> sysctl: iflist size get failed",
__func__);
__func__);
exit(1);
}
if ((*buf = malloc(*size)) == NULL) {
@ -495,7 +503,7 @@ get_iflist(char **buf, size_t *size)
}
if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) {
syslog(LOG_ERR, "<%s> sysctl: iflist get failed",
__func__);
__func__);
exit(1);
}
return;
@ -529,8 +537,8 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
if (ifm->ifm_msglen == 0) {
syslog(LOG_WARNING, "<%s> ifm_msglen is 0 "
"(buf=%p lim=%p ifm=%p)", __func__,
buf, lim, ifm);
"(buf=%p lim=%p ifm=%p)", __func__,
buf, lim, ifm);
return;
}
@ -538,10 +546,10 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
(*ifmlist_p)[ifm->ifm_index] = ifm;
} else {
syslog(LOG_ERR, "out of sync parsing NET_RT_IFLIST\n"
"expected %d, got %d\n msglen = %d\n"
"buf:%p, ifm:%p, lim:%p\n",
RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
buf, ifm, lim);
"expected %d, got %d\n msglen = %d\n"
"buf:%p, ifm:%p, lim:%p\n",
RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
buf, ifm, lim);
exit (1);
}
for (ifam = (struct ifa_msghdr *)
@ -552,8 +560,8 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
/* just for safety */
if (!ifam->ifam_msglen) {
syslog(LOG_WARNING, "<%s> ifa_msglen is 0 "
"(buf=%p lim=%p ifam=%p)", __func__,
buf, lim, ifam);
"(buf=%p lim=%p ifam=%p)", __func__,
buf, lim, ifam);
return;
}
if (ifam->ifam_type != RTM_NEWADDR)
@ -564,8 +572,11 @@ parse_iflist(struct if_msghdr ***ifmlist_p, char *buf, size_t bufsize)
}
void
init_iflist()
init_iflist(void)
{
syslog(LOG_DEBUG,
"<%s> generate iflist.", __func__);
if (ifblock) {
free(ifblock);
ifblock_size = 0;

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 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:
@ -16,7 +16,7 @@
* 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

View File

@ -1,4 +1,7 @@
/* $KAME: pathnames.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */
/* $FreeBSD$ */
#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
#define _PATH_RTADVDDUMP "/var/run/rtadvd.dump"
#define _PATH_RTADVDPID "/var/run/rtadvd.pid"

View File

@ -45,6 +45,7 @@
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
@ -74,7 +75,7 @@ static int s = -1;
/*
* Check validity of a Prefix Control Operation(PCO).
* Return 0 on success, 1 on failure.
* return 0 on success, 1 on failure.
*/
static int
rr_pco_check(int len, struct rr_pco_match *rpm)
@ -86,8 +87,8 @@ rr_pco_check(int len, struct rr_pco_match *rpm)
if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */
(rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */
syslog(LOG_WARNING, "<%s> rpm_len %d is not 4N * 3",
__func__, rpm->rpm_len);
return 1;
__func__, rpm->rpm_len);
return (1);
}
/* rpm->rpm_code must be valid value */
switch (rpm->rpm_code) {
@ -97,14 +98,14 @@ rr_pco_check(int len, struct rr_pco_match *rpm)
break;
default:
syslog(LOG_WARNING, "<%s> unknown rpm_code %d", __func__,
rpm->rpm_code);
return 1;
rpm->rpm_code);
return (1);
}
/* rpm->rpm_matchlen must be 0 to 128 inclusive */
if (rpm->rpm_matchlen > 128) {
syslog(LOG_WARNING, "<%s> rpm_matchlen %d is over 128",
__func__, rpm->rpm_matchlen);
return 1;
__func__, rpm->rpm_matchlen);
return (1);
}
/*
@ -126,23 +127,22 @@ rr_pco_check(int len, struct rr_pco_match *rpm)
*/
if (checklen > 128) {
syslog(LOG_WARNING, "<%s> sum of rpu_uselen %d and"
" rpu_keeplen %d is %d(over 128)",
__func__, rpu->rpu_uselen,
rpu->rpu_keeplen,
rpu->rpu_uselen + rpu->rpu_keeplen);
return 1;
" rpu_keeplen %d is %d(over 128)",
__func__, rpu->rpu_uselen, rpu->rpu_keeplen,
rpu->rpu_uselen + rpu->rpu_keeplen);
return (1);
}
}
return 0;
return (0);
}
static void
do_use_prefix(int len, struct rr_pco_match *rpm,
struct in6_rrenumreq *irr, int ifindex)
struct in6_rrenumreq *irr, int ifindex)
{
struct rr_pco_use *rpu, *rpulim;
struct rainfo *rai;
struct prefix *pp;
struct prefix *pfx;
rpu = (struct rr_pco_use *)(rpm + 1);
rpulim = (struct rr_pco_use *)((char *)rpm + len);
@ -164,7 +164,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
errno != EADDRNOTAVAIL)
syslog(LOG_ERR, "<%s> ioctl: %s", __func__,
strerror(errno));
strerror(errno));
return;
}
@ -176,19 +176,23 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
irr->irr_u_uselen = rpu->rpu_uselen;
irr->irr_u_keeplen = rpu->rpu_keeplen;
irr->irr_raf_mask_onlink =
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
irr->irr_raf_mask_auto =
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
!!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
irr->irr_vltime = ntohl(rpu->rpu_vltime);
irr->irr_pltime = ntohl(rpu->rpu_pltime);
irr->irr_raf_onlink =
(rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 0 : 1;
(rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ?
0 : 1;
irr->irr_raf_auto =
(rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 0 : 1;
(rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ?
0 : 1;
irr->irr_rrf_decrvalid =
(rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 0 : 1;
(rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ?
0 : 1;
irr->irr_rrf_decrprefd =
(rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 0 : 1;
(rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ?
0 : 1;
irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix);
irr->irr_useprefix.sin6_family = AF_INET6;
irr->irr_useprefix.sin6_addr = rpu->rpu_prefix;
@ -196,7 +200,7 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
errno != EADDRNOTAVAIL)
syslog(LOG_ERR, "<%s> ioctl: %s", __func__,
strerror(errno));
strerror(errno));
/* very adhoc: should be rewritten */
if (rpm->rpm_code == RPM_PCO_CHANGE &&
@ -206,28 +210,31 @@ do_use_prefix(int len, struct rr_pco_match *rpm,
if ((rai = if_indextorainfo(ifindex)) == NULL)
continue; /* non-advertising IF */
for (pp = rai->prefix.next; pp != &rai->prefix;
pp = pp->next) {
TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
struct timeval now;
if (prefix_match(&pp->prefix, pp->prefixlen,
&rpm->rpm_prefix,
rpm->rpm_matchlen)) {
if (prefix_match(&pfx->pfx_prefix,
pfx->pfx_prefixlen, &rpm->rpm_prefix,
rpm->rpm_matchlen)) {
/* change parameters */
pp->validlifetime = ntohl(rpu->rpu_vltime);
pp->preflifetime = ntohl(rpu->rpu_pltime);
pfx->pfx_validlifetime =
ntohl(rpu->rpu_vltime);
pfx->pfx_preflifetime =
ntohl(rpu->rpu_pltime);
if (irr->irr_rrf_decrvalid) {
gettimeofday(&now, 0);
pp->vltimeexpire =
now.tv_sec + pp->validlifetime;
pfx->pfx_vltimeexpire =
now.tv_sec +
pfx->pfx_validlifetime;
} else
pp->vltimeexpire = 0;
pfx->pfx_vltimeexpire = 0;
if (irr->irr_rrf_decrprefd) {
gettimeofday(&now, 0);
pp->pltimeexpire =
now.tv_sec + pp->preflifetime;
pfx->pfx_pltimeexpire =
now.tv_sec +
pfx->pfx_preflifetime;
} else
pp->pltimeexpire = 0;
pfx->pfx_pltimeexpire = 0;
}
}
}
@ -245,11 +252,11 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
struct in6_rrenumreq irr;
if ((rr_pco_check(len, rpm) != 0))
return 1;
return (1);
if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
syslog(LOG_ERR, "<%s> socket: %s", __func__,
strerror(errno));
strerror(errno));
exit(1);
}
@ -264,8 +271,8 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
while (if_indextoname(++ifindex, irr.irr_name)) {
/*
* if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off,
* the interface is not applied
* if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and
* IFF_UP is off, the interface is not applied
*/
if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 &&
(iflist[ifindex]->ifm_flags & IFF_UP) == 0)
@ -274,13 +281,13 @@ do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
do_use_prefix(len, rpm, &irr, ifindex);
}
if (errno == ENXIO)
return 0;
return (0);
else if (errno) {
syslog(LOG_ERR, "<%s> if_indextoname: %s", __func__,
strerror(errno));
return 1;
strerror(errno));
return (1);
}
return 0;
return (0);
}
/*
@ -305,11 +312,11 @@ do_rr(int len, struct icmp6_router_renum *rr)
int rpmlen;
rpm = (struct rr_pco_match *)cp;
if (len < sizeof(struct rr_pco_match)) {
if ((size_t)len < sizeof(struct rr_pco_match)) {
tooshort:
syslog(LOG_ERR, "<%s> pkt too short. left len = %d. "
"gabage at end of pkt?", __func__, len);
return 1;
"gabage at end of pkt?", __func__, len);
return (1);
}
rpmlen = rpm->rpm_len << 3;
if (len < rpmlen)
@ -325,7 +332,7 @@ do_rr(int len, struct icmp6_router_renum *rr)
len -= rpmlen;
}
return 0;
return (0);
}
/*
@ -334,46 +341,45 @@ do_rr(int len, struct icmp6_router_renum *rr)
*/
static int
rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from,
struct in6_addr *dst)
struct in6_addr *dst)
{
u_char ntopbuf[INET6_ADDRSTRLEN];
/* omit rr minimal length check. hope kernel have done it. */
/* rr_command length check */
if (len < (sizeof(struct icmp6_router_renum) +
sizeof(struct rr_pco_match))) {
if ((size_t)len < (sizeof(struct icmp6_router_renum) +
sizeof(struct rr_pco_match))) {
syslog(LOG_ERR, "<%s> rr_command len %d is too short",
__func__, len);
return 1;
__func__, len);
return (1);
}
/* destination check. only for multicast. omit unicast check. */
if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) &&
!IN6_IS_ADDR_MC_SITELOCAL(dst)) {
syslog(LOG_ERR, "<%s> dst mcast addr %s is illegal",
__func__,
inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN));
return 1;
__func__,
inet_ntop(AF_INET6, dst, ntopbuf, sizeof(ntopbuf)));
return (1);
}
/* seqnum and segnum check */
if (rro.rro_seqnum > rr->rr_seqnum) {
syslog(LOG_WARNING,
"<%s> rcvd old seqnum %d from %s",
__func__, (u_int32_t)ntohl(rr->rr_seqnum),
inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN));
return 1;
"<%s> rcvd old seqnum %d from %s",
__func__, (u_int32_t)ntohl(rr->rr_seqnum),
inet_ntop(AF_INET6, from, ntopbuf, sizeof(ntopbuf)));
return (1);
}
if (rro.rro_seqnum == rr->rr_seqnum &&
(rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 &&
RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) {
if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0)
syslog(LOG_WARNING,
"<%s> rcvd duped segnum %d from %s",
__func__, rr->rr_segnum,
inet_ntop(AF_INET6, from, ntopbuf,
INET6_ADDRSTRLEN));
return 0;
"<%s> rcvd duped segnum %d from %s",
__func__, rr->rr_segnum, inet_ntop(AF_INET6, from,
ntopbuf, sizeof(ntopbuf)));
return (0);
}
/* update seqnum */
@ -382,16 +388,16 @@ rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from,
/* init rro_segnum_bits */
memset(rro.rro_segnum_bits, 0,
sizeof(rro.rro_segnum_bits));
sizeof(rro.rro_segnum_bits));
}
rro.rro_seqnum = rr->rr_seqnum;
return 0;
return (0);
}
static void
rr_command_input(int len, struct icmp6_router_renum *rr,
struct in6_addr *from, struct in6_addr *dst)
struct in6_addr *from, struct in6_addr *dst)
{
/* rr_command validity check */
if (rr_command_check(len, rr, from, dst))
@ -401,9 +407,8 @@ rr_command_input(int len, struct icmp6_router_renum *rr,
return;
/* do router renumbering */
if (do_rr(len, rr)) {
if (do_rr(len, rr))
goto failed;
}
/* update segnum */
RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum);
@ -417,27 +422,26 @@ rr_command_input(int len, struct icmp6_router_renum *rr,
void
rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
struct sockaddr_in6 *from, struct in6_addr *dst)
struct sockaddr_in6 *from, struct in6_addr *dst)
{
u_char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
syslog(LOG_DEBUG,
"<%s> RR received from %s to %s on %s",
__func__,
inet_ntop(AF_INET6, &from->sin6_addr,
ntopbuf[0], INET6_ADDRSTRLEN),
inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
"<%s> RR received from %s to %s on %s",
__func__,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0] ,sizeof(ntopbuf[0])),
inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
/* packet validation based on Section 4.1 of RFC2894 */
if (len < sizeof(struct icmp6_router_renum)) {
if ((size_t)len < sizeof(struct icmp6_router_renum)) {
syslog(LOG_NOTICE,
"<%s>: RR short message (size %d) from %s to %s on %s",
__func__, len,
inet_ntop(AF_INET6, &from->sin6_addr,
ntopbuf[0], INET6_ADDRSTRLEN),
inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
"<%s>: RR short message (size %d) from %s to %s on %s",
__func__, len,
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[0],
sizeof(ntopbuf[0])),
inet_ntop(AF_INET6, &dst, ntopbuf[1], sizeof(ntopbuf[1])),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
@ -449,16 +453,16 @@ rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
* We rely on the kernel input routine for unicast addresses, and thus
* check multicast destinations only.
*/
if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) &&
!IN6_ARE_ADDR_EQUAL(&in6a_site_allrouters, &pi->ipi6_addr)) {
if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) && !IN6_ARE_ADDR_EQUAL(
&sin6_sitelocal_allrouters.sin6_addr, &pi->ipi6_addr)) {
syslog(LOG_NOTICE,
"<%s>: RR message with invalid destination (%s) "
"from %s on %s",
__func__,
inet_ntop(AF_INET6, &dst, ntopbuf[0], INET6_ADDRSTRLEN),
inet_ntop(AF_INET6, &from->sin6_addr,
ntopbuf[1], INET6_ADDRSTRLEN),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
"<%s>: RR message with invalid destination (%s) "
"from %s on %s",
__func__,
inet_ntop(AF_INET6, &dst, ntopbuf[0], sizeof(ntopbuf[0])),
inet_ntop(AF_INET6, &from->sin6_addr, ntopbuf[1],
sizeof(ntopbuf[1])),
if_indextoname(pi->ipi6_ifindex, ifnamebuf));
return;
}
@ -477,7 +481,7 @@ rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
break;
default:
syslog(LOG_ERR, "<%s> received unknown code %d",
__func__, rr->rr_code);
__func__, rr->rr_code);
break;
}

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 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:
@ -16,7 +16,7 @@
* 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

View File

@ -37,9 +37,10 @@
.Nd router advertisement daemon
.Sh SYNOPSIS
.Nm
.Op Fl dDfMRs
.Op Fl dDfRs
.Op Fl c Ar configfile
.Op Fl F Ar dumpfile
.Op Fl M Ar ifname
.Op Fl p Ar pidfile
.Ar interface ...
.Sh DESCRIPTION
@ -103,7 +104,7 @@ will not watch the routing table and the whole functionality described
above will be suppressed.
.Pp
Basically, hosts MUST NOT send Router Advertisement messages at any
time (RFC 2461, Section 6.2.3).
time (RFC 4861, Section 6.2.3).
However, it would sometimes be useful to allow hosts to advertise some
parameters such as prefix information and link MTU.
Thus,
@ -176,7 +177,7 @@ In this case,
.Nm
will transmit router advertisement with router lifetime 0
to all the interfaces
.Pq in accordance with RFC2461 6.2.5 .
.Pq in accordance with RFC 4861 6.2.5 .
.Sh FILES
.Bl -tag -width Pa -compact
.It Pa /etc/rtadvd.conf
@ -193,6 +194,34 @@ dumps its internal state.
.Sh SEE ALSO
.Xr rtadvd.conf 5 ,
.Xr rtsol 8
.Rs
.%A Thomas Narten
.%A Erik Nordmark
.%A W. A. Simpson
.%A Hesham Soliman
.%T Neighbor Discovery for IP version 6 (IPv6)
.%R RFC 4861
.Re
.Rs
.%A Thomas Narten
.%A Erik Nordmark
.%A W. A. Simpson
.%T Neighbor Discovery for IP version 6 (IPv6)
.%R RFC 2461 (obsoleted by RFC 4861)
.Re
.Rs
.%A Richard Draves
.%T Default Router Preferences and More-Specific Routes
.%R draft-ietf-ipngwg-router-selection-xx.txt
.Re
.Rs
.%A J. Jeong
.%A S. Park
.%A L. Beloeil
.%A S. Madanapalli
.%T IPv6 Router Advertisement Options for DNS Configuration
.%R RFC 6106
.Re
.Sh HISTORY
The
.Nm

File diff suppressed because it is too large Load Diff

View File

@ -18,4 +18,5 @@
# this part by hand, and then invoke rtadvd with the -s option.
#ef0:\
# :addr="3ffe:501:ffff:1000::":prefixlen#64:
# :addr="2001:db8:ffff:1000::":prefixlen#64:\
# :rdnss="2001:db8:ffff:1000::1":dnssl="example.com":

View File

@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd May 17, 1998
.Dd June 4, 2011
.Dt RTADVD.CONF 5
.Os
.Sh NAME
@ -179,10 +179,25 @@ will automatically get appropriate prefixes from the kernel's routing table,
and advertise the prefixes with the default parameters.
Keywords other than
.Cm clockskew
and
.Cm noifprefix
can be augmented with a number, like
.Dq Li prefix2 ,
to specify multiple prefixes.
.Bl -tag -width indent
.It Cm \&noifprefix
(bool) Specifies no prefix on the network interfaces will be advertised.
By default
.Nm rtadvd
automatically gathers on-link prefixes from all of the network interfaces
and advertise them.
The
.Cm noifprefix
disables that behavior.
If this is specified and no
.Cm addr
keyword is specified, no prefix information option will be included in the
message.
.It Cm \&clockskew
(num) Time skew to adjust link propagation delays and clock skews
between routers on the link
@ -355,6 +370,66 @@ However, keywords that start with
.Dq Li rtr
have basically been obsoleted, and should not be used any more.
.Pp
The following items are for ICMPv6 Recursive DNS Server Option and
DNS Search List Option
.Pq RFC 6106 ,
which will be attached to router advertisement header.
These items are optional.
.Bl -tag -width indent
.It Cm \&rdnss
(str) The IPv6 address of one or more recursive DNS servers.
The argument must be inside double quotes.
Multiple DNS servers can be specified in a comma-separated string.
If different lifetimes are needed for different servers,
separate entries can be given by using
.Cm rdnss ,
.Cm rdnss0 ,
.Cm rdnss1 ,
.Cm rdnss2 ...
options with corresponding
.Cm rdnssltime ,
.Cm rdnssltime0 ,
.Cm rdnssltime1 ,
.Cm rdnssltime2 ...
entries.
Note that the maximum number of servers depends on the receiver side.
See also
.Xr resolver 5
manual page for resolver implementation in
.Fx .
.It Cm \&rdnssltime
The lifetime of the
.Cm rdnss
DNS server entries.
The default value is 3/2 of the interval time.
.It Cm \&dnssl
(str) One or more domain names in a comma-separated string.
These domain names will be used when making DNS queries on a
non-fully-qualified domain name.
If different lifetimes are needed for different domains, separate entries
can be given by using
.Cm dnssl ,
.Cm dnssl0 ,
.Cm dnssl1 ,
.Cm dnssl2 ...
options with corresponding
.Cm dnsslltime ,
.Cm dnsslltime0 ,
.Cm dnsslltime1 ,
.Cm dnsslltime2 ...
entries.
Note that the maximum number of names depends on the receiver side.
See also
.Xr resolver 5
manual page for resolver implementation in
.Fx .
.It Cm \&dnsslltime
The lifetime of the
.Cm dnssl
DNS search list entries.
The default value is 3/2 of the interval time.
.El
.Pp
You can also refer one line from another by using
.Cm tc
capability.
@ -388,7 +463,18 @@ option to
.Xr rtadvd 8 .
.Bd -literal -offset
ef0:\\
:addr="3ffe:501:ffff:1000::":prefixlen#64:
:addr="2001:db8:ffff:1000::":prefixlen#64:
.Ed
.Pp
The following example configures the
.Li wlan0
interface and adds two DNS servers and a DNS domain search options
using the default option lifetime values.
.Bd -literal -offset
wlan0:\\
:addr="2001:db8:ffff:1000::":prefixlen#64:\\
:rdnss="2001:db8:ffff::10,2001:db8:ffff::2:43":\\
:dnssl="example.com":
.Ed
.Pp
The following example presents the default values in an explicit manner.
@ -399,24 +485,41 @@ default:\\
:chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\
:pinfoflags="la":vltime#2592000:pltime#604800:mtu#0:
ef0:\\
:addr="3ffe:501:ffff:1000::":prefixlen#64:tc=default:
:addr="2001:db8:ffff:1000::":prefixlen#64:tc=default:
.Ed
.Sh SEE ALSO
.Xr termcap 5 ,
.Xr resolver 5 ,
.Xr rtadvd 8 ,
.Xr rtsol 8
.Rs
.%A Thomas Narten
.%A Erik Nordmark
.%A W. A. Simpson
.%A Hesham Soliman
.%T Neighbor Discovery for IP version 6 (IPv6)
.%R RFC 2461
.%R RFC 4861
.Re
.Rs
.%A Thomas Narten
.%A Erik Nordmark
.%A W. A. Simpson
.%T Neighbor Discovery for IP version 6 (IPv6)
.%R RFC 2461 (obsoleted by RFC 4861)
.Re
.Rs
.%A Richard Draves
.%T Default Router Preferences and More-Specific Routes
.%R draft-ietf-ipngwg-router-selection-xx.txt
.Re
.Rs
.%A J. Jeong
.%A S. Park
.%A L. Beloeil
.%A S. Madanapalli
.%T IPv6 Router Advertisement Options for DNS Configuration
.%R RFC 6106
.Re
.Sh HISTORY
The
.Xr rtadvd 8

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 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:
@ -16,7 +16,7 @@
* 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
@ -30,11 +30,41 @@
* SUCH DAMAGE.
*/
#define ALLNODES "ff02::1"
#define ALLROUTERS_LINK "ff02::2"
#define ALLROUTERS_SITE "ff05::2"
#define ANY "::"
#define RTSOLLEN 8
#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}}
#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
#define IN6ADDR_SITELOCAL_ALLROUTERS_INIT \
{{{ 0xff, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
extern struct sockaddr_in6 sin6_linklocal_allnodes;
extern struct sockaddr_in6 sin6_linklocal_allrouters;
extern struct sockaddr_in6 sin6_sitelocal_allrouters;
/*
* RFC 3542 API deprecates IPV6_PKTINFO in favor of
* IPV6_RECVPKTINFO
*/
#ifndef IPV6_RECVPKTINFO
#ifdef IPV6_PKTINFO
#define IPV6_RECVPKTINFO IPV6_PKTINFO
#endif
#endif
/*
* RFC 3542 API deprecates IPV6_HOPLIMIT in favor of
* IPV6_RECVHOPLIMIT
*/
#ifndef IPV6_RECVHOPLIMIT
#ifdef IPV6_HOPLIMIT
#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
#endif
#endif
/* protocol constants and default values */
#define DEF_MAXRTRADVINTERVAL 600
@ -62,100 +92,150 @@
#define PREFIX_FROM_DYNAMIC 3
struct prefix {
struct prefix *next; /* forward link */
struct prefix *prev; /* previous link */
TAILQ_ENTRY(prefix) pfx_next;
struct rainfo *rainfo; /* back pointer to the interface */
struct rainfo *pfx_rainfo; /* back pointer to the interface */
/*
* Expiration timer. This is used when a prefix derived from
* the kernel is deleted.
*/
struct rtadvd_timer *pfx_timer;
struct rtadvd_timer *timer; /* expiration timer. used when a prefix
* derived from the kernel is deleted.
*/
u_int32_t pfx_validlifetime; /* AdvValidLifetime */
long pfx_vltimeexpire; /* Expiration of vltime */
u_int32_t pfx_preflifetime; /* AdvPreferredLifetime */
long pfx_pltimeexpire; /* Expiration of pltime */
u_int pfx_onlinkflg; /* bool: AdvOnLinkFlag */
u_int pfx_autoconfflg; /* bool: AdvAutonomousFlag */
int pfx_prefixlen;
int pfx_origin; /* From kernel or config */
u_int32_t validlifetime; /* AdvValidLifetime */
long vltimeexpire; /* expiration of vltime; decrement case only */
u_int32_t preflifetime; /* AdvPreferredLifetime */
long pltimeexpire; /* expiration of pltime; decrement case only */
u_int onlinkflg; /* bool: AdvOnLinkFlag */
u_int autoconfflg; /* bool: AdvAutonomousFlag */
int prefixlen;
int origin; /* from kernel or config */
struct in6_addr prefix;
struct in6_addr pfx_prefix;
};
#ifdef ROUTEINFO
struct rtinfo {
struct rtinfo *prev; /* previous link */
struct rtinfo *next; /* forward link */
TAILQ_ENTRY(rtinfo) rti_next;
u_int32_t ltime; /* route lifetime */
u_int rtpref; /* route preference */
int prefixlen;
struct in6_addr prefix;
u_int32_t rti_ltime; /* route lifetime */
u_int rti_rtpref; /* route preference */
int rti_prefixlen;
struct in6_addr rti_prefix;
};
#endif
struct rdnss_addr {
TAILQ_ENTRY(rdnss_addr) ra_next;
struct in6_addr ra_dns; /* DNS server entry */
};
struct rdnss {
TAILQ_ENTRY(rdnss) rd_next;
TAILQ_HEAD(, rdnss_addr) rd_list; /* list of DNS servers */
int rd_cnt; /* number of DNS servers */
u_int32_t rd_ltime; /* number of seconds valid */
};
/*
* The maximum length of a domain name in a DNS search list is calculated
* by a domain name + length fields per 63 octets + a zero octet at
* the tail and adding 8 octet boundary padding.
*/
#define _DNAME_LABELENC_MAXLEN \
(NI_MAXHOST + (NI_MAXHOST / 64 + 1) + 1)
#define DNAME_LABELENC_MAXLEN \
(_DNAME_LABELENC_MAXLEN + 8 - _DNAME_LABELENC_MAXLEN % 8)
struct dnssl_addr {
TAILQ_ENTRY(dnssl_addr) da_next;
int da_len; /* length of entry */
char da_dom[DNAME_LABELENC_MAXLEN]; /* search domain name entry */
};
struct dnssl {
TAILQ_ENTRY(dnssl) dn_next;
TAILQ_HEAD(, dnssl_addr) dn_list; /* list of search domains */
u_int32_t dn_ltime; /* number of seconds valid */
};
struct soliciter {
struct soliciter *next;
struct sockaddr_in6 addr;
TAILQ_ENTRY(soliciter) sol_next;
struct sockaddr_in6 sol_addr;
};
struct rainfo {
/* pointer for list */
struct rainfo *next;
TAILQ_ENTRY(rainfo) rai_next;
/* timer related parameters */
struct rtadvd_timer *timer;
int initcounter; /* counter for the first few advertisements */
struct timeval lastsent; /* timestamp when the latest RA was sent */
int waiting; /* number of RS waiting for RA */
struct rtadvd_timer *rai_timer;
/* counter for the first few advertisements */
int rai_initcounter;
/* timestamp when the latest RA was sent */
struct timeval rai_lastsent;
/* number of RS waiting for RA */
int rai_waiting;
/* interface information */
int ifindex;
int advlinkopt; /* bool: whether include link-layer addr opt */
struct sockaddr_dl *sdl;
char ifname[16];
int phymtu; /* mtu of the physical interface */
int rai_ifindex;
int rai_advlinkopt; /* bool: whether include link-layer addr opt */
int rai_advifprefix; /* bool: gather IF prefixes? */
struct sockaddr_dl *rai_sdl;
char rai_ifname[IFNAMSIZ];
u_int32_t rai_phymtu; /* mtu of the physical interface */
/* Router configuration variables */
u_short lifetime; /* AdvDefaultLifetime */
u_int maxinterval; /* MaxRtrAdvInterval */
u_int mininterval; /* MinRtrAdvInterval */
int managedflg; /* AdvManagedFlag */
int otherflg; /* AdvOtherConfigFlag */
u_short rai_lifetime; /* AdvDefaultLifetime */
u_int rai_maxinterval; /* MaxRtrAdvInterval */
u_int rai_mininterval; /* MinRtrAdvInterval */
int rai_managedflg; /* AdvManagedFlag */
int rai_otherflg; /* AdvOtherConfigFlag */
int rtpref; /* router preference */
u_int32_t linkmtu; /* AdvLinkMTU */
u_int32_t reachabletime; /* AdvReachableTime */
u_int32_t retranstimer; /* AdvRetransTimer */
u_int hoplimit; /* AdvCurHopLimit */
struct prefix prefix; /* AdvPrefixList(link head) */
int pfxs; /* number of prefixes */
long clockskew; /* used for consisitency check of lifetimes */
int rai_rtpref; /* router preference */
u_int32_t rai_linkmtu; /* AdvLinkMTU */
u_int32_t rai_reachabletime; /* AdvReachableTime */
u_int32_t rai_retranstimer; /* AdvRetransTimer */
u_int rai_hoplimit; /* AdvCurHopLimit */
TAILQ_HEAD(, prefix) rai_prefix;/* AdvPrefixList(link head) */
int rai_pfxs; /* number of prefixes */
long rai_clockskew; /* used for consisitency check of lifetimes */
TAILQ_HEAD(, rdnss) rai_rdnss; /* DNS server list */
TAILQ_HEAD(, dnssl) rai_dnssl; /* search domain list */
#ifdef ROUTEINFO
struct rtinfo route; /* route information option (link head) */
int routes; /* number of route information options */
TAILQ_HEAD(, rtinfo) rai_route; /* route information option (link head) */
int rai_routes; /* number of route information options */
#endif
/* actual RA packet data and its length */
size_t ra_datalen;
u_char *ra_data;
size_t rai_ra_datalen;
u_char *rai_ra_data;
/* statistics */
u_quad_t raoutput; /* number of RAs sent */
u_quad_t rainput; /* number of RAs received */
u_quad_t rainconsistent; /* number of RAs inconsistent with ours */
u_quad_t rsinput; /* number of RSs received */
u_quad_t rai_raoutput; /* # of RAs sent */
u_quad_t rai_rainput; /* # of RAs received */
u_quad_t rai_rainconsistent; /* # of RAs inconsistent with ours */
u_quad_t rai_rsinput; /* # of RSs received */
/* info about soliciter */
struct soliciter *soliciter; /* recent solication source */
TAILQ_HEAD(, soliciter) rai_soliciter; /* recent solication source */
};
struct rtadvd_timer *ra_timeout(void *);
void ra_timer_update(void *, struct timeval *);
/* Interface list including RA information */
extern TAILQ_HEAD(railist_head_t, rainfo) railist;
int prefix_match(struct in6_addr *, int, struct in6_addr *, int);
struct rainfo *if_indextorainfo(int);
struct prefix *find_prefix(struct rainfo *, struct in6_addr *, int);
struct rtadvd_timer *ra_timeout(void *);
void ra_timer_update(void *, struct timeval *);
extern struct in6_addr in6a_site_allrouters;
int prefix_match(struct in6_addr *, int,
struct in6_addr *, int);
struct rainfo *if_indextorainfo(int);
struct prefix *find_prefix(struct rainfo *,
struct in6_addr *, int);

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 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:
@ -16,7 +16,7 @@
* 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
@ -31,6 +31,7 @@
*/
#include <sys/time.h>
#include <sys/queue.h>
#include <unistd.h>
#include <syslog.h>
@ -39,21 +40,19 @@
#include <search.h>
#include "timer.h"
static struct rtadvd_timer timer_head;
#define MILLION 1000000
#define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\
(t1)->tv_usec == (t2)->tv_usec)
static struct timeval tm_max = {0x7fffffff, 0x7fffffff};
struct rtadvd_timer_head_t ra_timer =
TAILQ_HEAD_INITIALIZER(ra_timer);
static struct timeval tm_limit = {0x7fffffff, 0x7fffffff};
static struct timeval tm_max;
void
rtadvd_timer_init()
rtadvd_timer_init(void)
{
memset(&timer_head, 0, sizeof(timer_head));
timer_head.next = timer_head.prev = &timer_head;
timer_head.tm = tm_max;
tm_max = tm_limit;
TAILQ_INIT(&ra_timer);
}
struct rtadvd_timer *
@ -61,54 +60,57 @@ rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *),
void (*update)(void *, struct timeval *),
void *timeodata, void *updatedata)
{
struct rtadvd_timer *newtimer;
if ((newtimer = malloc(sizeof(*newtimer))) == NULL) {
syslog(LOG_ERR,
"<%s> can't allocate memory", __func__);
exit(1);
}
memset(newtimer, 0, sizeof(*newtimer));
struct rtadvd_timer *rat;
if (timeout == NULL) {
syslog(LOG_ERR,
"<%s> timeout function unspecified", __func__);
"<%s> timeout function unspecified", __func__);
exit(1);
}
newtimer->expire = timeout;
newtimer->update = update;
newtimer->expire_data = timeodata;
newtimer->update_data = updatedata;
newtimer->tm = tm_max;
rat = malloc(sizeof(*rat));
if (rat == NULL) {
syslog(LOG_ERR,
"<%s> can't allocate memory", __func__);
exit(1);
}
memset(rat, 0, sizeof(*rat));
rat->rat_expire = timeout;
rat->rat_update = update;
rat->rat_expire_data = timeodata;
rat->rat_update_data = updatedata;
rat->rat_tm = tm_max;
/* link into chain */
insque(newtimer, &timer_head);
TAILQ_INSERT_TAIL(&ra_timer, rat, rat_next);
return(newtimer);
return (rat);
}
void
rtadvd_remove_timer(struct rtadvd_timer **timer)
rtadvd_remove_timer(struct rtadvd_timer *rat)
{
remque(*timer);
free(*timer);
*timer = NULL;
if (rat == NULL)
return;
TAILQ_REMOVE(&ra_timer, rat, rat_next);
free(rat);
}
void
rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *rat)
{
struct timeval now;
/* reset the timer */
gettimeofday(&now, NULL);
TIMEVAL_ADD(&now, tm, &timer->tm);
TIMEVAL_ADD(&now, tm, &rat->rat_tm);
/* update the next expiration time */
if (TIMEVAL_LT(timer->tm, timer_head.tm))
timer_head.tm = timer->tm;
if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
tm_max = rat->rat_tm;
return;
}
@ -119,58 +121,52 @@ rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
* Return the next interval for select() call.
*/
struct timeval *
rtadvd_check_timer()
rtadvd_check_timer(void)
{
static struct timeval returnval;
struct timeval now;
struct rtadvd_timer *tm = timer_head.next, *tm_next;
struct rtadvd_timer *rat;
gettimeofday(&now, NULL);
timer_head.tm = tm_max;
for (tm = timer_head.next; tm != &timer_head; tm = tm_next) {
tm_next = tm->next;
if (TIMEVAL_LEQ(tm->tm, now)) {
if (((*tm->expire)(tm->expire_data) == NULL))
tm_max = tm_limit;
TAILQ_FOREACH(rat, &ra_timer, rat_next) {
if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
if (((*rat->rat_expire)(rat->rat_expire_data) == NULL))
continue; /* the timer was removed */
if (tm->update)
(*tm->update)(tm->update_data, &tm->tm);
TIMEVAL_ADD(&tm->tm, &now, &tm->tm);
if (rat->rat_update)
(*rat->rat_update)(rat->rat_update_data, &rat->rat_tm);
TIMEVAL_ADD(&rat->rat_tm, &now, &rat->rat_tm);
}
if (TIMEVAL_LT(tm->tm, timer_head.tm))
timer_head.tm = tm->tm;
if (TIMEVAL_LT(&rat->rat_tm, &tm_max))
tm_max = rat->rat_tm;
}
if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) {
if (TIMEVAL_EQUAL(&tm_max, &tm_limit)) {
/* no need to timeout */
return(NULL);
} else if (TIMEVAL_LT(timer_head.tm, now)) {
return (NULL);
} else if (TIMEVAL_LT(&tm_max, &now)) {
/* this may occur when the interval is too small */
returnval.tv_sec = returnval.tv_usec = 0;
} else
TIMEVAL_SUB(&timer_head.tm, &now, &returnval);
return(&returnval);
TIMEVAL_SUB(&tm_max, &now, &returnval);
return (&returnval);
}
struct timeval *
rtadvd_timer_rest(struct rtadvd_timer *timer)
rtadvd_timer_rest(struct rtadvd_timer *rat)
{
static struct timeval returnval, now;
gettimeofday(&now, NULL);
if (TIMEVAL_LEQ(timer->tm, now)) {
if (TIMEVAL_LEQ(&rat->rat_tm, &now)) {
syslog(LOG_DEBUG,
"<%s> a timer must be expired, but not yet",
__func__);
"<%s> a timer must be expired, but not yet",
__func__);
returnval.tv_sec = returnval.tv_usec = 0;
}
else
TIMEVAL_SUB(&timer->tm, &now, &returnval);
TIMEVAL_SUB(&rat->rat_tm, &now, &returnval);
return(&returnval);
return (&returnval);
}
/* result = a + b */

View File

@ -4,7 +4,7 @@
/*
* Copyright (C) 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:
@ -16,7 +16,7 @@
* 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
@ -31,35 +31,42 @@
*/
/* a < b */
#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\
(((a).tv_sec == (b).tv_sec) && \
((a).tv_usec < (b).tv_usec)))
#define TIMEVAL_LT(a, b) \
(((a)->tv_sec < (b)->tv_sec) || \
(((a)->tv_sec == (b)->tv_sec) && \
((a)->tv_usec < (b)->tv_usec)))
/* a <= b */
#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\
(((a).tv_sec == (b).tv_sec) &&\
((a).tv_usec <= (b).tv_usec)))
#define TIMEVAL_LEQ(a, b) \
(((a)->tv_sec < (b)->tv_sec) || \
(((a)->tv_sec == (b)->tv_sec) && \
((a)->tv_usec <= (b)->tv_usec)))
#define TIMEVAL_EQUAL(a,b) \
(((a)->tv_sec == (b)->tv_sec) && \
((a)->tv_usec == (b)->tv_usec))
extern TAILQ_HEAD(rtadvd_timer_head_t, rtadvd_timer) ra_timer;
struct rtadvd_timer {
struct rtadvd_timer *next;
struct rtadvd_timer *prev;
struct rainfo *rai;
struct timeval tm;
TAILQ_ENTRY(rtadvd_timer) rat_next;
struct rtadvd_timer *(*expire)(void *); /* expiration function */
void *expire_data;
void (*update)(void *, struct timeval *); /* update function */
void *update_data;
struct rainfo *rat_rai;
struct timeval rat_tm;
struct rtadvd_timer *(*rat_expire)(void *);
void *rat_expire_data;
void (*rat_update)(void *, struct timeval *);
void *rat_update_data;
};
void rtadvd_timer_init(void);
struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
void (*)(void *, struct timeval *), void *, void *);
void rtadvd_set_timer(struct timeval *, struct rtadvd_timer *);
void rtadvd_remove_timer(struct rtadvd_timer **);
struct timeval * rtadvd_check_timer(void);
struct timeval * rtadvd_timer_rest(struct rtadvd_timer *);
void TIMEVAL_ADD(struct timeval *, struct timeval *,
struct timeval *);
void TIMEVAL_SUB(struct timeval *, struct timeval *,
struct timeval *);
void rtadvd_timer_init(void);
struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
void (*)(void *, struct timeval *), void *, void *);
void rtadvd_set_timer(struct timeval *,
struct rtadvd_timer *);
void rtadvd_remove_timer(struct rtadvd_timer *);
struct timeval *rtadvd_check_timer(void);
struct timeval *rtadvd_timer_rest(struct rtadvd_timer *);
void TIMEVAL_ADD(struct timeval *, struct timeval *,
struct timeval *);
void TIMEVAL_SUB(struct timeval *, struct timeval *,
struct timeval *);

View File

@ -19,7 +19,7 @@ MAN= rtsold.8
MLINKS= rtsold.8 rtsol.8
SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c
WARNS?= 3
WARNS?= 6
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H
DPADD= ${LIBKVM}
LDADD= -lkvm

View File

@ -34,6 +34,7 @@
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <net/if.h>
#include <netinet/in.h>
@ -58,41 +59,41 @@ static const char * const ifstatstr[] = {"IDLE", "DELAY", "PROBE", "DOWN", "TENT
static void
dump_interface_status(void)
{
struct ifinfo *ifinfo;
struct ifinfo *ifi;
struct timeval now;
gettimeofday(&now, NULL);
for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
fprintf(fp, "Interface %s\n", ifinfo->ifname);
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
fprintf(fp, "Interface %s\n", ifi->ifname);
fprintf(fp, " probe interval: ");
if (ifinfo->probeinterval) {
fprintf(fp, "%d\n", ifinfo->probeinterval);
fprintf(fp, " probe timer: %d\n", ifinfo->probetimer);
if (ifi->probeinterval) {
fprintf(fp, "%d\n", ifi->probeinterval);
fprintf(fp, " probe timer: %d\n", ifi->probetimer);
} else {
fprintf(fp, "infinity\n");
fprintf(fp, " no probe timer\n");
}
fprintf(fp, " interface status: %s\n",
ifinfo->active > 0 ? "active" : "inactive");
ifi->active > 0 ? "active" : "inactive");
fprintf(fp, " other config: %s\n",
ifinfo->otherconfig ? "on" : "off");
fprintf(fp, " rtsold status: %s\n", ifstatstr[ifinfo->state]);
ifi->otherconfig ? "on" : "off");
fprintf(fp, " rtsold status: %s\n", ifstatstr[ifi->state]);
fprintf(fp, " carrier detection: %s\n",
ifinfo->mediareqok ? "available" : "unavailable");
ifi->mediareqok ? "available" : "unavailable");
fprintf(fp, " probes: %d, dadcount = %d\n",
ifinfo->probes, ifinfo->dadcount);
if (ifinfo->timer.tv_sec == tm_max.tv_sec &&
ifinfo->timer.tv_usec == tm_max.tv_usec)
ifi->probes, ifi->dadcount);
if (ifi->timer.tv_sec == tm_max.tv_sec &&
ifi->timer.tv_usec == tm_max.tv_usec)
fprintf(fp, " no timer\n");
else {
fprintf(fp, " timer: interval=%d:%d, expire=%s\n",
(int)ifinfo->timer.tv_sec,
(int)ifinfo->timer.tv_usec,
(ifinfo->expire.tv_sec < now.tv_sec) ? "expired"
: sec2str(ifinfo->expire.tv_sec - now.tv_sec));
(int)ifi->timer.tv_sec,
(int)ifi->timer.tv_usec,
(ifi->expire.tv_sec < now.tv_sec) ? "expired"
: sec2str(ifi->expire.tv_sec - now.tv_sec));
}
fprintf(fp, " number of valid RAs: %d\n", ifinfo->racnt);
fprintf(fp, " number of valid RAs: %d\n", ifi->racnt);
}
}
@ -145,5 +146,6 @@ sec2str(time_t total)
p += n;
}
snprintf(p, ep - p, "%ds", secs);
return(result);
return (result);
}

View File

@ -91,25 +91,25 @@ interface_up(char *name)
if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFFLAGS): %s",
strerror(errno));
return(-1);
return (-1);
}
if (!(ifr.ifr_flags & IFF_UP)) {
ifr.ifr_flags |= IFF_UP;
if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
warnmsg(LOG_ERR, __func__,
"ioctl(SIOCSIFFLAGS): %s", strerror(errno));
return(-1);
return (-1);
}
if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
warnmsg(LOG_WARNING, __func__, "socket(AF_INET6, SOCK_DGRAM): %s",
strerror(errno));
return(-1);
return (-1);
}
if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
warnmsg(LOG_WARNING, __func__, "ioctl(SIOCGIFINFO_IN6): %s",
strerror(errno));
close(s);
return(-1);
return (-1);
}
warnmsg(LOG_DEBUG, __func__, "checking if %s is ready...", name);
@ -122,13 +122,13 @@ interface_up(char *name)
"ioctl(SIOCSIFINFO_IN6): %s",
strerror(errno));
close(s);
return(-1);
return (-1);
}
} else {
warnmsg(LOG_WARNING, __func__,
"%s is disabled.", name);
close(s);
return(-1);
return (-1);
}
}
if (!(nd.ndi.flags & ND6_IFF_ACCEPT_RTADV)) {
@ -139,13 +139,13 @@ interface_up(char *name)
"ioctl(SIOCSIFINFO_IN6): %s",
strerror(errno));
close(s);
return(-1);
return (-1);
}
} else {
warnmsg(LOG_WARNING, __func__,
"%s does not accept Router Advertisement.", name);
close(s);
return(-1);
return (-1);
}
}
close(s);
@ -154,22 +154,22 @@ interface_up(char *name)
if (llflag < 0) {
warnmsg(LOG_WARNING, __func__,
"get_llflag() failed, anyway I'll try");
return 0;
return (0);
}
if (!(llflag & IN6_IFF_NOTREADY)) {
warnmsg(LOG_DEBUG, __func__, "%s is ready", name);
return(0);
return (0);
} else {
if (llflag & IN6_IFF_TENTATIVE) {
warnmsg(LOG_DEBUG, __func__, "%s is tentative",
name);
return IFS_TENTATIVE;
return (IFS_TENTATIVE);
}
if (llflag & IN6_IFF_DUPLICATED)
warnmsg(LOG_DEBUG, __func__, "%s is duplicated",
name);
return -1;
return (-1);
}
}
@ -186,16 +186,14 @@ interface_status(struct ifinfo *ifinfo)
if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
warnmsg(LOG_ERR, __func__, "ioctl(SIOCGIFFLAGS) on %s: %s",
ifname, strerror(errno));
return(-1);
return (-1);
}
/*
* if one of UP and RUNNING flags is dropped,
* the interface is not active.
*/
if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
goto inactive;
}
/* Next, check carrier on the interface, if possible */
if (!ifinfo->mediareqok)
goto active;
@ -232,10 +230,10 @@ interface_status(struct ifinfo *ifinfo)
}
inactive:
return(0);
return (0);
active:
return(1);
return (1);
}
#define ROUNDUP(a, size) \
@ -254,9 +252,9 @@ lladdropt_length(struct sockaddr_dl *sdl)
#ifdef IFT_IEEE80211
case IFT_IEEE80211:
#endif
return(ROUNDUP8(ETHER_ADDR_LEN + 2));
return (ROUNDUP8(ETHER_ADDR_LEN + 2));
default:
return(0);
return (0);
}
}
@ -301,7 +299,7 @@ if_nametosdl(char *name)
return(NULL);
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
free(buf);
return(NULL);
return (NULL);
}
lim = buf + len;
@ -327,17 +325,17 @@ if_nametosdl(char *name)
if (next == lim) {
/* search failed */
free(buf);
return(NULL);
return (NULL);
}
if ((ret_sdl = malloc(sdl->sdl_len)) == NULL) {
free(buf);
return(NULL);
return (NULL);
}
memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
free(buf);
return(ret_sdl);
return (ret_sdl);
}
int
@ -350,9 +348,9 @@ getinet6sysctl(int code)
mib[3] = code;
size = sizeof(value);
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0)
return -1;
return (-1);
else
return value;
return (value);
}
int
@ -366,9 +364,9 @@ setinet6sysctl(int code, int newval)
size = sizeof(value);
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size,
&newval, sizeof(newval)) < 0)
return -1;
return (-1);
else
return value;
return (value);
}
/*------------------------------------------------------------*/
@ -414,12 +412,12 @@ get_llflag(const char *name)
freeifaddrs(ifap);
close(s);
return ifr6.ifr_ifru.ifru_flags6;
return (ifr6.ifr_ifru.ifru_flags6);
}
freeifaddrs(ifap);
close(s);
return -1;
return (-1);
}

View File

@ -72,18 +72,18 @@ probe_init(void)
if (sndcmsgbuf == NULL &&
(sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) {
warnmsg(LOG_ERR, __func__, "malloc failed");
return(-1);
return (-1);
}
if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
return(-1);
return (-1);
}
/* make the socket send-only */
if (shutdown(probesock, 0)) {
warnmsg(LOG_ERR, __func__, "shutdown: %s", strerror(errno));
return(-1);
return (-1);
}
/* initialize msghdr for sending packets */
@ -92,7 +92,8 @@ probe_init(void)
sndmhdr.msg_iovlen = 1;
sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
sndmhdr.msg_controllen = scmsglen;
return(0);
return (0);
}
/*

View File

@ -83,7 +83,7 @@ int
rtsock_open(void)
{
return socket(PF_ROUTE, SOCK_RAW, 0);
return (socket(PF_ROUTE, SOCK_RAW, 0));
}
int
@ -130,7 +130,7 @@ rtsock_input(int s)
}
}
return ret;
return (ret);
}
#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
@ -142,7 +142,7 @@ rtsock_input_ifannounce(int s __unused, struct rt_msghdr *rtm, char *lim)
ifan = (struct if_announcemsghdr *)rtm;
if ((char *)(ifan + 1) > lim)
return -1;
return (-1);
switch (ifan->ifan_what) {
case IFAN_ARRIVAL:
@ -170,6 +170,6 @@ rtsock_input_ifannounce(int s __unused, struct rt_msghdr *rtm, char *lim)
break;
}
return 0;
return (0);
}
#endif

View File

@ -2,6 +2,7 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* Copyright (C) 2011 Hiroki Sato
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -43,13 +44,16 @@
#include <net/route.h>
#include <net/if_dl.h>
#define __BSD_VISIBLE 1 /* IN6ADDR_LINKLOCAL_ALLROUTERS_INIT */
#include <netinet/in.h>
#undef __BSD_VISIBLE
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
@ -61,8 +65,6 @@
#include <syslog.h>
#include "rtsold.h"
#define ALLROUTER "ff02::2"
static struct msghdr rcvmhdr;
static struct msghdr sndmhdr;
static struct iovec rcviov[2];
@ -71,15 +73,40 @@ static struct sockaddr_in6 from;
static int rcvcmsglen;
int rssock;
struct ifinfo_head_t ifinfo_head =
TAILQ_HEAD_INITIALIZER(ifinfo_head);
static struct sockaddr_in6 sin6_allrouters = {
static const struct sockaddr_in6 sin6_allrouters = {
.sin6_len = sizeof(sin6_allrouters),
.sin6_family = AF_INET6,
.sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT,
};
static void call_script(char *, char *);
static void call_script(const int, const char *const *, void *);
static size_t dname_labeldec(char *, size_t, const char *);
static int safefile(const char *);
#define _ARGS_OTHER otherconf_script, ifi->ifname
#define _ARGS_RESADD resolvconf_script, "-a", ifi->ifname
#define _ARGS_RESDEL resolvconf_script, "-d", ifi->ifname
#define CALL_SCRIPT(name, sm_head) \
do { \
const char *const sarg[] = { _ARGS_##name, NULL }; \
call_script(sizeof(sarg), sarg, sm_head); \
} while(0)
#define ELM_MALLOC(p,error_action) \
do { \
p = malloc(sizeof(*p)); \
if (p == NULL) { \
warnmsg(LOG_ERR, __func__, "malloc failed: %s", \
strerror(errno)); \
error_action; \
} \
memset(p, 0, sizeof(*p)); \
} while(0)
int
sockopen(void)
{
@ -93,63 +120,35 @@ sockopen(void)
if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
warnmsg(LOG_ERR, __func__,
"malloc for receive msghdr failed");
return(-1);
return (-1);
}
if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) {
warnmsg(LOG_ERR, __func__,
"malloc for send msghdr failed");
return(-1);
return (-1);
}
memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6));
sin6_allrouters.sin6_family = AF_INET6;
sin6_allrouters.sin6_len = sizeof(sin6_allrouters);
if (inet_pton(AF_INET6, ALLROUTER,
&sin6_allrouters.sin6_addr.s6_addr) != 1) {
warnmsg(LOG_ERR, __func__, "inet_pton failed for %s",
ALLROUTER);
return(-1);
}
if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
warnmsg(LOG_ERR, __func__, "socket: %s", strerror(errno));
return(-1);
return (-1);
}
/* specify to tell receiving interface */
on = 1;
#ifdef IPV6_RECVPKTINFO
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_RECVPKTINFO: %s",
strerror(errno));
exit(1);
}
#else /* old adv. API */
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_PKTINFO: %s",
strerror(errno));
exit(1);
}
#endif
on = 1;
/* specify to tell value of hoplimit field of received IP6 hdr */
#ifdef IPV6_RECVHOPLIMIT
on = 1;
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_RECVHOPLIMIT: %s",
strerror(errno));
exit(1);
}
#else /* old adv. API */
if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
sizeof(on)) < 0) {
warnmsg(LOG_ERR, __func__, "IPV6_HOPLIMIT: %s",
strerror(errno));
exit(1);
}
#endif
/* specfiy to accept only router advertisements on the socket */
ICMP6_FILTER_SETBLOCKALL(&filt);
@ -176,11 +175,11 @@ sockopen(void)
sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
sndmhdr.msg_controllen = sndcmsglen;
return(rssock);
return (rssock);
}
void
sendpacket(struct ifinfo *ifinfo)
sendpacket(struct ifinfo *ifi)
{
struct in6_pktinfo *pi;
struct cmsghdr *cm;
@ -189,11 +188,11 @@ sendpacket(struct ifinfo *ifinfo)
struct sockaddr_in6 dst;
dst = sin6_allrouters;
dst.sin6_scope_id = ifinfo->linkid;
dst.sin6_scope_id = ifi->linkid;
sndmhdr.msg_name = (caddr_t)&dst;
sndmhdr.msg_iov[0].iov_base = (caddr_t)ifinfo->rs_data;
sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen;
sndmhdr.msg_iov[0].iov_base = (caddr_t)ifi->rs_data;
sndmhdr.msg_iov[0].iov_len = ifi->rs_datalen;
cm = CMSG_FIRSTHDR(&sndmhdr);
/* specify the outgoing interface */
@ -202,7 +201,7 @@ sendpacket(struct ifinfo *ifinfo)
cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
pi = (struct in6_pktinfo *)CMSG_DATA(cm);
memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
pi->ipi6_ifindex = ifinfo->sdl->sdl_index;
pi->ipi6_ifindex = ifi->sdl->sdl_index;
/* specify the hop limit of the packet */
cm = CMSG_NXTHDR(&sndmhdr, cm);
@ -213,38 +212,50 @@ sendpacket(struct ifinfo *ifinfo)
warnmsg(LOG_DEBUG, __func__,
"send RS on %s, whose state is %d",
ifinfo->ifname, ifinfo->state);
ifi->ifname, ifi->state);
i = sendmsg(rssock, &sndmhdr, 0);
if (i < 0 || (size_t)i != ifinfo->rs_datalen) {
if (i < 0 || (size_t)i != ifi->rs_datalen) {
/*
* ENETDOWN is not so serious, especially when using several
* network cards on a mobile node. We ignore it.
*/
if (errno != ENETDOWN || dflag > 0)
warnmsg(LOG_ERR, __func__, "sendmsg on %s: %s",
ifinfo->ifname, strerror(errno));
ifi->ifname, strerror(errno));
}
/* update counter */
ifinfo->probes++;
ifi->probes++;
}
void
rtsol_input(int s)
{
u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
int ifindex = 0, *hlimp = NULL;
ssize_t i;
int l, ifindex = 0, *hlimp = NULL;
ssize_t msglen;
struct in6_pktinfo *pi = NULL;
struct ifinfo *ifi = NULL;
struct ra_opt *rao = NULL;
struct icmp6_hdr *icp;
struct nd_router_advert *nd_ra;
struct cmsghdr *cm;
char *raoptp;
char *p;
struct in6_addr *addr;
struct nd_opt_hdr *ndo;
struct nd_opt_rdnss *rdnss;
struct nd_opt_dnssl *dnssl;
size_t len;
char nsbuf[INET6_ADDRSTRLEN + 1 + IFNAMSIZ + 1];
char dname[NI_MAXHOST];
struct timeval now;
struct timeval lifetime;
/* get message. namelen and controllen must always be initialized. */
rcvmhdr.msg_namelen = sizeof(from);
rcvmhdr.msg_controllen = rcvcmsglen;
if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) {
if ((msglen = recvmsg(s, &rcvmhdr, 0)) < 0) {
warnmsg(LOG_ERR, __func__, "recvmsg: %s", strerror(errno));
return;
}
@ -275,9 +286,9 @@ rtsol_input(int s)
return;
}
if ((size_t)i < sizeof(struct nd_router_advert)) {
if ((size_t)msglen < sizeof(struct nd_router_advert)) {
warnmsg(LOG_INFO, __func__,
"packet size(%zd) is too short", i);
"packet size(%zd) is too short", msglen);
return;
}
@ -354,9 +365,157 @@ rtsol_input(int s)
warnmsg(LOG_DEBUG, __func__,
"OtherConfigFlag on %s is turned on", ifi->ifname);
ifi->otherconfig = 1;
call_script(otherconf_script, ifi->ifname);
CALL_SCRIPT(OTHER, NULL);
}
/* Initialize ra_opt per-interface structure. */
gettimeofday(&now, NULL);
if (!TAILQ_EMPTY(&ifi->ifi_ra_opt))
while ((rao = TAILQ_FIRST(&ifi->ifi_ra_opt)) != NULL) {
if (rao->rao_msg != NULL)
free(rao->rao_msg);
TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
free(rao);
}
else
TAILQ_INIT(&ifi->ifi_ra_opt);
#define RA_OPT_NEXT_HDR(x) (struct nd_opt_hdr *)((char *)x + \
(((struct nd_opt_hdr *)x)->nd_opt_len * 8))
/* Process RA options. */
warnmsg(LOG_DEBUG, __func__, "Processing RA");
raoptp = (char *)icp + sizeof(struct nd_router_advert);
while (raoptp < (char *)icp + msglen) {
ndo = (struct nd_opt_hdr *)raoptp;
warnmsg(LOG_DEBUG, __func__, "ndo = %p", raoptp);
warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_type = %d",
ndo->nd_opt_type);
warnmsg(LOG_DEBUG, __func__, "ndo->nd_opt_len = %d",
ndo->nd_opt_len);
switch (ndo->nd_opt_type) {
case ND_OPT_RDNSS:
rdnss = (struct nd_opt_rdnss *)raoptp;
/* Optlen sanity check (Section 5.3.1 in RFC 6106) */
if (rdnss->nd_opt_rdnss_len < 3) {
warnmsg(LOG_INFO, __func__,
"too short RDNSS option"
"in RA from %s was ignored.",
inet_ntop(AF_INET6, &from.sin6_addr,
ntopbuf, INET6_ADDRSTRLEN));
break;
}
addr = (struct in6_addr *)(raoptp + sizeof(*rdnss));
while ((char *)addr < (char *)RA_OPT_NEXT_HDR(raoptp)) {
if (inet_ntop(AF_INET6, addr, ntopbuf,
INET6_ADDRSTRLEN) == NULL) {
warnmsg(LOG_INFO, __func__,
"an invalid address in RDNSS option"
" in RA from %s was ignored.",
inet_ntop(AF_INET6, &from.sin6_addr,
ntopbuf, INET6_ADDRSTRLEN));
addr++;
continue;
}
if (IN6_IS_ADDR_LINKLOCAL(addr))
/* XXX: % has to be escaped here */
l = snprintf(nsbuf, sizeof(nsbuf),
"%s%c%s", ntopbuf,
SCOPE_DELIMITER,
ifi->ifname);
else
l = snprintf(nsbuf, sizeof(nsbuf),
"%s", ntopbuf);
if (l < 0 || (size_t)l >= sizeof(nsbuf)) {
warnmsg(LOG_ERR, __func__,
"address copying error in "
"RDNSS option: %d.", l);
addr++;
continue;
}
warnmsg(LOG_DEBUG, __func__, "nsbuf = %s",
nsbuf);
ELM_MALLOC(rao, break);
rao->rao_type = ndo->nd_opt_type;
rao->rao_len = strlen(nsbuf);
rao->rao_msg = strdup(nsbuf);
if (rao->rao_msg == NULL) {
warnmsg(LOG_ERR, __func__,
"strdup failed: %s",
strerror(errno));
free(rao);
addr++;
continue;
}
/* Set expiration timer */
memset(&rao->rao_expire, 0, sizeof(rao->rao_expire));
memset(&lifetime, 0, sizeof(lifetime));
lifetime.tv_sec = ntohl(rdnss->nd_opt_rdnss_lifetime);
timeradd(&now, &lifetime, &rao->rao_expire);
TAILQ_INSERT_TAIL(&ifi->ifi_ra_opt, rao, rao_next);
addr++;
}
break;
case ND_OPT_DNSSL:
dnssl = (struct nd_opt_dnssl *)raoptp;
/* Optlen sanity check (Section 5.3.1 in RFC 6106) */
if (dnssl->nd_opt_dnssl_len < 2) {
warnmsg(LOG_INFO, __func__,
"too short DNSSL option"
"in RA from %s was ignored.",
inet_ntop(AF_INET6, &from.sin6_addr,
ntopbuf, INET6_ADDRSTRLEN));
break;
}
/*
* Ensure NUL-termination in DNSSL in case of
* malformed field.
*/
p = (char *)RA_OPT_NEXT_HDR(raoptp);
*(p - 1) = '\0';
p = raoptp + sizeof(*dnssl);
while (1 < (len = dname_labeldec(dname, sizeof(dname),
p))) {
/* length == 1 means empty string */
warnmsg(LOG_DEBUG, __func__, "dname = %s",
dname);
ELM_MALLOC(rao, break);
rao->rao_type = ndo->nd_opt_type;
rao->rao_len = strlen(dname);
rao->rao_msg = strdup(dname);
if (rao->rao_msg == NULL) {
warnmsg(LOG_ERR, __func__,
"strdup failed: %s",
strerror(errno));
free(rao);
break;
}
/* Set expiration timer */
memset(&rao->rao_expire, 0, sizeof(rao->rao_expire));
memset(&lifetime, 0, sizeof(lifetime));
lifetime.tv_sec = ntohl(dnssl->nd_opt_dnssl_lifetime);
timeradd(&now, &lifetime, &rao->rao_expire);
TAILQ_INSERT_TAIL(&ifi->ifi_ra_opt, rao, rao_next);
p += len;
}
break;
default:
/* nothing to do for other options */
break;
}
raoptp = (char *)RA_OPT_NEXT_HDR(raoptp);
}
ra_opt_handler(ifi);
ifi->racnt++;
switch (ifi->state) {
@ -371,23 +530,166 @@ rtsol_input(int s)
}
}
static void
call_script(char *scriptpath, char *ifname)
{
pid_t pid, wpid;
static char resstr_ns_prefix[] = "nameserver ";
static char resstr_sh_prefix[] = "search ";
static char resstr_nl[] = "\n";
static char resstr_sp[] = " ";
if (scriptpath == NULL)
int
ra_opt_handler(struct ifinfo *ifi)
{
struct ra_opt *rao;
struct script_msg *smp1, *smp2, *smp3;
struct timeval now;
TAILQ_HEAD(, script_msg) sm_rdnss_head =
TAILQ_HEAD_INITIALIZER(sm_rdnss_head);
TAILQ_HEAD(, script_msg) sm_dnssl_head =
TAILQ_HEAD_INITIALIZER(sm_dnssl_head);
int dcount, dlen;
dcount = 0;
dlen = strlen(resstr_sh_prefix) + strlen(resstr_nl);
gettimeofday(&now, NULL);
TAILQ_FOREACH(rao, &ifi->ifi_ra_opt, rao_next) {
switch (rao->rao_type) {
case ND_OPT_RDNSS:
if (timercmp(&now, &rao->rao_expire, >)) {
warnmsg(LOG_INFO, __func__,
"expired rdnss entry: %s",
(char *)rao->rao_msg);
break;
}
ELM_MALLOC(smp1, continue);
ELM_MALLOC(smp2, goto free1);
ELM_MALLOC(smp3, goto free2);
smp1->sm_msg = resstr_ns_prefix;
TAILQ_INSERT_TAIL(&sm_rdnss_head, smp1, sm_next);
smp2->sm_msg = rao->rao_msg;
TAILQ_INSERT_TAIL(&sm_rdnss_head, smp2, sm_next);
smp3->sm_msg = resstr_nl;
TAILQ_INSERT_TAIL(&sm_rdnss_head, smp3, sm_next);
break;
case ND_OPT_DNSSL:
if (timercmp(&now, &rao->rao_expire, >)) {
warnmsg(LOG_INFO, __func__,
"expired dnssl entry: %s",
(char *)rao->rao_msg);
break;
}
dcount++;
/* Check resolv.conf(5) restrictions. */
if (dcount > 6) {
warnmsg(LOG_INFO, __func__,
"dnssl entry exceeding maximum count (%d>6)"
": %s", dcount, (char *)rao->rao_msg);
break;
}
if (256 < dlen + strlen(rao->rao_msg) +
strlen(resstr_sp)) {
warnmsg(LOG_INFO, __func__,
"dnssl entry exceeding maximum length "
"(>256): %s", (char *)rao->rao_msg);
break;
}
ELM_MALLOC(smp1, continue);
ELM_MALLOC(smp2, goto free1);
if (TAILQ_EMPTY(&sm_dnssl_head)) {
ELM_MALLOC(smp3, goto free2);
smp3->sm_msg = resstr_sh_prefix;
TAILQ_INSERT_TAIL(&sm_dnssl_head, smp3,
sm_next);
}
smp1->sm_msg = rao->rao_msg;
TAILQ_INSERT_TAIL(&sm_dnssl_head, smp1, sm_next);
smp2->sm_msg = resstr_sp;
TAILQ_INSERT_TAIL(&sm_dnssl_head, smp2, sm_next);
dlen += strlen(rao->rao_msg) + strlen(resstr_sp);
break;
default:
break;
}
continue;
free2:
free(smp2);
free1:
free(smp1);
}
/* Add \n for DNSSL list. */
if (!TAILQ_EMPTY(&sm_dnssl_head)) {
ELM_MALLOC(smp1, goto ra_opt_handler_freeit);
smp1->sm_msg = resstr_nl;
TAILQ_INSERT_TAIL(&sm_dnssl_head, smp1, sm_next);
}
TAILQ_CONCAT(&sm_rdnss_head, &sm_dnssl_head, sm_next);
if (!TAILQ_EMPTY(&sm_rdnss_head))
CALL_SCRIPT(RESADD, &sm_rdnss_head);
else
CALL_SCRIPT(RESDEL, NULL);
ra_opt_handler_freeit:
/* Clear script message queue. */
if (!TAILQ_EMPTY(&sm_rdnss_head)) {
while ((smp1 = TAILQ_FIRST(&sm_rdnss_head)) != NULL) {
TAILQ_REMOVE(&sm_rdnss_head, smp1, sm_next);
free(smp1);
}
}
return (0);
}
static void
call_script(const int argc, const char *const argv[], void *head)
{
const char *scriptpath;
int fd[2];
int error;
pid_t pid, wpid;
TAILQ_HEAD(, script_msg) *sm_head;
if ((scriptpath = argv[0]) == NULL)
return;
fd[0] = fd[1] = -1;
sm_head = head;
if (sm_head != NULL && !TAILQ_EMPTY(sm_head)) {
error = pipe(fd);
if (error) {
warnmsg(LOG_ERR, __func__,
"failed to create a pipe: %s", strerror(errno));
return;
}
}
/* launch the script */
pid = fork();
if (pid < 0) {
warnmsg(LOG_ERR, __func__,
"failed to fork: %s", strerror(errno));
return;
} else if (pid) {
} else if (pid) { /* parent */
int wstatus;
if (fd[0] != -1) { /* Send message to the child if any. */
ssize_t len;
struct script_msg *smp;
close(fd[0]);
TAILQ_FOREACH(smp, sm_head, sm_next) {
len = strlen(smp->sm_msg);
warnmsg(LOG_DEBUG, __func__,
"write to child = %s(%zd)",
smp->sm_msg, len);
if (write(fd[1], smp->sm_msg, len) != len) {
warnmsg(LOG_ERR, __func__,
"write to child failed: %s",
strerror(errno));
break;
}
}
close(fd[1]);
}
do {
wpid = wait(&wstatus);
} while (wpid != pid && wpid > 0);
@ -395,17 +697,12 @@ call_script(char *scriptpath, char *ifname)
if (wpid < 0)
warnmsg(LOG_ERR, __func__,
"wait: %s", strerror(errno));
else {
else
warnmsg(LOG_DEBUG, __func__,
"script \"%s\" terminated", scriptpath);
}
} else {
char *argv[3];
int fd;
argv[0] = scriptpath;
argv[1] = ifname;
argv[2] = NULL;
} else { /* child */
int nullfd;
char **_argv;
if (safefile(scriptpath)) {
warnmsg(LOG_ERR, __func__,
@ -413,20 +710,42 @@ call_script(char *scriptpath, char *ifname)
scriptpath);
exit(1);
}
if ((fd = open("/dev/null", O_RDWR)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO)
close(fd);
nullfd = open("/dev/null", O_RDWR);
if (nullfd < 0) {
warnmsg(LOG_ERR, __func__,
"open /dev/null: %s", strerror(errno));
exit(1);
}
if (fd[0] != -1) { /* Receive message from STDIN if any. */
close(fd[1]);
if (fd[0] != STDIN_FILENO) {
/* Connect a pipe read-end to child's STDIN. */
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
warnmsg(LOG_ERR, __func__,
"dup2 STDIN: %s", strerror(errno));
exit(1);
}
close(fd[0]);
}
} else
dup2(nullfd, STDIN_FILENO);
dup2(nullfd, STDOUT_FILENO);
dup2(nullfd, STDERR_FILENO);
if (nullfd > STDERR_FILENO)
close(nullfd);
execv(scriptpath, argv);
_argv = malloc(sizeof(*_argv) * argc);
if (_argv == NULL) {
warnmsg(LOG_ERR, __func__,
"malloc: %s", strerror(errno));
exit(1);
}
memcpy(_argv, argv, (size_t)argc);
execv(scriptpath, (char *const *)_argv);
warnmsg(LOG_ERR, __func__, "child: exec failed: %s",
strerror(errno));
exit(0);
exit(1);
}
return;
@ -471,3 +790,37 @@ safefile(const char *path)
return (0);
}
/* Decode domain name label encoding in RFC 1035 Section 3.1 */
static size_t
dname_labeldec(char *dst, size_t dlen, const char *src)
{
size_t len;
const char *src_origin;
const char *src_last;
const char *dst_origin;
src_origin = src;
src_last = strchr(src, '\0');
dst_origin = dst;
memset(dst, '\0', dlen);
while (src && (len = (uint8_t)(*src++) & 0x3f) &&
(src + len) <= src_last) {
if (dst != dst_origin)
*dst++ = '.';
warnmsg(LOG_DEBUG, __func__, "labellen = %zd", len);
memcpy(dst, src, len);
src += len;
dst += len;
}
*dst = '\0';
/*
* XXX validate that domain name only contains valid characters
* for two reasons: 1) correctness, 2) we do not want to pass
* possible malicious, unescaped characters like `` to a script
* or program that could be exploited that way.
*/
return (src - src_origin);
}

View File

@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd September 2, 2009
.Dd May 28, 2011
.Dt RTSOLD 8
.Os
.\"
@ -41,18 +41,24 @@
.Nm
.Op Fl dDfFm1
.Op Fl O Ar script-name
.Op Fl P Ar pidfile
.Op Fl R Ar script-name
.Ar interface ...
.Nm
.Op Fl dDfFm1
.Op Fl O Ar script-name
.Op Fl P Ar pidfile
.Op Fl R Ar script-name
.Fl a
.Nm rtsol
.Op Fl dDF
.Op Fl dD
.Op Fl O Ar script-name
.Op Fl R Ar script-name
.Ar interface ...
.Nm rtsol
.Op Fl dD
.Op Fl O Ar script-name
.Op Fl R Ar script-name
.Fl a
.\"
.Sh DESCRIPTION
@ -221,6 +227,24 @@ configuration.
must be the absolute path from root to the script file, be a regular
file, and be created by the same owner who runs
.Nm .
.It Fl P Ar pidfile
Writes the process ID of
.Nm
to
.Pa pidfile
instead of the default PID file
.Pa /var/run/rtsold.pid .
.It Fl R Ar script-name
Specifies a script to run when router advertisment options
.Dv RDNSS Pq Recursive DNS Server
or
.Dv DNSSL Pq DNS Search List
are encountered.
The information of DNS servers and DNS search domains will be sent to
standard input of this script.
The
.Xr resolvconf 8
script is used by default.
.El
.Sh FILES
.Bl -tag -width /var/run/rtsold.dump -compact
@ -235,6 +259,7 @@ dumps internal state on.
.Ex -std
.\"
.Sh SEE ALSO
.Xr resolvconf 8 ,
.Xr rtadvd 8 ,
.Xr sysctl 8
.\"

View File

@ -63,6 +63,9 @@
#include "rtsold.h"
#define RTSOL_DUMPFILE "/var/run/rtsold.dump";
#define RTSOL_PIDFILE "/var/run/rtsold.pid";
struct ifinfo *iflist;
struct timeval tm_max = {0x7fffffff, 0x7fffffff};
static int log_upto = 999;
@ -72,7 +75,8 @@ int Fflag = 0; /* force setting sysctl parameters */
int aflag = 0;
int dflag = 0;
char *otherconf_script;
const char *otherconf_script;
const char *resolvconf_script = "/sbin/resolvconf";
/* protocol constants */
#define MAX_RTR_SOLICITATION_DELAY 1 /* second */
@ -85,35 +89,32 @@ char *otherconf_script;
*/
#define PROBE_INTERVAL 60
int main(int, char **);
/* static variables and functions */
static int mobile_node = 0;
static const char *pidfilename = RTSOL_PIDFILE;
#ifndef SMALL
static int do_dump;
static const char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */
#endif
#if 1
static const char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */
static const char *dumpfilename = RTSOL_DUMPFILE;
#endif
#if 0
static int ifreconfig(char *);
#endif
static int make_packet(struct ifinfo *);
static struct timeval *rtsol_check_timer(void);
#ifndef SMALL
static void rtsold_set_dump_file(int);
#endif
static void usage(char *);
static void usage(void);
int
main(int argc, char **argv)
{
int s, ch, once = 0;
struct timeval *timeout;
char *argv0;
const char *opts;
#ifdef HAVE_POLL_H
struct pollfd set[2];
@ -124,19 +125,15 @@ main(int argc, char **argv)
#endif
int rtsock;
/*
* Initialization
*/
argv0 = argv[0];
/* get option */
if (argv0 && argv0[strlen(argv0) - 1] != 'd') {
fflag = 1;
once = 1;
opts = "adDFO:";
} else
opts = "adDfFm1O:";
#ifndef SMALL
/* rtsold */
opts = "adDfFm1O:P:R:";
#else
/* rtsol */
opts = "adDFO:P:R:";
fflag = 1;
once = 1;
#endif
while ((ch = getopt(argc, argv, opts)) != -1) {
switch (ch) {
case 'a':
@ -163,17 +160,23 @@ main(int argc, char **argv)
case 'O':
otherconf_script = optarg;
break;
case 'P':
pidfilename = optarg;
break;
case 'R':
resolvconf_script = optarg;
break;
default:
usage(argv0);
/*NOTREACHED*/
usage();
exit(1);
}
}
argc -= optind;
argv += optind;
if ((!aflag && argc == 0) || (aflag && argc != 0)) {
usage(argv0);
/*NOTREACHED*/
usage();
exit(1);
}
/* set log level */
@ -182,9 +185,9 @@ main(int argc, char **argv)
if (!fflag) {
char *ident;
ident = strrchr(argv0, '/');
ident = strrchr(argv[0], '/');
if (!ident)
ident = argv0;
ident = argv[0];
else
ident++;
openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
@ -196,7 +199,14 @@ main(int argc, char **argv)
errx(1, "configuration script (%s) must be an absolute path",
otherconf_script);
}
if (resolvconf_script && *resolvconf_script != '/') {
errx(1, "configuration script (%s) must be an absolute path",
resolvconf_script);
}
if (pidfilename && *pidfilename != '/') {
errx(1, "pid filename (%s) must be an absolute path",
pidfilename);
}
#ifndef HAVE_ARC4RANDOM
/* random value initialization */
srandom((u_long)time(NULL));
@ -226,7 +236,6 @@ main(int argc, char **argv)
if ((s = sockopen()) < 0) {
warnmsg(LOG_ERR, __func__, "failed to open a socket");
exit(1);
/*NOTREACHED*/
}
#ifdef HAVE_POLL_H
set[0].fd = s;
@ -242,7 +251,6 @@ main(int argc, char **argv)
if ((rtsock = rtsock_open()) < 0) {
warnmsg(LOG_ERR, __func__, "failed to open a socket");
exit(1);
/*NOTREACHED*/
}
#ifdef HAVE_POLL_H
set[1].fd = rtsock;
@ -255,12 +263,12 @@ main(int argc, char **argv)
#ifndef HAVE_POLL_H
fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
if ((fdsetp = malloc(fdmasks)) == NULL) {
err(1, "malloc");
/*NOTREACHED*/
warnmsg(LOG_ERR, __func__, "malloc");
exit(1);
}
if ((selectfdp = malloc(fdmasks)) == NULL) {
err(1, "malloc");
/*NOTREACHED*/
warnmsg(LOG_ERR, __func__, "malloc");
exit(1);
}
#endif
@ -269,7 +277,6 @@ main(int argc, char **argv)
warnmsg(LOG_ERR, __func__,
"failed to initialize interfaces");
exit(1);
/*NOTREACHED*/
}
if (aflag)
argv = autoifprobe();
@ -278,7 +285,6 @@ main(int argc, char **argv)
warnmsg(LOG_ERR, __func__,
"failed to initialize %s", *argv);
exit(1);
/*NOTREACHED*/
}
argv++;
}
@ -291,7 +297,6 @@ main(int argc, char **argv)
/*NOTREACHED*/
}
#if 1
/* dump the current pid */
if (!once) {
pid_t pid = getpid();
@ -306,8 +311,6 @@ main(int argc, char **argv)
fclose(fp);
}
}
#endif
#ifndef HAVE_POLL_H
memset(fdsetp, 0, fdmasks);
FD_SET(s, fdsetp);
@ -337,7 +340,7 @@ main(int argc, char **argv)
break;
/* if all interfaces have got RA packet, we are done */
for (ifi = iflist; ifi; ifi = ifi->next) {
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (ifi->state != IFS_DOWN && ifi->racnt == 0)
break;
}
@ -373,102 +376,97 @@ main(int argc, char **argv)
}
/* NOTREACHED */
return 0;
return (0);
}
int
ifconfig(char *ifname)
{
struct ifinfo *ifinfo;
struct ifinfo *ifi;
struct sockaddr_dl *sdl;
int flags;
if ((sdl = if_nametosdl(ifname)) == NULL) {
warnmsg(LOG_ERR, __func__,
"failed to get link layer information for %s", ifname);
return(-1);
return (-1);
}
if (find_ifinfo(sdl->sdl_index)) {
warnmsg(LOG_ERR, __func__,
"interface %s was already configured", ifname);
free(sdl);
return(-1);
return (-1);
}
if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) {
if ((ifi = malloc(sizeof(*ifi))) == NULL) {
warnmsg(LOG_ERR, __func__, "memory allocation failed");
free(sdl);
return(-1);
return (-1);
}
memset(ifinfo, 0, sizeof(*ifinfo));
ifinfo->sdl = sdl;
memset(ifi, 0, sizeof(*ifi));
ifi->sdl = sdl;
strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname));
strlcpy(ifi->ifname, ifname, sizeof(ifi->ifname));
/* construct a router solicitation message */
if (make_packet(ifinfo))
if (make_packet(ifi))
goto bad;
/* set link ID of this interface. */
#ifdef HAVE_SCOPELIB
if (inet_zoneid(AF_INET6, 2, ifname, &ifinfo->linkid))
if (inet_zoneid(AF_INET6, 2, ifname, &ifi->linkid))
goto bad;
#else
/* XXX: assume interface IDs as link IDs */
ifinfo->linkid = ifinfo->sdl->sdl_index;
ifi->linkid = ifi->sdl->sdl_index;
#endif
/*
* check if the interface is available.
* also check if SIOCGIFMEDIA ioctl is OK on the interface.
*/
ifinfo->mediareqok = 1;
ifinfo->active = interface_status(ifinfo);
if (!ifinfo->mediareqok) {
ifi->mediareqok = 1;
ifi->active = interface_status(ifi);
if (!ifi->mediareqok) {
/*
* probe routers periodically even if the link status
* does not change.
*/
ifinfo->probeinterval = PROBE_INTERVAL;
ifi->probeinterval = PROBE_INTERVAL;
}
/* activate interface: interface_up returns 0 on success */
flags = interface_up(ifinfo->ifname);
flags = interface_up(ifi->ifname);
if (flags == 0)
ifinfo->state = IFS_DELAY;
ifi->state = IFS_DELAY;
else if (flags == IFS_TENTATIVE)
ifinfo->state = IFS_TENTATIVE;
ifi->state = IFS_TENTATIVE;
else
ifinfo->state = IFS_DOWN;
ifi->state = IFS_DOWN;
rtsol_timer_update(ifinfo);
rtsol_timer_update(ifi);
/* link into chain */
if (iflist)
ifinfo->next = iflist;
iflist = ifinfo;
return(0);
TAILQ_INSERT_TAIL(&ifinfo_head, ifi, ifi_next);
return (0);
bad:
free(ifinfo->sdl);
free(ifinfo);
return(-1);
free(ifi->sdl);
free(ifi);
return (-1);
}
void
iflist_init(void)
{
struct ifinfo *ifi, *next;
struct ifinfo *ifi;
for (ifi = iflist; ifi; ifi = next) {
next = ifi->next;
if (ifi->sdl)
while ((ifi = TAILQ_FIRST(&ifinfo_head)) != NULL) {
TAILQ_REMOVE(&ifinfo_head, ifi, ifi_next);
if (ifi->sdl != NULL)
free(ifi->sdl);
if (ifi->rs_data)
if (ifi->rs_data != NULL)
free(ifi->rs_data);
free(ifi);
iflist = NULL;
}
}
@ -480,7 +478,7 @@ ifreconfig(char *ifname)
int rv;
prev = NULL;
for (ifi = iflist; ifi; ifi = ifi->next) {
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0)
break;
prev = ifi;
@ -494,7 +492,8 @@ ifreconfig(char *ifname)
free(ifi->rs_data);
free(ifi->sdl);
free(ifi);
return rv;
return (rv);
}
#endif
@ -503,34 +502,35 @@ find_ifinfo(int ifindex)
{
struct ifinfo *ifi;
for (ifi = iflist; ifi; ifi = ifi->next)
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (ifi->sdl->sdl_index == ifindex)
return(ifi);
return(NULL);
return (ifi);
}
return (NULL);
}
static int
make_packet(struct ifinfo *ifinfo)
make_packet(struct ifinfo *ifi)
{
size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0;
struct nd_router_solicit *rs;
char *buf;
if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) {
if ((lladdroptlen = lladdropt_length(ifi->sdl)) == 0) {
warnmsg(LOG_INFO, __func__,
"link-layer address option has null length"
" on %s. Treat as not included.", ifinfo->ifname);
" on %s. Treat as not included.", ifi->ifname);
}
packlen += lladdroptlen;
ifinfo->rs_datalen = packlen;
ifi->rs_datalen = packlen;
/* allocate buffer */
if ((buf = malloc(packlen)) == NULL) {
warnmsg(LOG_ERR, __func__,
"memory allocation failed for %s", ifinfo->ifname);
return(-1);
"memory allocation failed for %s", ifi->ifname);
return (-1);
}
ifinfo->rs_data = buf;
ifi->rs_data = buf;
/* fill in the message */
rs = (struct nd_router_solicit *)buf;
@ -542,9 +542,9 @@ make_packet(struct ifinfo *ifinfo)
/* fill in source link-layer address option */
if (lladdroptlen)
lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf);
lladdropt_fill(ifi->sdl, (struct nd_opt_hdr *)buf);
return(0);
return (0);
}
static struct timeval *
@ -552,56 +552,64 @@ rtsol_check_timer(void)
{
static struct timeval returnval;
struct timeval now, rtsol_timer;
struct ifinfo *ifinfo;
struct ifinfo *ifi;
struct ra_opt *rao;
int flags;
gettimeofday(&now, NULL);
rtsol_timer = tm_max;
for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
if (timercmp(&ifinfo->expire, &now, <=)) {
TAILQ_FOREACH(ifi, &ifinfo_head, ifi_next) {
if (timercmp(&ifi->expire, &now, <=)) {
if (dflag > 1)
warnmsg(LOG_DEBUG, __func__,
"timer expiration on %s, "
"state = %d", ifinfo->ifname,
ifinfo->state);
"state = %d", ifi->ifname,
ifi->state);
switch (ifinfo->state) {
/* Remove all RA options. */
while ((rao = TAILQ_FIRST(&ifi->ifi_ra_opt)) != NULL) {
if (rao->rao_msg != NULL)
free(rao->rao_msg);
TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
free(rao);
}
switch (ifi->state) {
case IFS_DOWN:
case IFS_TENTATIVE:
/* interface_up returns 0 on success */
flags = interface_up(ifinfo->ifname);
flags = interface_up(ifi->ifname);
if (flags == 0)
ifinfo->state = IFS_DELAY;
ifi->state = IFS_DELAY;
else if (flags == IFS_TENTATIVE)
ifinfo->state = IFS_TENTATIVE;
ifi->state = IFS_TENTATIVE;
else
ifinfo->state = IFS_DOWN;
ifi->state = IFS_DOWN;
break;
case IFS_IDLE:
{
int oldstatus = ifinfo->active;
int oldstatus = ifi->active;
int probe = 0;
ifinfo->active = interface_status(ifinfo);
ifi->active = interface_status(ifi);
if (oldstatus != ifinfo->active) {
if (oldstatus != ifi->active) {
warnmsg(LOG_DEBUG, __func__,
"%s status is changed"
" from %d to %d",
ifinfo->ifname,
oldstatus, ifinfo->active);
ifi->ifname,
oldstatus, ifi->active);
probe = 1;
ifinfo->state = IFS_DELAY;
} else if (ifinfo->probeinterval &&
(ifinfo->probetimer -=
ifinfo->timer.tv_sec) <= 0) {
ifi->state = IFS_DELAY;
} else if (ifi->probeinterval &&
(ifi->probetimer -=
ifi->timer.tv_sec) <= 0) {
/* probe timer expired */
ifinfo->probetimer =
ifinfo->probeinterval;
ifi->probetimer =
ifi->probeinterval;
probe = 1;
ifinfo->state = IFS_PROBE;
ifi->state = IFS_PROBE;
}
/*
@ -609,38 +617,58 @@ rtsol_check_timer(void)
* status wrt the "other" configuration.
*/
if (probe)
ifinfo->otherconfig = 0;
ifi->otherconfig = 0;
if (probe && mobile_node)
defrouter_probe(ifinfo);
defrouter_probe(ifi);
break;
}
case IFS_DELAY:
ifinfo->state = IFS_PROBE;
sendpacket(ifinfo);
ifi->state = IFS_PROBE;
sendpacket(ifi);
break;
case IFS_PROBE:
if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
sendpacket(ifinfo);
if (ifi->probes < MAX_RTR_SOLICITATIONS)
sendpacket(ifi);
else {
warnmsg(LOG_INFO, __func__,
"No answer after sending %d RSs",
ifinfo->probes);
ifinfo->probes = 0;
ifinfo->state = IFS_IDLE;
ifi->probes);
ifi->probes = 0;
ifi->state = IFS_IDLE;
}
break;
}
rtsol_timer_update(ifinfo);
}
rtsol_timer_update(ifi);
} else {
/* Expiration check for RA options. */
struct ra_opt *rao_tmp;
int expire = 0;
if (timercmp(&ifinfo->expire, &rtsol_timer, <))
rtsol_timer = ifinfo->expire;
TAILQ_FOREACH_SAFE(rao, &ifi->ifi_ra_opt, rao_next, rao_tmp) {
warnmsg(LOG_DEBUG, __func__,
"RA expiration timer: "
"type=%d, msg=%s, timer=%ld:%08ld",
rao->rao_type, (char *)rao->rao_msg,
(long)rao->rao_expire.tv_sec,
(long)rao->rao_expire.tv_usec);
if (timercmp(&now, &rao->rao_expire, >=)) {
warnmsg(LOG_DEBUG, __func__,
"RA expiration timer: expired.");
TAILQ_REMOVE(&ifi->ifi_ra_opt, rao, rao_next);
expire = 1;
}
}
if (expire)
ra_opt_handler(ifi);
}
if (timercmp(&ifi->expire, &rtsol_timer, <))
rtsol_timer = ifi->expire;
}
if (timercmp(&rtsol_timer, &tm_max, ==)) {
warnmsg(LOG_DEBUG, __func__, "there is no timer");
return(NULL);
return (NULL);
} else if (timercmp(&rtsol_timer, &now, <))
/* this may occur when the interval is too small */
returnval.tv_sec = returnval.tv_usec = 0;
@ -651,35 +679,35 @@ rtsol_check_timer(void)
warnmsg(LOG_DEBUG, __func__, "New timer is %ld:%08ld",
(long)returnval.tv_sec, (long)returnval.tv_usec);
return(&returnval);
return (&returnval);
}
void
rtsol_timer_update(struct ifinfo *ifinfo)
rtsol_timer_update(struct ifinfo *ifi)
{
#define MILLION 1000000
#define DADRETRY 10 /* XXX: adhoc */
long interval;
struct timeval now;
bzero(&ifinfo->timer, sizeof(ifinfo->timer));
bzero(&ifi->timer, sizeof(ifi->timer));
switch (ifinfo->state) {
switch (ifi->state) {
case IFS_DOWN:
case IFS_TENTATIVE:
if (++ifinfo->dadcount > DADRETRY) {
ifinfo->dadcount = 0;
ifinfo->timer.tv_sec = PROBE_INTERVAL;
if (++ifi->dadcount > DADRETRY) {
ifi->dadcount = 0;
ifi->timer.tv_sec = PROBE_INTERVAL;
} else
ifinfo->timer.tv_sec = 1;
ifi->timer.tv_sec = 1;
break;
case IFS_IDLE:
if (mobile_node) {
/* XXX should be configurable */
ifinfo->timer.tv_sec = 3;
ifi->timer.tv_sec = 3;
}
else
ifinfo->timer = tm_max; /* stop timer(valid?) */
ifi->timer = tm_max; /* stop timer(valid?) */
break;
case IFS_DELAY:
#ifndef HAVE_ARC4RANDOM
@ -687,12 +715,12 @@ rtsol_timer_update(struct ifinfo *ifinfo)
#else
interval = arc4random_uniform(MAX_RTR_SOLICITATION_DELAY * MILLION);
#endif
ifinfo->timer.tv_sec = interval / MILLION;
ifinfo->timer.tv_usec = interval % MILLION;
ifi->timer.tv_sec = interval / MILLION;
ifi->timer.tv_usec = interval % MILLION;
break;
case IFS_PROBE:
if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
if (ifi->probes < MAX_RTR_SOLICITATIONS)
ifi->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
else {
/*
* After sending MAX_RTR_SOLICITATIONS solicitations,
@ -701,30 +729,30 @@ rtsol_timer_update(struct ifinfo *ifinfo)
* the timer value to MAX_RTR_SOLICITATION_DELAY based
* on RFC 2461, Section 6.3.7.
*/
ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
ifi->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
}
break;
default:
warnmsg(LOG_ERR, __func__,
"illegal interface state(%d) on %s",
ifinfo->state, ifinfo->ifname);
ifi->state, ifi->ifname);
return;
}
/* reset the timer */
if (timercmp(&ifinfo->timer, &tm_max, ==)) {
ifinfo->expire = tm_max;
if (timercmp(&ifi->timer, &tm_max, ==)) {
ifi->expire = tm_max;
warnmsg(LOG_DEBUG, __func__,
"stop timer for %s", ifinfo->ifname);
"stop timer for %s", ifi->ifname);
} else {
gettimeofday(&now, NULL);
timeradd(&now, &ifinfo->timer, &ifinfo->expire);
timeradd(&now, &ifi->timer, &ifi->expire);
if (dflag > 1)
warnmsg(LOG_DEBUG, __func__,
"set timer for %s to %d:%d", ifinfo->ifname,
(int)ifinfo->timer.tv_sec,
(int)ifinfo->timer.tv_usec);
"set timer for %s to %d:%d", ifi->ifname,
(int)ifi->timer.tv_sec,
(int)ifi->timer.tv_usec);
}
#undef MILLION
@ -742,28 +770,23 @@ rtsold_set_dump_file(int sig __unused)
#endif
static void
usage(char *progname)
usage(void)
{
if (progname && progname[strlen(progname) - 1] != 'd') {
fprintf(stderr, "usage: rtsol [-dDF] interfaces...\n");
fprintf(stderr, "usage: rtsol [-dDF] -a\n");
} else {
fprintf(stderr, "usage: rtsold [-adDfFm1] interfaces...\n");
fprintf(stderr, "usage: rtsold [-dDfFm1] -a\n");
}
exit(1);
#ifndef SMALL
fprintf(stderr, "usage: rtsold [-adDfFm1] [-O script-name] "
"[-P pidfile] [-R script-name] interfaces...\n");
fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
"[-P pidfile] [-R script-name] -a\n");
#else
fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
"[-P pidfile] [-R script-name] interfaces...\n");
fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
"[-P pidfile] [-R script-name] -a\n");
#endif
}
void
#if __STDC__
warnmsg(int priority, const char *func, const char *msg, ...)
#else
warnmsg(priority, func, msg, va_alist)
int priority;
const char *func;
const char *msg;
va_dcl
#endif
{
va_list ap;
char buf[BUFSIZ];
@ -805,11 +828,11 @@ autoifprobe(void)
n = 0;
if (getifaddrs(&ifap) != 0)
return NULL;
return (NULL);
if (!Fflag && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
err(1, "socket");
/* NOTREACHED */
warnmsg(LOG_ERR, __func__, "socket");
exit(1);
}
target = NULL;
@ -845,8 +868,9 @@ autoifprobe(void)
memset(&nd, 0, sizeof(nd));
strlcpy(nd.ifname, ifa->ifa_name, sizeof(nd.ifname));
if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
err(1, "ioctl(SIOCGIFINFO_IN6)");
/* NOTREACHED */
warnmsg(LOG_ERR, __func__,
"ioctl(SIOCGIFINFO_IN6)");
exit(1);
}
if ((nd.ndi.flags & ND6_IFF_IFDISABLED))
continue;
@ -856,32 +880,40 @@ autoifprobe(void)
/* if we find multiple candidates, just warn. */
if (n != 0 && dflag > 1)
warnx("multiple interfaces found");
warnmsg(LOG_WARNING, __func__,
"multiple interfaces found");
a = (char **)realloc(argv, (n + 1) * sizeof(char **));
if (a == NULL)
err(1, "realloc");
if (a == NULL) {
warnmsg(LOG_ERR, __func__, "realloc");
exit(1);
}
argv = a;
argv[n] = strdup(ifa->ifa_name);
if (!argv[n])
err(1, "malloc");
if (!argv[n]) {
warnmsg(LOG_ERR, __func__, "malloc");
exit(1);
}
n++;
}
if (n) {
a = (char **)realloc(argv, (n + 1) * sizeof(char **));
if (a == NULL)
err(1, "realloc");
if (a == NULL) {
warnmsg(LOG_ERR, __func__, "realloc");
exit(1);
}
argv = a;
argv[n] = NULL;
if (dflag > 0) {
for (i = 0; i < n; i++)
warnx("probing %s", argv[i]);
warnmsg(LOG_WARNING, __func__, "probing %s",
argv[i]);
}
}
if (!Fflag)
close(s);
freeifaddrs(ifap);
return argv;
return (argv);
}

View File

@ -31,8 +31,23 @@
* $FreeBSD$
*/
struct script_msg {
TAILQ_ENTRY(script_msg) sm_next;
char *sm_msg;
};
struct ra_opt {
TAILQ_ENTRY(ra_opt) rao_next;
u_int8_t rao_type;
struct timeval rao_expire;
size_t rao_len;
void *rao_msg;
};
struct ifinfo {
struct ifinfo *next; /* pointer to the next interface */
TAILQ_ENTRY(ifinfo) ifi_next; /* pointer to the next interface */
struct sockaddr_dl *sdl; /* link-layer address */
char ifname[IF_NAMESIZE]; /* interface name */
@ -54,6 +69,8 @@ struct ifinfo {
size_t rs_datalen;
u_char *rs_data;
TAILQ_HEAD(, ra_opt) ifi_ra_opt;
};
/* per interface status */
@ -63,12 +80,41 @@ struct ifinfo {
#define IFS_DOWN 3
#define IFS_TENTATIVE 4
/* Interface list */
extern TAILQ_HEAD(ifinfo_head_t, ifinfo) ifinfo_head;
/*
* RFC 3542 API deprecates IPV6_PKTINFO in favor of
* IPV6_RECVPKTINFO
*/
#ifndef IPV6_RECVPKTINFO
#ifdef IPV6_PKTINFO
#define IPV6_RECVPKTINFO IPV6_PKTINFO
#endif
#endif
/*
* RFC 3542 API deprecates IPV6_HOPLIMIT in favor of
* IPV6_RECVHOPLIMIT
*/
#ifndef IPV6_RECVHOPLIMIT
#ifdef IPV6_HOPLIMIT
#define IPV6_RECVHOPLIMIT IPV6_HOPLIMIT
#endif
#endif
#ifndef IN6ADDR_LINKLOCAL_ALLROUTERS_INIT
#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \
{{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}}
#endif
/* rtsold.c */
extern struct timeval tm_max;
extern int dflag;
extern int aflag;
extern int Fflag;
extern char *otherconf_script;
extern const char *otherconf_script;
extern const char *resolvconf_script;
extern int ifconfig(char *);
extern void iflist_init(void);
struct ifinfo *find_ifinfo(int);
@ -76,6 +122,7 @@ void rtsol_timer_update(struct ifinfo *);
extern void warnmsg(int, const char *, const char *, ...)
__attribute__((__format__(__printf__, 3, 4)));
extern char **autoifprobe(void);
extern int ra_opt_handler(struct ifinfo *);
/* if.c */
extern int ifinit(void);