5 #include <linux/icmp.h>
6 #include <netinet/icmp6.h>
8 #include <netinet/ip6.h>
14 static uint16_t _checksum(uint8_t *addr
, int count
);
16 void host_unreachable(in_addr_t destination
, uint16_t id
, in_addr_t source
, uint8_t *packet
, int packet_len
)
21 int len
= 0, on
= 1, icmp_socket
;
22 struct sockaddr_in whereto
= {0};
24 if ((icmp_socket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0)
27 setsockopt(icmp_socket
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
, sizeof(on
));
29 whereto
.sin_addr
.s_addr
= destination
;
30 whereto
.sin_family
= AF_INET
;
32 iph
= (struct iphdr
*)(buf
);
33 len
= sizeof(struct iphdr
);
34 icmp
= (struct icmphdr
*)(buf
+ len
);
35 len
+= sizeof(struct icmphdr
);
37 /* ip header + first 8 bytes of payload */
38 if (packet_len
> (sizeof(struct iphdr
) + 8))
39 packet_len
= sizeof(struct iphdr
) + 8;
41 memcpy(buf
+ len
, packet
, packet_len
);
53 iph
->daddr
= destination
;
56 iph
->tot_len
= ntohs(len
);
58 icmp
->type
= ICMP_DEST_UNREACH
;
59 icmp
->code
= ICMP_HOST_UNREACH
;
60 icmp
->checksum
= _checksum((uint8_t *) icmp
, sizeof(struct icmphdr
) + packet_len
);
62 iph
->check
= _checksum((uint8_t *) iph
, sizeof(struct iphdr
));
64 sendto(icmp_socket
, buf
, len
, 0, (struct sockaddr
*)&whereto
, sizeof(struct sockaddr
));
68 static uint16_t _checksum(uint8_t *addr
, int count
)
70 register long sum
= 0;
72 for (; count
> 1; count
-= 2)
74 sum
+= ntohs(*(uint16_t *) addr
);
78 if (count
> 0) sum
+= *(unsigned char *)addr
;
80 // take only 16 bits out of the 32 bit sum and add up the carries
82 sum
= (sum
& 0xFFFF) + (sum
>> 16);
84 // one's complement the result
87 return htons((uint16_t) sum
);
90 void send_ipv6_ra(sessionidt s
, tunnelidt t
, struct in6_addr
*ip
)
92 struct nd_opt_prefix_info
*pinfo
;
93 struct ip6_hdr
*p_ip6_hdr
;
94 struct nd_router_advert
*p_nra
;
95 uint8_t b
[MAXETHER
+ 20];
96 struct ipv6_pseudo_hdr pseudo_hdr
;
99 LOG(3, s
, t
, "Sending IPv6 RA\n");
101 memset(b
, 0, sizeof(b
));
102 p_ip6_hdr
= (struct ip6_hdr
*) makeppp(b
, sizeof(b
), 0, 0, s
, t
, PPPIPV6
, 0, 0, 0);
106 LOG(3, s
, t
, "failed to send IPv6 RA\n");
110 p_ip6_hdr
->ip6_vfc
= 0x60; // IPv6
111 p_ip6_hdr
->ip6_plen
= 0; // Length of payload (not header) (calculation below)
112 p_ip6_hdr
->ip6_nxt
= IPPROTO_ICMPV6
; // icmp6 is next
113 p_ip6_hdr
->ip6_hlim
= 255; // Hop limit
115 inet_pton(AF_INET6
, "FE80::1", &p_ip6_hdr
->ip6_src
.s6_addr
);
119 memcpy(p_ip6_hdr
->ip6_dst
.s6_addr
, ip
, 16); // dest = ip
123 // FF02::1 - all hosts
124 inet_pton(AF_INET6
, "FF02::1", &p_ip6_hdr
->ip6_dst
.s6_addr
);
127 // RA message after Ipv6 header
128 p_nra
= (struct nd_router_advert
*) &p_ip6_hdr
[1];
129 p_nra
->nd_ra_type
= ND_ROUTER_ADVERT
; // RA message (134)
130 p_nra
->nd_ra_code
= 0; // Code
131 p_nra
->nd_ra_cksum
= 0; // Checksum
132 p_nra
->nd_ra_curhoplimit
= 64; // Hop count
133 p_nra
->nd_ra_flags_reserved
= (ND_RA_FLAG_MANAGED
|ND_RA_FLAG_OTHER
); // Flags
134 p_nra
->nd_ra_router_lifetime
= 0xFFFF; // Lifetime
135 p_nra
->nd_ra_reachable
= 0; // Reachable time
136 p_nra
->nd_ra_retransmit
= 0; // Retrans timer
137 // Option PI after RA message (rfc4861)
138 pinfo
= (struct nd_opt_prefix_info
*) &p_nra
[1];
139 pinfo
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
140 pinfo
->nd_opt_pi_len
= 4;
141 pinfo
->nd_opt_pi_flags_reserved
= ND_OPT_PI_FLAG_ONLINK
| ND_OPT_PI_FLAG_AUTO
;
142 pinfo
->nd_opt_pi_valid_time
= htonl(2592000);
143 pinfo
->nd_opt_pi_preferred_time
= htonl(604800);
144 pinfo
->nd_opt_pi_reserved2
= 0;
145 pinfo
->nd_opt_pi_prefix_len
= 64; // prefix length
146 if (session
[s
].ipv6address
.s6_addr
[0])
148 // MSB 64bits of assigned IPv6 address to user (see radius attribut Framed-IPv6-Address)
149 memcpy(&pinfo
->nd_opt_pi_prefix
, &session
[s
].ipv6address
.s6_addr
[0], 8);
152 pinfo
->nd_opt_pi_prefix
= config
->ipv6_prefix
;
154 // // Length of payload (not header)
155 p_ip6_hdr
->ip6_plen
= htons(sizeof(*pinfo
) + sizeof(*p_nra
));
157 l
= sizeof(*pinfo
) + sizeof(*p_nra
) + sizeof(*p_ip6_hdr
);
159 /* Use pseudo hearder for checksum calculation */
160 memset(&pseudo_hdr
, 0, sizeof(pseudo_hdr
));
161 memcpy(&pseudo_hdr
.src
, &p_ip6_hdr
->ip6_src
, 16);
162 memcpy(&pseudo_hdr
.dest
, &p_ip6_hdr
->ip6_dst
, 16);
163 pseudo_hdr
.ulp_length
= htonl(sizeof(*pinfo
) + sizeof(*p_nra
)); // Lenght whitout Ipv6 header
164 pseudo_hdr
.nexthdr
= IPPROTO_ICMPV6
;
165 // Checksum is over the icmp6 payload plus the pseudo header
166 p_nra
->nd_ra_cksum
= ipv6_checksum(&pseudo_hdr
, (uint8_t *) p_nra
, (sizeof(*pinfo
) + sizeof(*p_nra
)));
168 tunnelsend(b
, l
+ (((uint8_t *) p_ip6_hdr
)-b
), t
); // send it...