分类 Openwrt 下的文章

OpenWRT的BusyBox中小数除法并向上取整

##OpenWRT中BusyBox环境做浮点数除法并向上取整.

项目中出了点小问题,原因基本由2个方面引起:

  • 路由器中的DHCP服务器的dhcp leasetime默认12小时,而路由器地址池有限,对公共场合的路由器来说,12小时内也许很容易达到地址池用完的情况.
  • 对于免费WiFi的路由器来说,其客户端具有很强大的流动性和即时性,就是说,设备连接上后几分钟就走了.再也不回来了的.哪怕他没有达到认证时间到期. 而就算认证时间到期了.该设备离开了.而其分配的IP地址因为默认的dhcp leasetime很长而占有资源,导致新设备无法加入网络的可能.

解决办法:

  • 我们不能认为的把leasetime设置的过短,短于认证的时间,不然就会在认证时间段内,因为leasetime到期设备自动续租,自动续租到的IP地址不再相同,导致认证的IP-MAC映射关系出错而把已经认证过的设备当作新设备再次弹出Captive Portal认证.这是用户体验很差的.
  • 所以我们最好的办法就是把路由器的DHCP服务器的leasetime设置为认证时间相同的一个数值.

由于项目中认证时间用的时间单位是秒数,这个时间值是写在配置文件中的. 为了不去修改C代码,通过shell脚本去实现,就需要做OpenWrt的BusyBox环境下进行秒数转分钟数,并且应该向上取整.
一开始就想到shell里的bc命令,但是动手才发现环境有局限.折腾了一会才想到用如下的方法来做BusyBox环境下来实现这一简单需求:

auth_seconds=61.5  #比如这个是配置文件中的秒数:61.5秒

auth_minutes=`echo|awk '{printf "%.fm", ('$auth_seconds'/60)+0.5}'`;
uci set dhcp.lan.leasetime=$auth_minutes;
uci commit;
/etc/init.d/dnsmasq restart;

Shell真的是个万能胶,长期不用会生锈,要时不时磨磨刀.

Libevent2域名随机大小写DNS解析失败的解决

被evdns和国内电信厂商不遵守RFC1034中3.5节规矩的DNS服务器坑了一晚上.

一个OpenWrt MT7620路由器项目中用了libevent2的DNS异步解析,最近出现了点小BUG,经过一段时间的调试和分析,终于把问题给Kill掉了.特在此稍作总结:

