Skip to content

Port mapping in Endpoint::bind sometimes triggers the macOS firewall #4349

Description

@colinmarc

Describe the bug

On my office network (but not my home network, interestingly), I sometimes see a dialog like the following when calling Endpoint::bind on a fresh build:

Image

That's true even with a short-lived connection that only goes over the relay. After some debugging, I believe this is being caused by port mapping, and goes away using PortmapperConfig::Disabled.

To test this theory, I used an LLM to generate a bunch of simple C programs, and test which ones opened the dialog.

Things that don't trigger the dialog:

  • binding to 0.0.0.0 or [::1]
  • binding to 0.0.0.0 and sending a udp packet out
  • sending a dns query from 0.0.0.0 and getting a response

But here's what I think does:

  • Receiving a packet on a socket bound to 0.0.0.0 from an address you haven't sent to

Here's a small C program imitating the SSDP part of port mapping. I know very little about that protocol works, but at my office a few devices on the network respond, and if you imagine the OS firewall as a simple stateful fw it makes a lot of sense: a packet inbound to a port with no corresponding outbound tuple would register as a listener.

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(void) {
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) { perror("socket"); return 1; }

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = 0,
        .sin_addr.s_addr = INADDR_ANY,
    };

    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("bind");
        return 1;
    }
    printf("bound\n");

    struct sockaddr_in mcast = {
        .sin_family = AF_INET,
        .sin_port = htons(1900),
    };
    inet_aton("239.255.255.250", &mcast.sin_addr);

    const char *msg = "M-SEARCH * HTTP/1.1\r\n"
                      "HOST: 239.255.255.250:1900\r\n"
                      "MAN: \"ssdp:discover\"\r\n"
                      "MX: 1\r\n"
                      "ST: ssdp:all\r\n\r\n";

    ssize_t n = sendto(fd, msg, strlen(msg), 0,
                       (struct sockaddr *)&mcast, sizeof(mcast));
    printf("sent %zd bytes to multicast\n", n);

    sleep(3);
    close(fd);
    return 0;
}

packet dump:

 15:23:29.849172 IP 192.168.178.187.53565 > 239.255.255.250.1900: UDP, length 94
 15:23:29.849188 IP 192.168.178.187.53565 > 239.255.255.250.1900: UDP, length 94
 15:23:29.849210 IP 192.168.178.187.53565 > 239.255.255.250.1900: UDP, length 94
 15:23:29.856741 IP 192.168.178.250.1900 > 192.168.178.187.53565: UDP, length 345
 15:23:29.859756 IP 192.168.178.1.1900 > 192.168.178.187.53565: UDP, length 264
 15:23:29.859760 IP 192.168.178.1.1900 > 192.168.178.187.53565: UDP, length 273
 15:23:29.859761 IP 192.168.178.1.1900 > 192.168.178.187.53565: UDP, length 316
 15:23:29.861253 IP 192.168.178.1.1900 > 192.168.178.187.53565: UDP, length 252
 15:23:29.861255 IP 192.168.178.1.1900 > 192.168.178.187.53565: UDP, length 261
...

Iroh

Version: 1.0.0-rc1

Platform(s)
Desktop:

  • OS: macOS
  • Version 15.7.3 (worth testing on 26!)

Additional Context / Screenshots / GIFs

lolwut

  • This issue was created by a human that thought critically about
    the issue being reported and wrote this as concisely and clearly
    as they could. Taking full responsibility for the issue being
    accurate.
  • This issue isn't slop.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Projects

    Status
    🏗 In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions