diff --git a/Config.cpp b/Config.cpp index ce0ffd04..27f0fe1d 100644 --- a/Config.cpp +++ b/Config.cpp @@ -27,6 +27,10 @@ namespace config { variables_map m_Options; void Init() { + bool nat = true; +#ifdef MESHNET + nat = false; +#endif options_description general("General options"); general.add_options() ("help", "Show this message") @@ -39,6 +43,8 @@ namespace config { ("family", value()->default_value(""), "Specify a family, router belongs to") ("datadir", value()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("host", value()->default_value("0.0.0.0"), "External IP") + ("ifname", value()->default_value(""), "network interface to bind to") + ("nat", value()->zero_tokens()->default_value(nat), "should we assume we are behind NAT?") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") ("ipv4", value()->zero_tokens()->default_value(true), "Enable communication through ipv4") ("ipv6", value()->zero_tokens()->default_value(false), "Enable communication through ipv6") diff --git a/Daemon.cpp b/Daemon.cpp index 5d0cce6f..a5628414 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -22,6 +22,7 @@ #include "I2PControl.h" #include "ClientContext.h" #include "Crypto.h" +#include "util.h" #ifdef USE_UPNP #include "UPnP.h" @@ -114,7 +115,7 @@ namespace i2p } i2p::log::Logger().Ready(); - LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); + LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); LogPrint(eLogDebug, "FS: main config file: ", config); LogPrint(eLogDebug, "FS: data directory: ", datadir); @@ -122,6 +123,14 @@ namespace i2p i2p::crypto::InitCrypto (precomputation); i2p::context.Init (); + bool ipv6; i2p::config::GetOption("ipv6", ipv6); + bool ipv4; i2p::config::GetOption("ipv4", ipv4); +#ifdef MESHNET + // manual override for meshnet + ipv4 = false; + ipv6 = true; +#endif + uint16_t port; i2p::config::GetOption("port", port); if (!i2p::config::IsDefault("port")) { @@ -129,20 +138,31 @@ namespace i2p i2p::context.UpdatePort (port); } - std::string host; i2p::config::GetOption("host", host); - if (!i2p::config::IsDefault("host")) + bool nat; i2p::config::GetOption("nat", nat); + if (nat) + { + LogPrint(eLogInfo, "Daemon: assuming be are behind NAT"); + // we are behind nat, try setting via host + std::string host; i2p::config::GetOption("host", host); + if (!i2p::config::IsDefault("host")) + { + LogPrint(eLogInfo, "Daemon: setting address for incoming connections to ", host); + i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host)); + } + } + else { - LogPrint(eLogInfo, "Daemon: setting address for incoming connections to ", host); - i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host)); + // we are not behind nat + std::string ifname; i2p::config::GetOption("ifname", ifname); + if (ifname.size()) + { + // bind to interface, we have no NAT so set external address too + auto addr = i2p::util::net::GetInterfaceAddress(ifname, ipv6); + LogPrint(eLogInfo, "Daemon: bind to network interface ", ifname, " with public address ", addr); + i2p::context.UpdateAddress(addr); + } } - bool ipv6; i2p::config::GetOption("ipv6", ipv6); - bool ipv4; i2p::config::GetOption("ipv4", ipv4); -#ifdef MESHNET - // manual override for meshnet - ipv4 = false; - ipv6 = true; -#endif bool transit; i2p::config::GetOption("notransit", transit); i2p::context.SetSupportsV6 (ipv6); i2p::context.SetSupportsV4 (ipv4); diff --git a/util.cpp b/util.cpp index 5230f55f..7fc0daca 100644 --- a/util.cpp +++ b/util.cpp @@ -413,7 +413,53 @@ namespace net return GetMTUUnix(localAddress, fallback); #endif return fallback; - } + } + + const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6) + { +#ifdef WIN32 + LogPrint(eLogError, "NetIface: cannot get address by interface name, not implemented on WIN32"); + return boost::asio::ip::from_string("127.0.0.1"); +#else + int af = (ipv6 ? AF_INET6 : AF_INET); + ifaddrs * addrs = nullptr; + if(getifaddrs(&addrs) == 0) + { + // got ifaddrs + ifaddrs * cur = addrs; + while(cur) + { + std::string cur_ifname(cur->ifa_name); + if (cur_ifname == ifname && cur->ifa_addr->sa_family == af) + { + // match + size_t sz = (ipv6 ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN); + char * addr = new char[sz]; + addr[sz-1] = 0; + socklen_t sl = (ipv6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in)); + // this probably won't screw up (right?) + inet_ntop(af, cur->ifa_addr, addr, sl); + std::string cur_ifaddr(addr); + delete [] addr; + freeifaddrs(addrs); + return boost::asio::ip::address::from_string(cur_ifaddr); + } + cur = cur->ifa_next; + } + } + if(addrs) freeifaddrs(addrs); + std::string fallback; + if(ipv6) { + fallback = "::"; + LogPrint(eLogWarning, "NetIface: cannot find ipv6 address for interface ", ifname); + } else { + fallback = "127.0.0.1"; + LogPrint(eLogWarning, "NetIface: cannot find ipv4 address for interface ", ifname); + } + return boost::asio::ip::address::from_string(fallback); + +#endif + } } } // util diff --git a/util.h b/util.h index 9f797158..7c393e02 100644 --- a/util.h +++ b/util.h @@ -66,6 +66,7 @@ namespace util namespace net { int GetMTU (const boost::asio::ip::address& localAddress); + const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6=false); } } }