aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libbb.h21
-rw-r--r--libbb/xconnect.c234
-rw-r--r--networking/telnet.c31
-rw-r--r--networking/telnetd.c2
4 files changed, 172 insertions, 116 deletions
diff --git a/include/libbb.h b/include/libbb.h
index 6f66c8545..16f092f60 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -293,18 +293,17 @@ extern void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen);
293extern int xconnect_tcp_v4(struct sockaddr_in *s_addr); 293extern int xconnect_tcp_v4(struct sockaddr_in *s_addr);
294extern struct hostent *xgethostbyname(const char *name); 294extern struct hostent *xgethostbyname(const char *name);
295extern struct hostent *xgethostbyname2(const char *name, int af); 295extern struct hostent *xgethostbyname2(const char *name, int af);
296extern int xsocket_stream_ip4or6(sa_family_t *fp); 296
297typedef union {
298 struct sockaddr sa;
299 struct sockaddr_in sin;
300#if ENABLE_FEATURE_IPV6
301 struct sockaddr_in6 sin6;
302#endif
303} sockaddr_inet;
304extern int dotted2sockaddr(const char *dotted, struct sockaddr* sp, int socklen);
305extern int create_and_bind_socket_ip4or6(const char *hostaddr, int port);
306extern int setsockopt_reuseaddr(int fd); 297extern int setsockopt_reuseaddr(int fd);
307extern int setsockopt_broadcast(int fd); 298extern int setsockopt_broadcast(int fd);
299/* Create server TCP socket bound to bindaddr:port. bindaddr can be NULL,
300 * numeric IP ("N.N.N.N") or numeric IPv6 address,
301 * and can have ":PORT" suffix. If no suffix trere, second argument is used */
302extern int create_and_bind_stream_or_die(const char *bindaddr, int port);
303/* Create client TCP socket connected to peer:port. Peer cannot be NULL.
304 * Peer can be numeric IP ("N.N.N.N"), numeric IPv6 address or hostname,
305 * and can have ":PORT" suffix. If no suffix trere, second argument is used */
306extern int create_and_connect_stream_or_die(const char *peer, int def_port);
308 307
309 308
310extern char *xstrdup(const char *s); 309extern char *xstrdup(const char *s);
@@ -506,7 +505,7 @@ USE_DESKTOP(long long) int uncompress(int fd_in, int fd_out);
506int inflate(int in, int out); 505int inflate(int in, int out);
507 506
508 507
509unsigned short bb_lookup_port(const char *port, const char *protocol, unsigned short default_port); 508unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port);
510void bb_lookup_host(struct sockaddr_in *s_in, const char *host); 509void bb_lookup_host(struct sockaddr_in *s_in, const char *host);
511 510
512int bb_make_directory(char *path, long mode, int flags); 511int bb_make_directory(char *path, long mode, int flags);
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index bc0691531..93c3cd5c6 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -6,39 +6,62 @@
6 * 6 *
7 */ 7 */
8 8
9#include <netinet/in.h>
9#include "libbb.h" 10#include "libbb.h"
10 11
12static const int one = 1;
13int setsockopt_reuseaddr(int fd)
14{
15 return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
16}
17int setsockopt_broadcast(int fd)
18{
19 return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one));
20}
21
22void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
23{
24 if (connect(s, s_addr, addrlen) < 0) {
25 if (ENABLE_FEATURE_CLEAN_UP)
26 close(s);
27 if (s_addr->sa_family == AF_INET)
28 bb_perror_msg_and_die("%s (%s)",
29 "cannot connect to remote host",
30 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
31 bb_perror_msg_and_die("cannot connect to remote host");
32 }
33}
34
11/* Return network byte ordered port number for a service. 35/* Return network byte ordered port number for a service.
12 * If "port" is a number use it as the port. 36 * If "port" is a number use it as the port.
13 * If "port" is a name it is looked up in /etc/services, if it isnt found return 37 * If "port" is a name it is looked up in /etc/services, if it isnt found return
14 * default_port 38 * default_port */
15 */ 39unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port)
16unsigned short bb_lookup_port(const char *port, const char *protocol, unsigned short default_port)
17{ 40{
18 unsigned short port_nr = htons(default_port); 41 unsigned port_nr = htons(default_port);
19 if (port) { 42 if (port) {
20 char *endptr;
21 int old_errno; 43 int old_errno;
22 long port_long;
23 44
24 /* Since this is a lib function, we're not allowed to reset errno to 0. 45 /* Since this is a lib function, we're not allowed to reset errno to 0.
25 * Doing so could break an app that is deferring checking of errno. */ 46 * Doing so could break an app that is deferring checking of errno. */
26 old_errno = errno; 47 old_errno = errno;
27 errno = 0; 48 port_nr = bb_strtou(port, NULL, 10);
28 port_long = strtol(port, &endptr, 10); 49 if (errno || port_nr > 65535) {
29 if (errno != 0 || *endptr!='\0' || endptr==port || port_long < 0 || port_long > 65535) {
30 struct servent *tserv = getservbyname(port, protocol); 50 struct servent *tserv = getservbyname(port, protocol);
31 if (tserv) { 51 if (tserv)
32 port_nr = tserv->s_port; 52 port_nr = tserv->s_port;
33 }
34 } else { 53 } else {
35 port_nr = htons(port_long); 54 port_nr = htons(port_nr);
36 } 55 }
37 errno = old_errno; 56 errno = old_errno;
38 } 57 }
39 return port_nr; 58 return port_nr;
40} 59}
41 60
61
62/* "Old" networking API - only IPv4 */
63
64
42void bb_lookup_host(struct sockaddr_in *s_in, const char *host) 65void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
43{ 66{
44 struct hostent *he; 67 struct hostent *he;
@@ -49,18 +72,6 @@ void bb_lookup_host(struct sockaddr_in *s_in, const char *host)
49 memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length); 72 memcpy(&(s_in->sin_addr), he->h_addr_list[0], he->h_length);
50} 73}
51 74
52void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)
53{
54 if (connect(s, s_addr, addrlen) < 0) {
55 if (ENABLE_FEATURE_CLEAN_UP) close(s);
56 if (s_addr->sa_family == AF_INET)
57 bb_perror_msg_and_die("%s (%s)",
58 "cannot connect to remote host",
59 inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr));
60 bb_perror_msg_and_die("cannot connect to remote host");
61 }
62}
63
64int xconnect_tcp_v4(struct sockaddr_in *s_addr) 75int xconnect_tcp_v4(struct sockaddr_in *s_addr)
65{ 76{
66 int s = xsocket(AF_INET, SOCK_STREAM, 0); 77 int s = xsocket(AF_INET, SOCK_STREAM, 0);
@@ -68,87 +79,144 @@ int xconnect_tcp_v4(struct sockaddr_in *s_addr)
68 return s; 79 return s;
69} 80}
70 81
71static const int one = 1;
72int setsockopt_reuseaddr(int fd)
73{
74 return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
75}
76int setsockopt_broadcast(int fd)
77{
78 return setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one));
79}
80 82
81int dotted2sockaddr(const char *dotted, struct sockaddr* sp, int socklen) 83/* "New" networking API */
82{
83 union {
84 struct in_addr a4;
85#if ENABLE_FEATURE_IPV6
86 struct in6_addr a6;
87#endif
88 } a;
89 84
90 /* TODO maybe: port spec? like n.n.n.n:nn */
91 85
86/* So far we do not expose struct and helpers to libbb */
87typedef struct len_and_sockaddr {
88 int len;
89 union {
90 struct sockaddr sa;
91 struct sockaddr_in sin;
92#if ENABLE_FEATURE_IPV6 92#if ENABLE_FEATURE_IPV6
93 if (socklen >= sizeof(struct sockaddr_in6) 93 struct sockaddr_in6 sin6;
94 && inet_pton(AF_INET6, dotted, &a.a6) > 0
95 ) {
96 ((struct sockaddr_in6*)sp)->sin6_family = AF_INET6;
97 ((struct sockaddr_in6*)sp)->sin6_addr = a.a6;
98 /* ((struct sockaddr_in6*)sp)->sin6_port = */
99 return 0; /* success */
100 }
101#endif 94#endif
102 if (socklen >= sizeof(struct sockaddr_in) 95 };
103 && inet_pton(AF_INET, dotted, &a.a4) > 0 96} len_and_sockaddr;
104 ) { 97//extern int xsocket_stream_ip4or6(sa_family_t *fp);
105 ((struct sockaddr_in*)sp)->sin_family = AF_INET; 98//extern len_and_sockaddr* host2sockaddr(const char *host, int def_port);
106 ((struct sockaddr_in*)sp)->sin_addr = a.a4; 99//extern len_and_sockaddr* dotted2sockaddr(const char *dotted, int def_port);
107 /* ((struct sockaddr_in*)sp)->sin_port = */ 100
108 return 0; /* success */ 101/* peer: "1.2.3.4[:port]", "www.google.com[:port]"
102 * def_port: if neither of above specifies port #
103 */
104static len_and_sockaddr* str2sockaddr(const char *host, int def_port, int ai_flags)
105{
106 int rc;
107 len_and_sockaddr *r; // = NULL;
108 struct addrinfo *result = NULL;
109 const char *org_host = host; /* only for error msg */
110 const char *cp;
111 char service[sizeof(int)*3 + 1];
112 struct addrinfo hint;
113
114 /* Ugly parsing of host:addr */
115 if (ENABLE_FEATURE_IPV6 && host[0] == '[') {
116 host++;
117 cp = strchr(host, ']');
118 if (!cp || cp[1] != ':') /* Malformed: must have [xx]:nn */
119 bb_error_msg_and_die("bad address '%s'", org_host);
120 //return r; /* return NULL */
121 } else {
122 cp = strrchr(host, ':');
123 if (ENABLE_FEATURE_IPV6 && cp && strchr(host, ':') != cp) {
124 /* There is more than one ':' (e.g. "::1") */
125 cp = NULL; /* it's not a port spec */
126 }
109 } 127 }
110 return 1; 128 if (cp) {
129 host = safe_strncpy(alloca(cp - host + 1), host, cp - host);
130 if (ENABLE_FEATURE_IPV6 && *cp != ':')
131 cp++; /* skip ']' */
132 cp++; /* skip ':' */
133 } else {
134 utoa_to_buf(def_port, service, sizeof(service));
135 cp = service;
136 }
137
138 memset(&hint, 0 , sizeof(hint));
139 /* hint.ai_family = AF_UNSPEC; - zero anyway */
140#if !ENABLE_FEATURE_IPV6
141 hint.ai_family = AF_INET; /* do not try to find IPv6 */
142#endif
143 /* Needed. Or else we will get each address thrice (or more)
144 * for each possible socket type (tcp,udp,raw...): */
145 hint.ai_socktype = SOCK_STREAM;
146 hint.ai_flags = ai_flags | AI_NUMERICSERV;
147 rc = getaddrinfo(host, cp, &hint, &result);
148 if (rc || !result)
149 bb_error_msg_and_die("bad address '%s'", org_host);
150 r = xmalloc(offsetof(len_and_sockaddr, sa) + result->ai_addrlen);
151 r->len = result->ai_addrlen;
152 memcpy(&r->sa, result->ai_addr, result->ai_addrlen);
153 freeaddrinfo(result);
154 return r;
155}
156
157static len_and_sockaddr* host2sockaddr(const char *host, int def_port)
158{
159 return str2sockaddr(host, def_port, 0);
160}
161
162static len_and_sockaddr* dotted2sockaddr(const char *host, int def_port)
163{
164 return str2sockaddr(host, def_port, NI_NUMERICHOST);
111} 165}
112 166
113int xsocket_stream_ip4or6(sa_family_t *fp) 167static int xsocket_stream_ip4or6(len_and_sockaddr *lsa)
114{ 168{
115 int fd; 169 int fd;
116#if ENABLE_FEATURE_IPV6 170#if ENABLE_FEATURE_IPV6
117 fd = socket(AF_INET6, SOCK_STREAM, 0); 171 fd = socket(AF_INET6, SOCK_STREAM, 0);
118 if (fp) *fp = AF_INET6; 172 lsa->sa.sa_family = AF_INET6;
119 if (fd < 0) 173 lsa->len = sizeof(struct sockaddr_in6);
174 if (fd >= 0)
175 return fd;
120#endif 176#endif
121 { 177 fd = xsocket(AF_INET, SOCK_STREAM, 0);
122 fd = xsocket(AF_INET, SOCK_STREAM, 0); 178 lsa->sa.sa_family = AF_INET;
123 if (fp) *fp = AF_INET; 179 lsa->len = sizeof(struct sockaddr_in);
124 }
125 return fd; 180 return fd;
126} 181}
127 182
128int create_and_bind_socket_ip4or6(const char *hostaddr, int port) 183int create_and_bind_stream_or_die(const char *bindaddr, int port)
129{ 184{
130 int fd; 185 int fd;
131 sockaddr_inet sa; 186 len_and_sockaddr *lsa;
132 187
133 memset(&sa, 0, sizeof(sa)); 188 if (bindaddr) {
134 if (hostaddr) { 189 lsa = dotted2sockaddr(bindaddr, port);
135 if (dotted2sockaddr(hostaddr, &sa.sa, sizeof(sa))) 190 /* currently NULL check is in str2sockaddr */
136 bb_error_msg_and_die("bad address '%s'", hostaddr); 191 //if (!lsa)
192 // bb_error_msg_and_die("bad address '%s'", bindaddr);
137 /* user specified bind addr dictates family */ 193 /* user specified bind addr dictates family */
138 fd = xsocket(sa.sa.sa_family, SOCK_STREAM, 0); 194 fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
139 } else 195 } else {
140 fd = xsocket_stream_ip4or6(&sa.sa.sa_family); 196 lsa = xzalloc(offsetof(len_and_sockaddr, sa) +
197 USE_FEATURE_IPV6(sizeof(struct sockaddr_in6))
198 SKIP_FEATURE_IPV6(sizeof(struct sockaddr_in))
199 );
200 fd = xsocket_stream_ip4or6(lsa);
201 }
141 setsockopt_reuseaddr(fd); 202 setsockopt_reuseaddr(fd);
203 xbind(fd, &lsa->sa, lsa->len);
204 free(lsa);
205 return fd;
206}
142 207
143 /* if (port >= 0) { */ 208int create_and_connect_stream_or_die(const char *peer, int port)
144#if ENABLE_FEATURE_IPV6 209{
145 if (sa.sa.sa_family == AF_INET6 /* && !sa.sin6.sin6_port */) 210 int fd;
146 sa.sin6.sin6_port = htons(port); 211 len_and_sockaddr *lsa;
147#endif
148 if (sa.sa.sa_family == AF_INET /* && !sa.sin.sin_port */)
149 sa.sin.sin_port = htons(port);
150 /* } */
151 212
152 xbind(fd, &sa.sa, sizeof(sa)); 213 lsa = host2sockaddr(peer, port);
214 /* currently NULL check is in str2sockaddr */
215 //if (!lsa)
216 // bb_error_msg_and_die("bad address '%s'", peer);
217 fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0);
218 setsockopt_reuseaddr(fd);
219 xconnect(fd, &lsa->sa, lsa->len);
220 free(lsa);
153 return fd; 221 return fd;
154} 222}
diff --git a/networking/telnet.c b/networking/telnet.c
index e65b6918d..5ca64e133 100644
--- a/networking/telnet.c
+++ b/networking/telnet.c
@@ -22,15 +22,7 @@
22 */ 22 */
23 23
24#include <termios.h> 24#include <termios.h>
25#include <unistd.h>
26#include <errno.h>
27#include <stdlib.h>
28#include <stdarg.h>
29#include <string.h>
30#include <signal.h>
31#include <arpa/telnet.h> 25#include <arpa/telnet.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <netinet/in.h> 26#include <netinet/in.h>
35#include "busybox.h" 27#include "busybox.h"
36 28
@@ -593,8 +585,9 @@ static void cookmode(void)
593 585
594int telnet_main(int argc, char** argv) 586int telnet_main(int argc, char** argv)
595{ 587{
588 char *host;
589 int port;
596 int len; 590 int len;
597 struct sockaddr_in s_in;
598#ifdef USE_POLL 591#ifdef USE_POLL
599 struct pollfd ufds[2]; 592 struct pollfd ufds[2];
600#else 593#else
@@ -610,11 +603,10 @@ int telnet_main(int argc, char** argv)
610 ttype = getenv("TERM"); 603 ttype = getenv("TERM");
611#endif 604#endif
612 605
613 memset(&G, 0, sizeof G); 606 /* memset(&G, 0, sizeof G); - already is */
614 607
615 if (tcgetattr(0, &G.termios_def) >= 0) { 608 if (tcgetattr(0, &G.termios_def) >= 0) {
616 G.do_termios = 1; 609 G.do_termios = 1;
617
618 G.termios_raw = G.termios_def; 610 G.termios_raw = G.termios_def;
619 cfmakeraw(&G.termios_raw); 611 cfmakeraw(&G.termios_raw);
620 } 612 }
@@ -627,19 +619,18 @@ int telnet_main(int argc, char** argv)
627 autologin = getenv("USER"); 619 autologin = getenv("USER");
628 620
629 if (optind < argc) { 621 if (optind < argc) {
630 bb_lookup_host(&s_in, argv[optind++]); 622 host = argv[optind++];
631 s_in.sin_port = bb_lookup_port((optind < argc) ? argv[optind++] : 623 port = bb_lookup_port((optind < argc) ? argv[optind++] :
632 "telnet", "tcp", 23); 624 "telnet", "tcp", 23);
633 if (optind < argc) 625 if (optind < argc)
634 bb_show_usage(); 626 bb_show_usage();
635 } else 627 } else
636 bb_show_usage(); 628 bb_show_usage();
637#else 629#else
638 bb_lookup_host(&s_in, argv[1]); 630 host = argv[1];
639 s_in.sin_port = bb_lookup_port((argc == 3) ? argv[2] : "telnet", "tcp", 23); 631 port = bb_lookup_port((argc > 2) ? argv[2] : "telnet", "tcp", 23);
640#endif 632#endif
641 633 G.netfd = create_and_connect_stream_or_die(host, port);
642 G.netfd = xconnect_tcp_v4(&s_in);
643 634
644 setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one); 635 setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
645 636
@@ -655,8 +646,7 @@ int telnet_main(int argc, char** argv)
655 maxfd = G.netfd + 1; 646 maxfd = G.netfd + 1;
656#endif 647#endif
657 648
658 while (1) 649 while (1) {
659 {
660#ifndef USE_POLL 650#ifndef USE_POLL
661 fd_set rfds = readfds; 651 fd_set rfds = readfds;
662 652
@@ -700,8 +690,7 @@ int telnet_main(int argc, char** argv)
700 { 690 {
701 len = read(G.netfd, G.buf, DATABUFSIZE); 691 len = read(G.netfd, G.buf, DATABUFSIZE);
702 692
703 if (len <= 0) 693 if (len <= 0) {
704 {
705 WriteCS(1, "Connection closed by foreign host.\r\n"); 694 WriteCS(1, "Connection closed by foreign host.\r\n");
706 doexit(1); 695 doexit(1);
707 } 696 }
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 604f65c91..a0ee2c345 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -414,7 +414,7 @@ telnetd_main(int argc, char **argv)
414 if (IS_INETD) { 414 if (IS_INETD) {
415 sessions = make_new_session(0, 1); 415 sessions = make_new_session(0, 1);
416 } else { 416 } else {
417 master_fd = create_and_bind_socket_ip4or6(opt_bindaddr, portnbr); 417 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
418 xlisten(master_fd, 1); 418 xlisten(master_fd, 1);
419 if (!(opt & OPT_FOREGROUND)) 419 if (!(opt & OPT_FOREGROUND))
420 xdaemon(0, 0); 420 xdaemon(0, 0);