生のパケット データ (ヘッダーを含む) を文字列として出力しようとしています。この場合、E
ascii0x45
は IP ヘッダーの最初のバイトです。上位 4 ビットは「IPv4」を意味し、下位 4 ビットは IHL (IP ヘッダー内の 32 ビット ワードの数) であり、5*4 = 20 バイトです。
このデータに適切にアクセスするには、Linux が提供する IP/ICMP ヘッダー構造体を使用する必要があります。説明するためにコードを少し更新しました。
# include <unistd.h>
# include <sys/socket.h>
# include <sys/types.h>
# include <string.h>
# include <netinet/in.h>
# include <stdio.h>
# include<stdlib.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
main(){
int sockfd,retval,n;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
char buf[10000];
int i;
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sockfd < 0){
perror("sock:");
exit(1);
}
clilen = sizeof(struct sockaddr_in);
while(1){
printf(" before recvfrom\n");
n=recvfrom(sockfd,buf,10000,0,(struct sockaddr *)&cliaddr,&clilen);
printf(" rec'd %d bytes\n",n);
struct iphdr *ip_hdr = (struct iphdr *)buf;
printf("IP header is %d bytes.\n", ip_hdr->ihl*4);
for (i = 0; i < n; i++) {
printf("%02X%s", (uint8_t)buf[i], (i + 1)%16 ? " " : "\n");
}
printf("\n");
struct icmphdr *icmp_hdr = (struct icmphdr *)((char *)ip_hdr + (4 * ip_hdr->ihl));
printf("ICMP msgtype=%d, code=%d", icmp_hdr->type, icmp_hdr->code);
}
}
これを実行すると、ping 127.0.0.1
次のような出力が表示されます。
before recvfrom
rec'd 84 bytes
IP header is 20 bytes.
45 00 00 54 00 00 40 00 40 01 3C A7 7F 00 00 01
7F 00 00 01 08 00 A9 DF 11 66 00 01 9A 77 1A 51
00 00 00 00 BA 1D 0F 00 00 00 00 00 10 11 12 13
14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23
24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33
34 35 36 37
ICMP msgtype=8, code=0 before recvfrom
rec'd 84 bytes
IP header is 20 bytes.
45 00 00 54 8D F3 00 00 40 01 EE B3 7F 00 00 01
7F 00 00 01 00 00 B1 DF 11 66 00 01 9A 77 1A 51
00 00 00 00 BA 1D 0F 00 00 00 00 00 10 11 12 13
14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23
24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33
34 35 36 37
ICMP msgtype=0, code=0 before recvfrom
ここでは、msgtype 8 (エコー要求) と msgtype 0 (エコー応答) を示しています。この方法で配列からデータにアクセスすると、アラインメントの問題が発生する可能性があることに注意してください (x86/x64 は問題を処理してくれますが、他のアーキテクチャはそれほど寛大ではない可能性があります)。それは読者の演習として残しておきます ;)。