我尝试使用tracert
(echo)等原始套接字在linux(ubuntu)中实现ICMP
。我想我几乎实现了功能。但是当我执行它时,它不起作用。
我通过测试发现的是程序在recvfrom()'停止。
我使用wireshark
,我可以看到它正在发送和接收数据包。但是recvfrom()
不起作用。它只是在等待一个packaet包。
我从wireshark
上传了截图。
http://blogfiles.naver.net/20150508_188/hong015700_1431014683356CJkRQ_JPEG/wireshark.jpg
以下是我的代码。
/* Copyright (C) 2011-2015 P.D. Buchan (pdbuchan@yahoo.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Send an IPv4 ICMP packet via raw socket.
// Stack fills out layer 2 (data link) information (MAC addresses) for us.
// Values set for echo request packet, includes some ICMP data.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // close()
#include <string.h> // strcpy, memset(), and memcpy()
#include <netdb.h> // struct addrinfo
#include <sys/types.h> // needed for socket(), uint8_t, uint16_t, uint32_t
#include <sys/socket.h> // needed for socket()
#include <netinet/in.h> // IPPROTO_RAW, IPPROTO_IP, IPPROTO_ICMP, INET_ADDRSTRLEN
#include <netinet/ip.h> // struct ip and IP_MAXPACKET (which is 65535)
#include <netinet/ip_icmp.h> // struct icmp, ICMP_ECHO
#include <arpa/inet.h> // inet_pton() and inet_ntop()
#include <sys/ioctl.h> // macro ioctl is defined
//#include <bits/ioctls.h> // defines values for argument "request" of ioctl.
#include <net/if.h> // struct ifreq
#include <errno.h> // errno, perror()
// Define some constants.
#define IP4_HDRLEN 20 // IPv4 header length
#define ICMP_HDRLEN 8 // ICMP header length for echo request, excludes data
// Function prototypes
uint16_t checksum (uint16_t *, int);
char *allocate_strmem (int);
uint8_t *allocate_ustrmem (int);
int *allocate_intmem (int);
int
main (int argc, char **argv)
{
int status, sd, *ip_flags; // status? ip_flags?
const int on = 1; // ?
//char *interface, *target, *src_ip, *dst_ip; // ????
struct ip iphdr;
struct icmp icmphdr;
uint8_t data[1000];
uint8_t packet[1000];
struct addrinfo hints, *res; // hints? res?
struct sockaddr_in *ipv4, serverAddr, routerAddr, clientAddr; // ipv4?
struct ifreq ifr; // ifr?
void *tmp; // tmp?
memset (&ifr, 0, sizeof (ifr));
// IP header
iphdr.ip_hl = 5;
iphdr.ip_v = 4;
iphdr.ip_tos = 0;
iphdr.ip_len = htons (IP4_HDRLEN + ICMP_HDRLEN);
iphdr.ip_id = htons (0);
iphdr.ip_off = 0;
iphdr.ip_ttl = 1;
iphdr.ip_p = IPPROTO_ICMP;
iphdr.ip_src.s_addr=inet_addr("192.168.81.128");
iphdr.ip_dst.s_addr=inet_addr(argv[1]);
iphdr.ip_sum = 0;
iphdr.ip_sum = checksum ((uint16_t *) &iphdr, IP4_HDRLEN);
// ICMP header
icmphdr.icmp_type = ICMP_ECHO;
icmphdr.icmp_code = 0;
icmphdr.icmp_id = htons (1000);
icmphdr.icmp_seq = htons (0);
icmphdr.icmp_cksum = 0;
icmphdr.icmp_cksum = checksum ((uint16_t *) &icmphdr, ICMP_HDRLEN);
// set IP packet(IP Header, ICMP Header, ICMP Data)
memcpy (packet, &iphdr, IP4_HDRLEN);
memcpy ((packet + IP4_HDRLEN), &icmphdr, ICMP_HDRLEN);
// set Destination address
memset (&serverAddr, 0, sizeof (struct sockaddr_in)); // about destination(server). use for bind
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = iphdr.ip_dst.s_addr;
// Submit request for a raw socket descriptor.
if ((sd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror ("socket() failed ");
exit (EXIT_FAILURE);
}
// Set flag so socket expects us to provide IPv4 header.
if (setsockopt (sd, IPPROTO_IP, IP_HDRINCL, &on, sizeof (on)) < 0) {
perror ("setsockopt() failed to set IP_HDRINCL ");
exit (EXIT_FAILURE);
}
// Bind socket to interface index.
// send and receive
printf("send with ttl 1\n");
if (sendto (sd, packet, IP4_HDRLEN + ICMP_HDRLEN, 0, (struct sockaddr *) &serverAddr, sizeof (struct sockaddr)) < 0) {
perror ("sendto() failed ");
exit (EXIT_FAILURE);
}
printf("after send\n");
int addrSize = sizeof(routerAddr);
char buff[1000];
printf("before receive\n");
recvfrom(sd, buff, 1000, 0, (struct sockaddr*)&routerAddr, &addrSize);
printf("after receive\n");
printf("close(sd)!\n");
close (sd);
// Free allocated memory.
return (EXIT_SUCCESS);
}
uint16_t checksum (uint16_t *hdr, int hdrlen)
{
uint32_t sum = 0;
int n;
for(n=0; n<hdrlen/2; n++)
sum += hdr[n];
sum = (sum&0xFFFF) + (sum>>16);
sum = ~sum;
return sum;
}
我想像其他人一样上传我的代码(有些代码是彩色的),但我找不到它......抱歉。
以下是节目结果。
send with ttl 1
after send
before receive
谢谢。
PS。我使用vmware来使用ubuntu。我正在使用NAT。