diff --git a/android/assets/i2pd.conf b/android/assets/i2pd.conf index a18e13d7..312a24ea 100644 --- a/android/assets/i2pd.conf +++ b/android/assets/i2pd.conf @@ -37,7 +37,12 @@ port = 7070 enabled = true address = 127.0.0.1 port = 4444 -# keys = http-proxy-keys.dat +inbound.length = 1 +inbound.quantity = 5 +outbound.length = 1 +outbound.quantity = 5 +signaturetype=7 +keys = proxy-keys.dat # addresshelper = true # outproxy = http://false.i2p ## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. @@ -46,7 +51,7 @@ port = 4444 enabled = true address = 127.0.0.1 port = 4447 -# keys = socks-proxy-keys.dat +keys = proxy-keys.dat # outproxy.enabled = false # outproxy = 127.0.0.1 # outproxyport = 9050 @@ -80,3 +85,6 @@ verify = true [limits] transittunnels = 50 + +[persist] +profiles = false diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp index 8791c90b..ac968fd3 100755 --- a/android/jni/i2pd_android.cpp +++ b/android/jni/i2pd_android.cpp @@ -58,6 +58,11 @@ JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels i2p::context.SetAcceptsTunnels (false); } +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels + (JNIEnv * env, jclass clazz) { + i2p::context.SetAcceptsTunnels (true); +} + JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged (JNIEnv * env, jclass clazz, jboolean isConnected) { diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h index 04923d22..7beb1284 100644 --- a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h +++ b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h @@ -24,6 +24,9 @@ JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels (JNIEnv *, jclass); +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels + (JNIEnv *, jclass); + JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged (JNIEnv * env, jclass clazz, jboolean isConnected); diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml index a0cc264c..18aef3b1 100755 --- a/android/res/values/strings.xml +++ b/android/res/values/strings.xml @@ -3,6 +3,7 @@ i2pd Stop Graceful Stop + Cancel Graceful Stop Graceful stop is already in progress Graceful stop is in progress Already stopped diff --git a/android/src/org/purplei2p/i2pd/DaemonSingleton.java b/android/src/org/purplei2p/i2pd/DaemonSingleton.java index 4f3e62f7..4c3d5f44 100644 --- a/android/src/org/purplei2p/i2pd/DaemonSingleton.java +++ b/android/src/org/purplei2p/i2pd/DaemonSingleton.java @@ -33,6 +33,13 @@ public class DaemonSingleton { } } + public synchronized void startAcceptingTunnels() { + if(isStartedOkay()){ + setState(State.startedOkay); + I2PD_JNI.startAcceptingTunnels(); + } + } + private volatile boolean startedOkay; public enum State { diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index bc6f7209..3c95a832 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -13,13 +13,16 @@ import java.io.StringWriter; import java.util.Timer; import java.util.TimerTask; +import android.Manifest; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.res.AssetManager; +import android.content.pm.PackageManager; import android.os.Bundle; +import android.os.Build; import android.os.Environment; import android.os.IBinder; import android.util.Log; @@ -27,12 +30,15 @@ import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import android.widget.Toast; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; // For future package update checking import org.purplei2p.i2pd.BuildConfig; public class I2PDActivity extends Activity { private static final String TAG = "i2pdActvt"; + private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1; public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; private TextView textView; @@ -93,6 +99,17 @@ public class I2PDActivity extends Activity { daemon.addStateChangeListener(daemonStateUpdatedListener); daemonStateUpdatedListener.daemonStateUpdate(); + // request permissions + if (Build.VERSION.SDK_INT >= 23) + { + if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) + { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE); + } + } + // set the app be foreground doBindService(); @@ -119,6 +136,24 @@ public class I2PDActivity extends Activity { } } + @Override + public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) + { + switch (requestCode) + { + case MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE: + { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) + Log.e(TAG, "Memory permission granted"); + else + Log.e(TAG, "Memory permission declined"); + // TODO: terminate + return; + } + default: ; + } + } + private static void cancelGracefulStop() { Timer gracefulQuitTimer = getGracefulQuitTimer(); if(gracefulQuitTimer!=null) { @@ -205,7 +240,16 @@ public class I2PDActivity extends Activity { i2pdStop(); return true; case R.id.action_graceful_stop: - i2pdGracefulStop(); + if (getGracefulQuitTimer()!= null) + { + item.setTitle(R.string.action_graceful_stop); + i2pdCancelGracefulStop (); + } + else + { + item.setTitle(R.string.action_cancel_graceful_stop); + i2pdGracefulStop(); + } return true; } @@ -268,6 +312,32 @@ public class I2PDActivity extends Activity { },"gracInit").start(); } + + private void i2pdCancelGracefulStop() + { + cancelGracefulStop(); + Toast.makeText(this, R.string.startedOkay, Toast.LENGTH_SHORT).show(); + new Thread(new Runnable() + { + @Override + public void run() + { + try + { + Log.d(TAG, "grac stopping cancel"); + if(daemon.isStartedOkay()) + daemon.startAcceptingTunnels(); + else + i2pdStop(); + } + catch(Throwable tr) + { + Log.e(TAG,"",tr); + } + } + + },"gracCancel").start(); + } private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel(); diff --git a/android/src/org/purplei2p/i2pd/I2PD_JNI.java b/android/src/org/purplei2p/i2pd/I2PD_JNI.java index f965d471..63867273 100644 --- a/android/src/org/purplei2p/i2pd/I2PD_JNI.java +++ b/android/src/org/purplei2p/i2pd/I2PD_JNI.java @@ -12,6 +12,8 @@ public class I2PD_JNI { public static native void stopAcceptingTunnels(); + public static native void startAcceptingTunnels(); + public static native void onNetworkStateChanged(boolean isConnected); public static void loadLibraries() { diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 40949cc1..1ef725bb 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -93,6 +93,8 @@ ipv6 = false ## Address and port service will listen on address = 127.0.0.1 port = 7070 +## Path to web console, default "/" +# webroot = / ## Uncomment following lines to enable Web Console authentication # auth = true # user = i2pd @@ -223,3 +225,7 @@ verify = true # inbound.quantity = 3 # outbound.length = 2 # outbound.quantity = 3 + +[persist] +## Save peer profiles on disk (default: true) +# profiles = true diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 984ccffa..7888878d 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -55,19 +55,22 @@ make %{?_smp_mflags} %install cd build +%if 0%{?mageia} +cd build +%endif chrpath -d i2pd -install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd -install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf -install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf -install -d -m 755 %{buildroot}%{_datadir}/i2pd -install -d -m 755 %{buildroot}%{_datadir}/i2pd/tunnels.conf.d -%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates -%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/tunnels.d/ %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d -install -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service -install -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd -install -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd +%{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd +%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf +%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/subscriptions.txt %{buildroot}%{_sysconfdir}/i2pd/subscriptions.txt +%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf +%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.d/README %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d/README +%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service +%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/debian/i2pd.1 %{buildroot}%{_mandir}/man1/i2pd.1 +%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd +%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd +%{__install} -d -m 755 %{buildroot}%{_datadir}/%{name} +%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/%{name}/certificates ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates -ln -s %{_datadir}/i2pd/tunnels.conf.d %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d %pre @@ -90,14 +93,14 @@ getent passwd i2pd >/dev/null || \ %files -%doc LICENSE README.md +%doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d %{_sbindir}/i2pd -%{_datadir}/i2pd/certificates %config(noreplace) %{_sysconfdir}/i2pd/* -%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/* -/%{_unitdir}/i2pd.service -%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd +%{_unitdir}/i2pd.service +%{_mandir}/man1/i2pd.1* %dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd +%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd +%{_datadir}/%{name}/certificates %{_sharedstatedir}/i2pd/certificates diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 5daeef2c..f7577f0e 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -53,6 +53,9 @@ make %{?_smp_mflags} %install cd build +%if 0%{?mageia} +cd build +%endif chrpath -d i2pd install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf diff --git a/contrib/tunnels.d/IRC-Irc2P.conf b/contrib/tunnels.d/IRC-Irc2P.conf index 7255f9d5..97da71dc 100644 --- a/contrib/tunnels.d/IRC-Irc2P.conf +++ b/contrib/tunnels.d/IRC-Irc2P.conf @@ -4,4 +4,4 @@ #port = 6668 #destination = irc.postman.i2p #destinationport = 6667 -#keys = irc-keys.dat \ No newline at end of file +#keys = irc-keys.dat diff --git a/contrib/tunnels.d/README b/contrib/tunnels.d/README index 3ac3c1a3..7b07c4be 100644 --- a/contrib/tunnels.d/README +++ b/contrib/tunnels.d/README @@ -1 +1,4 @@ -In that directory you can store separated config files for every tunnel. \ No newline at end of file +# In that directory you can store separated config files for every tunnel. +# Please read documentation for more info. +# +# You can find examples in /usr/share/doc/i2pd/tunnels.d directory diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 0b88e983..8e0804d1 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -23,6 +23,7 @@ #include "ClientContext.h" #include "Crypto.h" #include "UPnP.h" +#include "Timestamp.h" #include "util.h" #include "Event.h" @@ -41,6 +42,7 @@ namespace i2p std::unique_ptr httpServer; std::unique_ptr m_I2PControlService; std::unique_ptr UPnP; + std::unique_ptr m_NTPSync; #ifdef WITH_EVENTS std::unique_ptr m_WebsocketServer; #endif @@ -282,6 +284,13 @@ namespace i2p d.UPnP->Start (); } + bool nettime; i2p::config::GetOption("nettime.enabled", nettime); + if (nettime) + { + d.m_NTPSync = std::unique_ptr(new i2p::util::NTPTimeSync); + d.m_NTPSync->Start (); + } + bool ntcp; i2p::config::GetOption("ntcp", ntcp); bool ssu; i2p::config::GetOption("ssu", ssu); LogPrint(eLogInfo, "Daemon: starting Transports"); @@ -351,11 +360,18 @@ namespace i2p LogPrint(eLogInfo, "Daemon: stopping Tunnels"); i2p::tunnel::tunnels.Stop(); - if (d.UPnP) { + if (d.UPnP) + { d.UPnP->Stop (); d.UPnP = nullptr; } + if (d.m_NTPSync) + { + d.m_NTPSync->Stop (); + d.m_NTPSync = nullptr; + } + LogPrint(eLogInfo, "Daemon: stopping Transports"); i2p::transport::transports.Stop(); LogPrint(eLogInfo, "Daemon: stopping NetDB"); diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index b4c3f79b..ccf2640c 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -155,6 +155,8 @@ namespace http { static void ShowPageHead (std::stringstream& s) { + std::string webroot; + i2p::config::GetOption("http.webroot", webroot); s << "\r\n" "\r\n" /* TODO: Add support for locale */ @@ -173,16 +175,16 @@ namespace http { "
i2pd webconsole
\r\n" "
\r\n" "
\r\n" - " Main page
\r\n
\r\n" - " Router commands
\r\n" - " Local destinations
\r\n" - " LeaseSets
\r\n" - " Tunnels
\r\n" - " Transit tunnels
\r\n" - " Transports
\r\n" - " I2P tunnels
\r\n"; + " Main page
\r\n
\r\n" + " Router commands
\r\n" + " Local destinations
\r\n" + " LeaseSets
\r\n" + " Tunnels
\r\n" + " Transit tunnels
\r\n" + " Transports
\r\n" + " I2P tunnels
\r\n"; if (i2p::client::context.GetSAMBridge ()) - s << " SAM sessions
\r\n"; + s << " SAM sessions
\r\n"; s << "
\r\n" "
"; @@ -321,11 +323,12 @@ namespace http { void ShowLocalDestinations (std::stringstream& s) { + std::string webroot; i2p::config::GetOption("http.webroot", webroot); s << "Local Destinations:
\r\n
\r\n"; for (auto& it: i2p::client::context.GetDestinations ()) { auto ident = it.second->GetIdentHash (); - s << ""; + s << ""; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n" << std::endl; } @@ -340,7 +343,7 @@ namespace http { { auto ident = dest->GetIdentHash (); auto& name = dest->GetNickname (); - s << "[ "; + s << "[ "; s << name << " ] ⇔ " << i2p::client::context.GetAddressBook ().ToAddress(ident) <<"
\r\n" << std::endl; } } @@ -510,33 +513,34 @@ namespace http { static void ShowCommands (std::stringstream& s, uint32_t token) { + std::string webroot; i2p::config::GetOption("http.webroot", webroot); /* commands */ s << "Router Commands
\r\n
\r\n"; - s << " Run peer test
\r\n"; + s << " Run peer test
\r\n"; //s << " Reload config
\r\n"; if (i2p::context.AcceptsTunnels ()) - s << " Decline transit tunnels
\r\n"; + s << " Decline transit tunnels
\r\n"; else - s << " Accept transit tunnels
\r\n"; + s << " Accept transit tunnels
\r\n"; #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) if (Daemon.gracefulShutdownInterval) - s << " Cancel graceful shutdown
"; + s << " Cancel graceful shutdown
"; else - s << " Start graceful shutdown
\r\n"; + s << " Start graceful shutdown
\r\n"; #elif defined(WIN32_APP) if (i2p::util::DaemonWin32::Instance().isGraceful) - s << " Cancel graceful shutdown
"; + s << " Cancel graceful shutdown
"; else - s << " Graceful shutdown
\r\n"; + s << " Graceful shutdown
\r\n"; #endif - s << " Force shutdown
\r\n"; + s << " Force shutdown
\r\n"; s << "
\r\nLogging level
\r\n"; - s << " [none] "; - s << " [error] "; - s << " [warn] "; - s << " [info] "; - s << " [debug]
\r\n"; + s << " [none] "; + s << " [error] "; + s << " [warn] "; + s << " [info] "; + s << " [debug]
\r\n"; } void ShowTransitTunnels (std::stringstream& s) @@ -653,6 +657,7 @@ namespace http { void ShowSAMSessions (std::stringstream& s) { + std::string webroot; i2p::config::GetOption("http.webroot", webroot); auto sam = i2p::client::context.GetSAMBridge (); if (!sam) { ShowError(s, "SAM disabled"); @@ -662,13 +667,14 @@ namespace http { for (auto& it: sam->GetSessions ()) { auto& name = it.second->localDestination->GetNickname (); - s << ""; + s << ""; s << name << " (" << it.first << ")
\r\n" << std::endl; } } static void ShowSAMSession (std::stringstream& s, const std::string& id) { + std::string webroot; i2p::config::GetOption("http.webroot", webroot); s << "SAM Session:
\r\n
\r\n"; auto sam = i2p::client::context.GetSAMBridge (); if (!sam) { @@ -681,7 +687,7 @@ namespace http { return; } auto& ident = session->localDestination->GetIdentHash(); - s << ""; + s << ""; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "
\r\n"; s << "
\r\n"; s << "Streams:
\r\n"; @@ -701,11 +707,12 @@ namespace http { void ShowI2PTunnels (std::stringstream& s) { + std::string webroot; i2p::config::GetOption("http.webroot", webroot); s << "Client Tunnels:
\r\n
\r\n"; for (auto& it: i2p::client::context.GetClientTunnels ()) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -714,7 +721,7 @@ namespace http { if (httpProxy) { auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << "HTTP Proxy" << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -723,7 +730,7 @@ namespace http { if (socksProxy) { auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << "SOCKS Proxy" << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -734,7 +741,7 @@ namespace http { for (auto& it: serverTunnels) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇒ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << ":" << it.second->GetLocalPort (); @@ -748,7 +755,7 @@ namespace http { for (auto& it: clientForwards) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -761,7 +768,7 @@ namespace http { for (auto& it: serverForwards) { auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); - s << ""; + s << ""; s << it.second->GetName () << " ⇐ "; s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << "
\r\n"<< std::endl; @@ -1025,10 +1032,12 @@ namespace http { ShowError(s, "Unknown command: " + cmd); return; } + std::string webroot; i2p::config::GetOption("http.webroot", webroot); + std::string redirect = "5; url=" + webroot + "?page=commands"; s << "SUCCESS: Command accepted

\r\n"; - s << "Back to commands list
\r\n"; + s << "Back to commands list
\r\n"; s << "

You will be redirected in 5 seconds"; - res.add_header("Refresh", "5; url=/?page=commands"); + res.add_header("Refresh", redirect.c_str()); } void HTTPConnection::SendReply (HTTPRes& reply, std::string& content) diff --git a/debian/docs b/debian/docs index b67deb18..dfa6f572 100644 --- a/debian/docs +++ b/debian/docs @@ -2,3 +2,4 @@ README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf +contrib/tunnels.d diff --git a/debian/i2pd.dirs b/debian/i2pd.dirs index 736e23bd..3b643352 100644 --- a/debian/i2pd.dirs +++ b/debian/i2pd.dirs @@ -1,3 +1,2 @@ etc/i2pd -etc/i2pd/tunnels.conf.d var/lib/i2pd diff --git a/debian/i2pd.install b/debian/i2pd.install index cae69c0e..d20b2c17 100644 --- a/debian/i2pd.install +++ b/debian/i2pd.install @@ -3,5 +3,5 @@ contrib/i2pd.conf etc/i2pd/ contrib/tunnels.conf etc/i2pd/ contrib/subscriptions.txt etc/i2pd/ contrib/certificates/ usr/share/i2pd/ -contrib/tunnels.d/ etc/i2pd/tunnels.conf.d +contrib/tunnels.d/README etc/i2pd/tunnels.conf.d/ contrib/apparmor/usr.sbin.i2pd etc/apparmor.d diff --git a/debian/i2pd.links b/debian/i2pd.links index 083bc6ca..a149967f 100644 --- a/debian/i2pd.links +++ b/debian/i2pd.links @@ -1,5 +1,5 @@ etc/i2pd/i2pd.conf var/lib/i2pd/i2pd.conf etc/i2pd/tunnels.conf var/lib/i2pd/tunnels.conf etc/i2pd/subscriptions.txt var/lib/i2pd/subscriptions.txt -etc/i2pd/tunnels.conf.d var/lib/i2pd/tunnels.conf.d +etc/i2pd/tunnels.conf.d var/lib/i2pd/tunnels.d usr/share/i2pd/certificates var/lib/i2pd/certificates diff --git a/libi2pd/ChaCha20.cpp b/libi2pd/ChaCha20.cpp index e43f1514..30e02f42 100644 --- a/libi2pd/ChaCha20.cpp +++ b/libi2pd/ChaCha20.cpp @@ -1,21 +1,23 @@ -#include "ChaCha20.h" - -/** - This code is licensed under the MCGSI Public License - Copyright 2018 Jeff Becker +/* +* Copyright (c) 2013-2018, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +* +* Kovri go write your own code +* +*/ - Kovri go write your own code +#include "ChaCha20.h" - */ +#if LEGACY_OPENSSL namespace i2p { namespace crypto { namespace chacha { -constexpr int rounds = 20; -constexpr std::size_t blocksize = 64; - void u32t8le(uint32_t v, uint8_t * p) { p[0] = v & 0xff; @@ -48,44 +50,18 @@ void quarterround(uint32_t *x, int a, int b, int c, int d) x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7); } - struct State_t - { - State_t() {}; - State_t(State_t &&) = delete; - - State_t & operator += (const State_t & other) - { - for(int i = 0; i < 16; i++) - data[i] += other.data[i]; - return *this; - } - - void Copy(const State_t & other) - { - memcpy(data, other.data, sizeof(uint32_t) * 16); - } - uint32_t data[16]; - }; - - struct Block_t - { - Block_t() {}; - Block_t(Block_t &&) = delete; - - uint8_t data[blocksize]; - void operator << (const State_t & st) - { - int i; - for (i = 0; i < 16; i++) - u32t8le(st.data[i], data + (i << 2)); - } - }; +void Chacha20Block::operator << (const Chacha20State & st) +{ + int i; + for (i = 0; i < 16; i++) + u32t8le(st.data[i], data + (i << 2)); +} -void block(const State_t &input, Block_t & block, int rounds) +void block (Chacha20State &input, int rounds) { int i; - State_t x; + Chacha20State x; x.Copy(input); for (i = rounds; i > 0; i -= 2) @@ -100,48 +76,61 @@ void block(const State_t &input, Block_t & block, int rounds) quarterround(x.data, 3, 4, 9, 14); } x += input; - block << x; + input.block << x; } -} // namespace chacha - - - - -void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter) +void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter) { - chacha::State_t state; - chacha::Block_t block; - size_t i, j; - - state.data[0] = 0x61707865; - state.data[1] = 0x3320646e; - state.data[2] = 0x79622d32; - state.data[3] = 0x6b206574; - - for (i = 0; i < 8; i++) - state.data[4 + i] = chacha::u8t32le(key + i * 4); - - - state.data[12] = counter; - - for (i = 0; i < 3; i++) - state.data[13 + i] = chacha::u8t32le(nonce + i * 4); - - - for (i = 0; i < sz; i += chacha::blocksize) - { - chacha::block(state, block, chacha::rounds); - state.data[12]++; - for (j = i; j < i + chacha::blocksize; j++) - { - if (j >= sz) break; - buf[j] ^= block.data[j - i]; - } - } + state.data[0] = 0x61707865; + state.data[1] = 0x3320646e; + state.data[2] = 0x79622d32; + state.data[3] = 0x6b206574; + for (size_t i = 0; i < 8; i++) + state.data[4 + i] = chacha::u8t32le(key + i * 4); + + state.data[12] = counter; + for (size_t i = 0; i < 3; i++) + state.data[13 + i] = chacha::u8t32le(nonce + i * 4); +} +void Chacha20SetCounter (Chacha20State& state, uint32_t counter) +{ + state.data[12] = counter; + state.offset = 0; +} + +void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz) +{ + if (state.offset > 0) + { + // previous block if any + auto s = chacha::blocksize - state.offset; + if (sz < s) s = sz; + for (size_t i = 0; i < s; i++) + buf[i] ^= state.block.data[state.offset + i]; + buf += s; + sz -= s; + state.offset = 0; + } + for (size_t i = 0; i < sz; i += chacha::blocksize) + { + chacha::block(state, chacha::rounds); + state.data[12]++; + for (size_t j = i; j < i + chacha::blocksize; j++) + { + if (j >= sz) + { + state.offset = j & 0x3F; // % 64 + break; + } + buf[j] ^= state.block.data[j - i]; + } + } } +} // namespace chacha } -} \ No newline at end of file +} +#endif + diff --git a/libi2pd/ChaCha20.h b/libi2pd/ChaCha20.h index c88325d5..a5a8aafc 100644 --- a/libi2pd/ChaCha20.h +++ b/libi2pd/ChaCha20.h @@ -1,26 +1,72 @@ -/** - This code is licensed under the MCGSI Public License - Copyright 2018 Jeff Becker - - Kovri go write your own code - - */ +/* +* Copyright (c) 2013-2018, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +* +* Kovri go write your own code +* +*/ #ifndef LIBI2PD_CHACHA20_H #define LIBI2PD_CHACHA20_H #include #include +#include +#include +#include "Crypto.h" +#if LEGACY_OPENSSL namespace i2p { namespace crypto { - const std::size_t CHACHA20_KEY_BYTES = 32; - const std::size_t CHACHA20_NOUNCE_BYTES = 12; + const std::size_t CHACHA20_KEY_BYTES = 32; + const std::size_t CHACHA20_NOUNCE_BYTES = 12; + +namespace chacha +{ + constexpr std::size_t blocksize = 64; + constexpr int rounds = 20; + + struct Chacha20State; + struct Chacha20Block + { + Chacha20Block () {}; + Chacha20Block (Chacha20Block &&) = delete; + + uint8_t data[blocksize]; - /** encrypt buf in place with chacha20 */ - void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter=1); + void operator << (const Chacha20State & st); + }; + struct Chacha20State + { + Chacha20State (): offset (0) {}; + Chacha20State (Chacha20State &&) = delete; + + Chacha20State & operator += (const Chacha20State & other) + { + for(int i = 0; i < 16; i++) + data[i] += other.data[i]; + return *this; + } + + void Copy(const Chacha20State & other) + { + memcpy(data, other.data, sizeof(uint32_t) * 16); + } + uint32_t data[16]; + Chacha20Block block; + size_t offset; + }; + + void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter); + void Chacha20SetCounter (Chacha20State& state, uint32_t counter); + void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz); // encrypt buf in place } +} } +#endif #endif diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index cf6f9b56..0403275f 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -88,6 +88,7 @@ namespace config { ("http.pass", value()->default_value(""), "Password for basic auth (default: random, see logs)") ("http.strictheaders", value()->default_value(true), "Enable strict host checking on WebUI") ("http.hostname", value()->default_value("localhost"), "Expected hostname for WebUI") + ("http.webroot", value()->default_value("/"), "WebUI root path (default: / )") ; options_description httpproxy("HTTP Proxy options"); @@ -236,10 +237,27 @@ namespace config { options_description ntcp2("NTCP2 Options"); ntcp2.add_options() ("ntcp2.enabled", value()->default_value(true), "Enable NTCP2 (default: enabled)") - ("ntcp2.published", value()->default_value(false), "Publish NTCP2 (default: disabled)") + ("ntcp2.published", value()->default_value(false), "Publish NTCP2 (default: disabled)") ("ntcp2.port", value()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)") ; + options_description nettime("Time sync options"); + nettime.add_options() + ("nettime.enabled", value()->default_value(false), "Disable time sync (default: disabled)") + ("nettime.ntpservers", value()->default_value( + "0.pool.ntp.org," + "1.pool.ntp.org," + "2.pool.ntp.org," + "3.pool.ntp.org" + ), "Comma separated list of NTCP servers") + ("nettime.ntpsyncinterval", value()->default_value(72), "NTP sync interval in hours (default: 72)") + ; + + options_description persist("Network information persisting options"); + persist.add_options() + ("persist.profiles", value()->default_value(true), "Persist peer profiles (default: true)") + ; + m_OptionsDesc .add(general) .add(limits) @@ -258,6 +276,8 @@ namespace config { .add(websocket) .add(exploratory) .add(ntcp2) + .add(nettime) + .add(persist) ; } diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index ffd3c4ef..28df1399 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1087,62 +1087,62 @@ namespace crypto if (encrypt && len < msgLen + 16) return false; bool ret = true; #if LEGACY_OPENSSL + chacha::Chacha20State state; // generate one time poly key - uint8_t polyKey[64]; + chacha::Chacha20Init (state, nonce, key, 0); + uint64_t polyKey[8]; memset(polyKey, 0, sizeof(polyKey)); - chacha20 (polyKey, 64, nonce, key, 0); - - // create Poly1305 message + chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64); + // create Poly1305 hash + Poly1305 polyHash (polyKey); if (!ad) adLen = 0; - std::vector polyMsg(adLen + msgLen + 3*16); - size_t offset = 0; uint8_t padding[16]; memset (padding, 0, 16); if (ad) { - memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data + polyHash.Update (ad, adLen);// additional authenticated data auto rem = adLen & 0x0F; // %16 if (rem) { // padding1 rem = 16 - rem; - memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + polyHash.Update (padding, rem); } } // encrypt/decrypt data and add to hash + Chacha20SetCounter (state, 1); if (buf != msg) memcpy (buf, msg, msgLen); if (encrypt) { - chacha20 (buf, msgLen, nonce, key, 1); // encrypt - memcpy (polyMsg.data () + offset, buf, msgLen); // after encryption + chacha::Chacha20Encrypt (state, buf, msgLen); // encrypt + polyHash.Update (buf, msgLen); // after encryption } else { - memcpy (polyMsg.data () + offset, buf, msgLen); // before decryption - chacha20 (buf, msgLen, nonce, key, 1); // decrypt + polyHash.Update (buf, msgLen); // before decryption + chacha::Chacha20Encrypt (state, buf, msgLen); // decrypt } - offset += msgLen; // encrypted data auto rem = msgLen & 0x0F; // %16 if (rem) { // padding2 rem = 16 - rem; - memcpy (polyMsg.data () + offset, padding, rem); offset += rem; + polyHash.Update (padding, rem); } - htole64buf (polyMsg.data () + offset, adLen); offset += 8; - htole64buf (polyMsg.data () + offset, msgLen); offset += 8; - + // adLen and msgLen + htole64buf (padding, adLen); + htole64buf (padding + 8, msgLen); + polyHash.Update (padding, 16); + if (encrypt) - { // calculate Poly1305 tag and write in after encrypted data - Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); - } + polyHash.Finish ((uint64_t *)(buf + msgLen)); else { - uint32_t tag[8]; + uint64_t tag[4]; // calculate Poly1305 tag - Poly1305HMAC (tag, (uint32_t *)polyKey, polyMsg.data (), offset); + polyHash.Finish (tag); if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided } #else @@ -1174,6 +1174,56 @@ namespace crypto return ret; } + void AEADChaCha20Poly1305Encrypt (std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac) + { + if (bufs.empty ()) return; +#if LEGACY_OPENSSL + chacha::Chacha20State state; + // generate one time poly key + chacha::Chacha20Init (state, nonce, key, 0); + uint64_t polyKey[8]; + memset(polyKey, 0, sizeof(polyKey)); + chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64); + Poly1305 polyHash (polyKey); + // encrypt buffers + Chacha20SetCounter (state, 1); + size_t size = 0; + for (auto& it: bufs) + { + chacha::Chacha20Encrypt (state, (uint8_t *)it.first, it.second); + polyHash.Update ((uint8_t *)it.first, it.second); // after encryption + size += it.second; + } + // padding + uint8_t padding[16]; + memset (padding, 0, 16); + auto rem = size & 0x0F; // %16 + if (rem) + { + // padding2 + rem = 16 - rem; + polyHash.Update (padding, rem); + } + // adLen and msgLen + // adLen is always zero + htole64buf (padding + 8, size); + polyHash.Update (padding, 16); + // MAC + polyHash.Finish ((uint64_t *)mac); +#else + int outlen = 0; + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); + EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); + EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce); + for (auto& it: bufs) + EVP_EncryptUpdate(ctx, (uint8_t *)it.first, &outlen, (uint8_t *)it.first, it.second); + EVP_EncryptFinal_ex(ctx, NULL, &outlen); + EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac); + EVP_CIPHER_CTX_free (ctx); +#endif + } + // init and terminate /* std::vector > m_OpenSSLMutexes; diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 5daf82b0..79d16e50 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -108,35 +109,16 @@ namespace crypto void operator^=(const ChipherBlock& other) // XOR { -#ifdef __AVX__ - if (i2p::cpu::avx) - { - __asm__ - ( - "vmovups (%[buf]), %%xmm0 \n" - "vmovups (%[other]), %%xmm1 \n" - "vxorps %%xmm0, %%xmm1, %%xmm0 \n" - "vmovups %%xmm0, (%[buf]) \n" - : - : [buf]"r"(buf), [other]"r"(other.buf) - : "%xmm0", "%xmm1", "memory" - ); - } + if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ? + { + for (int i = 0; i < 4; i++) + reinterpret_cast(buf)[i] ^= reinterpret_cast(other.buf)[i]; + } else -#endif - { - if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ? - { - // we are good to cast to uint32_t * - for (int i = 0; i < 4; i++) - ((uint32_t *)buf)[i] ^= ((uint32_t *)other.buf)[i]; - } - else - { - for (int i = 0; i < 16; i++) - buf[i] ^= other.buf[i]; - } - } + { + for (int i = 0; i < 16; i++) + buf[i] ^= other.buf[i]; + } } }; @@ -301,6 +283,8 @@ namespace crypto // AEAD/ChaCha20/Poly1305 bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag + void AEADChaCha20Poly1305Encrypt (std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad + // init and terminate void InitCrypto (bool precomputation); void TerminateCrypto (); diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 17264926..2c64c475 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -411,6 +411,7 @@ namespace crypto } } +#if !OPENSSL_X25519 BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const { BN_CTX_start (ctx); @@ -488,6 +489,7 @@ namespace crypto EncodeBN (q1, buf, 32); BN_free (p1); BN_free (n); BN_free (q1); } +#endif void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey) { diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index fc23a457..48b3a665 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.h @@ -3,6 +3,7 @@ #include #include +#include "Crypto.h" namespace i2p { @@ -75,8 +76,10 @@ namespace crypto EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; +#if !OPENSSL_X25519 void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519 void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; +#endif bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; @@ -100,8 +103,10 @@ namespace crypto BIGNUM * DecodeBN (const uint8_t * buf) const; void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const; +#if !OPENSSL_X25519 // for x25519 BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const; +#endif private: diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 15e3a32c..5160acec 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -75,6 +75,7 @@ namespace i2p enum I2NPMessageType { + eI2NPDummyMsg = 0, eI2NPDatabaseStore = 1, eI2NPDatabaseLookup = 2, eI2NPDatabaseSearchReply = 3, diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 8caafd2f..513aad08 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -695,8 +695,7 @@ namespace transport SendTerminationAndTerminate (eNTCP2IncorrectSParameter); return; } - - i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // TODO: should insert ri and not parse it twice + i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, buf.data () + 3, size)); // TODO: should insert ri and not parse it twice // TODO: process options // ready to communicate @@ -861,7 +860,7 @@ namespace transport case eNTCP2BlkRouterInfo: { LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]); - i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1); + i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, frame + offset, size)); break; } case eNTCP2BlkI2NPMessage: @@ -873,6 +872,7 @@ namespace transport break; } auto nextMsg = NewI2NPMessage (size); + nextMsg->Align (12); // for possible tunnel msg nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header memcpy (nextMsg->GetNTCP2Header (), frame + offset, size); nextMsg->FromNTCP2 (); diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index ec8ae527..eb46b2f8 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -73,6 +73,8 @@ namespace transport eNTCP2Banned, // 17 }; + // RouterInfo flags + const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01; typedef std::array NTCP2FrameBuffer; struct NTCP2Establisher diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 0add6f91..2e5c3a23 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -12,6 +12,7 @@ #include "I2NPProtocol.h" #include "Tunnel.h" #include "Transports.h" +#include "NTCP2.h" #include "RouterContext.h" #include "Garlic.h" #include "NetDb.hpp" @@ -25,7 +26,7 @@ namespace data { NetDb netdb; - NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_FloodfillBootstrap(nullptr), m_HiddenMode(false) + NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), m_HiddenMode(false) { } @@ -43,10 +44,12 @@ namespace data m_Families.LoadCertificates (); Load (); - uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold); + uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold); if (m_RouterInfos.size () < threshold) // reseed if # of router less than threshold Reseed (); + i2p::config::GetOption("persist.profiles", m_PersistProfiles); + m_IsRunning = true; m_Thread = new std::thread (std::bind (&NetDb::Run, this)); } @@ -55,8 +58,9 @@ namespace data { if (m_IsRunning) { - for (auto& it: m_RouterInfos) - it.second->SaveProfile (); + if (m_PersistProfiles) + for (auto& it: m_RouterInfos) + it.second->SaveProfile (); DeleteObsoleteProfiles (); m_RouterInfos.clear (); m_Floodfills.clear (); @@ -98,6 +102,10 @@ namespace data case eI2NPDatabaseLookup: HandleDatabaseLookupMsg (msg); break; + case eI2NPDummyMsg: + // plain RouterInfo from NTCP2 with flags for now + HandleNTCP2RouterInfoMsg (msg); + break; default: // WTF? LogPrint (eLogError, "NetDb: unexpected message type ", (int) msg->GetTypeID ()); //i2p::HandleI2NPMessage (msg); @@ -162,22 +170,38 @@ namespace data } } + void NetDb::SetHidden(bool hide) + { + // TODO: remove reachable addresses from router info + m_HiddenMode = hide; + } + bool NetDb::AddRouterInfo (const uint8_t * buf, int len) + { + bool updated; + AddRouterInfo (buf, len, updated); + return updated; + } + + std::shared_ptr NetDb::AddRouterInfo (const uint8_t * buf, int len, bool& updated) { IdentityEx identity; if (identity.FromBuffer (buf, len)) - return AddRouterInfo (identity.GetIdentHash (), buf, len); - return false; + return AddRouterInfo (identity.GetIdentHash (), buf, len, updated); + updated = false; + return nullptr; } - void NetDb::SetHidden(bool hide) { - // TODO: remove reachable addresses from router info - m_HiddenMode = hide; - } - bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len) { - bool updated = true; + bool updated; + AddRouterInfo (ident, buf, len, updated); + return updated; + } + + std::shared_ptr NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len, bool& updated) + { + updated = true; auto r = FindRouter (ident); if (r) { @@ -223,7 +247,7 @@ namespace data } // take care about requested destination m_Requests.RequestComplete (ident, r); - return updated; + return r; } bool NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, @@ -518,7 +542,7 @@ namespace data { if (it->second->IsUnreachable ()) { - it->second->SaveProfile (); + if (m_PersistProfiles) it->second->SaveProfile (); it = m_RouterInfos.erase (it); continue; } @@ -570,6 +594,17 @@ namespace data transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr)); } + void NetDb::HandleNTCP2RouterInfoMsg (std::shared_ptr m) + { + uint8_t flood = m->GetPayload ()[0] & NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD; + bool updated; + auto ri = AddRouterInfo (m->GetPayload () + 1, m->GetPayloadLength () - 1, updated); // without flags + if (flood && updated && context.IsFloodfill () && ri) + { + auto floodMsg = CreateDatabaseStoreMsg (ri, 0); // replyToken = 0 + Flood (ri->GetIdentHash (), floodMsg); + } + } void NetDb::HandleDatabaseStoreMsg (std::shared_ptr m) { @@ -649,22 +684,7 @@ namespace data { memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + payloadOffset, msgLen); floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore); - std::set excluded; - excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself - excluded.insert (ident); // don't flood back - for (int i = 0; i < 3; i++) - { - auto floodfill = GetClosestFloodfill (ident, excluded); - if (floodfill) - { - auto h = floodfill->GetIdentHash(); - LogPrint(eLogDebug, "NetDb: Flood lease set for ", ident.ToBase32(), " to ", h.ToBase64()); - transports.SendMessage (h, CopyI2NPMessage(floodMsg)); - excluded.insert (h); - } - else - break; - } + Flood (ident, floodMsg); } else LogPrint (eLogError, "NetDb: Database store message is too long ", floodMsg->len); @@ -965,6 +985,26 @@ namespace data } } + void NetDb::Flood (const IdentHash& ident, std::shared_ptr floodMsg) + { + std::set excluded; + excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself + excluded.insert (ident); // don't flood back + for (int i = 0; i < 3; i++) + { + auto floodfill = GetClosestFloodfill (ident, excluded); + if (floodfill) + { + auto h = floodfill->GetIdentHash(); + LogPrint(eLogDebug, "NetDb: Flood lease set for ", ident.ToBase32(), " to ", h.ToBase64()); + transports.SendMessage (h, CopyI2NPMessage(floodMsg)); + excluded.insert (h); + } + else + break; + } + } + std::shared_ptr NetDb::GetRandomRouter () const { return GetRandomRouter ( diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index 18377b4f..b34458fb 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -65,7 +65,8 @@ namespace data void HandleDatabaseStoreMsg (std::shared_ptr msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr msg); void HandleDatabaseLookupMsg (std::shared_ptr msg); - + void HandleNTCP2RouterInfoMsg (std::shared_ptr m); + std::shared_ptr GetRandomRouter () const; std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith) const; std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith) const; @@ -110,13 +111,16 @@ namespace data void Run (); // exploratory thread void Explore (int numDestinations); void Publish (); + void Flood (const IdentHash& ident, std::shared_ptr floodMsg); void ManageLeaseSets (); void ManageRequests (); - void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); + void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); - template - std::shared_ptr GetRandomRouter (Filter filter) const; + std::shared_ptr AddRouterInfo (const uint8_t * buf, int len, bool& updated); + std::shared_ptr AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len, bool& updated); + template + std::shared_ptr GetRandomRouter (Filter filter) const; private: @@ -140,6 +144,8 @@ namespace data friend class NetDbRequests; NetDbRequests m_Requests; + bool m_PersistProfiles; + /** router info we are bootstrapping from or nullptr if we are not currently doing that*/ std::shared_ptr m_FloodfillBootstrap; diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp index 9ee46640..4ce67d39 100644 --- a/libi2pd/Poly1305.cpp +++ b/libi2pd/Poly1305.cpp @@ -6,246 +6,20 @@ Kovri go write your own code */ + +#if LEGACY_OPENSSL namespace i2p { namespace crypto { - namespace poly1305 - { - - struct LongBlock - { - unsigned long data[17]; - operator unsigned long * () - { - return data; - } - }; - - struct Block - { - unsigned char data[17]; - - operator uint8_t * () - { - return data; - } - - Block & operator += (const Block & other) - { - unsigned short u; - unsigned int i; - for(u = 0, i = 0; i < 17; i++) - { - u += (unsigned short) data[i] + (unsigned short) other.data[i]; - data[i] = (unsigned char) u & 0xff; - u >>= 8; - } - return *this; - } - - Block & operator %=(const LongBlock & other) - { - unsigned long u; - unsigned int i; - u = 0; - for (i = 0; i < 16; i++) { - u += other.data[i]; - data[i] = (unsigned char)u & 0xff; - u >>= 8; - } - u += other.data[16]; - data[16] = (unsigned char)u & 0x03; - u >>= 2; - u += (u << 2); - for (i = 0; i < 16; i++) { - u += data[i]; - data[i] = (unsigned char)u & 0xff; - u >>= 8; - } - data[16] += (unsigned char)u; - return *this; - } - Block & operator = (const Block & other) - { - memcpy(data, other.data, sizeof(data)); - return *this; - } - - Block & operator ~ () - { - static const Block minusp = { - 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0xfc - }; - Block orig; - unsigned char neg; - unsigned int i; - orig = *this; - *this += minusp; - neg = -(data[16] >> 7); - for(i = 0; i < 17; i++) - data[i] ^= neg & (orig.data[i] ^ data[i]); - - return *this; - } - - void PutKey(const uint8_t * key) - { - data[0] = key[0] & 0xff; - data[1] = key[1] & 0xff; - data[2] = key[2] & 0xff; - data[3] = key[3] & 0x0f; - data[4] = key[4] & 0xfc; - data[5] = key[5] & 0xff; - data[6] = key[6] & 0xff; - data[7] = key[7] & 0x0f; - data[8] = key[8] & 0xfc; - data[9] = key[9] & 0xff; - data[10] = key[10] & 0xff; - data[11] = key[11] & 0x0f; - data[12] = key[12] & 0xfc; - data[13] = key[13] & 0xff; - data[14] = key[14] & 0xff; - data[15] = key[15] & 0x0f; - data[16] = 0; - } - - void Put(const uint8_t * d, uint8_t last=0) - { - memcpy(data, d, 17); - data[16] = last; - } - }; - - struct Buffer - { - uint8_t data[POLY1305_BLOCK_BYTES]; - - operator uint8_t * () - { - return data; - } - }; - } - - struct Poly1305 + void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz) { -#if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) // older than gcc 4.8 - Poly1305(const uint8_t * key) : m_Leftover(0), m_Final(0) - { - memset (&m_H, 0, sizeof (m_H)); -#else - Poly1305(const uint8_t * key) : m_Leftover(0), m_H{0}, m_Final(0) - { -#endif - m_R.PutKey(key); - m_Pad.Put(key + 16); - } - - void Update(const uint8_t * buf, size_t sz) - { - // process leftover - if(m_Leftover) - { - size_t want = POLY1305_BLOCK_BYTES - m_Leftover; - if(want > sz) want = sz; - memcpy(m_Buffer + m_Leftover, buf, want); - sz -= want; - buf += want; - m_Leftover += want; - if(m_Leftover < POLY1305_BLOCK_BYTES) return; - Blocks(m_Buffer, POLY1305_BLOCK_BYTES); - m_Leftover = 0; - } - // process blocks - if(sz >= POLY1305_BLOCK_BYTES) - { - size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1)); - Blocks(buf, want); - buf += want; - sz -= want; - } - // leftover - if(sz) - { - memcpy(m_Buffer+m_Leftover, buf, sz); - m_Leftover += sz; - } - } - - void Blocks(const uint8_t * buf, size_t sz) - { - const unsigned char hi = m_Final ^ 1; - while (sz >= POLY1305_BLOCK_BYTES) { - - unsigned long u; - - unsigned int i, j; - m_Msg.Put(buf, hi); - /* h += m */ - m_H += m_Msg; - - /* h *= r */ - for (i = 0; i < 17; i++) { - u = 0; - for (j = 0; j <= i ; j++) { - u += (unsigned short)m_H.data[j] * m_R.data[i - j]; - } - for (j = i + 1; j < 17; j++) { - unsigned long v = (unsigned short)m_H.data[j] * m_R.data[i + 17 - j]; - v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */ - u += v; - } - m_HR[i] = u; - } - /* (partial) h %= p */ - m_H %= m_HR; - buf += POLY1305_BLOCK_BYTES; - sz -= POLY1305_BLOCK_BYTES; - } - } - - void Finish(uint32_t *& out) - { - // process leftovers - if(m_Leftover) - { - size_t idx = m_Leftover; - m_Buffer[idx++] = 1; - for(; idx < POLY1305_BLOCK_BYTES; idx++) - m_Buffer[idx] = 0; - m_Final = 1; - Blocks(m_Buffer, POLY1305_BLOCK_BYTES); - } - - // freeze H - ~m_H; - // add pad - m_H += m_Pad; - // copy digest - memcpy(out, m_H, 16); - } - - size_t m_Leftover; - poly1305::Buffer m_Buffer; - poly1305::Block m_H; - poly1305::Block m_R; - poly1305::Block m_Pad; - poly1305::Block m_Msg; - poly1305::LongBlock m_HR; - uint8_t m_Final; - - }; - - void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz) - { - const uint8_t * k = (const uint8_t *) key; - Poly1305 p(k); + Poly1305 p(key); p.Update(buf, sz); p.Finish(out); - } + } } } +#endif + diff --git a/libi2pd/Poly1305.h b/libi2pd/Poly1305.h index 2c62c5aa..d9529c81 100644 --- a/libi2pd/Poly1305.h +++ b/libi2pd/Poly1305.h @@ -9,20 +9,253 @@ #define LIBI2PD_POLY1305_H #include #include +#include "Crypto.h" +#if LEGACY_OPENSSL namespace i2p { namespace crypto { - const std::size_t POLY1305_DIGEST_BYTES = 16; - const std::size_t POLY1305_DIGEST_DWORDS = 4; - const std::size_t POLY1305_KEY_BYTES = 32; - const std::size_t POLY1305_KEY_DWORDS = 8; - const std::size_t POLY1305_BLOCK_BYTES = 16; - - void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz); - + const std::size_t POLY1305_DIGEST_BYTES = 16; + const std::size_t POLY1305_DIGEST_DWORDS = 4; + const std::size_t POLY1305_KEY_BYTES = 32; + const std::size_t POLY1305_KEY_DWORDS = 8; + const std::size_t POLY1305_BLOCK_BYTES = 16; + + namespace poly1305 + { + + struct LongBlock + { + unsigned long data[17]; + operator unsigned long * () + { + return data; + } + }; + + struct Block + { + unsigned char data[17]; + + void Zero() + { + memset(data, 0, sizeof(data)); + } + + operator uint8_t * () + { + return data; + } + + Block & operator += (const Block & other) + { + unsigned short u; + unsigned int i; + for(u = 0, i = 0; i < 17; i++) + { + u += (unsigned short) data[i] + (unsigned short) other.data[i]; + data[i] = (unsigned char) u & 0xff; + u >>= 8; + } + return *this; + } + + Block & operator %=(const LongBlock & other) + { + unsigned long u; + unsigned int i; + u = 0; + for (i = 0; i < 16; i++) { + u += other.data[i]; + data[i] = (unsigned char)u & 0xff; + u >>= 8; + } + u += other.data[16]; + data[16] = (unsigned char)u & 0x03; + u >>= 2; + u += (u << 2); + for (i = 0; i < 16; i++) { + u += data[i]; + data[i] = (unsigned char)u & 0xff; + u >>= 8; + } + data[16] += (unsigned char)u; + return *this; + } + + Block & operator = (const Block & other) + { + memcpy(data, other.data, sizeof(data)); + return *this; + } + + Block & operator ~ () + { + static const Block minusp = { + 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xfc + }; + Block orig; + unsigned char neg; + unsigned int i; + orig = *this; + *this += minusp; + neg = -(data[16] >> 7); + for(i = 0; i < 17; i++) + data[i] ^= neg & (orig.data[i] ^ data[i]); + + return *this; + } + + void PutKey(const uint64_t * key_l) + { + const uint8_t * key = (const uint8_t*) key_l; + data[0] = key[0] & 0xff; + data[1] = key[1] & 0xff; + data[2] = key[2] & 0xff; + data[3] = key[3] & 0x0f; + data[4] = key[4] & 0xfc; + data[5] = key[5] & 0xff; + data[6] = key[6] & 0xff; + data[7] = key[7] & 0x0f; + data[8] = key[8] & 0xfc; + data[9] = key[9] & 0xff; + data[10] = key[10] & 0xff; + data[11] = key[11] & 0x0f; + data[12] = key[12] & 0xfc; + data[13] = key[13] & 0xff; + data[14] = key[14] & 0xff; + data[15] = key[15] & 0x0f; + data[16] = 0; + } + + template + void Put(const Int_t * d, uint8_t last=0) + { + memcpy(data, d, 16); + data[16] = last; + } + }; + + struct Buffer + { + uint8_t data[POLY1305_BLOCK_BYTES]; + + operator uint8_t * () + { + return data; + } + }; + } + + struct Poly1305 + { + Poly1305(const uint64_t * key) + { + m_Leftover = 0; + m_H.Zero(); + m_Final = 0; + m_R.PutKey(key); + m_Pad.Put(key + 2); + } + + void Update(const uint8_t * buf, size_t sz) + { + // process leftover + if(m_Leftover) + { + size_t want = POLY1305_BLOCK_BYTES - m_Leftover; + if(want > sz) want = sz; + memcpy(m_Buffer + m_Leftover, buf, want); + sz -= want; + buf += want; + m_Leftover += want; + if(m_Leftover < POLY1305_BLOCK_BYTES) return; + Blocks(m_Buffer, POLY1305_BLOCK_BYTES); + m_Leftover = 0; + } + // process blocks + if(sz >= POLY1305_BLOCK_BYTES) + { + size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1)); + Blocks(buf, want); + buf += want; + sz -= want; + } + // leftover + if(sz) + { + memcpy(m_Buffer+m_Leftover, buf, sz); + m_Leftover += sz; + } + } + + void Blocks(const uint8_t * buf, size_t sz) + { + const unsigned char hi = m_Final ^ 1; + while (sz >= POLY1305_BLOCK_BYTES) { + unsigned long u; + unsigned int i, j; + m_Msg.Put(buf, hi); + /* h += m */ + m_H += m_Msg; + + /* h *= r */ + for (i = 0; i < 17; i++) { + u = 0; + for (j = 0; j <= i ; j++) { + u += (unsigned short)m_H.data[j] * m_R.data[i - j]; + } + for (j = i + 1; j < 17; j++) { + unsigned long v = (unsigned short)m_H.data[j] * m_R.data[i + 17 - j]; + v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */ + u += v; + } + m_HR[i] = u; + } + /* (partial) h %= p */ + m_H %= m_HR; + buf += POLY1305_BLOCK_BYTES; + sz -= POLY1305_BLOCK_BYTES; + } + } + + void Finish(uint64_t * out) + { + // process leftovers + if(m_Leftover) + { + size_t idx = m_Leftover; + m_Buffer[idx++] = 1; + for(; idx < POLY1305_BLOCK_BYTES; idx++) + m_Buffer[idx] = 0; + m_Final = 1; + Blocks(m_Buffer, POLY1305_BLOCK_BYTES); + } + + // freeze H + ~m_H; + // add pad + m_H += m_Pad; + // copy digest + memcpy(out, m_H, 16); + } + + size_t m_Leftover; + poly1305::Buffer m_Buffer; + poly1305::Block m_H; + poly1305::Block m_R; + poly1305::Block m_Pad; + poly1305::Block m_Msg; + poly1305::LongBlock m_HR; + uint8_t m_Final; + }; + void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz); + } } +#endif #endif diff --git a/libi2pd/Siphash.h b/libi2pd/Siphash.h index aa8b8631..70822466 100644 --- a/libi2pd/Siphash.h +++ b/libi2pd/Siphash.h @@ -9,7 +9,9 @@ #define SIPHASH_H #include +#include "Crypto.h" +#if !OPENSSL_SIPHASH namespace i2p { namespace crypto @@ -148,5 +150,6 @@ namespace crypto } } } +#endif #endif diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp index 9e9b4e63..492e4559 100644 --- a/libi2pd/Timestamp.cpp +++ b/libi2pd/Timestamp.cpp @@ -1,6 +1,10 @@ #include #include +#include +#include #include +#include +#include "Config.h" #include "Log.h" #include "I2PEndian.h" #include "Timestamp.h" @@ -15,10 +19,30 @@ namespace i2p { namespace util { + static uint64_t GetLocalMillisecondsSinceEpoch () + { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count (); + } + + static uint32_t GetLocalHoursSinceEpoch () + { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count (); + } + + static uint64_t GetLocalSecondsSinceEpoch () + { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count (); + } + + static int64_t g_TimeOffset = 0; // in seconds - void SyncTimeWithNTP (const std::string& address) + static void SyncTimeWithNTP (const std::string& address) { + LogPrint (eLogInfo, "Timestamp: NTP request to ", address); boost::asio::io_service service; boost::asio::ip::udp::resolver::query query (boost::asio::ip::udp::v4 (), address, "ntp"); boost::system::error_code ec; @@ -48,19 +72,112 @@ namespace util } catch (std::exception& e) { - LogPrint (eLogError, "NTP error: ", e.what ()); + LogPrint (eLogError, "Timestamp: NTP error: ", e.what ()); } if (len >= 8) { - auto ourTs = GetSecondsSinceEpoch (); + auto ourTs = GetLocalSecondsSinceEpoch (); uint32_t ts = bufbe32toh (buf + 32); if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900 g_TimeOffset = ts - ourTs; - LogPrint (eLogInfo, address, " time offset from system time is ", g_TimeOffset, " seconds"); + LogPrint (eLogInfo, "Timestamp: ", address, " time offset from system time is ", g_TimeOffset, " seconds"); } } + else + LogPrint (eLogError, "Timestamp: Couldn't open UDP socket"); + } + else + LogPrint (eLogError, "Timestamp: Couldn't resove address ", address); + } + + NTPTimeSync::NTPTimeSync (): m_IsRunning (false), m_Timer (m_Service) + { + i2p::config::GetOption("nettime.ntpsyncinterval", m_SyncInterval); + std::string ntpservers; i2p::config::GetOption("nettime.ntpservers", ntpservers); + boost::split (m_NTPServersList, ntpservers, boost::is_any_of(","), boost::token_compress_on); + } + + NTPTimeSync::~NTPTimeSync () + { + Stop (); + } + + void NTPTimeSync::Start() + { + if (m_NTPServersList.size () > 0) + { + m_IsRunning = true; + LogPrint(eLogInfo, "Timestamp: NTP time sync starting"); + m_Service.post (std::bind (&NTPTimeSync::Sync, this)); + m_Thread.reset (new std::thread (std::bind (&NTPTimeSync::Run, this))); + } + else + LogPrint (eLogWarning, "Timestamp: No NTP server found"); + } + + void NTPTimeSync::Stop () + { + if (m_IsRunning) + { + LogPrint(eLogInfo, "Timestamp: NTP time sync stopping"); + m_IsRunning = false; + m_Timer.cancel (); + m_Service.stop (); + if (m_Thread) + { + m_Thread->join (); + m_Thread.reset (nullptr); + } + } + } + + void NTPTimeSync::Run () + { + while (m_IsRunning) + { + try + { + m_Service.run (); + } + catch (std::exception& ex) + { + LogPrint (eLogError, "Timestamp: NTP time sync exception: ", ex.what ()); + } + } + } + + void NTPTimeSync::Sync () + { + if (m_NTPServersList.size () > 0) + SyncTimeWithNTP (m_NTPServersList[rand () % m_NTPServersList.size ()]); + else + m_IsRunning = false; + + if (m_IsRunning) + { + m_Timer.expires_from_now (boost::posix_time::hours (m_SyncInterval)); + m_Timer.async_wait ([this](const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + Sync (); + }); } } + + uint64_t GetMillisecondsSinceEpoch () + { + return GetLocalMillisecondsSinceEpoch () + g_TimeOffset*1000; + } + + uint32_t GetHoursSinceEpoch () + { + return GetLocalHoursSinceEpoch () + g_TimeOffset/3600; + } + + uint64_t GetSecondsSinceEpoch () + { + return GetLocalSecondsSinceEpoch () + g_TimeOffset; + } } } diff --git a/libi2pd/Timestamp.h b/libi2pd/Timestamp.h index cddc6518..e859f7f6 100644 --- a/libi2pd/Timestamp.h +++ b/libi2pd/Timestamp.h @@ -2,29 +2,43 @@ #define TIMESTAMP_H__ #include -#include +#include +#include +#include +#include namespace i2p { namespace util { - inline uint64_t GetMillisecondsSinceEpoch () - { - return std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()).count (); - } + uint64_t GetMillisecondsSinceEpoch (); + uint32_t GetHoursSinceEpoch (); + uint64_t GetSecondsSinceEpoch (); - inline uint32_t GetHoursSinceEpoch () + class NTPTimeSync { - return std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()).count (); - } + public: - inline uint64_t GetSecondsSinceEpoch () - { - return std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()).count (); - } + NTPTimeSync (); + ~NTPTimeSync (); + + void Start (); + void Stop (); + + private: + + void Run (); + void Sync (); + + private: + + bool m_IsRunning; + std::unique_ptr m_Thread; + boost::asio::io_service m_Service; + boost::asio::deadline_timer m_Timer; + int m_SyncInterval; + std::vector m_NTPServersList; + }; } } diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 6a833ae0..64f41afd 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -35,8 +35,11 @@ namespace transport void DHKeysPairSupplier::Stop () { - m_IsRunning = false; - m_Acquired.notify_one (); + { + std::unique_lock l(m_AcquiredMutex); + m_IsRunning = false; + m_Acquired.notify_one (); + } if (m_Thread) { m_Thread->join (); @@ -50,19 +53,20 @@ namespace transport while (m_IsRunning) { int num, total = 0; - while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 20) + while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 10) { CreateDHKeysPairs (num); total += num; } - if (total >= 20) + if (total >= 10) { LogPrint (eLogWarning, "Transports: ", total, " DH keys generated at the time"); std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break } else { - std::unique_lock l(m_AcquiredMutex); + std::unique_lock l(m_AcquiredMutex); + if (!m_IsRunning) break; m_Acquired.wait (l); // wait for element gets acquired } } @@ -813,7 +817,6 @@ namespace transport if (profile) { profile->TunnelNonReplied(); - profile->Save(it->first); } std::unique_lock l(m_PeersMutex); it = m_Peers.erase (it); diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 1395c2e6..b558fca4 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -21,9 +21,9 @@ #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) +/* // No more needed. Exists in MinGW. int inet_pton(int af, const char *src, void *dst) -{ /* This function was written by Petar Korponai?. See -http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found */ +{ // This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found struct sockaddr_storage ss; int size = sizeof (ss); char src_copy[INET6_ADDRSTRLEN + 1]; @@ -45,7 +45,7 @@ http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found */ } } return 0; -} +}*/ #else /* !WIN32 => UNIX */ #include #include diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp index f0530ac1..e54ccda5 100644 --- a/libi2pd_client/HTTPProxy.cpp +++ b/libi2pd_client/HTTPProxy.cpp @@ -390,6 +390,10 @@ namespace proxy { std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for? m_ClientRequest.uri = m_ClientRequestURL.to_string(); + // update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections + if(m_ClientRequest.method != "CONNECT") + m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0"); + m_ClientRequest.write(m_ClientRequestBuffer); m_ClientRequestBuffer << m_recv_buf.substr(m_req_len); diff --git a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml index 16ae602a..f6b98ed7 100644 --- a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml +++ b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml @@ -35,6 +35,7 @@ + diff --git a/tests/test-aeadchacha20poly1305.cpp b/tests/test-aeadchacha20poly1305.cpp index dcd4b4d6..d10ab2fc 100644 --- a/tests/test-aeadchacha20poly1305.cpp +++ b/tests/test-aeadchacha20poly1305.cpp @@ -51,4 +51,10 @@ int main () uint8_t buf1[114]; assert (i2p::crypto::AEADChaCha20Poly1305 (buf, 114, ad, 12, key, nonce, buf1, 114, false)); assert (memcmp (buf1, text, 114) == 0); + // test encryption of multiple buffers + memcpy (buf, text, 114); + std::vector > bufs{ std::make_pair (buf, 50), std::make_pair (buf + 50, 50), std::make_pair (buf + 100, 14) }; + i2p::crypto::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114); + i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false); + assert (memcmp (buf1, text, 114) == 0); }