Tunnels: Improved logging and handling of offline signature expiration

Store back ref to controller in tunnel
Stop server controller on I2PException
Support generation of keys with fractional days expiration for testing
This commit is contained in:
zzz
2020-10-29 15:20:56 +00:00
parent 8d0b1214d2
commit 190b76d7fd
10 changed files with 93 additions and 23 deletions

View File

@@ -95,6 +95,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
private final long _tunnelId;
private final Properties _clientOptions;
private final Set<I2PSession> _sessions;
private final TunnelController _controller;
public static final int PACKET_DELAY = 100;
@@ -152,6 +153,16 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
this(nocli_args);
}
/**
* New standard constructor in router, with back ref to tc
* @param tc may be null
* @throws IllegalArgumentException
* @since 0.9.48
*/
public I2PTunnel(TunnelController tc) {
this(nocli_args, null, tc);
}
/**
* See usage() for options
* @throws IllegalArgumentException
@@ -166,10 +177,21 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
* @throws IllegalArgumentException
*/
public I2PTunnel(String[] args, ConnectionEventListener lsnr) {
this(args, lsnr, null);
}
/**
* @param lsnr may be null
* @param tc may be null
* @throws IllegalArgumentException
* @since 0.9.48
*/
private I2PTunnel(String[] args, ConnectionEventListener lsnr, TunnelController tc) {
super();
_context = I2PAppContext.getGlobalContext(); // new I2PAppContext();
_tunnelId = __tunnelId.incrementAndGet();
_log = _context.logManager().getLog(I2PTunnel.class);
_controller = tc;
// as of 0.8.4, include context properties
Properties p = _context.getProperties();
_clientOptions = p;
@@ -366,6 +388,13 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
*/
public Properties getClientOptions() { return _clientOptions; }
/**
* TunnelController that constructed this, or null.
* @return controller or null
* @since 0.9.48
*/
TunnelController getController() { return _controller; }
private void addtask(I2PTunnelTask tsk) {
tsk.setTunnel(this);
if (tsk.isOpen()) {

View File

@@ -307,12 +307,15 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
if (session.isOffline()) {
long exp = session.getOfflineExpiration();
long remaining = exp - getTunnel().getContext().clock().now();
if (remaining <= 0)
throw new IllegalArgumentException("Offline signature expired " + DataHelper.formatTime(exp));
if (remaining <= 0) {
String msg = "Offline signature for tunnel expired " + DataHelper.formatTime(exp);
_log.log(Log.CRIT, msg);
throw new IllegalArgumentException(msg);
}
if (remaining < 60*24*60*60*1000L) {
String msg = "Offline signature expires in " + DataHelper.formatDuration(remaining);
String msg = "Offline signature for tunnel expires in " + DataHelper.formatDuration(remaining);
_log.logAlways(Log.WARN, msg);
l.log(msg);
l.log("WARNING: " + msg);
}
}
while (session.isClosed()) {
@@ -641,9 +644,15 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
// so sockMgr will call ConnectionManager.setAllowIncomingConnections(true) again
i2pss = sockMgr.getServerSocket();
} catch (I2PException ipe) {
if (_log.shouldLog(Log.ERROR))
_log.error("Error accepting - KILLING THE TUNNEL SERVER", ipe);
open = false;
String s = "Error accepting - KILLING THE TUNNEL SERVER";
_log.log(Log.CRIT, s, ipe);
l.log(s + ": " + ipe);
// Tell TunnelController so it will change state
TunnelController tc = getTunnel().getController();
if (tc != null)
tc.stopTunnel();
else
close(true);
if (i2ps != null) try { i2ps.close(); } catch (IOException ioe) {}
break;
} catch (ConnectException ce) {

View File

@@ -213,7 +213,7 @@ public class TunnelController implements Logging {
* overwrite existing ones)
*/
public TunnelController(Properties config, String prefix, boolean createKey) {
_tunnel = new I2PTunnel();
_tunnel = new I2PTunnel(this);
_log = I2PAppContext.getGlobalContext().logManager().getLog(TunnelController.class);
setConfig(config, prefix);
_messages = new ArrayList<String>(4);

View File

@@ -7,6 +7,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PSession;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
@@ -235,6 +236,10 @@ class PacketLocal extends Packet implements MessageOutputStream.WriteStatus {
* @since 0.9.20 moved from Packet
*/
public int writeSignedPacket(byte buffer[], int offset) throws IllegalStateException {
if (isFlagSet(FLAG_SIGNATURE_OFFLINE)) {
if (_transientExpires < _context.clock().now())
throw new IllegalStateException("Offline signature expired " + DataHelper.formatTime(_transientExpires));
}
setFlag(FLAG_SIGNATURE_INCLUDED);
SigningPrivateKey key = _session.getPrivateKey();
int size = writePacket(buffer, offset, key.getType().getSigLen());

View File

@@ -150,8 +150,11 @@ class I2CPMessageProducer {
cfg.setOptions(p);
if (isOffline) {
long exp = session.getOfflineExpiration();
if (exp < _context.clock().now())
throw new I2PSessionException("Offline signature expired " + DataHelper.formatTime(exp));
if (exp < _context.clock().now()) {
String s = "Offline signature for tunnel expired " + DataHelper.formatTime(exp);
_log.log(Log.CRIT, s);
throw new I2PSessionException(s);
}
cfg.setOfflineSignature(exp,
session.getTransientSigningPublicKey(),
session.getOfflineSignature());
@@ -218,7 +221,7 @@ class I2CPMessageProducer {
msg.setDestination(dest);
SessionId sid = session.getSessionId();
if (sid == null) {
_log.error(session.toString() + " send message w/o session", new Exception());
_log.error(session.toString() + " cannot send message, session closed", new Exception());
return;
}
msg.setSessionId(sid);
@@ -245,7 +248,7 @@ class I2CPMessageProducer {
msg.setDestination(dest);
SessionId sid = session.getSessionId();
if (sid == null) {
_log.error(session.toString() + " send message w/o session", new Exception());
_log.error(session.toString() + " cannot send message, session closed", new Exception());
return;
}
msg.setSessionId(sid);
@@ -412,7 +415,7 @@ class I2CPMessageProducer {
msg.setLeaseSet(leaseSet);
SessionId sid = session.getSessionId();
if (sid == null) {
_log.error(session.toString() + " create LS w/o session", new Exception());
_log.error(session.toString() + " cannot create LS, session closed", new Exception());
return;
}
msg.setSessionId(sid);
@@ -444,7 +447,7 @@ class I2CPMessageProducer {
msg.setSessionConfig(cfg);
SessionId sid = session.getSessionId();
if (sid == null) {
_log.error(session.toString() + " update config w/o session", new Exception());
_log.error(session.toString() + " cannot update config, session closed", new Exception());
return;
}
msg.setSessionId(sid);

View File

@@ -326,10 +326,16 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
// offline keys
if (session.isOffline()) {
LeaseSet2 ls2 = (LeaseSet2) leaseSet;
boolean ok = ls2.setOfflineSignature(session.getOfflineExpiration(), session.getTransientSigningPublicKey(),
long exp = session.getOfflineExpiration();
boolean ok = ls2.setOfflineSignature(exp, session.getTransientSigningPublicKey(),
session.getOfflineSignature());
if (!ok) {
session.propogateError("Bad offline signature", new Exception());
String s;
if (exp <= _context.clock().now())
s = "Offline signature for tunnel expired " + DataHelper.formatTime(exp);
else
s = "Bad offline signature";
session.propogateError(s, new Exception());
session.destroySession();
}
}

View File

@@ -107,7 +107,7 @@ public class PrivateKeyFile {
String signername = null;
String signaction = null;
String certfile = null;
int days = 365;
double days = 365;
int mode = 0;
boolean error = false;
Getopt g = new Getopt("pkf", args, "t:nuxhse:c:a:o:d:r:p:b:y:z:w:");
@@ -178,7 +178,7 @@ public class PrivateKeyFile {
break;
case 'd':
days = Integer.parseInt(g.getOptarg());
days = Double.parseDouble(g.getOptarg());
break;
case 'r':
@@ -344,7 +344,7 @@ public class PrivateKeyFile {
SigningPublicKey tSigningPubKey = (SigningPublicKey) signingKeys[0];
SigningPrivateKey tSigningPrivKey = (SigningPrivateKey) signingKeys[1];
// set expires
long expires = System.currentTimeMillis() + (days * 24*60*60*1000L);
long expires = System.currentTimeMillis() + (long) (days * 24*60*60*1000L);
// sign
byte[] data = new byte[4 + 2 + tSigningPubKey.length()];
DataHelper.toLong(data, 0, 4, expires / 1000);
@@ -374,7 +374,7 @@ public class PrivateKeyFile {
java.security.PrivateKey jpriv = SigUtil.toJavaKey(priv);
if (signername == null)
signername = "example.i2p";
X509Certificate cert = SelfSignedGenerator.generate(priv, signername, days);
X509Certificate cert = SelfSignedGenerator.generate(priv, signername, (int) days);
java.security.cert.Certificate[] certs = { cert };
out = new FileOutputStream(certfile);
CertUtil.exportPrivateKey(jpriv, certs, out);

View File

@@ -1,3 +1,21 @@
2020-10-29 zzz
* Tunnels: Improved logging and handling of offline signature expiration
2020-10-28 zzz
* Tunnels: Fix tunnel tests for ECIES routers
2020-10-27 zzz
* Util:
- DNSOverHTTPS improvements
- Fix SSLEepGet handling of previous SSL state
2020-10-26 zzz
* Util: Fix EepGet allowCaching parameter
2020-10-25 zzz
* Router: Quick checks of eph. key MSB before Noise DH
* Tunnels: Additional checks on ECIES BRR to catch old/buggy routers
2020-10-23 zzz
* i2ptunnel: Remove mtn tunnel (new installs only)
* Tunnels:

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 10;
public final static long BUILD = 11;
/** for example "-test" */
public final static String EXTRA = "";

View File

@@ -251,8 +251,8 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
_log.error(msg);
_runner.disconnectClient(msg);
} else if (in.getOfflineSignature() != null && in.getOfflineExpiration() < _context.clock().now()) {
String msg = "Offline signature expired " + DataHelper.formatTime(in.getOfflineExpiration());
_log.error(msg);
String msg = "Offline signature for tunnel expired " + DataHelper.formatTime(in.getOfflineExpiration());
_log.log(Log.CRIT, msg);
_runner.disconnectClient(msg);
} else {
_log.error("Signature verification failed on a create session message:\n" + in);