DWORD getRouteTable(PMIB_IPFORWARDTABLE *ppIpForwardTable, HANDLE heap, DWORD flags) { DWORD ret; if (!ppIpForwardTable) ret = ERROR_INVALID_PARAMETER; else { DWORD numRoutes = getNumRoutes(); DWORD size = sizeof(MIB_IPFORWARDTABLE); PMIB_IPFORWARDTABLE table; if (numRoutes > 1) size += (numRoutes - 1) * sizeof(MIB_IPFORWARDROW); table = HeapAlloc(heap, flags, size); if (table) { #if defined(HAVE_SYS_SYSCTL_H) && defined(NET_RT_DUMP) int mib[6] = {CTL_NET, PF_ROUTE, 0, PF_INET, NET_RT_DUMP, 0}; size_t needed; char *buf, *lim, *next, *addrPtr; struct rt_msghdr *rtm; if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) { ERR ("sysctl 1 failed!\n"); HeapFree (GetProcessHeap (), 0, table); return NO_ERROR; } buf = HeapAlloc (GetProcessHeap (), 0, needed); if (!buf) { HeapFree (GetProcessHeap (), 0, table); return ERROR_OUTOFMEMORY; } if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { ERR ("sysctl 2 failed!\n"); HeapFree (GetProcessHeap (), 0, table); HeapFree (GetProcessHeap (), 0, buf); return NO_ERROR; } *ppIpForwardTable = table; table->dwNumEntries = 0; lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { int i; rtm = (struct rt_msghdr *)next; if (rtm->rtm_type != RTM_GET) { WARN ("Got unexpected message type 0x%x!\n", rtm->rtm_type); continue; } /* Ignore all entries except for gateway routes which aren't multicast */ if (!(rtm->rtm_flags & RTF_GATEWAY) || (rtm->rtm_flags & RTF_MULTICAST)) continue; memset (&table->table[table->dwNumEntries], 0, sizeof (MIB_IPFORWARDROW)); table->table[table->dwNumEntries].dwForwardIfIndex = rtm->rtm_index; table->table[table->dwNumEntries].dwForwardType = MIB_IPROUTE_TYPE_INDIRECT; table->table[table->dwNumEntries].dwForwardMetric1 = rtm->rtm_rmx.rmx_hopcount; table->table[table->dwNumEntries].dwForwardProto = MIB_IPPROTO_LOCAL; addrPtr = (char *)(rtm + 1); for (i = 1; i; i <<= 1) { struct sockaddr *sa; DWORD addr; if (!(i & rtm->rtm_addrs)) continue; sa = (struct sockaddr *)addrPtr; ADVANCE (addrPtr, sa); /* default routes are encoded by length-zero sockaddr */ if (sa->sa_len == 0) addr = 0; else if (sa->sa_family != AF_INET) { WARN ("Received unsupported sockaddr family 0x%x\n", sa->sa_family); addr = 0; } else { struct sockaddr_in *sin = (struct sockaddr_in *)sa; addr = sin->sin_addr.s_addr; } switch (i) { case RTA_DST: table->table[table->dwNumEntries].dwForwardDest = addr; break; case RTA_GATEWAY: table->table[table->dwNumEntries].dwForwardNextHop = addr; break; case RTA_NETMASK: table->table[table->dwNumEntries].dwForwardMask = addr; break; default: WARN ("Unexpected address type 0x%x\n", i); } } table->dwNumEntries++; } HeapFree (GetProcessHeap (), 0, buf); ret = NO_ERROR; #else FILE *fp; ret = NO_ERROR; *ppIpForwardTable = table; table->dwNumEntries = 0; /* get from /proc/net/route, no error if can't */ fp = fopen("/proc/net/route", "r"); if (fp) { char buf[512] = { 0 }, *ptr; /* skip header line */ ptr = fgets(buf, sizeof(buf), fp); while (ptr && table->dwNumEntries < numRoutes) { memset(&table->table[table->dwNumEntries], 0, sizeof(MIB_IPFORWARDROW)); ptr = fgets(buf, sizeof(buf), fp); if (ptr) { DWORD index; while (!isspace(*ptr)) ptr++; *ptr = '\0'; ptr++; if (getInterfaceIndexByName(buf, &index) == NO_ERROR) { char *endPtr; table->table[table->dwNumEntries].dwForwardIfIndex = index; if (*ptr) { table->table[table->dwNumEntries].dwForwardDest = strtoul(ptr, &endPtr, 16); ptr = endPtr; } if (ptr && *ptr) { table->table[table->dwNumEntries].dwForwardNextHop = strtoul(ptr, &endPtr, 16); ptr = endPtr; } if (ptr && *ptr) { DWORD flags = strtoul(ptr, &endPtr, 16); if (!(flags & RTF_UP)) table->table[table->dwNumEntries].dwForwardType = MIB_IPROUTE_TYPE_INVALID; else if (flags & RTF_GATEWAY) table->table[table->dwNumEntries].dwForwardType = MIB_IPROUTE_TYPE_INDIRECT; else table->table[table->dwNumEntries].dwForwardType = MIB_IPROUTE_TYPE_DIRECT; ptr = endPtr; } if (ptr && *ptr) { strtoul(ptr, &endPtr, 16); /* refcount, skip */ ptr = endPtr; } if (ptr && *ptr) { strtoul(ptr, &endPtr, 16); /* use, skip */ ptr = endPtr; } if (ptr && *ptr) { table->table[table->dwNumEntries].dwForwardMetric1 = strtoul(ptr, &endPtr, 16); ptr = endPtr; } if (ptr && *ptr) { table->table[table->dwNumEntries].dwForwardMask = strtoul(ptr, &endPtr, 16); ptr = endPtr; } /* FIXME: other protos might be appropriate, e.g. the default * route is typically set with MIB_IPPROTO_NETMGMT instead */ table->table[table->dwNumEntries].dwForwardProto = MIB_IPPROTO_LOCAL; table->dwNumEntries++; } } } fclose(fp); } else { ERR ("unimplemented!\n"); return ERROR_NOT_SUPPORTED; } #endif } else ret = ERROR_OUTOFMEMORY; } return ret; }
DWORD getIPStats(PMIB_IPSTATS stats) { #if defined(HAVE_SYS_SYSCTL_H) && defined(IPCTL_STATS) int mib[] = {CTL_NET, PF_INET, IPPROTO_IP, IPCTL_STATS}; #define MIB_LEN (sizeof(mib) / sizeof(mib[0])) int ip_ttl, ip_forwarding; struct ipstat ip_stat; size_t needed; if (!stats) return ERROR_INVALID_PARAMETER; needed = sizeof(ip_stat); if(sysctl(mib, MIB_LEN, &ip_stat, &needed, NULL, 0) == -1) { ERR ("failed to get ipstat\n"); return ERROR_NOT_SUPPORTED; } needed = sizeof(ip_ttl); if (sysctlbyname ("net.inet.ip.ttl", &ip_ttl, &needed, NULL, 0) == -1) { ERR ("failed to get ip Default TTL\n"); return ERROR_NOT_SUPPORTED; } needed = sizeof(ip_forwarding); if (sysctlbyname ("net.inet.ip.forwarding", &ip_forwarding, &needed, NULL, 0) == -1) { ERR ("failed to get ip forwarding\n"); return ERROR_NOT_SUPPORTED; } stats->dwForwarding = ip_forwarding; stats->dwDefaultTTL = ip_ttl; stats->dwInDelivers = ip_stat.ips_delivered; stats->dwInHdrErrors = ip_stat.ips_badhlen + ip_stat.ips_badsum + ip_stat.ips_tooshort + ip_stat.ips_badlen; stats->dwInAddrErrors = ip_stat.ips_cantforward; stats->dwInReceives = ip_stat.ips_total; stats->dwForwDatagrams = ip_stat.ips_forward; stats->dwInUnknownProtos = ip_stat.ips_noproto; stats->dwInDiscards = ip_stat.ips_fragdropped; stats->dwOutDiscards = ip_stat.ips_odropped; stats->dwReasmOks = ip_stat.ips_reassembled; stats->dwFragOks = ip_stat.ips_fragmented; stats->dwFragFails = ip_stat.ips_cantfrag; stats->dwReasmTimeout = ip_stat.ips_fragtimeout; stats->dwOutNoRoutes = ip_stat.ips_noroute; stats->dwOutRequests = ip_stat.ips_localout; stats->dwReasmReqds = ip_stat.ips_fragments; return NO_ERROR; #else FILE *fp; if (!stats) return ERROR_INVALID_PARAMETER; memset(stats, 0, sizeof(MIB_IPSTATS)); stats->dwNumIf = stats->dwNumAddr = getNumInterfaces(); stats->dwNumRoutes = getNumRoutes(); /* get most of these stats from /proc/net/snmp, no error if can't */ fp = fopen("/proc/net/snmp", "r"); if (fp) { static const char hdr[] = "Ip:"; char buf[512] = { 0 }, *ptr; do { ptr = fgets(buf, sizeof(buf), fp); } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1)); if (ptr) { /* last line was a header, get another */ ptr = fgets(buf, sizeof(buf), fp); if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) { char *endPtr; ptr += sizeof(hdr); if (ptr && *ptr) { stats->dwForwarding = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwDefaultTTL = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwInReceives = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwInHdrErrors = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwInAddrErrors = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwForwDatagrams = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwInUnknownProtos = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwInDiscards = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwInDelivers = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwOutRequests = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwOutDiscards = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwOutNoRoutes = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwReasmTimeout = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwReasmReqds = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwReasmOks = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwReasmFails = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwFragOks = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwFragFails = strtoul(ptr, &endPtr, 10); ptr = endPtr; } if (ptr && *ptr) { stats->dwFragCreates = strtoul(ptr, &endPtr, 10); ptr = endPtr; } /* hmm, no routingDiscards */ } } fclose(fp); } else { ERR ("unimplemented!\n"); return ERROR_NOT_SUPPORTED; } return NO_ERROR; #endif }
RouteTable *getRouteTable(void) { RouteTable *out_route_table; DWORD numRoutes = getNumRoutes(), routesAdded = 0; TDIEntityID ent; HANDLE tcpFile; NTSTATUS status = openTcpFile( &tcpFile ); int i; if( !NT_SUCCESS(status) ) return 0; TRACE("GETTING ROUTE TABLE\n"); out_route_table = HeapAlloc( GetProcessHeap(), 0, sizeof(RouteTable) + (sizeof(RouteEntry) * (numRoutes - 1)) ); if (!out_route_table) { closeTcpFile(tcpFile); return NULL; } out_route_table->numRoutes = numRoutes; for( i = 0; routesAdded < out_route_table->numRoutes; i++ ) { int j; IPRouteEntry *route_set; getNthIpEntity( tcpFile, i, &ent ); tdiGetRoutesForIpEntity( tcpFile, &ent, &route_set, &numRoutes ); if( !route_set ) { closeTcpFile( tcpFile ); HeapFree( GetProcessHeap(), 0, out_route_table ); return 0; } TRACE( "%d routes in instance %d\n", numRoutes, i ); #if 0 HexDump( route_set, sizeof( IPRouteEntry ) * snmpInfo.ipsi_numroutes ); #endif for( j = 0; j < numRoutes; j++ ) { int routeNum = j + routesAdded; out_route_table->routes[routeNum].dest = route_set[j].ire_dest; out_route_table->routes[routeNum].mask = route_set[j].ire_mask; out_route_table->routes[routeNum].gateway = route_set[j].ire_gw; out_route_table->routes[routeNum].ifIndex = route_set[j].ire_index; out_route_table->routes[routeNum].metric = route_set[j].ire_metric1; } if( route_set ) tdiFreeThingSet( route_set ); routesAdded += numRoutes; } closeTcpFile( tcpFile ); TRACE("Return: %08x, %08x\n", status, out_route_table); return out_route_table; }