auth and ssl support

This commit is contained in:
zzz
2015-11-27 00:46:45 +00:00
parent 4291450f37
commit 31ace20256
2 changed files with 102 additions and 18 deletions

View File

@ -6,8 +6,10 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.security.GeneralSecurityException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.net.ssl.SSLSocket;
import gnu.getopt.Getopt; import gnu.getopt.Getopt;
@ -15,6 +17,7 @@ import net.i2p.I2PAppContext;
import net.i2p.data.Base32; import net.i2p.data.Base32;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.util.I2PAppThread; import net.i2p.util.I2PAppThread;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.VersionComparator; import net.i2p.util.VersionComparator;
@ -38,19 +41,22 @@ public class SAMStreamSend {
//private boolean _dead; //private boolean _dead;
/** Connection id (Integer) to peer (Flooder) */ /** Connection id (Integer) to peer (Flooder) */
private final Map<String, Sender> _remotePeers; private final Map<String, Sender> _remotePeers;
private static I2PSSLSocketFactory _sslSocketFactory;
private static final int STREAM=0, DG=1, V1DG=2, RAW=3, V1RAW=4; private static final int STREAM=0, DG=1, V1DG=2, RAW=3, V1RAW=4;
private static final String USAGE = "Usage: SAMStreamSend [-s] [-m mode] [-v version] [-b samHost] [-p samPort] peerDestFile dataDir\n" + private static final String USAGE = "Usage: SAMStreamSend [-s] [-m mode] [-v version] [-b samHost] [-p samPort] [-u user] [-w password] peerDestFile dataDir\n" +
" modes: stream: 0; datagram: 1; v1datagram: 2; raw: 3; v1raw: 4\n" + " modes: stream: 0; datagram: 1; v1datagram: 2; raw: 3; v1raw: 4\n" +
" -s: use SSL"; " -s: use SSL";
public static void main(String args[]) { public static void main(String args[]) {
Getopt g = new Getopt("SAM", args, "sb:m:p:v:"); Getopt g = new Getopt("SAM", args, "sb:m:p:u:v:w:");
boolean isSSL = false; boolean isSSL = false;
int mode = STREAM; int mode = STREAM;
String version = "1.0"; String version = "1.0";
String host = "127.0.0.1"; String host = "127.0.0.1";
String port = "7656"; String port = "7656";
String user = null;
String password = null;
int c; int c;
while ((c = g.getopt()) != -1) { while ((c = g.getopt()) != -1) {
switch (c) { switch (c) {
@ -78,6 +84,14 @@ public class SAMStreamSend {
port = g.getOptarg(); port = g.getOptarg();
break; break;
case 'u':
user = g.getOptarg();
break;
case 'w':
password = g.getOptarg();
break;
case 'h': case 'h':
case '?': case '?':
case ':': case ':':
@ -92,10 +106,19 @@ public class SAMStreamSend {
System.err.println(USAGE); System.err.println(USAGE);
return; return;
} }
if ((user == null && password != null) ||
(user != null && password == null)) {
System.err.println("both user and password or neither");
return;
}
if (user != null && password != null && VersionComparator.comp(version, "3.2") < 0) {
System.err.println("user/password require 3.2");
return;
}
I2PAppContext ctx = I2PAppContext.getGlobalContext(); I2PAppContext ctx = I2PAppContext.getGlobalContext();
SAMStreamSend sender = new SAMStreamSend(ctx, host, port, SAMStreamSend sender = new SAMStreamSend(ctx, host, port,
args[startArgs], args[startArgs + 1]); args[startArgs], args[startArgs + 1]);
sender.startup(version, isSSL, mode); sender.startup(version, isSSL, mode, user, password);
} }
public SAMStreamSend(I2PAppContext ctx, String samHost, String samPort, String destFile, String dataFile) { public SAMStreamSend(I2PAppContext ctx, String samHost, String samPort, String destFile, String dataFile) {
@ -110,7 +133,7 @@ public class SAMStreamSend {
_remotePeers = new HashMap<String, Sender>(); _remotePeers = new HashMap<String, Sender>();
} }
public void startup(String version, boolean isSSL, int mode) { public void startup(String version, boolean isSSL, int mode, String user, String password) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Starting up"); _log.debug("Starting up");
try { try {
@ -121,7 +144,7 @@ public class SAMStreamSend {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Reader created"); _log.debug("Reader created");
OutputStream out = sock.getOutputStream(); OutputStream out = sock.getOutputStream();
String ourDest = handshake(out, version, true, eventHandler, mode); String ourDest = handshake(out, version, true, eventHandler, mode, user, password);
if (ourDest == null) if (ourDest == null)
throw new IOException("handshake failed"); throw new IOException("handshake failed");
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
@ -134,7 +157,7 @@ public class SAMStreamSend {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Reader2 created"); _log.debug("Reader2 created");
out = sock2.getOutputStream(); out = sock2.getOutputStream();
String ok = handshake(out, version, false, eventHandler, mode); String ok = handshake(out, version, false, eventHandler, mode, user, password);
if (ok == null) if (ok == null)
throw new IOException("2nd handshake failed"); throw new IOException("2nd handshake failed");
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
@ -172,14 +195,33 @@ public class SAMStreamSend {
} }
private Socket connect(boolean isSSL) throws IOException { private Socket connect(boolean isSSL) throws IOException {
return new Socket(_samHost, Integer.parseInt(_samPort)); int port = Integer.parseInt(_samPort);
if (!isSSL)
return new Socket(_samHost, port);
synchronized(SAMStreamSink.class) {
if (_sslSocketFactory == null) {
try {
_sslSocketFactory = new I2PSSLSocketFactory(
_context, true, "certificates/sam");
} catch (GeneralSecurityException gse) {
throw new IOException("SSL error", gse);
}
}
}
SSLSocket sock = (SSLSocket) _sslSocketFactory.createSocket(_samHost, port);
I2PSSLSocketFactory.verifyHostname(_context, sock, _samHost);
return sock;
} }
/** @return our b64 dest or null */ /** @return our b64 dest or null */
private String handshake(OutputStream samOut, String version, boolean isMaster, SAMEventHandler eventHandler, int mode) { private String handshake(OutputStream samOut, String version, boolean isMaster,
SAMEventHandler eventHandler, int mode, String user, String password) {
synchronized (samOut) { synchronized (samOut) {
try { try {
samOut.write(("HELLO VERSION MIN=1.0 MAX=" + version + '\n').getBytes()); if (user != null && password != null)
samOut.write(("HELLO VERSION MIN=1.0 MAX=" + version + " USER=" + user + " PASSWORD=" + password + '\n').getBytes());
else
samOut.write(("HELLO VERSION MIN=1.0 MAX=" + version + '\n').getBytes());
samOut.flush(); samOut.flush();
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Hello sent"); _log.debug("Hello sent");

View File

@ -6,9 +6,11 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.security.GeneralSecurityException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import javax.net.ssl.SSLSocket;
import gnu.getopt.Getopt; import gnu.getopt.Getopt;
@ -16,6 +18,7 @@ import net.i2p.I2PAppContext;
import net.i2p.data.Base32; import net.i2p.data.Base32;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.util.I2PAppThread; import net.i2p.util.I2PAppThread;
import net.i2p.util.I2PSSLSocketFactory;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.VersionComparator; import net.i2p.util.VersionComparator;
@ -41,19 +44,22 @@ public class SAMStreamSink {
//private boolean _dead; //private boolean _dead;
/** Connection id (Integer) to peer (Flooder) */ /** Connection id (Integer) to peer (Flooder) */
private final Map<String, Sink> _remotePeers; private final Map<String, Sink> _remotePeers;
private static I2PSSLSocketFactory _sslSocketFactory;
private static final int STREAM=0, DG=1, V1DG=2, RAW=3, V1RAW=4; private static final int STREAM=0, DG=1, V1DG=2, RAW=3, V1RAW=4;
private static final String USAGE = "Usage: SAMStreamSink [-s] [-m mode] [-v version] [-b samHost] [-p samPort] myDestFile sinkDir\n" + private static final String USAGE = "Usage: SAMStreamSink [-s] [-m mode] [-v version] [-b samHost] [-p samPort] [-u user] [-w password] myDestFile sinkDir\n" +
" modes: stream: 0; datagram: 1; v1datagram: 2; raw: 3; v1raw: 4\n" + " modes: stream: 0; datagram: 1; v1datagram: 2; raw: 3; v1raw: 4\n" +
" -s: use SSL"; " -s: use SSL";
public static void main(String args[]) { public static void main(String args[]) {
Getopt g = new Getopt("SAM", args, "sb:m:p:v:"); Getopt g = new Getopt("SAM", args, "sb:m:p:u:v:w:");
boolean isSSL = false; boolean isSSL = false;
int mode = STREAM; int mode = STREAM;
String version = "1.0"; String version = "1.0";
String host = "127.0.0.1"; String host = "127.0.0.1";
String port = "7656"; String port = "7656";
String user = null;
String password = null;
int c; int c;
while ((c = g.getopt()) != -1) { while ((c = g.getopt()) != -1) {
switch (c) { switch (c) {
@ -81,6 +87,14 @@ public class SAMStreamSink {
port = g.getOptarg(); port = g.getOptarg();
break; break;
case 'u':
user = g.getOptarg();
break;
case 'w':
password = g.getOptarg();
break;
case 'h': case 'h':
case '?': case '?':
case ':': case ':':
@ -95,10 +109,19 @@ public class SAMStreamSink {
System.err.println(USAGE); System.err.println(USAGE);
return; return;
} }
if ((user == null && password != null) ||
(user != null && password == null)) {
System.err.println("both user and password or neither");
return;
}
if (user != null && password != null && VersionComparator.comp(version, "3.2") < 0) {
System.err.println("user/password require 3.2");
return;
}
I2PAppContext ctx = I2PAppContext.getGlobalContext(); I2PAppContext ctx = I2PAppContext.getGlobalContext();
SAMStreamSink sink = new SAMStreamSink(ctx, host, port, SAMStreamSink sink = new SAMStreamSink(ctx, host, port,
args[startArgs], args[startArgs + 1]); args[startArgs], args[startArgs + 1]);
sink.startup(version, isSSL, mode); sink.startup(version, isSSL, mode, user, password);
} }
public SAMStreamSink(I2PAppContext ctx, String samHost, String samPort, String destFile, String sinkDir) { public SAMStreamSink(I2PAppContext ctx, String samHost, String samPort, String destFile, String sinkDir) {
@ -113,7 +136,7 @@ public class SAMStreamSink {
_remotePeers = new HashMap<String, Sink>(); _remotePeers = new HashMap<String, Sink>();
} }
public void startup(String version, boolean isSSL, int mode) { public void startup(String version, boolean isSSL, int mode, String user, String password) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Starting up"); _log.debug("Starting up");
try { try {
@ -124,7 +147,7 @@ public class SAMStreamSink {
_reader.startReading(); _reader.startReading();
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Reader created"); _log.debug("Reader created");
String ourDest = handshake(out, version, true, eventHandler, mode); String ourDest = handshake(out, version, true, eventHandler, mode, user, password);
if (ourDest == null) if (ourDest == null)
throw new IOException("handshake failed"); throw new IOException("handshake failed");
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
@ -142,7 +165,7 @@ public class SAMStreamSink {
_reader2.startReading(); _reader2.startReading();
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Reader2 created"); _log.debug("Reader2 created");
String ok = handshake(out, version, false, eventHandler, mode); String ok = handshake(out, version, false, eventHandler, mode, user, password);
if (ok == null) if (ok == null)
throw new IOException("2nd handshake failed"); throw new IOException("2nd handshake failed");
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
@ -350,14 +373,33 @@ public class SAMStreamSink {
} }
private Socket connect(boolean isSSL) throws IOException { private Socket connect(boolean isSSL) throws IOException {
return new Socket(_samHost, Integer.parseInt(_samPort)); int port = Integer.parseInt(_samPort);
if (!isSSL)
return new Socket(_samHost, port);
synchronized(SAMStreamSink.class) {
if (_sslSocketFactory == null) {
try {
_sslSocketFactory = new I2PSSLSocketFactory(
_context, true, "certificates/sam");
} catch (GeneralSecurityException gse) {
throw new IOException("SSL error", gse);
}
}
}
SSLSocket sock = (SSLSocket) _sslSocketFactory.createSocket(_samHost, port);
I2PSSLSocketFactory.verifyHostname(_context, sock, _samHost);
return sock;
} }
/** @return our b64 dest or null */ /** @return our b64 dest or null */
private String handshake(OutputStream samOut, String version, boolean isMaster, SAMEventHandler eventHandler, int mode) { private String handshake(OutputStream samOut, String version, boolean isMaster,
SAMEventHandler eventHandler, int mode, String user, String password) {
synchronized (samOut) { synchronized (samOut) {
try { try {
samOut.write(("HELLO VERSION MIN=1.0 MAX=" + version + '\n').getBytes()); if (user != null && password != null)
samOut.write(("HELLO VERSION MIN=1.0 MAX=" + version + " USER=" + user + " PASSWORD=" + password + '\n').getBytes());
else
samOut.write(("HELLO VERSION MIN=1.0 MAX=" + version + '\n').getBytes());
samOut.flush(); samOut.flush();
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Hello sent"); _log.debug("Hello sent");