mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-28 06:52:45 +00:00
- 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:
parent
77bc49858c
commit
db82af41db
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=222732
@ -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
|
||||
*/
|
||||
|
@ -23,6 +23,6 @@ LDADD= -lutil
|
||||
|
||||
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DROUTEINFO
|
||||
|
||||
WARNS?= 1
|
||||
WARNS?= 6
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -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
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
@ -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":
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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 *);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
.\"
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user