dhcpd传输层基于UDP协议,dhcpv4的client和server分别使用udp的68和67号端口,在守护进程中,关于port设置的代码结构如下:
判断全局变量local_port,若是0,从getenv函数从环境中获取DHCPD_PORT环境变量的值,getenv函数原型如下:
/* Return the value of envariable NAME, or NULL if it doesn't exist. */
extern char *getenv (__const char *__name) __THROW __nonnull ((1)) __wur;
一个简单的使用示例:
char * env = getenv("HOME");
printf("%s\n", env);
结果是打印/root
一般获取不到,然后判断全局变量local_family是否是AF_INET,即ipv4套接字,若是,调用getservbyname以dhcp为入参获取dhcp的udp端口号,否则是v6,还是调用这个函数以dhcpv6为入参获取dhcpv6的udp端口号。注意这里是server的代码流程,因此获取的都是server的端口号,v4默认是67,v6是547,getservbyname函数定义如下
struct servent * PASCAL
getservbyname(const char* a0, const char* a1)
{
static struct servent * (PASCAL *fp)(const char* a0, const char* a1);
#ifdef DEBUG_STUB
idnLogPrintf(idn_log_level_trace, "stub getservbyname() called\n");
#endif
if (fp == NULL) {
void *p;
if ((p = GetProcAddress(DLLHANDLE, "getservbyname")) == NULL) {
FATAL("cannot find entry getservbyname (%d)\n", GetLastError());
abort();
}
fp = p;
}
return (*fp)(a0, a1);
}
里面涉及一些结构体和系统调用,其中,struct servent声明在inlcude/netdb.h中,声明如下
/* 单个条目的数据库条目描述 */
struct servent
{
char *s_name; /* 服务名称 */
char **s_aliases; /* 别名列表 */
int s_port; /* 端口号 */
char *s_proto; /* 协议 */
};
GetProcAddress函数从指定dll库中寻找函数地址,其内部实现在这里不做探究。调用getservbyname("dhcp","port"),将得到一个struct servent结构的ent变量,从ent->s_port中可以获取对应的端口号,若获取不到,就使用默认的。
若是dhcpv4,给全局变量remote_port远端端口号赋值为68,即client使用的udp端口号,否则是dhcpv6,给remote_port赋值为546,main函数中完整代码如下
if (!local_port)
{
if ((s = getenv ("DHCPD_PORT"))) {
local_port = validate_port (s);
log_debug ("binding to environment-specified port %d",
ntohs (local_port));
} else {
if (local_family == AF_INET) {
ent = getservbyname("dhcp", "udp");
if (ent == NULL) {
local_port = htons(67);
} else {
local_port = ent->s_port;
}
} else {
/* INSIST(local_family == AF_INET6); */
ent = getservbyname("dhcpv6-server", "udp");
if (ent == NULL) {
local_port = htons(547);
} else {
local_port = ent->s_port;
}
}
#ifndef __CYGWIN32__ /* XXX */
endservent ();
#endif
}
}
if (local_family == AF_INET) {
remote_port = htons(ntohs(local_port) + 1);
} else {
/* INSIST(local_family == AF_INET6); */
ent = getservbyname("dhcpv6-client", "udp");
if (ent == NULL) {
remote_port = htons(546);
} else {
remote_port = ent->s_port;
}
}