int avahi_server_add_dns_server_address(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    const char *domain,
    AvahiDNSServerType type,
    const AvahiAddress *address,
    uint16_t port /** should be 53 */) {

    AvahiRecord *r;
    char n[64], h[64];
    AvahiEntry *a_entry, *s_entry;

    assert(s);
    assert(address);

    AVAHI_CHECK_VALIDITY(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY(s, AVAHI_PROTO_VALID(protocol) && AVAHI_PROTO_VALID(address->proto), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_USE_MULTICAST|AVAHI_PUBLISH_USE_WIDE_AREA), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY(s, type == AVAHI_DNS_SERVER_UPDATE || type == AVAHI_DNS_SERVER_RESOLVE, AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY(s, port != 0, AVAHI_ERR_INVALID_PORT);
    AVAHI_CHECK_VALIDITY(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);

    if (!domain)
        domain = s->domain_name;

    transport_flags_from_domain(s, &flags, domain);
    AVAHI_CHECK_VALIDITY(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);
    
    if (address->proto == AVAHI_PROTO_INET) {
        hexstring(h, sizeof(h), &address->data, sizeof(AvahiIPv4Address));
        snprintf(n, sizeof(n), "ip-%s.%s", h, domain);
        r = avahi_record_new_full(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, AVAHI_DEFAULT_TTL_HOST_NAME);
        r->data.a.address = address->data.ipv4;
    } else {
        hexstring(h, sizeof(h), &address->data, sizeof(AvahiIPv6Address));
        snprintf(n, sizeof(n), "ip6-%s.%s", h, domain);
        r = avahi_record_new_full(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, AVAHI_DEFAULT_TTL_HOST_NAME);
        r->data.aaaa.address = address->data.ipv6;
    }

    if (!r)
        return avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
    
    a_entry = server_add_internal(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_ALLOW_MULTIPLE, r);
    avahi_record_unref(r);

    if (!a_entry)
        return avahi_server_errno(s);
    
    if (!(s_entry = server_add_dns_server_name(s, g, interface, protocol, flags, domain, type, n, port))) {
        if (!(flags & AVAHI_PUBLISH_UPDATE))
            avahi_entry_free(s, a_entry);
        return avahi_server_errno(s);
    }

    return AVAHI_OK;
}
Beispiel #2
0
void avahi_llmnr_query_remove_for_all(AvahiServer *s, AvahiIfIndex idx, AvahiProtocol protocol, AvahiKey *key) {

	assert(s);
	assert(AVAHI_IF_VALID(idx));
	assert(AVAHI_PROTO_VALID(protocol));
	assert(key);
	
	avahi_interface_monitor_walk(s->monitor, idx, protocol, remove_llmnr_query_callback, key);
}
static int server_update_service_txt_strlst_nocopy(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    const char *name,     
    const char *type,     
    const char *domain,   
    AvahiStringList *strlst) {

    char svc_name[AVAHI_DOMAIN_NAME_MAX];
    int ret = AVAHI_OK;
    AvahiEntry *e;
    
    assert(s);
    assert(type);
    assert(name);

    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags,
                                                                AVAHI_PUBLISH_NO_COOKIE|
                                                                AVAHI_PUBLISH_USE_WIDE_AREA|
                                                                AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);

    if (!domain)
        domain = s->domain_name;

    transport_flags_from_domain(s, &flags, domain);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);

    if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0) {
        avahi_server_set_errno(s, ret);
        goto fail;
    }

    /* Add TXT record */
    if (!(flags & AVAHI_PUBLISH_NO_COOKIE))
        strlst = add_magic_cookie(s, strlst);
    
    e = server_add_txt_strlst_nocopy(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_UPDATE, AVAHI_DEFAULT_TTL, svc_name, strlst);
    strlst = NULL;

    if (!e)
        ret = avahi_server_errno(s);
    
