udhcp源码详解(六)--script

来源:互联网 发布:邀请好友进群js编码 编辑:程序博客网 时间:2024/06/05 02:26
首先得讲明udhcp客户端设置IP的机制。

在udhcp中,客户端通过和主机的多次报文交互协商而获得可用的IP地址。在获得IP地址之后,客户端使用execle函数调用shell脚本完成客户端ip,netmak,dns,gateway等等参数的设定。而shell脚本的调用在script.h和script.c中实现。

以下为script.c源码中的主要实现函数:

/* get a rough idea of how long an option will be (rounding up...) */static int max_option_length[] = {[OPTION_IP] =sizeof("255.255.255.255 "),[OPTION_IP_PAIR] =sizeof("255.255.255.255 ") * 2,[OPTION_STRING] =1,[OPTION_BOOLEAN] =sizeof("yes "),[OPTION_U8] =sizeof("255 "),[OPTION_U16] =sizeof("65535 "),[OPTION_S16] =sizeof("-32768 "),[OPTION_U32] =sizeof("4294967295 "),[OPTION_S32] =sizeof("-2147483684 "),};

本函数为option字段占用的最大字节数。如OPTION_BOOLEAN变量里,true 对应yes。False对应no,那么这种类型的变量中对应的最大字节占用就为sizeof(yes)。

static int upper_length(int length, struct dhcp_option *option){return max_option_length[option->flags & TYPE_MASK] *       (length / option_lengths[option->flags & TYPE_MASK]);}

转化为shell脚本参数格式所占字节大小的上限。

