[avahi] [PATCH] Filtering Reflector Advertisements

Rudd, James James.Rudd at sbhs.nsw.edu.au
Sun Aug 24 23:00:26 PDT 2014


Allows Avahi-Daemon to filter which advertisements are added to the cache to be reflected to different networks.
It checks incoming service names against a list defined in avahi-daemon.conf [reflector] reflect-filters. 
The list can be types of services or can contain hostnames to match. 
For example we only allow AirPlay and AirTunes to be reflected between VLANs, so have "_airplay._tcp.local,_raop._tcp.local" set.

The patch will block the PTR and SRV advertisements but will still allow A records for machine name lookup.
All locally published services are still published even if they do not match the filter.

The filter also blocks local programs from seeing advertised programs so it is recommend to only enable it on a dedicated bonjour reflector server.

If anyone has any suggestions or betters ways of implementing this please let me know.

Regards,
 James

James Rudd
Network Administrator
Sydney Boys High School
556 Cleveland St
Moore Park, NSW 2021
Ph: (02) 9662-9300  Fax: (02) 9662-9310

---
 avahi-core/core.h              |  1 +
 avahi-core/server.c            | 42 +++++++++++++++++++++++++++++++++++++++++-
 avahi-daemon/avahi-daemon.conf |  1 +
 avahi-daemon/main.c            | 12 ++++++++++++
 4 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/avahi-core/core.h b/avahi-core/core.h
index f50c612..1ebd27a 100644
--- a/avahi-core/core.h
+++ b/avahi-core/core.h
@@ -56,6 +56,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 */
+    AvahiStringList *reflect_filters;  /**< if enable_reflector is 1, will only add services containing one of these strings */
     int add_service_cookie;           /**< Add magic service cookie to all locally generated records implicitly */
     int enable_wide_area;             /**< Enable wide area support */
     AvahiAddress wide_area_servers[AVAHI_WIDE_AREA_SERVERS_MAX]; /** Unicast DNS server to use for wide area lookup */
diff --git a/avahi-core/server.c b/avahi-core/server.c
index 69a1d02..81725ac 100644
--- a/avahi-core/server.c
+++ b/avahi-core/server.c
@@ -674,6 +674,34 @@ static void handle_response_packet(AvahiServer *s, AvahiDnsPacket *p, AvahiInter
         }
 
         if (!avahi_key_is_pattern(record->key)) {
+            // Filter services that will be cached. Allow all local services
+            if (!from_local_iface && s->config.enable_reflector && s->config.reflect_filters != NULL){
+               AvahiStringList *l;
+               int match = 0;
+
+                if (record->key->type == AVAHI_DNS_TYPE_PTR){
+                    // Need to match DNS pointer target with filter
+                    for (l = s->config.reflect_filters; l; l = l->next)
+                        if (strstr( record->data.ptr.name, (char*) l->text) != NULL)
+                        match = 1;
+
+                    if (! match){
+                        //avahi_log_info("Reject Ptr SRC [%s] Dest [%s]", record->key->name, record->data.ptr.name);
+                        return;
+                    }
+                }
+                else if (record->key->type == AVAHI_DNS_TYPE_SRV || record->key->type == AVAHI_DNS_TYPE_TXT){
+                    // Need to match key name with filter
+                    for (l = s->config.reflect_filters; l; l = l->next)
+                        if (strstr( record->key->name, (char*) l->text) != NULL)
+                        match = 1;
+
+                    if (! match){
+                        //avahi_log_info("Reject Key [%s] iface [%d]", record->key->name, from_local_iface);
+                        return;
+                    }
+                }
+            }
 
             if (handle_conflict(s, i, record, cache_flush)) {
                 if (!from_local_iface && !avahi_record_is_link_local_address(record))
@@ -1589,6 +1617,7 @@ AvahiServerConfig* avahi_server_config_init(AvahiServerConfig *c) {
     c->use_iff_running = 0;
     c->enable_reflector = 0;
     c->reflect_ipv = 0;
+    c->reflect_filters = NULL;
     c->add_service_cookie = 0;
     c->enable_wide_area = 0;
     c->n_wide_area_servers = 0;
@@ -1611,13 +1640,14 @@ void avahi_server_config_free(AvahiServerConfig *c) {
     avahi_free(c->host_name);
     avahi_free(c->domain_name);
     avahi_string_list_free(c->browse_domains);
+    avahi_string_list_free(c->reflect_filters);
     avahi_string_list_free(c->allow_interfaces);
     avahi_string_list_free(c->deny_interfaces);
 }
 
 AvahiServerConfig* avahi_server_config_copy(AvahiServerConfig *ret, const AvahiServerConfig *c) {
     char *d = NULL, *h = NULL;
-    AvahiStringList *browse = NULL, *allow = NULL, *deny = NULL;
+    AvahiStringList *browse = NULL, *allow = NULL, *deny = NULL, *reflect = NULL ;
     assert(ret);
     assert(c);
 
@@ -1652,12 +1682,22 @@ AvahiServerConfig* avahi_server_config_copy(AvahiServerConfig *ret, const AvahiS
         return NULL;
     }
 
+   if (!(reflect = avahi_string_list_copy(c->reflect_filters)) && c->reflect_filters) {
+        avahi_string_list_free(allow);
+        avahi_string_list_free(browse);
+        avahi_string_list_free(deny);
+        avahi_free(h);
+        avahi_free(d);
+        return NULL;
+    }
+
     *ret = *c;
     ret->host_name = h;
     ret->domain_name = d;
     ret->browse_domains = browse;
     ret->allow_interfaces = allow;
     ret->deny_interfaces = deny;
+    ret->reflect_filters = reflect;
 
     return ret;
 }
diff --git a/avahi-daemon/avahi-daemon.conf b/avahi-daemon/avahi-daemon.conf
index 27e240d..662fd69 100644
--- a/avahi-daemon/avahi-daemon.conf
+++ b/avahi-daemon/avahi-daemon.conf
@@ -57,6 +57,7 @@ publish-workstation=no
 [reflector]
 #enable-reflector=no
 #reflect-ipv=no
+#reflect-filters=_airplay._tcp.local,_raop._tcp.local
 
 [rlimits]
 #rlimit-as=
diff --git a/avahi-daemon/main.c b/avahi-daemon/main.c
index 8c28fd6..2676133 100644
--- a/avahi-daemon/main.c
+++ b/avahi-daemon/main.c
@@ -820,6 +820,18 @@ static int load_config_file(DaemonConfig *c) {
                     c->server_config.enable_reflector = is_yes(p->value);
                 else if (strcasecmp(p->key, "reflect-ipv") == 0)
                     c->server_config.reflect_ipv = is_yes(p->value);
+                else if (strcasecmp(p->key, "reflect-filters") == 0) {
+                    char **e, **t;
+
+                    avahi_string_list_free(c->server_config.reflect_filters);
+                    c->server_config.reflect_filters = NULL;
+                    e = avahi_split_csv(p->value);
+
+                    for (t = e; *t; t++)
+                        c->server_config.reflect_filters = avahi_string_list_add(c->server_config.reflect_filters, *t);
+
+                    avahi_strfreev(e);
+                }
                 else {
                     avahi_log_error("Invalid configuration key \"%s\" in group \"%s\"\n", p->key, g->name);
                     goto finish;
-- 
1.9.1

**********************************************************************
This message is intended for the addressee named and may contain
privileged information or confidential information or both. If you
are not the intended recipient please delete it and notify the sender.
**********************************************************************


More information about the avahi mailing list