5 #include <netinet/in.h>
8 #include <linux/icmp.h>
9 #include <netinet/icmp6.h>
11 #include <sys/socket.h>
13 #include <sys/types.h>
20 static uint16_t _checksum(uint8_t *addr
, int count
);
22 struct ipv6_pseudo_hdr
{
30 void host_unreachable(in_addr_t destination
, uint16_t id
, in_addr_t source
, uint8_t *packet
, int packet_len
)
35 int len
= 0, on
= 1, icmp_socket
;
36 struct sockaddr_in whereto
= {0};
38 if ((icmp_socket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0)
41 setsockopt(icmp_socket
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
, sizeof(on
));
43 whereto
.sin_addr
.s_addr
= destination
;
44 whereto
.sin_family
= AF_INET
;
46 iph
= (struct iphdr
*)(buf
);
47 len
= sizeof(struct iphdr
);
48 icmp
= (struct icmphdr
*)(buf
+ len
);
49 len
+= sizeof(struct icmphdr
);
51 /* ip header + first 8 bytes of payload */
52 if (packet_len
> (sizeof(struct iphdr
) + 8))
53 packet_len
= sizeof(struct iphdr
) + 8;
55 memcpy(buf
+ len
, packet
, packet_len
);
67 iph
->daddr
= destination
;
70 iph
->tot_len
= ntohs(len
);
72 icmp
->type
= ICMP_DEST_UNREACH
;
73 icmp
->code
= ICMP_HOST_UNREACH
;
74 icmp
->checksum
= _checksum((uint8_t *) icmp
, sizeof(struct icmphdr
) + packet_len
);
76 iph
->check
= _checksum((uint8_t *) iph
, sizeof(struct iphdr
));
78 sendto(icmp_socket
, buf
, len
, 0, (struct sockaddr
*)&whereto
, sizeof(struct sockaddr
));
82 static uint16_t _checksum(uint8_t *addr
, int count
)
84 register long sum
= 0;
86 for (; count
> 1; count
-= 2)
88 sum
+= ntohs(*(uint32_t *) addr
);
92 if (count
> 1) sum
+= *(unsigned char *)addr
;
94 // take only 16 bits out of the 32 bit sum and add up the carries
96 sum
= (sum
& 0xFFFF) + (sum
>> 16);
98 // one's complement the result
101 return htons((uint16_t) sum
);
104 void send_ipv6_ra(sessionidt s
, tunnelidt t
, struct in6_addr
*ip
)
106 struct nd_opt_prefix_info
*pinfo
;
107 struct ipv6_pseudo_hdr
*phdr
;
108 uint8_t b
[MAXETHER
+ 20];
109 uint8_t c
[MAXETHER
+ 20];
113 LOG(3, s
, t
, "Sending IPv6 RA\n");
115 memset(b
, 0, sizeof(b
));
116 o
= makeppp(b
, sizeof(b
), 0, 0, s
, t
, PPPIPV6
, 0, 0, 0);
120 LOG(3, s
, t
, "failed to send IPv6 RA\n");
126 *(o
+5) = 48; // Length of payload (not header)
127 *(o
+6) = 58; // icmp6 is next
128 *(o
+7) = 255; // Hop limit
129 memset(o
+8, 0, 16); // source = FE80::1
135 memcpy(o
+24, ip
, 16); // dest = ip
139 // FF02::1 - all hosts
144 *(o
+40) = 134; // RA message
146 *(o
+42) = *(o
+43) = 0; // Checksum
147 *(o
+44) = 64; // Hop count
148 *(o
+45) = 0; // Flags
149 *(o
+46) = *(o
+47) = 255; // Lifetime
150 *(uint32_t *)(o
+48) = 0; // Reachable time
151 *(uint32_t *)(o
+52) = 0; // Retrans timer
152 pinfo
= (struct nd_opt_prefix_info
*)(o
+56);
153 pinfo
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
154 pinfo
->nd_opt_pi_len
= 4;
155 pinfo
->nd_opt_pi_prefix_len
= 64; // prefix length
156 pinfo
->nd_opt_pi_flags_reserved
= ND_OPT_PI_FLAG_ONLINK
;
157 pinfo
->nd_opt_pi_flags_reserved
|= ND_OPT_PI_FLAG_AUTO
;
158 pinfo
->nd_opt_pi_valid_time
= htonl(2592000);
159 pinfo
->nd_opt_pi_preferred_time
= htonl(604800);
160 pinfo
->nd_opt_pi_reserved2
= 0;
161 pinfo
->nd_opt_pi_prefix
= config
->ipv6_prefix
;
162 l
= sizeof(*pinfo
) + 56;
164 memset(c
, 0, sizeof(c
));
165 phdr
= (struct ipv6_pseudo_hdr
*) c
;
166 memcpy(&phdr
->src
, o
+8, 16);
167 memcpy(&phdr
->dest
, o
+24, 16);
168 phdr
->ulp_length
= htonl(l
- 40);
169 phdr
->nexthdr
= IPPROTO_ICMPV6
;
171 memcpy(c
+ sizeof(*phdr
), o
+ 40, l
- 40);
173 // Checksum is over the icmp6 payload plus the pseudo header
174 *(uint16_t *)(o
+42) = _checksum(c
, l
- 40 + sizeof(*phdr
));
176 tunnelsend(b
, l
+ (o
-b
), t
); // send it...