EDIT: The bad solution is to unblock UDP port 5353 but the port has to be source port, not destination port. (--sport flag) See the now modified rules. The issue is that this is very insecure (see this stackexchange question and comments) but obviously better than no firewall at all because at least I’m blocking TCP traffic.

The proper solution (other than using glibc and installing nss-mdns package) is to open a port with netcat (nc) in the background (using &) and then listen with dig on that port using the -b flag.

port="42069"
nc -l -p "$port" > /dev/null || exit 1 &
dig somehostname.local @224.0.0.241 -p 5353 -b "0.0.0.0#${port}"

Then we need to remember to kill the background process. The DNS reply will now be sent to port 42069, so we can just open it with this iptables rule:

-A INPUT -p udp -m udp --dport 42069 -j ACCEPT

---->END OF EDIT.

I want to setup iptables firewall but if I do that, it blocks multicast DNS which I need. I am using command

dig "somehostname.local" @224.0.0.251 -p 5353

to get the IP through mDNS and these are my iptables rules (from superuser.com):

*filter

# drop forwarded traffic. you only need it of you are running a router
:FORWARD DROP [0:0]

# Accept all outgoing traffic
:OUTPUT ACCEPT [623107326:1392470726908]


# Block all incoming traffic, all protocols (tcp, udp, icmp, ...) everything.
# This is the base rule we can define exceptions from.
:INPUT DROP [11486:513044]

# do not block already running connections (important for outgoing)
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# do not block localhost
-A INPUT -i lo -j ACCEPT

# do not block icmp for ping and network diagnostics. Remove if you do not want this
# note that -p icmp has no effect on ipv6, so we need an extra ipv6 rule
-4 -A INPUT -p icmp -j ACCEPT
-6 -A INPUT -p ipv6-icmp -j ACCEPT

# allow some incoming ports for services that should be public available
# -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
# -A INPUT -p udp -m udp --dport 5353 -j ACCEPT # does not help
-A OUTPUT -p udp -m udp --sport 5353 -j ACCEPT # SOLVES THE ISSUE BUT IS INSECURE - not recommended


# commit changes
COMMIT

