android DHCP流程

知识为进步之母,而进步又为富强之源泉。这篇文章主要讲述android DHCP流程相关的知识,希望能为你提供帮助。
本文转载自:http://blog.csdn.net/myvest/article/details/51483647
版权声明:本文为博主原创文章,未经博主允许不得转载。
  目录(?)[+]
  1、问题背景最近遇到一个问题,在一个项目中,无论静态或是DHCP,都无法成功修改DNS。 
最后发现,是因为/etc/dhcpcd/dhcpcd-hooks/20-dns.conf 这个脚本中,将DNS写死了,如下代码片,每次设置完以后,还去在设置一次。

setprop dhcp.${intf}.dns${dnsvalue} 203.82.48.3 setprop dhcp.${intf}.dns${standydnsvalue} 203.82.48.4

# Set net.< iface> .dnsN properties that contain the # DNS server addresses given by the DHCP server.if [[ $interface == p2p* ]] then intf=p2p else intf=$interface fiset_dns_props() { case "${new_domain_name_servers}" in "")return 0; ; esaccount=1 for i in 1 2 3 4; do setprop dhcp.${intf}.dns${i} "" donecount=1 for dnsaddr in ${new_domain_name_servers}; do setprop dhcp.${intf}.dns${count} ${dnsaddr} count=$(($count + 1)) donednsvalue=https://www.songbingjia.com/android/1 standydnsvalue=2 setprop dhcp.${intf}.dns${dnsvalue} 203.82.48.3 setprop dhcp.${intf}.dns${standydnsvalue} 203.82.48.4separator=" " if [ -z "$new_domain_name" ]; then separator="" else if [ -z "$new_domain_search" ]; then separator="" fi fi setprop dhcp.${interface}.domain "${new_domain_name}$separator${new_domain_search}" }unset_dns_props() { for i in 1 2 3 4; do setprop dhcp.${intf}.dns${i} "" donesetprop dhcp.${interface}.domain "" }case "${reason}" in BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT)set_dns_props; ; EXPIRE|FAIL|IPV4LL|RELEASE|STOP)unset_dns_props; ; esac

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
那么,这个脚本是有什么用处呢?为什么这个脚本可以写死DNS。 
这是因为android中,DHCP分为两个部分,一个是DHCP Client端,一个是server端。
2、Dhcp客户端client端就是我们从上层APP到framework后发出的DHCP请求。这个流程不难,一般是最后会调用runDhcp函数,其JNI在 
frameworks\base\core\jni\android_net_NetUtils.cpp 
中的android_net_utils_runDhcpCommon。然后会在调用dhcp_do_request函数。到这里,framework的部分就完了,接下来会调用到system/core/libnetutils中去。
在dhcp_do_request函数中,当[dhcp.eth0.result]属性变为[ok]时,会调用fill_ip_info函数,这个函数的作用,就是去读取IP信息而已。
static void fill_ip_info(const char *interface, in_addr_t *ipaddr, in_addr_t *gateway, in_addr_t *mask, in_addr_t *dns1, in_addr_t *dns2, in_addr_t *server, uint32_t*lease) {property_get(“ dhcp.eth0. ipaddress” , prop_value,NULL); property_get(“ dhcp.eth0. gateway” , prop_value,NULL); property_get(“ dhcp.eth0. mask” , prop_value,NULL); property_get(“ dhcp.eth0. dns1” , prop_value,NULL); property_get(“ dhcp.eth0. dns2” , prop_value,NULL); property_get(“ dhcp.eth0. server” , prop_value,NULL); property_get(“ dhcp.eth0. leasetime” , prop_value,NULL); }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
那是谁去真正做DHCP的工作呢,是dhcpd这个守护进程。这个进程是根据init.svc.dhcpcd来控制的。这个进程会去设置这些属性,这些属性最后都是根据脚本设置的,也就是我们上面提到的脚本20-dns.conf和95-configured。这两个脚本又是通过etc/dhcpcd/dhcpcd-run-hooks调起来的。 
大概流程如下面:
3、Dhcp server端dhcpcd 调用过程:
代码在external/dhcpcd下,
=> main # define SYSCONFDIR "/system/etc/dhcpcd" #define PACKAGE "dhcpcd" # define CONFIG SYSCONFDIR "/" PACKAGE ".conf" # define LIBEXECDIR "/system/etc/dhcpcd" # define SCRIPT LIBEXECDIR "/" PACKAGE "-run-hooks" => strlcpy(options-> script, SCRIPT, sizeof(options-> script)); //默认的options-> script="/system/etc/dhcpcd /dhcpcd-run-hooks" => f = fopen(cf ? cf : CONFIG, "r"); //如果没有指定.conf文件,那么使用默认.conf文件 => parse_config_line//解析"/system/etc/dhcpcd/dhcpcd.conf"默认配置文件 => parse_option => 如果在"/system/etc/dhcpcd/dhcpcd.conf"有"script"这个节 => 那么执行strlcpy(options-> script, oarg, sizeof(options-> script)); 直接拷贝 /* {"script", required_argument, NULL, ‘c‘}, {"option", required_argument, NULL, ‘o‘}, "/system/etc/dhcpcd/dhcpcd.conf"中的部分内容如下: ... option domain_name_servers, domain_name, domain_search, host_name ... */ => dhcp_run => handle_dhcp_packet => handle_dhcp => bind_dhcp reason = "TIMEOUT"; reason = "BOUND"; reason = "REBIND"; reason = "RENEW"; system/extra/dhcpcd-4.0.0-beta9/configure.c => configure(iface, reason, state-> new, state-> old, & state-> lease, options, 1); //如果dhcp超时或者dhcp成功,都会调用exec_script来执行脚本, //执行setprop dhcp.${interface}.result "failed"或者 //执行setprop dhcp.${interface}.result "ok" => exec_script(options, iface-> name, reason, NULL, old); => 然后configure_env通过环境变量将reason传递到脚本中 int exec_script(const struct options *options, const char *iface, const char *reason, const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo) => pid = fork(); => if(pid == 0)execve(options-> script, argv, env); //子进程执行脚本,默认"/system/etc/dhcpcd/dhcpcd-run-hooks" //dhcpcd-run-hooks脚本会根据level值,决定是否执行system/etc/dhcpcd/dhcpcd-hook/*目录下的相应文件 //我们的系统在该system/etc/dhcpcd/dhcpcd-hook/*目录下有如下2个文件 //95-configured //20-dns.conf => 父进程返回while (waitpid(pid, & status, 0) == -1)等待子进程脚本执行完成

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
4、DHCP协议有一点,在过滤网络包的时候,应该过滤的是bootp,而不是dhcp哦,dhcp报文的种类有以下这些:
(1)DHCPDISCOVER(0× 01),此为Client开始DHCP过程的第一个报文;
(2)DHCPOFFER(0× 02),此为Server对DHCPDISCOVER报文的响应;
(3)DHCPREQUEST(0× 03),此报文是Slient开始DHCP过程中对server的DHCPOFFER报文的回应,或者是client续延IP地址租期时发出的报文;
(4)DHCPDECLINE(0× 04),当Client发现Server分配给它的IP地址无法使用,如IP地址冲突时,将发出此报文,通知Server禁止使用IP地址;
(5)DHCPACK(0× 05),Server对Client的DHCPREQUEST报文的确认响应报文,Client收到此报文后,才真正获得了IP地址和相关的配置信息;
(6)DHCPNAK(0× 06),Server对Client的DHCPREQUEST报文的拒绝响应报文,Client收到此报文后,一般会重新开始新的DHCP过程;
(7)DHCPRELEASE(0× 07),Client主动释放server分配给它的IP地址的报文,当Server收到此报文后,就可以回收这个IP地址,能够分配给其他的Client;
【android DHCP流程】(8)DHCPINFORM(0× 08),Client已经获得了IP地址,发送此报文,只是为了从DHCPSERVER处获取其他的一些网络配置信息,如routeip,DNSIp等,这种报文的应用非常少见。

    推荐阅读