Commit message: CVE-2009-0758: Reflector creates packet storm on legacy unicast traffic

Fixes rhbz #488314.
CVE: CVE-2009-0758
CWE: CWE-399
Vulnerability description: The originates_from_local_legacy_unicast_socket function in avahi-core/server.c in avahi-daemon 0.6.23 does not account for the network byte order of a port number when processing incoming multicast packets, which allows remote attackers to cause a denial of service (network bandwidth and CPU consumption) via a crafted legacy unicast mDNS query packet that triggers a multicast packet storm.

Project: avahi
File: server.c

static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const AvahiAddress *src_address, uint16_t port, const AvahiAddress *dst_address, AvahiIfIndex iface, int ttl) {
    AvahiInterface *i;
    int from_local_iface = 0;

    assert(s);
    assert(p);
    assert(src_address);
    assert(dst_address);
    assert(iface > 0);
    assert(src_address->proto == dst_address->proto);

    if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, src_address->proto)) ||
        !i->announcing) {
        avahi_log_warn("Received packet from invalid interface.");
        return;
    }

    if (port <= 0) {
        /* This fixes RHBZ #475394 */
        avahi_log_warn("Received packet from invalid source port %u.", (unsigned) port);
        return;
    }

    if (avahi_address_is_ipv4_in_ipv6(src_address))
        /* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */
        return;

    if (originates_from_local_legacy_unicast_socket(s, src_address, port))
        /* This originates from our local reflector, so let's ignore it */
        return;

    /* We don't want to reflect local traffic, so we check if this packet is generated locally. */
    if (s->config.enable_reflector)
        from_local_iface = originates_from_local_iface(s, iface, src_address, port);

    if (avahi_dns_packet_check_valid_multicast(p) < 0) {
        avahi_log_warn("Received invalid packet.");
        return;
    }

    if (avahi_dns_packet_is_query(p)) {
        int legacy_unicast = 0;

        if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT) != 0) {
            avahi_log_warn("Invalid query packet.");
            return;
        }

        if (port != AVAHI_MDNS_PORT) {
            /* Legacy Unicast */

            if ((avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) != 0 ||
                 avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT) != 0)) {
                avahi_log_warn("Invalid legacy unicast query packet.");
                return;
            }

            legacy_unicast = 1;
        }

        if (legacy_unicast)
            reflect_legacy_unicast_query_packet(s, p, i, src_address, port);

        handle_query_packet(s, p, i, src_address, port, legacy_unicast, from_local_iface);

    } else {
        char t[AVAHI_ADDRESS_STR_MAX];

        if (port != AVAHI_MDNS_PORT) {
            avahi_log_warn("Received response from host %s with invalid source port %u on interface '%s.%i'", avahi_address_snprint(t, sizeof(t), src_address), port, i->hardware->name, i->protocol);
            return;
        }

        if (ttl != 255 && s->config.check_response_ttl) {
            avahi_log_warn("Received response from host %s with invalid TTL %u on interface '%s.%i'.", avahi_address_snprint(t, sizeof(t), src_address), ttl, i->hardware->name, i->protocol);
            return;
        }

        if (!is_mdns_mcast_address(dst_address) &&
            !avahi_interface_address_on_link(i, src_address)) {

            avahi_log_warn("Received non-local response from host %s on interface '%s.%i'.", avahi_address_snprint(t, sizeof(t), src_address), i->hardware->name, i->protocol);
            return;
        }

        if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_QDCOUNT) != 0 ||
            avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) == 0 ||
            avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT) != 0) {

            avahi_log_warn("Invalid response packet from host %s.", avahi_address_snprint(t, sizeof(t), src_address));
            return;
        }

        handle_response_packet(s, p, i, src_address, from_local_iface);
    }
}

Project: avahi
File: server.c

AvahiServerConfig* avahi_server_config_init(AvahiServerConfig *c) {
    assert(c);

    memset(c, 0, sizeof(AvahiServerConfig));
    c->use_ipv6 = 1;
    c->use_ipv4 = 1;
    c->allow_interfaces = NULL;
    c->deny_interfaces = NULL;
    c->host_name = NULL;
    c->domain_name = NULL;
    c->check_response_ttl = 0;
    c->publish_hinfo = 1;
    c->publish_addresses = 1;
    c->publish_workstation = 1;
    c->publish_domain = 1;
    c->use_iff_running = 0;
    c->enable_reflector = 0;
    c->reflect_ipv = 0;
    c->add_service_cookie = 0;
    c->enable_wide_area = 0;
    c->n_wide_area_servers = 0;
    c->disallow_other_stacks = 0;
    c->browse_domains = NULL;
    c->disable_publishing = 0;
    c->allow_point_to_point = 0;
    c->publish_aaaa_on_ipv4 = 1;
    c->publish_a_on_ipv6 = 0;

    return c;
}