mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Merge branch 'socks-socket' into 'master'
Fetch RSS feeds via Tor This patch replaces jsocks with our own minimal SOCKS 5 implementation, which is compatible with Android's OpenSSL hacks (see discussion on #599 for the horrifying details). This allows us to use OkHttp over Tor to fetch RSS feeds. It turns out that SOCKS 5 without authentication is a really simple protocol: https://tools.ietf.org/html/rfc1928 Closes #599. See merge request !308
This commit is contained in:
@@ -11,9 +11,6 @@ dependencies {
|
|||||||
compile project(':briar-api')
|
compile project(':briar-api')
|
||||||
compile project(':briar-core')
|
compile project(':briar-core')
|
||||||
compile fileTree(dir: 'libs', include: '*.jar')
|
compile fileTree(dir: 'libs', include: '*.jar')
|
||||||
// This shouldn't be necessary; per section 23.4.4 of the Gradle docs:
|
|
||||||
// "file dependencies are included in transitive project dependencies within the same build".
|
|
||||||
compile files('../briar-core/libs/jsocks.jar')
|
|
||||||
|
|
||||||
compile "com.android.support:support-v4:$supportVersion"
|
compile "com.android.support:support-v4:$supportVersion"
|
||||||
compile("com.android.support:appcompat-v7:$supportVersion") {
|
compile("com.android.support:appcompat-v7:$supportVersion") {
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import java.util.Collection;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
@@ -30,15 +32,16 @@ public class AndroidPluginsModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
public PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
|
public PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor,
|
||||||
AndroidExecutor androidExecutor,
|
AndroidExecutor androidExecutor, SecureRandom random,
|
||||||
SecureRandom random, BackoffFactory backoffFactory, Application app,
|
SocketFactory torSocketFactory, BackoffFactory backoffFactory,
|
||||||
LocationUtils locationUtils, DevReporter reporter,
|
Application app, LocationUtils locationUtils, DevReporter reporter,
|
||||||
EventBus eventBus) {
|
EventBus eventBus) {
|
||||||
Context appContext = app.getApplicationContext();
|
Context appContext = app.getApplicationContext();
|
||||||
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
|
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
|
||||||
androidExecutor, appContext, random, backoffFactory);
|
androidExecutor, appContext, random, backoffFactory);
|
||||||
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
|
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
|
||||||
locationUtils, reporter, eventBus, backoffFactory);
|
locationUtils, reporter, eventBus, torSocketFactory,
|
||||||
|
backoffFactory);
|
||||||
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
||||||
backoffFactory, appContext);
|
backoffFactory, appContext);
|
||||||
final Collection<DuplexPluginFactory> duplex =
|
final Collection<DuplexPluginFactory> duplex =
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import android.os.PowerManager;
|
|||||||
|
|
||||||
import net.freehaven.tor.control.EventHandler;
|
import net.freehaven.tor.control.EventHandler;
|
||||||
import net.freehaven.tor.control.TorControlConnection;
|
import net.freehaven.tor.control.TorControlConnection;
|
||||||
import net.sourceforge.jsocks.socks.Socks5Proxy;
|
|
||||||
import net.sourceforge.jsocks.socks.SocksSocket;
|
|
||||||
|
|
||||||
import org.briarproject.android.util.AndroidUtils;
|
import org.briarproject.android.util.AndroidUtils;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
@@ -62,6 +60,8 @@ import java.util.logging.Logger;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import static android.content.Context.CONNECTIVITY_SERVICE;
|
import static android.content.Context.CONNECTIVITY_SERVICE;
|
||||||
import static android.content.Context.MODE_PRIVATE;
|
import static android.content.Context.MODE_PRIVATE;
|
||||||
import static android.content.Context.POWER_SERVICE;
|
import static android.content.Context.POWER_SERVICE;
|
||||||
@@ -74,7 +74,6 @@ import static java.util.logging.Level.WARNING;
|
|||||||
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
|
import static net.freehaven.tor.control.TorControlCommands.HS_ADDRESS;
|
||||||
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
|
import static net.freehaven.tor.control.TorControlCommands.HS_PRIVKEY;
|
||||||
import static org.briarproject.api.plugins.TorConstants.CONTROL_PORT;
|
import static org.briarproject.api.plugins.TorConstants.CONTROL_PORT;
|
||||||
import static org.briarproject.api.plugins.TorConstants.SOCKS_PORT;
|
|
||||||
import static org.briarproject.util.PrivacyUtils.scrubOnion;
|
import static org.briarproject.util.PrivacyUtils.scrubOnion;
|
||||||
|
|
||||||
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
||||||
@@ -93,6 +92,7 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
private final DevReporter reporter;
|
private final DevReporter reporter;
|
||||||
|
private final SocketFactory torSocketFactory;
|
||||||
private final Backoff backoff;
|
private final Backoff backoff;
|
||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
private final String architecture;
|
private final String architecture;
|
||||||
@@ -110,13 +110,15 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
private volatile BroadcastReceiver networkStateReceiver = null;
|
private volatile BroadcastReceiver networkStateReceiver = null;
|
||||||
|
|
||||||
TorPlugin(Executor ioExecutor, Context appContext,
|
TorPlugin(Executor ioExecutor, Context appContext,
|
||||||
LocationUtils locationUtils, DevReporter reporter, Backoff backoff,
|
LocationUtils locationUtils, DevReporter reporter,
|
||||||
|
SocketFactory torSocketFactory, Backoff backoff,
|
||||||
DuplexPluginCallback callback, String architecture, int maxLatency,
|
DuplexPluginCallback callback, String architecture, int maxLatency,
|
||||||
int maxIdleTime) {
|
int maxIdleTime) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
this.reporter = reporter;
|
this.reporter = reporter;
|
||||||
|
this.torSocketFactory = torSocketFactory;
|
||||||
this.backoff = backoff;
|
this.backoff = backoff;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.architecture = architecture;
|
this.architecture = architecture;
|
||||||
@@ -295,6 +297,14 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tryToClose(Socket s) {
|
||||||
|
try {
|
||||||
|
if (s != null) s.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void listFiles(File f) {
|
private void listFiles(File f) {
|
||||||
if (f.isDirectory()) for (File child : f.listFiles()) listFiles(child);
|
if (f.isDirectory()) for (File child : f.listFiles()) listFiles(child);
|
||||||
else LOG.info(f.getAbsolutePath());
|
else LOG.info(f.getAbsolutePath());
|
||||||
@@ -320,8 +330,9 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
ioExecutor.execute(new Runnable() {
|
ioExecutor.execute(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
// TODO: Trigger this with a TransportEnabledEvent
|
||||||
File reportDir = AndroidUtils.getReportDir(appContext);
|
File reportDir = AndroidUtils.getReportDir(appContext);
|
||||||
reporter.sendReports(reportDir, SOCKS_PORT);
|
reporter.sendReports(reportDir);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -516,21 +527,22 @@ class TorPlugin implements DuplexPlugin, EventHandler, EventListener {
|
|||||||
if (LOG.isLoggable(INFO)) LOG.info("Invalid hostname: " + onion);
|
if (LOG.isLoggable(INFO)) LOG.info("Invalid hostname: " + onion);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Socket s = null;
|
||||||
try {
|
try {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Connecting to " + scrubOnion(onion));
|
LOG.info("Connecting to " + scrubOnion(onion));
|
||||||
controlConnection.forgetHiddenService(onion);
|
controlConnection.forgetHiddenService(onion);
|
||||||
Socks5Proxy proxy = new Socks5Proxy("127.0.0.1", SOCKS_PORT);
|
s = torSocketFactory.createSocket(onion + ".onion", 80);
|
||||||
proxy.resolveAddrLocally(false);
|
|
||||||
Socket s = new SocksSocket(proxy, onion + ".onion", 80);
|
|
||||||
s.setSoTimeout(socketTimeout);
|
s.setSoTimeout(socketTimeout);
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Connected to " + scrubOnion(onion));
|
LOG.info("Connected to " + scrubOnion(onion));
|
||||||
return new TorTransportConnection(this, s);
|
return new TorTransportConnection(this, s);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Could not connect to " + scrubOnion(onion) + ": " +
|
LOG.info("Could not connect to " + scrubOnion(onion) + ": " +
|
||||||
e.toString());
|
e.toString());
|
||||||
|
}
|
||||||
|
tryToClose(s);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ import org.briarproject.api.system.LocationUtils;
|
|||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
public class TorPluginFactory implements DuplexPluginFactory {
|
public class TorPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
@@ -34,16 +36,19 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
private final LocationUtils locationUtils;
|
private final LocationUtils locationUtils;
|
||||||
private final DevReporter reporter;
|
private final DevReporter reporter;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
private final SocketFactory torSocketFactory;
|
||||||
private final BackoffFactory backoffFactory;
|
private final BackoffFactory backoffFactory;
|
||||||
|
|
||||||
public TorPluginFactory(Executor ioExecutor, Context appContext,
|
public TorPluginFactory(Executor ioExecutor, Context appContext,
|
||||||
LocationUtils locationUtils, DevReporter reporter,
|
LocationUtils locationUtils, DevReporter reporter,
|
||||||
EventBus eventBus, BackoffFactory backoffFactory) {
|
EventBus eventBus, SocketFactory torSocketFactory,
|
||||||
|
BackoffFactory backoffFactory) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.locationUtils = locationUtils;
|
this.locationUtils = locationUtils;
|
||||||
this.reporter = reporter;
|
this.reporter = reporter;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.torSocketFactory = torSocketFactory;
|
||||||
this.backoffFactory = backoffFactory;
|
this.backoffFactory = backoffFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,8 +86,8 @@ public class TorPluginFactory implements DuplexPluginFactory {
|
|||||||
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
TorPlugin plugin = new TorPlugin(ioExecutor, appContext, locationUtils,
|
TorPlugin plugin = new TorPlugin(ioExecutor, appContext, locationUtils,
|
||||||
reporter, backoff, callback, architecture, MAX_LATENCY,
|
reporter, torSocketFactory, backoff, callback, architecture,
|
||||||
MAX_IDLE_TIME);
|
MAX_LATENCY, MAX_IDLE_TIME);
|
||||||
eventBus.addListener(plugin);
|
eventBus.addListener(plugin);
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,4 +9,5 @@ public interface TorConstants {
|
|||||||
int SOCKS_PORT = 59050;
|
int SOCKS_PORT = 59050;
|
||||||
int CONTROL_PORT = 59051;
|
int CONTROL_PORT = 59051;
|
||||||
|
|
||||||
|
int CONNECT_TO_PROXY_TIMEOUT = 5000; // Milliseconds
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ public interface DevReporter {
|
|||||||
* Send reports previously stored on-disk.
|
* Send reports previously stored on-disk.
|
||||||
*
|
*
|
||||||
* @param reportDir the directory where reports are stored.
|
* @param reportDir the directory where reports are stored.
|
||||||
* @param socksPort the SOCKS port of a Tor client.
|
|
||||||
*/
|
*/
|
||||||
void sendReports(File reportDir, int socksPort);
|
void sendReports(File reportDir);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -22,6 +22,7 @@ import org.briarproject.reliability.ReliabilityModule;
|
|||||||
import org.briarproject.reporting.ReportingModule;
|
import org.briarproject.reporting.ReportingModule;
|
||||||
import org.briarproject.settings.SettingsModule;
|
import org.briarproject.settings.SettingsModule;
|
||||||
import org.briarproject.sharing.SharingModule;
|
import org.briarproject.sharing.SharingModule;
|
||||||
|
import org.briarproject.socks.SocksModule;
|
||||||
import org.briarproject.sync.SyncModule;
|
import org.briarproject.sync.SyncModule;
|
||||||
import org.briarproject.system.SystemModule;
|
import org.briarproject.system.SystemModule;
|
||||||
import org.briarproject.transport.TransportModule;
|
import org.briarproject.transport.TransportModule;
|
||||||
@@ -50,6 +51,7 @@ import dagger.Module;
|
|||||||
ReportingModule.class,
|
ReportingModule.class,
|
||||||
SettingsModule.class,
|
SettingsModule.class,
|
||||||
SharingModule.class,
|
SharingModule.class,
|
||||||
|
SocksModule.class,
|
||||||
SyncModule.class,
|
SyncModule.class,
|
||||||
SystemModule.class,
|
SystemModule.class,
|
||||||
TransportModule.class,
|
TransportModule.class,
|
||||||
|
|||||||
@@ -40,9 +40,6 @@ import org.briarproject.util.StringUtils;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.Proxy;
|
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -55,11 +52,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_BODY_LENGTH;
|
import static org.briarproject.api.blogs.BlogConstants.MAX_BLOG_POST_BODY_LENGTH;
|
||||||
@@ -67,7 +66,6 @@ import static org.briarproject.api.feed.FeedConstants.FETCH_DELAY_INITIAL;
|
|||||||
import static org.briarproject.api.feed.FeedConstants.FETCH_INTERVAL;
|
import static org.briarproject.api.feed.FeedConstants.FETCH_INTERVAL;
|
||||||
import static org.briarproject.api.feed.FeedConstants.FETCH_UNIT;
|
import static org.briarproject.api.feed.FeedConstants.FETCH_UNIT;
|
||||||
import static org.briarproject.api.feed.FeedConstants.KEY_FEEDS;
|
import static org.briarproject.api.feed.FeedConstants.KEY_FEEDS;
|
||||||
import static org.briarproject.api.plugins.TorConstants.SOCKS_PORT;
|
|
||||||
|
|
||||||
class FeedManagerImpl implements FeedManager, Client, EventListener {
|
class FeedManagerImpl implements FeedManager, Client, EventListener {
|
||||||
|
|
||||||
@@ -79,6 +77,8 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
|
|||||||
"466565644d616e6167657202fb797097"
|
"466565644d616e6167657202fb797097"
|
||||||
+ "255af837abbf8c16e250b3c2ccc286eb"));
|
+ "255af837abbf8c16e250b3c2ccc286eb"));
|
||||||
|
|
||||||
|
private static final int CONNECT_TIMEOUT = 60 * 1000; // Milliseconds
|
||||||
|
|
||||||
private final ScheduledExecutorService feedExecutor;
|
private final ScheduledExecutorService feedExecutor;
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
@@ -86,6 +86,7 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
|
|||||||
private final ClientHelper clientHelper;
|
private final ClientHelper clientHelper;
|
||||||
private final IdentityManager identityManager;
|
private final IdentityManager identityManager;
|
||||||
private final BlogManager blogManager;
|
private final BlogManager blogManager;
|
||||||
|
private final SocketFactory torSocketFactory;
|
||||||
private final AtomicBoolean fetcherStarted = new AtomicBoolean(false);
|
private final AtomicBoolean fetcherStarted = new AtomicBoolean(false);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -99,7 +100,8 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
|
|||||||
FeedManagerImpl(ScheduledExecutorService feedExecutor,
|
FeedManagerImpl(ScheduledExecutorService feedExecutor,
|
||||||
@IoExecutor Executor ioExecutor, DatabaseComponent db,
|
@IoExecutor Executor ioExecutor, DatabaseComponent db,
|
||||||
PrivateGroupFactory privateGroupFactory, ClientHelper clientHelper,
|
PrivateGroupFactory privateGroupFactory, ClientHelper clientHelper,
|
||||||
IdentityManager identityManager, BlogManager blogManager) {
|
IdentityManager identityManager, BlogManager blogManager,
|
||||||
|
SocketFactory torSocketFactory) {
|
||||||
|
|
||||||
this.feedExecutor = feedExecutor;
|
this.feedExecutor = feedExecutor;
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
@@ -108,6 +110,7 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
|
|||||||
this.clientHelper = clientHelper;
|
this.clientHelper = clientHelper;
|
||||||
this.identityManager = identityManager;
|
this.identityManager = identityManager;
|
||||||
this.blogManager = blogManager;
|
this.blogManager = blogManager;
|
||||||
|
this.torSocketFactory = torSocketFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -354,14 +357,10 @@ class FeedManagerImpl implements FeedManager, Client, EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private InputStream getFeedInputStream(String url) throws IOException {
|
private InputStream getFeedInputStream(String url) throws IOException {
|
||||||
// Set proxy
|
|
||||||
SocketAddress socketAddress =
|
|
||||||
new InetSocketAddress("127.0.0.1", SOCKS_PORT);
|
|
||||||
Proxy proxy = new Proxy(Proxy.Type.SOCKS, socketAddress);
|
|
||||||
|
|
||||||
// Build HTTP Client
|
// Build HTTP Client
|
||||||
OkHttpClient client = new OkHttpClient.Builder()
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
// .proxy(proxy)
|
.socketFactory(torSocketFactory)
|
||||||
|
.connectTimeout(CONNECT_TIMEOUT, MILLISECONDS)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Build Request
|
// Build Request
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
package org.briarproject.reporting;
|
package org.briarproject.reporting;
|
||||||
|
|
||||||
import net.sourceforge.jsocks.socks.Socks5Proxy;
|
|
||||||
import net.sourceforge.jsocks.socks.SocksException;
|
|
||||||
import net.sourceforge.jsocks.socks.SocksSocket;
|
|
||||||
|
|
||||||
import org.briarproject.api.crypto.CryptoComponent;
|
import org.briarproject.api.crypto.CryptoComponent;
|
||||||
import org.briarproject.api.reporting.DevConfig;
|
import org.briarproject.api.reporting.DevConfig;
|
||||||
import org.briarproject.api.reporting.DevReporter;
|
import org.briarproject.api.reporting.DevReporter;
|
||||||
@@ -21,10 +17,10 @@ import java.io.OutputStream;
|
|||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
class DevReporterImpl implements DevReporter {
|
class DevReporterImpl implements DevReporter {
|
||||||
@@ -35,21 +31,28 @@ class DevReporterImpl implements DevReporter {
|
|||||||
private static final int SOCKET_TIMEOUT = 30 * 1000; // 30 seconds
|
private static final int SOCKET_TIMEOUT = 30 * 1000; // 30 seconds
|
||||||
private static final int LINE_LENGTH = 70;
|
private static final int LINE_LENGTH = 70;
|
||||||
|
|
||||||
private CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private DevConfig devConfig;
|
private final DevConfig devConfig;
|
||||||
|
private final SocketFactory torSocketFactory;
|
||||||
|
|
||||||
public DevReporterImpl(CryptoComponent crypto, DevConfig devConfig) {
|
public DevReporterImpl(CryptoComponent crypto, DevConfig devConfig,
|
||||||
|
SocketFactory torSocketFactory) {
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.devConfig = devConfig;
|
this.devConfig = devConfig;
|
||||||
|
this.torSocketFactory = torSocketFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Socket connectToDevelopers(int socksPort)
|
private Socket connectToDevelopers() throws IOException {
|
||||||
throws UnknownHostException, SocksException, SocketException {
|
String onion = devConfig.getDevOnionAddress();
|
||||||
Socks5Proxy proxy = new Socks5Proxy("127.0.0.1", socksPort);
|
Socket s = null;
|
||||||
proxy.resolveAddrLocally(false);
|
try {
|
||||||
Socket s = new SocksSocket(proxy, devConfig.getDevOnionAddress(), 80);
|
s = torSocketFactory.createSocket(onion, 80);
|
||||||
s.setSoTimeout(SOCKET_TIMEOUT);
|
s.setSoTimeout(SOCKET_TIMEOUT);
|
||||||
return s;
|
return s;
|
||||||
|
} catch (IOException e) {
|
||||||
|
tryToClose(s);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -74,7 +77,7 @@ class DevReporterImpl implements DevReporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendReports(File reportDir, int socksPort) {
|
public void sendReports(File reportDir) {
|
||||||
File[] reports = reportDir.listFiles();
|
File[] reports = reportDir.listFiles();
|
||||||
if (reports == null || reports.length == 0)
|
if (reports == null || reports.length == 0)
|
||||||
return; // No reports to send
|
return; // No reports to send
|
||||||
@@ -84,7 +87,7 @@ class DevReporterImpl implements DevReporter {
|
|||||||
OutputStream out = null;
|
OutputStream out = null;
|
||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
try {
|
try {
|
||||||
Socket s = connectToDevelopers(socksPort);
|
Socket s = connectToDevelopers();
|
||||||
out = s.getOutputStream();
|
out = s.getOutputStream();
|
||||||
in = new FileInputStream(f);
|
in = new FileInputStream(f);
|
||||||
IoUtils.copy(in, out);
|
IoUtils.copy(in, out);
|
||||||
@@ -106,4 +109,12 @@ class DevReporterImpl implements DevReporter {
|
|||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tryToClose(Socket s) {
|
||||||
|
try {
|
||||||
|
if (s != null) s.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import org.briarproject.api.crypto.CryptoComponent;
|
|||||||
import org.briarproject.api.reporting.DevConfig;
|
import org.briarproject.api.reporting.DevConfig;
|
||||||
import org.briarproject.api.reporting.DevReporter;
|
import org.briarproject.api.reporting.DevReporter;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
@@ -12,7 +14,7 @@ public class ReportingModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
DevReporter provideDevReportTask(CryptoComponent crypto,
|
DevReporter provideDevReportTask(CryptoComponent crypto,
|
||||||
DevConfig devConfig) {
|
DevConfig devConfig, SocketFactory torSocketFactory) {
|
||||||
return new DevReporterImpl(crypto, devConfig);
|
return new DevReporterImpl(crypto, devConfig, torSocketFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
briar-core/src/org/briarproject/socks/SocksModule.java
Normal file
22
briar-core/src/org/briarproject/socks/SocksModule.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package org.briarproject.socks;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
import static org.briarproject.api.plugins.TorConstants.CONNECT_TO_PROXY_TIMEOUT;
|
||||||
|
import static org.briarproject.api.plugins.TorConstants.SOCKS_PORT;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class SocksModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
SocketFactory provideTorSocketFactory() {
|
||||||
|
InetSocketAddress proxy = new InetSocketAddress("127.0.0.1",
|
||||||
|
SOCKS_PORT);
|
||||||
|
return new SocksSocketFactory(proxy, CONNECT_TO_PROXY_TIMEOUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
108
briar-core/src/org/briarproject/socks/SocksSocket.java
Normal file
108
briar-core/src/org/briarproject/socks/SocksSocket.java
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
package org.briarproject.socks;
|
||||||
|
|
||||||
|
import org.briarproject.util.ByteUtils;
|
||||||
|
import org.briarproject.util.IoUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
class SocksSocket extends Socket {
|
||||||
|
|
||||||
|
private final SocketAddress proxy;
|
||||||
|
private final int connectToProxyTimeout;
|
||||||
|
|
||||||
|
SocksSocket(SocketAddress proxy, int connectToProxyTimeout) {
|
||||||
|
this.proxy = proxy;
|
||||||
|
this.connectToProxyTimeout = connectToProxyTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect(SocketAddress endpoint, int timeout)
|
||||||
|
throws IOException {
|
||||||
|
|
||||||
|
// Validate the endpoint
|
||||||
|
if (!(endpoint instanceof InetSocketAddress))
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
InetSocketAddress inet = (InetSocketAddress) endpoint;
|
||||||
|
String host = inet.getHostName();
|
||||||
|
if (host.length() > 255) throw new IllegalArgumentException();
|
||||||
|
int port = inet.getPort();
|
||||||
|
|
||||||
|
// Connect to the proxy
|
||||||
|
super.connect(proxy, connectToProxyTimeout);
|
||||||
|
OutputStream out = getOutputStream();
|
||||||
|
InputStream in = getInputStream();
|
||||||
|
|
||||||
|
// Request SOCKS 5 with no authentication
|
||||||
|
sendMethodRequest(out);
|
||||||
|
receiveMethodResponse(in);
|
||||||
|
|
||||||
|
// Use the supplied timeout temporarily
|
||||||
|
int oldTimeout = getSoTimeout();
|
||||||
|
setSoTimeout(timeout);
|
||||||
|
|
||||||
|
// Connect to the endpoint via the proxy
|
||||||
|
sendConnectRequest(out, host, port);
|
||||||
|
receiveConnectResponse(in);
|
||||||
|
|
||||||
|
// Restore the old timeout
|
||||||
|
setSoTimeout(oldTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendMethodRequest(OutputStream out) throws IOException {
|
||||||
|
byte[] methodRequest = new byte[] {
|
||||||
|
5, // SOCKS version is 5
|
||||||
|
1, // Number of methods is 1
|
||||||
|
0 // Method is 0, no authentication
|
||||||
|
};
|
||||||
|
out.write(methodRequest);
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receiveMethodResponse(InputStream in) throws IOException {
|
||||||
|
byte[] methodResponse = new byte[2];
|
||||||
|
IoUtils.read(in, methodResponse);
|
||||||
|
byte version = methodResponse[0];
|
||||||
|
byte method = methodResponse[1];
|
||||||
|
if (version != 5)
|
||||||
|
throw new IOException("Unsupported SOCKS version: " + version);
|
||||||
|
if (method == (byte) 255)
|
||||||
|
throw new IOException("Proxy requires authentication");
|
||||||
|
if (method != 0)
|
||||||
|
throw new IOException("Unsupported auth method: " + method);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendConnectRequest(OutputStream out, String host, int port)
|
||||||
|
throws IOException {
|
||||||
|
byte[] connectRequest = new byte[7 + host.length()];
|
||||||
|
connectRequest[0] = 5; // SOCKS version is 5
|
||||||
|
connectRequest[1] = 1; // Command is 1, connect
|
||||||
|
connectRequest[3] = 3; // Address type is 3, domain name
|
||||||
|
connectRequest[4] = (byte) host.length(); // Length of domain name
|
||||||
|
for (int i = 0; i < host.length(); i++)
|
||||||
|
connectRequest[5 + i] = (byte) host.charAt(i);
|
||||||
|
ByteUtils.writeUint16(port, connectRequest, connectRequest.length - 2);
|
||||||
|
out.write(connectRequest);
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void receiveConnectResponse(InputStream in) throws IOException {
|
||||||
|
byte[] connectResponse = new byte[4];
|
||||||
|
IoUtils.read(in, connectResponse);
|
||||||
|
byte version = connectResponse[0];
|
||||||
|
byte reply = connectResponse[1];
|
||||||
|
byte addressType = connectResponse[3];
|
||||||
|
if (version != 5)
|
||||||
|
throw new IOException("Unsupported SOCKS version: " + version);
|
||||||
|
if (reply != 0)
|
||||||
|
throw new IOException("Connection failed: " + reply);
|
||||||
|
if (addressType == 1) IoUtils.read(in, new byte[4]); // IPv4
|
||||||
|
else if (addressType == 4) IoUtils.read(in, new byte[16]); // IPv6
|
||||||
|
else throw new IOException("Unsupported address type: " + addressType);
|
||||||
|
IoUtils.read(in, new byte[2]); // Port number
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package org.briarproject.socks;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
|
||||||
|
class SocksSocketFactory extends SocketFactory {
|
||||||
|
|
||||||
|
private final SocketAddress proxy;
|
||||||
|
private final int connectToProxyTimeout;
|
||||||
|
|
||||||
|
SocksSocketFactory(SocketAddress proxy, int connectToProxyTimeout) {
|
||||||
|
this.proxy = proxy;
|
||||||
|
this.connectToProxyTimeout = connectToProxyTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Socket createSocket() {
|
||||||
|
return new SocksSocket(proxy, connectToProxyTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Socket createSocket(String host, int port) throws IOException {
|
||||||
|
Socket socket = createSocket();
|
||||||
|
socket.connect(InetSocketAddress.createUnresolved(host, port));
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Socket createSocket(InetAddress host, int port) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Socket createSocket(String host, int port, InetAddress localHost,
|
||||||
|
int localPort) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Socket createSocket(InetAddress address, int port,
|
||||||
|
InetAddress localAddress, int localPort) throws IOException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.briarproject.util;
|
package org.briarproject.util;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -22,19 +24,34 @@ public class IoUtils {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
byte[] buf = new byte[4096];
|
byte[] buf = new byte[4096];
|
||||||
try {
|
try {
|
||||||
try {
|
while (true) {
|
||||||
while (true) {
|
int read = in.read(buf);
|
||||||
int read = in.read(buf);
|
if (read == -1) break;
|
||||||
if (read == -1) break;
|
out.write(buf, 0, read);
|
||||||
out.write(buf, 0, read);
|
|
||||||
}
|
|
||||||
out.flush();
|
|
||||||
} finally {
|
|
||||||
in.close();
|
|
||||||
}
|
}
|
||||||
} finally {
|
in.close();
|
||||||
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
tryToClose(in);
|
||||||
|
tryToClose(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void tryToClose(Closeable c) {
|
||||||
|
try {
|
||||||
|
if (c != null) c.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// We did our best
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void read(InputStream in, byte[] b) throws IOException {
|
||||||
|
int offset = 0;
|
||||||
|
while (offset < b.length) {
|
||||||
|
int read = in.read(b, offset, b.length - offset);
|
||||||
|
if (read == -1) throw new EOFException();
|
||||||
|
offset += read;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user