iOS: reachabilityWithHostname YES although it should be NO
Asked Answered
B

5

6

I tested different frameworks, e.g.

and I would like to know if a host is reachable. On my iPhone, I set my iMac as proxy (Charles) and block or don't block the connections, but the reachability is always YES. Only if I set a non-existing host, it returns NO. But if the host exists but I block the connection to it, I always get isReachable. Isn't there a way to check if the host is really reachable?

If I try with KSReachability, I'm doing the following:

self.reachability = [KSReachability reachabilityToHost:@"www.stackoverflow.com"];
self.reachability.notificationName = kDefaultNetworkReachabilityChangedNotification;
self.reachability.onReachabilityChanged = ^(KSReachability *reachability) {
    NSLog(@"isReachable: %i", reachability.reachable);
};

I always get isReachable: 1 there with the following configuration:

  • connected to Wifi
  • configured my iMac as HTTP-Proxy
  • blocking www.stackoverflow.com in my Charles Proxy

When I try to reach www.stackoverflow.com in Safari, the page can't be opened (as expected). I would expect the reachability to be false (isReachable: 0) in this case.

EDIT So the most important question for me is - how to achieve the behavior I'm expecting? I.e. that the app continuously checks if the given host is really reachable?

Begot answered 17/6, 2014 at 9:57 Comment(8)
Can you tell the proxy URL ? if it is something like www.example.com/something/some then it won't work. Only host name like www.example.com will workWomanizer
it's a subdomain: testing.example.comBegot
Did you try to open that hosts in a mobile Safari while connected via a proxy? May be it's actually really reachable for some reason?Arran
Yet the DNS server to resolve the network address is available so network is still reachable. Try to blacklist all ip addresses in CharlesDiaphaneity
The recommended way to handle what you are describing is to attempt to connect to it normally and handle any error returned appropriately.Lunsford
When you say you're blocking the connections or blocking stackoverflow.com you are blocking the http protocol port 80, right? Blocking a connection or url/domain won't block the host, the host is still reachable; that's way you always get isReachable: 1. Probably, blocking the host ip address in your proxy can give you the results you expect.Verda
It has to do with the networking layers; http is an application layer protocol and your HTTP proxy can block that for sure; if you want to block the host you have to do it at a lower level layer or as suggested block the host ip address entirely.Verda
@Begot I am stuck in exactly the same situation with my app. The user is connected to a wifi but doesn't have internet access (say he needs some additional sign in to wifi before accessing the web). I have tried many reachability frameworks including apple's but all of them return YES for above scenario. Did you find a solution for this ? Or a workaround.Receptor
B
8

The code statement:

self.reachability = [KSReachability reachabilityToHost:@"www.stackoverflow.com"];

actually calls below method:

SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL,
                                                          [hostName UTF8String]);

SCNetworkReachability reference says:

The SCNetworkReachability programming interface allows an application to determine the status of a system's current network configuration and the reachability of a target host. A remote host is considered reachable when a data packet, sent by an application into the network stack, can leave the local device. Reachability does not guarantee that the data packet will actually be received by the host.

The explanation clears that iOS system doesn't send any request to outside world to check the reachability. It just tells that data packet can leave the device or not. If system were to send the request it automatically means that it is connected to network.

You can verify this by mentioning a valid host like "www.stackoverflow.com" and check in charles (first unblock it) that no request is sent.You can also check with other valid host names like "www.abcdefgh.com" (verify this by running it in Safari and see in charles) it also gives you the reachability but charles shows no request.Also if you put http:// before any valid host, something like "http://www.stackoverflow.com" it will also fails reachability. So it is clear that it is not an outgoing http request. If system has to send a request outside then what's the point of providing the class? A developer could have created a network connection and try to connect to a host and see if it passes or fails.

However it is interesting that if an invalid host like "www.hjjkhkhk.com" is provided iOS system gives reachability as false. Now the question is how iOS system finds a valid or invalid host without sending any query to outside world? May be it is periodically caching a list of DNS ranges??? Highly improbable to me.

Brutality answered 24/6, 2014 at 11:38 Comment(0)
M
4

In your AppDelegate add this method:

#import "Reachability.h"

-(NSString *)checkNetworkConnectivity
{
    NSString *networkValue;

    Reachability *rc = [Reachability reachabilityWithHostName:@"www.stackoverflow.com"];
    NetworkStatus internetStatus = [rc currentReachabilityStatus];

    if(internetStatus==0)
    {
        networkValue = @"NoAccess";
    }
    else if(internetStatus==1)
    {
        networkValue = @"ReachableViaWiFi";

    } else if(internetStatus==2)
    {
        networkValue = @"ReachableViaWWAN";
    }
    else
    {
        networkValue = @"Reachable";
    }

    return networkValue;
}

Checking if the host is reachable

NSString *netStr = [appDelegate checkNetworkConnectivity];

if([netStr isEqualToString:@"NoAccess"])
{
     [appDelegate callNoNetworkAlert];
}
Maladjusted answered 27/6, 2014 at 10:38 Comment(1)
It is returning internetStatus==1 when my Wifi is not connected to internetBarde
D
3

Firstly, unless we see some code, we cannot make sure what you're doing, you're doing the right way. However I will assume you are doing it correctly.

Secondly, you should test what FreeNickname has suggested in his comment. Maybe it's not actually unreachable, and the reachability is acting correctly, when you expect a different response.

Last, but very important, from the Reachability docs :

Note: Reachability cannot tell your application if you can connect to a particular host, only that an interface is available that might allow a connection, and whether that interface is the WWAN.

What it means is that, even though your server might not be returning any responses, Reachability does NOT check that. It only checks if your server is available , such that a packet can be sent. What it does with that packet is of no concern to Reachability. If Reachability is able to transmit the entire packet, it assumes your host is reachable. It will return unreachable iff your server is down, disconnected, or does not exist.

Drew answered 23/6, 2014 at 5:45 Comment(0)
G
2

I would like to add that To listen the Network changes at Runtime, you need to listen to the Notifications that tell you that a Network state has been changed.

This is how you can do this :

  1. Implement a listener in AppDelegate file.

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];

  • Now reachabilityChanged will be called when there is a change in Network status (perhaps connectivity of internet connection or it's disconnection). You can do appropriate handling in reachabilityChanged event

like:

- (void) reachabilityChanged:(NSNotification *)note
{
     Reachability* reachability = [note object];

     if (reachability == self.hostReachability)
     {
        isHostReachable = YES;  //A flag to keep track of connectivity
     }

     if (reachability == self.internetReachability)
     {
         isInternetAvailable = YES;  
     }

     if (reachability == self.wifiReachability)
     {
         isWifiAvailable = YES;  
     }

     //If all are true that means we have host and Internet available
     if (isHostReachable && isInternetAvailable && isWifiAvailable) 
     {
          isInternetAvailable = true;
     }
}

Hope this will help you.

Granese answered 27/6, 2014 at 14:49 Comment(0)
B
1

AFNetworking

A delightful iOS and OS X networking framework http://afnetworking.com


Network Reachability Manager

AFNetworkReachabilityManager monitors the reachability of domains, and addresses for both WWAN and WiFi network interfaces.

Shared Network Reachability

[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status)
 {
     NSLog(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status));
 }];

HTTP Manager Reachability

NSURL *baseURL = [NSURL URLWithString:@"http://example.com/"];
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL];

NSOperationQueue *operationQueue = manager.operationQueue;
[manager.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status)
 {
     switch (status)
     {
         case AFNetworkReachabilityStatusReachableViaWWAN:
         case AFNetworkReachabilityStatusReachableViaWiFi:
             [operationQueue setSuspended:NO];
             break;
         case AFNetworkReachabilityStatusNotReachable:
         default:
             [operationQueue setSuspended:YES];
             break;
     }
 }];
Baptlsta answered 23/6, 2014 at 4:45 Comment(2)
what if stack overflow goes offline for maintenance ? many time on week end I observed this :)Susurrus
but this doesn't work "automatically", i.e. it's not called if the reachability changes during the app runsBegot

© 2022 - 2024 — McMap. All rights reserved.