提交 55d444cc 编写于 作者: S Stefan Berger

nwfilter: Process DHCP option to determine whether packet is a DHCP_OFFER

I mistakenly took the op field in the DHCP message as the DHCP_OFFER
type. Rather than basing the decision to read the VM's IP address on
that field, process the appended DHCP options where option 53 indicates
the actual type of the packet. I am also reading the broadcast address
of the VM, but don't use it so far.
上级 cddd3ac8
...@@ -64,6 +64,13 @@ struct f_arphdr { ...@@ -64,6 +64,13 @@ struct f_arphdr {
} ATTRIBUTE_PACKED; } ATTRIBUTE_PACKED;
struct dhcp_option {
uint8_t code;
uint8_t len;
uint8_t value[0]; /* length varies */
} ATTRIBUTE_PACKED;
/* structure representing DHCP message */ /* structure representing DHCP message */
struct dhcp { struct dhcp {
uint8_t op; uint8_t op;
...@@ -78,9 +85,12 @@ struct dhcp { ...@@ -78,9 +85,12 @@ struct dhcp {
uint32_t siaddr; uint32_t siaddr;
uint32_t giaddr; uint32_t giaddr;
uint8_t chaddr[16]; uint8_t chaddr[16];
/* omitted */ uint8_t zeroes[192];
uint32_t magic;
struct dhcp_option options[0];
} ATTRIBUTE_PACKED; } ATTRIBUTE_PACKED;
#define DHCP_MSGT_DHCPOFFER 2
struct ether_vlan_header struct ether_vlan_header
{ {
...@@ -212,6 +222,40 @@ virNWFilterGetIpAddrForIfname(const char *ifname) { ...@@ -212,6 +222,40 @@ virNWFilterGetIpAddrForIfname(const char *ifname) {
#ifdef HAVE_LIBPCAP #ifdef HAVE_LIBPCAP
static void
procDHCPOpts(struct dhcp *dhcp, int dhcp_opts_len,
uint32_t *vmaddr, uint32_t *bcastaddr,
enum howDetect *howDetected) {
struct dhcp_option *dhcpopt = &dhcp->options[0];
while (dhcp_opts_len >= 2) {
switch (dhcpopt->code) {
case 28: /* Broadcast address */
if (dhcp_opts_len >= 6) {
uint32_t *tmp = (uint32_t *)&dhcpopt->value;
(*bcastaddr) = ntohl(*tmp);
}
break;
case 53: /* Message type */
if (dhcp_opts_len >= 3) {
uint8_t *val = (uint8_t *)&dhcpopt->value;
switch (*val) {
case DHCP_MSGT_DHCPOFFER:
*vmaddr = dhcp->yiaddr;
*howDetected = DETECT_DHCP;
break;
}
}
}
dhcp_opts_len -= (2 + dhcpopt->len);
dhcpopt = (struct dhcp_option*)((char *)dhcpopt + 2 + dhcpopt->len);
}
}
/** /**
* learnIPAddressThread * learnIPAddressThread
* arg: pointer to virNWFilterIPAddrLearnReq structure * arg: pointer to virNWFilterIPAddrLearnReq structure
...@@ -236,12 +280,13 @@ learnIPAddressThread(void *arg) ...@@ -236,12 +280,13 @@ learnIPAddressThread(void *arg)
struct ether_header *ether_hdr; struct ether_header *ether_hdr;
struct ether_vlan_header *vlan_hdr; struct ether_vlan_header *vlan_hdr;
virNWFilterIPAddrLearnReqPtr req = arg; virNWFilterIPAddrLearnReqPtr req = arg;
uint32_t vmaddr = 0; uint32_t vmaddr = 0, bcastaddr = 0;
unsigned int ethHdrSize; unsigned int ethHdrSize;
char *listen_if = (strlen(req->linkdev) != 0) ? req->linkdev char *listen_if = (strlen(req->linkdev) != 0) ? req->linkdev
: req->ifname; : req->ifname;
int to_ms = (strlen(req->linkdev) != 0) ? 1000 int to_ms = (strlen(req->linkdev) != 0) ? 1000
: 0; : 0;
int dhcp_opts_len;
char macaddr[VIR_MAC_STRING_BUFLEN]; char macaddr[VIR_MAC_STRING_BUFLEN];
virBuffer buf = VIR_BUFFER_INITIALIZER; virBuffer buf = VIR_BUFFER_INITIALIZER;
char *filter= NULL; char *filter= NULL;
...@@ -382,12 +427,18 @@ learnIPAddressThread(void *arg) ...@@ -382,12 +427,18 @@ learnIPAddressThread(void *arg)
sizeof(struct dhcp)) { sizeof(struct dhcp)) {
struct dhcp *dhcp = (struct dhcp *) struct dhcp *dhcp = (struct dhcp *)
((char *)udphdr + sizeof(udphdr)); ((char *)udphdr + sizeof(udphdr));
if (dhcp->op == 2 /* DHCP OFFER */ && if (dhcp->op == 2 /* BOOTREPLY */ &&
!memcmp(&dhcp->chaddr[0], !memcmp(&dhcp->chaddr[0],
req->macaddr, req->macaddr,
6)) { 6)) {
vmaddr = dhcp->yiaddr; dhcp_opts_len = header.len -
howDetected = DETECT_DHCP; (ethHdrSize + iphdr->ihl * 4 +
sizeof(struct udphdr) +
sizeof(struct dhcp));
procDHCPOpts(dhcp, dhcp_opts_len,
&vmaddr,
&bcastaddr,
&howDetected);
} }
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册