mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
1057 lines
29 KiB
C++
Executable file
1057 lines
29 KiB
C++
Executable file
//
|
|
// Created on: 6/8/21
|
|
|
|
#include "IP4Address.hpp"
|
|
|
|
|
|
#include <algorithm>
|
|
#include <stdexcept>
|
|
#include <fstream>
|
|
#if defined(_WIN32)
|
|
#define NOMINMAX
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <iphlpapi.h>
|
|
#include <stringapiset.h>
|
|
|
|
#pragma comment(lib, "Ws2_32.lib")
|
|
#pragma comment(lib, "IPHLPAPI.lib")
|
|
constexpr auto WORKING_BUFFER_SIZE = 15000;
|
|
constexpr auto MAX_TRIES = 3;
|
|
|
|
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
|
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
|
#else
|
|
|
|
#include <sys/types.h>
|
|
#include <netdb.h>
|
|
#include <arpa/inet.h>
|
|
#include <ifaddrs.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/socket.h>
|
|
#endif
|
|
using namespace std::string_literals ;
|
|
//=================================================================================
|
|
// string manipulation, in case strutil is not available. Enables this to be standalone
|
|
//=================================================================================
|
|
//=================================================================================
|
|
auto trim(const std::string &value) ->std::string {
|
|
auto rvalue = std::string() ;
|
|
auto startpos = value.find_first_not_of(" \t\r\n\f");
|
|
if(startpos!= std::string::npos){
|
|
rvalue = value.substr(startpos);
|
|
auto endpos = rvalue.find_last_not_of(" \t\r\n\f");
|
|
if (endpos != std::string::npos) {
|
|
rvalue = rvalue.substr(0,endpos+1) ;
|
|
}
|
|
}
|
|
return rvalue ;
|
|
}
|
|
//=================================================================================
|
|
auto parse(const std::string &value, const std::string &separator=".") ->std::vector<std::string>{
|
|
auto rvalue = std::vector<std::string>() ;
|
|
auto subject = trim(value) ;
|
|
auto position = subject.find(separator) ;
|
|
if (position == std::string::npos){
|
|
// It coulnd't find the separator
|
|
rvalue.push_back(subject);
|
|
}
|
|
else {
|
|
while (position != std::string::npos){
|
|
auto parsed = trim(subject.substr(0,position)) ;
|
|
rvalue.push_back(parsed);
|
|
subject = subject.substr(position+separator.size()) ;
|
|
position = subject.find(separator);
|
|
}
|
|
subject = trim(subject);
|
|
rvalue.push_back(subject);
|
|
}
|
|
return rvalue ;
|
|
}
|
|
//=================================================================================
|
|
auto strip(const std::string &value, const std::string &identifier="//") -> std::string {
|
|
auto position = value.find(identifier);
|
|
return value.substr(0,position) ;
|
|
}
|
|
//=================================================================================
|
|
auto split(const std::string &value, const std::string &identifier="=") -> std::pair<std::string,std::string>{
|
|
auto position = value.find(identifier);
|
|
auto pos1 = trim(value.substr(0,position)) ;
|
|
auto pos2 = trim(value.substr(position+identifier.size()));
|
|
return std::make_pair(pos1, pos2);
|
|
}
|
|
|
|
//=================================================================================
|
|
// ip4addr_t
|
|
//=================================================================================
|
|
|
|
//=================================================================================
|
|
const std::vector<ip4addr_t> ip4addr_t::lanips{
|
|
ip4addr_t("10.*.*.*"s),ip4addr_t("192.168.*.*"s),ip4addr_t("172.16.*.*"s),ip4addr_t("172.17.*.*"s),
|
|
ip4addr_t("172.18.*.*"s),ip4addr_t("172.19.*.*"s),ip4addr_t("172.20.*.*"s),ip4addr_t("172.21.*.*"s),
|
|
ip4addr_t("172.22.*.*"s),ip4addr_t("172.23.*.*"s),ip4addr_t("172.241.*.*"s),ip4addr_t("172.25.*.*"s),
|
|
ip4addr_t("172.26.*.*"s),ip4addr_t("172.27.*.*"s),ip4addr_t("172.28.*.*"s),ip4addr_t("172.29.*.*"s),
|
|
ip4addr_t("172.30.*.*"s),ip4addr_t("172.31.*.*"s)
|
|
} ;
|
|
//=================================================================================
|
|
const std::vector<ip4addr_t> ip4addr_t::localips{
|
|
ip4addr_t("127.*.*.*")
|
|
};
|
|
//=================================================================================
|
|
const std::vector<ip4addr_t> ip4addr_t::apipaips{
|
|
ip4addr_t("169.254.*.*")
|
|
};
|
|
|
|
auto ip4addr_t::exact(const ip4addr_t& value) const ->bool {
|
|
auto rvalue = true ;
|
|
for (auto i = 0; i<4;++i) {
|
|
if (components[i] != value.components[i]){
|
|
rvalue = false ;
|
|
break;
|
|
}
|
|
}
|
|
return rvalue ;
|
|
}
|
|
|
|
//==============================================================
|
|
auto ip4addr_t::match(std::uint32_t value, bool bigendian) const ->int {
|
|
auto ptr = reinterpret_cast<std::uint8_t*>(&value) ;
|
|
if (!bigendian){
|
|
std::reverse(ptr, ptr+4);
|
|
}
|
|
auto match = 0 ;
|
|
for (const auto &comp : components){
|
|
match += 1 ;
|
|
if ((comp != "*") && !comp.empty()) {
|
|
try {
|
|
if (std::stoi(comp) != *ptr) {
|
|
match -=1 ;
|
|
break;
|
|
}
|
|
}
|
|
catch(...) {
|
|
// the value couldn't be converted
|
|
match -=1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return match ;
|
|
}
|
|
//==============================================================
|
|
auto ip4addr_t::match(const ip4addr_t &value) const ->int {
|
|
auto rvalue = 0 ;
|
|
for (auto i = 0 ; i<4 ; ++i){
|
|
rvalue = i+1 ;
|
|
if (!(((value.components[i] == "*") || value.components[i].empty()) ||
|
|
((components[i] == "*") || components[i].empty()))){
|
|
// Neither are wild, we have to match them
|
|
if ( value.components[i] != components[i]) {
|
|
rvalue = rvalue -1 ;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return rvalue ;
|
|
}
|
|
//=========================================================
|
|
ip4addr_t::ip4addr_t(const std::string &value ){
|
|
components.fill("*"s);
|
|
auto values = parse(value) ;
|
|
switch (value.size()) {
|
|
default:
|
|
case 4:
|
|
components[3] = values[3] ;
|
|
[[fallthrough]];
|
|
case 3:
|
|
components[2] = values[2] ;
|
|
[[fallthrough]];
|
|
case 2:
|
|
components[1] = values[1] ;
|
|
[[fallthrough]];
|
|
case 1:
|
|
components[0] = values[0] ;
|
|
[[fallthrough]];
|
|
case 0:
|
|
break;
|
|
}
|
|
}
|
|
//=========================================================
|
|
ip4addr_t::ip4addr_t(std::uint32_t addr,bool bigendian ){
|
|
components.fill("*"s);
|
|
auto ptr = reinterpret_cast<std::uint8_t*>(&addr);
|
|
if (!bigendian) {
|
|
std::reverse(ptr, ptr+4);
|
|
}
|
|
for (auto i=0 ; i<4 ;++i) {
|
|
components[i] = std::to_string(ptr[i]) ;
|
|
}
|
|
}
|
|
//=========================================================
|
|
auto ip4addr_t::ipaddr(bool bigendian) const ->std::uint32_t {
|
|
auto rvalue = std::uint32_t(0) ;
|
|
auto ptr = reinterpret_cast<std::uint8_t*>(&rvalue);
|
|
for (auto i=0 ; i<4 ; ++i){
|
|
auto value = std::uint8_t(0) ;
|
|
try {
|
|
value = static_cast<std::uint8_t>(std::stoi(components[i])) ;
|
|
}
|
|
catch(...){
|
|
throw std::runtime_error("Error converting ip to a number"s);
|
|
}
|
|
ptr[i] = value ;
|
|
}
|
|
if (!bigendian){
|
|
std::reverse(ptr, ptr+4);
|
|
}
|
|
return rvalue ;
|
|
}
|
|
//=========================================================
|
|
// This assumes the value is in big endian
|
|
auto ip4addr_t::operator==(std::uint32_t value) const ->bool {
|
|
return match(value)==4 ;
|
|
}
|
|
//=========================================================
|
|
auto ip4addr_t::operator==(const ip4addr_t &value) const ->bool {
|
|
return match(value)==4 ;
|
|
}
|
|
//=========================================================
|
|
auto ip4addr_t::type() const ->ip4type_t {
|
|
auto rvalue = ip4type_t::wan ;
|
|
try {
|
|
auto iter = std::find_if(lanips.begin(),lanips.end(),[this](const ip4addr_t& ip){
|
|
return *this == ip ;
|
|
});
|
|
if (iter!= lanips.end()){
|
|
rvalue = ip4type_t::lan ;
|
|
}
|
|
else{
|
|
auto iter = std::find_if(localips.begin(),localips.end(),[this](const ip4addr_t& ip){
|
|
return *this == ip ;
|
|
});
|
|
if (iter !=localips.end()){
|
|
rvalue = ip4type_t::local ;
|
|
}
|
|
else {
|
|
auto iter = std::find_if(apipaips.begin(),apipaips.end(),[this](const ip4addr_t& ip){
|
|
return *this == ip ;
|
|
});
|
|
if (iter !=apipaips.end()){
|
|
rvalue = ip4type_t::apipa ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch(...) {
|
|
rvalue = ip4type_t::invalid ;
|
|
}
|
|
return rvalue ;
|
|
}
|
|
//=========================================================
|
|
auto ip4addr_t::description() const ->std::string {
|
|
auto ip = std::string() ;
|
|
for (auto &value : components){
|
|
ip += value + "."s ;
|
|
}
|
|
return ip.substr(0,ip.size()-1) ;
|
|
}
|
|
//=================================================================================
|
|
// ip4list_t
|
|
//=================================================================================
|
|
|
|
//=================================================================================
|
|
ip4list_t::ip4list_t(const std::string &filename) {
|
|
if (!filename.empty()){
|
|
load(filename) ;
|
|
}
|
|
}
|
|
|
|
//=================================================================================
|
|
auto ip4list_t::bestmatch(const ip4addr_t &value) const ->std::pair<ip4addr_t,int> {
|
|
auto matches = std::vector<std::pair<ip4addr_t,int>>() ;
|
|
for (const auto &addr: ipaddresses){
|
|
auto comp = addr.match(value);
|
|
matches.push_back(std::make_pair(addr, comp));
|
|
}
|
|
std::sort(matches.begin(),matches.end(),[](const std::pair<ip4addr_t,int> &lhs, const std::pair<ip4addr_t,int> &rhs){
|
|
return lhs.second < rhs.second ;
|
|
});
|
|
return *matches.rbegin();
|
|
}
|
|
//=================================================================================
|
|
auto ip4list_t::bestmatch(std::uint32_t value, bool bigendian ) const ->std::pair<ip4addr_t,int> {
|
|
auto ptr = reinterpret_cast<std::uint8_t*>(&value);
|
|
if (!bigendian){
|
|
std::reverse(ptr, ptr+4);
|
|
}
|
|
auto matches = std::vector<std::pair<ip4addr_t,int>>() ;
|
|
for (const auto &addr: ipaddresses){
|
|
auto comp = addr.match(value);
|
|
matches.push_back(std::make_pair(addr, comp));
|
|
}
|
|
std::sort(matches.begin(),matches.end(),[](const std::pair<ip4addr_t,int> &lhs, const std::pair<ip4addr_t,int> &rhs){
|
|
return lhs.second < rhs.second ;
|
|
});
|
|
return *matches.rbegin();
|
|
|
|
}
|
|
//=================================================================================
|
|
auto ip4list_t::add(const ip4addr_t &value) ->void {
|
|
ipaddresses.push_back(value);
|
|
}
|
|
//=================================================================================
|
|
auto ip4list_t::remove(const ip4addr_t &value) ->void {
|
|
auto iter = std::find_if(ipaddresses.begin(),ipaddresses.end(),[value](const ip4addr_t &entry){
|
|
return value.exact(entry);
|
|
});
|
|
if (iter != ipaddresses.end()){
|
|
ipaddresses.erase(iter) ;
|
|
}
|
|
}
|
|
//=================================================================================
|
|
auto ip4list_t::size() const ->size_t {
|
|
return ipaddresses.size() ;
|
|
}
|
|
//=================================================================================
|
|
auto ip4list_t::load(const std::string &filename) ->bool {
|
|
auto rvalue = false ;
|
|
enum state_t {section,startsection,data};
|
|
ipaddresses.clear() ;
|
|
auto input = std::ifstream(filename);
|
|
if (input.is_open()){
|
|
rvalue = true ;
|
|
char inputline[4096] ;
|
|
auto state = state_t::section ;
|
|
while (input.good() && !input.eof()) {
|
|
input.getline(inputline, 4095);
|
|
if (input.gcount()>0) {
|
|
inputline[input.gcount()]=0 ;
|
|
auto line = trim(strip(std::string(inputline))) ;
|
|
if (!line.empty()){
|
|
// look for a section
|
|
switch (static_cast<int>(state)){
|
|
case static_cast<int>(state_t::section): {
|
|
if (line[0] == '['){
|
|
if (line[line.size()-1] == ']'){
|
|
// it is a section!
|
|
line = trim(line.substr(1,line.find("]")-1));
|
|
// apparently we dont look at this?
|
|
state = state_t::startsection;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case static_cast<int>(state_t::startsection):{
|
|
if (line[0] == '{') {
|
|
state = state_t::data ;
|
|
}
|
|
break;
|
|
}
|
|
case static_cast<int>(state_t::data):{
|
|
if (line[0] != '}') {
|
|
auto [key,value] = split(line,"=") ;
|
|
if ((key=="ip") || (key=="IP") || (key=="Ip") || (key=="iP")) {
|
|
ipaddresses.push_back(ip4addr_t(value));
|
|
}
|
|
}
|
|
else {
|
|
state = state_t::section;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return rvalue ;
|
|
}
|
|
|
|
//=================================================================================
|
|
auto ip4list_t::ips() const ->const std::vector<ip4addr_t>& {
|
|
return ipaddresses;
|
|
}
|
|
//=================================================================================
|
|
auto ip4list_t::ips() -> std::vector<ip4addr_t>&{
|
|
return ipaddresses;
|
|
}
|
|
|
|
// Unfortunately, the approach here for the unix/windows is almost totally
|
|
// different, so effectively, to completely different routines
|
|
#if defined(_WIN32)
|
|
//=================================================================================
|
|
auto ip4list_t::available() ->ip4list_t{
|
|
/* Note: could also use malloc() and free() */
|
|
|
|
ip4list_t rvalue;
|
|
std::string device ;
|
|
ip4addr_t device_address ;
|
|
|
|
|
|
/* Declare and initialize variables */
|
|
|
|
DWORD dwSize = 0;
|
|
DWORD dwRetVal = 0;
|
|
|
|
unsigned int i = 0;
|
|
|
|
// Set the flags to pass to GetAdaptersAddresses
|
|
ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
|
|
|
|
// default to unspecified address family (both)
|
|
ULONG family = AF_INET;
|
|
|
|
LPVOID lpMsgBuf = NULL;
|
|
|
|
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
|
|
ULONG outBufLen = 0;
|
|
ULONG Iterations = 0;
|
|
|
|
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
|
|
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
|
|
PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
|
|
PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
|
|
IP_ADAPTER_DNS_SERVER_ADDRESS* pDnServer = NULL;
|
|
IP_ADAPTER_PREFIX* pPrefix = NULL;
|
|
|
|
// Allocate a 15 KB buffer to start with.
|
|
outBufLen = WORKING_BUFFER_SIZE;
|
|
|
|
do {
|
|
|
|
pAddresses = (IP_ADAPTER_ADDRESSES*)MALLOC(outBufLen);
|
|
if (pAddresses == nullptr) {
|
|
throw std::runtime_error("Memory allocation files for IP_ADAPTER_ADDRESSES");
|
|
}
|
|
|
|
dwRetVal =
|
|
GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
|
|
|
|
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
|
|
FREE(pAddresses);
|
|
pAddresses = NULL;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
|
|
Iterations++;
|
|
|
|
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
|
|
|
|
if (dwRetVal == NO_ERROR) {
|
|
// If successful, output some information from the data we received
|
|
pCurrAddresses = pAddresses;
|
|
while (pCurrAddresses) {
|
|
|
|
|
|
|
|
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
|
if (pUnicast != nullptr) {
|
|
if (pUnicast->Address.lpSockaddr->sa_family == AF_INET) {
|
|
for (i = 0; pUnicast != nullptr; i++) {
|
|
const int friendlen = 200;
|
|
|
|
char friendly[friendlen];
|
|
std::memset(friendly, 0, friendlen);
|
|
sockaddr_in* sa_in = (sockaddr_in*)pUnicast->Address.lpSockaddr;
|
|
device_address = ip4addr_t(sa_in->sin_addr.S_un.S_addr );
|
|
|
|
if (device_address.type() != ip4addr_t::ip4type_t::apipa) {
|
|
//ourdevice.address = inet_ntop(AF_INET, &(sa_in->sin_addr), buff, bufflen);
|
|
BOOL conv = false;
|
|
device = "";
|
|
if (WideCharToMultiByte(CP_UTF8, 0, pCurrAddresses->FriendlyName, -1, friendly, friendlen, 0, &conv)> 0) {
|
|
device = friendly;
|
|
}
|
|
if (!device.empty()){
|
|
// The device has a name, might be intersted
|
|
if (device.find("(WSL)")== std::string::npos){
|
|
// we dont want a psuedo WSL device on windows
|
|
rvalue.add(device_address) ;
|
|
}
|
|
}
|
|
|
|
}
|
|
pUnicast = pUnicast->Next;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
pCurrAddresses = pCurrAddresses->Next;
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (dwRetVal != ERROR_NO_DATA) {
|
|
if (pAddresses)
|
|
FREE(pAddresses);
|
|
|
|
throw std::runtime_error("Unable to get address info");
|
|
}
|
|
}
|
|
|
|
if (pAddresses) {
|
|
FREE(pAddresses);
|
|
}
|
|
return rvalue;
|
|
}
|
|
#else
|
|
auto ip4list_t::available() ->ip4list_t {
|
|
ip4list_t rvalue ;
|
|
struct ifaddrs * ifAddrStruct=NULL;
|
|
struct ifaddrs * ifa=NULL;
|
|
void * tmpAddrPtr=NULL;
|
|
ip4addr_t device_address ;
|
|
|
|
getifaddrs(&ifAddrStruct);
|
|
|
|
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
|
|
if (!ifa->ifa_addr) {
|
|
continue;
|
|
}
|
|
if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
|
|
// is a valid IP4 Address
|
|
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
|
|
auto holder = *reinterpret_cast<sockaddr_in *>(ifa->ifa_addr);
|
|
auto addr = ip4addr_t(holder.sin_addr.s_addr);
|
|
if (addr.type() != ip4addr_t::ip4type_t::apipa){
|
|
rvalue.add(addr);
|
|
}
|
|
}
|
|
}
|
|
if (ifAddrStruct!=NULL) {
|
|
freeifaddrs(ifAddrStruct);
|
|
}
|
|
return rvalue ;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
#include "ConfigOS.h"
|
|
|
|
#include <iostream>
|
|
#include <stdexcept>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
|
|
#if PLATFORM == WINDOWS
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <iphlpapi.h>
|
|
#include <stringapiset.h>
|
|
|
|
#pragma comment(lib, "Ws2_32.lib")
|
|
#pragma comment(lib, "IPHLPAPI.lib")
|
|
#define WORKING_BUFFER_SIZE 15000
|
|
#define MAX_TRIES 3
|
|
|
|
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
|
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
|
|
|
#else
|
|
|
|
#include <sys/types.h>
|
|
#include <netdb.h>
|
|
#include <arpa/inet.h>
|
|
#include <ifaddrs.h>
|
|
#include <netinet/in.h>
|
|
|
|
#endif
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// Methods for IP4Address
|
|
//
|
|
//+++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
const std::vector<IP4Address> IP4Address::_privateIPs = {IP4Address("10.*.*.*"),IP4Address("192.168.*.*"),
|
|
IP4Address("172.16.*.*"),IP4Address("172.17.*.*"), IP4Address("172.18.*.*"),IP4Address("172.19.*.*"),
|
|
IP4Address("172.20.*.*"),IP4Address("172.21.*.*"),IP4Address("172.22.*.*"),IP4Address("172.23.*.*"),
|
|
IP4Address("172.241.*.*"),IP4Address("172.25.*.*"),IP4Address("172.26.*.*"),IP4Address("172.27.*.*"),
|
|
IP4Address("172.28.*.*"),IP4Address("172.29.*.*"),IP4Address("172.30.*.*"),IP4Address("172.31.*.*")
|
|
};
|
|
|
|
const IP4Address IP4Address::_localIP = IP4Address("127.*.*.*");
|
|
|
|
const IP4Address IP4Address::_APIPA = IP4Address("169.254.*.*");
|
|
|
|
std::vector<IP4Address> IP4Address::_myIPs = std::vector<IP4Address>() ;
|
|
|
|
IP4Address IP4Address::_externalIP =IP4Address("*.*.*.*");
|
|
//============================================================================
|
|
void IP4Address::loadIPs() {
|
|
_myIPs = available();
|
|
}
|
|
|
|
|
|
//=====================================================================
|
|
void IP4Address::setExternal(const std::string &address) {
|
|
IP4Address::_externalIP = lookup(address);
|
|
}
|
|
|
|
//=====================================================================
|
|
std::vector<std::string> IP4Address::parseIP(const std::string &ip) {
|
|
// Examples: 192.168.1.0
|
|
// 192..1.0
|
|
// 192.*.1.0
|
|
|
|
std::vector<std::string> rvalue ;
|
|
std::string::size_type startloc = 0 ;
|
|
std::string::size_type endloc =ip.size();
|
|
std::size_t increment = 0 ;
|
|
for (increment = 0; increment<3;increment++) {
|
|
if (startloc >= ip.size()){
|
|
endloc = std::string::npos;
|
|
}
|
|
else {
|
|
endloc = ip.find(".",startloc) ;
|
|
}
|
|
std::string entry ;
|
|
entry = "";
|
|
// Coudn't find it
|
|
if (endloc== std::string::npos) {
|
|
if (startloc < ip.size()){
|
|
entry = ip.substr(startloc);
|
|
}
|
|
}
|
|
else {
|
|
entry = ip.substr(startloc,endloc-startloc);
|
|
}
|
|
if (entry.empty()){
|
|
entry = "*";
|
|
}
|
|
rvalue.push_back(entry);
|
|
if (endloc == std::string::npos){
|
|
break;
|
|
}
|
|
startloc = endloc + 1 ;
|
|
}
|
|
if (increment <3) {
|
|
for (auto i = increment + 1 ; i < 4; i++){
|
|
rvalue.push_back("*");
|
|
}
|
|
}
|
|
else {
|
|
// just need to find the last
|
|
std::string entry;
|
|
if (startloc < ip.size()){
|
|
entry = ip.substr(startloc);
|
|
}
|
|
if (entry.empty()){
|
|
entry = "*";
|
|
}
|
|
rvalue.push_back(entry);
|
|
}
|
|
return rvalue ;
|
|
}
|
|
//====================================================================
|
|
unsigned int IP4Address::createIP(const std::string &ip){
|
|
auto values = parseIP(ip);
|
|
std::vector<char> numbers ;
|
|
numbers.resize(4,0);
|
|
for (auto i = 0 ; i < 4 ; i++){
|
|
if (values[i] !="*"){
|
|
numbers[i] = static_cast<char>(std::stoi(values[i])) ;
|
|
}
|
|
}
|
|
return *reinterpret_cast<unsigned int*>(numbers.data());
|
|
}
|
|
//====================================================================
|
|
std::string IP4Address::string() const {
|
|
return _components[0] + "." + _components[1]+ "." + _components[2] + "." + _components[3];
|
|
}
|
|
//====================================================================
|
|
IP4Address::IP4Address() {
|
|
_components.resize(4,"*");
|
|
}
|
|
//====================================================================
|
|
IP4Address::IP4Address(unsigned int address) : IP4Address() {
|
|
_components.clear();
|
|
_components.push_back(std::to_string(((address>>24)&0xFF))) ;
|
|
_components.push_back(std::to_string(((address>>16)&0xFF))) ;
|
|
_components.push_back(std::to_string(((address>>8)&0xFF))) ;
|
|
_components.push_back(std::to_string(((address)&0xFF))) ;
|
|
|
|
}
|
|
//====================================================================
|
|
IP4Address::IP4Address(const std::string &address) : IP4Address(){
|
|
_components = parseIP(address);
|
|
}
|
|
//====================================================================
|
|
IP4Address& IP4Address::operator=(const std::string &address){
|
|
_components.clear();
|
|
_components = parseIP(address);
|
|
return *this;
|
|
}
|
|
//====================================================================
|
|
IP4Address& IP4Address::operator=(const unsigned int &address){
|
|
_components.clear();
|
|
_components.push_back(std::to_string(((address>>24)&0xFF))) ;
|
|
_components.push_back(std::to_string(((address>>16)&0xFF))) ;
|
|
_components.push_back(std::to_string(((address>>8)&0xFF))) ;
|
|
_components.push_back(std::to_string(((address)&0xFF))) ;
|
|
return *this;
|
|
|
|
}
|
|
|
|
//=========================================================================
|
|
std::vector<IP4Address> IP4Address::deviceIPs() {
|
|
return _myIPs;
|
|
}
|
|
//=========================================================================
|
|
std::string IP4Address::externalIP() {
|
|
return _externalIP.string();
|
|
}
|
|
|
|
//====================================================================
|
|
bool IP4Address::operator==(const IP4Address &address) const {
|
|
return match(address,4);
|
|
}
|
|
//====================================================================
|
|
bool IP4Address::operator!=(const IP4Address &address) const {
|
|
return !match(address,4);
|
|
}
|
|
|
|
//====================================================================
|
|
bool IP4Address::match(const IP4Address &address, int level) const {
|
|
for (auto i = 0 ; i < level ; i++){
|
|
if (!((_components[i] =="*") || (address._components[i]=="*"))){
|
|
if (_components[i] != address._components[i]) {
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
|
|
}
|
|
//=====================================================================
|
|
IP4Address::typeIP IP4Address::type(bool notmine ) const{
|
|
// Check for a match!
|
|
if (!notmine){
|
|
for (auto &entry: _myIPs){
|
|
if (entry == *this){
|
|
return mine;
|
|
}
|
|
}
|
|
}
|
|
if (_externalIP == *this) {
|
|
return mine ;
|
|
}
|
|
if (*this == _localIP){
|
|
return local;
|
|
}
|
|
|
|
if (*this == _APIPA){
|
|
return apipa ;
|
|
}
|
|
for (auto &entry: _privateIPs){
|
|
if (entry == *this){
|
|
return lan;
|
|
}
|
|
}
|
|
return wan;
|
|
}
|
|
//============================================================================
|
|
IP4Address IP4Address::respond(IP4Address &address){
|
|
// get the type
|
|
auto ttype = address.type(false);
|
|
if (ttype == mine) {
|
|
// respond with local host
|
|
return IP4Address("127.0.0.1");
|
|
}
|
|
else if (ttype == lan){
|
|
return bestMatch(address);
|
|
}
|
|
return IP4Address::_externalIP;
|
|
}
|
|
|
|
//===================================================================
|
|
const IP4Address& IP4Address::bestMatch(const IP4Address &address){
|
|
if (_myIPs.size() == 0){
|
|
return _externalIP;
|
|
}
|
|
auto matchcount = 0 ;
|
|
auto index = -1;
|
|
for (auto i = 0 ; i < _myIPs.size() ; i++){
|
|
auto count = 0 ;
|
|
for (auto j= 0 ; j<4 ; j++) {
|
|
if (_myIPs[i]._components[j] != address._components[j]) {
|
|
break;
|
|
}
|
|
count = count + 1 ;
|
|
}
|
|
if (count >= matchcount){
|
|
index = i ;
|
|
matchcount = count ;
|
|
}
|
|
}
|
|
if (matchcount == 0){
|
|
return _externalIP;
|
|
}
|
|
else {
|
|
return _myIPs[index];
|
|
}
|
|
}
|
|
//====================================================================
|
|
unsigned int IP4Address::littleEndian() const {
|
|
return convert(3,-1);
|
|
}
|
|
//====================================================================
|
|
unsigned int IP4Address::bigEndian() const{
|
|
return convert(0,1);
|
|
}
|
|
//====================================================================
|
|
unsigned int IP4Address::convert(int start, int increment) const{
|
|
unsigned int address =0;
|
|
auto count = start ;
|
|
for (auto &entry: _components){
|
|
unsigned int temp =0;
|
|
try {
|
|
temp = static_cast<unsigned int>(std::stoi(entry));
|
|
}
|
|
catch(...) {
|
|
temp = 0 ;
|
|
}
|
|
address = (temp << (count*8) ) | address;
|
|
count = count +increment ;
|
|
}
|
|
return address ;
|
|
}
|
|
|
|
//====================================================================
|
|
bool IP4Address::valid() const {
|
|
for (auto &entry : _components){
|
|
if (entry != "*"){
|
|
try {
|
|
auto value = std::stoi(entry) ;
|
|
if( (value <0 ) || (value>255)) {
|
|
|
|
return false ;
|
|
}
|
|
|
|
}
|
|
catch(...) {
|
|
return false ;
|
|
}
|
|
}
|
|
}
|
|
return true ;
|
|
}
|
|
|
|
//====================================================================
|
|
IP4Address IP4Address::lookup(const std::string& address){
|
|
struct addrinfo hints;
|
|
struct addrinfo *result, *rp;
|
|
std::memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = AF_INET; /* Allow IPv4 or IPv6 */
|
|
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
|
|
hints.ai_flags = 0;
|
|
hints.ai_protocol = 0; /* Any protocol */
|
|
#if PLATFORM == WINDOWS
|
|
WSAData wsdata;
|
|
int startresult = WSAStartup(MAKEWORD(2, 2), &wsdata);
|
|
if (startresult != 0) {
|
|
throw std::runtime_error(std::string("Error start Winsock: ") + std::to_string(startresult));
|
|
}
|
|
#endif
|
|
int status = getaddrinfo(address.c_str(), nullptr, &hints, &result);
|
|
if (status != 0) {
|
|
#if PLATFORM == WINDOWS
|
|
WSACleanup();
|
|
#endif
|
|
|
|
return IP4Address(address);
|
|
/*
|
|
#if PLATFORM == WINDOWS
|
|
WSACleanup();
|
|
throw std::runtime_error(std::string("Error on DNS lookup for ") + address+std::string(" : ") + std::to_string(WSAGetLastError()));
|
|
#else
|
|
throw std::runtime_error(std::string("Error on DNS lookup for ") + address+std::string(" : ")+std::string(gai_strerror(status)));
|
|
#endif
|
|
*/
|
|
}
|
|
else {
|
|
for (rp = result; rp != nullptr; rp = rp->ai_next) {
|
|
if (rp->ai_family == AF_INET){
|
|
sockaddr_in adr = *reinterpret_cast<sockaddr_in*>(rp->ai_addr);
|
|
auto number = ntohl(adr.sin_addr.s_addr);
|
|
freeaddrinfo(result);
|
|
#if PLATFORM == WINDOWS
|
|
WSACleanup();
|
|
#endif
|
|
return IP4Address(number) ;
|
|
|
|
}
|
|
}
|
|
freeaddrinfo(result);
|
|
return IP4Address();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Unfortunately, the approach here for the unix/windows is almost totally
|
|
// different, so effectively, to completely different routines
|
|
#if PLATFORM == WINDOWS
|
|
//====================================================================
|
|
std::vector<IP4Address> IP4Address::available() {
|
|
/* Note: could also use malloc() and free() */
|
|
|
|
std::vector<IP4Address> rvalue;
|
|
std::string device ;
|
|
IP4Address device_address ;
|
|
|
|
|
|
/* Declare and initialize variables */
|
|
|
|
DWORD dwSize = 0;
|
|
DWORD dwRetVal = 0;
|
|
|
|
unsigned int i = 0;
|
|
|
|
// Set the flags to pass to GetAdaptersAddresses
|
|
ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
|
|
|
|
// default to unspecified address family (both)
|
|
ULONG family = AF_INET;
|
|
|
|
LPVOID lpMsgBuf = NULL;
|
|
|
|
PIP_ADAPTER_ADDRESSES pAddresses = NULL;
|
|
ULONG outBufLen = 0;
|
|
ULONG Iterations = 0;
|
|
|
|
PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
|
|
PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
|
|
PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
|
|
PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
|
|
IP_ADAPTER_DNS_SERVER_ADDRESS* pDnServer = NULL;
|
|
IP_ADAPTER_PREFIX* pPrefix = NULL;
|
|
|
|
// Allocate a 15 KB buffer to start with.
|
|
outBufLen = WORKING_BUFFER_SIZE;
|
|
|
|
do {
|
|
|
|
pAddresses = (IP_ADAPTER_ADDRESSES*)MALLOC(outBufLen);
|
|
if (pAddresses == nullptr) {
|
|
throw std::runtime_error("Memory allocation files for IP_ADAPTER_ADDRESSES");
|
|
}
|
|
|
|
dwRetVal =
|
|
GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
|
|
|
|
if (dwRetVal == ERROR_BUFFER_OVERFLOW) {
|
|
FREE(pAddresses);
|
|
pAddresses = NULL;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
|
|
Iterations++;
|
|
|
|
} while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < MAX_TRIES));
|
|
|
|
if (dwRetVal == NO_ERROR) {
|
|
// If successful, output some information from the data we received
|
|
pCurrAddresses = pAddresses;
|
|
while (pCurrAddresses) {
|
|
|
|
|
|
|
|
pUnicast = pCurrAddresses->FirstUnicastAddress;
|
|
if (pUnicast != nullptr) {
|
|
if (pUnicast->Address.lpSockaddr->sa_family == AF_INET) {
|
|
for (i = 0; pUnicast != nullptr; i++) {
|
|
const int friendlen = 200;
|
|
|
|
char friendly[friendlen];
|
|
std::memset(friendly, 0, friendlen);
|
|
sockaddr_in* sa_in = (sockaddr_in*)pUnicast->Address.lpSockaddr;
|
|
device_address = IP4Address(ntohl(sa_in->sin_addr.S_un.S_addr ));
|
|
|
|
if (device_address != _APIPA) {
|
|
//ourdevice.address = inet_ntop(AF_INET, &(sa_in->sin_addr), buff, bufflen);
|
|
BOOL conv = false;
|
|
device = "";
|
|
if (WideCharToMultiByte(CP_UTF8, 0, pCurrAddresses->FriendlyName, -1, friendly, friendlen, 0, &conv)> 0) {
|
|
device = friendly;
|
|
}
|
|
if (!device.empty()){
|
|
// The device has a name, might be intersted
|
|
if (device.find("(WSL)")== std::string::npos){
|
|
// we dont want a psuedo WSL device on windows
|
|
rvalue.push_back(device_address) ;
|
|
}
|
|
}
|
|
|
|
}
|
|
pUnicast = pUnicast->Next;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
pCurrAddresses = pCurrAddresses->Next;
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (dwRetVal != ERROR_NO_DATA) {
|
|
if (pAddresses)
|
|
FREE(pAddresses);
|
|
|
|
throw std::runtime_error("Unable to get address info");
|
|
}
|
|
}
|
|
|
|
if (pAddresses) {
|
|
FREE(pAddresses);
|
|
}
|
|
return rvalue;
|
|
}
|
|
#else
|
|
std::vector<IP4Address> IP4Address::available() {
|
|
std::vector<IP4Address> rvalue ;
|
|
struct ifaddrs * ifAddrStruct=NULL;
|
|
struct ifaddrs * ifa=NULL;
|
|
void * tmpAddrPtr=NULL;
|
|
IP4Address device_address ;
|
|
|
|
getifaddrs(&ifAddrStruct);
|
|
|
|
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
|
|
if (!ifa->ifa_addr) {
|
|
continue;
|
|
}
|
|
if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
|
|
// is a valid IP4 Address
|
|
tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
|
|
auto holder = *reinterpret_cast<sockaddr_in *>(ifa->ifa_addr);
|
|
auto addr = IP4Address(ntohl(holder.sin_addr.s_addr));
|
|
if (addr != _APIPA){
|
|
rvalue.push_back(addr);
|
|
}
|
|
}
|
|
}
|
|
if (ifAddrStruct!=NULL) {
|
|
freeifaddrs(ifAddrStruct);
|
|
}
|
|
return rvalue ;
|
|
}
|
|
|
|
#endif
|
|
#endif
|