udhcp源碼詳解(六)–script

來源:互聯網
上載者:User

首先得講明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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.