mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 19:41:16 +00:00
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.
This commit is contained in:
parent
cddd3ac8b0
commit
55d444cc10
@ -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 {
|
|||||||
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) {
|
|||||||
|
|
||||||
#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)
|
|||||||
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)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user