Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 45 additions & 13 deletions src/hal/utils/halrmt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ using namespace linuxcnc;
static std::string helloPwd = "EMC"; // Connect password
static std::string enablePwd = "EMCTOO"; // Enable password
static std::string serverName = "EMCNETSVR"; // Server name written in hello response
static bool isipv4 = false; // We try AF_INET6, but can fallback to AF_INET
static int port = 5006;
static std::string inifilename;
static volatile int quitloop = 0; // Signal to main loop to exit
Expand Down Expand Up @@ -2886,19 +2887,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 | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is EAFNOSUPPORT the only failure worth falling back on? EACCES/EPERM from a
restricted netns or LSM policy reach the same point, and bind() to :: can fail
independently of socket(). Reason not to fall back on any IPv6 failure?

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 | SOCK_CLOEXEC | SOCK_NONBLOCK, 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));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as #4403: this depends on net.ipv6.bindv6only being 0. With that sysctl at
1, socket(AF_INET6, ...) succeeds so the fallback never fires and IPv4 clients
get ECONNREFUSED. Confirmed:

v6only=0  IPv4 client: connected OK
v6only=1  IPv4 client: connect FAILED (Connection refused)

Explicit setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, ...) on the IPv6
branch?

// 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()");
Expand Down Expand Up @@ -2985,8 +3008,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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accept4() writes the real length back, so sizeof(csa) works for both families.
Would sockaddr_storage plus getnameinfo(..., NI_NUMERICHOST | NI_NUMERICSERV)
remove the union, isipv4, and the duplicated logging branch below altogether?

cfd = accept4(svrfd, reinterpret_cast<struct sockaddr *>(&csa), &csal, SOCK_CLOEXEC | SOCK_NONBLOCK);
if (cfd < 0) {
switch (errno) {
Expand Down Expand Up @@ -3028,9 +3054,15 @@ static int sockMain(int svrfd)
cr.echo = true;
cr.inifilename = inifilename; // Inherit global default
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);
}
Expand Down