New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SOCKS proxy not working on Android platform #2315

Closed
mariotaku opened this Issue Feb 4, 2016 · 3 comments

Comments

2 participants
@mariotaku

mariotaku commented Feb 4, 2016

SOCKS proxy is completely broken on Android. When I set up SOCKS proxy in my app, all requests failed, when I wrote an instrumentation test, I found even create a default okhttp instance with a SOCKS proxy, it fails.

Here's the stack trace:

java.net.UnknownHostException: Host is unresolved: www.google.com
at java.net.Socket.connect(Socket.java:867)
at okhttp3.internal.Platform$Android.connectSocket(Platform.java:200)
at okhttp3.internal.io.RealConnection.connectSocket(RealConnection.java:137)
at okhttp3.internal.io.RealConnection.connect(RealConnection.java:108)
at okhttp3.internal.http.StreamAllocation.findConnection(StreamAllocation.java:188)
at okhttp3.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:127)
at okhttp3.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at okhttp3.internal.http.HttpEngine.connect(HttpEngine.java:289)
at okhttp3.internal.http.HttpEngine.sendRequest(HttpEngine.java:241)
at okhttp3.RealCall.getResponse(RealCall.java:240)
at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:198)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:160)
at okhttp3.RealCall.execute(RealCall.java:57)
at org.mariotaku.twidere.test.okhttp3.OkHttpClientTest.testSocksFunctionality(OkHttpClientTest.java:27)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:240)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1879)

Sample code:

import org.junit.Test;

import java.net.InetSocketAddress;
import java.net.Proxy;

import okhttp3.OkHttpClient;
import okhttp3.Request;

import static org.junit.Assert.assertTrue;

/**
 * Created by mariotaku on 16/2/5.
 */
public class OkHttpClientTest {

    @Test
    public void testSocksFunctionality() throws Exception {
        final Proxy proxy = new Proxy(Proxy.Type.SOCKS, InetSocketAddress.createUnresolved("127.0.0.1", 1080));
        final OkHttpClient client = new OkHttpClient.Builder()
                .proxy(proxy)
                .build();
        final Request request = new Request.Builder()
                .url("https://www.google.com/")
                .build();
        assertTrue(client.newCall(request).execute().isSuccessful());
    }

}
@mariotaku

This comment has been minimized.

mariotaku commented Feb 4, 2016

Seems it's a bug inside Android Socket implementation.

SOCKS working fine on Oracle JRE and OpenJDK JRE, and I looked into their code:
Socket.connect(SocketAddress endpoint, int timeout)

            if (epoint.isUnresolved())
                impl.connect(addr.getHostName(), port);
            else
                impl.connect(addr, port);

That's what I found in Android framework:

        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
        InetAddress addr;
        if ((addr = inetAddr.getAddress()) == null) {
            throw new UnknownHostException("Host is unresolved: " + inetAddr.getHostName());
        }
        int port = inetAddr.getPort();

        checkDestination(addr, port);
        synchronized (connectLock) {
            try {
                if (!isBound()) {
                    // socket already created at this point by earlier call or
                    // checkOpenAndCreate this caused us to lose socket
                    // options on create
                    // impl.create(true);
                    if (!usingSocks()) {
                        impl.bind(Inet6Address.ANY, 0);
                    }
                    isBound = true;
                }
                impl.connect(remoteAddr, timeout);
                isConnected = true;
                cacheLocalAddress();
            } catch (IOException e) {
                impl.close();
                throw e;
            }
        }

Android only accept resolved InetSocketAddress.

@swankjesse swankjesse added the bug label Feb 5, 2016

mariotaku added a commit to TwidereProject/Twidere-Android that referenced this issue Feb 5, 2016

vanita5 added a commit to vanita5/twittnuker that referenced this issue Feb 6, 2016

@swankjesse

This comment has been minimized.

Member

swankjesse commented Feb 21, 2016

Could you report this issue upstream to AOSP? I’m not particularly eager to implement a SOCKS proxy inside of OkHttp. You might need to implement your own SocketFactory that implements SOCKS.

@swankjesse

This comment has been minimized.

Member

swankjesse commented Feb 21, 2016

No action for us to take on this.

@swankjesse swankjesse closed this Feb 21, 2016

@mfietz mfietz referenced this issue Mar 4, 2016

Merged

Proxy support #1732

FHandrick pushed a commit to project-draco-hr/Twidere-Android that referenced this issue Oct 4, 2016

bemasc added a commit to bemasc/okhttp that referenced this issue Dec 3, 2018

Support SOCKS proxies on older Android versions
This is currently nonfunctional due to an interaction
between InetAddress.createUnresolved and the SOCKS 4 protocol.

Fixes square#2315

bemasc added a commit to bemasc/okhttp that referenced this issue Dec 3, 2018

Support SOCKS proxies on older Android versions
This is currently nonfunctional due to an interaction
between InetAddress.createUnresolved and the SOCKS 4 protocol.

Fixes square#2315

bemasc added a commit to bemasc/okhttp that referenced this issue Dec 4, 2018

Support custom DNS and SOCKS at the same time
Currently, setting a SOCKS proxy in OkHttpClient.Builder
silently overrides any custom DNS setting.  This changes
behavior for users who are currently using both settings
in a single Builder, but any such usage is likely already
buggy because the custom DNS setting is being ignored.

This also fixes square#2315 (SOCKS 4 support) if users "opt in"
by adding a custom DNS setting in their Builder.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment