libssh tunnel echoing input - c

I've created my own SSH reverse tunnel using libssh by following the tutorials at http://api.libssh.org/master/libssh_tutorial.html and piecing things together from various other samples. However, now, all I get is the client echoing back whatever is inputted via the tunnel connection. I'm trying to get to the point where I can execute commands through the reverse tunnel (ex: ls -al).
The reverse tunnel (initiated on the client side):
int reverse_loop(ssh_session session){
ssh_channel channel;
int rc;
int nbytes, nwritten;
char buf[256];
int port = 0;
rc = ssh_channel_listen_forward(session, NULL, 43434, NULL);
if (rc != SSH_OK){
fprintf(stderr, "Error opening remote port %s\n", ssh_get_error(session));
return rc;
}
channel = ssh_channel_accept_forward(session, 60000, &port);
if (channel == NULL){
fprintf(stderr, "Error waiting for incoming connection: %s\n", ssh_get_error(session));
return SSH_ERROR;
}
while(1){
printf("In loop\n");
nbytes = ssh_channel_read(channel, buf, sizeof(buf), 0);
if (nbytes < 0){
fprintf(stderr, "Error reading incoming data: %s\n", ssh_get_error(session));
ssh_channel_send_eof(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
printf("read channel\n");
if (nbytes > 0){
nwritten = ssh_channel_write(channel, buf, nbytes);
if (nwritten != nbytes){
fprintf(stderr, "Error sending answer: %s\n", ssh_get_error(session));
ssh_channel_send_eof(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
printf("Wrote channel\n");
}
printf("sent answer!\n");
}
// close_channel
ssh_channel_send_eof(channel);
ssh_channel_free(channel);
return SSH_OK;
}
Running this, the reverse session is initiated. So, from the SSH server, I can run:
> nc localhost 43434
ls (this is what I sent)
ls (this is what I receive)
pwd (this is what I sent)
pwd (this is what I receive)
Then on the client side, I see this output:
In loop
read channel
Wrote channel
sent answer!
In loop
What I'm looking for are the actual results of running ls or pwd (or whatever system command the user inputs, not the echo. Can anyone direct me on the step that I missed to do this?
Thanks!

Related

Socket not completely filling receive buffer

I'm building my own netcat style listener in C for a project that I'm working on.
The client (linux in this case) connects to the listener using netcat, and from the listener I'm able to send linux commands back. When running commands which give a small output (e.g. whoami, uname, pwd) the output comes back fine. However, when running a command that can give a substantial output (e.g. ls -la), I only get partial output until I send another command, which then means subsequent commands are executing the previous command. Screenshot:
Fig 1: Start of output
Fig 2: Entering another command to force output to finish
Fig 3: Now I'm one command behind, giving incorrect output.
Code as follows (includes/defines/other functions left out for brevity):
int main(int argc, char *argv[])
{
char readbuff[262144];
char user_input[1024] = "";
struct sockaddr_in srv, cln;
int bnd, checkrtr, len, lstn, new_sfd, rd, result, sfd, val;
if(argc != 2)
{
fprintf(stderr, "[*]Usage: %s <target_router>\n", argv[0]);
return -1;
}
check_router(argv[1]);
// Start a listener on port 8888
// Create the socket
sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd == -1)
{
fprintf(stderr, "\n[*]socket: %s (%d)", strerror(errno), errno);
return -1;
}
else
{
fprintf(stdout, "\n[*]Socket created.");
}
val = 1;
result = 0;
result = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if(result == -1)
{
fprintf(stderr, "\n[*]setsockopt: %s (%d)", strerror(errno), errno);
}
else
{
fprintf(stdout, "\n[*]Address reuse set");
}
srv.sin_family = AF_INET;
srv.sin_addr.s_addr = inet_addr(IP);
srv.sin_port = htons(atoi(LPORT));
len = sizeof(srv);
bnd = bind(sfd, (struct sockaddr*)&srv, len);
if(bnd != 0)
{
fprintf(stderr, "\n[*]bind: %s (%d)", strerror(errno), errno);
return -1;
}
else
{
fprintf(stdout, "\n[*]Socket bound");
}
lstn = listen(sfd, 10);
if(lstn != 0)
{
fprintf(stderr, "\n[*]listen: %s (%d)", strerror(errno), errno);
return -1;
}
else
{
fprintf(stdout, "\n[*]Server listening on %s:%s", IP, LPORT);
}
socklen_t len_c = sizeof(cln);
new_sfd = accept(sfd, (struct sockaddr*)&cln, &len_c);
if(new_sfd == -1)
{
fprintf(stderr, "\n[*]accept: %s (%d)", strerror(errno), errno);
return -1;
}
else
{
char *ip_c = inet_ntoa(cln.sin_addr);
fprintf(stdout, "\n[*]New connection from client: %s:%d\n", ip_c, ntohs(cln.sin_port));
while(1)
{
memset(readbuff, 0x00, sizeof(readbuff));
memset(user_input, 0x00, sizeof(user_input));
fgets(user_input, sizeof(user_input), stdin);
if(user_input[0] == '\n')
{
continue;
}
int send_data = send(new_sfd, user_input, sizeof(user_input), 0);
if(send_data == -1)
{
fprintf(stderr, "\n[*]send: %s (%d)", strerror(errno), errno);
continue;
}
rd = read(new_sfd, readbuff, sizeof(readbuff));
fprintf(stdout, "\n size of rd: %d", rd);
fprintf(stdout, "\n size of readbuff: %ld", sizeof(readbuff));
if(rd > 0)
{
fprintf(stdout, "\n%s", readbuff);
}
else if(rd == 0)
{
fprintf(stdout, "\n[*]Client connection closed.\n");
continue;
//break;
}
else
{
fprintf(stderr, "\n[*]recv: %s (%d)", strerror(errno), errno);
continue;
}
}
}
}
Is anyone able to give me a reason why the output stops partway through please?
That's quite to be expected.
A single read can only read as much data as has been received so far (or otherwise it would need to bend time and space). The other end may also not have sent off everything they have to send by the time you issue read, so a single read won't be able to read everything either (because, well, it may not have been sent).
Since TCP is a stream protocol, you will need to devise a way to know how many bytes to expect for a single "message" from the other end, and read exactly that many bytes so you know you've gotten everything the other end has to say; I'd recommend some sort of Type-Length-Value scheme, even if you didn't need more than 1 type at present.

How to reconnect to TCP server after network goes down and comes back up again?

I have a raspberry pi that connects to a TCP server and sends some data every couple of seconds, I want to be able to handle all kind of failures and disconnects, so at the moment I am trying a test where I disconnect the Huawei USB dongle that I am connecting through.
I have a thread that runs in the background and check the connection periodically. The code does not reconnect when I remove the USB dongle and plug it back in sometime later, I need help on how to make this more robust. At the moment on the server side I see that after I plug back in the USB dongle I see the client connect but immediately disconnect from it.
The thread is called KeepSocketOpen and inside here I call a ping function to 8.8.8.8 to see if the connection is still active and here is my code, I'm kind of new to socket programming so excuse the mess:
int ping(char *ipaddr)
{
char *command = NULL;
FILE *fp;
int x, match=0;
char* result = NULL;
size_t len = 0;
asprintf (&command, "%s %s -p 50 -r 3", "fping", ipaddr);
//printf ("%s %s -q 2>&1", "fping", ipaddr);
fp = popen(command, "r");
if (fp == NULL) {
fprintf(stderr, "Failed to execute fping command\n");
free(command);
return -1;
}
while(getline(&result, &len, fp) != -1) {
fputs(result, stdout);
//printf("%s",result);
}
for(x=0;x<len;x++)
{
if(x>5 && result[x]=='e'&& result[x-1]=='v'&& result[x-2]=='i'&& result[x-3]=='l'&& result[x-4]=='a')
{
match=1;
break;
}
}
if(match==0)
sleep(5);
free(result);
fflush(fp);
if (pclose(fp) != 0) {
perror("Cannot close stream.\n");
}
free(command);
//printf("%s\r\n",result);
if(match==0)
return -1;
else
return 1;
}
void* KeepSocketOpen(void *arg)
{
pthread_t id= pthread_self();
char tcprxbuff[1024];
int numbytes, status=0,attempts,reuse=1;
struct timeval timeout={0};
timeout.tv_sec=10;
timeout.tv_usec=0;
printf("in sock thread\r\n");
while(1)
{
if(is_socket_connected==0)
{
sock=socket(AF_INET,SOCK_STREAM,0);
addr.sin_family = AF_INET;
addr.sin_port = htons(34879);
addr.sin_addr.s_addr=inet_addr("X.X.X.X");
attempts=0;
setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(timeout));
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout));
setsockopt(sock, SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
status=connect(sock, (struct sockaddr *) &addr,sizeof (addr));
// wait for 5s and see if the socket has connected
do
{
delay(5);
}
while(errno && attempts++<1000);
if (attempts >=1000 || errno) // this is the fail case
{
printf("socket not connected %s\r\n",strerror(errno));
is_socket_connected=0;
close(sock);
//shutdown(sock,SHUT_RDWR);
sleep(30);
}
else
{
// fcntl(sock, F_SETFL, O_NONBLOCK);
printf("socket reconnected %d,%s\r\n",attempts,strerror(errno));
is_socket_connected=1;
write(sock, "HI FROM RASPI", strlen("HI FROM RASPI"));
}
}
else
{
numbytes=read(sock,tcprxbuff,sizeof(tcprxbuff));
if(numbytes==0)// if this is zero, socket was closed by server
{
is_socket_connected=0;
while(close(sock)==-1);
}
else
{
printf("socket connected:%d\r\n",numbytes);
status = ping("8.8.8.8");
if (status!=-1) {
printf("socket still connected:%d\r\n",status);
is_socket_connected=1;
} else {
printf("socket disconnected:%d\r\n",status);
is_socket_connected=0;
//shutdown(sock,SHUT_RDWR);
while(close(sock)==-1);
}
}
sleep(30);
}
}
}

SSH Tunneling with a c library

I am trying to use libssh library to open an SSH tunnel.
Basically, I need to reach a server through a tunnel. First, I would need to SSH to the gateway (I have already done this), then I would need to SSH from that host to the server:
[PC] -- ssh user1#gateway --> [gateway] -- ssh www#server --> [server]
The first ssh needs a password to reach the gateway but the second ssh is of a different user and it doesn't require a password.
I want to reach that server and execute a script, in this case, it's just a command: ls -all
I tried using ssh_channel_open_forward() but I don't know where to specify the 'user' plus it hangs when I use it. There aren't many examples to follow or that much of documentation.
Here is how I tried to reach a server through a bridge/tunnel :
int direct_forwarding(ssh_session session)
{
ssh_channel channel;
int rc = -1;
int nbytes, nwritten;
channel = ssh_channel_new(session);
if (channel == NULL) {
return rc;
}
printf("\n*********channel is created************\n");
rc = ssh_channel_open_forward(channel, "server", 22, "gateway", 22);
if (rc != SSH_OK)
{
ssh_channel_free(channel);
return rc;
}
printf("\n*********channel is opened************\n");
char *command = "ls -all";
nbytes = strlen(command);
nwritten = ssh_channel_write(channel, command, nbytes);
if (nbytes != nwritten)
{
ssh_channel_free(channel);
return SSH_ERROR;
}
printf("\n*********Write command is finished************\n");
char buffer[256];
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
while (nbytes > 0)
{
printf("number of bytes read : %d\n", nbytes);
if (write(1, buffer, nbytes) != (unsigned int)nbytes)
{
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
}
if (nbytes < 0)
{
ssh_channel_close(channel);
ssh_channel_free(channel);
return SSH_ERROR;
}
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
printf("\n*******************no errors*******************\n");
ssh_channel_free(channel);
return SSH_OK;
}
Is this possible in libssh?

Sending special characters to pseudo-terminal?

I'm trying to write a C program that creates a pseudo-terminal running a new bash instance, and records all the input and output that goes through it. The eventual goal would be to asynchronously send this to a server, where somebody else could view your terminal activity in real time.
I've completed the pseudo-term creation step, and I can start a new bash instance and log "most" of the input and output. My issue right now is that the pseudo-term isn't properly recognizing arrow keys. They get printed to the screen as ASCII values (^[[A, ^[[[B, ^[[C, ^[[D), instead of moving the cursor around the command line.
Here's the slave portion of the pty, which will run bash:
if(pid == 0){ //child
struct termios term_settings;
close(ptyfds.master);
rc = tcgetattr(ptyfds.slave, &term_settings);
cfmakeraw(&term_settings);
tcsetattr(ptyfds.slave, TCSANOW, &term_settings);
//replace stdin,out,err with the slave filedesc
close(0);
close(1);
close(2);
dup(ptyfds.slave);
dup(ptyfds.slave);
dup(ptyfds.slave);
//We can close original fd and use 0,1,2
close(ptyfds.slave);
//Make this process the session lead
setsid();
//Slave side of PTY becomes the new controlling terminal
ioctl(0, TIOCSCTTY, 1);
char ** child_argv = (char **) malloc(argc * sizeof(char*));
int i;
for(i=1; i<argc; i++){
child_argv[i-1] = strdup(argv[i]); //could be bash, bc, python
}
child_argv[i-1] = NULL;
rc = execvp(child_argv[0], child_argv);
}
And here's the master side of the pty, sending input to the slave and capturing its output.
if(pid == 0){ //parent
fd_set fd_in;
close(ptyfds.slave);
FILE *logFile = fopen("./log", "w");
while(1){
//Add stdin and master fd to object
FD_ZERO(&fd_in);
FD_SET(0,&fd_in);
FD_SET(ptyfds.master, &fd_in);
//intercept data from stdin or from slave out (which is redirected to master)
rc = select(ptyfds.master+1, &fd_in, NULL,NULL,NULL);
switch(rc){
case -1:
fprintf(stderr, "Error %d on select()\n", errno);
exit(1);
default:
if (FD_ISSET(0, &fd_in)){ //There's data on stdin
rc = read(0, input, sizeof(input));
if(rc > 0){
input[rc] = '\0';
write(ptyfds.master, input, rc);//send to master -> slave
fputs(input, logFile);
}
else if(rc < 0){
fprintf(stderr, "Error %d on stdin\n", errno);
exit(1);
}
}
if(FD_ISSET(ptyfds.master, &fd_in)){ //There's data from slave
rc = read(ptyfds.master, input, sizeof(input)-1);
if(rc > 0){
input[rc] = '\0';
write(1, input, rc);//send to stdout
fputs(input, logFile);
}
else if (rc < 0){
fprintf(stderr, "Error %d on read master pty\n", errno);
exit(1);
}
}
}//switch
}//while
}//end parent
I've tried messing around with the termios flags here, but there are none that specify arrow keys.
What do I need to do?
Much of this code came from here.
I think there was a mistake in the example program.
I was able to fix it by moving:
rc = tcgetattr(ptyfds.slave, &term_settings);
cfmakeraw(&term_settings);
tcsetattr(ptyfds.slave, TCSANOW, &term_settings);
into the master section and replacing ptyfds.slave with STDIN_FILENO
(This sets STDIN to raw mode, rather than the slave)

How to use recv to recieve long text strings

I am trying to create a server and client program that sends a string from client to server where the server executes that string and sends the output back to the client. I am doing this in linux and I am very confused why my program isnt working the least bit. Here is the code.
**Client**
int main()
{
//Code to use unix socket here
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
perror("connect");
exit(1);
}
printf("Connected.\n");
while(printf("> "), fgets(str, MAX, stdin), !feof(stdin)) {
if (send(s, str, strlen(str), 0) == -1) {
perror("send");
exit(1);
}
}
done=0;
do {
if(t=recv(s, str, MAX, 0)<0)
perror("recv failed at client side!\n");
str[t] = '\0';
if(strcmp(str, "ENDOFTRANS")==0)
{
printf("\nRead ENDOFTRANS. Breaking loop.\n");
done=1;
}
printf("Server > %s", str);
} while(!done);
}
And then the server code is:
**Server**
#define MAX 1000
int main(void)
{
//Unix socket code
//This process is now a daemon.
daemon();
//Listens for client connections, up to 5 clients can queue up at the same time.
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
for(;;) {
int done, n, status;
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done = 0;
do {
switch(fork())
{
case -1: //ERROR
perror("Could not fork.\n");
break;
case 0: //CHILD
//Accept string from client.
//Edit: Why am I getting an error here? says: Invalid argument.
if(n = recv(newsock, str, MAX, 0)) {
perror("Recv error at server side.\n");
exit(1);
}
str[n]='\0';
if (n <= 0) {
if (n < 0)
perror("recv");
done = 1;
}
printf("String=>%s<",str);
//Redirect socket to STDOUT & STDERR.
test = close(WRITE); assert(test==0);
test = dup(newsock); assert(test==WRITE);
test = close(ERROR); assert(test==0);
test = dup(newsock); assert(test==ERROR);
if (!done)
{
if (str==something)
{
//execute command
}
else {
//Fork and execvp the command
}
//Sends End of Transaction character.
ENDTHETRANS();
exit(0);
}
break;
default: //PARENT
//Parent keeps accepting further clients.
wait(&status);
if ((newsock= accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
done=1;
break;
}
} while (!done);
}
close(s);
}
Im relatively new to programming in general and from my understanding the client code is good except that when it recieves the text back from the server it only recieves the text in small bits (2 rows at a time). I have to keep pressing enter on client promt to get the rest of the input. I have tried so many things that by this point I dont even know what I am doing wrong anymore.
Firstly, in the server code, after it recieves the string from the client I have a printf("String=>%s<",str); that outputs the string. However when the server prints the output as String=>ls -l the < key at the end gets eaten up somehow. It shouldnt be doing that right?
Any help much appreciated. Please bare in mind that I am a beginner and have only used pipes as inter process communcation before. Now I wanna make my first unix socket program.
Thanks in advance.
The usual problem in cases such as this is not realizing that SOCK_STREAM sockets don't preserve message boundaries. So data sent with a send call might be split up and received in multiple recvs, or it might be coalesced and multiple sends end up in a single recv. Most importantly, when a kernel send buffer fills up, a send call might write partial data (sending only some of the requested data) and return a short return value. You need to test for this and resend the rest of the data.
Another problem that often shows up is issues with line endings (particularly when talking between linux and windows). There may be extra carriage return characters (\r) in the either the client or server that confuse the other side. These tend to result in apparently missing or truncated output when printed.
edit
The line
if(t=recv(s, str, MAX, 0)<0)
is equivalent to
if(t = (recv(s, str, MAX, 0)<0))
that is, it sets t to 0 or 1 depending on whether there was an error or not. As with most errors of this type, turning on warnings will give you some indication about it.

Resources