1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-26 09:29:01 +00:00

Refactor getsysroutes. It had two ways to get routes: by reading

/proc/net/route and with libdnet. I split those into two separate functions.
This commit is contained in:
david
2009-01-01 16:45:55 +00:00
parent 516a8ddd0c
commit 9f7cffc025

275
tcpip.cc
View File

@@ -3042,6 +3042,131 @@ static int nmaskcmp(const void *a, const void *b) {
else return 1;
}
/* Read system routes from a handle to a /proc/net/route file. */
static struct sys_route *getsysroutes_proc(FILE *routefp, int *howmany) {
struct sys_route *routes = NULL;
int route_capacity = 128;
struct interface_info *ifaces;
char buf[1024];
char iface[16];
char *p, *endptr;
struct interface_info *ii;
u32 mask;
struct sockaddr_in *sin;
int numifaces = 0, numroutes = 0;
int i;
ifaces = getinterfaces(&numifaces);
routes = (struct sys_route *) safe_zalloc(route_capacity * sizeof(struct sys_route));
(void) fgets(buf, sizeof(buf), routefp); /* Kill the first line (column headers) */
while(fgets(buf,sizeof(buf), routefp)) {
p = strtok(buf, " \t\n");
if (!p) {
error("Could not find interface in /proc/net/route line");
continue;
}
if (*p == '*')
continue; /* Deleted route -- any other valid reason for
a route to start with an asterict? */
Strncpy(iface, p, sizeof(iface));
p = strtok(NULL, " \t\n");
endptr = NULL;
routes[numroutes].dest = strtoul(p, &endptr, 16);
if (!endptr || *endptr) {
error("Failed to determine Destination from /proc/net/route");
continue;
}
/* Now for the gateway */
p = strtok(NULL, " \t\n");
if (!p) break;
endptr = NULL;
routes[numroutes].gw.s_addr = strtoul(p, &endptr, 16);
if (!endptr || *endptr) {
error("Failed to determine gw for %s from /proc/net/route", iface);
}
for(i=0; i < 5; i++) {
p = strtok(NULL, " \t\n");
if (!p) break;
}
if (!p) {
error("Failed to find field %d in /proc/net/route", i + 2);
continue;
}
endptr = NULL;
routes[numroutes].netmask = strtoul(p, &endptr, 16);
if (!endptr || *endptr) {
error("Failed to determine mask from /proc/net/route");
continue;
}
for(i=0; i < numifaces; i++) {
if (!strcmp(iface, ifaces[i].devfullname)) {
routes[numroutes].device = &ifaces[i];
break;
}
}
if (i == numifaces) {
error("Failed to find device %s which was referenced in /proc/net/route", iface);
continue;
}
/* Now to deal with some alias nonsense ... at least on Linux
this file will just list the short name, even though IP
information (such as source address) from an alias must be
used. So if the purported device can't reach the gateway,
try to find a device that starts with the same short
devname, but can (e.g. eth0 -> eth0:3) */
ii = &ifaces[i];
mask = htonl((unsigned long) (0-1) << (32 - ii->netmask_bits));
sin = (struct sockaddr_in *) &ii->addr;
if (routes[numroutes].gw.s_addr && (sin->sin_addr.s_addr & mask) !=
(routes[numroutes].gw.s_addr & mask)) {
for(i=0; i < numifaces; i++) {
if (ii == &ifaces[i]) continue;
if (strcmp(ii->devname, ifaces[i].devname) == 0) {
sin = (struct sockaddr_in *) &ifaces[i].addr;
if ((sin->sin_addr.s_addr & mask) ==
(routes[numroutes].gw.s_addr & mask)) {
routes[numroutes].device = &ifaces[i];
}
}
}
}
numroutes++;
if (numroutes >= route_capacity) {
route_capacity <<= 2;
routes = (struct sys_route *) safe_realloc(routes, route_capacity * sizeof(struct sys_route));
}
}
*howmany = numroutes;
return routes;
}
/* Read system routes via libdnet. */
static struct sys_route *getsysroutes_dnet(int *howmany) {
struct dnet_collector_route_nfo dcrn;
struct interface_info *ifaces;
int numifaces = 0;
ifaces = getinterfaces(&numifaces);
dcrn.capacity = 128;
dcrn.routes = (struct sys_route *) safe_zalloc(dcrn.capacity * sizeof(struct sys_route));
dcrn.ifaces = ifaces;
dcrn.numifaces = numifaces;
dcrn.numroutes = 0;
route_t *dr = route_open();
if (!dr) fatal("%s: route_open() failed", __func__);
if (route_loop(dr, collect_dnet_routes, &dcrn) != 0) {
fatal("%s: route_loop() failed", __func__);
}
route_close(dr);
*howmany = dcrn.numroutes;
return dcrn.routes;
}
/* Parse the system routing table, converting each route into a
sys_route entry. Returns an array of sys_routes. numroutes is set
to the number of routes in the array. The routing table is only
@@ -3049,141 +3174,39 @@ static int nmaskcmp(const void *a, const void *b) {
The returned route array is sorted by netmask with the most
specific matches first. */
struct sys_route *getsysroutes(int *howmany) {
int route_capacity = 128;
static struct sys_route *routes = NULL;
static int numroutes = 0;
FILE *routefp;
char buf[1024];
char iface[16];
char *p, *endptr;
struct interface_info *ifaces;
int numifaces = 0;
int i;
u32 mask;
struct sockaddr_in *sin;
struct interface_info *ii;
if (!howmany) fatal("NULL howmany ptr passed to %s()", __func__);
if (!routes) {
routes = (struct sys_route *) safe_zalloc(route_capacity * sizeof(struct sys_route));
ifaces = getinterfaces(&numifaces);
/* First let us try Linux-style /proc/net/route */
routefp = fopen("/proc/net/route", "r");
if (routefp) {
(void) fgets(buf, sizeof(buf), routefp); /* Kill the first line (column headers) */
while(fgets(buf,sizeof(buf), routefp)) {
p = strtok(buf, " \t\n");
if (!p) {
error("Could not find interface in /proc/net/route line");
continue;
}
if (*p == '*')
continue; /* Deleted route -- any other valid reason for
a route to start with an asterict? */
Strncpy(iface, p, sizeof(iface));
p = strtok(NULL, " \t\n");
endptr = NULL;
routes[numroutes].dest = strtoul(p, &endptr, 16);
if (!endptr || *endptr) {
error("Failed to determine Destination from /proc/net/route");
continue;
}
/* Now for the gateway */
p = strtok(NULL, " \t\n");
if (!p) break;
endptr = NULL;
routes[numroutes].gw.s_addr = strtoul(p, &endptr, 16);
if (!endptr || *endptr) {
error("Failed to determine gw for %s from /proc/net/route", iface);
}
for(i=0; i < 5; i++) {
p = strtok(NULL, " \t\n");
if (!p) break;
}
if (!p) {
error("Failed to find field %d in /proc/net/route", i + 2);
continue;
}
endptr = NULL;
routes[numroutes].netmask = strtoul(p, &endptr, 16);
if (!endptr || *endptr) {
error("Failed to determine mask from /proc/net/route");
continue;
}
for(i=0; i < numifaces; i++) {
if (!strcmp(iface, ifaces[i].devfullname)) {
routes[numroutes].device = &ifaces[i];
break;
}
}
if (i == numifaces) {
error("Failed to find device %s which was referenced in /proc/net/route", iface);
continue;
}
/* Now to deal with some alias nonsense ... at least on Linux
this file will just list the short name, even though IP
information (such as source address) from an alias must be
used. So if the purported device can't reach the gateway,
try to find a device that starts with the same short
devname, but can (e.g. eth0 -> eth0:3) */
ii = &ifaces[i];
mask = htonl((unsigned long) (0-1) << (32 - ii->netmask_bits));
sin = (struct sockaddr_in *) &ii->addr;
if (routes[numroutes].gw.s_addr && (sin->sin_addr.s_addr & mask) !=
(routes[numroutes].gw.s_addr & mask)) {
for(i=0; i < numifaces; i++) {
if (ii == &ifaces[i]) continue;
if (strcmp(ii->devname, ifaces[i].devname) == 0) {
sin = (struct sockaddr_in *) &ifaces[i].addr;
if ((sin->sin_addr.s_addr & mask) ==
(routes[numroutes].gw.s_addr & mask)) {
routes[numroutes].device = &ifaces[i];
}
}
}
}
numroutes++;
if (numroutes >= route_capacity) {
route_capacity <<= 2;
routes = (struct sys_route *) safe_realloc(routes, route_capacity * sizeof(struct sys_route));
}
}
} else {
struct dnet_collector_route_nfo dcrn;
dcrn.routes = routes;
dcrn.numroutes = numroutes;
dcrn.capacity = route_capacity;
dcrn.ifaces = ifaces;
dcrn.numifaces = numifaces;
route_t *dr = route_open();
if (!dr) fatal("%s: route_open() failed", __func__);
if (route_loop(dr, collect_dnet_routes, &dcrn) != 0) {
fatal("%s: route_loop() failed", __func__);
}
route_close(dr);
/* These values could have changed in the callback */
route_capacity = dcrn.capacity;
numroutes = dcrn.numroutes;
routes = dcrn.routes;
}
/* Ensure that the route array is sorted by netmask */
for(i=1; i < numroutes; i++) {
if (ntohl(routes[i].netmask) > ntohl(routes[i-1].netmask))
break;
}
if (i < numroutes) {
/* they're not sorted ... better take care of that */
qsort(routes, numroutes, sizeof(routes[0]), nmaskcmp);
}
if (routes != NULL) {
/* We have it cached. */
*howmany = numroutes;
return routes;
}
/* First let us try Linux-style /proc/net/route */
routefp = fopen("/proc/net/route", "r");
if (routefp)
routes = getsysroutes_proc(routefp, howmany);
else
routes = getsysroutes_dnet(howmany);
numroutes = *howmany;
/* Ensure that the route array is sorted by netmask */
for(i=1; i < numroutes; i++) {
if (ntohl(routes[i].netmask) > ntohl(routes[i-1].netmask))
break;
}
if (i < numroutes) {
/* they're not sorted ... better take care of that */
qsort(routes, numroutes, sizeof(routes[0]), nmaskcmp);
}
*howmany = numroutes;
return routes;
}