I'm designing a pair of c programs that uses basic stream sockets to communicate between two programs, similar to a server-client interaction. Most of the programs seem to work fine, but the client end of the system keeps reporting an error that I can't quite work out.
The client program, once compiled, is executed using a command line argument, which as I understand is supposed to be the name of the server program. However, every time I run the following line
./client server
I get an error that only gets reported in the event that argv[1] is null. Here's the code from string_client.c:
if ((he=gethostbyname(argv[1])) == NULL) { // get the host info
perror("gethostbyname");
printf("%s", argv[1]);
exit(1);
}
server is just the executable file from string_server.c, which is supposed to wait for an incoming request from the client and receive input from the client program(and works as far as that, as far as I can tell). I'm not sure about the gethostbyname method, but as that code was provided, I haven't questioned it yet.
Also, whenever I try printing out argv[1], it comes out as "la"... not sure what's happening there. What's going on with the command line? am I just using the wrong argument?
Here you go:
#include <stdio.h>
#include <netdb.h>
extern int h_errno;
int main(int argc, char **argv)
{
struct hostent *he;
if(argc < 2)
{
printf("usage: %s hostname\n", argv[0]);
return 255;
}
if ((he=gethostbyname(argv[1])) == NULL) { // get the host info
perror("gethostbyname");
printf("%s", argv[1]);
return 1;
}
printf("%s resolved to %u.%u.%u.%u\n", argv[1],
(unsigned char)(he->h_addr_list[0][0]),
(unsigned char)(he->h_addr_list[0][1]),
(unsigned char)(he->h_addr_list[0][2]),
(unsigned char)(he->h_addr_list[0][3]));
return 0;
}
It works now:
$ gcc -Wall -o gethost gethost.c
$ ./gethost
usage: ./gethost hostname
$ ./gethost google.com
google.com resolved to 173.194.40.196
$ ./gethost localhost
localhost resolved to 127.0.0.1
Related
I'm recently writing a piece of code to access an external server using SSH and then communicating with interactive shell-like application to which I'm directly connecting through it.
I'm using embedded Linux with only basic libraries available, with no possibility to use any additional software nor library. Also, I have to do it via C/C++ code inside the application. So I've decided to use pipes and read(), write() system calls, and I would rather stick to that.
I've written some code to better understand and test the concept. But it doesn't work as expected. I've used a snippet from here. It seems to work fine, but then the loop in main behaves not as expected
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
static bool
start_subprocess(char *const command[], int *pid, int *infd, int *outfd)
{
int p1[2], p2[2];
if (!pid || !infd || !outfd)
return false;
if (pipe(p1) == -1)
goto err_pipe1;
if (pipe(p2) == -1)
goto err_pipe2;
if ((*pid = fork()) == -1)
goto err_fork;
if (*pid) {
/* Parent process. */
*infd = p1[1];
*outfd = p2[0];
close(p1[0]);
close(p2[1]);
return true;
} else {
/* Child process. */
dup2(p1[0], STDIN_FILENO);
dup2(p2[1], STDOUT_FILENO);
close(p1[0]);
close(p1[1]);
close(p2[0]);
close(p2[1]);
execvp(*command, command);
/* Error occured. */
fprintf(stderr, "error running %s: %s", *command, strerror(errno));
abort();
}
err_fork:
close(p2[1]);
close(p2[0]);
err_pipe2:
close(p1[1]);
close(p1[0]);
err_pipe1:
return false;
}
int main() {
char *cmd[4];
cmd[0] = "/usr/bin/ssh";
cmd[1] = "-tt";
cmd[2] = "user#localhost";
cmd[3] = NULL;
char buf[65535];
char msg[65535];
int pid, infd, outfd;
start_subprocess(cmd, &pid, &infd, &outfd);
printf ("Started app %s as %d\n\n", *cmd, pid);
while(1) {
read(outfd, buf, 65535);
printf(">>> %s\n", buf);
printf("<<< ");
scanf("%s", msg);
if(strcmp(msg, "exit") == 0) break;
write(infd, msg, strlen(msg));
}
return 0;
}
I've experimeted with various SSH -t settings and it seems to somehow work with -tt option enabled (As I understand it forces pseudoterminal), without it I'm getting
Pseudo-terminal will not be allocated because stdin is not a terminal.
So I assume -tt is correct here. But the beheviour is strange. I wanted to connect through SSH, then issue ls command and see the output, which should be similar to normal SSH :
user#xubuntuLTS ~/dev/cpp/pipes$ ssh localhost
>>>> WELCOME TO SSH SERVER <<<<
Last login: Thu Jan 3 22:34:35 2019 from 127.0.0.1
user#xubuntuLTS ~$ ls
Desktop dev Documents Downloads Music Pictures Public Templates TEST_FILE Videos
user#xubuntuLTS ~$
But insted, my application works like this:
user#xubuntuLTS ~/dev/cpp/pipes$ ./a.out
Started app /usr/bin/ssh as 18393
>>>> WELCOME TO SSH SERVER <<<<
>>> Last login: Thu Jan 3 22:35:28 2019 from 127.0.0.1
<<< ls
>>> user#xubuntuLTS ~$
<<<
ls
>>> ls0;user#xubuntuLTS: ~user#xubuntuLTS ~$
<<< ls
>>> ls0;user#xubuntuLTS: ~user#xubuntuLTS ~$
Can you hint me what is wrong in my code? I want to read exactly the same output as I see during "normal" SSH session from terminal, possibly having "appending" output during each read() call, so I can easily perform some automated task with this type of interactive communication. Please note that using standard terminal here is just an example, in the real world solution I'm connecting to some kind of command line interface program directly by logging through SSH, without actual access to shell.
I'm pretty sure that there is something wrong with correct usage of write() and read() here, but I'm not an expert in that matter.
I want to create a program in C that displays the router password using telnet protocol. The instruction to do that from cmd is:
open CMD
Type telnet <router ip>
Type the router dashboard User
Type the router dashboard password
Type wireless default
I try with
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
system("telnet 192.168.1.1");
system("Menara");
system("Menara");
system("wireless default");
system("PAUSE");
return 0;
}
but the program stops at the second argument so I assume that system() cannot communicate with telnet. Can someone give me the correct code?
You need to open a pipe to the telnet command and send commands to it. Look at the popen() function in C and look at this StackOverflow question.
Here is a code example (taken from the StackOverflow question that I just pointed before):
#include <stdio.h>
int main()
{
FILE *fp = popen("telnet 192.168.1.1","w");
fprintf(fp, "Menara\n");
fprintf(fp, "Menara\n");
fprintf(fp, "PAUSE\n");
if (pclose(fp) != 0) {
/* Error reported by pclose() */
fprintf (stderr, "Could not run more or other error.\n");
}
return 0;
}
Update: I tried to print the return value of system(). If ssh failed, it will return 65280, if it succeed ,it returns 0.
I want to ssh to another machine from my laptop,I write a C program, it access to that machine and touch a file on that machine. But sometimes the network is not stable or maybe that machine is down. Therefore, ssh will failed. How could I know the ssh failed in that program ? Sometime ssh to that machine succeed, but touch that file failed, how to distinguish them in the C program? How could I know that shell command failed is because of ssh failed not touch ? I don't want to stare at the screen, I want the program to check that automatically.
here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(int argc,const char *argv[])
{
while(1)
{
system("ssh liulyix#localhost -p 22210 'touch script/rebooter.sh'");
sleep(5);
}
}
Read the man page for system.
The proto type is
int system (constant char *command)
The return values are
-1 system was unable to execute the command because of say a fork failure. Look at the man page for execve and look at the error number which may raised. All these errnos are reasons why system will return -1.
All other returns ed values are the exit code of the command. 0 implies success, all other values imply the command crashed with EXIT_FAILURE.
Using function popen() will be more easy:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main(int argc,const char *argv[])
{
FILE *fp;
fp = popen("ssh liulyix#localhost -p 22210 'touch script/rebooter.sh'", "r");
while(1)
{
char *line; char buf[1024];
line = fgets(buf, 1024, fp);
if (line == NULL) break;
printf("%s", line);
}
pclose(fp);
return 0;
}
I want to get the value of kernel.shmmax in C code (which I query on centos5.0, centos6.0 and ubuntu10.04 using the shell command "$ sysctl -q kernel.shmmax").
I used the following code to find it:
#include <sys/sysctl.h>
const int SHM_ERROR=1;
main(){
int name[] = {KERN_SHMMAX};
int namelen = 1;
int oldval[1];
size_t oldlen = sizeof(oldval);
int rv = sysctl(name, namelen, (void*) oldval, &oldlen, NULL, 0);
if (rv!=0) {
fprintf(stderr, "while quering for shared memory size, sysctl returned error: %s\n", strerror(errno));
return SHM_ERROR;
}
else{
return 0;
}
}
After running the code above I get the following error:
while quering for shared memory size, sysctl returned error: Not a directory
I am clueless about why I am getting this error. I googled for it and found there is some issue with the paths into which library tries to look into.
I tried running the above code with GDB but the code doesn't steps into the function sysctl, otherwise I could have provided you more information.
Data point:
I am easily able to set and get kernel.shmmax from command line on all the operating systems mentioned using the following commands:
$ sysctl -q kernel.shmmax
$ sysctl -w kernel.shmmax=1000000000
Thanks
You shouldn't be calling sysctl from userspace code. From the man page:
Glibc does not provide a wrapper for this system call; call it using
syscall(2).
Or rather... don't call it: use of this system call has long been
discouraged, and it is so unloved that it is likely to disappear in a
future kernel version. Remove it from your programs now; use the
/proc/sys interface instead.
So give this a shot instead:
#include <stdio.h>
#define SHMMAX_SYS_FILE "/proc/sys/kernel/shmmax"
int main(int argc, char **argv)
{
unsigned int shmmax;
FILE *f = fopen(SHMMAX_SYS_FILE, "r");
if (!f) {
fprintf(stderr, "Failed to open file: `%s'\n", SHMMAX_SYS_FILE);
return 1;
}
if (fscanf(f, "%u", &shmmax) != 1) {
fprintf(stderr, "Failed to read shmmax from file: `%s'\n", SHMMAX_SYS_FILE);
fclose(f);
return 1;
}
fclose(f);
printf("shmmax: %u\n", shmmax);
return 0;
}
I install strace and see that sysctl looks at /proc/sys/kernel/shmmax with open() call instead of _sysctl() call or syscall() call.
It looks like this just sends a ping, but whats the point of that when you can just use ping?
/* WARNING: this is someone's attempt at writing a malware trojan. Do not
compile and *definitely* don't install. I added an exit as the
first line to avoid mishaps - msw */
int main (int argc, char *argv[])
{
exit(1);
unsigned int pid = 0;
char buffer[2];
char *args[] = {
"/bin/ping",
"-c",
"5",
NULL,
NULL
};
if (argc != 2)
return 0;
args[3] = strdup(argv[1]);
for (;;)
{
gets(buffer); /* FTW */
if (buffer[0] == 0x6e)
break;
switch (pid = fork())
{
case -1:
printf("Error Forking\n");
exit(255);
case 0:
execvp(args[0], args);
exit(1);
default:
break;
}
}
return 255;
}
It's a hack - or an attempt at a hack - to get arbitrary code run in a privileged mode. Ping needs to run SUID root to get a raw socket for an ICMP_ECHO_REQUEST and the intentional buffer overrun in gets(buffer) is intended to pass junk to ping.
I don't see how this could work in practice, but you shouldn't compile and run it.
It makes sure that ping is called with the arguments -c 5. Which is stupid, because a shell script or alias would be easier to read and faster to write.
This program basically emulates a simple shell program. A shell program is going to take the arguments of another program as input and launch that specified program in a new process. The program you have above is just hard coded for one specific program (ping in this case) and is very simple.
A shell program makes working with the operating system more user friendly by providing an interface to boot up programs.