用socket编写的linux反向远程管理程序(c/s模式)
这是我第一个正式写的linux程序,对我来说很有纪念意义。
程序主要是通过socket实现客户端连接到服务器端,然后服务器端可以控制客户端传递运行。
适用于客户端处于内网,服务器为公网的环境。其中使用了select函数实现并发连接。
源代码如下:
server.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 2048
#define BACKLOG 20
int
main(int argc, char **argv)
{
int i, j,maxi, maxfd, listenfd, connfd, sockfd,len,id;
int nready, client[FD_SETSIZE];
ssize_t n;
fd_set rset, allset;
char line[MAXLINE],temp[INET_ADDRSTRLEN];
socklen_t clilen,templen;
struct sockaddr_in cliaddr, servaddr,tempaddr;
char buf[20],cmd[20];
if ( (listenfd = socket(AF_INET, SOCK_STREAM, 0))<0 )
{
perror("socket");
}
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port =htons(1234);
if (bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) == -1)
{
perror("bind");
exit(1);
}
/* how we can get the binded socket information */
templen = sizeof(struct sockaddr);
if (getsockname(listenfd, (struct sockaddr *)&tempaddr,&templen) == -1){
perror("getsockname");
exit(1);
}
printf("Server is listening on port %d/n",ntohs(tempaddr.sin_port));
if (listen(listenfd,BACKLOG) == -1){
perror("listen");
exit(1);
}
maxfd = listenfd; /* initialize */
maxi = -1; /* index into client[] array */
for (i = 0; i < FD_SETSIZE; i++)
client[i] = -1; /* -1 indicates available entry */
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
FD_SET(0, &allset);
//maxfd = 0;
for ( ; ; ) {
rset = allset; /* structure assignment */
nready = select(maxfd+1, &rset, NULL, NULL, NULL);
if (nready == -1) {
printf("exit! select error! %s", strerror(errno));
break;
}
if (FD_ISSET(listenfd, &rset)) { /* new client connection */
clilen = sizeof(cliaddr);
if ( ( connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen) )
{
perror("accept");
}
printf("A new connect from: %s, port %d/n",
inet_ntop(AF_INET, &cliaddr.sin_addr, temp, INET_ADDRSTRLEN),ntohs(cliaddr.sin_port));
printf("input id and cmd like: id cmd/n");
for (i = 0; i < FD_SETSIZE; i++)
if (client[i] < 0) {
client[i] = connfd; /* save descriptor */
break;
}
if (i == FD_SETSIZE)
perror("too many clients");
FD_SET(connfd, &allset); /* add new descriptor to set */
if (connfd > maxfd)
maxfd = connfd; /* for select */
if (i > maxi)
maxi = i; /* max index in client[] array */
if (--nready <= 0)
continue; /* no more readable descriptors */
}
for (i = 0; i <= maxi; i++) { /* check all clients for data */
if ( (sockfd = client[i]) < 0)
continue;
if (FD_ISSET(sockfd, &rset)) {
//n = read(sockfd, line, MAXLINE);
if ( (n = read(sockfd, line, MAXLINE)) <= 0) {
//if(n==0){
/*4connection closed by client */
close(sockfd);
FD_CLR(sockfd, &allset);
client[i] = -1;
printf("client %d exited!/n",i);
}else {
printf("%s/n",line);
printf("from ID %d/n",i);
fflush(stdout);
}
bzero(line,MAXLINE);
if (--nready <= 0)
break; /* no more readable descriptors */
}
}
if (FD_ISSET(0, &rset)) {
/* 用户按键了,则读取用户输入的内容发送出去 */
bzero(buf, MAXLINE + 1);
fgets(buf, MAXLINE, stdin);
id=atoi(buf);
for(j=0;buf[j+1]!='/n';j++)
cmd[j]=buf[j+2];
for(j=0;(j<=maxi)&&((sockfd=client[j])>=0);j++)
{
if(j==id)
{
len =write(sockfd,cmd,strlen(cmd));
//bzero(cmd,sizeof(cmd));
if (len > 0)
printf("send %s command to ID %d/n",cmd, id);
else {
printf("send %s error!/n",buf);
break;
}
bzero(cmd,sizeof(cmd));
}
}
}
}
}
client.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define MAXLINE 4096
char sendhead[MAXLINE];
int main(int argc , char* argv[])
{
int sockfd;
struct sockaddr_in servaddr;
char *info="client number 1 ";
char *sys_err="system error!/n";
char *first="pid/tppid/t/tcmd/n";
int maxfdp1, stdineof;
fd_set rset;
char recvbuf[20],tmp[128],buffer[MAXLINE];
int n,len,fd;
FILE *ff;
if(argc!=3){
printf("useage:client address port ");
exit(0);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1 )
{
perror("socket");
exit(1);
}
printf("%s connect server/n",info);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(atoi(argv[2]));
inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
if( ( connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)) )<0)
{
perror("connect");
exit(1);
}
write(sockfd,info,strlen(info));
FD_ZERO(&rset);
for ( ; ; ) {
FD_SET(sockfd, &rset);
maxfdp1=sockfd+1;
if( ( select(maxfdp1, &rset, NULL, NULL, NULL) )<0)
{
perror("select");
}
if (FD_ISSET(sockfd, &rset)) { /* socket is readable */
bzero(recvbuf,20);
n=read(sockfd, recvbuf, 20) ;
if(n<0) {
perror("str_cli: server terminated prematurely");
}else if(n==0)
{
printf("sever shutdown!");
exit(-1);
}
printf("receive cmd:%s/n",recvbuf);
write(sockfd,info,strlen(info));
bzero(buffer,MAXLINE);
ff=popen(recvbuf,"r");
fread(buffer,sizeof(char),MAXLINE,ff);
write(sockfd,buffer,strlen(buffer));
//printf("%s",buffer);
bzero(buffer,MAXLINE);
}
}
exit(0);
}
其实这就是个简单的telnet程序,不过是反向连接的,linux的ssh也可以实现反向连接。
方法如下:
例如一部linux在内网,一部在公网,
在内网上执行: ssh -f -N -R 8888:localhost:22 xxx@xxx.xxx.org , xxx.xxx.org可以是ip,
在公网的的电脑上执行: ssh xxxx@localhost -p 8888 就可以成功连上内网的电脑了,
上面命令里面的 8888 是任一个本地端口。
参考文章: