2011年12月16日 星期五

在iPhone上面要怎麼拿到gateway的IP

要從iPhone獲得一些網路相關的連線資訊
最常看到也常用到的就是Apple自家提供的

Reachability :無論是3G,wifi,edge都有辦法很簡單的拿到結果


但是要拿到router的local ip呢?
仔細再想一下,其實就是要拿gateway ip呀!
搜遍了幾個討論串,終於在前輩的指點下總算有大進展XD

以下的程式碼只是小小修改了getgateway.c的原始碼
但足夠讓iPhone拿到gateway的IP囉~


#import <sys sysctl.h="">
#import <netinet in.h="">
#import <arpa inet.h="">
#import "route.h"      /*the very same from google-code*/

#define CTL_NET         4               /* network, see socket.h */

#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))


- (NSString *)getGatewayIPAddress {

 NSString *address = @"error";

    /* net.route.0.inet.flags.gateway */
    int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET,
        NET_RT_FLAGS, RTF_GATEWAY};
    size_t l;
    char * buf, * p;
    struct rt_msghdr * rt;
    struct sockaddr * sa;
    struct sockaddr * sa_tab[RTAX_MAX];
    int i;
    int r = -1;
 
    if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) {
        address = @"192.168.0.1";
  //return -1;
    }
 
    if(l>0) {
        buf = malloc(l);
        if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) {
            address = @"192.168.0.1";
   //return -1;
        }

        for(p=buf; p<buf+l; p+="rt-">rtm_msglen) {
            rt = (struct rt_msghdr *)p;
            sa = (struct sockaddr *)(rt + 1);
            for(i=0; i<rtax_max; i++)="" if(rt-="" {="">rtm_addrs & (1 << i)) {
                    sa_tab[i] = sa;
                    sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
                } else {
                    sa_tab[i] = NULL;
                }
            }
   
            if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY))
               && sa_tab[RTAX_DST]->sa_family == AF_INET
               && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) {
    
                unsigned char octet[4]  = {0,0,0,0};
                int i;
    for (i=0; i<4; i++){
                    octet[i] = ( ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr >> (i*8) ) & 0xFF;
                }
                if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) {
                    //if(octet[0] == 192 && octet[1] == 168){
     in_addr_t addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr;
     r = 0;
     address = [NSString stringWithFormat:@"%s", inet_ntoa(*((struct in_addr*)&addr))];
                    //}
     NSLog(@"\naddress%@",address);
     break;
                }
            }
        }
        free(buf);
    }
    return address;
}

咦~先別急著copy去用阿!
當放到實機去跑的時候會發現....媽呀這什麼鬼IP
一眼就知道是拿到了3G的gateway ip了啦!!

喔~原來當wifi跟3G同時開啟的狀態下,
兩個interface的gateway都會被抓到.
剛好又是for迴圈跑完,自然就吐回了最後一個interface

所以我們試驗了以後,發現無論3G跟wifi的開啟先後順序
並不會影響到interface擷取的順序,因此我們採取了相當大膽的措施!!!
就是搭配Reachability確認在wifi情況下,
拿到第一個interface(即wifi) 時候就break掉.

希望可以幫助有需要的人 :)

2 則留言:

  1. 請問我要怎麼取得route.h檔?

    回覆刪除
    回覆
    1. Hey~ 你可以參考Apple的open source code:

      http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/net/route.h

      刪除

內容回應