From e8edcf439d2ce1593af11c357893681b6b3c0bb4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 10 Sep 2005 00:22:30 +0000 Subject: * add magic identification cookies to service TXT records automatically * add an API to query the local service cookie * add a DBUS interface to query the local service cookie * wrap that in avahi-client git-svn-id: file:///home/lennart/svn/public/avahi/trunk@555 941a03a8-eaeb-0310-b9a0-b1bbd8fe43fe --- avahi-client/client-test.c | 4 ++++ avahi-client/client.c | 52 +++++++++++++++++++++++++++++++++++++++++- avahi-client/client.h | 3 +++ avahi-client/internal.h | 2 ++ avahi-common/defs.h | 9 ++++++++ avahi-core/core.h | 4 ++++ avahi-core/server.c | 29 +++++++++++++++++++++++ avahi-core/server.h | 2 ++ avahi-daemon/Server.introspect | 4 ++++ avahi-daemon/dbus-protocol.c | 20 ++++++++++++++++ avahi-daemon/main.c | 2 +- configure.ac | 6 ++--- docs/TODO | 2 +- 13 files changed, 133 insertions(+), 6 deletions(-) diff --git a/avahi-client/client-test.c b/avahi-client/client-test.c index a65a925..96c9f1e 100644 --- a/avahi-client/client-test.c +++ b/avahi-client/client-test.c @@ -164,6 +164,7 @@ int main (int argc, char *argv[]) { AvahiHostNameResolver *hnr; const char *ret; int error; + uint32_t cookie; struct timeval tv; simple_poll = avahi_simple_poll_new(); @@ -188,6 +189,9 @@ int main (int argc, char *argv[]) { ret = avahi_client_get_host_name_fqdn (avahi); printf("FQDN: %s (Error Return: %s)\n", ret, ret ? "OK" : avahi_strerror(avahi_client_errno(avahi))); + cookie = avahi_client_get_local_service_cookie(avahi); + printf("Local service cookie: %u (Error Return: %s)\n", cookie, cookie != AVAHI_SERVICE_COOKIE_INVALID ? "OK" : avahi_strerror(avahi_client_errno(avahi))); + group = avahi_entry_group_new (avahi, avahi_entry_group_callback, "omghai"); printf("Creating entry group: %s\n", group ? "OK" : avahi_strerror(avahi_client_errno (avahi))); diff --git a/avahi-client/client.c b/avahi-client/client.c index b536beb..31bfcdc 100644 --- a/avahi-client/client.c +++ b/avahi-client/client.c @@ -303,7 +303,8 @@ AvahiClient *avahi_client_new(const AvahiPoll *poll_api, AvahiClientCallback cal client->host_name_fqdn = NULL; client->domain_name = NULL; client->version_string = NULL; - + client->local_service_cookie_valid = 0; + AVAHI_LLIST_HEAD_INIT(AvahiEntryGroup, client->groups); AVAHI_LLIST_HEAD_INIT(AvahiDomainBrowser, client->domain_browsers); AVAHI_LLIST_HEAD_INIT(AvahiServiceBrowser, client->service_browsers); @@ -594,3 +595,52 @@ fail: return r; } +uint32_t avahi_client_get_local_service_cookie(AvahiClient *client) { + DBusMessage *message = NULL, *reply = NULL; + DBusError error; + assert(client); + + if (client->state == AVAHI_CLIENT_DISCONNECTED) { + avahi_client_set_errno(client, AVAHI_ERR_BAD_STATE); + return AVAHI_SERVICE_COOKIE_INVALID; + } + + if (client->local_service_cookie_valid) + return client->local_service_cookie; + + dbus_error_init (&error); + + if (!(message = dbus_message_new_method_call(AVAHI_DBUS_NAME, AVAHI_DBUS_PATH_SERVER, AVAHI_DBUS_INTERFACE_SERVER, "GetLocalServiceCookie"))) { + avahi_client_set_errno(client, AVAHI_ERR_NO_MEMORY); + goto fail; + } + + reply = dbus_connection_send_with_reply_and_block (client->bus, message, -1, &error); + + if (!reply || dbus_error_is_set (&error)) + goto fail; + + if (!dbus_message_get_args (reply, &error, DBUS_TYPE_UINT32, &client->local_service_cookie, DBUS_TYPE_INVALID) || + dbus_error_is_set (&error)) + goto fail; + + dbus_message_unref(message); + dbus_message_unref(reply); + + client->local_service_cookie_valid = 1; + return client->local_service_cookie; + +fail: + + if (message) + dbus_message_unref(message); + if (reply) + dbus_message_unref(reply); + + if (dbus_error_is_set(&error)) { + avahi_client_set_dbus_error(client, &error); + dbus_error_free(&error); + } + + return AVAHI_SERVICE_COOKIE_INVALID; +} diff --git a/avahi-client/client.h b/avahi-client/client.h index 2d8f41b..f92f4bf 100644 --- a/avahi-client/client.h +++ b/avahi-client/client.h @@ -317,6 +317,9 @@ AvahiClient* avahi_address_resolver_get_client (AvahiAddressResolver *); /** Free a AvahiAddressResolver resolver object */ int avahi_address_resolver_free(AvahiAddressResolver *r); +/** Return the local service cookie. returns AVAHI_SERVICE_COOKIE_INVALID on failure. */ +uint32_t avahi_client_get_local_service_cookie(AvahiClient *client); + #ifndef DOXYGEN_SHOULD_SKIP_THIS AVAHI_C_DECL_END #endif diff --git a/avahi-client/internal.h b/avahi-client/internal.h index b826175..b05835f 100644 --- a/avahi-client/internal.h +++ b/avahi-client/internal.h @@ -33,6 +33,8 @@ struct AvahiClient { /* Cache for some seldom changing server data */ char *version_string, *host_name, *host_name_fqdn, *domain_name; + uint32_t local_service_cookie; + int local_service_cookie_valid; AvahiClientCallback callback; void *userdata; diff --git a/avahi-common/defs.h b/avahi-common/defs.h index 1475a43..b973b0c 100644 --- a/avahi-common/defs.h +++ b/avahi-common/defs.h @@ -172,6 +172,15 @@ typedef enum { AVAHI_SERVER_COLLISION /**< There is a collision with a host RR. All host RRs have been withdrawn, the user should set a new host name via avahi_server_set_host_name() */ } AvahiServerState; +/** For every service a special TXT item is implicitly added, which + * contains a random cookie which is private to the local daemon. This + * can be used by clients to determine if two services on two + * different subnets are effectively the same. */ +#define AVAHI_SERVICE_COOKIE "org.freedesktop.Avahi.cookie" + +/** In invalid cookie as special value */ +#define AVAHI_SERVICE_COOKIE_INVALID (0) + #ifndef DOXYGEN_SHOULD_SKIP_THIS AVAHI_C_DECL_END #endif diff --git a/avahi-core/core.h b/avahi-core/core.h index 1cf35fc..427a09a 100644 --- a/avahi-core/core.h +++ b/avahi-core/core.h @@ -85,6 +85,7 @@ typedef struct AvahiServerConfig { int use_iff_running; /**< Require IFF_RUNNING on local network interfaces. This is the official way to check for link beat. Unfortunately this doesn't work with all drivers. So bettere leave this off. */ int enable_reflector; /**< Reflect incoming mDNS traffic to all local networks. This allows mDNS based network browsing beyond ethernet borders */ int reflect_ipv; /**< if enable_reflector is 1, enable/disable reflecting between IPv4 and IPv6 */ + int add_service_cookie; /**< Add magic service cookie to all locally generated records implicitly */ } AvahiServerConfig; /** Allocate a new mDNS responder object. */ @@ -564,6 +565,9 @@ void avahi_s_dns_server_browser_free(AvahiSDNSServerBrowser *b); /** Return the last error code */ int avahi_server_errno(AvahiServer *s); +/** Return the local service cookie */ +uint32_t avahi_server_get_local_service_cookie(AvahiServer *s); + #ifndef DOXYGEN_SHOULD_SKIP_THIS AVAHI_C_DECL_END #endif diff --git a/avahi-core/server.c b/avahi-core/server.c index 66cc705..625af50 100644 --- a/avahi-core/server.c +++ b/avahi-core/server.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -1411,6 +1412,10 @@ AvahiServer *avahi_server_new(const AvahiPoll *poll_api, const AvahiServerConfig s->legacy_unicast_reflect_slots = NULL; s->legacy_unicast_reflect_id = 0; + + do { + s->local_service_cookie = (uint32_t) rand() * (uint32_t) rand(); + } while (s->local_service_cookie == AVAHI_SERVICE_COOKIE_INVALID); /* Get host name */ s->host_name = s->config.host_name ? avahi_normalize_name(s->config.host_name) : avahi_get_host_name(); @@ -1849,6 +1854,22 @@ static void escape_service_name(char *d, size_t size, const char *s) { *(d++) = 0; } +static AvahiStringList *add_magic_cookie( + AvahiServer *s, + AvahiStringList *strlst) { + + assert(s); + + if (!s->config.add_service_cookie) + return strlst; + + if (avahi_string_list_find(strlst, AVAHI_SERVICE_COOKIE)) + /* This string list already contains a magic cookie */ + return strlst; + + return avahi_string_list_add_printf(strlst, AVAHI_SERVICE_COOKIE"=%u", s->local_service_cookie); +} + static int server_add_service_strlst_nocopy( AvahiServer *s, AvahiSEntryGroup *g, @@ -1919,6 +1940,8 @@ static int server_add_service_strlst_nocopy( if (ret < 0) goto fail; + strlst = add_magic_cookie(s, strlst); + ret = server_add_txt_strlst_nocopy(s, g, interface, protocol, AVAHI_ENTRY_UNIQUE, AVAHI_DEFAULT_TTL, svc_name, strlst); strlst = NULL; @@ -2389,6 +2412,7 @@ AvahiServerConfig* avahi_server_config_init(AvahiServerConfig *c) { c->use_iff_running = 0; c->enable_reflector = 0; c->reflect_ipv = 0; + c->add_service_cookie = 1; return c; } @@ -2435,3 +2459,8 @@ int avahi_server_set_errno(AvahiServer *s, int error) { return s->error = error; } +uint32_t avahi_server_get_local_service_cookie(AvahiServer *s) { + assert(s); + + return s->local_service_cookie; +} diff --git a/avahi-core/server.h b/avahi-core/server.h index 6ceab42..7384e98 100644 --- a/avahi-core/server.h +++ b/avahi-core/server.h @@ -139,6 +139,8 @@ struct AvahiServer { uint16_t legacy_unicast_reflect_id; int error; + + uint32_t local_service_cookie; }; int avahi_server_entry_match_interface(AvahiEntry *e, AvahiInterface *i); diff --git a/avahi-daemon/Server.introspect b/avahi-daemon/Server.introspect index 1229733..3cd85f8 100644 --- a/avahi-daemon/Server.introspect +++ b/avahi-daemon/Server.introspect @@ -33,6 +33,10 @@ + + + + diff --git a/avahi-daemon/dbus-protocol.c b/avahi-daemon/dbus-protocol.c index 9cc4434..61d26d0 100644 --- a/avahi-daemon/dbus-protocol.c +++ b/avahi-daemon/dbus-protocol.c @@ -452,6 +452,17 @@ static DBusHandlerResult respond_int32(DBusConnection *c, DBusMessage *m, int32_ return DBUS_HANDLER_RESULT_HANDLED; } +static DBusHandlerResult respond_uint32(DBusConnection *c, DBusMessage *m, uint32_t u) { + DBusMessage *reply; + + reply = dbus_message_new_method_return(m); + dbus_message_append_args(reply, DBUS_TYPE_UINT32, &u, DBUS_TYPE_INVALID); + dbus_connection_send(c, reply, NULL); + dbus_message_unref(reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + static DBusHandlerResult respond_ok(DBusConnection *c, DBusMessage *m) { DBusMessage *reply; @@ -1541,6 +1552,15 @@ static DBusHandlerResult msg_server_impl(DBusConnection *c, DBusMessage *m, void state = avahi_server_get_state(avahi_server); return respond_int32(c, m, (int32_t) state); + } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetLocalServiceCookie")) { + + if (!(dbus_message_get_args(m, &error, DBUS_TYPE_INVALID))) { + avahi_log_warn("Error parsing Server::GetLocalServiceCookie message"); + goto fail; + } + + return respond_uint32(c, m, avahi_server_get_local_service_cookie(avahi_server)); + } else if (dbus_message_is_method_call(m, AVAHI_DBUS_INTERFACE_SERVER, "GetNetworkInterfaceNameByIndex")) { int32_t idx; int fd; diff --git a/avahi-daemon/main.c b/avahi-daemon/main.c index 566a276..dab65f7 100644 --- a/avahi-daemon/main.c +++ b/avahi-daemon/main.c @@ -220,7 +220,7 @@ static void server_callback(AvahiServer *s, AvahiServerState state, void *userda #endif if (state == AVAHI_SERVER_RUNNING) { - avahi_log_info("Server startup complete. Host name is %s.", avahi_server_get_host_name_fqdn(s)); + avahi_log_info("Server startup complete. Host name is %s. Local service cookie is %u.", avahi_server_get_host_name_fqdn(s), avahi_server_get_local_service_cookie(s)); static_service_add_to_server(); remove_dns_server_entry_groups(); diff --git a/configure.ac b/configure.ac index 1bd727a..38a7332 100644 --- a/configure.ac +++ b/configure.ac @@ -28,9 +28,9 @@ AM_INIT_AUTOMAKE([foreign 1.9 -Wall]) AC_SUBST(PACKAGE_URL, [http://www.freedesktop.org/Software/Avahi]) -AC_SUBST(LIBAVAHI_COMMON_VERSION_INFO, [1:0:1]) -AC_SUBST(LIBAVAHI_CORE_VERSION_INFO, [0:2:0]) -AC_SUBST(LIBAVAHI_CLIENT_VERSION_INFO, [1:0:0]) +AC_SUBST(LIBAVAHI_COMMON_VERSION_INFO, [1:1:1]) +AC_SUBST(LIBAVAHI_CORE_VERSION_INFO, [1:0:0]) +AC_SUBST(LIBAVAHI_CLIENT_VERSION_INFO, [1:1:0]) AC_SUBST(LIBAVAHI_GLIB_VERSION_INFO, [0:1:0]) AC_SUBST(LIBAVAHI_QT3_VERSION_INFO, [0:0:0]) AC_SUBST(LIBAVAHI_QT4_VERSION_INFO, [0:0:0]) diff --git a/docs/TODO b/docs/TODO index a5e32cf..97b8aac 100644 --- a/docs/TODO +++ b/docs/TODO @@ -2,7 +2,6 @@ todo: * Add sensible record updating API * Passive observation of failures * support for special domain PTR records based on local IP subnet address -* add identical service detection cookie * add API to detect if a service is local * add subtype browsing * add wide area support (i.e. DNS-SD over unicast DNS) @@ -61,3 +60,4 @@ done: * examples * publish IP addresses with scope "link" only, unless ther are the only one the interface * release 0.2! +* add identical service detection cookie -- cgit