fail:
    
    avahi_string_list_free(strlst);
    
    return ret;
}
Beispiel #4
0
AvahiSRecordBrowser *avahi_s_record_browser_new(
    AvahiServer *server,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiKey *key,
    AvahiLookupFlags flags,
    AvahiSRecordBrowserCallback callback,
    void* userdata) {

    AvahiSRecordBrowser *b;

    assert(server);
    assert(key);
    assert(callback);

    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !avahi_key_is_pattern(key), AVAHI_ERR_IS_PATTERN);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, avahi_key_is_valid(key), AVAHI_ERR_INVALID_KEY);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !(flags & AVAHI_LOOKUP_USE_WIDE_AREA) || !(flags & AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);

    if (!(b = avahi_new(AvahiSRecordBrowser, 1))) {
        avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
        return NULL;
    }

    b->dead = 0;
    b->server = server;
    b->interface = interface;
    b->protocol = protocol;
    b->key = avahi_key_ref(key);
    b->flags = flags;
    b->callback = callback;
    b->userdata = userdata;
    b->n_lookups = 0;
    AVAHI_LLIST_HEAD_INIT(AvahiSRBLookup, b->lookups);
    b->root_lookup = NULL;

    AVAHI_LLIST_PREPEND(AvahiSRecordBrowser, browser, server->record_browsers, b);

    /* The currently cached entries are scanned a bit later, and than we will start querying, too */
    b->defer_time_event = avahi_time_event_new(server->time_event_queue, NULL, defer_callback, b);
    assert(b->defer_time_event);

    return b;
}
int avahi_server_add_service_subtype(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    const char *name,        
    const char *type,        
    const char *domain,      
    const char *subtype) {

    int ret = AVAHI_OK;
    char svc_name[AVAHI_DOMAIN_NAME_MAX], ptr_name[AVAHI_DOMAIN_NAME_MAX];
    
    assert(name);
    assert(type);
    assert(subtype);

    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags, AVAHI_PUBLISH_USE_MULTICAST|AVAHI_PUBLISH_USE_WIDE_AREA), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_subtype(subtype), AVAHI_ERR_INVALID_SERVICE_SUBTYPE);

    if (!domain)
        domain = s->domain_name;

    transport_flags_from_domain(s, &flags, domain);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);

    if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0 ||
        (ret = avahi_service_name_join(ptr_name, sizeof(ptr_name), NULL, subtype, domain)) < 0) {
        avahi_server_set_errno(s, ret);
        goto fail;
    }

    if ((ret = avahi_server_add_ptr(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, ptr_name, svc_name)) < 0)
        goto fail;

fail:
    
    return ret;
}
Beispiel #6
0
static AvahiSRBLookup* lookup_new(
    AvahiSRecordBrowser *b,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiLookupFlags flags,
    AvahiKey *key) {

    AvahiSRBLookup *l;

    assert(b);
    assert(AVAHI_IF_VALID(interface));
    assert(AVAHI_PROTO_VALID(protocol));

    if (b->n_lookups >= AVAHI_LOOKUPS_PER_BROWSER_MAX)
        /* We don't like cyclic CNAMEs */
        return NULL;

    if (!(l = avahi_new(AvahiSRBLookup, 1)))
        return NULL;

    l->ref = 1;
    l->record_browser = b;
    l->interface = interface;
    l->protocol = protocol;
    l->key = avahi_key_ref(key);
    l->wide_area = NULL;
    l->multicast = NULL;
    l->llmnr = NULL;
    l->cname_lookups = NULL;
    l->flags = flags;

    transport_flags_from_domain(b->server, &l->flags, key->name);

    AVAHI_LLIST_PREPEND(AvahiSRBLookup, lookups, b->lookups, l);

    b->n_lookups ++;

    return l;
}
Beispiel #7
0
void avahi_llmnr_query_add_for_all(
		AvahiServer *s, 
		AvahiIfIndex idx, 
		AvahiProtocol protocol, 
		AvahiKey *key, 
		AvahiLLMNRQueryCallback callback, 
		void *userdata) {

		struct cbdata cbdata;

			assert(s);
			assert(callback);
			assert(AVAHI_IF_VALID(idx));
			assert(AVAHI_PROTO_VALID(protocol));
			assert(key);
	
			cbdata.callback = callback;
			cbdata.key = key;
			cbdata.userdata = userdata;
	
			avahi_interface_monitor_walk(s->monitor, idx, protocol, llmnr_query_add_callback, &cbdata);

}
Beispiel #8
0
AvahiSDomainBrowser *avahi_s_domain_browser_prepare(
    AvahiServer *server,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    const char *domain,
    AvahiDomainBrowserType type,
    AvahiLookupFlags flags,
    AvahiSDomainBrowserCallback callback,
    void* userdata) {

    static const char * const type_table[AVAHI_DOMAIN_BROWSER_MAX] = {
        "b",
        "db",
        "r",
        "dr",
        "lb"
    };

    AvahiSDomainBrowser *b;
    AvahiKey *k = NULL;
    char n[AVAHI_DOMAIN_NAME_MAX];
    int r;

    assert(server);
    assert(callback);

    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, type < AVAHI_DOMAIN_BROWSER_MAX, AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);

    if (!domain)
        domain = server->domain_name;

    if ((r = avahi_service_name_join(n, sizeof(n), type_table[type], "_dns-sd._udp", domain)) < 0) {
        avahi_server_set_errno(server, r);
        return NULL;
    }

    if (!(b = avahi_new(AvahiSDomainBrowser, 1))) {
        avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
        return NULL;
    }

    b->ref = 1;
    b->server = server;
    b->callback = callback;
    b->userdata = userdata;
    b->record_browser = NULL;
    b->type = type;
    b->all_for_now_scheduled = 0;
    b->defer_event = NULL;

    AVAHI_LLIST_PREPEND(AvahiSDomainBrowser, browser, server->domain_browsers, b);

    if (!(k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR))) {
        avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
        goto fail;
    }

    if (!(b->record_browser = avahi_s_record_browser_prepare(server, interface, protocol, k, flags, record_browser_callback, b)))
        goto fail;

    avahi_key_unref(k);

    if (type == AVAHI_DOMAIN_BROWSER_BROWSE && b->server->config.browse_domains)
        b->defer_event = avahi_time_event_new(server->time_event_queue, NULL, defer_callback, b);

    return b;

