{
        struct iphdr *iph = nh;
        uint16_t proto = cfg_encap ? IPPROTO_UDP : cfg_proto;
+       uint16_t ip_len;
 
        if (len < sizeof(*iph) || iph->protocol != proto)
                return -1;
 
+       ip_len = ntohs(iph->tot_len);
+       if (ip_len > len || ip_len < sizeof(*iph))
+               return -1;
+
+       len = ip_len;
        iph_addr_p = &iph->saddr;
        if (proto == IPPROTO_TCP)
                return recv_verify_packet_tcp(iph + 1, len - sizeof(*iph));
 {
        struct ipv6hdr *ip6h = nh;
        uint16_t proto = cfg_encap ? IPPROTO_UDP : cfg_proto;
+       uint16_t ip_len;
 
        if (len < sizeof(*ip6h) || ip6h->nexthdr != proto)
                return -1;
 
+       ip_len = ntohs(ip6h->payload_len);
+       if (ip_len > len - sizeof(*ip6h))
+               return -1;
+
+       len = ip_len;
        iph_addr_p = &ip6h->saddr;
 
        if (proto == IPPROTO_TCP)
-               return recv_verify_packet_tcp(ip6h + 1, len - sizeof(*ip6h));
+               return recv_verify_packet_tcp(ip6h + 1, len);
        else
-               return recv_verify_packet_udp(ip6h + 1, len - sizeof(*ip6h));
+               return recv_verify_packet_udp(ip6h + 1, len);
 }
 
 /* return whether auxdata includes TP_STATUS_CSUM_VALID */