0

日曜日は、libpcap を使用したパケット スニッフィングの理解に取り組んでおり、パケットとメタデータを読み取ることができるようになりました。いくつかのパケットをスニッフィングしてコードをチェックしていたとき、どこかにエラーがあるに違いないことがわかりました。

父の Web ページhttp://www.telpho.deを盗聴すると、サーバーの応答全体が返されます。200 OK から ... までですが、各パケットには、先頭に ASCII でない 4 バイトがあります。以下のコードでは、for ループを (i = 0) に変更すると、4 バイトも出力されます。(i = 4) のままにしておくと、受信した最初の ASCII 文字からペイロードが完全に表示されます。

私の質問は、data_offset を間違って計算しますか? 私が設定しなかったフラグはありますか?の tcp オプションを数え忘れましたか?

また、パディングと関係があるのではないかと思いました。TCP 標準では、TCP ヘッダーの長さは 32 の倍数である必要があるとされています。しかし、32 - 20 = 12.. なので、これは 3 バイトの違いです。

たとえばこんな計算になるのでしょうか。

TCP_HDR_SIZE = 32
sizeof(struct tcphdr) = 20
tcp->doff = 8    

sizeof(struct tcphdr) + tcp->doff = 28
TCP_HDR_SIZE - 28 = 4    <--- the 4 bytes i am looking for??? Maybe options? 

コードは次のとおりです。

void handle_packet_ip(const struct pcap_pkthdr *header, const u_char* data) {
  struct ip *ip;
  struct tcphdr *tcp;
  int ip_len;
  int data_offset;
  int payload_len;
  int i;
  unsigned char* payload;

  ip = (struct ip*)(data + sizeof(struct ether_header));
  ip_len = (ip->ip_hl & 0x0f) * 4;

  tcp = (struct tcphdr*)(data + sizeof(struct ether_header) + ip_len);
  printf("sizeof(ip): %d\n", sizeof(struct ip));
  printf("ip_len: %d\n", ip_len);
  printf("sizeof(ether_header): %d\n", sizeof(struct ether_header));
  printf("sizeof(tcp): %d\n", sizeof(struct tcphdr));

  data_offset = sizeof(struct ether_header) + ip_len + sizeof(struct tcphdr) + tcp->doff;
  payload_len = header->len - data_offset;

  payload = (unsigned char*)(data + data_offset);

  printf("IP PACKET\n");
  printf("\tlen: %u\n", ntohs(ip->ip_len));
  printf("\tsrc: %s\n", inet_ntoa(ip->ip_src));
  printf("\tdst: %s\n", inet_ntoa(ip->ip_dst));
  printf("\thl: %d\n", (ip->ip_hl & 0x0f));

  printf("READ TCP\n");
  printf("\tsrc port: %u\n", ntohs(tcp->source));
  printf("\tdst port: %u\n", ntohs(tcp->dest));
  printf("\tdata_offset: %d\n", data_offset); 
  printf("\tdoff: %d-%d\n", tcp->doff, ntohs(tcp->doff));
  printf("\tpayload len: %d\n", payload_len);
  printf("\tFLAGS\n");
  printf("\t\tFIN: %i\n", tcp->fin);
  printf("\t\tSYN: %i\n", tcp->syn);
  printf("\t\tACK: %i\n", tcp->ack);
  printf("PAYLOAD: \n");
  **for (i = 4; i < payload_len; ++i) {**
    printf("%c", payload[i]);
  }
  printf("\n");

  printf("\n");
  printf("END OF PAYLOAD\n");
}

出力:

Grabbed Packet:
Length: 74
    Capture Length: 74
sizeof(ip): 20
ip_len: 20
sizeof(ether_header): 14
sizeof(tcp): 20
IP PACKET
len: 60
src: 80.237.132.106
dst: 192.168.0.17
hl: 5
READ TCP
src port: 80
dst port: 57662
data_offset: 62     **this should be 64 ??**
doff: 8
payload len: 10
FLAGS
    FIN: 0
    SYN: 1
    ACK: 1
4

1 に答える 1

3

これは正しくないようです。

data_offset = sizeof(struct ether_header) + ip_len + sizeof(struct tcphdr) + tcp->doff

tcp->doff にはすでに tcp ヘッダーが含まれており、4 バイトの倍数になっています。だからあなたはしたいでしょう

 data_offset = sizeof(struct ether_header) + ip_len + tcp->doff * 4;

sizeof(struct tcphdr) だけを使用しても、発生する可能性のある TCP オプションは考慮されません。

コードは多くのことを想定していることに注意してください。

  • イーサネット VLAN がないことを前提としています
  • IP パケットがイーサネット上にあると仮定します (arp や stp などではありません)。
  • IP 上の TCP を想定
  • 必要なすべてのデータを実際にキャプチャしたと仮定します。(つまり、長さが header->cap_len を超えていないことを確認する必要があります)
于 2012-07-08T13:39:29.150 に答える