fail:

    if (k)
        avahi_key_unref(k);

    avahi_s_domain_browser_free(b);

    return NULL;
}
Beispiel #9
0
AvahiSServiceResolver *avahi_s_service_resolver_new(
    AvahiServer *server,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    const char *name,
    const char *type,
    const char *domain,
    AvahiProtocol aprotocol,
    AvahiLookupFlags flags,
    AvahiSServiceResolverCallback callback,
    void* userdata) {
    
    AvahiSServiceResolver *r;
    AvahiKey *k;
    char n[AVAHI_DOMAIN_NAME_MAX];
    int ret;
    
    assert(server);
    assert(type);
    assert(callback);

    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(aprotocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, !name || avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_NO_TXT|AVAHI_LOOKUP_NO_ADDRESS), AVAHI_ERR_INVALID_FLAGS);

    if (!domain)
        domain = server->domain_name;

    if ((ret = avahi_service_name_join(n, sizeof(n), name, type, domain)) < 0) {
        avahi_server_set_errno(server, ret);
        return NULL;
    }
    
    if (!(r = avahi_new(AvahiSServiceResolver, 1))) {
        avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
        return NULL;
    }
    
    r->server = server;
    r->service_name = avahi_strdup(name);
    r->service_type = avahi_normalize_name_strdup(type);
    r->domain_name = avahi_normalize_name_strdup(domain);
    r->callback = callback;
    r->userdata = userdata;
    r->address_protocol = aprotocol;
    r->srv_record = r->txt_record = r->address_record = NULL;
    r->srv_flags = r->txt_flags = r->address_flags = 0;
    r->interface = interface;
    r->protocol = protocol;
    r->user_flags = flags;
    r->record_browser_a = r->record_browser_aaaa = r->record_browser_srv = r->record_browser_txt = NULL;
    r->time_event = NULL;
    AVAHI_LLIST_PREPEND(AvahiSServiceResolver, resolver, server->service_resolvers, r);

    k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV);
    r->record_browser_srv = avahi_s_record_browser_new(server, interface, protocol, k, flags & ~(AVAHI_LOOKUP_NO_TXT|AVAHI_LOOKUP_NO_ADDRESS), record_browser_callback, r);
    avahi_key_unref(k);

    if (!r->record_browser_srv) {
        avahi_s_service_resolver_free(r);
        return NULL;
    }

    if (!(flags & AVAHI_LOOKUP_NO_TXT)) {
        k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT);
        r->record_browser_txt = avahi_s_record_browser_new(server, interface, protocol, k, flags & ~(AVAHI_LOOKUP_NO_TXT|AVAHI_LOOKUP_NO_ADDRESS),  record_browser_callback, r);
        avahi_key_unref(k);
        
        if (!r->record_browser_txt) {
            avahi_s_service_resolver_free(r);
            return NULL;
        }
    }

    start_timeout(r);
    
    return r;
}
AvahiSAddressResolver *avahi_s_address_resolver_new(
    AvahiServer *server,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    const AvahiAddress *address,
    AvahiLookupFlags flags,
    AvahiSAddressResolverCallback callback,
    void* userdata) {

    AvahiSAddressResolver *r;
    AvahiKey *k;
    char n[AVAHI_DOMAIN_NAME_MAX];

    assert(server);
    assert(address);
    assert(callback);

    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, address->proto == AVAHI_PROTO_INET || address->proto == AVAHI_PROTO_INET6, AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(server, AVAHI_FLAGS_VALID(flags, AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_USE_LLMNR), AVAHI_ERR_INVALID_FLAGS);

    avahi_reverse_lookup_name(address, n, sizeof(n));
    if (!(k = avahi_key_new(n, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_PTR))) {
        avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
        return NULL;
    }

    if (!(r = avahi_new(AvahiSAddressResolver, 1))) {
        avahi_server_set_errno(server, AVAHI_ERR_NO_MEMORY);
        avahi_key_unref(k);
        return NULL;
    }

    r->server = server;
    r->address = *address;
    r->callback = callback;
    r->userdata = userdata;
    r->ptr_record = NULL;
    r->interface = interface;
    r->protocol = protocol;
    r->flags = 0;
    r->retry_with_multicast = 0;
    r->retry_with_llmnr = 0;
    r->llmnr_has_record = 0;
    r->key = k;

    r->record_browser = NULL;
    AVAHI_LLIST_PREPEND(AvahiSAddressResolver, resolver, server->address_resolvers, r);

    r->time_event = NULL;

    if (!(flags & (AVAHI_LOOKUP_USE_MULTICAST|AVAHI_LOOKUP_USE_WIDE_AREA|AVAHI_LOOKUP_USE_LLMNR))) {

        if (!server->wide_area.wide_area_lookup_engine || !avahi_wide_area_has_servers(server->wide_area.wide_area_lookup_engine))
            flags |= AVAHI_LOOKUP_USE_LLMNR;
        else {
            flags |= AVAHI_LOOKUP_USE_WIDE_AREA;
            r->retry_with_llmnr = 1;
        }
        r->retry_with_multicast = 1;
    }

    r->record_browser = avahi_s_record_browser_new(server, interface, protocol, k, flags, record_browser_callback, r);

    if (!r->record_browser) {
        avahi_s_address_resolver_free(r);
        return NULL;
    }

    start_timeout(r);

    return r;
}
Beispiel #11
0
/* This function is called when 'AvahiLLMNRQuery' has been processed completely.
Based on the data we get in 'userdata', state of the 'AvahiLLMNREntryVerifier' is decided*/
static void query_callback(
    AvahiIfIndex idx,
    AvahiProtocol protocol,
    AvahiRecord *r,
    void *userdata) {
    /* Get AvahiLLMNREntryVerify object, responder address and 'T' bit info, if any*/

    AvahiVerifierData *vdata = userdata;
    int win, t_bit ;

    AvahiLLMNREntryVerify *ev;
    const AvahiAddress *address;

    win = 0;
    ev = (vdata->ev);
    address = (vdata->address);
    t_bit = (vdata->t_bit);

    /* May be by the time we come back in this function due to conflict in some other entry
    of the group this entry belongs to, this entry has already been put up in the dead state.*/
    if (ev->e->dead)
        return;

    assert(AVAHI_IF_VALID(idx));
    assert(AVAHI_PROTO_VALID(protocol));
    assert(userdata);
    assert(ev->e->type == AVAHI_ENTRY_LLMNR);
    assert(!ev->e->dead);

    /* Start comparing values.*/
    if(ev->state == AVAHI_CONFLICT) {

        /* Set by handle_response function*/
        /* There is already a conflict about this key or name is not UNIQUE */
        /* Withdraw this Entry*/
        withdraw_rrset(ev->s, ev->e->record->key);

    } else {

        if(!r && !address) {
            /* No record found for this key. Our name is unique. */
/*            char *t;
            t = avahi_record_to_string(ev->e->record);
            avahi_log_info("LLMNR Entry Verified\n %s on interface index (%d) and protocol : %s",
                            t,
                            ev->interface->hardware->index,
                            avahi_proto_to_string(ev->interface->protocol));*/

            ev->state = AVAHI_VERIFIED;

            if(ev->e->group)
                decrease_n_verify(ev);

        } else {
            /* We may have two cases now !r && address || r && !address
            r && !address when T bit is clear
            !r && address when T bit is set */

            /*  So check 'T' bit first*/
            if(!(t_bit)) {

                 /* Assert that we had a response for this key */
                assert(r);

                /*Another host has already claimed for this name and is using it.*/
                ev->state = AVAHI_CONFLICT;

                /* withdraw this entry */
                withdraw_rrset(ev->s, ev->e->record->key);

            } else {
                /* 'T' bit is set. Now we compare two IP addresses lexicographically*/
                assert(protocol == address->proto);

                /* Source IP address = which is being used by interface to join LLMNR group
                We compare that address and responder address */
                assert(ev->interface->llmnr.llmnr_joined);

                    if( (protocol == AVAHI_PROTO_INET) &&
                        (memcmp (&(ev->interface->llmnr.local_llmnr_address.data.ipv4.address), &(address->data.ipv4.address), sizeof(AvahiIPv4Address))) )
                            win = 1;
                    else /*( protocol == AVAHI_PROTO_INET6) */
                        if(memcmp( &(ev->interface->llmnr.local_llmnr_address.data.ipv6.address), &(address->data.ipv6.address), sizeof(AvahiIPv6Address)))
                            win = 1;

                    if(win) {
                        /* We can claim this name */
                        ev->state = AVAHI_ESTABLISHED;
                        decrease_n_verify(ev);

                    } else {
                        ev->state = AVAHI_CONFLICT;
                        withdraw_rrset(ev->s, ev->e->record->key);
                    }
                }
        }
    }

    ev->lq = NULL;
    return;
}
static int server_add_service_strlst_nocopy(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    const char *name,
    const char *type,
    const char *domain,
    const char *host,
    uint16_t port,
    AvahiStringList *strlst) {

    char ptr_name[AVAHI_DOMAIN_NAME_MAX], svc_name[AVAHI_DOMAIN_NAME_MAX], enum_ptr[AVAHI_DOMAIN_NAME_MAX], *h = NULL;
    AvahiRecord *r = NULL;
    int ret = AVAHI_OK;
    AvahiEntry *srv_entry = NULL, *txt_entry = NULL, *ptr_entry = NULL, *enum_entry = NULL;
    
    assert(s);
    assert(type);
    assert(name);

    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, AVAHI_FLAGS_VALID(flags,
                                                                AVAHI_PUBLISH_NO_COOKIE|
                                                                AVAHI_PUBLISH_UPDATE|
                                                                AVAHI_PUBLISH_USE_WIDE_AREA|
                                                                AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_name(name), AVAHI_ERR_INVALID_SERVICE_NAME);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, avahi_is_valid_service_type_strict(type), AVAHI_ERR_INVALID_SERVICE_TYPE);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !domain || avahi_is_valid_domain_name(domain), AVAHI_ERR_INVALID_DOMAIN_NAME);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, !host || avahi_is_valid_fqdn(host), AVAHI_ERR_INVALID_HOST_NAME);

    if (!domain)
        domain = s->domain_name;

    if (!host)
        host = s->host_name_fqdn;

    transport_flags_from_domain(s, &flags, domain);
    AVAHI_CHECK_VALIDITY_SET_RET_GOTO_FAIL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);
    
    if (!(h = avahi_normalize_name_strdup(host))) {
        ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
        goto fail;
    }

    if ((ret = avahi_service_name_join(svc_name, sizeof(svc_name), name, type, domain)) < 0 ||
        (ret = avahi_service_name_join(ptr_name, sizeof(ptr_name), NULL, type, domain)) < 0 ||
        (ret = avahi_service_name_join(enum_ptr, sizeof(enum_ptr), NULL, "_services._dns-sd._udp", domain)) < 0) {
        avahi_server_set_errno(s, ret);
        goto fail;
    }

    /* Add service enumeration PTR record */
    
    if (!(ptr_entry = server_add_ptr_internal(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, ptr_name, svc_name))) {
        ret = avahi_server_errno(s);
        goto fail;
    }

    /* Add SRV record */
    
    if (!(r = avahi_record_new_full(svc_name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_SRV, AVAHI_DEFAULT_TTL_HOST_NAME))) {
        ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
        goto fail;
    }
    
    r->data.srv.priority = 0;
    r->data.srv.weight = 0;
    r->data.srv.port = port;
    r->data.srv.name = h;
    h = NULL;
    srv_entry = server_add_internal(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE, r);
    avahi_record_unref(r);

    if (!srv_entry) {
        ret = avahi_server_errno(s);
        goto fail;
    }

    /* Add TXT record */

    if (!(flags & AVAHI_PUBLISH_NO_COOKIE))
        strlst = add_magic_cookie(s, strlst);
    
    txt_entry = server_add_txt_strlst_nocopy(s, g, interface, protocol, AVAHI_PUBLISH_UNIQUE, AVAHI_DEFAULT_TTL, svc_name, strlst);
    strlst = NULL;

    if (!txt_entry) {
        ret = avahi_server_errno(s);
        goto fail;
    }

    /* Add service type enumeration record */
    
    if (!(enum_entry = server_add_ptr_internal(s, g, interface, protocol, 0, AVAHI_DEFAULT_TTL, enum_ptr, ptr_name))) {
        ret = avahi_server_errno(s);
        goto fail;
    }

