📄 slp_dhcp.c
字号:
*hlen = 0; sin = (struct sockaddr_in *)&arpreq.arp_pa; memset(sin, 0, sizeof(struct sockaddr_in)); sin->sin_family = AF_INET; memcpy(&sin->sin_addr, ipaddr, sizeof(struct in_addr)); if (ioctl(sockfd, SIOCGARP, &arpreq) >= 0 && (arpreq.arp_flags & ATF_COM)) { *hlen = 6; /* assume IEEE802 compatible */ *htype = arpreq.arp_ha.sa_family; memcpy(chaddr, arpreq.arp_ha.sa_data, 6); } closesocket(sockfd);#else /* figure out another way ... */ (void)ipaddr; (void)chaddr; (void)htype; *hlen = 0;#endif return *hlen? 0: -1;}/*=========================================================================*/ int DHCPGetOptionInfo(unsigned char *dhcpOptCodes, int dhcpOptCodeCnt, DHCPInfoCallBack *dhcpInfoCB, void *context)/* Calls dhcpInfoCB once for each requested option in dhcpOptCodes. Returns - zero on success, non-zero on failure errno ENOTCONN error during read ETIME read timed out ENOMEM out of memory EINVAL parse error BOOTP/DHCP packet header format: Offs Len Name Description 0 1 opcode Message opcode: 1 = BOOTREQUEST, 2 = BOOTREPLY 1 1 htype Hardware address type (eg., 1 = 10mb ethernet) 2 1 hlen Hardware address length (eg., 6 = 10mb ethernet) 3 1 hops Client sets to zero, optionally used by relay agents 4 4 xid Transaction ID, random number chosen by client 8 2 secs Client sets to seconds since start of boot process 10 2 flags Bit 0: broadcast response bit 12 4 ciaddr Client IP address - only filled if client is bound 16 4 yiaddr 'your' (Client) IP address 20 4 siaddr IP address of next server to use in bootstrap 24 4 giaddr Relay agent IP address, used in booting via RA 28 16 chaddr Client hardware address 44 64 sname Optional server host name, null-terminated string 108 128 file Boot file name, null-terminated string 236 var options Optional parameters field The options field has the following format: Offs Len Name Description 0 4 cookie 4-byte cookie field: 99.130.83.99 (0x63825363) Followed by 1-byte option codes and 1-byte option lengths, except for the two special fixed length options, pad (0) and end (255). Options are defined in slp_dhcp.h as TAG_XXX values. The two we really care about here are options TAG_SLP_DA and TAG_SLP_SCOPE, 78 and 79, respectively. The format for TAG_SLP_DA (starting with the tag) is: Offs Len Name Description 0 1 tag TAG_SLP_DA - directory agent ip addresses 1 1 length length of remaining data in the option 2 1 mand flag: the use of these DA's is mandatory 3 4 a(0) 4-byte ip address ... 3+n*4 4 a(n) 4-byte ip address The format for TAG_SLP_SCOPE (starting with the tag) is: Offs Len Name Description 0 1 tag TAG_SLP_SCOPE - directory scopes to use 1 1 length length of remaining data in the option 2 1 mand flag: the use of these scopes is mandatory 3 var scopes a null-terminated, comma-separated string of scopes The "DHCP Message Type" option must be included in every DHCP message. All tags except for TAG_PAD(0) and TAG_END(255) begin with a tag value followed by a length of remaining data value. =========================================================================*/ { UINT32 xid; time_t timer; struct timeval tv; int sockfd, retries; struct sockaddr_in sendaddr; unsigned char chaddr[MAX_MACADDR_SIZE]; unsigned char hlen, htype; unsigned char sndbuf[512]; unsigned char rcvbuf[512]; struct hostent *hep; unsigned char *p; size_t rcvbufsz = 0; char host[256]; /* Get our IP and MAC addresses */ if(gethostname(host, (int)sizeof(host)) || !(hep = gethostbyname(host)) || dhcpGetAddressInfo((unsigned char *)hep->h_addr, chaddr, &hlen, &htype)) return -1; /* get a reasonably random transaction id value */ xid = (UINT32)time(&timer); /* BOOTP request header */ memset(sndbuf, 0, 236); /* clear bootp header */ p = sndbuf; *p++ = BOOTREQUEST; /* opcode */ *p++ = htype; *p++ = hlen; p++; /* hops */ ToUINT32(p, xid); p += 2 * sizeof(UINT32); /* xid, secs, flags */ memcpy(p, hep->h_addr, 4); p += 4 * sizeof(UINT32); /* ciaddr, yiaddr, siaddr, giaddr */ memcpy(p, chaddr, hlen); p += 16 + 64 + 128; /* chaddr, sname and file */ *p++ = DHCP_COOKIE1; /* options, cookies 1-4 */ *p++ = DHCP_COOKIE2; *p++ = DHCP_COOKIE3; *p++ = DHCP_COOKIE4; /* DHCP Message Type option */ *p++ = TAG_DHCP_MSG_TYPE; *p++ = 1; /* option length */ *p++ = DHCP_MSG_INFORM; /* message type is DHCPINFORM */ /* DHCP Parameter Request option */ *p++ = TAG_DHCP_PARAM_REQ; /* request for DHCP parms */ *p++ = (unsigned char)dhcpOptCodeCnt; memcpy(p, dhcpOptCodes, dhcpOptCodeCnt); p += dhcpOptCodeCnt; /* DHCP Client Identifier option */ *p++ = TAG_CLIENT_IDENTIFIER; *p++ = hlen + 1; /* option length */ *p++ = htype; /* client id is htype/haddr */ memcpy(p, chaddr, hlen); p += hlen; /* End option */ *p++ = TAG_END; /* get a broadcast send/recv socket and address */ if((sockfd = dhcpCreateBCSkt(&sendaddr)) < 0) return -1; /* setup select timeout */ tv.tv_sec = 0; tv.tv_usec = INIT_TMOUT_USECS; retries = 0; srand((unsigned)time(&timer)); while (retries++ < MAX_DHCP_RETRIES) { if(dhcpSendRequest(sockfd, sndbuf, p - sndbuf, (struct sockaddr *)&sendaddr, &tv) < 0) { if (errno != ETIMEDOUT) { closesocket(sockfd); return -1; } } else if((rcvbufsz = dhcpRecvResponse(sockfd, rcvbuf, sizeof(rcvbuf), &tv)) < 0) { if (errno != ETIMEDOUT) { closesocket(sockfd); return -1; } } else if(rcvbufsz >= 236 && AsUINT32(&rcvbuf[4]) == xid) break; /* exponential backoff randomized by a uniform number between -1 and 1 */ tv.tv_usec = tv.tv_usec * 2 + (rand() % 3) - 1; tv.tv_sec = tv.tv_usec / USECS_PER_SEC; tv.tv_usec %= USECS_PER_SEC; } closesocket(sockfd); return rcvbufsz? dhcpProcessOptions(rcvbuf + 236, rcvbufsz - 236, dhcpInfoCB, context): -1;}/*-------------------------------------------------------------------------*/int DHCPParseSLPTags(int tag, void *optdata, size_t optdatasz, void *context)/* Callback routined tests each DA discovered from DHCP and add it to the *//* DA cache. *//* *//* Returns: 0 on success, or nonzero to stop being called. *//*-------------------------------------------------------------------------*/{ int cpysz, bufsz; DHCPContext *ctxp = (DHCPContext *)context; unsigned char *p = (unsigned char *)optdata; unsigned char flags, dasize; int encoding; /* filter out zero length options */ if (!optdatasz) return 0; switch(tag) { case TAG_SLP_SCOPE: /* Draft 3 format is only supported for ASCII and UNICODE character encodings - UTF8 encodings must use rfc2610 format. To determine the format, we parse 2 bytes and see if the result is a valid encoding. If so it's draft 3, otherwise rfc2610. */ encoding = (optdatasz > 1)? AsUINT16(p): 0; if (encoding != CT_ASCII && encoding != CT_UNICODE) { /* rfc2610 format */ if (optdatasz == 1) break; /* UA's should ignore statically configured scopes for this interface - add code to handle this later... */ flags = *p++; /* pick up the mandatory flag... */ optdatasz--; if (flags) ; /* ...and add code to handle it later... */ /* copy utf8 string into return buffer */ cpysz = optdatasz < sizeof(ctxp->scopelist)? optdatasz: sizeof(ctxp->scopelist); strncpy(ctxp->scopelist, (char*)p, cpysz); ctxp->scopelist[sizeof(ctxp->scopelist) - 1] = 0; } else { /* draft 3 format: defined to configure scopes for SA's only so we should flag the scopes to be used only as registration filter scopes - add code to handle this case later... offs len name description 0 2 encoding character encoding used 2 n scopelist list of scopes as asciiz string. */ optdatasz -= 2; /* skip encoding bytes */ p += 2; /* if UNICODE encoding is used convert to utf8 */ if (encoding == CT_UNICODE) wcstombs(ctxp->scopelist, (wchar_t*)p, sizeof(ctxp->scopelist)); else { cpysz = optdatasz < sizeof(ctxp->scopelist)? optdatasz: sizeof(ctxp->scopelist); strncpy(ctxp->scopelist, (char*)p, cpysz); ctxp->scopelist[sizeof(ctxp->scopelist) - 1] = 0; } } break; case TAG_SLP_DA: flags = *p++; optdatasz--; /* If the flags byte has the high bit set, we know we are using draft 3 format, otherwise rfc2610 format. */ if (!(flags & DA_NAME_PRESENT)) { /* rfc2610 format */ if (flags) { /* If the mandatory byte is non-zero, indicate that multicast is not to be used to dynamically discover directory agents on this interface by setting the LACBF_STATIC_DA flag in the LACB for this interface. */ /* skip this for now - deal with it later... */ } bufsz = sizeof(ctxp->addrlist) - ctxp->addrlistlen; cpysz = (int)optdatasz < bufsz? optdatasz: bufsz; memcpy(ctxp->addrlist + ctxp->addrlistlen, p, cpysz); ctxp->addrlistlen += cpysz; } else { /* pre-rfc2610 (draft 3) format: offs len name description 0 1 flags contains 4 flags (defined above) 1 1 dasize name or addr length 2 dasize daname da name or ip address (flags) */ dasize = *p++; optdatasz--; if (dasize > optdatasz) dasize = optdatasz; if (flags & DA_NAME_IS_DNS) ; /* DA name contains dns name - we have to resolve - later... */ else { /* DA name is one 4-byte ip address */ if (dasize < 4) break; /* oops, bad option format */ dasize = 4; bufsz = sizeof(ctxp->addrlist) - ctxp->addrlistlen; cpysz = dasize < bufsz? dasize: bufsz; memcpy(ctxp->addrlist + ctxp->addrlistlen, p, cpysz); ctxp->addrlistlen += cpysz; } if (flags & DISABLE_DA_MCAST) ; /* this is the equivalent of the rfc2610 mandatory bit */ } break; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -