1
我重用了這個site的原始套接字片斷,並刪除了TCP部分並添加了我的ICMP部分來請求回顯。我的兩臺機器都在同一個LAN上,運行Ubuntu 32位。 我給校驗功能我ICMP指針,但它無法計算正確的校驗:ICMP指針和校驗和
icmph->icmp_sum = csum((unsigned short *) datagram + sizeof(struct iphdr), sizeof(struct icmp_header));
然後我嘗試了一些原始數字作爲補償,直到它的工作:
icmph->icmp_sum = csum((unsigned short *) datagram + 10, sizeof(struct icmp_header));
我甚至查指針的位置和IP報頭,結構的大小:
Datagram-Pointer: 0xbff94680
IP-Pointer: 0xbff94680
ICMP-Pointer: 0xbff94694
正如你可以看到,ICMP指針是20從Datagram-和IP-指針了。爲什麼要做10工作?
預先感謝您。
PS:這裏是代碼:
**/*
Raw TCP packets
Silver Moon ([email protected])
*/
#include<stdio.h> //for printf
#include<string.h> //memset
#include<sys/socket.h> //for socket ofcourse
#include<stdlib.h> //for exit(0);
#include<errno.h> //For errno - the error number
#include<netinet/tcp.h> //Provides declarations for tcp header
#include<netinet/ip.h> //Provides declarations for ip header
//ICMP Header
struct icmp_header
{
u_char icmp_type;
u_char icmp_code;
u_short icmp_sum;
u_short icmp_ident;
u_short icmp_seq;
};
/*
Generic checksum calculation function
*/
unsigned short csum(unsigned short *ptr,int nbytes)
{
register long sum;
unsigned short oddbyte;
register short answer;
sum=0;
while(nbytes>1) {
sum+=*ptr++;
nbytes-=2;
}
if(nbytes==1) {
oddbyte=0;
*((u_char*)&oddbyte)=*(u_char*)ptr;
sum+=oddbyte;
}
sum = (sum>>16)+(sum & 0xffff);
sum = sum + (sum>>16);
answer=(short)~sum;
return(answer);
}
int main (void)
{
//Create a raw socket
int s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);
if(s == -1)
{
//socket creation failed, may be because of non-root privileges
perror("Failed to create socket");
exit(1);
}
//Datagram to represent the packet
char datagram[sizeof(struct iphdr) + sizeof(struct icmp_header)] , source_ip[32];
//zero out the packet buffer
memset (datagram, 0, sizeof(struct iphdr) + sizeof(struct icmp_header));
//IP header
struct iphdr *iph = (struct iphdr *) datagram;
//TCP header
struct icmp_header *icmph = (struct icmp_header *) (datagram + sizeof (struct iphdr));
struct sockaddr_in sin;
//some address resolution
strcpy(source_ip , "10.0.2.5");
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr ("10.0.2.4");
//Fill in the IP Header
iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = sizeof (struct iphdr) + sizeof (struct icmp_header);
iph->id = htonl (54321); //Id of this packet
iph->frag_off = 0;
iph->ttl = 255;
iph->protocol = 1; //Use ICMP afterwards
iph->check = 0; //Set to 0 before calculating checksum
iph->saddr = inet_addr (source_ip); //Spoof the source ip address
iph->daddr = sin.sin_addr.s_addr;
//Ip checksum
iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//Fill in the ICMP Header
icmph->icmp_type = 8; //Ping Request
icmph->icmp_code = 0;
icmph->icmp_sum = 0; //Set to 0 before calculating checksum
icmph->icmp_ident = 0x4142; //Just some Numbers
icmph->icmp_seq = 0x4142; //Just some Numbers
icmph->icmp_sum = csum((unsigned short *) datagram + 10, sizeof(struct icmp_header));//? Why 10 and not sizeof(struct iphdr)=20?
//For Debugging
printf("Datagram-Pointer: %p\n", (void*) datagram);
printf("IP-Pointer: %p\n", (void*) iph);
printf("ICMP-Pointer: %p\n\n", (void*) icmph);
printf("IP-Struct Size: %d\n", sizeof(struct iphdr));
//IP_HDRINCL to tell the kernel that headers are included in the packet
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
{
perror("Error setting IP_HDRINCL");
exit(0);
}
//Senden
if (sendto (s, datagram, iph->tot_len , 0, (struct sockaddr *) &sin, sizeof (sin)) < 0)
{
perror("sendto failed");
}
//Data send successfully
else
{
printf ("Packet Send. Length : %d \n" , iph->tot_len);
}
return 0;
}
//Complete**
或者,做'char'大小的單位加:'(無符號短*)((的char *)數據報+的sizeof (struct iphdr))'。 –
謝謝@TobySpeight我喜歡這種方法。 – user3880174