[rarun2] Added pseudo tty for listen and connect (#6328)

* [rarun2] added pseudo tty for listen and connect
* Fixed the socket connect error message
* [rarun2] moved pseudo tty under pty option
This commit is contained in:
Asutosh Palai 2016-12-15 19:36:06 +05:30 committed by radare
parent 3ca5f5f1f7
commit 79a609630f
4 changed files with 138 additions and 14 deletions

View File

@ -205,6 +205,7 @@ typedef struct r_run_profile_t {
char *_input;
char *_connect;
char *_listen;
int _pty;
int _timeout;
int _timeout_sig;
int _nice;

View File

@ -46,6 +46,8 @@
#endif
#endif
#define HAVE_PTY __UNIX__ && !__ANDROID__ && LIBC_HAVE_FORK
R_API RRunProfile *r_run_new(const char *str) {
RRunProfile *p = R_NEW (RRunProfile);
if (p) {
@ -221,7 +223,7 @@ static void setASLR(int enabled) {
}
static int handle_redirection_proc (const char *cmd, bool in, bool out, bool err) {
#if __UNIX__ && !__ANDROID__ && LIBC_HAVE_FORK
#if HAVE_PTY
// use PTY to redirect I/O because pipes can be problematic in
// case of interactive programs.
int fdm;
@ -352,6 +354,7 @@ R_API int r_run_parseline (RRunProfile *p, char *b) {
else if (!strcmp (b, "pidfile")) p->_pidfile = strdup (e);
else if (!strcmp (b, "connect")) p->_connect = strdup (e);
else if (!strcmp (b, "listen")) p->_listen = strdup (e);
else if (!strcmp (b, "pty")) p->_pty = parseBool (e);
else if (!strcmp (b, "stdio")) {
if (e[0] == '!') {
p->_stdio = strdup (e);
@ -448,6 +451,7 @@ R_API const char *r_run_help() {
"timeout=3\n"
"# connect=localhost:8080\n"
"# listen=8080\n"
"# pty=false\n"
"# fork=true\n"
"# bits=32\n"
"# pid=0\n"
@ -475,6 +479,116 @@ R_API const char *r_run_help() {
"# nice=5\n";
}
#if __UNIX__
static int fd_forward(int in_fd, int out_fd, char **buff) {
int size = 0;
if (ioctl (in_fd, FIONREAD, &size) == -1) {
perror ("ioctl");
return -1;
}
if (size == 0) { // child process exited or socket is closed
return -1;
}
char *new_buff = realloc (*buff, size);
if (new_buff == NULL) {
eprintf ("Failed to allocate buffer for redirection");
return -1;
}
*buff = new_buff;
read (in_fd, *buff, size);
if (write (out_fd, *buff, size) != size) {
perror ("write");
return -1;
}
return 0;
}
#endif
static int redirect_socket_to_stdio(RSocket *sock) {
close (0);
close (1);
close (2);
dup2 (sock->fd, 0);
dup2 (sock->fd, 1);
dup2 (sock->fd, 2);
return 0;
}
static int redirect_socket_to_pty(RSocket *sock) {
#if HAVE_PTY
// directly duplicating the fds using dup2() creates problems
// in case of interactive applications
int fdm;
pid_t child_pid = forkpty (&fdm, NULL, NULL, NULL);
if (child_pid == -1) {
perror ("forking pty");
return -1;
}
if (child_pid == 0) {
// child process
r_socket_close_fd (sock);
// disable the echo on slave stdin
struct termios t;
tcgetattr (0, &t);
cfmakeraw (&t);
tcsetattr (0, TCSANOW, &t);
return 0;
}
// parent
char *buff = NULL;
int sockfd = sock->fd;
int max_fd = fdm > sockfd ? fdm : sockfd;
while (true) {
fd_set readfds;
FD_ZERO (&readfds);
FD_SET (fdm, &readfds);
FD_SET (sockfd, &readfds);
int activity = select (max_fd + 1, &readfds, NULL, NULL, NULL);
if (activity < 0) {
perror ("select error");
break;
}
if (FD_ISSET (fdm, &readfds)) {
if (fd_forward (fdm, sockfd, &buff) != 0) {
break;
}
}
if (FD_ISSET (sockfd, &readfds)) {
if (fd_forward (sockfd, fdm, &buff) != 0) {
break;
}
}
}
free (buff);
close (fdm);
r_socket_free (sock);
_exit (0);
#else
// Fallback to socket to I/O redirection
return redirect_socket_to_stdio (sock);
#endif
}
R_API int r_run_config_env(RRunProfile *p) {
int ret;
@ -521,12 +635,15 @@ R_API int r_run_config_env(RRunProfile *p) {
return 1;
}
eprintf ("connected\n");
close (0);
close (1);
close (2);
dup2 (fd->fd, 0);
dup2 (fd->fd, 1);
dup2 (fd->fd, 2);
if (p->_pty) {
if (redirect_socket_to_pty (fd) != 0) {
eprintf ("socket redirection failed\n");
r_socket_free (fd);
return 1;
}
} else {
redirect_socket_to_stdio (fd);
}
} else {
eprintf ("Invalid format for connect. missing ':'\n");
return 1;
@ -561,12 +678,16 @@ R_API int r_run_config_env(RRunProfile *p) {
if (is_child) {
r_socket_close_fd (fd);
eprintf ("connected\n");
close (0);
close (1);
close (2);
dup2 (child->fd, 0);
dup2 (child->fd, 1);
dup2 (child->fd, 2);
if (p->_pty) {
if (redirect_socket_to_pty (child) != 0) {
eprintf ("socket redirection failed\n");
r_socket_free (child);
r_socket_free (fd);
return 1;
}
} else {
redirect_socket_to_stdio (child);
}
break;
} else {
r_socket_close_fd (child);

View File

@ -253,7 +253,7 @@ R_API bool r_socket_connect (RSocket *s, const char *host, const char *port, int
}
freeaddrinfo (res);
if (!rp) {
eprintf ("Could not resolve address '%s'\n", host);
eprintf ("Could not resolve address '%s' or failed to connect\n", host);
return false;
}
}

View File

@ -34,6 +34,8 @@ unset the whole environment
set no limit the core file size
.It Ar connect
connect stdin/stdout/stderr to a socket
.It Ar pty
use a pty for connection over socket (with connect/listen)
.It Ar envfile
set a file with lines like `var=value` to be used as env
.It Ar fork