blake / external-mdns

A service to advertise records for Kubernetes resources on a LAN over multicast DNS.
Apache License 2.0
65 stars 9 forks source link

Does not work with Android #10

Closed L2jLiga closed 1 year ago

L2jLiga commented 1 year ago

Hi there, I'm trying to make this work with Android phones with no success

I've tried original image, image with this commits: #9 as well as adding more "fixes" like setting RecursionDesired bit to 0 accroding to https://datatracker.ietf.org/doc/html/rfc6762#section-18.6.

mDNS works perfectly fine on other machines in my network - Ubuntu, Fedora, Windows 10, Windows 11 I've tested it on 2 phones:

Both does not work =(

I have no idea what's wrong, according to packet sniffer Android sends mDNS request and external-mdns replies to it, everything looks correct, however no luck.


mdns.yaml ``` kind: Namespace apiVersion: v1 metadata: name: kube-mdns labels: k8s-app: mdns pod-security.kubernetes.io/enforce: privileged --- apiVersion: v1 kind: ServiceAccount metadata: name: mdns namespace: kube-mdns --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: mdns namespace: kube-mdns rules: - apiGroups: [""] resources: ["services"] verbs: ["list", "watch"] - apiGroups: ["extensions","networking.k8s.io"] resources: ["ingresses"] verbs: ["list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: mdns-viewer namespace: kube-mdns roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: mdns subjects: - kind: ServiceAccount name: mdns namespace: kube-mdns --- apiVersion: apps/v1 kind: DaemonSet metadata: name: mdns namespace: kube-mdns spec: selector: matchLabels: app: mdns template: metadata: labels: app: mdns spec: tolerations: - effect: NoSchedule key: node-role.kubernetes.io/master - effect: NoSchedule key: node-role.kubernetes.io/control-plane affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/os operator: In values: - linux serviceAccountName: mdns hostNetwork: true containers: - name: mdns image: 192.168.89.2:5000/external-mdns:latest args: - -source=service - -source=ingress - -expose-ipv6=true - -without-namespace=true ports: - containerPort: 5353 protocol: UDP resources: requests: cpu: 50m memory: 50Mi securityContext: privileged: false capabilities: drop: - ALL add: - NET_ADMIN - NET_RAW - NET_BROADCAST ```
kubectl get pods,svc,pvc,deploy,daemonsets -o wide -n kube-mdns ``` NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/mdns-cqjqc 1/1 Running 0 9m33s 192.168.88.89 steamlink pod/mdns-fpx8f 1/1 Running 0 9m33s 192.168.88.88 storage pod/mdns-nt497 1/1 Running 0 9m33s 192.168.88.100 zoidberg NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR daemonset.apps/mdns 3 3 3 3 3 4d4h mdns 192.168.89.2:5000/external-mdns:lastest app=mdns ```

CAP file: android-dns-mdns-wsdd-llmnr.zip

blake commented 1 year ago

Hi @L2jLiga,

I'm not sure what could be going on here. I'm interested in debugging this, but unfortunately I don't have any Android devices to test with. I'm not sure how I could go about troubleshooting this without having access to an Android device or VM. 🤔

L2jLiga commented 1 year ago

No problem, may be someone else knows the answer, I'm currently stuck at "send_mdns: timeout" in logcat

Message comes from here: https://android.googlesource.com/platform/packages/modules/DnsResolver/+/refs/heads/master/res_send.cpp#1226

blake commented 1 year ago

@L2jLiga Thanks for sharing that additional detail.

I looked at how Android sends the mDNS queries and I realized that the resolver is performing a one-shot multicast DNS query. Per section 5.1 of the multicast DNS RFC:

These queries are typically done using a high-numbered ephemeral UDP source port, but regardless of whether they are sent from a dynamic port or from a fixed port, these queries MUST NOT be sent using UDP source port 5353, since using UDP source port 5353 signals the presence of a fully compliant Multicast DNS querier…

You can see this in the Wireshark capture as well. The DNS query uses source port 34175 instead of 5353.

Section 6.7 of that same RFC, Legacy Unicast Responses, describes how a server should respond to these simple requests.

If the source UDP port in a received Multicast DNS query is not port 5353, this indicates that the querier originating the query is a simple resolver such as described in Section 5.1, "One-Shot Multicast DNS Queries", which does not fully implement all of Multicast DNS. In this case, the Multicast DNS responder MUST send a UDP response directly back to the querier, via unicast, to the query packet's source IP address and port. This unicast response MUST be a conventional unicast response as would be generated by a conventional Unicast DNS server; for example, it MUST repeat the query ID and the question given in the query message. In addition, the cache-flush bit described in Section 10.2, "Announcements to Flush Outdated Cache Entries", MUST NOT be set in legacy unicast responses.

external-mdns does not currently implement the required behavior in order for it to be compatible with one-shot queries / simple resolvers, so this explains why the request fails from the Android phones.

If this capability were to be added, the responses should succeed.

L2jLiga commented 1 year ago

Wow! I re-read RFC multiple times and didn't noticed that! 😅

Btw, already made all required changes and now it works like a charm! Will create PR soon =)