ヘッダーに追加するバイトでICMPヘッダーのチェックサムを再計算する必要があります。
* icmp_send
をbuff
文字列を指すように初期化し、そこでフィールドをマングルすることをお勧めします。これにより、memcpy
から* icmp_send
〜buff
への回避が回避されます。ここに例があります。上記の例で
unsigned char buff[2000];
unsigned char *p = buff;
struct icmp *icmp_send;
icmp_send = (struct icmp *)buff;
icmp_send->icmp_type = ICMP_ECHO;
icmp_send->icmp_code = 0;
icmp_send->icmp_id = getpid();
icmp_send->icmp_cksum = 0;
icmp_send->icmp_seq = htons(1);
p += sizeof(icmp_send);
*p = 'A';
icmp_send->icmp_cksum = checksum(buff, sizeof(icmp_send) + 1);
if (sendto(sd, (unsigned char*)buff, sizeof(icmp_send) + 1, 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0) {
printf("Send err.\n");
}
は、任意の値に搬送するペイロードのサイズ(sizeof(icmp_send) + 1
)を調整することができます。
UPDATE:マッテオでコメントしたようご使用のプラットフォームが適切な構造でずれフィールドへのアクセスを処理するためにあなたを必要とする場合、ICMPフィールドを変更後、アクセスするためにstruct icmp
ポインタにbuff
をキャストすることは安全ではないかもしれません。ネットワークを介して送信する前に、memcpy
をbuff
に別々に書いてください。この場合は、移動する方法です。
コードに戻って、コードサンプルと完全なコードについて詳しく説明します。ここでの考え方は、ポインタ間の値を計算してコピーすることです。* icmp_send
とbuff
は無関係です。
このコードは、データと共にICMPエコー要求を送信し、ICMPエコー応答を受信します。ホスト間でパケットが交換されていることを確認するためにtcpdump
とともにテストされています。
完全なコード以下(OT:必要に応じて、ネットワーク経由でデータを送信するときの機能をhton使用してください)
unsigned short checksum(void *b, int len)
{ unsigned short *buf = b;
unsigned int sum=0;
unsigned short result;
for (sum = 0; len > 1; len -= 2)
sum += *buf++;
if (len == 1)
sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
void ping(struct sockaddr_in *addr) {
int sd;
const int val=255;
struct sockaddr_in r_addr;
sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sd < 0) {
perror("socket");
return;
}
if (setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0)
perror("Set TTL option");
if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
perror("Request nonblocking I/O");
socklen_t len=sizeof(r_addr);
struct icmp *icmp_send, *icmp_recv;
icmp_send->icmp_type = ICMP_ECHO;
icmp_send->icmp_code = 0;
icmp_send->icmp_id = getpid();
icmp_send->icmp_seq = htons(1);
unsigned char buff[2000];
unsigned char*p = buff;
p += sizeof(icmp_send);
*p = 'A';
icmp_send->icmp_cksum = 0;
memcpy(buff, icmp_send, sizeof(icmp_send)) ;
icmp_send->icmp_cksum = checksum(buff, sizeof(icmp_send) + 1);
memcpy(buff, icmp_send, sizeof(icmp_send)) ;
if (sendto(sd, (unsigned char*)buff, sizeof(icmp_send) + 1, 0, (struct sockaddr*)addr, sizeof(*addr)) <= 0) {
printf("Send err.\n");
}
}
int main(int argc, char *argv[])
{
if (argc != 2) {
printf("usage: %s destination_ip\n", argv[0]);
return 1;
}
struct sockaddr_in addr;
struct in_addr dst;
if (inet_aton(argv[1], &dst) == 0) {
perror("inet_aton");
printf("%s isn't a valid IP address\n", argv[1]);
return 1;
}
memset(&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_addr = dst;
ping(&addr);
return 0;
}
希望にこのことができます!
C!= C++。両方が実際に関連している場合を除き、使用している言語のみでタグを設定してください。 – tambre
あなたの '* icmp_send'は初期化されていません。そしてあなたは明らかに 'perror'について知っています、なぜあなたはprintf" send err "をしますか?代わりに? – rustyx
バッファを変更してパケットを送信する直前にチェックサムを再計算する必要はありませんか?良い例がここに与えられます: http://www.binarytides.com/icmp-ping-flood-code-sockets-c-linux/ –