Any help is welcome :)

  • gnuhaut@lemmy.ml
    link
    fedilink
    arrow-up
    4
    ·
    4 days ago

    My hunch on what’s going on: Dig opens up a different udp port (it has to, there would be avahi-daemon listening on 5353). So it sends out to the multicast address on 5353, but the answer comes back from the actual IP of whoever is answering, to whatever port dig is listening on, and the connection tracking is not smart enough to figure out this should be let through?

    You should look at the traffic with wireshark.

    Also maybe that’s fine in practice? Do applications actually run their own mDNS queries? Maybe it all goes through avahi-daemon? That uses port 5353 so that would get an answer if it did the mDNS query instead of dig. But I’m not sure how this works, so that’s just a guess.

    • TMP_NKcYUEoM7kXg4qYe@lemmy.worldOP
      link
      fedilink
      arrow-up
      1
      ·
      4 days ago

      Actually I don’t have avahi installed. I only have some avahi-libs. I thought it’s only needed on the computer who’s IP I’m trying to get.

      • gnuhaut@lemmy.ml
        link
        fedilink
        arrow-up
        1
        ·
        4 days ago

        As I said, I’m not sure about that.

        Still, dig won’t be listening on port 5353 for the answer, it’ll open some random port, so the firewall rule for 5353 will not apply. And the conntrack rule, is my guess, also doesn’t apply, because what I think the conntrack module does is:

        • Remembers about the outgoing connection (i.e. when dig sends its udp packet out): source port, destination IP and port
        • Check incoming packets against this info, and lets them through if they appear to be an answer

        Since the outgoing packet is going to multicast, and the incoming packet (I suspect) is coming from the IP of the machine that answers (a different IP therefore), conntrack wouldn’t be able to figure that out. The answer doesn’t match the outgoing packet that dig sends. Since this is just a hunch, I would try to confirm this by looking at the traffic in e.g. wireshark.

        • TMP_NKcYUEoM7kXg4qYe@lemmy.worldOP
          link
          fedilink
          arrow-up
          2
          ·
          edit-2
          4 days ago

          Edit 2: Actually dig picks a random port to send the mDNS request from and sends it to 224.0.0.251:5353 (multicast IP). The correct host then replies from port 5353 to the previously picked random port from dig. But I found that you can specify the port with dig -b IP#port so I think that should help. I kinda don’t have the time to try it out currently though.

          end of edit2.

          well I randomly solved it by adding

          -A OUTPUT -p udp -m udp --sport 5353 -j ACCEPT
          

          Which basically means you are right. The destination port is just some randomly picked number (checked wireshark), so I have to filter based on source port, which is 5353.

          Edit: Also thanks for your help!

          • gnuhaut@lemmy.ml
            link
            fedilink
            arrow-up
            1
            ·
            4 days ago

            Yeah no problem. I’d like to point out that this puts a hole in your firewall. If you have something exposed via udp, and an attacker knows about your --sport rule or figures this out, they can connect to it just by setting their source port to 5353. You can check what’s listening on udp with ss -lun or sudo ss -lunp (for process info).

            Also, I have looked up what @Eideen@lemmy.world said about dig not supporting mdns and I think they are correct. With mdns, because of the multicast nature, you can get replies from multiple computers, and that’s a pretty big difference to regular dns. How could it even reliably know it has gotten all the replies or if it should wait for more? It just sort of happens to work correctly if you get a single reply.

            Also, and I also looked this up, mdns lookups will to go through avahi-daemon on regular glibc distros. The libnss-mdns plugin description for glibc says this:

            nss-mdns tries to contact a running avahi-daemon for resolving host names and addresses and making use of its superior record cacheing. If Avahi is not available at lookup time, the lookups will fail.

            • TMP_NKcYUEoM7kXg4qYe@lemmy.worldOP
              link
              fedilink
              arrow-up
              2
              ·
              4 days ago

              this puts a hole in your firewall

              Indeed, thanks, I realized that shortly after posting it.

              dig not supporting mdns

              Yep you both are correct. Looking at it now, the result does actually warn me that I’m trying to send a regular DNS request to mDNS multicast address.

              It just sort of happens to work correctly if you get a single reply

              Yeah I guess it’s a hack. To me it does not really matter because I’m just using it for wireguard, so the worst thing that could happen is that I would try to connect to a wrong host and the key exchange would fail.

              libnss-mdns

              The reason for why I’m doing this whole hack is that nss-mdns package is only available on glibc version of Void but I’m using musl, so it’s really just hacks on top of hacks. I found a final solution though so that’s nice (see final edit of post). Thanks for all your replies!

  • Eideen@lemmy.world
    link
    fedilink
    arrow-up
    4
    ·
    edit-2
    4 days ago

    My understanding is that dig does not support mDNS.

    The most common way to use it via avahi-browse and avahi-daemon (mDNS service).

    https://askubuntu.com/a/1526875

    The following failes for me:

    dig "pihole-s5.local" @224.0.0.251 -p 5353
    

    The following works for me:

    $getent hosts pihole-s5.local
    192.168.2.10    pihole-s5.local
    
    • TMP_NKcYUEoM7kXg4qYe@lemmy.worldOP
      link
      fedilink
      arrow-up
      1
      ·
      edit-2
      4 days ago

      Huh weird. For me the first one works but the second one fails and returns an empty string.

      I guess I should have specified that I’m on Void-musl. The reason why I’m doing this is because there is no NSS library on musl, so as far as I know you cannot automagically query hostnames on the network.

      • Eideen@lemmy.world
        link
        fedilink
        arrow-up
        1
        ·
        4 days ago

        I don’t know Void-musl.

        I don’t know if you can install libnss-mdns. If /etc/nsswitch.conf is not standard you also need to configure it.

        Are you able to setup VM with Debian, so you can test with a standard environment?

  • just_another_person@lemmy.world
    link
    fedilink
    arrow-up
    2
    ·
    4 days ago

    It’s blocking the querying as well? It’s hard to discern where the issue is.

    Mdns is udp on port 5353, and your rules don’t seem to block outgoing udp, so your dig should work if enabled or not.

        • TMP_NKcYUEoM7kXg4qYe@lemmy.worldOP
          link
          fedilink
          arrow-up
          1
          ·
          4 days ago

          It’s solved now. Basically what’s happening is that I ask a multicast address on UDP port 5353 and get a response from different IP because the original IP was multicast. So my firewall blocks the reply, because it really isn’t a reply like downloading a webpage. I solved it by filtering based on the source port. Meaning the reply has source port 5353 but on my machine it arrives at some random UDP port so I cannot really filter based on the destination port.

          solution

          -A OUTPUT -p udp -m udp --sport 5353 -j ACCEPT
          

          Thanks for your help!