在调试分析得知原因后,竟然我的问题和一个网友之前遇到的问题如出一辙,下面是转载直网友的博文 (via https://www.sunchangming.com/blog/post/4601.html) 结合我调试的实际情况稍作改动的记录:

libevent内置的异步DNS解析器采用了一种叫做DNS-0x20 bit encoding的hacking手段来防止DNS投毒攻击。但是这种做法是有问题的,在某些特殊环境(比如国内网络)下会导致DNS解析全部失败。

DNS协议对域名大小写的规定:
数据库中,域名应该是不分大小写的。

DNS协议的RFC标准是http://tools.ietf.org/html/rfc1034。在它的3.5节中特别有一段话:

“Note that while upper and lower case letters are allowed in domain names, no significance is attached to the case. That is, two names with the same spelling but different case are to be treated as if identical.”

DNS答复中,应保持域名大小写不变。DNS消息有三种类型 请求、答复、更新。请求包中域名是怎样的大小写,答复包中也应该保持一致。例如,我要查www.baidU.com,那收到的答复消息中域名也应该是www.baidU.com,而不是www.baidu.com或www.Baidu.com。而且在数据库中,www.baidU.com、www.baidu.com和www.Baidu.com应该是同一条记录。

实际上,目前有很多很多的DNS Server并不遵守这一标准。

下面是我做的实验。我在我的MacBook上用nslookup www.Baidu.com 202.106.0.20向联通的DNS(202.106.0.20)发起了请求对www.Baidu.com的查询请求,并用wireshark抓取来往的包。

请求:

0000 00 02 01 00 00 01 00 00 00 00 00 00 03 77 77 77 .............www

0010 05 42 61 69 64 75 03 63 6f 6d 00 00 01 00 01 .Baidu.com.....

答复:

0000 00 02 80 00 00 01 00 01 00 00 00 00 03 77 77 77 .............www

0010 05 62 61 69 64 75 03 63 6f 6d 00 00 01 00 01 c0 .baidu.com......

0020 0c 00 01 00 01 00 00 01 f4 00 04 77 4b d9 38 ...........wK.8

可以很明显的看出答复的包中,域名被全小写了。据我猜测,不是联通DNS Server的问题,而是中途被我的ISP搞了鬼。

什么是DNS-0x20 encoding?
它是一种未被标准化的防伪机制。DNS尽管本来就有TransactionID,但是很容易被伪造。于是就有人想,如果我们把请求包中的域名进行随机大小写,并且DNS server确实遵守rfc 1034规范,按照原样返回,那么这样就增加了中途投毒的难度。因为中途如果有人想要篡改,就得维持一个session来记录当初发过去的包是大写还是小写。ascii表中,大写字母从0x41开始,小写字母从0x61开始,恰好相差0x20。即 'A' | 0x20 = 'a'; 所以这种随机大小写的方式被称为0x20 encoding。但是我觉得,到底是你太笨还是你把别人想的太笨了?

实际上,google在构建它的public dns server(8.8.8.8)时确实也采用了这种方式。但是它深知现实与理想是不一致的,所以采用了一套白名单机制。只有位于白名单中的DNS server,才用0x20 encoding。google说这样的请求占了它70%以上的流量(“The whitelisted nameservers comprise more than 70% of our traffic.” from https://developers.google.com/speed/public-dns/docs/security)

Libevent如何实现DNS-0x20 encoding
Libevent是一套非常流行的网络库,比如Chrome、memcached就是依靠它实现非阻塞IO。在编写非阻塞IO程序时,很重要的一点是连域名解析也必须是异步的,也就是说glibc里面的那些域名解析函数都不能用。为此,libevent内置了一套异步DNS解析器,叫evdns。但是evdns的实现就要简单粗暴的很多。它默认对所有请求都采用了0x20 encoding。

evdns_base结构体内部有一个字段:


/* true iff we will use the 0x20 hack to prevent poisoning attacks. */

int global_randomize_case;

这个字段在evdns_base_new这个函数中被初始化为1,所以这个功能默认是打开的。

global_randomize_case这个开关会影响如何构造DNS request。

在evdns.c的request_new这个函数中,

if (base->global_randomize_case) {
  unsigned i;
  char randbits[(sizeof(namebuf)+7)/8];
  strlcpy(namebuf, name, sizeof(namebuf));
  evutil_secure_rng_get_bytes(randbits, (name_len+7)/8);
  for (i = 0; i < name_len; ++i) {
    if (EVUTIL_ISALPHA(namebuf[i])) {
      if ((randbits[i >> 3] & (1<<(i & 7))))
        namebuf[i] |= 0x20;
      else
        namebuf[i] &= ~0x20;
    }
  }
  name = namebuf;
}

它发现如果这个开关是打开的,就会随机的改变域名的大小写。

当从DNS Server收到reply之后,client会调用reply_parse函数来解析。下面是函数栈。

 reply_parse(evdns_base * base, unsigned char * packet, int length)

 nameserver_read(nameserver * ns)

 nameserver_ready_callback(int fd, short events, void * arg)

 event_persist_closure(event_base * base, event * ev)

 event_process_active_single_queue(event_base * base, event_list * activeq) 

 event_process_active(event_base * base)

 event_base_loop(event_base * base, int flags)

 event_base_dispatch(event_base * event_base)

int reply_parse(struct evdns_base *base, u8 *packet, int length)这个函数中,它要在请求包和答复包中按照DNS lable做查找匹配。

下面的tmp_name来自reply,cmp_name来自request。

int name_matches=0;
//...
if (base->global_randomize_case) {
if (strcmp(tmp_name, cmp_name) == 0)
  name_matches = 1;
}else {
  if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0) 
    name_matches = 1;
}

如果全找完后name_matches是0。那么就是DNS解析失败了。

在libevent的samples目录下有一个小程序,你可以试下

# ./dns-example -v www.baidu.com

INFO: Parsing resolv.conf file /etc/resolv.conf

INFO: Added nameserver 219.239.26.42:53 as 0xbf86d0

INFO: Added nameserver 202.106.0.20:53 as 0xbf88a0

EVUTIL_AI_CANONNAME in example = 2

resolving (fwd) www.baidu.com...

INFO: Resolve requested for www.baidu.com

INFO: Setting timeout for request 0xbf8a70, sent to nameserver 0xbf86d0

INFO: Removing timeout for request 0xbf8a70

www.baidu.com: No answer (66)

不应该是No answser啊!

如果你好奇,既然chrome用的也是libevent,那么为何没这个问题呢?答案是:chrome没用libevent内置的DNS解析器,它只用了基础IO部分。

原博主的解决方法是修改libevent2的源码,关闭那个开关.然后像官方项目发Pull Request,但是可惜的是没有被合并,作者比较有原则.

其实项目作者提供给了我们灵活设置这些选项的接口API的,该API就是:

/* exported function */
int
evdns_base_set_option(struct evdns_base *base,
    const char *option, const char *val)
{
    int res;
    EVDNS_LOCK(base);
    res = evdns_base_set_option_impl(base, option, val, DNS_OPTIONS_ALL);
    EVDNS_UNLOCK(base);
    return res;
}

此方法在include/event2/dns.h中有导出:

/**
  Set the value of a configuration option.
  The currently available configuration options are:
    ndots, timeout, max-timeouts, max-inflight, attempts, randomize-case,
    bind-to, initial-probe-timeout, getaddrinfo-allow-skew.
  In versions before Libevent 2.0.3-alpha, the option name needed to end with
  a colon.
  @param base the evdns_base to which to apply this operation
  @param option the name of the configuration option to be modified
  @param val the value to be set
  @return 0 if successful, or -1 if an error occurred
 */
EVENT2_EXPORT_SYMBOL
int evdns_base_set_option(struct evdns_base *base, const char *option, const char *val);

所以,从该接口中就可以得知,一共有好几个选项是可以设置的.

我们回去看看上面方法内的实现函数evdns_base_set_option_impl的具体实现:


static int
evdns_base_set_option_impl(struct evdns_base *base,
    const char *option, const char *val, int flags)
{
    ASSERT_LOCKED(base);
    if (str_matches_option(option, "ndots:")) {
        const int ndots = strtoint(val);
        if (ndots == -1) return -1;
        if (!(flags & DNS_OPTION_SEARCH)) return 0;
        log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
        if (!base->global_search_state) base->global_search_state = search_state_new();
        if (!base->global_search_state) return -1;
        base->global_search_state->ndots = ndots;
    } else if (str_matches_option(option, "timeout:")) {
        struct timeval tv;
        if (strtotimeval(val, &tv) == -1) return -1;
        if (!(flags & DNS_OPTION_MISC)) return 0;
        log(EVDNS_LOG_DEBUG, "Setting timeout to %s", val);
        memcpy(&base->global_timeout, &tv, sizeof(struct timeval));
    } else if (str_matches_option(option, "getaddrinfo-allow-skew:")) {
        struct timeval tv;
        if (strtotimeval(val, &tv) == -1) return -1;
        if (!(flags & DNS_OPTION_MISC)) return 0;
        log(EVDNS_LOG_DEBUG, "Setting getaddrinfo-allow-skew to %s",
            val);
        memcpy(&base->global_getaddrinfo_allow_skew, &tv,
            sizeof(struct timeval));
    } else if (str_matches_option(option, "max-timeouts:")) {
        const int maxtimeout = strtoint_clipped(val, 1, 255);
        if (maxtimeout == -1) return -1;
        if (!(flags & DNS_OPTION_MISC)) return 0;
        log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
            maxtimeout);
        base->global_max_nameserver_timeout = maxtimeout;
    } else if (str_matches_option(option, "max-inflight:")) {
        const int maxinflight = strtoint_clipped(val, 1, 65000);
        if (maxinflight == -1) return -1;
        if (!(flags & DNS_OPTION_MISC)) return 0;
        log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
            maxinflight);
        evdns_base_set_max_requests_inflight(base, maxinflight);
    } else if (str_matches_option(option, "attempts:")) {
        int retries = strtoint(val);
        if (retries == -1) return -1;
        if (retries > 255) retries = 255;
        if (!(flags & DNS_OPTION_MISC)) return 0;
        log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
        base->global_max_retransmits = retries;
    } else if (str_matches_option(option, "randomize-case:")) {
        int randcase = strtoint(val);
        if (!(flags & DNS_OPTION_MISC)) return 0;
        base->global_randomize_case = randcase;
    } else if (str_matches_option(option, "bind-to:")) {
        /* XXX This only applies to successive nameservers, not
         * to already-configured ones.  We might want to fix that. */
        int len = sizeof(base->global_outgoing_address);
        if (!(flags & DNS_OPTION_NAMESERVERS)) return 0;
        if (evutil_parse_sockaddr_port(val,
            (struct sockaddr*)&base->global_outgoing_address, &len))
            return -1;
        base->global_outgoing_addrlen = len;
    } else if (str_matches_option(option, "initial-probe-timeout:")) {
        struct timeval tv;
        if (strtotimeval(val, &tv) == -1) return -1;
        if (tv.tv_sec > 3600)
            tv.tv_sec = 3600;
        if (!(flags & DNS_OPTION_MISC)) return 0;
        log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s",
            val);
        memcpy(&base->global_nameserver_probe_initial_timeout, &tv,
            sizeof(tv));
    }
    return 0;
}

