telnetd是一个telnet服务端程序
下载地址:
解压缩后进入busybox目录
make defconfig
make
make install
然后会生成 _install 目录,里面就是编译好的可执行文件
源码位于 ./networking/telnetd.c
程序流程图:
程序中非常重要的就是2个buf,位于struct tsession结构体之后
socket接收到远端的数据,写入count个字节到buf1中从rdidx1开始的空闲区域,然后size1 += count;rdidx1 += count;
pty可以写,从buf1中读取count个字节写入pty,然后size1 -= count;wridx1 += count;
pty可以读,写入count个字节到buf2中从rdidx2开始的空闲区域,然后size2 += count;rdidx2 += count;
socket可以发送数据到远端,从buf2中wridx2开始的位置读取count个字节,通过socket发送出去,然后size2 -= count;wridx2 += count;
-
master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
-
xlisten(master_fd, 1);
-
-
FD_ZERO(&rdfdset);
-
FD_ZERO(&wrfdset);
-
-
ts = G.sessions;
-
while (ts) {
-
struct tsession *next = ts->next;
-
if (ts->shell_pid == -1) {
-
-
free_session(ts);
-
} else {
-
if (ts->size1 > 0)
-
FD_SET(ts->ptyfd, &wrfdset);
-
if (ts->size1 < BUFSIZE)
-
FD_SET(ts->sockfd_read, &rdfdset);
-
if (ts->size2 > 0)
-
FD_SET(ts->sockfd_write, &wrfdset);
-
if (ts->size2 < BUFSIZE)
-
FD_SET(ts->ptyfd, &rdfdset);
-
}
-
ts = next;
-
}
-
-
FD_SET(master_fd, &rdfdset);
-
if (master_fd > G.maxfd)
-
G.maxfd = master_fd;
-
-
count = select(G.maxfd + 1, &rdfdset, &wrfdset, NULL, tv_ptr);
-
-
if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) {
-
int fd;
-
struct tsession *new_ts;
-
fd = accept(master_fd, NULL, NULL);
-
new_ts = make_new_session(fd);
-
new_ts->next = G.sessions;
-
G.sessions = new_ts;
-
}
-
-
-
-
-
-
ts = G.sessions;
-
while (ts) {
-
struct tsession *next = ts->next;
-
-
if ( FD_ISSET(ts->ptyfd, &wrfdset)) {
-
int num_totty;
-
unsigned char *ptr;
-
-
ptr = remove_iacs(ts, &num_totty);
-
count = safe_write(ts->ptyfd, ptr, num_totty);
-
if (count < 0) {
-
if (errno == EAGAIN)
-
goto skip1;
-
goto kill_session;
-
}
-
ts->size1 -= count;
-
ts->wridx1 += count;
-
if (ts->wridx1 >= BUFSIZE)
-
ts->wridx1 = 0;
-
}
-
skip1:
-
if ( FD_ISSET(ts->sockfd_write, &wrfdset)) {
-
-
count = MIN(BUFSIZE - ts->wridx2, ts->size2);
-
count = iac_safe_write(ts->sockfd_write, (void*)(TS_BUF2(ts) + ts->wridx2), count);
-
if (count < 0) {
-
if (errno == EAGAIN)
-
goto skip2;
-
goto kill_session;
-
}
-
ts->size2 -= count;
-
ts->wridx2 += count;
-
if (ts->wridx2 >= BUFSIZE)
-
ts->wridx2 = 0;
-
}
-
skip2:
-
-
-
-
-
-
-
if (ts->size1 == 0) {
-
ts->rdidx1 = 0;
-
ts->wridx1 = 0;
-
}
-
if (ts->size2 == 0) {
-
ts->rdidx2 = 0;
-
ts->wridx2 = 0;
-
}
-
-
if ( FD_ISSET(ts->sockfd_read, &rdfdset)) {
-
-
count = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1);
-
count = safe_read(ts->sockfd_read, TS_BUF1(ts) + ts->rdidx1, count);
-
if (count <= 0) {
-
if (count < 0 && errno == EAGAIN)
-
goto skip3;
-
goto kill_session;
-
}
-
-
if (!TS_BUF1(ts)[ts->rdidx1 + count - 1]) {
-
--count;
-
}
-
ts->size1 += count;
-
ts->rdidx1 += count;
-
if (ts->rdidx1 >= BUFSIZE)
-
ts->rdidx1 = 0;
-
}
-
skip3:
-
if ( FD_ISSET(ts->ptyfd, &rdfdset)) {
-
-
count = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2);
-
count = safe_read(ts->ptyfd, TS_BUF2(ts) + ts->rdidx2, count);
-
if (count <= 0) {
-
if (count < 0 && errno == EAGAIN)
-
goto skip4;
-
goto kill_session;
-
}
-
ts->size2 += count;
-
ts->rdidx2 += count;
-
if (ts->rdidx2 >= BUFSIZE)
-
ts->rdidx2 = 0;
-
}
-
skip4:
-
ts = next;
-
continue;
-
kill_session:
-
if (ts->shell_pid > 0)
-
update_utmp(ts->shell_pid, DEAD_PROCESS, NULL, NULL, NULL);
-
free_session(ts);
-
ts = next;
-
}
-
-
---------------------------------
-
| | | | | | | | | | | | | | | | |
-
---------------------------------
-
^ ^
-
| |
-
ptr0 end
-
-
remove_iacs函数对buf1中从wridx1开始size1长度的缓冲区进行操作,提取出实际有效地命令行语句,移动这段字符串到首部,
-
更新wridx1 += ptr - totty;size1 -= ptr - totty;num_totty是实际有效地命令行语句的字节个数,返回首部地址。
-
static unsigned char *
-
remove_iacs(struct tsession *ts, int *pnum_totty)
-
{
-
unsigned char *ptr0 = TS_BUF1(ts) + ts->wridx1;
-
unsigned char *ptr = ptr0;
-
unsigned char *totty = ptr;
-
unsigned char *end = ptr + MIN(BUFSIZE - ts->wridx1, ts->size1);
-
int num_totty;
-
-
while (ptr < end) {
-
-
-
}
-
-
num_totty = totty - ptr0;
-
*pnum_totty = num_totty;
-
-
-
if ((ptr - totty) == 0)
-
return ptr0;
-
ts->wridx1 += ptr - totty;
-
ts->size1 -= ptr - totty;
-
-
return memmove(ptr - num_totty, ptr0, num_totty);
-
}
-
-
-
-
free_session函数从G.sessions链表头中删除ts指向的结构,关闭pty和socket文件句柄,释放内存,更新G.maxfd
-
static void
-
free_session(struct tsession *ts)
make_new_session函数非常关键,它调用xgetpty打开一个伪终端,调用vfork创建一个子进程,父进程保存打开的伪终端和相关句柄
后返回,子进程调用setsid,关闭标准输入,打开伪终端,然后将0重定向到标准输出和标准错误,然后执行/bin/login,login执行
验证过程后启动shell程序。
以后只要父进程往获得的伪终端句柄里面写数据,就是把输入写到子进程启动的shell里面,shell执行之后,父进程通过read读取伪
终端句柄,就可以读取到shell的标准输出。
-
static struct tsession *
-
make_new_session
-
{
-
struct tsession *ts = xzalloc
-
fd = xgetpty(tty_name);
-
ts->ptyfd = fd;
-
pid =vfork();
-
if(pid > 0)
-
{
-
-
return ts;
-
}
-
-
-
setsid();
-
close(0);
-
xopen(tty_name, O_RDWR);
-
dup2(0,1);
-
dup2(0,2);
-
execvp("/bin/login",);
-
_exit(EXIT_FAILURE);
-
}
阅读(2900) | 评论(0) | 转发(0) |