* The mrouted program is covered by the license in the accompanying file
* named "LICENSE". Use of the mrouted program represents acceptance of
* the terms and conditions listed in that file.
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
* $Id: config.c,v 1.3 1993/05/30 01:36:38 deering Exp $
char *configfilename
= "/etc/mrouted.conf";
static char *next_word();
* Query the kernel to find network interfaces that are multicast-capable
* and install them in the uvifs array.
void config_vifs_from_kernel()
struct ifreq
*ifrp
, *ifend
, *mp
;
u_long addr
, mask
, subnet
;
ifc
.ifc_buf
= (char *)ifbuf
;
ifc
.ifc_len
= sizeof(ifbuf
);
if (ioctl(udp_socket
, SIOCGIFCONF
, (char *)&ifc
) < 0)
log(LOG_ERR
, errno
, "ioctl SIOCGIFCONF");
ifrp
= (struct ifreq
*)ifbuf
;
ifend
= (struct ifreq
*)((char *)ifbuf
+ ifc
.ifc_len
);
* Loop through all of the interfaces.
for (; ifrp
< ifend
; ifrp
= (struct ifreq
*)((char *)ifrp
+ n
)) {
n
= ifrp
->ifr_addr
.sa_len
+ sizeof(ifrp
->ifr_name
);
* Ignore any interface for an address family other than IP.
addr
= ((struct sockaddr_in
*)&ifrp
->ifr_addr
)->sin_addr
.s_addr
;
if (ifrp
->ifr_addr
.sa_family
!= AF_INET
)
* Need a template to preserve address info that is
* used below to locate the next entry. (Otherwise,
* SIOCGIFFLAGS stomps over it because the requests
* are returned in a union.)
bcopy(ifrp
->ifr_name
, ifr
.ifr_name
, sizeof(ifr
.ifr_name
));
* Ignore loopback interfaces and interfaces that do not support
if (ioctl(udp_socket
, SIOCGIFFLAGS
, (char *)&ifr
) < 0)
log(LOG_ERR
, errno
, "ioctl SIOCGIFFLAGS for %s", ifr
.ifr_name
);
if ((flags
& (IFF_LOOPBACK
|IFF_MULTICAST
)) != IFF_MULTICAST
) continue;
* Ignore any interface whose address and mask do not define a
* valid subnet number, or whose address is of the form {subnet,0}
if (ioctl(udp_socket
, SIOCGIFNETMASK
, (char *)&ifr
) < 0)
log(LOG_ERR
, errno
, "ioctl SIOCGIFNETMASK for %s", ifr
.ifr_name
);
mask
= ((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_addr
.s_addr
;
if (!inet_valid_subnet(subnet
, mask
) ||
addr
== (subnet
| ~mask
)) {
"ignoring %s, has invalid address (%s) and/or mask (%08x)",
ifr
.ifr_name
, inet_fmt(addr
, s1
), ntohl(mask
));
* Ignore any interface that is connected to the same subnet as
* one already installed in the uvifs array.
for (vifi
= 0, v
= uvifs
; vifi
< numvifs
; ++vifi
, ++v
) {
if ((addr
& v
->uv_subnetmask
) == v
->uv_subnet
||
(v
->uv_subnet
& mask
) == subnet
) {
log(LOG_WARNING
, 0, "ignoring %s, same subnet as %s",
ifr
.ifr_name
, v
->uv_name
);
if (vifi
!= numvifs
) continue;
* If there is room in the uvifs array, install this interface.
if (numvifs
== MAXVIFS
) {
log(LOG_WARNING
, 0, "too many vifs, ignoring %s", ifr
.ifr_name
);
v
->uv_metric
= DEFAULT_METRIC
;
v
->uv_threshold
= DEFAULT_THRESHOLD
;
v
->uv_subnetbcast
= subnet
| ~mask
;
strncpy(v
->uv_name
, ifr
.ifr_name
, IFNAMSIZ
);
log(LOG_INFO
, 0, "installing %s (%s on subnet %s) as vif #%u",
v
->uv_name
, inet_fmt(addr
, s1
), inet_fmts(subnet
, mask
, s2
),
* If the interface is not yet up, set the vifs_down flag to
* remind us to check again later.
v
->uv_flags
|= VIFF_DOWN
;
struct ifreq
*ifrp
= (struct ifreq
*)ifcp
->ifc_buf
;
struct ifreq
*ifend
= (struct ifreq
*)((char *)ifrp
+ ifcp
->ifc_len
);
if (ifrp
->ifr_addr
.sa_family
== AF_INET
&&
((struct sockaddr_in
*)&ifrp
->ifr_addr
)->sin_addr
.s_addr
== a
)
n
= ifrp
->ifr_addr
.sa_len
+ sizeof(ifrp
->ifr_name
);
ifrp
= (struct ifreq
*)((char *)ifrp
+ n
);
* Read the config file to learn about tunnel vifs and
* non-default phyint parameters.
void config_vifs_from_file()
u_long lcl_addr
, rmt_addr
;
f
= fopen(configfilename
, "r");
log(LOG_WARNING
, errno
, "can't open %s", configfilename
);
ifc
.ifc_buf
= (char *)ifbuf
;
ifc
.ifc_len
= sizeof(ifbuf
);
if (ioctl(udp_socket
, SIOCGIFCONF
, (char *)&ifc
) < 0)
log(LOG_ERR
, errno
, "ioctl SIOCGIFCONF");
while (fgets(linebuf
, sizeof(linebuf
), f
) != NULL
) {
if (EQUAL((w
= next_word(&s
)), "")) {
* blank or comment line; ignore
else if (EQUAL(w
, "phyint")) {
* phyint <local-addr> [disable] [metric <m>] [threshold <t>]
* Parse the local address.
if (EQUAL((w
= next_word(&s
)), "")) {
"missing phyint address in %s",
if ((lcl_addr
= inet_parse(w
)) == 0xffffffff ||
!inet_valid_host(lcl_addr
)) {
"invalid phyint address '%s' in %s",
* Look up the vif with the specified local address.
for (vifi
= 0, v
= uvifs
; vifi
< numvifs
; ++vifi
, ++v
) {
if (!(v
->uv_flags
& VIFF_TUNNEL
) &&
lcl_addr
== v
->uv_lcl_addr
) {
"phyint %s in %s is not a configured interface",
inet_fmt(lcl_addr
, s1
), configfilename
);
* Look for "disable", "metric" and "threshold" options.
while (!EQUAL((w
= next_word(&s
)), "")) {
if (EQUAL(w
, "disable")) {
v
->uv_flags
|= VIFF_DISABLED
;
else if (EQUAL(w
, "metric")) {
if(EQUAL((w
= next_word(&s
)), "")) {
"missing metric for phyint %s in %s",
inet_fmt(lcl_addr
, s1
), configfilename
);
if(sscanf(w
, "%u%c", &n
, &c
) != 1 ||
n
< 1 || n
>= UNREACHABLE
) {
"invalid metric '%s' for phyint %s in %s",
w
, inet_fmt(lcl_addr
, s1
), configfilename
);
else if (EQUAL(w
, "threshold")) {
if(EQUAL((w
= next_word(&s
)), "")) {
"missing threshold for phyint %s in %s",
inet_fmt(lcl_addr
, s1
), configfilename
);
if(sscanf(w
, "%u%c", &n
, &c
) != 1 ||
"invalid threshold '%s' for phyint %s in %s",
w
, inet_fmt(lcl_addr
, s1
), configfilename
);
if (!EQUAL(w
, "")) continue;
else if (EQUAL(w
, "tunnel")) {
* tunnel <local-addr> <remote-addr> [srcrt] [metric <m>] [threshold <t>]
* Parse the local address.
if (EQUAL((w
= next_word(&s
)), "")) {
"missing tunnel local address in %s",
if ((lcl_addr
= inet_parse(w
)) == 0xffffffff ||
!inet_valid_host(lcl_addr
)) {
"invalid tunnel local address '%s' in %s",
* Make sure the local address is one of ours.
ifr
= ifconfaddr(&ifc
, lcl_addr
);
"tunnel local address %s in %s is not one of ours",
inet_fmt(lcl_addr
, s1
), configfilename
);
* Make sure the local address doesn't name a loopback interface..
strncpy(ffr
.ifr_name
, ifr
->ifr_name
, IFNAMSIZ
);
if (ioctl(udp_socket
, SIOCGIFFLAGS
, (char *)&ffr
) < 0) {
"ioctl SIOCGIFFLAGS for %s", ffr
.ifr_name
);
if (ffr
.ifr_flags
& IFF_LOOPBACK
) {
"tunnel local address %s in %s is a loopback interface",
inet_fmt(lcl_addr
, s1
), configfilename
);
* Parse the remote address.
if (EQUAL((w
= next_word(&s
)), "")) {
"missing tunnel remote address in %s",
if ((rmt_addr
= inet_parse(w
)) == 0xffffffff ||
!inet_valid_host(rmt_addr
)) {
"invalid tunnel remote address %s in %s",
* Make sure the remote address is not one of ours.
if (ifconfaddr(&ifc
, rmt_addr
) != 0) {
"tunnel remote address %s in %s is one of ours",
inet_fmt(rmt_addr
, s1
), configfilename
);
* Make sure the remote address has not been used for another
* tunnel and does not belong to a subnet to which we have direct
* access on an enabled phyint.
for (vifi
= 0, v
= uvifs
; vifi
< numvifs
; ++vifi
, ++v
) {
if (v
->uv_flags
& VIFF_TUNNEL
) {
if (rmt_addr
== v
->uv_rmt_addr
) {
"duplicate tunnel remote address %s in %s",
inet_fmt(rmt_addr
, s1
), configfilename
);
else if (!(v
->uv_flags
& VIFF_DISABLED
)) {
if ((rmt_addr
& v
->uv_subnetmask
) == v
->uv_subnet
) {
"unnecessary tunnel remote address %s in %s",
inet_fmt(rmt_addr
, s1
), configfilename
);
if (vifi
!= numvifs
) continue;
* OK, let's initialize a uvif structure for the tunnel.
if (numvifs
== MAXVIFS
) {
log(LOG_WARNING
, 0, "too many vifs, ignoring tunnel to %s",
v
->uv_flags
= VIFF_TUNNEL
;
v
->uv_metric
= DEFAULT_METRIC
;
v
->uv_threshold
= DEFAULT_THRESHOLD
;
v
->uv_lcl_addr
= lcl_addr
;
v
->uv_rmt_addr
= rmt_addr
;
strncpy(v
->uv_name
, ffr
.ifr_name
, IFNAMSIZ
);
* Look for "metric" and "threshold" options.
while (!EQUAL((w
= next_word(&s
)), "")) {
if (EQUAL(w
, "metric")) {
if(EQUAL((w
= next_word(&s
)), "")) {
"missing metric for tunnel to %s in %s",
inet_fmt(rmt_addr
, s1
), configfilename
);
if(sscanf(w
, "%u%c", &n
, &c
) != 1 ||
n
< 1 || n
>= UNREACHABLE
) {
"invalid metric '%s' for tunnel to %s in %s",
w
, inet_fmt(rmt_addr
, s1
), configfilename
);
else if (EQUAL(w
, "threshold")) {
if(EQUAL((w
= next_word(&s
)), "")) {
"missing threshold for tunnel to %s in %s",
inet_fmt(rmt_addr
, s1
), configfilename
);
if(sscanf(w
, "%u%c", &n
, &c
) != 1 ||
"invalid threshold '%s' for tunnel to %s in %s",
w
, inet_fmt(rmt_addr
, s1
), configfilename
);
else if (EQUAL(w
, "srcrt") || EQUAL(w
, "sourceroute")) {
v
->uv_flags
|= VIFF_SRCRT
;
if (!EQUAL(w
, "")) continue;
"installing %stunnel from %s to %s as vif #%u",
v
->uv_flags
& VIFF_SRCRT
? "srcrt " : "",
inet_fmt(lcl_addr
, s1
), inet_fmt(rmt_addr
, s2
), numvifs
);
if (!(ffr
.ifr_flags
& IFF_UP
)) {
v
->uv_flags
|= VIFF_DOWN
;
"unknown command '%s' in %s", w
, configfilename
);
* Return a pointer to the next "word" in the string to which '*s' points,
* lower-cased and null terminated, and advance '*s' to point beyond the word.
* Words are separated by blanks and/or tabs, and the input string is
* considered to terminate at a newline, '#' (comment), or null character.
* If no words remain, a pointer to a null string ("") is returned.
* Warning: This function clobbers the input string.
static char *next_word(s
)
while (*w
== ' ' || *w
== '\t')
default : if (isascii(**s
) && isupper(**s
))