浏览过此段代码之后,我想心中肯定一目了然了.
那么问题的解决方法也就清楚了,只需要在evdns_base_new后加一行设置该选项为关闭就搞定. 如下:

    evdns_base_set_option(dnsbase, "randomize-case:", "0");//TurnOff DNS-0x20 encoding
    evdns_base_nameserver_ip_add(dnsbase, "180.76.76.76");//BaiduDNS
    evdns_base_nameserver_ip_add(dnsbase, "223.5.5.5");//AliDNS
    evdns_base_nameserver_ip_add(dnsbase, "223.6.6.6");//AliDNS
    evdns_base_nameserver_ip_add(dnsbase, "114.114.114.114");//114DNS
    evdns_base_nameserver_ip_add(dnsbase, "8.8.8.8");//GoogleDNS

写在最后:
开源项目就是这点方便,可以阅读其源码,有问题可以立马自己分析解决.
可惜的是开源氛围在长沙还是千里戈壁的景象.看来长沙的未来靠我戴维营哈!

【MTK】iwpriv命令使用说明

#iwpriv 命令

####1. CountryRegion 2.4GHz的国家地区码,不同的地区码信道选择范围不一样,范围是0--7,31--33
iwpriv ra0 set CountryRegion=5

####2. CountryRegionABand 5G的国家地区码

