Привет всем. Никак не могу понять как правильно написать. Программа использует icmp протокол. Например я пингую хост, в настройках ip устанавливаю ttl++. В wireshark пишет некоректная чексумма, она такая, а должна быть такая. А как мне известно, что icmp с неправильной чексуммой не дождёться ответа, но, маршрут проходит до хоста, но последний хост в моей программе не отображаеться, хоть я могу сам дописать, но может что-то в чек сумме? Вот код.
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <errno.h>
#include <stdlib.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <strings.h>
#include <sys/time.h>
unsigned short checksum(unsigned short *, int);
int main(int argc, char *argv[]){
int sockfd;
struct sockaddr_in dst;
struct sockaddr_in from;
struct hostent *ht;
struct icmp *icmp;
struct ip *ip;
pid_t pid = getpid();
static int icmplen = 64;
char sendbuf[1500];
char readbuf[1500];
int ttl;
int seq = 0;
int len;
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1){
perror("socket() failed");
exit(-1);
}
if (setuid(getuid()) == -1)
perror("setuid() failed");
if ((ht = gethostbyname(argv[1])) == NULL){
herror("gethostbyname() failed");
exit(-1);
}
dst.sin_family = AF_INET;
dst.sin_port = IPPROTO_ICMP;
dst.sin_addr = *((struct in_addr *)ht->h_addr);
for(ttl = 1; ttl <= 64; ttl++){
if(setsockopt(sockfd, SOL_IP, IP_TTL,&ttl,sizeof(ttl)) == -1){
perror("setsockopt() failed");
exit(-1);
}
bzero(&sendbuf, 1500);
bzero(&readbuf, 1500);
icmp = (struct icmp *) sendbuf;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_id = pid;
icmp->icmp_seq = seq;
icmp->icmp_cksum = 0;
icmp->icmp_cksum = checksum((unsigned short *)icmp, icmplen);
if(sendto( sockfd,
sendbuf,
icmplen,
0,
(struct sockaddr *)&dst,
sizeof(dst)) == -1){
perror("sendto failed");
exit(-1);
}
unsigned int fromlen = sizeof(from);
if((len =recvfrom(sockfd,
readbuf,
icmplen,
0,
(struct sockaddr *)&from,
&fromlen)) == -1){
perror("recvfrom() failed");
exit(-1);
}
char *ptr = &readbuf[0];
int iplen;
ip = (struct ip *) ptr;
iplen = ip->ip_hl << 2;
icmp = (struct icmp *) (ptr + iplen);
if(icmp->icmp_type == ICMP_TIME_EXCEEDED)
printf( "%s ttl=%d len=%d icmplen=%d\n",
inet_ntoa(from.sin_addr),ttl, len,icmplen);
else if(icmp->icmp_type == ICMP_ECHOREPLY){
printf("%s\n", inet_ntoa(from.sin_addr));
exit(0);
}
//seq++;
}
}
unsigned short checksum(unsigned short *addr, int count){
register long sum;
// unsigned short sum;
unsigned short icmpsum;
while(count > 1){
sum += (unsigned short) *addr++;
count -= 2;
}
if(count == 1)
sum += *(unsigned char *) addr;
while(sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
icmpsum = ~sum;
return icmpsum;
}