-
Notifications
You must be signed in to change notification settings - Fork 1.3k
linuxcncrsh: Allow IPv4 as fallback when IPv6 is disabled #4403
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -185,6 +185,7 @@ typedef struct { | |
| int commProt; // Deprecated | ||
| } connectionRecType; | ||
|
|
||
| static bool isipv4 = false; // We try AF_INET6, but can fallback to AF_INET | ||
| static int port = 5007; | ||
| static std::string helloPwd = "EMC"; | ||
| static std::string enablePWD = "EMCTOO"; | ||
|
|
@@ -369,19 +370,41 @@ static int initSocket() | |
| int optval = 1; | ||
| int err; | ||
| int sockfd; | ||
| struct sockaddr_in6 address = {}; | ||
| union { | ||
| struct sockaddr_in6 addr6; | ||
| struct sockaddr_in addr4; | ||
| } addr; | ||
|
|
||
| // Using AF_INET6 will also allow IPv4 to connect (v4-mapped-on-v6) | ||
| // We will try IPv6 first and hope it is available | ||
| addr.addr6 = {}; | ||
| addr.addr6.sin6_family = AF_INET6; | ||
| addr.addr6.sin6_addr = IN6ADDR_ANY_INIT; | ||
| addr.addr6.sin6_port = htons(port); | ||
| socklen_t slen = sizeof(addr.addr6); | ||
|
|
||
| sockfd = socket(AF_INET6, SOCK_STREAM, 0); | ||
| if (sockfd < 0) { | ||
| xperror("socket()"); | ||
| return -1; | ||
| if(EAFNOSUPPORT == errno) { | ||
| // Someone disabled IPv6 on the machine. Try IPv4 instead. | ||
| sockfd = socket(AF_INET, SOCK_STREAM, 0); | ||
| if (sockfd < 0) { | ||
| xperror("IPv4 socket()"); | ||
| return -1; | ||
| } | ||
| isipv4 = true; | ||
| addr.addr4 = {}; | ||
| addr.addr4.sin_family = AF_INET; | ||
| addr.addr4.sin_addr.s_addr = INADDR_ANY; | ||
| addr.addr4.sin_port = htons(port); | ||
| slen = sizeof(addr.addr4); | ||
| } else { | ||
| xperror("IPv6 socket()"); | ||
| return -1; | ||
| } | ||
| } | ||
| setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dual-stack here relies on net.ipv6.bindv6only defaulting to 0. With that sysctl Worth pinning the assumption rather than inheriting it, on the IPv6 branch only? |
||
| // Using AF_INET6 will also allow IPv4 to connect (v4-mapped-on-v6) | ||
| address.sin6_family = AF_INET6; | ||
| address.sin6_addr = IN6ADDR_ANY_INIT; | ||
| address.sin6_port = htons(port); | ||
| err = bind(sockfd, reinterpret_cast<struct sockaddr *>(&address), sizeof(address)); | ||
| err = bind(sockfd, reinterpret_cast<struct sockaddr *>(&addr), slen); | ||
| if (err) { | ||
| close(sockfd); | ||
| xperror("bind()"); | ||
|
|
@@ -3424,6 +3447,13 @@ static void closeClient(connectionRecType &ctx) | |
| { | ||
| if (ctx.sock < 0) | ||
| return; | ||
| if(ctx.cmdtimeout > 0.0) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The latch clears, but the NML command is still in flight, so its completion or |
||
| // Happens when a client disconnects with an active SET command. This | ||
| // is bad because it desynchronizes the command channel from the error | ||
| // channel. We don't know what happened anymore. | ||
| info("Warning: Client '%s' disconnected while waiting for SET %s", ctx.hostname.c_str(), activeSetter.c_str()); | ||
| setterClear(ctx); | ||
| } | ||
| info("Connection terminated '%s' (%d)", ctx.hostname.c_str(), ctx.sock); | ||
| close(ctx.sock); | ||
| ctx.sock = -1; | ||
|
|
@@ -3493,8 +3523,11 @@ static int sockMain(int svrfd) | |
| } else if (pfds[0].revents & POLLIN) { | ||
| // POLLIN on a listen socket means new connection available | ||
| int cfd; | ||
| struct sockaddr_in6 csa; | ||
| socklen_t csal = sizeof(csa); | ||
| union { | ||
| struct sockaddr_in6 csa6; | ||
| struct sockaddr_in csa4; | ||
| } csa; | ||
| socklen_t csal = isipv4 ? sizeof(csa.csa4) : sizeof(csa.csa6); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. accept() writes the real length back, so does the family need to be known here? Broader: would sockaddr_storage plus getnameinfo(..., NI_NUMERICHOST | |
||
| cfd = accept(svrfd, reinterpret_cast<struct sockaddr *>(&csa), &csal); | ||
| if (cfd < 0) { | ||
| switch (errno) { | ||
|
|
@@ -3537,9 +3570,15 @@ static int sockMain(int svrfd) | |
| cr.waitmode = EMC_WAIT_DONE; | ||
| //cr.timestamp= true; | ||
| clients.push_back(cr); | ||
| char addr[INET6_ADDRSTRLEN] = {}; | ||
| inet_ntop(AF_INET6, &csa.sin6_addr, addr, sizeof(addr)); | ||
| info("New connection from %s:%d", addr, ntohs(csa.sin6_port)); | ||
| if(isipv4) { | ||
| char addr[INET_ADDRSTRLEN] = {}; | ||
| inet_ntop(AF_INET, &csa.csa4.sin_addr, addr, sizeof(addr)); | ||
| info("New connection from %s:%d", addr, ntohs(csa.csa4.sin_port)); | ||
| } else { | ||
| char addr[INET6_ADDRSTRLEN] = {}; | ||
| inet_ntop(AF_INET6, &csa.csa6.sin6_addr, addr, sizeof(addr)); | ||
| info("New connection from %s:%d", addr, ntohs(csa.csa6.sin6_port)); | ||
| } | ||
| } else { | ||
| close(cfd); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is EAFNOSUPPORT the only way the IPv6 listener can be unavailable in practice?
A restricted netns or an LSM/seccomp policy returns EACCES or EPERM here, and
there are setups where socket() succeeds but bind() to :: is what fails. Since
IPv4 is a strict fallback, any downside to taking it on any IPv6 failure?