[libslirp] allow guest->host MDNS service discovery

Reproduce:

1. On host run apache-httpd
2. On host use chrome to visit "<machine-name>.local:80"
3. Observe web page response: "It Works!"
4. On GUEST use chrome to visit same URL
5. Note the timeout

BUG: 342830958

Change-Id: If590c2a49a55f6025ac9a8f47a3122f6012bde02
diff --git a/src/udp.c b/src/udp.c
index 1693ad3..a811a52 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -220,7 +220,30 @@
         icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, NULL);
         goto bad;
     }
-    setsockopt(so->s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
+
+    /*
+     * Check for MULTICAST
+     */
+    if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
+      setsockopt(so->s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl));
+      DEBUG_MISC("multicast");
+      if (!slirp->disable_host_loopback) {
+        DEBUG_MISC("multicast loopback enabled");
+        int loopback = 1;  // Enable loopback
+        if (setsockopt(so->s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopback, sizeof(loopback)) == -1) {
+          DEBUG_MISC(" multicast loop errno = %d-%s", errno, strerror(errno));
+        };
+      }
+      struct ip_mreq mreq;
+      mreq.imr_multiaddr.s_addr = ip->ip_dst.s_addr;       // Multicast group address
+      mreq.imr_interface.s_addr = htonl(INADDR_ANY); // Interface to use
+      if (setsockopt(so->s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) == -1) {
+        DEBUG_MISC(" multicast membership errno = %d-%s", errno, strerror(errno));
+      };
+    } else {
+      setsockopt(so->s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
+    }
+
 
     /*
      * Now we sendto() the packet.
diff --git a/src/udp6.c b/src/udp6.c
index effdf77..c6a577c 100644
--- a/src/udp6.c
+++ b/src/udp6.c
@@ -128,7 +128,28 @@
         icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
         goto bad;
     }
-    setsockopt(so->s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, sizeof(hop_limit));
+
+    /*
+     * Check for MULTICAST
+     */
+    if (IN6_IS_ADDR_MULTICAST(&ip->ip_dst)) {
+        setsockopt(so->s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hop_limit, sizeof(hop_limit));
+        if (!so->slirp->disable_host_loopback) {
+            DEBUG_MISC("multicast loopback enabled\n");
+            int loopback = 1;  // Enable loopback
+            if (setsockopt(so->s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&loopback, sizeof(loopback)) == -1) {
+                DEBUG_MISC(" multicast loop errno = %d-%s\n", errno, strerror(errno));
+            };
+        }
+        struct ipv6_mreq mreq;
+        mreq.ipv6mr_multiaddr = ip->ip_dst;       // Multicast group address
+        mreq.ipv6mr_interface = 0; // The default multicast interface is used when set 0.
+        if (setsockopt(so->s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq, sizeof(mreq)) == -1) {
+            DEBUG_MISC("multicast membership errno = %d-%s\n", errno, strerror(errno));
+        };
+    } else {
+        setsockopt(so->s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, sizeof(hop_limit));
+    }
 
     /*
      * Now we sendto() the packet.