BB telnetd doesn't properly handle 2-byte IAC
sequences. (Both in the 1.10 and 1.11 we've used.)
The following diff is what we've applied, it fixes
both IAC-IAC (emacs M-DEL) and IAC-NOP (putty keepalive):
$ diff -c networking/telnetd.c~ networking/telnetd.c
*** networking/telnetd.c~ 2008-11-04 14:40:31.000000000 -0800
--- networking/telnetd.c 2008-11-06 14:16:51.000000000 -0800
***************
*** 74,82 ****
past (bf + len) then that IAC will be left unprocessed and
*processed
will be less than len.
- FIXME - if we mean to send 0xFF to the terminal then it will be
escaped,
- what is the escape character? We aren't handling that situation
here.
-
CR-LF ->'s CR mapping is also done here, for convenience.
NB: may fail to remove iacs which wrap around buffer!
--- 74,79 ----
***************
*** 103,108 ****
--- 100,113 ----
if (c == '\r' && ptr < end && (*ptr == '\n' ||
*ptr == '\0'))
ptr++;
} else {
+ if ((ptr+1) >= end) // Need at least 2
bytes.
+ break;
+ if (ptr[1] == NOP) // Ignore? (Keepalive,
etc.)
+ ptr += 2;
+ else if (ptr[1] == IAC){// Literal IAC?
+ *totty++ = ptr[1];
+ ptr += 2;
+ } else
/*
* TELOPT_NAWS support!
*/
***************
$
The bracing/indention stinks a bit, but this minimized
the diff's so that's how we went with it. A fully incorporated
fix would probably add a brace and an indention level.
We've also found a need to enable the stack's keepalive probes, our
embedded system will not tolerate an indefinite hung telnet session.
So we included the more-or-less standard telnetd -n disable option
in case the prior behavior was ever desired by our customers.
The diffs (continued from the invocation above) for that are:
*** 269,276 ****
enum {
OPT_WATCHCHILD = (1 << 2), /* -K */
OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -i */
! OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -p */
! OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -F */
};
#if ENABLE_FEATURE_TELNETD_STANDALONE
--- 293,301 ----
enum {
OPT_WATCHCHILD = (1 << 2), /* -K */
OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -i */
! OPT_NKEEPALIVE = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -n */
! OPT_PORT = (1 << 5) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -p */
! OPT_FOREGROUND = (1 << 7) * ENABLE_FEATURE_TELNETD_STANDALONE,
/* -F */
};
#if ENABLE_FEATURE_TELNETD_STANDALONE
***************
*** 373,379 ****
#endif
/* Even if !STANDALONE, we accept (and ignore) -i, thus people
* don't need to guess whether it's ok to pass -i to us */
! opt = getopt32(argv, "f:l:Ki"
USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
&issuefile, &loginpath
USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr,
&opt_bindaddr));
if (!IS_INETD /*&& !re_execed*/) {
--- 398,404 ----
#endif
/* Even if !STANDALONE, we accept (and ignore) -i, thus people
* don't need to guess whether it's ok to pass -i to us */
! opt = getopt32(argv, "f:l:Kin"
USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
&issuefile, &loginpath
USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr,
&opt_bindaddr));
if (!IS_INETD /*&& !re_execed*/) {
***************
*** 401,406 ****
--- 426,434 ----
#if ENABLE_FEATURE_TELNETD_STANDALONE
if (IS_INETD) {
+ if (!(opt & OPT_NKEEPALIVE))
+ setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
+ &const_int_1, sizeof(const_int_1));
sessions = make_new_session(0);
if (!sessions) /* pty opening or vfork problem, exit */
return 1; /* make_new_session prints error
message */
***************
*** 409,414 ****
--- 437,445 ----
xlisten(master_fd, 1);
}
#else
+ if (!(opt & OPT_NKEEPALIVE))
+ setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
+ &const_int_1, sizeof(const_int_1));
sessions = make_new_session();
if (!sessions) /* pty opening or vfork problem, exit */
return 1; /* make_new_session prints error message */
***************
*** 489,494 ****
--- 520,528 ----
if (fd < 0)
goto again;
/* Create a new session and link it into our active list
*/
+ if (!(opt & OPT_NKEEPALIVE))
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
+ &const_int_1, sizeof(const_int_1));
new_ts = make_new_session(fd);
if (new_ts) {
new_ts->next = sessions;
Basically just add a new -n option, and everywhere that
make_new_session()
is called you check first to see if you need the setsockopt() call. The
usage.h file got this too:
"\n -l LOGIN Exec LOGIN on connect" \
+ "\n -n No session keepalive probes" \
"\n -f issue_file Display issue_file instead of
/etc/issue" \
This might make a nice configurable option, if there's enough associated
code to trip the bloat-o-meter.
We also found a need to send the peer connection name into login's -h
argument so that successive programs could know to whom they were
talking.
I think that ssh already did this. (I wasn't the one to put in this
code.)
Here are those diffs (part of the invocation above):
*** 154,164 ****
USE_FEATURE_TELNETD_STANDALONE(int sock)
SKIP_FEATURE_TELNETD_STANDALONE(void)
) {
! const char *login_argv[2];
struct termios termbuf;
int fd, pid;
char tty_name[GETPTY_BUFSIZE];
struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE
* 2);
/*ts->buf1 = (char *)(ts + 1);*/
/*ts->buf2 = ts->buf1 + BUFSIZE;*/
--- 159,187 ----
USE_FEATURE_TELNETD_STANDALONE(int sock)
SKIP_FEATURE_TELNETD_STANDALONE(void)
) {
! const char *login_argv[3];
struct termios termbuf;
int fd, pid;
char tty_name[GETPTY_BUFSIZE];
struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE
* 2);
+ struct sockaddr_in ir_sin;
+ socklen_t size;
+ char envBuf[32];
+
+ size = sizeof(ir_sin);
+
+ memset(envBuf,0, sizeof envBuf);
+
+ // grab the peer IP address before it's gone
+ if (getpeername(sock, (struct sockaddr *) &ir_sin, &size) < 0) {
+ fprintf(stdout, "%s %d getsockname
error\n\r",__FUNCTION__,__LINE__);
+ bb_perror_msg("getsockname");
+ }
+ else
+ {
+ //fprintf(stdout, "%s %d
0x%s\n\r",__FUNCTION__,__LINE__,inet_ntoa(ir_sin.sin_addr));
+ snprintf(envBuf, sizeof envBuf - 1,
"-h%s",inet_ntoa(ir_sin.sin_addr));
+ }
/*ts->buf1 = (char *)(ts + 1);*/
/*ts->buf2 = ts->buf1 + BUFSIZE;*/
***************
*** 256,262 ****
/* Exec shell / login / whatever */
login_argv[0] = loginpath;
! login_argv[1] = NULL;
/* exec busybox applet (if PREFER_APPLETS=y), if that fails,
* exec external program */
BB_EXECVP(loginpath, (char **)login_argv);
--- 279,286 ----
/* Exec shell / login / whatever */
login_argv[0] = loginpath;
! login_argv[1] = envBuf;
! login_argv[2] = NULL;
/* exec busybox applet (if PREFER_APPLETS=y), if that fails,
* exec external program */
BB_EXECVP(loginpath, (char **)login_argv);
***************
Another configurable feature?
-- Jim
_______________________________________________
busybox mailing list
[email protected]
http://busybox.net/cgi-bin/mailman/listinfo/busybox