-
Notifications
You must be signed in to change notification settings - Fork 1.3k
halrmt: Allow IPv4 as fallback when IPv6 is disabled. #4405
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 |
|---|---|---|
|
|
@@ -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 | ||
|
|
@@ -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); | ||
| 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)); | ||
|
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. Same as #4403: this depends on net.ipv6.bindv6only being 0. With that sysctl at Explicit setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, ...) on the IPv6 |
||
| // 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()"); | ||
|
|
@@ -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); | ||
|
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. accept4() writes the real length back, so sizeof(csa) works for both families. |
||
| cfd = accept4(svrfd, reinterpret_cast<struct sockaddr *>(&csa), &csal, SOCK_CLOEXEC | SOCK_NONBLOCK); | ||
| if (cfd < 0) { | ||
| switch (errno) { | ||
|
|
@@ -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); | ||
| } | ||
|
|
||
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 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?