X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-core%2Fserver.c;h=1630b29098b85ca4a1cfd91c86cef69afc294dcb;hb=d7a2e63033dd0d2d248b4cab7bf35e78f4049354;hp=e95fcca769b6306ddad448ded8e605920c6cacde;hpb=e1f934bbe96fd8e7f3f5212b783c0d3a434d4789;p=catta diff --git a/avahi-core/server.c b/avahi-core/server.c index e95fcca..1630b29 100644 --- a/avahi-core/server.c +++ b/avahi-core/server.c @@ -28,14 +28,16 @@ #include #include #include +#include #include "server.h" #include "util.h" #include "iface.h" #include "socket.h" #include "browse.h" +#include "log.h" -#define AVAHI_HOST_RR_HOLDOFF_MSEC 1000 +#define AVAHI_HOST_RR_HOLDOFF_MSEC 2000 static void free_entry(AvahiServer*s, AvahiEntry *e) { AvahiEntry *t; @@ -160,7 +162,7 @@ void avahi_server_prepare_matching_responses(AvahiServer *s, AvahiInterface *i, g_assert(i); g_assert(k); -/* g_message("Posting responses matching [%s]", txt = avahi_key_to_string(k)); */ +/* avahi_log_debug("Posting responses matching [%s]", txt = avahi_key_to_string(k)); */ /* g_free(txt); */ if (avahi_key_is_pattern(k)) { @@ -225,16 +227,21 @@ static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface * gint cmp; n = e->by_key_next; - if (e->dead || !avahi_entry_probing(s, e, i)) + if (e->dead) continue; if ((cmp = avahi_record_lexicographical_compare(e->record, record)) == 0) { ours = TRUE; break; - } else if (cmp > 0) - won = TRUE; - else /* cmp < 0 */ - lost = TRUE; + } else { + + if (avahi_entry_probing(s, e, i)) { + if (cmp > 0) + won = TRUE; + else /* cmp < 0 */ + lost = TRUE; + } + } } t = avahi_record_to_string(record); @@ -242,9 +249,9 @@ static void incoming_probe(AvahiServer *s, AvahiRecord *record, AvahiInterface * if (!ours) { if (won) - g_message("Recieved conflicting probe [%s]. Local host won.", t); + avahi_log_debug("xxx Recieved conflicting probe [%s]. Local host won.", t); else if (lost) { - g_message("Recieved conflicting probe [%s]. Local host lost. Withdrawing.", t); + avahi_log_debug("yyy Recieved conflicting probe [%s]. Local host lost. Withdrawing.", t); withdraw_rrset(s, record->key); } } @@ -261,7 +268,7 @@ static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord * g_assert(record); -/* g_message("CHECKING FOR CONFLICT: [%s]", t); */ +/* avahi_log_debug("CHECKING FOR CONFLICT: [%s]", t); */ for (e = g_hash_table_lookup(s->entries_by_key, record->key); e; e = n) { n = e->by_key_next; @@ -271,36 +278,36 @@ static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord * /* Either our entry or the other is intended to be unique, so let's check */ - if (avahi_entry_registered(s, e, i)) { - - if (avahi_record_equal_no_ttl(e->record, record)) { - ours = TRUE; /* We have an identical record, so this is no conflict */ + if (avahi_record_equal_no_ttl(e->record, record)) { + ours = TRUE; /* We have an identical record, so this is no conflict */ + + /* Check wheter there is a TTL conflict */ + if (record->ttl <= e->record->ttl/2 && + avahi_entry_registered(s, e, i)) { + gchar *t; + /* Refresh */ + t = avahi_record_to_string(record); - /* Check wheter there is a TTL conflict */ - if (record->ttl <= e->record->ttl/2) { - gchar *t; - /* Refresh */ - t = avahi_record_to_string(record); - - g_message("Recieved record with bad TTL [%s]. Refreshing.", t); - avahi_server_prepare_matching_responses(s, i, e->record->key, FALSE); - valid = FALSE; - - g_free(t); - } + avahi_log_debug("Recieved record with bad TTL [%s]. Refreshing.", t); + avahi_server_prepare_matching_responses(s, i, e->record->key, FALSE); + valid = FALSE; + + g_free(t); + } + + /* There's no need to check the other entries of this RRset */ + break; + + } else { + + if (avahi_entry_registered(s, e, i)) { - /* There's no need to check the other entries of this RRset */ - break; - } else { /* A conflict => we have to return to probe mode */ conflict = TRUE; conflicting_entry = e; - } - } else if (avahi_entry_probing(s, e, i)) { + } else if (avahi_entry_probing(s, e, i)) { - if (!avahi_record_equal_no_ttl(record, e->record)) { - /* We are currently registering a matching record, but * someone else already claimed it, so let's * withdraw */ @@ -310,7 +317,7 @@ static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord * } } -/* g_message("ours=%i conflict=%i", ours, conflict); */ +/* avahi_log_debug("ours=%i conflict=%i", ours, conflict); */ if (!ours && conflict) { gchar *t; @@ -320,11 +327,11 @@ static gboolean handle_conflict(AvahiServer *s, AvahiInterface *i, AvahiRecord * t = avahi_record_to_string(record); if (withdraw_immediately) { - g_message("Recieved conflicting record [%s] with local record to be. Withdrawing.", t); + avahi_log_debug("Recieved conflicting record [%s] with local record to be. Withdrawing.", t); withdraw_rrset(s, record->key); } else { g_assert(conflicting_entry); - g_message("Recieved conflicting record [%s]. Resetting our record.", t); + avahi_log_debug("Recieved conflicting record [%s]. Resetting our record.", t); avahi_entry_return_to_initial_state(s, conflicting_entry, i); /* Local unique records are returned to probin @@ -374,7 +381,7 @@ void avahi_server_generate_response(AvahiServer *s, AvahiInterface *i, AvahiDnsP avahi_dns_packet_inc_field(reply, AVAHI_DNS_FIELD_ANCOUNT); else { gchar *t = avahi_record_to_string(r); - g_warning("Record [%s] not fitting in legacy unicast packet, dropping.", t); + avahi_log_warn("Record [%s] not fitting in legacy unicast packet, dropping.", t); g_free(t); } @@ -438,7 +445,7 @@ void avahi_server_generate_response(AvahiServer *s, AvahiInterface *i, AvahiDnsP avahi_dns_packet_free(reply); gchar *t = avahi_record_to_string(r); - g_warning("Record [%s] too large, doesn't fit in any packet!", t); + avahi_log_warn("Record [%s] too large, doesn't fit in any packet!", t); g_free(t); break; } else @@ -477,10 +484,22 @@ static void reflect_response(AvahiServer *s, AvahiInterface *i, AvahiRecord *r, return; for (j = s->monitor->interfaces; j; j = j->interface_next) - if (j != i) + if (j != i && (s->config.ipv_reflect || j->protocol == i->protocol)) avahi_interface_post_response(j, r, flush_cache, NULL, TRUE); } +static gpointer reflect_cache_walk_callback(AvahiCache *c, AvahiKey *pattern, AvahiCacheEntry *e, gpointer userdata) { + AvahiServer *s = userdata; + + g_assert(c); + g_assert(pattern); + g_assert(e); + g_assert(s); + + avahi_record_list_push(s->record_list, e->record, e->cache_flush, FALSE, FALSE); + return NULL; +} + static void reflect_query(AvahiServer *s, AvahiInterface *i, AvahiKey *k) { AvahiInterface *j; @@ -492,8 +511,15 @@ static void reflect_query(AvahiServer *s, AvahiInterface *i, AvahiKey *k) { return; for (j = s->monitor->interfaces; j; j = j->interface_next) - if (j != i) + if (j != i && (s->config.ipv_reflect || j->protocol == i->protocol)) { + /* Post the query to other networks */ avahi_interface_post_query(j, k, TRUE); + + /* Reply from caches of other network. This is needed to + * "work around" known answer suppression. */ + + avahi_cache_walk(j->cache, k, reflect_cache_walk_callback, s); + } } static void reflect_probe(AvahiServer *s, AvahiInterface *i, AvahiRecord *r) { @@ -507,11 +533,11 @@ static void reflect_probe(AvahiServer *s, AvahiInterface *i, AvahiRecord *r) { return; for (j = s->monitor->interfaces; j; j = j->interface_next) - if (j != i) + if (j != i && (s->config.ipv_reflect || j->protocol == i->protocol)) avahi_interface_post_probe(j, r, TRUE); } -static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast) { +static void handle_query_packet(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port, gboolean legacy_unicast) { guint n; g_assert(s); @@ -519,7 +545,7 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c g_assert(i); g_assert(a); -/* g_message("query"); */ +/* avahi_log_debug("query"); */ g_assert(avahi_record_list_empty(s->record_list)); @@ -529,11 +555,12 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c gboolean unicast_response = FALSE; if (!(key = avahi_dns_packet_consume_key(p, &unicast_response))) { - g_warning("Packet too short (1)"); + avahi_log_warn("Packet too short (1)"); goto fail; } - reflect_query(s, i, key); + if (!legacy_unicast) + reflect_query(s, i, key); avahi_query_scheduler_incoming(i->query_scheduler, key); avahi_server_prepare_matching_responses(s, i, key, unicast_response); avahi_key_unref(key); @@ -545,7 +572,7 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c gboolean unique = FALSE; if (!(record = avahi_dns_packet_consume_record(p, &unique))) { - g_warning("Packet too short (2)"); + avahi_log_warn("Packet too short (2)"); goto fail; } @@ -563,7 +590,7 @@ static void handle_query(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, c gboolean unique = FALSE; if (!(record = avahi_dns_packet_consume_record(p, &unique))) { - g_warning("Packet too short (3)"); + avahi_log_warn("Packet too short (3)"); goto fail; } @@ -585,7 +612,7 @@ fail: } -static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a) { +static void handle_response_packet(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a) { guint n; g_assert(s); @@ -593,7 +620,7 @@ static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i g_assert(i); g_assert(a); -/* g_message("response"); */ +/* avahi_log_debug("response"); */ for (n = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) + avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT); n > 0; n--) { @@ -602,13 +629,13 @@ static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i /* gchar *txt; */ if (!(record = avahi_dns_packet_consume_record(p, &cache_flush))) { - g_warning("Packet too short (4)"); + avahi_log_warn("Packet too short (4)"); break; } if (record->key->type != AVAHI_DNS_TYPE_ANY) { -/* g_message("Handling response: %s", txt = avahi_record_to_string(record)); */ +/* avahi_log_debug("Handling response: %s", txt = avahi_record_to_string(record)); */ /* g_free(txt); */ if (handle_conflict(s, i, record, cache_flush, a)) { @@ -622,7 +649,182 @@ static void handle_response(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i } } -static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, struct sockaddr *sa, gint iface, gint ttl) { +static AvahiLegacyUnicastReflectSlot* allocate_slot(AvahiServer *s) { + guint n, index = (guint) -1; + AvahiLegacyUnicastReflectSlot *slot; + + g_assert(s); + + if (!s->legacy_unicast_reflect_slots) + s->legacy_unicast_reflect_slots = g_new0(AvahiLegacyUnicastReflectSlot*, AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS); + + for (n = 0; n < AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS; n++, s->legacy_unicast_reflect_id++) { + index = s->legacy_unicast_reflect_id % AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS; + + if (!s->legacy_unicast_reflect_slots[index]) + break; + } + + if (index == (guint) -1 || s->legacy_unicast_reflect_slots[index]) + return NULL; + + slot = s->legacy_unicast_reflect_slots[index] = g_new(AvahiLegacyUnicastReflectSlot, 1); + slot->id = s->legacy_unicast_reflect_id++; + slot->server = s; + return slot; +} + +static void deallocate_slot(AvahiServer *s, AvahiLegacyUnicastReflectSlot *slot) { + guint index; + + g_assert(s); + g_assert(slot); + + index = slot->id % AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS; + + g_assert(s->legacy_unicast_reflect_slots[index] == slot); + + avahi_time_event_queue_remove(s->time_event_queue, slot->time_event); + + g_free(slot); + s->legacy_unicast_reflect_slots[index] = NULL; +} + +static void free_slots(AvahiServer *s) { + guint index; + g_assert(s); + + if (!s->legacy_unicast_reflect_slots) + return; + + for (index = 0; index < AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS; index ++) + if (s->legacy_unicast_reflect_slots[index]) + deallocate_slot(s, s->legacy_unicast_reflect_slots[index]); + + g_free(s->legacy_unicast_reflect_slots); + s->legacy_unicast_reflect_slots = NULL; +} + +static AvahiLegacyUnicastReflectSlot* find_slot(AvahiServer *s, guint16 id) { + guint index; + + g_assert(s); + + if (!s->legacy_unicast_reflect_slots) + return NULL; + + index = id % AVAHI_MAX_LEGACY_UNICAST_REFLECT_SLOTS; + + if (!s->legacy_unicast_reflect_slots[index] || s->legacy_unicast_reflect_slots[index]->id != id) + return NULL; + + return s->legacy_unicast_reflect_slots[index]; +} + +static void legacy_unicast_reflect_slot_timeout(AvahiTimeEvent *e, void *userdata) { + AvahiLegacyUnicastReflectSlot *slot = userdata; + + g_assert(e); + g_assert(slot); + g_assert(slot->time_event == e); + + deallocate_slot(slot->server, slot); +} + +static void reflect_legacy_unicast_query_packet(AvahiServer *s, AvahiDnsPacket *p, AvahiInterface *i, const AvahiAddress *a, guint16 port) { + AvahiLegacyUnicastReflectSlot *slot; + AvahiInterface *j; + + g_assert(s); + g_assert(p); + g_assert(i); + g_assert(a); + g_assert(port > 0); + g_assert(i->protocol == a->family); + + if (!s->config.enable_reflector) + return; + +/* avahi_log_debug("legacy unicast reflectr"); */ + + /* Reflecting legacy unicast queries is a little more complicated + than reflecting normal queries, since we must route the + responses back to the right client. Therefore we must store + some information for finding the right client contact data for + response packets. In contrast to normal queries legacy + unicast query and response packets are reflected untouched and + are not reassembled into larger packets */ + + if (!(slot = allocate_slot(s))) { + /* No slot available, we drop this legacy unicast query */ + avahi_log_warn("No slot available for legacy unicast reflection, dropping query packet."); + return; + } + + slot->original_id = avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ID); + slot->address = *a; + slot->port = port; + slot->interface = i->hardware->index; + + avahi_elapse_time(&slot->elapse_time, 2000, 0); + slot->time_event = avahi_time_event_queue_add(s->time_event_queue, &slot->elapse_time, legacy_unicast_reflect_slot_timeout, slot); + + /* Patch the packet with our new locally generatedt id */ + avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ID, slot->id); + + for (j = s->monitor->interfaces; j; j = j->interface_next) + if (avahi_interface_relevant(j) && + j != i && + (s->config.ipv_reflect || j->protocol == i->protocol)) { + + if (j->protocol == AF_INET && s->fd_legacy_unicast_ipv4 >= 0) { + avahi_send_dns_packet_ipv4(s->fd_legacy_unicast_ipv4, j->hardware->index, p, NULL, 0); + } else if (j->protocol == AF_INET6 && s->fd_legacy_unicast_ipv6 >= 0) + avahi_send_dns_packet_ipv6(s->fd_legacy_unicast_ipv6, j->hardware->index, p, NULL, 0); + } + + /* Reset the id */ + avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ID, slot->original_id); +} + +static gboolean originates_from_local_legacy_unicast_socket(AvahiServer *s, const struct sockaddr *sa) { + AvahiAddress a; + g_assert(s); + g_assert(sa); + + if (!s->config.enable_reflector) + return FALSE; + + avahi_address_from_sockaddr(sa, &a); + + if (!avahi_address_is_local(s->monitor, &a)) + return FALSE; + + if (sa->sa_family == AF_INET && s->fd_legacy_unicast_ipv4 >= 0) { + struct sockaddr_in lsa; + socklen_t l = sizeof(lsa); + + if (getsockname(s->fd_legacy_unicast_ipv4, &lsa, &l) != 0) + avahi_log_warn("getsockname(): %s", strerror(errno)); + else + return lsa.sin_port == ((struct sockaddr_in*) sa)->sin_port; + + } + + if (sa->sa_family == AF_INET6 && s->fd_legacy_unicast_ipv6 >= 0) { + struct sockaddr_in6 lsa; + socklen_t l = sizeof(lsa); + + if (getsockname(s->fd_legacy_unicast_ipv6, &lsa, &l) != 0) + avahi_log_warn("getsockname(): %s", strerror(errno)); + else + return lsa.sin6_port == ((struct sockaddr_in6*) sa)->sin6_port; + } + + return FALSE; +} + +static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sockaddr *sa, gint iface, gint ttl) { AvahiInterface *i; AvahiAddress a; guint16 port; @@ -634,37 +836,33 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, struct sockaddr * if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, sa->sa_family)) || !avahi_interface_relevant(i)) { - g_warning("Recieved packet from invalid interface."); + avahi_log_warn("Recieved packet from invalid interface."); return; } -/* g_message("new packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol); */ - - if (sa->sa_family == AF_INET6) { - static const guint8 ipv4_in_ipv6[] = { - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF }; +/* avahi_log_debug("new packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol); */ + port = avahi_port_from_sockaddr(sa); + avahi_address_from_sockaddr(sa, &a); + + if (avahi_address_is_ipv4_in_ipv6(&a)) /* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */ + return; - if (memcmp(((struct sockaddr_in6*) sa)->sin6_addr.s6_addr, ipv4_in_ipv6, sizeof(ipv4_in_ipv6)) == 0) - return; - } + if (originates_from_local_legacy_unicast_socket(s, sa)) + /* This originates from our local reflector, so let's ignore it */ + return; if (avahi_dns_packet_check_valid(p) < 0) { - g_warning("Recieved invalid packet."); + avahi_log_warn("Recieved invalid packet."); return; } - port = avahi_port_from_sockaddr(sa); - avahi_address_from_sockaddr(sa, &a); - if (avahi_dns_packet_is_query(p)) { gboolean legacy_unicast = FALSE; if (avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ARCOUNT) != 0) { - g_warning("Invalid query packet."); + avahi_log_warn("Invalid query packet."); return; } @@ -673,25 +871,28 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, struct sockaddr * if ((avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ANCOUNT) != 0 || avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_NSCOUNT) != 0)) { - g_warning("Invalid legacy unicast query packet."); + avahi_log_warn("Invalid legacy unicast query packet."); return; } legacy_unicast = TRUE; } - handle_query(s, p, i, &a, port, legacy_unicast); + if (legacy_unicast) + reflect_legacy_unicast_query_packet(s, p, i, &a, port); + + handle_query_packet(s, p, i, &a, port, legacy_unicast); -/* g_message("Handled query"); */ +/* avahi_log_debug("Handled query"); */ } else { if (port != AVAHI_MDNS_PORT) { - g_warning("Recieved repsonse with invalid source port %u on interface '%s.%i'", port, i->hardware->name, i->protocol); + avahi_log_warn("Recieved repsonse with invalid source port %u on interface '%s.%i'", port, i->hardware->name, i->protocol); return; } if (ttl != 255) { - g_warning("Recieved response with invalid TTL %u on interface '%s.%i'.", ttl, i->hardware->name, i->protocol); + avahi_log_warn("Recieved response with invalid TTL %u on interface '%s.%i'.", ttl, i->hardware->name, i->protocol); if (s->config.check_response_ttl) return; } @@ -699,15 +900,65 @@ static void dispatch_packet(AvahiServer *s, AvahiDnsPacket *p, struct sockaddr * 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) { - g_warning("Invalid response packet."); + avahi_log_warn("Invalid response packet."); return; } - handle_response(s, p, i, &a); -/* g_message("Handled response"); */ + handle_response_packet(s, p, i, &a); +/* avahi_log_debug("Handled response"); */ } } +static void dispatch_legacy_unicast_packet(AvahiServer *s, AvahiDnsPacket *p, const struct sockaddr *sa, gint iface, gint ttl) { + AvahiInterface *i, *j; + AvahiAddress a; + guint16 port; + AvahiLegacyUnicastReflectSlot *slot; + + g_assert(s); + g_assert(p); + g_assert(sa); + g_assert(iface > 0); + + if (!(i = avahi_interface_monitor_get_interface(s->monitor, iface, sa->sa_family)) || + !avahi_interface_relevant(i)) { + avahi_log_warn("Recieved packet from invalid interface."); + return; + } + +/* avahi_log_debug("new legacy unicast packet recieved on interface '%s.%i'.", i->hardware->name, i->protocol); */ + + port = avahi_port_from_sockaddr(sa); + avahi_address_from_sockaddr(sa, &a); + + if (avahi_address_is_ipv4_in_ipv6(&a)) + /* This is an IPv4 address encapsulated in IPv6, so let's ignore it. */ + return; + + if (avahi_dns_packet_check_valid(p) < 0 || avahi_dns_packet_is_query(p)) { + avahi_log_warn("Recieved invalid packet."); + return; + } + + if (!(slot = find_slot(s, avahi_dns_packet_get_field(p, AVAHI_DNS_FIELD_ID)))) { + avahi_log_warn("Recieved legacy unicast response with unknown id"); + return; + } + + if (!(j = avahi_interface_monitor_get_interface(s->monitor, slot->interface, slot->address.family)) || + !avahi_interface_relevant(j)) + return; + + /* Patch the original ID into this response */ + avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ID, slot->original_id); + + /* Forward the response to the correct client */ + avahi_interface_send_packet_unicast(j, p, &slot->address, slot->port); + + /* Undo changes to packet */ + avahi_dns_packet_set_field(p, AVAHI_DNS_FIELD_ID, slot->id); +} + static void work(AvahiServer *s) { struct sockaddr_in6 sa6; struct sockaddr_in sa; @@ -717,19 +968,33 @@ static void work(AvahiServer *s) { g_assert(s); - if (s->pollfd_ipv4.revents & G_IO_IN) { + if (s->fd_ipv4 >= 0 && (s->pollfd_ipv4.revents & G_IO_IN)) { if ((p = avahi_recv_dns_packet_ipv4(s->fd_ipv4, &sa, &iface, &ttl))) { dispatch_packet(s, p, (struct sockaddr*) &sa, iface, ttl); avahi_dns_packet_free(p); } } - if (s->pollfd_ipv6.revents & G_IO_IN) { + if (s->fd_ipv6 >= 0 && (s->pollfd_ipv6.revents & G_IO_IN)) { if ((p = avahi_recv_dns_packet_ipv6(s->fd_ipv6, &sa6, &iface, &ttl))) { dispatch_packet(s, p, (struct sockaddr*) &sa6, iface, ttl); avahi_dns_packet_free(p); } } + + if (s->fd_legacy_unicast_ipv4 >= 0 && (s->pollfd_legacy_unicast_ipv4.revents & G_IO_IN)) { + if ((p = avahi_recv_dns_packet_ipv4(s->fd_legacy_unicast_ipv4, &sa, &iface, &ttl))) { + dispatch_legacy_unicast_packet(s, p, (struct sockaddr*) &sa, iface, ttl); + avahi_dns_packet_free(p); + } + } + + if (s->fd_legacy_unicast_ipv6 >= 0 && (s->pollfd_legacy_unicast_ipv6.revents & G_IO_IN)) { + if ((p = avahi_recv_dns_packet_ipv6(s->fd_legacy_unicast_ipv6, &sa6, &iface, &ttl))) { + dispatch_legacy_unicast_packet(s, p, (struct sockaddr*) &sa6, iface, ttl); + avahi_dns_packet_free(p); + } + } } static gboolean prepare_func(GSource *source, gint *timeout) { @@ -742,12 +1007,23 @@ static gboolean prepare_func(GSource *source, gint *timeout) { static gboolean check_func(GSource *source) { AvahiServer* s; + gushort revents = 0; + g_assert(source); s = *((AvahiServer**) (((guint8*) source) + sizeof(GSource))); g_assert(s); + + if (s->fd_ipv4 >= 0) + revents |= s->pollfd_ipv4.revents; + if (s->fd_ipv6 >= 0) + revents |= s->pollfd_ipv6.revents; + if (s->fd_legacy_unicast_ipv4 >= 0) + revents |= s->pollfd_legacy_unicast_ipv4.revents; + if (s->fd_legacy_unicast_ipv6 >= 0) + revents |= s->pollfd_legacy_unicast_ipv6.revents; - return (s->pollfd_ipv4.revents | s->pollfd_ipv6.revents) & (G_IO_IN | G_IO_HUP | G_IO_ERR); + return !!(revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)); } static gboolean dispatch_func(GSource *source, GSourceFunc callback, gpointer user_data) { @@ -917,7 +1193,7 @@ static void delayed_register_stuff(AvahiServer *s) { s->register_time_event = avahi_time_event_queue_add(s->time_event_queue, &tv, register_time_event_callback, s); } -void avahi_server_set_host_name(AvahiServer *s, const gchar *host_name) { +gint avahi_server_set_host_name(AvahiServer *s, const gchar *host_name) { g_assert(s); g_assert(host_name); @@ -930,9 +1206,10 @@ void avahi_server_set_host_name(AvahiServer *s, const gchar *host_name) { update_fqdn(s); delayed_register_stuff(s); + return 0; } -void avahi_server_set_domain_name(AvahiServer *s, const gchar *domain_name) { +gint avahi_server_set_domain_name(AvahiServer *s, const gchar *domain_name) { g_assert(s); g_assert(domain_name); @@ -944,6 +1221,19 @@ void avahi_server_set_domain_name(AvahiServer *s, const gchar *domain_name) { update_fqdn(s); delayed_register_stuff(s); + return 0; +} + + +static void prepare_pollfd(AvahiServer *s, GPollFD *pollfd, gint fd) { + g_assert(s); + g_assert(pollfd); + g_assert(fd >= 0); + + memset(pollfd, 0, sizeof(GPollFD)); + pollfd->fd = fd; + pollfd->events = G_IO_IN|G_IO_ERR|G_IO_HUP; + g_source_add_poll(s->source, pollfd); } AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc, AvahiServerCallback callback, gpointer userdata) { @@ -978,10 +1268,13 @@ AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc, Avah } if (s->fd_ipv4 < 0 && s->config.use_ipv4) - g_message("Failed to create IPv4 socket, proceeding in IPv6 only mode"); + avahi_log_debug("Failed to create IPv4 socket, proceeding in IPv6 only mode"); else if (s->fd_ipv6 < 0 && s->config.use_ipv6) - g_message("Failed to create IPv6 socket, proceeding in IPv4 only mode"); - + avahi_log_debug("Failed to create IPv6 socket, proceeding in IPv4 only mode"); + + s->fd_legacy_unicast_ipv4 = s->fd_ipv4 >= 0 && s->config.enable_reflector ? avahi_open_legacy_unicast_socket_ipv4() : -1; + s->fd_legacy_unicast_ipv6 = s->fd_ipv6 >= 0 && s->config.enable_reflector ? avahi_open_legacy_unicast_socket_ipv6() : -1; + if (c) g_main_context_ref(s->context = c); else @@ -991,16 +1284,15 @@ AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc, Avah s->source = g_source_new(&source_funcs, sizeof(GSource) + sizeof(AvahiServer*)); *((AvahiServer**) (((guint8*) s->source) + sizeof(GSource))) = s; - memset(&s->pollfd_ipv4, 0, sizeof(s->pollfd_ipv4)); - s->pollfd_ipv4.fd = s->fd_ipv4; - s->pollfd_ipv4.events = G_IO_IN|G_IO_ERR|G_IO_HUP; - g_source_add_poll(s->source, &s->pollfd_ipv4); + if (s->fd_ipv4 >= 0) + prepare_pollfd(s, &s->pollfd_ipv4, s->fd_ipv4); + if (s->fd_ipv6 >= 0) + prepare_pollfd(s, &s->pollfd_ipv6, s->fd_ipv6); + if (s->fd_legacy_unicast_ipv4 >= 0) + prepare_pollfd(s, &s->pollfd_legacy_unicast_ipv4, s->fd_legacy_unicast_ipv4); + if (s->fd_legacy_unicast_ipv6 >= 0) + prepare_pollfd(s, &s->pollfd_legacy_unicast_ipv6, s->fd_legacy_unicast_ipv6); - memset(&s->pollfd_ipv6, 0, sizeof(s->pollfd_ipv6)); - s->pollfd_ipv6.fd = s->fd_ipv6; - s->pollfd_ipv6.events = G_IO_IN|G_IO_ERR|G_IO_HUP; - g_source_add_poll(s->source, &s->pollfd_ipv6); - g_source_attach(s->source, s->context); s->callback = callback; @@ -1019,6 +1311,9 @@ AvahiServer *avahi_server_new(GMainContext *c, const AvahiServerConfig *sc, Avah AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, s->service_browsers); AVAHI_LLIST_HEAD_INIT(AvahiServiceResolver, s->service_resolvers); + s->legacy_unicast_reflect_slots = NULL; + s->legacy_unicast_reflect_id = 0; + /* Get host name */ s->host_name = s->config.host_name ? avahi_normalize_name(s->config.host_name) : avahi_get_host_name(); s->host_name[strcspn(s->host_name, ".")] = 0; @@ -1056,6 +1351,8 @@ void avahi_server_free(AvahiServer* s) { while (s->groups) free_group(s, s->groups); + free_slots(s); + while (s->host_name_resolvers) avahi_host_name_resolver_free(s->host_name_resolvers); while (s->address_resolvers) @@ -1084,6 +1381,10 @@ void avahi_server_free(AvahiServer* s) { close(s->fd_ipv4); if (s->fd_ipv6 >= 0) close(s->fd_ipv6); + if (s->fd_legacy_unicast_ipv4 >= 0) + close(s->fd_legacy_unicast_ipv4); + if (s->fd_legacy_unicast_ipv6 >= 0) + close(s->fd_legacy_unicast_ipv6); g_free(s->host_name); g_free(s->domain_name); @@ -1098,7 +1399,7 @@ void avahi_server_free(AvahiServer* s) { g_free(s); } -void avahi_server_add( +gint avahi_server_add( AvahiServer *s, AvahiEntryGroup *g, gint interface, @@ -1135,7 +1436,10 @@ void avahi_server_add( AVAHI_LLIST_PREPEND(AvahiEntry, by_group, g->entries, e); avahi_announce_entry(s, e); + + return 0; } + const AvahiRecord *avahi_server_iterate(AvahiServer *s, AvahiEntryGroup *g, void **state) { AvahiEntry **e = (AvahiEntry**) state; g_assert(s); @@ -1174,7 +1478,7 @@ void avahi_server_dump(AvahiServer *s, FILE *f) { avahi_dump_caches(s->monitor, f); } -void avahi_server_add_ptr( +gint avahi_server_add_ptr( AvahiServer *s, AvahiEntryGroup *g, gint interface, @@ -1191,9 +1495,10 @@ void avahi_server_add_ptr( r->data.ptr.name = avahi_normalize_name(dest); avahi_server_add(s, g, interface, protocol, flags, r); avahi_record_unref(r); + return 0; } -void avahi_server_add_address( +gint avahi_server_add_address( AvahiServer *s, AvahiEntryGroup *g, gint interface, @@ -1240,9 +1545,11 @@ void avahi_server_add_address( } g_free(n); + + return 0; } -void avahi_server_add_text_strlst( +gint avahi_server_add_text_strlst( AvahiServer *s, AvahiEntryGroup *g, gint interface, @@ -1259,9 +1566,11 @@ void avahi_server_add_text_strlst( r->data.txt.string_list = strlst; avahi_server_add(s, g, interface, protocol, flags, r); avahi_record_unref(r); + + return 0; } -void avahi_server_add_text_va( +gint avahi_server_add_text_va( AvahiServer *s, AvahiEntryGroup *g, gint interface, @@ -1273,9 +1582,10 @@ void avahi_server_add_text_va( g_assert(s); avahi_server_add_text_strlst(s, g, interface, protocol, flags, name, avahi_string_list_new_va(va)); + return 0; } -void avahi_server_add_text( +gint avahi_server_add_text( AvahiServer *s, AvahiEntryGroup *g, gint interface, @@ -1291,6 +1601,8 @@ void avahi_server_add_text( va_start(va, name); avahi_server_add_text_va(s, g, interface, protocol, flags, name, va); va_end(va); + + return 0; } static void escape_service_name(gchar *d, guint size, const gchar *s) { @@ -1315,7 +1627,7 @@ static void escape_service_name(gchar *d, guint size, const gchar *s) { *(d++) = 0; } -void avahi_server_add_service_strlst( +gint avahi_server_add_service_strlst( AvahiServer *s, AvahiEntryGroup *g, gint interface, @@ -1362,9 +1674,11 @@ void avahi_server_add_service_strlst( snprintf(enum_ptr, sizeof(enum_ptr), "_services._dns-sd._udp.%s", domain); avahi_server_add_ptr(s, g, interface, protocol, AVAHI_ENTRY_NULL, enum_ptr, ptr_name); + + return 0; } -void avahi_server_add_service_va( +gint avahi_server_add_service_va( AvahiServer *s, AvahiEntryGroup *g, gint interface, @@ -1381,9 +1695,10 @@ void avahi_server_add_service_va( g_assert(name); avahi_server_add_service_strlst(s, g, interface, protocol, type, name, domain, host, port, avahi_string_list_new_va(va)); + return 0; } -void avahi_server_add_service( +gint avahi_server_add_service( AvahiServer *s, AvahiEntryGroup *g, gint interface, @@ -1404,6 +1719,7 @@ void avahi_server_add_service( va_start(va, port); avahi_server_add_service_va(s, g, interface, protocol, type, name, domain, host, port, va); va_end(va); + return 0; } static void post_query_callback(AvahiInterfaceMonitor *m, AvahiInterface *i, gpointer userdata) { @@ -1472,16 +1788,18 @@ void avahi_entry_group_free(AvahiEntryGroup *g) { g->server->need_entry_cleanup = TRUE; } -void avahi_entry_group_commit(AvahiEntryGroup *g) { +gint avahi_entry_group_commit(AvahiEntryGroup *g) { g_assert(g); g_assert(!g->dead); if (g->state != AVAHI_ENTRY_GROUP_UNCOMMITED) - return; + return -1; avahi_entry_group_change_state(g, AVAHI_ENTRY_GROUP_REGISTERING); avahi_announce_group(g->server, g); avahi_entry_group_check_probed(g, FALSE); + + return 0; } gboolean avahi_entry_commited(AvahiEntry *e) { @@ -1562,6 +1880,8 @@ AvahiServerConfig* avahi_server_config_init(AvahiServerConfig *c) { c->announce_domain = TRUE; c->use_iff_running = FALSE; c->enable_reflector = FALSE; + c->ipv_reflect = FALSE; + c->register_workstation = TRUE; return c; }