usuario una totalplay saltar página pide pero para etecsa contraseña conectarse como cautivo arnet abre abierta android http authentication redirect connectivity

android - una - saltar portal cautivo arnet



¿Cómo verificar el acceso a Internet sin restricciones?(detección de portal cautivo) (5)

Como referencia, aquí está el método ''oficial'' de la base de código AOSP de Android 4.0.1: WifiWatchdogStateMachine.isWalledGardenConnection() . Incluyo el código a continuación solo en caso de que el enlace se rompa en el futuro.

private static final String mWalledGardenUrl = "http://clients3.google.com/generate_204"; private static final int WALLED_GARDEN_SOCKET_TIMEOUT_MS = 10000; private boolean isWalledGardenConnection() { HttpURLConnection urlConnection = null; try { URL url = new URL(mWalledGardenUrl); // "http://clients3.google.com/generate_204" urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setInstanceFollowRedirects(false); urlConnection.setConnectTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(WALLED_GARDEN_SOCKET_TIMEOUT_MS); urlConnection.setUseCaches(false); urlConnection.getInputStream(); // We got a valid response, but not from the real google return urlConnection.getResponseCode() != 204; } catch (IOException e) { if (DBG) { log("Walled garden check - probably not a portal: exception " + e); } return false; } finally { if (urlConnection != null) { urlConnection.disconnect(); } } }

Este enfoque se basa en una URL específica, mWalledGardenUrl = "http://clients3.google.com/generate_204" siempre devuelve un código de respuesta 204 . Esto funcionará incluso si se ha interferido con el DNS, ya que en ese caso se devolverá un código 200 lugar del 204 esperado. He visto algunas portales cautivas suplantando solicitudes a esta URL específica para evitar el mensaje de Internet no accesible en dispositivos Android.

Google tiene una variación de este tema: buscar http://www.google.com/blank.html devolverá un código 200 con un cuerpo de respuesta de longitud cero. Entonces, si obtienes un cuerpo no vacío, esta sería otra forma de descubrir que estás detrás de un jardín amurallado.

Apple tiene sus propias URL para detectar portales cautivos: cuando la red está activa, los dispositivos IOS y MacOS se conectarían a una URL como http://www.apple.com/library/test/success.html , http://attwifi.apple.com/library/test/success.html , o http://captive.apple.com/hotspot-detect.html que debe devolver un código de estado HTTP de 200 y un cuerpo que contenga Success .

NOTA : Este enfoque no funcionará en áreas con acceso restringido a Internet, como China, donde todo el país es un jardín amurallado , y donde la mayoría de los servicios de Google / Apple están bloqueados o filtrados. Algunos de estos pueden no estar bloqueados: http://www.google.cn/generate_204 , http://g.cn/generate_204 , http://gstatic.com/generate_204 o http://connectivitycheck.gstatic.com/generate_204 - sin embargo, todos estos pertenecen a Google, por lo que no está garantizado que funcione.

Necesito detectar de manera confiable si un dispositivo tiene acceso completo a Internet, es decir, que el usuario no está confinado a un portal cautivo (también llamado jardín amurallado ), es decir, una subred limitada que obliga a los usuarios a enviar sus credenciales en un formulario para obtener acceso.

Mi aplicación está automatizando el proceso de autenticación y, por lo tanto, es importante saber que el acceso completo a Internet no está disponible antes de iniciar la actividad de inicio de sesión.

La pregunta no es sobre cómo verificar que la interfaz de red esté activada y en un estado conectado. Se trata de asegurarse de que el dispositivo tenga acceso a Internet sin restricciones en lugar de un segmento de intranet de espacio aislado.

Todos los enfoques que he intentado hasta ahora están fallando, porque la conexión a cualquier host conocido no generaría una excepción sino que devolvería un código de respuesta HTTP 200 válido porque todas las solicitudes se enrutan a la página de inicio de sesión.

Estos son todos los enfoques que probé, pero todos devuelven true lugar de false por las razones explicadas anteriormente:

1:

InetAddress.getByName(host).isReachable(TIMEOUT_IN_MILLISECONDS); isConnected = true; <exception not thrown>

2:

Socket socket = new Socket(); SocketAddress sockaddr = new InetSocketAddress(InetAddress.getByName(host), 80); socket.connect(sockaddr, pingTimeout); isConnected = socket.isConnected();

3:

URL url = new URL(hostUrl)); URLConnection urlConn = url.openConnection(); HttpURLConnection httpConn = (HttpURLConnection) urlConn; httpConn.setAllowUserInteraction(false); httpConn.setRequestMethod("GET"); httpConn.connect(); responseCode = httpConn.getResponseCode(); isConnected = responseCode == HttpURLConnection.HTTP_OK;

Entonces, ¿cómo me aseguro de conectarme con un host real en lugar de la página de redirección de inicio de sesión? Obviamente, podría verificar el cuerpo de respuesta real desde el host ''ping'' que uso, pero no parece una solución adecuada.


Creo que la prevención del redireccionamiento de tu conexión funcionará.

URL url = new URL(hostUrl)); HttpURLConnection httpConn = (HttpURLConnection)url.openConnection(); /* This line prevents redirects */ httpConn.setInstanceFollowRedirects( false ); httpConn.setAllowUserInteraction( false ); httpConn.setRequestMethod( "GET" ); httpConn.connect(); responseCode = httpConn.getResponseCode(); isConnected = responseCode == HttpURLConnection.HTTP_OK;

