On Fri, Apr 09, 2010 at 02:57:43PM -0400, Stefan Berger wrote: > 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. > > Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxx> > > --- > src/nwfilter/nwfilter_learnipaddr.c | 61 +++++++++++++++++++++++++++++++++--- > 1 file changed, 56 insertions(+), 5 deletions(-) > > Index: libvirt-acl/src/nwfilter/nwfilter_learnipaddr.c > =================================================================== > --- libvirt-acl.orig/src/nwfilter/nwfilter_learnipaddr.c > +++ libvirt-acl/src/nwfilter/nwfilter_learnipaddr.c > @@ -64,6 +64,13 @@ struct f_arphdr { > } ATTRIBUTE_PACKED; > > > +struct dhcp_option { > + uint8_t code; > + uint8_t len; > + uint8_t value[0]; /* length varies */ > +} ATTRIBUTE_PACKED; > + > + > /* structure representing DHCP message */ > struct dhcp { > uint8_t op; > @@ -78,9 +85,12 @@ struct dhcp { > uint32_t siaddr; > uint32_t giaddr; > uint8_t chaddr[16]; > - /* omitted */ > + uint8_t zeroes[192]; > + uint32_t magic; > + struct dhcp_option options[0]; > } ATTRIBUTE_PACKED; > > +#define DHCP_MSGT_DHCPOFFER 2 > > struct ether_vlan_header > { > @@ -212,6 +222,40 @@ virNWFilterGetIpAddrForIfname(const char > > #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 > * arg: pointer to virNWFilterIPAddrLearnReq structure > @@ -236,12 +280,13 @@ learnIPAddressThread(void *arg) > struct ether_header *ether_hdr; > struct ether_vlan_header *vlan_hdr; > virNWFilterIPAddrLearnReqPtr req = arg; > - uint32_t vmaddr = 0; > + uint32_t vmaddr = 0, bcastaddr = 0; > unsigned int ethHdrSize; > char *listen_if = (strlen(req->linkdev) != 0) ? req->linkdev > : req->ifname; > int to_ms = (strlen(req->linkdev) != 0) ? 1000 > : 0; > + int dhcp_opts_len; > char macaddr[VIR_MAC_STRING_BUFLEN]; > virBuffer buf = VIR_BUFFER_INITIALIZER; > char *filter= NULL; > @@ -382,12 +427,18 @@ learnIPAddressThread(void *arg) > sizeof(struct dhcp)) { > struct dhcp *dhcp = (struct dhcp *) > ((char *)udphdr + sizeof(udphdr)); > - if (dhcp->op == 2 /* DHCP OFFER */ && > + if (dhcp->op == 2 /* BOOTREPLY */ && > !memcmp(&dhcp->chaddr[0], > req->macaddr, > 6)) { > - vmaddr = dhcp->yiaddr; > - howDetected = DETECT_DHCP; > + dhcp_opts_len = header.len - > + (ethHdrSize + iphdr->ihl * 4 + > + sizeof(struct udphdr) + > + sizeof(struct dhcp)); > + procDHCPOpts(dhcp, dhcp_opts_len, > + &vmaddr, > + &bcastaddr, > + &howDetected); > } > } > } > > Okay, it's a bit annoying to have to gather all those protocol frame format within libvirt, but that's the simpler concerning the specific usage. Code looks okay, ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@xxxxxxxxxxxx | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/ -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list