forked from I2P_Developers/i2p.i2p
merge of '200dbdfc1dba31eb7abc6bb3403ac77cc9072c94'
and '56425d32b819bb74fe3abb999e7e3763814533ac'
This commit is contained in:
@@ -31,6 +31,9 @@ import net.i2p.util.Log;
|
||||
*
|
||||
* There are three options for mangling the desthash. Put the option in the
|
||||
* "custom options" section of i2ptunnel.
|
||||
* - ircserver.method unset: Defaults to user.
|
||||
* - ircserver.method=user: Use method described above.
|
||||
* - ircserver.method=webirc: Use the WEBIRC protocol.
|
||||
* - ircserver.cloakKey unset: Cloak with a random value that is persistent for
|
||||
* the life of this tunnel. This is the default.
|
||||
* - ircserver.cloakKey=somepassphrase: Cloak with the hash of the passphrase. Use this to
|
||||
@@ -39,6 +42,8 @@ import net.i2p.util.Log;
|
||||
* be able to track users even when they switch servers.
|
||||
* Note: don't quote or put spaces in the passphrase,
|
||||
* the i2ptunnel gui can't handle it.
|
||||
* - ircserver.webircPassword=password The password to use for the WEBIRC protocol.
|
||||
* - ircserver.webircSpoofIP=IP The IP
|
||||
* - ircserver.fakeHostname=%f.b32.i2p: Set the fake hostname sent by I2PTunnel,
|
||||
* %f is the full B32 destination hash
|
||||
* %c is the cloaked hash.
|
||||
@@ -48,7 +53,12 @@ import net.i2p.util.Log;
|
||||
* @author zzz
|
||||
*/
|
||||
public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
public static final String PROP_METHOD="ircserver.method";
|
||||
public static final String PROP_METHOD_DEFAULT="user";
|
||||
public static final String PROP_CLOAK="ircserver.cloakKey";
|
||||
public static final String PROP_WEBIRC_PASSWORD="ircserver.webircPassword";
|
||||
public static final String PROP_WEBIRC_SPOOF_IP="ircserver.webircSpoofIP";
|
||||
public static final String PROP_WEBIRC_SPOOF_IP_DEFAULT="127.0.0.1";
|
||||
public static final String PROP_HOSTNAME="ircserver.fakeHostname";
|
||||
public static final String PROP_HOSTNAME_DEFAULT="%f.b32.i2p";
|
||||
|
||||
@@ -67,7 +77,20 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
|
||||
/** generate a random 32 bytes, or the hash of the passphrase */
|
||||
private void initCloak(I2PTunnel tunnel) {
|
||||
// get the properties of this server-tunnel
|
||||
Properties opts = tunnel.getClientOptions();
|
||||
|
||||
// get method of host faking
|
||||
this.method = opts.getProperty(PROP_METHOD, PROP_METHOD_DEFAULT);
|
||||
assert this.method != null;
|
||||
|
||||
// get the password for the webirc method
|
||||
this.webircPassword = opts.getProperty(PROP_WEBIRC_PASSWORD);
|
||||
|
||||
// get the spoof IP for the webirc method
|
||||
this.webircSpoofIP = opts.getProperty(PROP_WEBIRC_SPOOF_IP, PROP_WEBIRC_SPOOF_IP_DEFAULT);
|
||||
|
||||
// get the cloaking passphrase
|
||||
String passphrase = opts.getProperty(PROP_CLOAK);
|
||||
if (passphrase == null) {
|
||||
this.cloakKey = new byte[Hash.HASH_LENGTH];
|
||||
@@ -76,17 +99,30 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
this.cloakKey = SHA256Generator.getInstance().calculateHash(passphrase.trim().getBytes()).getData();
|
||||
}
|
||||
|
||||
// get the fake hostmask to use
|
||||
this.hostname = opts.getProperty(PROP_HOSTNAME, PROP_HOSTNAME_DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void blockingHandle(I2PSocket socket) {
|
||||
try {
|
||||
// give them 15 seconds to send in the request
|
||||
socket.setReadTimeout(15*1000);
|
||||
InputStream in = socket.getInputStream();
|
||||
String modifiedRegistration = filterRegistration(in, cloakDest(socket.getPeerDestination()));
|
||||
socket.setReadTimeout(readTimeout);
|
||||
String modifiedRegistration;
|
||||
if(!this.method.equals("webirc")) {
|
||||
// give them 15 seconds to send in the request
|
||||
socket.setReadTimeout(15*1000);
|
||||
InputStream in = socket.getInputStream();
|
||||
modifiedRegistration = filterRegistration(in, cloakDest(socket.getPeerDestination()));
|
||||
socket.setReadTimeout(readTimeout);
|
||||
} else {
|
||||
StringBuffer buf = new StringBuffer("WEBIRC ");
|
||||
buf.append(this.webircPassword);
|
||||
buf.append(" cgiirc ");
|
||||
buf.append(cloakDest(socket.getPeerDestination()));
|
||||
buf.append(' ');
|
||||
buf.append(this.webircSpoofIP);
|
||||
buf.append("\r\n");
|
||||
modifiedRegistration = buf.toString();
|
||||
}
|
||||
Socket s = new Socket(remoteHost, remotePort);
|
||||
new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null);
|
||||
} catch (SocketException ex) {
|
||||
@@ -185,4 +221,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
|
||||
private byte[] cloakKey; // 32 bytes of stuff to scramble the dest with
|
||||
private String hostname;
|
||||
private String method;
|
||||
private String webircPassword;
|
||||
private String webircSpoofIP;
|
||||
}
|
||||
|
@@ -14,7 +14,9 @@ import java.io.IOException;
|
||||
import net.i2p.crypto.DSAEngine;
|
||||
import net.i2p.crypto.SHA256Generator;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.Signature;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -33,7 +35,7 @@ public final class I2PDatagramDissector {
|
||||
private DSAEngine dsaEng = DSAEngine.getInstance();
|
||||
private SHA256Generator hashGen = SHA256Generator.getInstance();
|
||||
|
||||
private byte[] rxHashBytes = null;
|
||||
private Hash rxHash = null;
|
||||
|
||||
private Signature rxSign = new Signature();
|
||||
|
||||
@@ -62,21 +64,27 @@ public final class I2PDatagramDissector {
|
||||
ByteArrayInputStream dgStream = new ByteArrayInputStream(dgram);
|
||||
byte[] rxTrimmedPayload;
|
||||
|
||||
// set invalid(very important!)
|
||||
this.valid = false;
|
||||
|
||||
try {
|
||||
// read destination
|
||||
rxDest.readBytes(dgStream);
|
||||
|
||||
// read signature
|
||||
rxSign.readBytes(dgStream);
|
||||
|
||||
// read payload
|
||||
rxPayloadLen = dgStream.read(rxPayload);
|
||||
|
||||
// FIXME: hashGen.calculateHash(source, offset, len) would rock...
|
||||
rxTrimmedPayload = new byte[rxPayloadLen];
|
||||
System.arraycopy(rxPayload, 0, rxTrimmedPayload, 0, rxPayloadLen);
|
||||
|
||||
rxHashBytes =hashGen.calculateHash(rxTrimmedPayload).toByteArray();
|
||||
|
||||
// calculate the hash of the payload
|
||||
this.rxHash = hashGen.calculateHash(rxPayload, 0, rxPayloadLen);
|
||||
assert this.hashGen.calculateHash(this.extractPayload()).equals(this.rxHash);
|
||||
} catch (IOException e) {
|
||||
_log.error("Caught IOException - INCONSISTENT STATE!", e);
|
||||
}
|
||||
} catch(AssertionError e) {
|
||||
_log.error("Assertion failed!", e);
|
||||
}
|
||||
|
||||
//_log.debug("Datagram payload size: " + rxPayloadLen + "; content:\n"
|
||||
// + HexDump.dump(rxPayload, 0, rxPayloadLen));
|
||||
@@ -93,10 +101,7 @@ public final class I2PDatagramDissector {
|
||||
public byte[] getPayload() throws I2PInvalidDatagramException {
|
||||
this.verifySignature();
|
||||
|
||||
byte[] retPayload = new byte[rxPayloadLen];
|
||||
System.arraycopy(rxPayload, 0, retPayload, 0, rxPayloadLen);
|
||||
|
||||
return retPayload;
|
||||
return this.extractPayload();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -110,17 +115,23 @@ public final class I2PDatagramDissector {
|
||||
public Destination getSender() throws I2PInvalidDatagramException {
|
||||
this.verifySignature();
|
||||
|
||||
Destination retDest = new Destination();
|
||||
try {
|
||||
retDest.fromByteArray(rxDest.toByteArray());
|
||||
} catch (DataFormatException e) {
|
||||
_log.error("Caught DataFormatException", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
return retDest;
|
||||
return this.extractSender();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the hash of the payload of an I2P repliable datagram (previously
|
||||
* loaded with the loadI2PDatagram() method), verifying the datagram
|
||||
* signature.
|
||||
* @return The hash of the payload of the I2P repliable datagram
|
||||
* @throws I2PInvalidDatagramException if the signature verification fails
|
||||
*/
|
||||
public Hash getHash() throws I2PInvalidDatagramException {
|
||||
// make sure it has a valid signature
|
||||
this.verifySignature();
|
||||
|
||||
return this.extractHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the payload carried by an I2P repliable datagram (previously
|
||||
* loaded with the loadI2PDatagram() method), without verifying the
|
||||
@@ -129,8 +140,8 @@ public final class I2PDatagramDissector {
|
||||
* @return A byte array containing the datagram payload
|
||||
*/
|
||||
public byte[] extractPayload() {
|
||||
byte[] retPayload = new byte[rxPayloadLen];
|
||||
System.arraycopy(rxPayload, 0, retPayload, 0, rxPayloadLen);
|
||||
byte[] retPayload = new byte[this.rxPayloadLen];
|
||||
System.arraycopy(this.rxPayload, 0, retPayload, 0, this.rxPayloadLen);
|
||||
|
||||
return retPayload;
|
||||
}
|
||||
@@ -144,7 +155,7 @@ public final class I2PDatagramDissector {
|
||||
public Destination extractSender() {
|
||||
Destination retDest = new Destination();
|
||||
try {
|
||||
retDest.fromByteArray(rxDest.toByteArray());
|
||||
retDest.fromByteArray(this.rxDest.toByteArray());
|
||||
} catch (DataFormatException e) {
|
||||
_log.error("Caught DataFormatException", e);
|
||||
return null;
|
||||
@@ -152,10 +163,21 @@ public final class I2PDatagramDissector {
|
||||
|
||||
return retDest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the hash of the payload of an I2P repliable datagram (previously
|
||||
* loaded with the loadI2PDatagram() method), without verifying the datagram
|
||||
* signature.
|
||||
* @return The hash of the payload of the I2P repliable datagram
|
||||
*/
|
||||
public Hash extractHash() {
|
||||
return this.rxHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the signature of this datagram (previously loaded with the
|
||||
* loadI2PDatagram() method)
|
||||
* @throws I2PInvalidDatagramException if the signature is invalid
|
||||
*/
|
||||
public void verifySignature() throws I2PInvalidDatagramException {
|
||||
// first check if it already got validated
|
||||
@@ -163,7 +185,7 @@ public final class I2PDatagramDissector {
|
||||
return;
|
||||
|
||||
// now validate
|
||||
if (!dsaEng.verifySignature(rxSign, rxHashBytes, rxDest.getSigningPublicKey()))
|
||||
if (!this.dsaEng.verifySignature(rxSign, rxHash.getData(), rxDest.getSigningPublicKey()))
|
||||
throw new I2PInvalidDatagramException("Incorrect I2P repliable datagram signature");
|
||||
|
||||
// set validated
|
||||
|
Reference in New Issue
Block a user