0

私は、過去に行った他の多くのスクリプトと同じように、小さなクライアントサーバースクリプトを作成しようとしています。
しかし、これには問題があります。私がコードとそれが私に与える出力を投稿するならば、それはより良いです。
コード:

#include <mysql.h> //not important now
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

//constant definition
#define SERVER_PORT 2121
#define LINESIZE 21

//global var definition
char victim_ip[LINESIZE], file_write[LINESIZE], hacker_ip[LINESIZE];

//function
void leggi (int); //not use now for debugging purpose
//void scriviDB (); //not important now

main () {

int sock, client_len, fd;

struct sockaddr_in server, client;

// transport end point
if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  perror("system call socket fail");
  exit(1);
}

server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("10.10.10.1");
server.sin_port = htons(SERVER_PORT);

// binding address at transport end point
if (bind(sock, (struct sockaddr *)&server, sizeof server) == -1) {
  perror("system call bind fail");
  exit(1);
}

//fprintf(stderr, "Server open: listening.\n");
listen(sock, 5);

/* managae client connection */
while (1) {
  client_len = sizeof(client);
  if ((fd = accept(sock, (struct sockaddr *)&client, &client_len)) < 0) 
     { perror("accepting connection"); exit(1);  }

  strcpy(hacker_ip, inet_ntoa(client.sin_addr));
  printf("1 %s\n", hacker_ip); //debugging purpose
  //leggi(fd);

//////////////////////////
//receive client 
  recv(fd, victim_ip, LINESIZE, 0);
  victim_ip[sizeof(victim_ip)] = '\0';
  printf("2 %s\n", hacker_ip); //debugging purpose
  recv(fd, file_write, LINESIZE, 0);
  file_write[sizeof(file_write)] = '\0';
  printf("3 %s\n", hacker_ip); //debugging purpose
  printf("%s@%s for %s\n", file_write, victim_ip, hacker_ip);

  //send to client
  send(fd, hacker_ip, 40, 0); //now is hacker_ip for debug

/////////////////////////

  close(fd);

}//end while

exit(0);
} //end main

クライアント送信文字列:./ send -i 10.10.10.4 -f filename.ext
なので、スクリプトはサーバーで-i(IP)と-f(FILE)を送信します。
これが私の出力サーバー側です:

1 10.10.10.6
2 10.10.10.6
3
filename.ext@10.10.10.4 for

ご覧のとおり、printf(3)とprintf(ip、file、ip)は失敗します。
方法と場所はわかりませんが、誰かが私のhacker_ip文字列を上書きします。
ご協力いただきありがとうございます!:)

4

2 に答える 2

3

TCPは、パケットではなくストリームを提供します。したがって、1回のsend()呼び出しで送信するデータが、1回のrecv()呼び出しで受信されるという保証はありません。1つのsend()呼び出しが送信したものを受信するには、複数のrecv()呼び出しが必要になる場合があります。または、複数のsend()呼び出しが送信したものを受信するには、1つのrecv()呼び出しが必要になる場合があります。

特に、recv()の戻り値をチェックして、受け取ったバイト数を確認する必要があります。これが開始になる可能性があるため、少なくとも文字列にガベージを出力しないようにします。

ssize_t bytes = recv(fd, victim_ip, LINESIZE, 0);
 if(bytes == 0) {
   //remote closed the connection, handle it
 } else if (bytes < 0) {
    //handle error
 } else {
   victim_ip[bytes] = '\0';
   printf("%s\n", victim_ip); 
}
于 2010-05-26T09:20:21.480 に答える
1

次のような行を修正する必要があります。

victim_ip[sizeof(victim_ip)] = '\0';

file_write[sizeof(file_write)] = '\0';

これは、hacker_ip文字列を上書きするものです。

配列の終わりの後にゼロを書き込みます(sizeof(file_write) == LINE_SIZE)。ウォッチドッグゼロを記述したい場合は、配列の次元をのようにもう1文字に設定する必要がありますfile_write[LINE_SIZE+1]

これを除いて、動作するはずです。ここのような非常に小さいデータチャンク(21バイト)の場合、パケットが分割される可能性はほとんどありません(標準のイーサネットフレームは約1400バイトです)。ただし、複数の送信を行った場合、それらは確かに同じパケットにマージされます。

送信者コードを見るのは興味深いでしょう。毎回フルバッファを送信しましたか?(あなたのrecv()を見ているは​​ずです)。

于 2010-05-26T09:29:48.947 に答える