/* Fill dest with the text of option 'option'. */static void fill_options(char *dest, unsigned char *option, struct dhcp_option *type_p){int type, optlen;u_int16_t val_u16;int16_t val_s16;u_int32_t val_u32;int32_t val_s32;int len = option[OPT_LEN - 2];//报文中该option的长度dest += sprintf(dest, "%s=", type_p->name);type = type_p->flags & TYPE_MASK;optlen = option_lengths[type];for(;;) {switch (type) {case OPTION_IP_PAIR:dest += sprintip(dest, "", option);*(dest++) = '/';option += 4;optlen = 4;case OPTION_IP:/* Works regardless of host byte order. */dest += sprintip(dest, "", option); break;case OPTION_BOOLEAN:dest += sprintf(dest, *option ? "yes " : "no ");break;case OPTION_U8:dest += sprintf(dest, "%u ", *option);break;case OPTION_U16:memcpy(&val_u16, option, 2);dest += sprintf(dest, "%u ", ntohs(val_u16));break;case OPTION_S16:memcpy(&val_s16, option, 2);dest += sprintf(dest, "%d ", ntohs(val_s16));break;case OPTION_U32:memcpy(&val_u32, option, 4);dest += sprintf(dest, "%lu ", (unsigned long) ntohl(val_u32));break;case OPTION_S32:memcpy(&val_s32, option, 4);dest += sprintf(dest, "%ld ", (long) ntohl(val_s32));break;case OPTION_STRING:memcpy(dest, option, len);dest[len] = '\0';return; /* Short circuit this case */}option += optlen;len -= optlen;if (len <= 0) break;}}

//读取options,并输出至dest所指内存。例如 router输出格式为router=192.168.2.3

/* put all the paramaters into an environment */static char **fill_envp(struct dhcpMessage *packet){int num_options = 0;int i, j;char **envp;unsigned char *temp;char over = 0;if (packet == NULL)num_options = 0;else {for (i = 0; options[i].code; i++)if (get_option(packet, options[i].code))num_options++;if (packet->siaddr) num_options++;if ((temp = get_option(packet, DHCP_OPTION_OVER)))over = *temp;if (!(over & FILE_FIELD) && packet->file[0]) num_options++;if (!(over & SNAME_FIELD) && packet->sname[0]) num_options++;}envp = xmalloc((num_options + 5) * sizeof(char *));envp[0] = xmalloc(sizeof("interface=") + strlen(client_config.interface));sprintf(envp[0], "interface=%s", client_config.interface);envp[1] = find_env("PATH", "PATH=/bin:/usr/bin:/sbin:/usr/sbin");envp[2] = find_env("HOME", "HOME=/");//读取本地环境变量if (packet == NULL) {envp[3] = NULL;return envp;}envp[3] = xmalloc(sizeof("ip=255.255.255.255"));//按最大的点分十进制格式申请空间sprintip(envp[3], "ip=", (unsigned char *) &packet->yiaddr);for (i = 0, j = 4; options[i].code; i++) {//读取if ((temp = get_option(packet, options[i].code))) {envp[j] = xmalloc(upper_length(temp[OPT_LEN - 2], &options[i]) + strlen(options[i].name) + 2);fill_options(envp[j], temp, &options[i]);j++;}}if (packet->siaddr) {envp[j] = xmalloc(sizeof("siaddr=255.255.255.255"));sprintip(envp[j++], "siaddr=", (unsigned char *) &packet->siaddr);}if (!(over & FILE_FIELD) && packet->file[0]) {/* watch out for invalid packets */packet->file[sizeof(packet->file) - 1] = '\0';envp[j] = xmalloc(sizeof("boot_file=") + strlen(packet->file));sprintf(envp[j++], "boot_file=%s", packet->file);}if (!(over & SNAME_FIELD) && packet->sname[0]) {/* watch out for invalid packets */packet->sname[sizeof(packet->sname) - 1] = '\0';envp[j] = xmalloc(sizeof("sname=") + strlen(packet->sname));sprintf(envp[j++], "sname=%s", packet->sname);}envp[j] = NULL;return envp;}

按指定的格式填充环境变量


/* Call a script with a par file and env vars */void run_script(struct dhcpMessage *packet, const char *name){int pid;char **envp;if (client_config.script == NULL)return;/* call script */pid = fork();if (pid) {waitpid(pid, NULL, 0);return;} else if (pid == 0) {envp = fill_envp(packet);//从数据报文和主机中获取相关信息/* close fd's? *//* exec script */DEBUG(LOG_INFO, "execle'ing %s", client_config.script);execle(client_config.script, client_config.script,       name, NULL, envp);LOG(LOG_ERR, "script %s failed: %s",    client_config.script, strerror(errno));exit(1);}}

execle(client_config.script,client_config.script,name, NULL, envp);

函数在执行时envp所存环境变量能够被shell script所直接使用。这种用法不大常见,具体execle函数用法,请google之。

 

以下为运行至execle函数时,envp的一个示例:

interface=eth0

PATH= …(过长不写明)…

HOME=/root

ip=192.168.0.24

subnet=255.255.255.0

router=192.168.10.2

dns= 129.219.13.81

domain=local

wins=192.168.10.10

leases=8640000

dhcptype=5

serverid=192.168.253.23

 

由上面可以看出这些参数和udhcpd服务端配置文件所指定的参数一致。

 

 

值得注意的是options.c文件的全局dhcp_option变量并没有将所有的option包括进去,从这点上讲如果你是要扩展某个option字段,则必需在options按指定的格式中加入相关字段,同时如果该字段不属于option_lengths中指定类型中任何一种,那么你也必需在其指定该类型字段所占的字节数。当然script.c文件中的max_option_length字段也要添加相应信息。

sample.script脚本内容如下:

#!/bin/sh

# Currently, we only dispatch according tocommand.  However, a more

# elaborate system might dispatch bycommand and interface or do some

# common initialization first, especiallyif more dhcp event notifications

# are added.

 

exec /usr/share/udhcpc/sample.$1

该脚本就一句话,就是执行/usr/share/udhcpc/sample.$1脚本。其中的$1为调用执行sample.script说指定的参数。

例如:

execle(client_config.script, client_config.script,

                          name, NULL, envp);

中,client_config.script为/usr/…/sample.script,name为”bound”,那么在sample.script被执行时exec /usr/share/udhcpc/sample.$1语句中的$1就可以被替换为”bound”,亦即执行的是

exec /usr/share/udhcpc/sample.bound。

这里$1可以为deconfig nak renew bound四个值。

 

在sample.bound脚本中,出项了broadcast,subnet,ip,router等等变量这些变量若在envp中被指定了,那么该变量就存在一个有意义的值。


更多信息请参见:

1、  dhcp基本原理介绍:

H3C的dhcp技术白皮书

http://www.h3c.com.cn/Products___Technology/Technology/IPv4_IPv6_series/Other_technology/Technology_book/200802/333443_30003_0.htm

dhcp的rfc2131文档

http://www.ietf.org/rfc/rfc2131.txt

2、  dhcp报文中的options字段信息(可选变长选项字段)介绍:

http://www.networksorcery.com/enp/protocol/bootp/options.htm

rfc2132

http://www.ietf.org/rfc/rfc2132.txt

3、  execle指定环境变量并调用执行shell脚本介绍:

APUE 8.10

http://blog.csdn.net/baidu20008/article/details/9764765


本人享有博客文章的版权,转载请标明出处http://blog.csdn.net/baidu20008


原创粉丝点击