####3.CountryCode 无线国家码

####4.国家码简写标准:https://www.iso.org/obp/ui/#search
iwpriv ra0 set CountryCode=cn

####5.ChannelGeography:信道地理类型
0:Outdoor 1:Indoor 2:Both

####6.SSID 无线SSID,1~32 ASCII码
iwpriv ra0 set SSID="AAA"

####7.WirelessMode 无线模式
1.legacy 11B only;2.legacy 11A only;3.legacy 11a/b/g mixed;4.legacy 11G only;5.11ABGN mixed
6.11N only in 2.4G; 7.11GN mixed;8.11AN mixed; 9.11BGN mixed; 10.11AGN mixed;11.11N only in 5G;
14.11A/AN/AC mixed 5G band only;15. 11AN/AC mixed 5G band only.

####8.Channel 无线channel
Channel=0; 0表示自动扫描;

####9.BasicRate 无线支持的基本速率集
1.1Mbps;2.2Mbps;3.1Mbps,2Mbps;4.5.5Mbps;15.1Mbps,2Mbps,5.5Mbps,11Mbps;

####10.Beacon Period Beacon帧的周期
iwpriv ra0 set BeaconPeriod=100

####11.DtimPeriod duratin time 1~255
iwpriv ra0 set DtimPeriod=64

####12.TxPower 传输功率,0~100
iwpriv ra0 set TxPower=99

####13.DisableOLBC

####14.BGProtection 启用/禁用 无线11B or 11G保护
0:auto;1:on;2:off

####15.MaxStaNum 最大sta连接数量
0:disable 1~32

####16.TxAntenna 配置Tx天线数量
iwpriv ra0 set TxAntenna=1

####17.RxAntenna 配置Rx天线数量

####18.TxPreamble 启用/禁用Tx 前导码
iwpriv ra0 set TxPreamble=0

####19.RTSThreshold 设置RTS 阈值 1~2347

####20.FragThreshold 设置分片包阈值,256~2346
iwpriv ra0 set FragThreshold=1024

####21.TxBurst 启用/禁用Tx burst,0:disable;1:enable
iwpriv ra0 set TxBurst=1

####22.PktAggregate 启用/禁用 Tx 帧聚合,0:disable,1:enable

####23.NoForwarding 启用或禁用不同的sta的包在相同的SSID转发,0:disable;1:enable
iwpriv ra0 set NoForwarding=0

####24.NoForwardingBTNBSSID,禁用或启用在每个BSSID之间不转发0:disable;1:enable

####25.NoForwardingMBCast,禁用或启用不抓发组播/多播包

####26.HideSSID,禁用或启用隐藏SSID,0:disable;1:enable
iwpriv ra0 set HideSSID=0

####27.StationKeepAlive禁用或启用周期性自动检测活跃的sta,0:disable;1:enable
iwpriv ra0 set StationKeepAlive=1

####28.ShortSlot,禁用或启用short slot time,0:disable;1:enable
iwpriv ra0 set ShortSlot=1

####29.AutoChannelSelect,启用禁用信道自动选则,0,disable;1:旧算法,2:新算法;

####30.Debug 设置WLAN debug等级(0~5) 0:off;1:Error;2:Warning;3:Trace;4:Info;5:Loud
iwpriv ra0 set Debug=3

####31.DriverVersion 检测无线驱动版本
iwpriv ra0 set DriverVersion=0

####32.AccessPolicy 配置访问控制规则,0:允许访问AP,1:禁止访问AP
iwpriv ra0 set AccessPolicy=0

####33.ResetCounter,重设计算器
iwpriv ra0 set ResetCounter=1

####34.SiteSurvey 请求动作做站点测量
iwpriv ra0 set SiteSurvey=
被动扫描:空串,iwpriv ra0 set SiteSurvey=
主动扫描:目的SSID,iwpriv ra0 set SiteSurvey=Target_SSID

####35.CountryString 设置国家
iwpriv ra0 set CountryString=China

####36.FixedTxMode设置发送调制模式,CCK OFDM HT
iwpriv ra0 set FixedTxMode=CCK

####37.DisConnectSta断开一个指定的STA
iwpriv ra0 set DisConnectSta=00:11:22:33:44:55

####38.DisConnectAllSta 断开所有sta
iwpriv ra0 set DisConnectAllSta=1

####39.McastPhyMode 设置多播物理模式,0:Disable; 1:CCK;2:OFDM;3:HTMIX
iwpriv ra0 set McastPhyMode=0

####40.McastMcs设置多播包的MCS,0~15
iwpriv ra0 set McastMcs=0

####41.MaxStaNum 现在每一个BSS可以管理sta的最大值 1~32
iwpriv ra0 set MaxStaNum=0
0:禁用限制

####42.AutoFallBack 启用/禁用自动降低速率功能。0:disable; 1:enable
iwpriv ra0 set AutoFallBack=1

####43.MBSSWirelessMode 设置MBSS 无线物理方式
iwpriv ra0 set MBSSWirelessMode=1
0:802.11B/G mixed
1:802.11B only
2:801.11A only
4:801.11G only
6:801.11N only
7:801.11G/N mixed
8:801.11A/N mixed
9:801.11B/G/Nmixed
10:801.11A/G/N mixed
11:801.11N in 5G band only

####44.HtBw HT信道带宽设置, 0:20MHz;1:20/40 MHz
iwpriv ra0 set HtBw=1

####45.HtMcs 设置无线调制编码策略, 0~15,32:fix MCS rate, 33,自动适配
iwpriv ra0 set HtMcs=33

####46.HtGi 设置无线guard 间隔,0:长间隔;1短间隔
iwpriv ra0 set HtGi=1

####47.HtOpMode 设置HT操作模式,0:HT混合模式,1:HT greenfield模式
iwpriv ra0 set HtOpMode=0

####48.HtBaWinSize 设置Block Ack 窗口大小,1~64
iwpriv ra0 set HtBaWinSize=64

####49.HtTxBASize 设置一次传输burst中AMPDU聚合包的个数,1~64
iwpriv ra0 set HtBASize=64

####50.HtAmsdu 启用禁用A-MSDU,0 禁用,1启用
iwpriv ra0 set HtAmsdu=0

####51.HtAutoBa 启用禁用自动block ack,0 禁用,1启用
iwpriv ra0 set HtAutoBa=1

####52.HtMimoPs 启用禁用HT MIMMO power save 模式,1:enable,0:disable
iwpriv ra0 set HtMimoPs=1

####53.AP2040Rescan 触发HT20/40 coexistence重新扫描,1:触发
iwpriv ra0 set AP2040Rescan=1

####54.HtBssCoex 启用禁用HT BSS coexistence,0 禁用,1启用
iwpriv ra0 set HtBssCoex=1

####55.AssocReqRssiThres设置关联请求时接收灵敏度的阈值,使拒绝STA的关联请求在弱信号的情况下
iwpriv ra0 set AssocReqRssiThres=-88
0:关闭
0~-100RSSI的值

####56.stat 显示无线统计信息
iwpriw ra0 stat
或者:
while [ 1 ]; do iwpriv ra0 set ResetCounter=1; sleep 1; iwpriv ra0 stat; done;

####57.get_site_survey 获取扫描信息
iwpriv ra0 get_site_survey
执行该命令前先执行iwpriv ra0 set SiteSurvey=

####58.get_mac_table 获取连接到AP的sta的mac地址信息
iwpriv ra0 get_mac_talbe

####59.get_ba_table 显示BlackACK table
iwpriv ra0 get_ba_table

