3 #include <netinet/in.h>
5 #include <linux/icmp.h>
7 #include <sys/socket.h>
16 __u16
_checksum(unsigned char *addr
, int count
);
18 void host_unreachable(ipt destination
, u16 id
, ipt source
, char *packet
, int packet_len
)
24 int len
= 0, on
= 1, icmp_socket
;
25 struct sockaddr_in whereto
= {0};
27 if (!(icmp_socket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)))
29 setsockopt(icmp_socket
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
, sizeof(on
));
31 whereto
.sin_addr
.s_addr
= destination
;
32 whereto
.sin_family
= AF_INET
;
34 iph
= (struct iphdr
*)(buf
);
35 len
= sizeof(struct iphdr
);
36 icmp
= (struct icmphdr
*)(buf
+ len
);
37 len
+= sizeof(struct icmphdr
);
38 data
= (char *)(buf
+ len
);
39 len
+= (packet_len
< 64) ? packet_len
: 64;
40 memcpy(data
, packet
, (packet_len
< 64) ? packet_len
: 64);
51 iph
->daddr
= destination
;
54 iph
->tot_len
= ntohs(len
);
56 icmp
->type
= ICMP_DEST_UNREACH
;
57 icmp
->code
= ICMP_HOST_UNREACH
;
58 icmp
->checksum
= _checksum((char *)icmp
, sizeof(struct icmphdr
) + ((packet_len
< 64) ? packet_len
: 64));
60 iph
->check
= _checksum((char *)iph
, sizeof(struct iphdr
));
62 sendto(icmp_socket
, (char *)buf
, len
, 0, (struct sockaddr
*)&whereto
, sizeof(struct sockaddr
));
66 __u16
_checksum(unsigned char *addr
, int count
)
68 register long sum
= 0;
70 for (; count
> 1; count
-= 2)
72 sum
+= ntohs(*(u32
*)addr
);
76 if (count
> 1) sum
+= *(unsigned char *)addr
;
78 // take only 16 bits out of the 32 bit sum and add up the carries
80 sum
= (sum
& 0xFFFF) + (sum
>> 16);
82 // one's complement the result
85 return htons((u16
) sum
);