[libvirt] [PATCH] nwfilter: Process DHCP option to determine whether packet is a DHCP_OFFER

Daniel Veillard veillard at redhat.com
Fri Apr 9 19:50:21 UTC 2010


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 at us.ibm.com>
> 
> ---
>  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 at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/




More information about the libvir-list mailing list