Subject: Routing question
To: None <tech-net@NetBSD.ORG>
From: Martin Husemann <martin@rumolt.teuto.de>
List: tech-net
Date: 02/23/1997 12:03:11
I stumbled accross a small problem when I got the connection to my ISP
changed from slip (via modem) to PPP (via ISDN). I have a ppp interface
always up, with a default route to that interface. When the connection
comes up pppd does address negotiation and reconfigures the interface.
Please ignore the unusual PPP setup for the moment, I have attached a
small script and demo program to see the effect without any pppd interaction.
If you have a spare ppp0 interface, just compile the program (with -o demo)
and run the script. This gives you output similar to this:
---- 8< --------- 8< --------- 8< --------- 8< --------- 8< --------- 8< -----
removing default route (if any)
ppp0 set to start configuration:
ppp0: flags=8010<POINTOPOINT,MULTICAST>
inet 194.40.112.230 --> 194.40.112.250 netmask 0xffffffff
add net default: gateway 194.40.112.250
routing table before demo program:
Routing tables
Internet:
Destination Gateway Flags
default 194.40.112.250 UG
localhost 127.0.0.1 UH
up-vision-net 192.168.110.42 UG
emmas.up-vision. 194.77.123.129 UH
194.40.112.250 194.40.112.230 UH
194.77.123.128 link#1 U
rumolt 127.0.0.1 UGH
194.77.123.143 link#1 UH
now running demo program
new ppp0 configuration:
ppp0: flags=8010<POINTOPOINT,MULTICAST>
inet 194.40.112.248 --> 194.40.112.249 netmask 0xffffffff
routing table is now:
Routing tables
Internet:
Destination Gateway Flags
default 194.40.112.250 UG
localhost 127.0.0.1 UH
up-vision-net 192.168.110.42 UG
emmas.up-vision. 194.77.123.129 UH
194.40.112.249 194.40.112.248 UH
194.77.123.128 link#1 U
rumolt 127.0.0.1 UGH
194.77.123.143 link#1 UH
---- >8 --------- >8 --------- >8 --------- >8 --------- >8 --------- >8 -----
I am wondering, if the new setup of ppp0 by the demo program should delete
the defaultroute. According to "TCP/IP Illustrated" the ioctl's should remove
all routes based on the old address. It doesn't do so for the defaultroute
obviously. This may be desirable or may not, I'm not sure.
Actualy, the case that bit me is a more subtle: Since my service provider
always assigns the same address to his side of the link I had the remote
address and the defaultroute set to the same value, that comes out of the
address negotiation. You can simulate this by changing the commented DEST
settings in the script. This leaves you with a correct default route as shown
by "route show" - but it doesn't work! I guess there are two ifaddr structs
with the same address, one with reference from the old defaultroute and no
connection to ppp0, and another from the new ppp0 configuration but no
connection to the defaultroute entry in the routing tree. You have to do
"route delete default" and then "route add default ...." with the same
address you just deleted the default route to - and magically it works again.
Yes, this is pilot-error (and I know how to modify my setup), but the
"route show" output is realy confusing!
Any comments?
Martin
The script to produce the above output:
---- 8< --------- 8< --------- 8< --------- 8< --------- 8< --------- 8< -----
#!/bin/sh
DEST=194.40.112.250
#DEST=194.40.112.249
echo "removing default route (if any)"
route delete default > /dev/null 2>&1
ifconfig ppp0 inet 194.40.112.230 $DEST netmask 255.255.255.255
echo " "
echo "ppp0 set to start configuration:"
ifconfig ppp0
route add default $DEST
echo " "
echo "routing table before demo program:"
route show
echo " "
echo "now running demo program"
./demo
echo " "
echo "new ppp0 configuration:"
ifconfig ppp0
echo " "
echo "routing table is now:"
route show
---- >8 --------- >8 --------- >8 --------- >8 --------- >8 --------- >8 -----
The program "demo.c", compile with something like (Hmm, shouldn't specify
the addresses like this, I'm on a little endian machine, swap bytes manualy
or insert hton/ntoh macros if you like. Sorry, but it's just a demo...)
cc -Wall -O2 -o demo demo.c
---- 8< --------- 8< --------- 8< --------- 8< --------- 8< --------- 8< -----
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#define SET_SA_FAMILY(addr, family) \
bzero((char *) &(addr), sizeof(addr)); \
addr.sa_family = (family); \
addr.sa_len = sizeof(addr);
#define LOCALIP 0xf87028c2
#define REMOTEIP 0xf97028c2
#define NETMASK 0xffffffff
int main()
{
int sockfd;
struct ifaliasreq ifra;
struct ifreq ifrd;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
return 1;
strncpy(ifrd.ifr_name, "ppp0", sizeof (ifrd.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifrd) < 0) {
fprintf(stderr, "interface ppp0 not configured\n");
close(sockfd);
return 1;
}
strncpy(ifra.ifra_name, "ppp0", sizeof(ifra.ifra_name));
SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = LOCALIP;
SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = REMOTEIP;
SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = NETMASK;
strncpy(ifrd.ifr_name, "ppp0", sizeof(ifrd.ifr_name));
SET_SA_FAMILY(ifrd.ifr_addr, AF_INET);
if (ioctl(sockfd, SIOCGIFADDR, (caddr_t) &ifrd) != -1)
ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifrd);
if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
if (errno != EEXIST) {
perror("Couldn't set interface address");
return 1;
}
fprintf(stderr, "Warning: Couldn't set interface address: Address already exists\n");
}
close(sockfd);
return 0;
}
---- >8 --------- >8 --------- >8 --------- >8 --------- >8 --------- >8 -----