// Network.cpp // Libunistd Copyright 2016 Robin.Rowe@CinePaint.org // License open source MIT #include #include #include #include #include #include #include "Network.h" #include "StdFile.h" #include "StdBlob.h" #ifdef WIN32 #define SUPPRESS_SECURITY_WARNING __pragma(warning(suppress:4996)) #else #define SUPPRESS_SECURITY_WARNING #endif #define CHECK(var) if(var!=ifstat->var){ ifstat->var=var; isChanged = true;} namespace portable { const char* output_proc_net_route = "Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT\n" "eth0 00000000 0202000A 0003 0 0 100 00000000 0 0 1\n" "eth1 0002000A 00000000 0001 0 0 100 00FFFFFF 0 0 2\n"; const char* output_proc_net_dev = "Inter-| Receive | Transmit\n" " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n" " lo: 13380 87 0 0 0 0 0 0 13380 87 0 0 0 0 0 0\n" " eth0: 279068630 1507895 0 0 0 0 0 0 567397982 852533 0 0 0 0 0 0\n" " eth1: 1090810015 4017054 42 0 0 0 0 0 13975469 134398 0 0 0 0 0 0\n"; Network::Network(unsigned interfaceCount) : isChanged(false) , interfaces(0) { ifStats.resize(interfaceCount); route_filename = "/proc/net/route"; dev_filename = "/proc/net/dev"; } /* (size = 450 +4 = 77 + 123 + 2*125 + 4 LF) root@vm-ubuntu:/opt/toolchains# cat /proc/net/dev Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed enth0: 616352817 446732 0 0 0 0 0 0 13516902 165770 0 0 0 0 0 0 enth1: 485454 4814 0 0 0 0 0 0 485454 502 0 0 0 0 0 0 */ bool Network::UpdateIfStats() { #ifdef WIN32 StdBlob proc_net_dev(output_proc_net_dev); #else StdFile proc_net_dev; if(!proc_net_dev.Open(dev_filename, "r")) { return false; } #endif proc_net_dev.SkipLine(); proc_net_dev.SkipLine(); unsigned lineCount=3; interfaces = 0; while(!proc_net_dev.IsFeof()) { if(interfaces>=ifStats.size()) { proc_net_dev.SkipLine(); interfaces++; } IfStat* ifstat=&ifStats[interfaces]; ifstat->Reset(); SUPPRESS_SECURITY_WARNING const int items = proc_net_dev.fscanf( " %20[^:]:%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", ifstat->ifname, &ifstat->in.bytes, &ifstat->in.packets, &ifstat->in.errors, &ifstat->in.drops, &ifstat->in.overruns, &ifstat->in.in_frame, &ifstat->in.in_compress, &ifstat->in.multicast, &ifstat->out.bytes, &ifstat->out.packets, &ifstat->out.errors, &ifstat->out.drops, &ifstat->out.overruns, &ifstat->out.out_colls, &ifstat->out.out_carrier, &ifstat->out.out_carrier ); interfaces++; if(-1==items) { break; } if(items != 17) { printf("Invalid data read Network::UpdateIfStats() %u:%i\n",lineCount,items); break; } UpdateIoctls(ifstat); lineCount++; } UpdateRoute(); return true; } struct ProcNetRoute { char ifname[10]; unsigned destination; unsigned gateway; unsigned flags; unsigned refcnt; unsigned use; unsigned metric; unsigned mask; unsigned mtu; unsigned window; unsigned irtt; void Reset() { ifname[0]=0; destination=0; gateway=0; flags=0; refcnt=0; use=0; metric=0; mask=0; mtu=0; window=0; irtt=0; } }; /* $ cat /proc/net/route Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT eth0 00000000 0202000A 0003 0 0 100 00000000 0 0 0 eth1 0002000A 00000000 0001 0 0 100 00FFFFFF 0 0 0 */ void Network::UpdateRoute() { #ifdef WIN32 StdBlob proc_net_route(output_proc_net_route); #else StdFile proc_net_route; if(!proc_net_route.Open(route_filename, "r")) { return; } #endif proc_net_route.SkipLine(); ProcNetRoute pnr; unsigned lineCount = 2; while(!proc_net_route.IsFeof()) { pnr.Reset(); SUPPRESS_SECURITY_WARNING const int items = proc_net_route.fscanf( "%s %x %x %x %x %x %x %x %x %x %x", pnr.ifname, &pnr.destination, &pnr.gateway, &pnr.flags, &pnr.refcnt, &pnr.use, &pnr.metric, &pnr.mask, &pnr.mtu, &pnr.window, &pnr.irtt ); // printf("Network::ifname=%s gateway=%u\n",pnr.ifname,pnr.gateway); if(pnr.gateway) { IfStat* ifstat=GetIfStat(pnr.ifname); if(ifstat) { const unsigned gateway = pnr.gateway; CHECK(gateway) } } if(-1==items) { break; } if(items != 11) { printf("Invalid data read Network::UpdateRoute() %u:%i\n",lineCount,items); break; } lineCount++; } } IfStat* Network::GetIfStat(const char* ifname) { for(unsigned i=0;isa_family) { return 0; } return ((struct sockaddr_in*)addr)->sin_addr.s_addr; } inline bool IsGood(int retval) { return -1!=retval || EADDRNOTAVAIL==errno; } bool Network::UpdateIoctls(IfStat* ifstat) { #ifdef WIN32 ifstat->address= 0x0100007f; ifstat->broadcast= 0x0000007f; ifstat->netmask= 0x00ffffff; ifstat->gateway= 0x04030201; ifstat->hw_address=0x0102030405060708ULL; ifstat->mtu=32; return true; #else const int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); if(-1 == sock) { return false; } ifreq req; strncpy(req.ifr_name, ifstat->ifname, IFNAMSIZ); req.ifr_name[IFNAMSIZ - 1] = 0; int retval = ioctl(sock, SIOCGIFADDR, &req); const uint32_t address=GetQuad(&req.ifr_addr,IsGood(retval)); CHECK(address) retval += ioctl(sock, SIOCGIFNETMASK, &req); const uint32_t netmask=GetQuad(&req.ifr_addr,IsGood(retval));; CHECK(netmask) retval += ioctl(sock, SIOCGIFBRDADDR, &req); const uint32_t broadcast=GetQuad(&req.ifr_addr,IsGood(retval)); CHECK(broadcast) retval += ioctl(sock, SIOCGIFMTU, &req); const int mtu = -1!=retval ? req.ifr_mtu:0; CHECK(mtu) retval += ioctl(sock, SIOCGIFHWADDR, &req); uint64_t hw_address = 0; unsigned char* hwaddr = (unsigned char *) &req.ifr_hwaddr.sa_data; memcpy(&hw_address,hwaddr,6); CHECK(hw_address) close(sock); //printf("Network::ioctl=%i address=%u netmask=%u broadcast=%u mtu=%i hw=%llu\n",retval,address,netmask,broadcast,mtu,hw_address); return !retval; #endif } void Network::PrintStats() { printf("Network::PrintStats() interfaces=%u isChanged=%i\n",interfaces,isChanged); for(unsigned i=0;i(&quad); SUPPRESS_SECURITY_WARNING sprintf(data,"%u%c%u%c%u%c%u",unsigned(p[0]),sep,unsigned(p[1]),sep,unsigned(p[2]),sep,unsigned(p[3])); } const char* Get() const { return data; } }; class HwAddress { char data[4*4]; public: HwAddress(uint64_t quad2,char sep) { unsigned char* p = reinterpret_cast(&quad2); SUPPRESS_SECURITY_WARNING sprintf(data,"%u%c%u%c%u%c%u%c%u%c%u",// only has 48 bits, ignore p[0] and p[1] unsigned(p[2]),sep,unsigned(p[3]),sep,unsigned(p[4]),sep,unsigned(p[5]),sep,unsigned(p[6]),sep,unsigned(p[7])); } const char* Get() const { return data; } }; void Network::PrintIfStat(IfStat* ifstat) { if(!ifstat || !ifstat->address) { return; } Ip4Address address(ifstat->address,'.'); Ip4Address netmask(ifstat->netmask,':'); Ip4Address broadcast(ifstat->broadcast,'.'); Ip4Address gateway(ifstat->gateway,'.'); HwAddress hw_address(ifstat->hw_address,':'); printf("Interface: %s ip=%s mask=%s gateway=%s\n broadcast=%s hw=%s mtu=%i\n",ifstat->ifname,address.Get(),netmask.Get(),gateway.Get(),broadcast.Get(),hw_address.Get(),ifstat->mtu); ifstat->in.Print(true); ifstat->out.Print(false); } } #if 0 uint32_t GetInet4(SOCKET sock) { struct sockaddr_storage addr; char ipstr[INET_ADDRSTRLEN]; socklen_t len = sizeof addr; getpeername(sock, (struct sockaddr*)&addr, &len); if (addr.ss_family != AF_INET) { return 0; } struct sockaddr_in *s = (struct sockaddr_in *)&addr; inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); unsigned ip[4]; SUPPRESS_SECURITY_WARNING scanf("%x.%x.%x.%x",ip,ip+1,ip+2,ip+3); uint32_t r; unsigned char* p = reinterpret_cast(&r); p[0] = (unsigned char) ip[3]; p[1] = (unsigned char) ip[2]; p[2] = (unsigned char) ip[1]; p[3] = (unsigned char) ip[0]; return r; } f() { int s; struct sockaddr_in sa; int sa_len; sa_len = sizeof(sa); if (getsockname(s, &sa, &sa_len) == -1) { perror("getsockname() failed"); return -1; } printf("Local IP address is: %s\n", inet_ntoa(sa.sin_add r)); printf("Local port is: %d\n", (int) ntohs(sa.sin_port)); } #endif