I want to proxy network traffic for an Android emulator.
I can't seem to get it to work.
My emulator is booted up using this:
emulator #Nexus_5X_API_23 -http-proxy 10.0.1.17:8888
The IP and port points to what Charles reports in the Help menu.
The SSL certificate is installed. I can open the emulator browser and Charles shows me all traffic. The browser updates as usual.
All seems good so far.
Now I attempt to run my app. My first network call goes out successfully through Charles. The response returns and Charles displays it. However the response isn't passed to the app successfully.
I've set a breakpoint in the error callback and I can see a com.android.volley.NoConnectionError which is caused by java.io.IOException: unexpected end of stream on Connection.
Why doesn't Charles pass the result back back properly to the app?
Do I need to do what's defined at the end of the configuration page on Charles?
HttpHost httpproxy = new HttpHost("192.168.0.101", 8888, "http");
httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,httpproxy);
This doesn't seem correct - what am I missing?
In order to help solving
java.io.IOException: unexpected end of stream on Connection
issue please answer the questions in the comments.
As regards to
HttpHost httpproxy = new HttpHost("192.168.0.101", 8888, "http");
httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,httpproxy);
it will not help you just like that.
In fact this is another way to apply a proxy which IMO is even better than '-http-proxy' because you can apply it anywhere not only for an emulator and it is only for this app build.
You need to apply the proxy in the Http Stack you use. for example:
public class ProxyHurlStack extends HurlStack {
#Override
protected HttpURLConnection createConnection(URL url) throws IOException {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("10.0.1.17", 8888));
HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
return conn;
}
}
and then for you debug build you can use smth like:
requestQueue = Volley.newRequestQueue(context, new ProxyHurlStack());
The only way to this is that install the SSL (Secure Socket Layer) certificate at server end then no need to set any Charles proxy.
Every enterprise has two development environments,
Development ( http ) : doesn't need any SSL certificate
Production ( https ) : needs SSL certificate
When production environment installs the SSL certificate then android emulator and Volley library automatically detects the network connection and your were able to consume the apis/web services as expected.
No other solution to this problem.
Related
I am developing a Xamarin mobile Android app. For data access, the app uses a Portable class library to make webservice calls to the back end. I’m using the Portable class library so that I can share it with an iOS version of the mobile app later. The data is sensitive and requires SSL for all communications which is configured in the WebAPI web service project. It uses oAuth for authentication.
The challenge I’m running into is that the initial request to authenticate is failing when I run it locally with the following error:
System.Net.Http.HttpRequestException: An error occurred while sending the request
System.Net.WebException: Error: TrustFailure (The authentication or decryption has failed.)
System.IO.IOException: The authentication or decryption has failed.
Some additional information:
I am using the following built in Visual Studio emulator and version - Android_Accelerated_x86 (Android 6.0 – API 23).
I am currently running it on localhost and following is the code snippet for this call:
HttpClient client = new HttpClient(new NativeMessageHandler())
{
BaseAddress = new Uri("https://10.0.2.2:44342/") // I also tried installing it on IIS and using port 443 on localhost. Same problem.
};
var content = new StringContent("grant_type=password&username=[USER_NAME]&password=[PASSWORD]", Encoding.UTF8, "application/json");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsync("Token", content).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
var stuffList = JsonConvert.DeserializeObject<List<Stuff>>(data);
return stuffList;
}
else
{
return new List<Stuff>();
}
The call works when I test it through Fiddler on localhost, so I know that everything is configured correctly on the web service end and with authentication. But from the emulator my understanding is that I need to use IP address 10.0.2.2. I have create a self-signed cert and that hasn’t seemed to help.
I have also attempted to use Fiddler as a middleman, but I’m not seeing any activity in Fiddler when I run the app locally. I have also tried to change the network settings of the emulator, but it doesn’t appear to be having any affect. The base emulator seems to be fairly limited in these settings, but I also don’t want to pay for a more advanced one at this point in time. I have seen a number of posts with similar issues, but none of the existing recommendations that I have found are helping. Any help would be greatly appreciated!
Following my previous question (it's still unanswered if you have an idea...), I tried to set the proxy explicitly in the Java code. When doing this, I finally see in Fiddler the request tunnel (A SSLv3-compatible ClientHello handshake was found...), but still not the request itself. However, instead of response 200 which I receive when not using proxy, the following error is thrown:
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
In short, my primary goal is to automate a login process via emulating web browser behavior (in terms of headers & post parameters). I managed to do it with a native Java application on PC, but the exact same code returns 400 in some request on Android (probably because the HttpUrlConnection class implementation is totally different in Android compared to Oracle SDK's), so I wanna capture the outgoing traffic and find the difference(s). I successfully got the requests sent from my PC and now struggling with Android.
Android device browser requests are captured successfully, the problem occurs only with applications (specifically my app). I installed the Fiddler certificate on device and set the WiFi proxy as required.
I also tried it on two devices, one of them is rooted, to no avail.
Any help will be appreciated!
Some code:
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("192.168.0.120", 8888)); //My PC IP on local LAN
conn = (HttpsURLConnection) url.openConnection(proxy);
conn.setRequestMethod("GET");
conn.setUseCaches(false);
conn.setRequestProperty(...) //Repeating thie line to add headers
int responseCode = conn.getResponseCode(); //Exception is thrown in this line
The chances are Fiddler root certificate didn't get installed correctly. To verify that try capturing in Fiddler HTTPS traffic from the device browser. If it doesn't work out here is plenty of information on troubleshooting custom CA - How to install trusted CA certificate on Android device?
Another approach is setting up your connection to trust Fiddler CA programatically. Create a custom KeyStore containing Fiddler root CA and initialize a TrustManager with that KeyStore. Then use the TrustManager to initialize an SSLContext and use the SSLContext provided SSLSocketFactory with your HttpsURLConnection.
Scenario: I am trying to debug an Android app by proxying requests through Fiddler.
I got FiddlerRoot certificate installed on the Android device, and the SSL decryption works for most requests, but for other requests I can only see the HTTPS Connect, and nothing else in the Fiddler log. I think it might be image requests over SSL that fails to decrypt.
I have double-checked that "Hide images" is off, etc. Images retrieved are hosted on another domain than the main API the app talks to.
What could cause this behaviour ? And how do I get the image requests to show in Fiddler ?
I am using the latest Fiddler4.
There are plenty of tutorials on how you can intercept HTTP(s) traffic from Android using Fiddler.
Try this one: http://docs.telerik.com/fiddler/configure-fiddler/tasks/configureforandroid
However, it will fail when you try to intercept and decrypt Android SSL traffic coming from an application, and not from a browser.
It might be that the application uses a certificate pinning – and you are probably cannot decipher this connection. Lost cause!
But more probably, the reason is a bug in the HttpsUrlConnection pipeline implementation.
To solve the issue, please proceed with the following steps:
In Fiddler click "Rules->Customize Rules";
Find function OnBeforeResponse in the script
Add following code to the function body:
if (oSession.oRequest["User-Agent"].indexOf("Dalvik") > -1 &&
oSession.HTTPMethodIs("CONNECT")) {
oSession.oResponse.headers["Connection"] = "Keep-Alive";
}
Save the file and restart Fiddler.
As per Google recommendation, I am using HttpsURLConnection for my api-level 15 project.
My test case is very simple :
URL url = new URL(STATS);
HttpsURLConnection we = (HttpsURLConnection)url.openConnection();
InputStream in = new BufferedInputStream(we.getInputStream());
When I connect to my server over WiFi, everything works fine.
When I connect to my server over 3g, I am getting an error in my Apache logs :
Hostname 202.139.83.152 provided via SNI and hostname myserver.com provided via HTTP are different
Now the 202.139.83.152 address is the proxy address of my mobile providers APN.
I have dumped out the 'Client Hello' packet of both requests and the Handshake Protocol/Extension:server_name field contains the target hostname (myserver.com) for the wifi request but the APN proxy address for the 3g request.
Is this :
Something I have coded incorrectly
Something I have configured incorrectly on my phone (Samsung Galaxy S3)
Something I have configured incorrectly on my server
Something evil my mobile provider is doing
A bug in the Android libraries
My server is using a dedicated ip address for this vhost.
I can successfully make a request over 3g using a simple subclass of DefaultHttpClient but as my min API level is 15, I was hoping to go down the 'preferred' path.
Any suggestions would be very greatfully received. I've spent way too much time trying to get this basic thing working.
My colleague who is handling the iPhone development for this project shakes his head because his code 'just works out of the box'.
It turns out that this is a known issue.
I have found a workaround although I'm not sure how robust it is. What works for me so far is to disable the Proxy when making the connection :
HttpsURLConnection http = (HttpsURLConnection) url.openConnection(Proxy.NO_PROXY);
I hope this helps someone.
Here is my server side workaround for Apache (working for the last year on Apache2 - Apache/2.2.14).
Recompiled Apache/mod_ssl.so after having changed ssl_engine_kernel.c by removing the "return HTTP_BAD_REQUEST;" for the strcmp(host, servername) check :
if (strcmp(host, servername)) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"Hostname %s provided via SNI and hostname %s provided"
" via HTTP are different", servername, host);
//return HTTP_BAD_REQUEST; // REMOVE THIS LINE
You will still get the error log message but not the error 400 response code.
I have a python REST API server running on my laptop. I am trying to write a rest client in Android (using Eclipse ADT etc) to contact it using Apache's client (org.apache.http.client) libraries.
The code is really simple, and basically does the following -
HttpGet httpget = new HttpGet(new URI("http://10.0.2.2:8000/user?username=tim"));
HttpResponse response = httpclient.execute(httpget);
However at execute, it exceptions out with a time out exception. I cannot hit the URL even from the browser in the emulator.
Details of the exception
org.apache.http.conn.ConnectTimeoutException: Connect to /10.0.2.2:8000 timed out
However, I tried using the cREST client on Chrome on my laptop, and I am able to query the REST server fine.
Is it possible the machine is not on your network? Ie - it is on the other side of a router, on the internet somewhere? Because addresses starting "10." are reserved as private addresses and not routable.
See http://en.wikipedia.org/wiki/Private_network for more info
I had the same issue and here's how I figured out the cause:
Quit you emulator. Start your local server. In the browser, you should be able to access "http://localhost:8000/user?username=tim" and get some response. If you get a timeout, your server is likely not running. In my case, my python server had a break-point set and it was stuck there. Once I let it run, I was able to see responses on the browser and subsequently in the emulator (using 10.0.2.2).