####60.show 显示信息
iwpriv ra0 show [parameter]
[parameter list]
1.driverinfo
2.stat
3.stainfo
4.stacountinfo
5.stasecinfo
6.bainfo
7.connStatus
8.reptinfo
9.wdsinfo
10.igmpinfo
11.mbss
12.blockch

大陆地区OS X/Unix-like系统智能路由表实现无缝翻墙.

背景吐槽

方校长搞的GFW太恼火了. 搞的我们IT从业人员上国外网站搜个google,查个资料啥的甚是不方便.
Goagent和ssh的socks5以及shadowsocks虽然可以翻出去.但是他只能工作在应用层代理.而且一旦翻出去的话..
上国外网站方便了.但是再上国内网站就奇慢无比了(当然也有GFWList自动判断丁PAC脚本)..因为我们的网络数据要先传到国外再传回国内..
然后在传到国外再传到我们的电脑上来.. 网络数据绕的累不累?反正我是累了.
所以我还是喜欢在国外的Linux机器上开个VPN服务器.然后本地通过VPN拨号出去.然后设置把所有流量都通过VPN,这样任何数据都默认先到国外去了.
这样一来..我们需要想办法搞到所有天朝各大运营商所分配的IP地址段.然后把所有ip地址段都一一设置路由表,让其走本地网关而不是ppp0接口(或者其他私有VPN接口).

稍加思索

思路大概就是吐槽的这样了.下面我们来看怎么一步一步设置.

大概步骤:

  1. 第一步:
    连接海外VPN,让所有数据默认都走VPN,就是说把vpn连接设置为默认路由.
    输入VPN服务器地址.用户名和密码. 设置通过所有VPN连接发送所有流量(Linux下设置默认路由为VPN出口)。

  2. 第二步:
    想办法获取中国所有的IP段列表,解析列表计算生成各个网段的网络地址和掩码保存到脚本当中,
    执行脚本添加路由表,国内IP走国内网关,其他的IP默认统一海外VPN出去。

立马行动

我们去哪里能得到中国的IP分配信息呢..那肯定要去管理这区域的互联网信息的机构去弄,那中国的当然就是去这地方:
亚太互联网络信息中心.
亚太互联网络信息中心(Asia-Pacific Network Information Centre,APNIC),全球五大区域性英特网注册管理机构之一,负责亚太地区IP地址、ASN(自治系统号)的分配并管理一部分根域名服务器镜像。
它提供全球性的支持互联网操作的分派和注册服务。这是成员包括网络服务提供商、全国互联网登记,和相似的组织的一个非营利,基于会员资格的组织。APNIC负责亚洲太平洋区域,包含56个经济区。

我们需要获取亚太地区IP信息表,然后过滤出中国的IP地址段,并计算各个段的网络地址和掩码,生成路由添加脚本.

下载下面这个我已经写好的自动化脚本

#!/bin/bash
#######################戴维营教育 获取中国IPv4地址段路由表 Shell脚本########
FILE=china-ip
ACTION=add
GW=`netstat -nr|grep default |tail -1|awk '{print $2}'`
rm ip_mask.txt add_route_mac.sh $FILE >/dev/null
curl  http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest -o $FILE
grep 'apnic|CN|ipv4|' $FILE | cut -f 4,5 -d'|'|sed -e 's/|/ /g' | while read ip cnt
do
mask=$(cat << EOF | bc | tail -1
pow=32;
define mylog(a)
{
        if (a<=1) return (pow);
        pow--;
        return (mylog( a/2 ));
}
mylog($cnt);
);

echo $ip/$mask/$GW/:$cnt
echo $ip/$mask >> ip_mask.txt
echo "sudo route $ACTION -net $ip/$mask $GW" >> add_route_mac.sh
chmod +x add_route_mac.sh
done

运行这个脚本之后会在当前目录下生成 add_route_mac.sh脚本文件.
然后再执行sudo add_route_mac_sh命令把上一步生成的路由项都添加的到系统的路由表里.
稍等片刻就大功告成啦.. 因为毕竟也有3700条左右的路由项.
这个时候打开国内网站自动走本地网关..国外网站自动走vpn接口.
这个时候我们来用命令测试一下到www.youtube.com和www.baidu.com的路由分别是什么样的:

其中192.168.123.1是vpn服务器那边的vpn网关..192.168.2.253是我本地无线路由的网关:

这样一来,我们就不仅仅是流量网页可以无缝翻墙了.其他一切应用都OK拉..因为我们是在网络层开刀的.而不是在应用层或传输层开刀的.

