/*----------------------------------------------------------------------------- * Method: void makeip(struct ip* ipHdr, unsigned int len, unsigned char ttl, * unsigned char proto, in_addr* src, in_addr* dst) * * makes an ip header out of the given info, assumes everything is in host * byte order *---------------------------------------------------------------------------*/ void makeip( struct ip* ipHdr, unsigned int len, uint16_t off, unsigned char ttl, unsigned char proto, uint32_t src, uint32_t dst ) { uint32_t sbuf, dbuf; uint8_t* p = (uint8_t*) ipHdr; *p = 0x45; // set ip version and header length ipHdr->ip_tos = 0; ipHdr->ip_len = htons(len); ipHdr->ip_id = 0; // what should this be? ipHdr->ip_off = htons(off); ipHdr->ip_ttl = ttl; ipHdr->ip_p = proto; // read into buffers in case we are overwriting in place sbuf = src; dbuf = dst; ipHdr->ip_src.s_addr = sbuf; ipHdr->ip_dst.s_addr = dbuf; ipHdr->ip_sum = 0x0000; ipHdr->ip_sum = in_checksum((uint16_t*)ipHdr, 20); }
int do_checksum(u_char *buf, int protocol, int len) /* len = protocol header length + payload length */ { struct ip *ip; int iplen, sum = 0; if (len == 0) { fprintf(stderr, "header length can't be zero"); return -1; } ip = (struct ip *)buf; if (ip->ip_v != 4) { fprintf(stderr, "Unsupported IP protocol: %d", ip->ip_v); return -1; } iplen = ip->ip_hl << 2; switch (protocol) { case IPPROTO_TCP: { struct tcphdr *tcp = (struct tcphdr *)(buf + iplen); tcp->th_sum = 0; sum = in_checksum((uint16_t *)&ip->ip_src, 8); sum += ntohs(IPPROTO_TCP+len); sum += in_checksum((uint16_t *)tcp, len); tcp->th_sum = CKSUM_CARRY(sum); break; } case IPPROTO_UDP: { struct udphdr *udp = (struct udphdr *)(buf + iplen); udp->uh_sum = 0; sum = in_checksum((uint16_t *)&ip->ip_src, 8); sum += ntohs(IPPROTO_UDP+len); sum += in_checksum((uint16_t *)udp, len); udp->uh_sum = CKSUM_CARRY(sum); break; } case IPPROTO_ICMP: { struct icmp *icmp = (struct icmp *)(buf + iplen); icmp->icmp_cksum = 0; sum = in_checksum((uint16_t *)icmp, len); icmp->icmp_cksum = CKSUM_CARRY(sum); break; } case IPPROTO_IP: { ip->ip_sum = 0; sum = in_checksum((uint16_t *)ip, ip->ip_hl); ip->ip_sum = CKSUM_CARRY(sum); break; } default: { fprintf(stderr, "Unsupported protocol: %d", protocol); return -1; } } #ifdef _DEBUG printf("\nProtocol: %d: %x\n", protocol, CKSUM_CARRY(sum)); #endif return 0; }
int main(int argc, char** argv) { if(argc < 2) { std::cerr << "Specify destination ip address" << std::endl; exit(EXIT_FAILURE); } std::string dest_addr = argv[1]; uint32_t my_time = get_time(); icmp_timestamp_mgs msg; msg.hdr.type = ICMP_TIMESTAMP; msg.hdr.code = 0; msg.hdr.checksum = 0; msg.hdr.un.echo.id = 0; msg.hdr.un.echo.sequence = 0; msg.originate = htonl(my_time); msg.receive = 0; msg.transmit = 0; msg.hdr.checksum = in_checksum((uint16_t*)&msg, sizeof(msg)); int sockfd; if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) { perror("socket"); exit(EXIT_FAILURE); } sockaddr_in dest; dest.sin_family = AF_INET; dest.sin_addr.s_addr = inet_addr(dest_addr.c_str()); int send_cnt = sendto(sockfd, &msg, sizeof(msg), 0, (sockaddr*)&dest, sizeof(sockaddr)); if(send_cnt == -1) { perror("send"); exit(EXIT_FAILURE); } if(send_cnt != sizeof(msg)) { fprintf(stderr, "failed to send full packet\n"); exit(EXIT_FAILURE); } // set timeout timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); char buffer[sizeof(iphdr) + sizeof(icmp_timestamp_mgs)]; socklen_t addrlen = sizeof(dest); int recv_cnt = recvfrom(sockfd, &buffer, sizeof(buffer), 0, (sockaddr*)&dest, &addrlen); uint32_t receive_time = get_time(); if(recv_cnt == -1) { perror("recv"); exit(EXIT_FAILURE); } if(recv_cnt != sizeof(buffer)) { fprintf(stderr, "failed to receive full packet\n"); exit(EXIT_FAILURE); } icmp_timestamp_mgs &answer = *(icmp_timestamp_mgs*)(buffer + sizeof(iphdr)); if(answer.hdr.type != ICMP_TIMESTAMPREPLY) { fprintf(stderr, "received wrong message\n"); exit(EXIT_FAILURE); } int64_t delta = calc_delta(answer, receive_time); std::cout << "Time delta: " << delta / 1000 << "s " << abs(delta) % 1000 << "ms" << std::endl; close(sockfd); return 0; }