3 char const *cvs_id_icmp
= "$Id: icmp.c,v 1.9 2005-07-31 10:04:10 bodea Exp $";
7 #include <netinet/in.h>
10 #include <linux/icmp.h>
11 #include <netinet/icmp6.h>
13 #include <sys/socket.h>
15 #include <sys/types.h>
21 static uint16_t _checksum(uint8_t *addr
, int count
);
23 struct ipv6_pseudo_hdr
{
31 void host_unreachable(in_addr_t destination
, uint16_t id
, in_addr_t source
, uint8_t *packet
, int packet_len
)
36 int len
= 0, on
= 1, icmp_socket
;
37 struct sockaddr_in whereto
= {0};
39 if ((icmp_socket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0)
42 setsockopt(icmp_socket
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
, sizeof(on
));
44 whereto
.sin_addr
.s_addr
= destination
;
45 whereto
.sin_family
= AF_INET
;
47 iph
= (struct iphdr
*)(buf
);
48 len
= sizeof(struct iphdr
);
49 icmp
= (struct icmphdr
*)(buf
+ len
);
50 len
+= sizeof(struct icmphdr
);
52 /* ip header + first 8 bytes of payload */
53 if (packet_len
> (sizeof(struct iphdr
) + 8))
54 packet_len
= sizeof(struct iphdr
) + 8;
56 memcpy(buf
+ len
, packet
, packet_len
);
68 iph
->daddr
= destination
;
71 iph
->tot_len
= ntohs(len
);
73 icmp
->type
= ICMP_DEST_UNREACH
;
74 icmp
->code
= ICMP_HOST_UNREACH
;
75 icmp
->checksum
= _checksum((uint8_t *) icmp
, sizeof(struct icmphdr
) + packet_len
);
77 iph
->check
= _checksum((uint8_t *) iph
, sizeof(struct iphdr
));
79 sendto(icmp_socket
, buf
, len
, 0, (struct sockaddr
*)&whereto
, sizeof(struct sockaddr
));
83 static uint16_t _checksum(uint8_t *addr
, int count
)
85 register long sum
= 0;
87 for (; count
> 1; count
-= 2)
89 sum
+= ntohs(*(uint32_t *) addr
);
93 if (count
> 1) sum
+= *(unsigned char *)addr
;
95 // take only 16 bits out of the 32 bit sum and add up the carries
97 sum
= (sum
& 0xFFFF) + (sum
>> 16);
99 // one's complement the result
102 return htons((uint16_t) sum
);
105 void send_ipv6_ra(tunnelidt t
, sessionidt s
, struct in6_addr
*ip
)
107 struct nd_opt_prefix_info
*pinfo
;
108 struct ipv6_pseudo_hdr
*phdr
;
109 uint8_t b
[MAXETHER
+ 20];
110 uint8_t c
[MAXETHER
+ 20];
114 LOG(3, s
, t
, "Sending IPv6 RA\n");
116 memset(b
, 0, sizeof(b
));
117 o
= makeppp(b
, sizeof(b
), 0, 0, t
, s
, PPPIPV6
);
121 LOG(3, s
, t
, "failed to send IPv6 RA\n");
127 *(o
+5) = 48; // Length of payload (not header)
128 *(o
+6) = 58; // icmp6 is next
129 *(o
+7) = 255; // Hop limit
130 memset(o
+8, 0, 16); // source = FE80::1
135 memcpy(o
+24, ip
, 16); // dest = ip
138 // FF02::1 - all hosts
143 *(o
+40) = 134; // RA message
145 *(o
+42) = *(o
+43) = 0; // Checksum
146 *(o
+44) = 64; // Hop count
147 *(o
+45) = 0; // Flags
148 *(o
+46) = *(o
+47) = 255; // Lifetime
149 *(uint32_t *)(o
+48) = 0; // Reachable time
150 *(uint32_t *)(o
+52) = 0; // Retrans timer
151 pinfo
= (struct nd_opt_prefix_info
*)(o
+56);
152 pinfo
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
153 pinfo
->nd_opt_pi_len
= 4;
154 pinfo
->nd_opt_pi_prefix_len
= 64; // prefix length
155 pinfo
->nd_opt_pi_flags_reserved
= ND_OPT_PI_FLAG_ONLINK
;
156 pinfo
->nd_opt_pi_flags_reserved
|= ND_OPT_PI_FLAG_AUTO
;
157 pinfo
->nd_opt_pi_valid_time
= htonl(2592000);
158 pinfo
->nd_opt_pi_preferred_time
= htonl(604800);
159 pinfo
->nd_opt_pi_reserved2
= 0;
160 pinfo
->nd_opt_pi_prefix
= config
->ipv6_prefix
;
161 l
= sizeof(*pinfo
) + 56;
163 memset(c
, 0, sizeof(c
));
164 phdr
= (struct ipv6_pseudo_hdr
*) c
;
165 memcpy(&phdr
->src
, o
+8, 16);
166 memcpy(&phdr
->dest
, o
+24, 16);
167 phdr
->ulp_length
= htonl(l
- 40);
168 phdr
->nexthdr
= IPPROTO_ICMPV6
;
170 memcpy(c
+ sizeof(*phdr
), o
+ 40, l
- 40);
172 // Checksum is over the icmp6 payload plus the pseudo header
173 *(uint16_t *)(o
+42) = _checksum(c
, l
- 40 + sizeof(*phdr
));
175 tunnelsend(b
, l
+ (o
-b
), t
); // send it...