3 char const *cvs_id_icmp
= "$Id: icmp.c,v 1.3 2004/06/28 02:43:13 fred_nerk Exp $";
7 #include <netinet/in.h>
10 #include <linux/icmp.h>
12 #include <sys/socket.h>
14 #include <sys/types.h>
20 __u16
_checksum(unsigned char *addr
, int count
);
22 void host_unreachable(ipt destination
, u16 id
, ipt source
, char *packet
, int packet_len
)
28 int len
= 0, on
= 1, icmp_socket
;
29 struct sockaddr_in whereto
= {0};
31 if (!(icmp_socket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)))
33 setsockopt(icmp_socket
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
, sizeof(on
));
35 whereto
.sin_addr
.s_addr
= destination
;
36 whereto
.sin_family
= AF_INET
;
38 iph
= (struct iphdr
*)(buf
);
39 len
= sizeof(struct iphdr
);
40 icmp
= (struct icmphdr
*)(buf
+ len
);
41 len
+= sizeof(struct icmphdr
);
42 data
= (char *)(buf
+ len
);
43 len
+= (packet_len
< 64) ? packet_len
: 64;
44 memcpy(data
, packet
, (packet_len
< 64) ? packet_len
: 64);
55 iph
->daddr
= destination
;
58 iph
->tot_len
= ntohs(len
);
60 icmp
->type
= ICMP_DEST_UNREACH
;
61 icmp
->code
= ICMP_HOST_UNREACH
;
62 icmp
->checksum
= _checksum((char *)icmp
, sizeof(struct icmphdr
) + ((packet_len
< 64) ? packet_len
: 64));
64 iph
->check
= _checksum((char *)iph
, sizeof(struct iphdr
));
66 sendto(icmp_socket
, (char *)buf
, len
, 0, (struct sockaddr
*)&whereto
, sizeof(struct sockaddr
));
70 __u16
_checksum(unsigned char *addr
, int count
)
72 register long sum
= 0;
74 for (; count
> 1; count
-= 2)
76 sum
+= ntohs(*(u32
*)addr
);
80 if (count
> 1) sum
+= *(unsigned char *)addr
;
82 // take only 16 bits out of the 32 bit sum and add up the carries
84 sum
= (sum
& 0xFFFF) + (sum
>> 16);
86 // one's complement the result
89 return htons((u16
) sum
);