forked from I2P_Developers/i2p.i2p
i2ptunnel: Add checks for offline expiration in alternate destination
Improve logging for expiration checks
This commit is contained in:
@ -281,7 +281,27 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
|
|||||||
FileInputStream privData = null;
|
FileInputStream privData = null;
|
||||||
try {
|
try {
|
||||||
privData = new FileInputStream(altFile);
|
privData = new FileInputStream(altFile);
|
||||||
return sMgr.addSubsession(privData, props);
|
I2PSession rv = sMgr.addSubsession(privData, props);
|
||||||
|
if (rv.isOffline()) {
|
||||||
|
long exp = rv.getOfflineExpiration();
|
||||||
|
long remaining = exp - getTunnel().getContext().clock().now();
|
||||||
|
// if expires before the LS expires...
|
||||||
|
if (remaining <= 10*60*1000) {
|
||||||
|
String msg;
|
||||||
|
if (remaining > 0)
|
||||||
|
msg = "Offline signature for tunnel alternate destination expires " + DataHelper.formatTime(exp);
|
||||||
|
else
|
||||||
|
msg = "Offline signature for tunnel alternate destination expired " + DataHelper.formatTime(exp);
|
||||||
|
_log.log(Log.CRIT, msg);
|
||||||
|
throw new IllegalArgumentException(msg);
|
||||||
|
}
|
||||||
|
if (remaining < 60*24*60*60*1000L) {
|
||||||
|
String msg = "Offline signature for tunnel alternate destination expires in " + DataHelper.formatDuration(remaining);
|
||||||
|
_log.logAlways(Log.WARN, msg);
|
||||||
|
l.log("WARNING: " + msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
_log.error("Failed to add subssession", ioe);
|
_log.error("Failed to add subssession", ioe);
|
||||||
return null;
|
return null;
|
||||||
|
@ -488,15 +488,13 @@ public class TunnelController implements Logging {
|
|||||||
}
|
}
|
||||||
acquire();
|
acquire();
|
||||||
changeState(TunnelState.RUNNING);
|
changeState(TunnelState.RUNNING);
|
||||||
if ((!isClient() || getPersistentClientKey()) && getIsOfflineKeys()) {
|
if ((!isClient() || getPersistentClientKey()) && getIsOfflineKeysAnySession()) {
|
||||||
File f = getPrivateKeyFile();
|
File f = getPrivateKeyFile();
|
||||||
long time = f.lastModified();
|
File f2 = getAlternatePrivateKeyFile();
|
||||||
if (time > 0) {
|
_pkfc = new PKFChecker(f, f2);
|
||||||
_pkfc = new PKFChecker(f, time);
|
|
||||||
_pkfc.schedule(5*60*1000L);
|
_pkfc.schedule(5*60*1000L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void startHttpClient() {
|
private void startHttpClient() {
|
||||||
setListenOn();
|
setListenOn();
|
||||||
@ -1185,7 +1183,7 @@ public class TunnelController implements Logging {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns false if not running.
|
* Returns false if not running.
|
||||||
* @return true if offline keys or not running
|
* @return true if the primary session has offline keys
|
||||||
* @since 0.9.40
|
* @since 0.9.40
|
||||||
*/
|
*/
|
||||||
public boolean getIsOfflineKeys() {
|
public boolean getIsOfflineKeys() {
|
||||||
@ -1195,6 +1193,24 @@ public class TunnelController implements Logging {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns false if not running.
|
||||||
|
* @return true if ANY session or subsession has offline keys
|
||||||
|
* @since 0.9.48
|
||||||
|
*/
|
||||||
|
private boolean getIsOfflineKeysAnySession() {
|
||||||
|
List<I2PSession> sessions = _tunnel.getSessions();
|
||||||
|
for (I2PSession sess : sessions) {
|
||||||
|
if (sess.isOffline())
|
||||||
|
return true;
|
||||||
|
for (I2PSession sub : sess.getSubsessions()) {
|
||||||
|
if (sub.isOffline())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO synch
|
// TODO synch
|
||||||
public boolean getIsRunning() { return _state == TunnelState.RUNNING; }
|
public boolean getIsRunning() { return _state == TunnelState.RUNNING; }
|
||||||
public boolean getIsStarting() { return _state == TunnelState.START_ON_LOAD || _state == TunnelState.STARTING; }
|
public boolean getIsStarting() { return _state == TunnelState.START_ON_LOAD || _state == TunnelState.STARTING; }
|
||||||
@ -1376,75 +1392,99 @@ public class TunnelController implements Logging {
|
|||||||
* @since 0.9.48
|
* @since 0.9.48
|
||||||
*/
|
*/
|
||||||
private class PKFChecker extends SimpleTimer2.TimedEvent {
|
private class PKFChecker extends SimpleTimer2.TimedEvent {
|
||||||
private final File f;
|
private final List<File> files;
|
||||||
private final long stamp;
|
private final List<Long> stamps;
|
||||||
private boolean wasRun;
|
private boolean wasRun;
|
||||||
|
|
||||||
/** caller must schedule */
|
/**
|
||||||
public PKFChecker(File f, long stamp) {
|
* caller must schedule
|
||||||
|
* @param f2 may be null
|
||||||
|
*/
|
||||||
|
public PKFChecker(File f, File f2) {
|
||||||
super(SimpleTimer2.getInstance());
|
super(SimpleTimer2.getInstance());
|
||||||
this.f = f;
|
files = new ArrayList<File>(2);
|
||||||
this.stamp = stamp;
|
stamps = new ArrayList<Long>(2);
|
||||||
|
files.add(f);
|
||||||
|
stamps.add(Long.valueOf(f.lastModified()));
|
||||||
|
if (f2 != null) {
|
||||||
|
files.add(f2);
|
||||||
|
stamps.add(Long.valueOf(f2.lastModified()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void timeReached() {
|
public void timeReached() {
|
||||||
if (!getIsRunning() && !getIsStarting())
|
if (!getIsRunning() && !getIsStarting())
|
||||||
return;
|
return;
|
||||||
List<I2PSession> sessions = _tunnel.getSessions();
|
List<I2PSession> sessions = _tunnel.getSessions();
|
||||||
if (!sessions.isEmpty()) {
|
if (getIsOfflineKeysAnySession()) {
|
||||||
I2PSession sess = sessions.get(0);
|
I2PAppContext ctx = _tunnel.getContext();
|
||||||
long delay;
|
long now = ctx.clock().now();
|
||||||
if (sess.isOffline()) {
|
long delay = 2*24*60*60*1000L;
|
||||||
|
for (int i = 0; i < files.size(); i++) {
|
||||||
|
File f = files.get(i);
|
||||||
|
long stamp = stamps.get(i).longValue();
|
||||||
|
if (_log.shouldDebug())
|
||||||
|
_log.debug("PKFC checking: " + f + " stamp: " + DataHelper.formatTime(stamp));
|
||||||
|
if (stamp <= 0)
|
||||||
|
continue;
|
||||||
if (f.lastModified() > stamp) {
|
if (f.lastModified() > stamp) {
|
||||||
String msg = "Private key file with offline signature updated, restarting tunnel";
|
String msg = "Private key file " + f + " with offline signature updated, restarting tunnel";
|
||||||
_log.logAlways(Log.WARN, msg);
|
_log.logAlways(Log.WARN, msg);
|
||||||
_tunnel.log(msg);
|
_tunnel.log(msg);
|
||||||
restartTunnel();
|
restartTunnel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
long exp = sess.getOfflineExpiration();
|
if (sessions.isEmpty())
|
||||||
I2PAppContext ctx = _tunnel.getContext();
|
continue;
|
||||||
long now = ctx.clock().now();
|
I2PSession sess = sessions.get(0);
|
||||||
long remaining = exp - now;
|
if (i > 0) {
|
||||||
if (remaining > 10*365*24*60*60*1000L) {
|
List<I2PSession> subs = sess.getSubsessions();
|
||||||
// don't bother
|
if (subs.isEmpty())
|
||||||
return;
|
continue;
|
||||||
|
sess = subs.get(0);
|
||||||
}
|
}
|
||||||
if (remaining <= 10*60*1000) {
|
if (!sess.isOffline())
|
||||||
|
continue;
|
||||||
|
long exp = sess.getOfflineExpiration();
|
||||||
|
long remaining = exp - now;
|
||||||
|
if (remaining <= 11*60*1000) {
|
||||||
// can't sign another LS
|
// can't sign another LS
|
||||||
String msg;
|
String msg;
|
||||||
if (remaining > 0)
|
if (remaining > 0)
|
||||||
msg = "Offline signature for tunnel expires " + DataHelper.formatTime(exp);
|
msg = "Offline signature in private key file " + f + " for tunnel expires " + DataHelper.formatTime(exp) + ", stopping the tunnel!";
|
||||||
else
|
else
|
||||||
msg = "Offline signature for tunnel expired " + DataHelper.formatTime(exp);
|
msg = "Offline signature in private key file " + f + " for tunnel expired " + DataHelper.formatTime(exp) + ", stopping the tunnel!";
|
||||||
_log.log(Log.CRIT, msg);
|
_log.log(Log.CRIT, msg);
|
||||||
_tunnel.log(msg);
|
_tunnel.log(msg);
|
||||||
stopTunnel();
|
stopTunnel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
long d;
|
||||||
if (remaining < 24*60*60*1000L) {
|
if (remaining < 24*60*60*1000L) {
|
||||||
delay = Math.min(60*60*1000L, remaining - (9*60*1000));
|
d = Math.min(60*60*1000L, remaining - (11*60*1000));
|
||||||
} else if (remaining < 7*24*60*60*1000L) {
|
} else if (remaining < 7*24*60*60*1000L) {
|
||||||
delay = 6*60*60*1000L;
|
d = 6*60*60*1000L;
|
||||||
if (!wasRun) {
|
if (!wasRun) {
|
||||||
delay += ctx.random().nextLong(4 * delay);
|
d += ctx.random().nextLong(4 * delay);
|
||||||
wasRun = true;
|
wasRun = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
delay = 24*60*60*1000L;
|
d = 24*60*60*1000L;
|
||||||
if (!wasRun) {
|
if (!wasRun) {
|
||||||
delay += ctx.random().nextLong(delay);
|
delay += ctx.random().nextLong(delay);
|
||||||
wasRun = true;
|
wasRun = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (remaining < 30*24*60*60*1000L) {
|
if (remaining < 30*24*60*60*1000L) {
|
||||||
String msg = "Offline signature for tunnel expires in " + DataHelper.formatDuration(remaining);
|
String msg = "Offline signature in private key file " + f + " for tunnel expires in " + DataHelper.formatDuration(remaining);
|
||||||
_log.logAlways(Log.WARN, msg);
|
_log.logAlways(Log.WARN, msg);
|
||||||
_tunnel.log("WARNING: " + msg);
|
_tunnel.log("WARNING: " + msg);
|
||||||
}
|
}
|
||||||
} else {
|
if (d < delay)
|
||||||
delay = 24*60*60*1000L;
|
delay = d;
|
||||||
}
|
}
|
||||||
|
if (_log.shouldDebug())
|
||||||
|
_log.debug("PKFC sleeping " + DataHelper.formatDuration(delay));
|
||||||
schedule(delay);
|
schedule(delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user