9f1134d4aa
9634d9031c
disabled unused code.
This patch removes what was left.
If do_pty is 2, the function returns immediately, so any later checks
for do_pty == 2 will always fail and can be removed together with
the code which is never executed. Then variable master is unused and
can be removed, too.
This issue was detected by coverity.
Cc: Blue Swirl <blauwirbel@gmail.com>
Signed-off-by: Stefan Weil <sw@weilnetz.de>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
409 lines
10 KiB
C
409 lines
10 KiB
C
/*
|
|
* Copyright (c) 1995 Danny Gasparovski.
|
|
*
|
|
* Please read the file COPYRIGHT for the
|
|
* terms and conditions of the copyright.
|
|
*/
|
|
|
|
#include <slirp.h>
|
|
#include <libslirp.h>
|
|
|
|
#include "monitor.h"
|
|
|
|
#ifdef DEBUG
|
|
int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR;
|
|
#endif
|
|
|
|
struct quehead {
|
|
struct quehead *qh_link;
|
|
struct quehead *qh_rlink;
|
|
};
|
|
|
|
inline void
|
|
insque(void *a, void *b)
|
|
{
|
|
register struct quehead *element = (struct quehead *) a;
|
|
register struct quehead *head = (struct quehead *) b;
|
|
element->qh_link = head->qh_link;
|
|
head->qh_link = (struct quehead *)element;
|
|
element->qh_rlink = (struct quehead *)head;
|
|
((struct quehead *)(element->qh_link))->qh_rlink
|
|
= (struct quehead *)element;
|
|
}
|
|
|
|
inline void
|
|
remque(void *a)
|
|
{
|
|
register struct quehead *element = (struct quehead *) a;
|
|
((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
|
|
((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
|
|
element->qh_rlink = NULL;
|
|
}
|
|
|
|
int add_exec(struct ex_list **ex_ptr, int do_pty, char *exec,
|
|
struct in_addr addr, int port)
|
|
{
|
|
struct ex_list *tmp_ptr;
|
|
|
|
/* First, check if the port is "bound" */
|
|
for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
|
|
if (port == tmp_ptr->ex_fport &&
|
|
addr.s_addr == tmp_ptr->ex_addr.s_addr)
|
|
return -1;
|
|
}
|
|
|
|
tmp_ptr = *ex_ptr;
|
|
*ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list));
|
|
(*ex_ptr)->ex_fport = port;
|
|
(*ex_ptr)->ex_addr = addr;
|
|
(*ex_ptr)->ex_pty = do_pty;
|
|
(*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec);
|
|
(*ex_ptr)->ex_next = tmp_ptr;
|
|
return 0;
|
|
}
|
|
|
|
#ifndef HAVE_STRERROR
|
|
|
|
/*
|
|
* For systems with no strerror
|
|
*/
|
|
|
|
extern int sys_nerr;
|
|
extern char *sys_errlist[];
|
|
|
|
char *
|
|
strerror(error)
|
|
int error;
|
|
{
|
|
if (error < sys_nerr)
|
|
return sys_errlist[error];
|
|
else
|
|
return "Unknown error.";
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
int
|
|
fork_exec(struct socket *so, const char *ex, int do_pty)
|
|
{
|
|
/* not implemented */
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
/*
|
|
* XXX This is ugly
|
|
* We create and bind a socket, then fork off to another
|
|
* process, which connects to this socket, after which we
|
|
* exec the wanted program. If something (strange) happens,
|
|
* the accept() call could block us forever.
|
|
*
|
|
* do_pty = 0 Fork/exec inetd style
|
|
* do_pty = 1 Fork/exec using slirp.telnetd
|
|
* do_ptr = 2 Fork/exec using pty
|
|
*/
|
|
int
|
|
fork_exec(struct socket *so, const char *ex, int do_pty)
|
|
{
|
|
int s;
|
|
struct sockaddr_in addr;
|
|
socklen_t addrlen = sizeof(addr);
|
|
int opt;
|
|
const char *argv[256];
|
|
/* don't want to clobber the original */
|
|
char *bptr;
|
|
const char *curarg;
|
|
int c, i, ret;
|
|
pid_t pid;
|
|
|
|
DEBUG_CALL("fork_exec");
|
|
DEBUG_ARG("so = %lx", (long)so);
|
|
DEBUG_ARG("ex = %lx", (long)ex);
|
|
DEBUG_ARG("do_pty = %lx", (long)do_pty);
|
|
|
|
if (do_pty == 2) {
|
|
return 0;
|
|
} else {
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = 0;
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
if ((s = qemu_socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
|
|
bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
|
|
listen(s, 1) < 0) {
|
|
lprint("Error: inet socket: %s\n", strerror(errno));
|
|
closesocket(s);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
pid = fork();
|
|
switch(pid) {
|
|
case -1:
|
|
lprint("Error: fork failed: %s\n", strerror(errno));
|
|
close(s);
|
|
return 0;
|
|
|
|
case 0:
|
|
setsid();
|
|
|
|
/* Set the DISPLAY */
|
|
getsockname(s, (struct sockaddr *)&addr, &addrlen);
|
|
close(s);
|
|
/*
|
|
* Connect to the socket
|
|
* XXX If any of these fail, we're in trouble!
|
|
*/
|
|
s = qemu_socket(AF_INET, SOCK_STREAM, 0);
|
|
addr.sin_addr = loopback_addr;
|
|
do {
|
|
ret = connect(s, (struct sockaddr *)&addr, addrlen);
|
|
} while (ret < 0 && errno == EINTR);
|
|
|
|
dup2(s, 0);
|
|
dup2(s, 1);
|
|
dup2(s, 2);
|
|
for (s = getdtablesize() - 1; s >= 3; s--)
|
|
close(s);
|
|
|
|
i = 0;
|
|
bptr = g_strdup(ex); /* No need to free() this */
|
|
if (do_pty == 1) {
|
|
/* Setup "slirp.telnetd -x" */
|
|
argv[i++] = "slirp.telnetd";
|
|
argv[i++] = "-x";
|
|
argv[i++] = bptr;
|
|
} else
|
|
do {
|
|
/* Change the string into argv[] */
|
|
curarg = bptr;
|
|
while (*bptr != ' ' && *bptr != (char)0)
|
|
bptr++;
|
|
c = *bptr;
|
|
*bptr++ = (char)0;
|
|
argv[i++] = strdup(curarg);
|
|
} while (c);
|
|
|
|
argv[i] = NULL;
|
|
execvp(argv[0], (char **)argv);
|
|
|
|
/* Ooops, failed, let's tell the user why */
|
|
fprintf(stderr, "Error: execvp of %s failed: %s\n",
|
|
argv[0], strerror(errno));
|
|
close(0); close(1); close(2); /* XXX */
|
|
exit(1);
|
|
|
|
default:
|
|
qemu_add_child_watch(pid);
|
|
/*
|
|
* XXX this could block us...
|
|
* XXX Should set a timer here, and if accept() doesn't
|
|
* return after X seconds, declare it a failure
|
|
* The only reason this will block forever is if socket()
|
|
* of connect() fail in the child process
|
|
*/
|
|
do {
|
|
so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
|
|
} while (so->s < 0 && errno == EINTR);
|
|
closesocket(s);
|
|
opt = 1;
|
|
setsockopt(so->s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(int));
|
|
opt = 1;
|
|
setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, (char *)&opt, sizeof(int));
|
|
fd_nonblock(so->s);
|
|
|
|
/* Append the telnet options now */
|
|
if (so->so_m != NULL && do_pty == 1) {
|
|
sbappend(so, so->so_m);
|
|
so->so_m = NULL;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef HAVE_STRDUP
|
|
char *
|
|
strdup(str)
|
|
const char *str;
|
|
{
|
|
char *bptr;
|
|
|
|
bptr = (char *)malloc(strlen(str)+1);
|
|
strcpy(bptr, str);
|
|
|
|
return bptr;
|
|
}
|
|
#endif
|
|
|
|
#include "monitor.h"
|
|
|
|
void lprint(const char *format, ...)
|
|
{
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
monitor_vprintf(default_mon, format, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void
|
|
u_sleep(int usec)
|
|
{
|
|
struct timeval t;
|
|
fd_set fdset;
|
|
|
|
FD_ZERO(&fdset);
|
|
|
|
t.tv_sec = 0;
|
|
t.tv_usec = usec * 1000;
|
|
|
|
select(0, &fdset, &fdset, &fdset, &t);
|
|
}
|
|
|
|
/*
|
|
* Set fd blocking and non-blocking
|
|
*/
|
|
|
|
void
|
|
fd_nonblock(int fd)
|
|
{
|
|
#ifdef FIONBIO
|
|
#ifdef _WIN32
|
|
unsigned long opt = 1;
|
|
#else
|
|
int opt = 1;
|
|
#endif
|
|
|
|
ioctlsocket(fd, FIONBIO, &opt);
|
|
#else
|
|
int opt;
|
|
|
|
opt = fcntl(fd, F_GETFL, 0);
|
|
opt |= O_NONBLOCK;
|
|
fcntl(fd, F_SETFL, opt);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
fd_block(int fd)
|
|
{
|
|
#ifdef FIONBIO
|
|
#ifdef _WIN32
|
|
unsigned long opt = 0;
|
|
#else
|
|
int opt = 0;
|
|
#endif
|
|
|
|
ioctlsocket(fd, FIONBIO, &opt);
|
|
#else
|
|
int opt;
|
|
|
|
opt = fcntl(fd, F_GETFL, 0);
|
|
opt &= ~O_NONBLOCK;
|
|
fcntl(fd, F_SETFL, opt);
|
|
#endif
|
|
}
|
|
|
|
void slirp_connection_info(Slirp *slirp, Monitor *mon)
|
|
{
|
|
const char * const tcpstates[] = {
|
|
[TCPS_CLOSED] = "CLOSED",
|
|
[TCPS_LISTEN] = "LISTEN",
|
|
[TCPS_SYN_SENT] = "SYN_SENT",
|
|
[TCPS_SYN_RECEIVED] = "SYN_RCVD",
|
|
[TCPS_ESTABLISHED] = "ESTABLISHED",
|
|
[TCPS_CLOSE_WAIT] = "CLOSE_WAIT",
|
|
[TCPS_FIN_WAIT_1] = "FIN_WAIT_1",
|
|
[TCPS_CLOSING] = "CLOSING",
|
|
[TCPS_LAST_ACK] = "LAST_ACK",
|
|
[TCPS_FIN_WAIT_2] = "FIN_WAIT_2",
|
|
[TCPS_TIME_WAIT] = "TIME_WAIT",
|
|
};
|
|
struct in_addr dst_addr;
|
|
struct sockaddr_in src;
|
|
socklen_t src_len;
|
|
uint16_t dst_port;
|
|
struct socket *so;
|
|
const char *state;
|
|
char buf[20];
|
|
int n;
|
|
|
|
monitor_printf(mon, " Protocol[State] FD Source Address Port "
|
|
"Dest. Address Port RecvQ SendQ\n");
|
|
|
|
for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
|
|
if (so->so_state & SS_HOSTFWD) {
|
|
state = "HOST_FORWARD";
|
|
} else if (so->so_tcpcb) {
|
|
state = tcpstates[so->so_tcpcb->t_state];
|
|
} else {
|
|
state = "NONE";
|
|
}
|
|
if (so->so_state & (SS_HOSTFWD | SS_INCOMING)) {
|
|
src_len = sizeof(src);
|
|
getsockname(so->s, (struct sockaddr *)&src, &src_len);
|
|
dst_addr = so->so_laddr;
|
|
dst_port = so->so_lport;
|
|
} else {
|
|
src.sin_addr = so->so_laddr;
|
|
src.sin_port = so->so_lport;
|
|
dst_addr = so->so_faddr;
|
|
dst_port = so->so_fport;
|
|
}
|
|
n = snprintf(buf, sizeof(buf), " TCP[%s]", state);
|
|
memset(&buf[n], ' ', 19 - n);
|
|
buf[19] = 0;
|
|
monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
|
|
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
|
|
ntohs(src.sin_port));
|
|
monitor_printf(mon, "%15s %5d %5d %5d\n",
|
|
inet_ntoa(dst_addr), ntohs(dst_port),
|
|
so->so_rcv.sb_cc, so->so_snd.sb_cc);
|
|
}
|
|
|
|
for (so = slirp->udb.so_next; so != &slirp->udb; so = so->so_next) {
|
|
if (so->so_state & SS_HOSTFWD) {
|
|
n = snprintf(buf, sizeof(buf), " UDP[HOST_FORWARD]");
|
|
src_len = sizeof(src);
|
|
getsockname(so->s, (struct sockaddr *)&src, &src_len);
|
|
dst_addr = so->so_laddr;
|
|
dst_port = so->so_lport;
|
|
} else {
|
|
n = snprintf(buf, sizeof(buf), " UDP[%d sec]",
|
|
(so->so_expire - curtime) / 1000);
|
|
src.sin_addr = so->so_laddr;
|
|
src.sin_port = so->so_lport;
|
|
dst_addr = so->so_faddr;
|
|
dst_port = so->so_fport;
|
|
}
|
|
memset(&buf[n], ' ', 19 - n);
|
|
buf[19] = 0;
|
|
monitor_printf(mon, "%s %3d %15s %5d ", buf, so->s,
|
|
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*",
|
|
ntohs(src.sin_port));
|
|
monitor_printf(mon, "%15s %5d %5d %5d\n",
|
|
inet_ntoa(dst_addr), ntohs(dst_port),
|
|
so->so_rcv.sb_cc, so->so_snd.sb_cc);
|
|
}
|
|
|
|
for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so->so_next) {
|
|
n = snprintf(buf, sizeof(buf), " ICMP[%d sec]",
|
|
(so->so_expire - curtime) / 1000);
|
|
src.sin_addr = so->so_laddr;
|
|
dst_addr = so->so_faddr;
|
|
memset(&buf[n], ' ', 19 - n);
|
|
buf[19] = 0;
|
|
monitor_printf(mon, "%s %3d %15s - ", buf, so->s,
|
|
src.sin_addr.s_addr ? inet_ntoa(src.sin_addr) : "*");
|
|
monitor_printf(mon, "%15s - %5d %5d\n", inet_ntoa(dst_addr),
|
|
so->so_rcv.sb_cc, so->so_snd.sb_cc);
|
|
}
|
|
}
|