3 char const *cvs_id_icmp
= "$Id: icmp.c,v 1.5 2004/11/16 07:54:32 bodea Exp $";
7 #include <netinet/in.h>
10 #include <linux/icmp.h>
12 #include <sys/socket.h>
14 #include <sys/types.h>
20 static __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
)) < 0)
34 setsockopt(icmp_socket
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
, sizeof(on
));
36 whereto
.sin_addr
.s_addr
= destination
;
37 whereto
.sin_family
= AF_INET
;
39 iph
= (struct iphdr
*)(buf
);
40 len
= sizeof(struct iphdr
);
41 icmp
= (struct icmphdr
*)(buf
+ len
);
42 len
+= sizeof(struct icmphdr
);
43 data
= (char *)(buf
+ len
);
44 len
+= (packet_len
< 64) ? packet_len
: 64;
45 memcpy(data
, packet
, (packet_len
< 64) ? packet_len
: 64);
56 iph
->daddr
= destination
;
59 iph
->tot_len
= ntohs(len
);
61 icmp
->type
= ICMP_DEST_UNREACH
;
62 icmp
->code
= ICMP_HOST_UNREACH
;
63 icmp
->checksum
= _checksum((char *)icmp
, sizeof(struct icmphdr
) + ((packet_len
< 64) ? packet_len
: 64));
65 iph
->check
= _checksum((char *)iph
, sizeof(struct iphdr
));
67 sendto(icmp_socket
, (char *)buf
, len
, 0, (struct sockaddr
*)&whereto
, sizeof(struct sockaddr
));
71 static __u16
_checksum(unsigned char *addr
, int count
)
73 register long sum
= 0;
75 for (; count
> 1; count
-= 2)
77 sum
+= ntohs(*(u32
*)addr
);
81 if (count
> 1) sum
+= *(unsigned char *)addr
;
83 // take only 16 bits out of the 32 bit sum and add up the carries
85 sum
= (sum
& 0xFFFF) + (sum
>> 16);
87 // one's complement the result
90 return htons((u16
) sum
);