0

イーサネットレベルで動作する単純なエコーサーバー/クライアントを構築しようとしています(生のソケットを使用)。サーバー側はそれ自体で動作し、eth0 ですべての着信パケットを表示します。クライアントは動作し、eth0 でイーサネット パケットを送信します (wireshark で確認したところ、パケットが送信されていることがわかりました)。関心のあるパケットのみを表示するフィルターを作成したいと考えています。(これは宛先/送信元アドレスに基づいています。)

以下のコードで、strncmp が 0 を返す (つまり、文字列が一致する) のに、「if(ethernet_header->h_dest == mac)」が実行に失敗する (一致しない) 理由を説明してください。変数 "mac" と "ethernet_header->h_dest" はどちらも同じ型と長さです。

いくつかの背景: - これは linux 64 ビット (ubuntu) で行われます - 送信/受信に同じマシンで eth0 を使用しています....これは問題ではないと思いますか?

strcmp が一致を返す理由と、そうでない場合の理由がわかりません。何が足りないの??

void ParseEthernetHeader(unsigned char *packet, int len) {
    struct ethhdr *ethernet_header;
 unsigned char mac[ETH_ALEN] = {0x01, 0x55, 0x56, 0x88, 0x32, 0x7c}; 

 if (len > sizeof(struct ethhdr)) {
  ethernet_header = (struct ethhdr *) packet;

  int result = strncmp(ethernet_header->h_dest, mac, ETH_ALEN);
  printf("Result: %d\n", result);

  if(ethernet_header->h_dest == mac) {
   /* First set of 6 bytes are Destination MAC */
   PrintInHex("Destination MAC: ", ethernet_header->h_dest, 6);
   printf("\n");

   /* Second set of 6 bytes are Source MAC */
   PrintInHex("Source MAC: ", ethernet_header->h_source, 6);
   printf("\n");

   /* Last 2 bytes in the Ethernet header are the protocol it carries */
   PrintInHex("Protocol: ", (void *) &ethernet_header->h_proto, 2);
   printf("\n\n");
   printf("Length: %d\n",len);
  }

 } else {
  printf("Packet size too small (length: %d)!\n",len);
 }

}
4

6 に答える 6

9

MAC アドレスの比較には、ネイキッドもネイキッドも使用しないでくださいstrncmpif

ゼロバイトが埋め込まれている可能性がある場合、最初のものは正しく機能しません。これによりstrncmp、実際には等しくないのに等しいと宣言されます。これstrncmpは、次の 2 つの値のいずれかであるためです。

ff ff 00 ff ff ff
ff ff 00 aa aa aa

true になります (最初の 0 バイトまでしかチェックしません)。

ポインターが指す内容ではなく、ポインターを比較しているため、2番目は機能しません。次のメモリ レイアウトがある場合:

0x12345678 (mac) | 0x11111111 |
0x1234567c (eth) | 0x11111111 |

と比較するmaceth、それらは異なるポインターであり、一方は で終わり、もう一方は で終わるため、 と比較するif (mac == eth)と得られます。false787c

memcmp初期のゼロバイトで停止することなく生のメモリバイトを比較するため、代わりに使用する必要があります。

int result = memcmp (ethernet_header->h_dest, mac, ETH_ALEN);
于 2010-07-29T10:09:54.363 に答える
1

== 演算子を使用して文字列が等しいかどうかをテストすることはできません。そもそも strcmp() 関数が存在するのはそのためです。

于 2010-07-29T10:08:35.207 に答える
1

strncmp最初の 2 つの引数として char へのポインターを取ります。

strncmpこれらの 2 つの場所の文字列は文字に対して同じであるため、ゼロを返します。これは、等しいという意味ではありETH_ALENません。これらは2 つの異なるポインターです。ethernet_header->h_destmac

int main()
{
        char a1[] = "asdf";
        char a2[] = "asdf";
        char *p1 = "asdf";
        char *p2 = "asdf";
        char *s1 = malloc(5);
        char *s2 = malloc(5);
        strcpy(s1, "asdf");
        strcpy(s2, "asdf");
        printf("a1 and a2: strcmp gives %d and they are %s\n", strcmp(a1, a2), a1 == a2 ? "equal" : "different");
        printf("p1 and p2: strcmp gives %d and they are %s\n", strcmp(p1, p2), p1 == p2 ? "equal" : "different");
        printf("s1 and s2: strcmp gives %d and they are %s\n", strcmp(s1, s2), s1 == s2 ? "equal" : "different");
        return 0;
}

出力:

a1 and a2: strcmp gives 0 and they are different  
p1 and p2: strcmp gives 0 and they are equal  
s1 and s2: strcmp gives 0 and they are different
  • p1p2両方ともメモリ内の同じ const 文字列を指しているため、等しいです。
  • 配列の場合、5 バイトの連続ブロックが (スタック内の) 各配列変数に割り当てられ、文字列asdf\0がそれらの場所にコピーされます。
  • s1s2は、たまたま同じ値を含むヒープ内の 5 バイト シーケンスの 2 つの異なるブロックを指す 2 つの異なるポインターです。
于 2010-07-29T10:09:58.620 に答える
0

このコードは何ですか?

if(ethernet_header->h_dest == mac)

C で文字列比較を行うのではなく、常に false になるポインタ比較のみを行います。

于 2010-07-29T10:07:35.433 に答える
0

生のif(ethernet_header->h_dest == mac)ポインター値を比較するだけです。つまり、両方の文字列が同じメモリ アドレスで始まるかどうかをチェックします。通常、それはあなたが望むものではありません。

2 つの c-string の内容を比較するには、常に を使用しますstrncmp()

于 2010-07-29T10:08:08.140 に答える
0

Cでは、==あなたが思うように文字列では機能しません。strncmp()代わりに使用する必要があります。

変えるだけ

 if(ethernet_header->h_dest == mac) {

if(result == 0) {
于 2010-07-29T10:12:02.413 に答える