diff --git a/include/server.h b/include/server.h index b1c3a4232..8572003a9 100644 --- a/include/server.h +++ b/include/server.h @@ -60,7 +60,9 @@ namespace kiwix { m_withTaskbar = withTaskbar; m_withLibraryButton = withLibraryButton; } void setBlockExternalLinks(bool blockExternalLinks) { m_blockExternalLinks = blockExternalLinks; } - + int getPort(); + std::string getAddress(); + protected: Library* mp_library; NameMapper* mp_nameMapper; diff --git a/include/tools.h b/include/tools.h index 967e22ed3..45f06ca77 100644 --- a/include/tools.h +++ b/include/tools.h @@ -22,6 +22,7 @@ #include #include +#include namespace kiwix { @@ -194,5 +195,17 @@ bool fileExists(const std::string& path); * @return mimetype from filename in string format. */ std::string getMimeTypeForFile(const std::string& filename); + +/** Provides all available network interfaces + * + * This function provides the available IPv4 network interfaces + */ +std::map getNetworkInterfaces(); + +/** Provides the best IP address + * This function provides the best IP address from the list given by getNetworkInterfaces + */ +std::string getBestPublicIp(); + } #endif // KIWIX_TOOLS_H diff --git a/src/server.cpp b/src/server.cpp index 255f88883..e630515ce 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -71,4 +71,14 @@ void Server::setRoot(const std::string& root) } } +int Server::getPort() +{ + return mp_server->getPort(); +} + +std::string Server::getAddress() +{ + return mp_server->getAddress(); +} + } diff --git a/src/server/internalServer.cpp b/src/server/internalServer.cpp index d59de4d70..14d03e1ef 100644 --- a/src/server/internalServer.cpp +++ b/src/server/internalServer.cpp @@ -48,6 +48,7 @@ extern "C" { #include "tools/regexTools.h" #include "tools/stringTools.h" #include "tools/archiveTools.h" +#include "tools/networkTools.h" #include "library.h" #include "name_mapper.h" #include "entry.h" @@ -159,15 +160,16 @@ bool InternalServer::start() { sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons(m_port); if (m_addr.empty()) { - if (0 != INADDR_ANY) + if (0 != INADDR_ANY) { sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); + } + m_addr = kiwix::getBestPublicIp(); } else { if (inet_pton(AF_INET, m_addr.c_str(), &(sockAddr.sin_addr.s_addr)) == 0) { std::cerr << "Ip address " << m_addr << " is not a valid ip address" << std::endl; return false; } } - mp_daemon = MHD_start_daemon(flags, m_port, NULL, diff --git a/src/server/internalServer.h b/src/server/internalServer.h index 898ff0390..3a7d98c26 100644 --- a/src/server/internalServer.h +++ b/src/server/internalServer.h @@ -67,6 +67,8 @@ class InternalServer { void** cont_cls); bool start(); void stop(); + std::string getAddress() { return m_addr; } + int getPort() { return m_port; } private: // functions std::unique_ptr handle_request(const RequestContext& request); diff --git a/src/tools/networkTools.cpp b/src/tools/networkTools.cpp index 746fbfcae..42de314fb 100644 --- a/src/tools/networkTools.cpp +++ b/src/tools/networkTools.cpp @@ -1,5 +1,6 @@ /* * Copyright 2012 Emmanuel Engelhart + * Copyright 2021 Nikhil Tanwar <2002nikhiltanwar@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +18,7 @@ * MA 02110-1301, USA. */ +#include "tools.h" #include #include @@ -29,6 +31,17 @@ #include #include +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif size_t write_callback_to_iss(char* ptr, size_t size, size_t nmemb, void* userdata) { @@ -57,3 +70,104 @@ std::string kiwix::download(const std::string& url) { } return ss.str(); } + +std::map kiwix::getNetworkInterfaces() { + std::map interfaces; + +#ifdef _WIN32 + SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); + if (sd == SOCKET_ERROR) { + std::cerr << "Failed to get a socket. Error " << WSAGetLastError() << std::endl; + return interfaces; + } + + INTERFACE_INFO InterfaceList[20]; + unsigned long nBytesReturned; + if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, + sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) { + std::cerr << "Failed calling WSAIoctl: error " << WSAGetLastError() << std::endl; + return interfaces; + } + + int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO); + for (int i = 0; i < nNumInterfaces; ++i) { + sockaddr_in *pAddress; + pAddress = (sockaddr_in *) & (InterfaceList[i].iiAddress.AddressIn); + if(pAddress->sin_family == AF_INET) { + /* Add to the map */ + std::string interfaceName = std::string(inet_ntoa(pAddress->sin_addr)); + interfaces[interfaceName] = interfaceName; + } + } +#else + /* Get Network interfaces information */ + char buf[16384]; + struct ifconf ifconf; + int fd = socket(PF_INET, SOCK_DGRAM, 0); /* Only IPV4 */ + ifconf.ifc_len = sizeof(buf); + ifconf.ifc_buf=buf; + if(ioctl(fd, SIOCGIFCONF, &ifconf)!=0) { + perror("ioctl(SIOCGIFCONF)"); + } + + /* Go through each interface */ + struct ifreq *ifreq; + ifreq = ifconf.ifc_req; + for (int i = 0; i < ifconf.ifc_len; ) { + if (ifreq->ifr_addr.sa_family == AF_INET) { + /* Get the network interface ip */ + char host[128] = { 0 }; + const int error = getnameinfo(&(ifreq->ifr_addr), sizeof(ifreq->ifr_addr), + host, sizeof(host), + 0, 0, NI_NUMERICHOST); + if (!error) { + std::string interfaceName = std::string(ifreq->ifr_name); + std::string interfaceIp = std::string(host); + /* Add to the map */ + interfaces[interfaceName] = interfaceIp; + } else { + perror("getnameinfo()"); + } + } + + /* some systems have ifr_addr.sa_len and adjust the length that + * way, but not mine. weird */ + size_t len; +#ifndef __linux__ + len = IFNAMSIZ + ifreq->ifr_addr.sa_len; +#else + len = sizeof(*ifreq); +#endif + ifreq = (struct ifreq*)((char*)ifreq+len); + i += len; + } +#endif + return interfaces; +} + +std::string kiwix::getBestPublicIp() { + auto interfaces = getNetworkInterfaces(); + +#ifndef _WIN32 + const char* const prioritizedNames[] = + { "eth0", "eth1", "wlan0", "wlan1", "en0", "en1" }; + for(auto name: prioritizedNames) { + auto it = interfaces.find(name); + if(it != interfaces.end()) { + return it->second; + } + } +#endif + + const char* const prefixes[] = { "192.168", "172.16.", "10.0" }; + for(auto prefix : prefixes){ + for(auto& itr : interfaces) { + auto interfaceIp = itr.second; + if (interfaceIp.find(prefix) == 0) { + return interfaceIp; + } + } + } + + return "127.0.0.1"; +}