mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-01-22 20:44:39 +00:00
commit
c9d5b3c0ff
12
Config.cpp
12
Config.cpp
@ -113,6 +113,7 @@ namespace config {
|
||||
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file (stdout if not set, file - otherwise, for compatibility)")
|
||||
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
|
||||
("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error)")
|
||||
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
|
||||
("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
|
||||
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
|
||||
("ipv6", value<bool>()->zero_tokens()->default_value(false), "Enable communication through ipv6")
|
||||
@ -223,6 +224,15 @@ namespace config {
|
||||
|
||||
void Finalize() {
|
||||
notify(m_Options);
|
||||
};
|
||||
}
|
||||
|
||||
bool IsDefault(const char *name) {
|
||||
if (!m_Options.count(name))
|
||||
throw "try to check non-existent option";
|
||||
|
||||
if (m_Options[name].defaulted())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
} // namespace config
|
||||
} // namespace i2p
|
||||
|
7
Config.h
7
Config.h
@ -94,6 +94,13 @@ namespace config {
|
||||
notify(m_Options);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check is value explicitly given or default
|
||||
* @param name Name of checked parameter
|
||||
* @return true if value set to default, false othervise
|
||||
*/
|
||||
bool IsDefault(const char *name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,14 +83,14 @@ namespace i2p
|
||||
LogPrint(eLogDebug, "FS: data directory: ", datadir);
|
||||
|
||||
uint16_t port; i2p::config::GetOption("port", port);
|
||||
if (port)
|
||||
if (!i2p::config::IsDefault("port"))
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
|
||||
i2p::context.UpdatePort (port);
|
||||
}
|
||||
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (host != "0.0.0.0")
|
||||
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));
|
||||
@ -125,7 +125,10 @@ namespace i2p
|
||||
i2p::context.SetExtraBandwidth ();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint(eLogInfo, "Daemon: bandwidth set to 'low'");
|
||||
i2p::context.SetLowBandwidth ();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ namespace datagram
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeTunnel,
|
||||
leases[i].tunnelGateway, leases[i].tunnelID,
|
||||
leases[i]->tunnelGateway, leases[i]->tunnelID,
|
||||
garlic
|
||||
});
|
||||
outboundTunnel->SendTunnelDataMsg (msgs);
|
||||
|
@ -303,7 +303,7 @@ namespace client
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "New remote LeaseSet verification failed");
|
||||
LogPrint (eLogError, "New remote LeaseSet failed");
|
||||
leaseSet = nullptr;
|
||||
}
|
||||
}
|
||||
@ -678,7 +678,7 @@ namespace client
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
for (auto it = m_RemoteLeaseSets.begin (); it != m_RemoteLeaseSets.end ();)
|
||||
{
|
||||
if (ts > it->second->GetExpirationTime ()) // leaseset expired
|
||||
if (it->second->IsEmpty () || ts > it->second->GetExpirationTime ()) // leaseset expired
|
||||
{
|
||||
LogPrint (eLogWarning, "Destination: Remote LeaseSet ", it->second->GetIdentHash ().ToBase64 (), " expired");
|
||||
it = m_RemoteLeaseSets.erase (it);
|
||||
|
@ -265,9 +265,9 @@ namespace i2p
|
||||
auto leases = leaseSet->GetNonExpiredLeases ();
|
||||
if (leases.size () > 0)
|
||||
{
|
||||
htobe32buf (payload + size, leases[0].tunnelID);
|
||||
htobe32buf (payload + size, leases[0]->tunnelID);
|
||||
size += 4; // reply tunnelID
|
||||
memcpy (payload + size, leases[0].tunnelGateway, 32);
|
||||
memcpy (payload + size, leases[0]->tunnelGateway, 32);
|
||||
size += 32; // reply tunnel gateway
|
||||
}
|
||||
else
|
||||
|
76
LeaseSet.cpp
76
LeaseSet.cpp
@ -69,7 +69,6 @@ namespace data
|
||||
|
||||
void LeaseSet::Update (const uint8_t * buf, size_t len)
|
||||
{
|
||||
m_Leases.clear ();
|
||||
if (len > m_BufferLen)
|
||||
{
|
||||
auto oldBuffer = m_Buffer;
|
||||
@ -84,7 +83,6 @@ namespace data
|
||||
void LeaseSet::PopulateLeases ()
|
||||
{
|
||||
m_StoreLeases = true;
|
||||
m_Leases.clear ();
|
||||
ReadFromBuffer (false);
|
||||
}
|
||||
|
||||
@ -112,8 +110,16 @@ namespace data
|
||||
return;
|
||||
}
|
||||
|
||||
// reset existing leases
|
||||
if (m_StoreLeases)
|
||||
for (auto it: m_Leases)
|
||||
it->isUpdated = false;
|
||||
else
|
||||
m_Leases.clear ();
|
||||
|
||||
// process leases
|
||||
m_ExpirationTime = 0;
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
const uint8_t * leases = m_Buffer + size;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
@ -124,21 +130,48 @@ namespace data
|
||||
leases += 4; // tunnel ID
|
||||
lease.endDate = bufbe64toh (leases);
|
||||
leases += 8; // end date
|
||||
if (lease.endDate > m_ExpirationTime)
|
||||
m_ExpirationTime = lease.endDate;
|
||||
if (m_StoreLeases)
|
||||
if (ts < lease.endDate)
|
||||
{
|
||||
m_Leases.push_back (lease);
|
||||
// check if lease's gateway is in our netDb
|
||||
if (!netdb.FindRouter (lease.tunnelGateway))
|
||||
{
|
||||
// if not found request it
|
||||
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
|
||||
netdb.RequestDestination (lease.tunnelGateway);
|
||||
}
|
||||
}
|
||||
if (lease.endDate > m_ExpirationTime)
|
||||
m_ExpirationTime = lease.endDate;
|
||||
if (m_StoreLeases)
|
||||
{
|
||||
auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
|
||||
if (!ret.second) *(*ret.first) = lease; // update existing
|
||||
(*ret.first)->isUpdated = true;
|
||||
// check if lease's gateway is in our netDb
|
||||
if (!netdb.FindRouter (lease.tunnelGateway))
|
||||
{
|
||||
// if not found request it
|
||||
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
|
||||
netdb.RequestDestination (lease.tunnelGateway);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "LeaseSet: Lease is expired already ");
|
||||
}
|
||||
|
||||
if (!m_ExpirationTime)
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped");
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
// delete old leases
|
||||
if (m_StoreLeases)
|
||||
{
|
||||
for (auto it = m_Leases.begin (); it != m_Leases.end ();)
|
||||
{
|
||||
if (!(*it)->isUpdated)
|
||||
{
|
||||
(*it)->endDate = 0; // somebody might still hold it
|
||||
m_Leases.erase (it++);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
// verify
|
||||
if (!m_Identity->Verify (m_Buffer, leases - m_Buffer, leases))
|
||||
{
|
||||
@ -147,13 +180,13 @@ namespace data
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<Lease> LeaseSet::GetNonExpiredLeases (bool withThreshold) const
|
||||
const std::vector<std::shared_ptr<Lease> > LeaseSet::GetNonExpiredLeases (bool withThreshold) const
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
std::vector<Lease> leases;
|
||||
for (auto& it: m_Leases)
|
||||
std::vector<std::shared_ptr<Lease> > leases;
|
||||
for (auto it: m_Leases)
|
||||
{
|
||||
auto endDate = it.endDate;
|
||||
auto endDate = it->endDate;
|
||||
if (!withThreshold)
|
||||
endDate -= i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000;
|
||||
if (ts < endDate)
|
||||
@ -165,13 +198,14 @@ namespace data
|
||||
bool LeaseSet::HasExpiredLeases () const
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
for (auto& it: m_Leases)
|
||||
if (ts >= it.endDate) return true;
|
||||
for (auto it: m_Leases)
|
||||
if (ts >= it->endDate) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LeaseSet::IsExpired () const
|
||||
{
|
||||
if (IsEmpty ()) return true;
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
return ts > m_ExpirationTime;
|
||||
}
|
||||
|
33
LeaseSet.h
33
LeaseSet.h
@ -4,6 +4,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
@ -20,15 +21,19 @@ namespace data
|
||||
{
|
||||
IdentHash tunnelGateway;
|
||||
uint32_t tunnelID;
|
||||
uint64_t endDate;
|
||||
uint64_t endDate; // 0 means invalid
|
||||
bool isUpdated; // trasient
|
||||
};
|
||||
|
||||
bool operator< (const Lease& other) const
|
||||
{
|
||||
if (endDate != other.endDate)
|
||||
return endDate > other.endDate;
|
||||
struct LeaseCmp
|
||||
{
|
||||
bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const
|
||||
{
|
||||
if (l1->tunnelID != l2->tunnelID)
|
||||
return l1->tunnelID < l2->tunnelID;
|
||||
else
|
||||
return tunnelID < other.tunnelID;
|
||||
}
|
||||
return l1->tunnelGateway < l2->tunnelGateway;
|
||||
};
|
||||
};
|
||||
|
||||
const int MAX_LS_BUFFER_SIZE = 3072;
|
||||
@ -41,20 +46,20 @@ namespace data
|
||||
LeaseSet (std::shared_ptr<const i2p::tunnel::TunnelPool> pool);
|
||||
~LeaseSet () { delete[] m_Buffer; };
|
||||
void Update (const uint8_t * buf, size_t len);
|
||||
void PopulateLeases (); /// from buffer
|
||||
void PopulateLeases (); // from buffer
|
||||
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
||||
|
||||
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
bool IsValid () const { return m_IsValid; };
|
||||
const std::vector<std::shared_ptr<Lease> > GetNonExpiredLeases (bool withThreshold = true) const;
|
||||
bool HasExpiredLeases () const;
|
||||
bool IsExpired () const;
|
||||
bool IsEmpty () const { return m_Leases.empty (); };
|
||||
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
|
||||
|
||||
// implements RoutingDestination
|
||||
const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
|
||||
const std::vector<Lease>& GetLeases () const { return m_Leases; };
|
||||
const std::vector<Lease> GetNonExpiredLeases (bool withThreshold = true) const;
|
||||
bool HasExpiredLeases () const;
|
||||
bool IsExpired () const;
|
||||
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
|
||||
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; };
|
||||
bool IsDestination () const { return true; };
|
||||
|
||||
@ -65,7 +70,7 @@ namespace data
|
||||
private:
|
||||
|
||||
bool m_IsValid, m_StoreLeases; // we don't need to store leases for floodfill
|
||||
std::vector<Lease> m_Leases;
|
||||
std::set<std::shared_ptr<Lease>, LeaseCmp> m_Leases;
|
||||
uint64_t m_ExpirationTime; // in milliseconds
|
||||
std::shared_ptr<const IdentityEx> m_Identity;
|
||||
uint8_t m_EncryptionKey[256];
|
||||
|
@ -736,7 +736,7 @@ namespace transport
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
LogPrint (eLogWarning, "NTCP: No activity fo ", NTCP_TERMINATION_TIMEOUT, " seconds");
|
||||
LogPrint (eLogWarning, "NTCP: No activity for ", NTCP_TERMINATION_TIMEOUT, " seconds");
|
||||
//Terminate ();
|
||||
m_Socket.close ();// invoke Terminate () from HandleReceive
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ namespace i2p
|
||||
if (!port)
|
||||
port = rand () % (30777 - 9111) + 9111; // I2P network ports range
|
||||
std::string host; i2p::config::GetOption("host", host);
|
||||
if (host == "0.0.0.0")
|
||||
if (i2p::config::IsDefault("host"))
|
||||
host = "127.0.0.1"; // replace default address with safe value
|
||||
routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ());
|
||||
routerInfo.AddNTCPAddress (host.c_str(), port);
|
||||
|
@ -22,7 +22,6 @@ namespace stream
|
||||
{
|
||||
RAND_bytes ((uint8_t *)&m_RecvStreamID, 4);
|
||||
m_RemoteIdentity = remote->GetIdentity ();
|
||||
m_CurrentRemoteLease.endDate = 0;
|
||||
}
|
||||
|
||||
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local):
|
||||
@ -599,9 +598,9 @@ namespace stream
|
||||
}
|
||||
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
if (!m_CurrentRemoteLease.endDate || ts >= m_CurrentRemoteLease.endDate - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000)
|
||||
if (!m_CurrentRemoteLease || ts >= m_CurrentRemoteLease->endDate - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000)
|
||||
UpdateCurrentRemoteLease (true);
|
||||
if (ts < m_CurrentRemoteLease.endDate)
|
||||
if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate)
|
||||
{
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
|
||||
for (auto it: packets)
|
||||
@ -610,7 +609,7 @@ namespace stream
|
||||
msgs.push_back (i2p::tunnel::TunnelMessageBlock
|
||||
{
|
||||
i2p::tunnel::eDeliveryTypeTunnel,
|
||||
m_CurrentRemoteLease.tunnelGateway, m_CurrentRemoteLease.tunnelID,
|
||||
m_CurrentRemoteLease->tunnelGateway, m_CurrentRemoteLease->tunnelID,
|
||||
msg
|
||||
});
|
||||
m_NumSentBytes += it->GetLength ();
|
||||
@ -705,11 +704,11 @@ namespace stream
|
||||
|
||||
void Stream::UpdateCurrentRemoteLease (bool expired)
|
||||
{
|
||||
if (!m_RemoteLeaseSet)
|
||||
if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired ())
|
||||
{
|
||||
m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());
|
||||
if (!m_RemoteLeaseSet)
|
||||
LogPrint (eLogError, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
|
||||
if (!m_RemoteLeaseSet)
|
||||
LogPrint (eLogWarning, "Streaming: LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found");
|
||||
}
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
@ -725,10 +724,10 @@ namespace stream
|
||||
if (!leases.empty ())
|
||||
{
|
||||
bool updated = false;
|
||||
if (expired)
|
||||
if (expired && m_CurrentRemoteLease)
|
||||
{
|
||||
for (auto it: leases)
|
||||
if ((it.tunnelGateway == m_CurrentRemoteLease.tunnelGateway) && (it.tunnelID != m_CurrentRemoteLease.tunnelID))
|
||||
if ((it->tunnelGateway == m_CurrentRemoteLease->tunnelGateway) && (it->tunnelID != m_CurrentRemoteLease->tunnelID))
|
||||
{
|
||||
m_CurrentRemoteLease = it;
|
||||
updated = true;
|
||||
@ -738,7 +737,7 @@ namespace stream
|
||||
if (!updated)
|
||||
{
|
||||
uint32_t i = rand () % leases.size ();
|
||||
if (m_CurrentRemoteLease.endDate && leases[i].tunnelID == m_CurrentRemoteLease.tunnelID)
|
||||
if (m_CurrentRemoteLease && leases[i]->tunnelID == m_CurrentRemoteLease->tunnelID)
|
||||
// make sure we don't select previous
|
||||
i = (i + 1) % leases.size (); // if so, pick next
|
||||
m_CurrentRemoteLease = leases[i];
|
||||
@ -747,12 +746,12 @@ namespace stream
|
||||
else
|
||||
{
|
||||
m_RemoteLeaseSet = nullptr;
|
||||
m_CurrentRemoteLease.endDate = 0;
|
||||
m_CurrentRemoteLease = nullptr;
|
||||
// re-request expired
|
||||
}
|
||||
}
|
||||
else
|
||||
m_CurrentRemoteLease.endDate = 0;
|
||||
m_CurrentRemoteLease = nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> Stream::CreateDataMessage (const uint8_t * payload, size_t len)
|
||||
@ -879,7 +878,7 @@ namespace stream
|
||||
it->second.push_back (packet);
|
||||
else
|
||||
{
|
||||
m_SavedPackets.emplace (receiveStreamID, std::list<Packet *>{ packet });
|
||||
m_SavedPackets[receiveStreamID] = std::list<Packet *>{ packet };
|
||||
auto timer = std::make_shared<boost::asio::deadline_timer> (m_Owner->GetService ());
|
||||
timer->expires_from_now (boost::posix_time::seconds(PENDING_INCOMING_TIMEOUT));
|
||||
auto s = shared_from_this ();
|
||||
|
@ -172,7 +172,7 @@ namespace stream
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
||||
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
|
||||
i2p::data::Lease m_CurrentRemoteLease;
|
||||
std::shared_ptr<i2p::data::Lease> m_CurrentRemoteLease;
|
||||
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
|
||||
std::queue<Packet *> m_ReceiveQueue;
|
||||
std::set<Packet *, PacketCmp> m_SavedPackets;
|
||||
|
@ -666,6 +666,10 @@ namespace tunnel
|
||||
{
|
||||
// trying to create one more inbound tunnel
|
||||
auto router = i2p::data::netdb.GetRandomRouter ();
|
||||
if (!router) {
|
||||
LogPrint (eLogWarning, "Tunnel: can't find any router, skip creating tunnel");
|
||||
return;
|
||||
}
|
||||
LogPrint (eLogDebug, "Tunnel: creating one hop inbound tunnel");
|
||||
CreateTunnel<InboundTunnel> (
|
||||
std::make_shared<TunnelConfig> (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > { router->GetRouterIdentity () })
|
||||
|
6
debian/i2pd.init
vendored
6
debian/i2pd.init
vendored
@ -18,6 +18,7 @@ DAEMON_OPTS="" # Arguments to run the daemon with
|
||||
PIDFILE=/var/run/$NAME.pid
|
||||
I2PCONF=/etc/$NAME/i2pd.conf
|
||||
TUNCONF=/etc/$NAME/tunnels.conf
|
||||
LOGFILE=/var/log/$NAME.log
|
||||
USER="i2pd"
|
||||
|
||||
# Exit if the package is not installed
|
||||
@ -43,10 +44,13 @@ do_start()
|
||||
touch "$PIDFILE"
|
||||
chown -f $USER:adm "$PIDFILE"
|
||||
|
||||
touch "$LOGFILE"
|
||||
chown -f $USER:adm "$LOGFILE"
|
||||
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" --test > /dev/null \
|
||||
|| return 1
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" -- \
|
||||
--service --daemon --log --conf=$I2PCONF --tunconf=$TUNCONF \
|
||||
--service --daemon --log=file --logfile=$LOGFILE --conf=$I2PCONF --tunconf=$TUNCONF \
|
||||
--port=$I2PD_PORT $DAEMON_OPTS > /dev/null 2>&1 \
|
||||
|| return 2
|
||||
return $?
|
||||
|
3
debian/i2pd.upstart
vendored
3
debian/i2pd.upstart
vendored
@ -6,5 +6,6 @@ stop on runlevel [016] or unmounting-filesystem
|
||||
# these can be overridden in /etc/init/i2pd.override
|
||||
env I2PD_HOST="1.2.3.4"
|
||||
env I2PD_PORT="4567"
|
||||
env LOGFILE="/var/log/i2pd.log"
|
||||
|
||||
exec /usr/sbin/i2pd --daemon --log --host=$I2PD_HOST --port=$I2PD_PORT
|
||||
exec /usr/sbin/i2pd --daemon --log=file --logfile=$LOGFILE --service --host=$I2PD_HOST --port=$I2PD_PORT
|
||||
|
@ -12,6 +12,7 @@ Command line options
|
||||
* --log= - Logs destination: stdout, file (stdout if not set, file - otherwise, for compatibility)
|
||||
* --logfile= - Path to logfile (default - autodetect)
|
||||
* --loglevel= - Log messages above this level (debug, *info, warn, error)
|
||||
* --datadir= - Path to storage of i2pd data (RI, keys, peer profiles, ...)
|
||||
* --host= - The external IP
|
||||
* --port= - The port to listen on
|
||||
* --daemon - Router will go to background after start
|
||||
|
Loading…
x
Reference in New Issue
Block a user