telnetd: if FEATURE_IPV6 is on, telnet will NOT work on IPv4 which is kind of stupid
No binary (build failed)
—
(log yok)
| @@ -37,10 +37,8 @@ | |
| #define BUFSIZE 4000 | |
| #if ENABLE_FEATURE_IPV6 | |
| - | #define SOCKET_TYPE AF_INET6 |
| typedef struct sockaddr_in6 sockaddr_type; | |
| #else | |
| - | #define SOCKET_TYPE AF_INET |
| typedef struct sockaddr_in sockaddr_type; | |
| #endif | |
| @@ -357,31 +355,77 @@ free_session(struct tsession *ts) | |
| } | |
| static int | |
| - | create_socket(int port, const char *opt_bindaddr) |
| + | dotted2sockaddr(const char *dotted, struct sockaddr* sp, int socklen) |
| + | { |
| + | union { |
| + | struct in_addr a4; |
| + | #if ENABLE_FEATURE_IPV6 |
| + | struct in6_addr a6; |
| + | #endif |
| + | } a; |
| + | |
| + | #if ENABLE_FEATURE_IPV6 |
| + | if (socklen >= sizeof(struct sockaddr_in6) |
| + | && inet_pton(AF_INET6, dotted, &a) > 0 |
| + | ) { |
| + | ((struct sockaddr_in6*)sp)->sin6_family = AF_INET6; |
| + | ((struct sockaddr_in6*)sp)->sin6_addr = a.a6; |
| + | } else |
| + | #endif |
| + | if (socklen >= sizeof(struct sockaddr_in) |
| + | && inet_pton(AF_INET, dotted, &a) > 0 |
| + | ) { |
| + | ((struct sockaddr_in*)sp)->sin_family = AF_INET; |
| + | ((struct sockaddr_in*)sp)->sin_addr = a.a4; |
| + | } else |
| + | return 1; |
| + | |
| + | return 0; /* success */ |
| + | } |
| + | |
| + | static int |
| + | xsocket_stream_ip4or6(sa_family_t *fp) |
| + | { |
| + | int fd = socket(AF_INET6, SOCK_STREAM, 0); |
| + | if (fp) *fp = AF_INET6; |
| + | if (fd < 0) { |
| + | fd = xsocket(AF_INET, SOCK_STREAM, 0); |
| + | if (fp) *fp = AF_INET; |
| + | } |
| + | return fd; |
| + | } |
| + | |
| + | static int |
| + | create_socket(const char *hostaddr, int port) |
| { | |
| static const int on = 1; | |
| int fd; | |
| - | sockaddr_type sa; |
| - | #if !ENABLE_FEATURE_IPV6 |
| - | struct in_addr bind_addr = { .s_addr = 0x0 }; |
| + | union { |
| + | struct sockaddr sa; |
| + | struct sockaddr_in sin; |
| + | #if ENABLE_FEATURE_IPV6 |
| + | struct sockaddr_in6 sin6; |
| + | #endif |
| + | } sa; |
| - | /* TODO: generic string -> sockaddr converter */ |
| - | if (opt_bindaddr && inet_aton(opt_bindaddr, &bind_addr) == 0) |
| + | memset(&sa, 0, sizeof(sa)); |
| + | if (hostaddr && dotted2sockaddr(hostaddr, &sa.sa, sizeof(sa))) |
| bb_show_usage(); | |
| - | #endif |
| - | fd = xsocket(SOCKET_TYPE, SOCK_STREAM, 0); |
| + | |
| + | if (!sa.sa.sa_family) |
| + | fd = xsocket_stream_ip4or6(&sa.sa.sa_family); |
| + | else /* user specified -b ADDR dictates family */ |
| + | fd = xsocket(sa.sa.sa_family, SOCK_STREAM, 0); |
| setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); | |
| - | memset((void *)&sa, 0, sizeof(sa)); |
| + | |
| #if ENABLE_FEATURE_IPV6 | |
| - | sa.sin6_family = AF_INET6; |
| - | sa.sin6_port = htons(port); |
| - | /* sa.sin6_addr = bind_addr6; */ |
| - | #else |
| - | sa.sin_family = AF_INET; |
| - | sa.sin_port = htons(port); |
| - | sa.sin_addr = bind_addr; |
| + | if (sa.sa.sa_family == AF_INET6) |
| + | sa.sin6.sin6_port = htons(port); |
| #endif | |
| - | xbind(fd, (struct sockaddr *) &sa, sizeof(sa)); |
| + | if (sa.sa.sa_family == AF_INET) |
| + | sa.sin.sin_port = htons(port); |
| + | |
| + | xbind(fd, &sa.sa, sizeof(sa)); |
| xlisten(fd, 1); | |
| return fd; | |
| } | |
| @@ -390,7 +434,7 @@ create_socket(int port, const char *opt_bindaddr) | |
| /* Never actually called */ | |
| void free_session(struct tsession *ts); | |
| - | int create_socket(int port, const char *opt_bindaddr); |
| + | int create_socket(const char *hostaddr, int port); |
| #endif | |
| @@ -447,7 +491,7 @@ telnetd_main(int argc, char **argv) | |
| if (IS_INETD) { | |
| sessions = make_new_session(0, 1); | |
| } else { | |
| - | master_fd = create_socket(portnbr, opt_bindaddr); |
| + | master_fd = create_socket(opt_bindaddr, portnbr); |
| if (!(opt & OPT_FOREGROUND)) | |
| xdaemon(0, 0); | |
| } | |