如果有朋友的公司用的软路由或者好一点的路由器..可以把这些在路由器上建立vpn客户端,然后把路由项加到路由器里.然后就整个公司都可以畅通无阻啦.让员工感觉好像不在天朝一样.

前两天才给我们的iOS开发学员讲解了TCP/IP原理, 之前有给每个人分配一个VPN账号用来google查资料. 但是估计他们觉得翻出去后打开国内网站又很慢. 总是不能两全其美. 故今天特意把这样法子简单整理个步骤. 希望能给大家带来方便..

长沙戴维营教育 iOS开发培训 Linux后台开发培训 欢迎大家一起讨论一切关于开发啊 网络啊 等等的问题.

本文最初于 2013-9-29 发表于 http://bbs.diveinedu.com/forum.php?mod=viewthread&tid=1445

Mac OS X中编译WRTNode固件

#1.Disk Image Creation
Mac OS X系统默认的磁盘文件系统是非大小写敏感的,而Openwrt编译环境需要大小写敏感支持,故我们创建一个磁盘映像文件来新建大小写敏感的文件系统.

下面开始用MacOSX系统中自带的命令hdiutil来创建一个新磁盘镜像并挂载到系统中.

Hackintosh:~ Diveinedu$ cd $HOME
Hackintosh:~ Diveinedu$ hdiutil create -size 20g -fs "Case-sensitive HFS+" -volname OpenWrt OpenWrt.dmg
Hackintosh:~ Diveinedu$ hdiutil attach OpenWrt.dmg

上面命令会在我们的主目录下创建一个大小为20G的镜像文件,并格式化为Case-sensitive HFS+的文件系统,卷标名为OpenWrt,然后挂载到系统中.挂载后我们看样子Finder界面的左侧边栏看到他.
我们需要在终端命令行下进入我们刚刚创建好的文件系统对应的目录下去:

Hackintosh:~ Diveinedu$ cd /Volumes/OpenWrt

#2.Packages Installation
下一步我们需要安装搭建OpenWrt编译环境所需的一些软件包,主要是两个部分:

  • XCode IDE: Apple的一个集成开发环境SDK,包含一些核心的库文件和编译器
  • Homebrew: OS X 不可或缺的套件管理器,MacOSX平台的软件包管理系统(类似于Debian/Ubuntu系统里的apt-get),用来下载和安装一些开源项目软件,比如在Unix/Linux/BSD世界里广泛存在而Apple的MacOSX没有自带的软件.http://brew.sh/index_zh-cn.html

XCode的安装:

  • 打开 Mac App Store 应用商店
  • 在右上角的搜索框搜索 "Xcode"
  • 选择 Xcode,然后点击安装
  • 输入你的Apple ID账号和密码,就会开始下载安装.
  • 最后还需要一步,运行下面命令确保命令行开发工具已经安装:
Hackintosh:OpenWrt Diveinedu$ xcode-select --install

如果有弹出窗口,就选择安装他,他会自带去Apple的更新服务器上下载安装的.

Homebrew的安装:

  • 获取 Homebrew, 打开Homebrew的官网中文页面: http://brew.sh/index_zh-cn.html
  • 打开终端窗口, 粘贴以下脚本,脚本会解释它的作用,然后在您的确认下执行安装。
Hackintosh:OpenWrt Diveinedu$ ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

基础依赖软件包安装:

  • brew 命令安装:
Hackintosh:OpenWrt Diveinedu$ brew install asciidoc docbook gdbm libxml2 pbzip2 autoconf e2fsprogs gettext libxslt pkg-config bash-completion fastjar gnu-getopt libyaml readline binutils findutils gnu-tar lzlib sqlite bison flex gputils openssl wget coreutils gawk intltool ossp-uuid xz

#3.Checkout the OpenWrt Source
我们可以从OpenWrt的官方网站上的源码仓库里检出代码,用SVN或者Git版本管理工具都可以,我这里推荐使用Git,选择自己需要的源码版本然后用下面的命令检出代码:

  • trunk (main development tree)

Main repository

git clone git://git.openwrt.org/openwrt.git

  • 14.07 branch (Barrier Breaker)

Main repository

git clone git://git.openwrt.org/14.07/openwrt.git

我选择检出14.07分支版本,在之前准备好的文件系统的挂载目录下依次执行如下命令:

Hackintosh:OpenWrt Diveinedu$ git clone git://git.openwrt.org/14.07/openwrt.git
Hackintosh:OpenWrt Diveinedu$ cd openwrt
Hackintosh:openwrt Diveinedu$ ./scripts/feeds update
Hackintosh:openwrt Diveinedu$ ./scripts/feeds install -a