fail:
    if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) {
        if (srv_entry)
            avahi_entry_free(s, srv_entry);
        if (txt_entry)
            avahi_entry_free(s, txt_entry);
        if (ptr_entry)
            avahi_entry_free(s, ptr_entry);
        if (enum_entry)
            avahi_entry_free(s, enum_entry);
    }
    
    avahi_string_list_free(strlst);
    avahi_free(h);
    
    return ret;
}
int avahi_server_add_address(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    const char *name,
    AvahiAddress *a) {

    char n[AVAHI_DOMAIN_NAME_MAX];
    int ret = AVAHI_OK;
    AvahiEntry *entry = NULL, *reverse = NULL;
    AvahiRecord  *r;
    
    assert(s);
    assert(a);

    AVAHI_CHECK_VALIDITY(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY(s, AVAHI_PROTO_VALID(protocol) && AVAHI_PROTO_VALID(a->proto), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY(s, AVAHI_FLAGS_VALID(flags,
                                              AVAHI_PUBLISH_NO_REVERSE|
                                              AVAHI_PUBLISH_NO_ANNOUNCE|
                                              AVAHI_PUBLISH_NO_PROBE|
                                              AVAHI_PUBLISH_UPDATE|
                                              AVAHI_PUBLISH_USE_WIDE_AREA|
                                              AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY(s, !name || avahi_is_valid_fqdn(name), AVAHI_ERR_INVALID_HOST_NAME);

    /* Prepare the host naem */
    
    if (!name)
        name = s->host_name_fqdn;
    else {
        AVAHI_ASSERT_TRUE(avahi_normalize_name(name, n, sizeof(n)));
        name = n;
    }

    transport_flags_from_domain(s, &flags, name);
    AVAHI_CHECK_VALIDITY(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);
    
    /* Create the A/AAAA record */
    
    if (a->proto == AVAHI_PROTO_INET) {

        if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_A, AVAHI_DEFAULT_TTL_HOST_NAME))) {
            ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
            goto finish;
        }
        
        r->data.a.address = a->data.ipv4;
        
    } else {
        assert(a->proto == AVAHI_PROTO_INET6);
            
        if (!(r = avahi_record_new_full(name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_AAAA, AVAHI_DEFAULT_TTL_HOST_NAME))) {
            ret = avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
            goto finish;
        }
        
        r->data.aaaa.address = a->data.ipv6;
    }
        
    entry = server_add_internal(s, g, interface, protocol, (flags & ~ AVAHI_PUBLISH_NO_REVERSE) | AVAHI_PUBLISH_UNIQUE | AVAHI_PUBLISH_ALLOW_MULTIPLE, r);
    avahi_record_unref(r);

    if (!entry) {
        ret = avahi_server_errno(s);
        goto finish;
    }

    /* Create the reverse lookup entry */
    
    if (!(flags & AVAHI_PUBLISH_NO_REVERSE)) {
        char reverse_n[AVAHI_DOMAIN_NAME_MAX];
        avahi_reverse_lookup_name(a, reverse_n, sizeof(reverse_n));
            
        if (!(reverse = server_add_ptr_internal(s, g, interface, protocol, flags | AVAHI_PUBLISH_UNIQUE, AVAHI_DEFAULT_TTL_HOST_NAME, reverse_n, name))) {
            ret = avahi_server_errno(s);
            goto finish;
        }
    }
    
finish:

    if (ret != AVAHI_OK && !(flags & AVAHI_PUBLISH_UPDATE)) {
        if (entry)
            avahi_entry_free(s, entry);
        if (reverse)
            avahi_entry_free(s, reverse);
    }

    return ret;
}
static AvahiEntry * server_add_internal(
    AvahiServer *s,
    AvahiSEntryGroup *g,
    AvahiIfIndex interface,
    AvahiProtocol protocol,
    AvahiPublishFlags flags,
    AvahiRecord *r) {

    AvahiEntry *e;
    
    assert(s);
    assert(r);

    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, s->state != AVAHI_SERVER_FAILURE && s->state != AVAHI_SERVER_INVALID, AVAHI_ERR_BAD_STATE);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_IF_VALID(interface), AVAHI_ERR_INVALID_INTERFACE);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_PROTO_VALID(protocol), AVAHI_ERR_INVALID_PROTOCOL);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, AVAHI_FLAGS_VALID(
                                         flags,
                                         AVAHI_PUBLISH_NO_ANNOUNCE|
                                         AVAHI_PUBLISH_NO_PROBE|
                                         AVAHI_PUBLISH_UNIQUE|
                                         AVAHI_PUBLISH_ALLOW_MULTIPLE|
                                         AVAHI_PUBLISH_UPDATE|
                                         AVAHI_PUBLISH_USE_WIDE_AREA|
                                         AVAHI_PUBLISH_USE_MULTICAST), AVAHI_ERR_INVALID_FLAGS);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_is_valid_domain_name(r->key->name), AVAHI_ERR_INVALID_HOST_NAME);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->ttl != 0, AVAHI_ERR_INVALID_TTL);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !avahi_key_is_pattern(r->key), AVAHI_ERR_IS_PATTERN);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, avahi_record_is_valid(r), AVAHI_ERR_INVALID_RECORD);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, r->key->clazz == AVAHI_DNS_CLASS_IN, AVAHI_ERR_INVALID_DNS_CLASS);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s,
                                     (r->key->type != 0) &&
                                     (r->key->type != AVAHI_DNS_TYPE_ANY) &&
                                     (r->key->type != AVAHI_DNS_TYPE_OPT) &&
                                     (r->key->type != AVAHI_DNS_TYPE_TKEY) &&
                                     (r->key->type != AVAHI_DNS_TYPE_TSIG) &&
                                     (r->key->type != AVAHI_DNS_TYPE_IXFR) &&
                                     (r->key->type != AVAHI_DNS_TYPE_AXFR), AVAHI_ERR_INVALID_DNS_TYPE);

    transport_flags_from_domain(s, &flags, r->key->name);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, flags & AVAHI_PUBLISH_USE_MULTICAST, AVAHI_ERR_NOT_SUPPORTED);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s, !s->config.disable_publishing, AVAHI_ERR_NOT_PERMITTED);
    AVAHI_CHECK_VALIDITY_RETURN_NULL(s,
                                     !g ||
                                     (g->state != AVAHI_ENTRY_GROUP_ESTABLISHED && g->state != AVAHI_ENTRY_GROUP_REGISTERING) ||
                                     (flags & AVAHI_PUBLISH_UPDATE), AVAHI_ERR_BAD_STATE);
    
    if (flags & AVAHI_PUBLISH_UPDATE) {
        AvahiRecord *old_record;
        int is_first = 1;
        
        /* Update and existing record */

        /* Find the first matching entry */
        for (e = avahi_hashmap_lookup(s->entries_by_key, r->key); e; e = e->by_key_next) {
            if (!e->dead && e->group == g && e->interface == interface && e->protocol == protocol)
                break;

            is_first = 0;
        }

        /* Hmm, nothing found? */
        if (!e) {
            avahi_server_set_errno(s, AVAHI_ERR_NOT_FOUND);
            return NULL;
        }

        /* Update the entry */
        old_record = e->record;
        e->record = avahi_record_ref(r);
        e->flags = flags;

        /* Announce our changes when needed */
        if (!avahi_record_equal_no_ttl(old_record, r) && (!g || g->state != AVAHI_ENTRY_GROUP_UNCOMMITED)) {

            /* Remove the old entry from all caches, if needed */
            if (!(e->flags & AVAHI_PUBLISH_UNIQUE))
                avahi_goodbye_entry(s, e, 1, 0);

            /* Reannounce our updated entry */
            avahi_reannounce_entry(s, e);
        }

        /* If we were the first entry in the list, we need to update the key */
        if (is_first)
            avahi_hashmap_replace(s->entries_by_key, e->record->key, e);
        
        avahi_record_unref(old_record);

    } else {
        AvahiEntry *t;

        /* Add a new record */
    
        if (check_record_conflict(s, interface, protocol, r, flags) < 0) {
            avahi_server_set_errno(s, AVAHI_ERR_COLLISION);
            return NULL;
        }

        if (!(e = avahi_new(AvahiEntry, 1))) {
            avahi_server_set_errno(s, AVAHI_ERR_NO_MEMORY);
            return NULL;
        }
        
        e->server = s;
        e->record = avahi_record_ref(r);
        e->group = g;
        e->interface = interface;
        e->protocol = protocol;
        e->flags = flags;
        e->dead = 0;
        
        AVAHI_LLIST_HEAD_INIT(AvahiAnnouncer, e->announcers);
        
        AVAHI_LLIST_PREPEND(AvahiEntry, entries, s->entries, e);
        
        /* Insert into hash table indexed by name */
        t = avahi_hashmap_lookup(s->entries_by_key, e->record->key);
        AVAHI_LLIST_PREPEND(AvahiEntry, by_key, t, e);
        avahi_hashmap_replace(s->entries_by_key, e->record->key, t);
        
        /* Insert into group list */
        if (g)
            AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); 
        
        avahi_announce_entry(s, e);
    }

    return e;
}