Si eso no funciona, entonces creo que la única forma de hacerlo es verificar el cuerpo de la respuesta.


Esto se ha implementado en la versión Android 4.2.2+. Creo que su enfoque es rápido e interesante:

CaptivePortalTracker.java detecta el jardín amurallado de la siguiente manera: intente conectarse a www.google.com/generate_204: compruebe que la respuesta HTTP es 204

Si el cheque falla, estamos en un jardín amurallado.

private boolean isCaptivePortal(InetAddress server) { HttpURLConnection urlConnection = null; if (!mIsCaptivePortalCheckEnabled) return false; mUrl = "http://" + server.getHostAddress() + "/generate_204"; if (DBG) log("Checking " + mUrl); try { URL url = new URL(mUrl); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setInstanceFollowRedirects(false); urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); urlConnection.setUseCaches(false); urlConnection.getInputStream(); // we got a valid response, but not from the real google return urlConnection.getResponseCode() != 204; } catch (IOException e) { if (DBG) log("Probably not a portal: exception " + e); return false; } finally { if (urlConnection != null) { urlConnection.disconnect(); } } }


Otra posible solución podría ser conectarse a través de HTTPS e inspeccionar el certificado de destino. No estoy seguro si los jardines amurallados sirven la página de inicio de sesión a través de HTTPS o simplemente eliminan las conexiones. En cualquier caso, debería poder ver que su destino no es el que esperaba.

Por supuesto, también tiene la sobrecarga de TLS y verificaciones de certificados. Tal es el precio de las conexiones autenticadas, desafortunadamente.


Si ya está utilizando la retrofit , puede hacerlo mediante la retrofit . solo haga una página ping.html y envíe una solicitud de encabezado utilizando la modificación y asegúrese de que su cliente http esté configurado de la siguiente manera: (la parte más importante es la parte followRedirects(false) )

private OkHttpClient getCheckInternetOkHttpClient() { return new OkHttpClient.Builder() .readTimeout(2L, TimeUnit.SECONDS) .connectTimeout(2L, TimeUnit.SECONDS) .followRedirects(false) .build(); }

luego construye tu actualización como a continuación:

private InternetCheckApi getCheckInternetRetrofitApi() { return (new Retrofit.Builder()) .baseUrl("[base url of your ping.html page]") .addConverterFactory(GsonConverterFactory.create(new Gson())) .client(getCheckInternetOkHttpClient()) .build().create(InternetCheckApi.class); }

su InternetCheckApi.class sería como:

public interface InternetCheckApi { @Headers({"Content-Typel: application/json"}) @HEAD("ping.html") Call<Void> checkInternetConnectivity(); }

entonces puedes usarlo como a continuación:

getCheckInternetOkHttpClient().checkInternetConnectivity().enqueue(new Callback<Void>() { public void onResponse(Call<Void> call, Response<Void> response) { if(response.code() == 200) { //internet is available } else { //internet is not available } } public void onFailure(Call<Void> call, Throwable t) { //internet is not available } } );

tenga en cuenta que su cliente http de verificación de Internet debe estar separado de su cliente http principal.