上述命令成功执行完成后,我们就已经准备好了OpenWrt的源码并部署了所有的软件包以供我们后面的编译配置步骤去选择了.

#4. Configure and Build OpenWrt For MT7620

A. 到这里,我们就可以开始为我们的路由器板子进行配置了,比如我现在为我的MT7620N板子进行编译的配置,在命令行执行如下命令:

Hackintosh:openwrt Diveinedu$ make menuconfig

这条命令会在终端显示一个基于ncurses的文本图形菜单,我们在菜单里作如下选择:

Target System (Ralink RT288x/RT3xxx) --->

Subtarget (MT7620n based boards) --->

其他具体的配置项这里就从略...

比如MT7620的WiFi驱动啊, USB存储驱动啊, USB的3G Modem驱动等等,

根据实际需求添加配置.此处只做配置编译过程的演示.

配置好这些合适的编译配置项目后,退出菜单保存设置.


B.此时此刻,万事具备只欠东风,东风就是最后一条编译命令:

Hackintosh:openwrt Diveinedu$ make V=s

由于是第一次编译,这一条命令的时间足够让我们睡一个午觉,如果不想睡觉,那就喝几杯咖啡吧.
如果网络条件好,那么首次编译过程中所需要下载的软件包应该不会遇到什么错误.因为我这次就非常的顺利,不过我是用的VPN番茄了的.

编译完成之后,我们可以在输出目录下查看我们的结果,那就是各种MT7620N方案的路由器板子的固件:

Hackintosh:openwrt Diveinedu$ ls -lh bin/ramips/
total 62344
-rw-r--r--  1 Diveinedu  staff   812B  9  8 20:45 md5sums
-rw-r--r--  1 Diveinedu  staff   3.5M  9  8 20:45 openwrt-ramips-mt7620n-mlw221-squashfs-sysupgrade.bin
-rw-r--r--  1 Diveinedu  staff   2.5M  9  8 20:45 openwrt-ramips-mt7620n-root.squashfs
-rw-r--r--  1 Diveinedu  staff   3.5M  9  8 20:45 openwrt-ramips-mt7620n-rt-n14u-squashfs-sysupgrade.bin
-rw-r--r--  1 Diveinedu  staff   1.0M  9  8 20:45 openwrt-ramips-mt7620n-uImage.bin
-rwxr-xr-x  1 Diveinedu  staff   2.9M  9  8 20:45 openwrt-ramips-mt7620n-vmlinux.bin
-rwxr-xr-x  1 Diveinedu  staff   3.0M  9  8 20:45 openwrt-ramips-mt7620n-vmlinux.elf
-rw-r--r--  1 Diveinedu  staff   3.5M  9  8 20:45 openwrt-ramips-mt7620n-wmr-300-squashfs-sysupgrade.bin
-rw-r--r--  1 Diveinedu  staff   3.5M  9  8 20:45 openwrt-ramips-mt7620n-wr8305rt-squashfs-sysupgrade.bin
-rw-r--r--  1 Diveinedu  staff   3.5M  9  8 20:45 openwrt-ramips-mt7620n-wrtnode-squashfs-sysupgrade.bin
-rw-r--r--  1 Diveinedu  staff   3.5M  9  8 20:45 openwrt-ramips-mt7620n-zbt-wa05-squashfs-sysupgrade.bin
drwxr-xr-x  4 Diveinedu  staff   136B  9  8 20:20 packages
Hackintosh:openwrt Diveinedu$

选择我们板子对应的固件,比如我们罗老湿的 WRTNode ,那就选择bin/ramips/openwrt-ramips-mt7620n-wrtnode-squashfs-sysupgrade.bin, 然后scp上传到路由器里或者通过TTL+TFTP的方式进行刷机测试.
如果是采用TTL+TFTP的方式,那我们还需要安装一个minicom工具.同样,在命令行运行命令:

Hackintosh:openwrt Diveinedu$ brew install minicom

安装完成之后运行minicom,设置正确的设备文件和正确的波特率:

Hackintosh:openwrt Diveinedu$ minicom -s

公司笔记本使用USB转串口的适配器在MacOSX里的设备文件的话,一般是/dev/tty.USBxxx这样的文件,像我现在家里所使用的台式机黑苹果的画,主板上的串口对应的设备文件是/dev/tty.serial1.具体看芯片的驱动是怎么样命名.

到此,在Mac OS X 10.9.4系统中进行OpenWrt智能路由器,嵌入式Linux开发环境搭建和编译的步骤就介绍完成.