5 #include <linux/icmp.h>
6 #include <netinet/icmp6.h>
8 #include <linux/rtnetlink.h>
9 #include <netinet/ip6.h>
15 static uint16_t _checksum(uint8_t *addr
, int count
);
17 void host_unreachable(in_addr_t destination
, uint16_t id
, in_addr_t source
, uint8_t *packet
, int packet_len
)
22 int len
= 0, on
= 1, icmp_socket
;
23 struct sockaddr_in whereto
= {0};
25 if ((icmp_socket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0)
28 setsockopt(icmp_socket
, IPPROTO_IP
, IP_HDRINCL
, (char *)&on
, sizeof(on
));
30 whereto
.sin_addr
.s_addr
= destination
;
31 whereto
.sin_family
= AF_INET
;
33 iph
= (struct iphdr
*)(buf
);
34 len
= sizeof(struct iphdr
);
35 icmp
= (struct icmphdr
*)(buf
+ len
);
36 len
+= sizeof(struct icmphdr
);
38 /* ip header + first 8 bytes of payload */
39 if (packet_len
> (sizeof(struct iphdr
) + 8))
40 packet_len
= sizeof(struct iphdr
) + 8;
42 memcpy(buf
+ len
, packet
, packet_len
);
54 iph
->daddr
= destination
;
57 iph
->tot_len
= ntohs(len
);
59 icmp
->type
= ICMP_DEST_UNREACH
;
60 icmp
->code
= ICMP_HOST_UNREACH
;
61 icmp
->checksum
= _checksum((uint8_t *) icmp
, sizeof(struct icmphdr
) + packet_len
);
63 iph
->check
= _checksum((uint8_t *) iph
, sizeof(struct iphdr
));
65 sendto(icmp_socket
, buf
, len
, 0, (struct sockaddr
*)&whereto
, sizeof(struct sockaddr
));
69 static uint16_t _checksum(uint8_t *addr
, int count
)
71 register long sum
= 0;
73 for (; count
> 1; count
-= 2)
75 sum
+= ntohs(*(uint16_t *) addr
);
79 if (count
> 0) sum
+= *(unsigned char *)addr
;
81 // take only 16 bits out of the 32 bit sum and add up the carries
83 sum
= (sum
& 0xFFFF) + (sum
>> 16);
85 // one's complement the result
88 return htons((uint16_t) sum
);
91 void send_ipv6_ra(sessionidt s
, tunnelidt t
, struct in6_addr
*ip
)
93 struct nd_opt_prefix_info
*pinfo
;
94 struct ip6_hdr
*p_ip6_hdr
;
95 struct nd_router_advert
*p_nra
;
96 uint8_t b
[MAXETHER
+ 20];
97 struct ipv6_pseudo_hdr pseudo_hdr
;
100 LOG(3, s
, t
, "Sending IPv6 RA\n");
102 memset(b
, 0, sizeof(b
));
103 p_ip6_hdr
= (struct ip6_hdr
*) makeppp(b
, sizeof(b
), 0, 0, s
, t
, PPPIPV6
, 0, 0, 0);
107 LOG(3, s
, t
, "failed to send IPv6 RA\n");
111 p_ip6_hdr
->ip6_vfc
= 0x60; // IPv6
112 p_ip6_hdr
->ip6_plen
= 0; // Length of payload (not header) (calculation below)
113 p_ip6_hdr
->ip6_nxt
= IPPROTO_ICMPV6
; // icmp6 is next
114 p_ip6_hdr
->ip6_hlim
= 255; // Hop limit
116 inet_pton(AF_INET6
, "FE80::1", &p_ip6_hdr
->ip6_src
.s6_addr
);
120 memcpy(p_ip6_hdr
->ip6_dst
.s6_addr
, ip
, 16); // dest = ip
124 // FF02::1 - all hosts
125 inet_pton(AF_INET6
, "FF02::1", &p_ip6_hdr
->ip6_dst
.s6_addr
);
128 // RA message after Ipv6 header
129 p_nra
= (struct nd_router_advert
*) &p_ip6_hdr
[1];
130 p_nra
->nd_ra_type
= ND_ROUTER_ADVERT
; // RA message (134)
131 p_nra
->nd_ra_code
= 0; // Code
132 p_nra
->nd_ra_cksum
= 0; // Checksum
133 p_nra
->nd_ra_curhoplimit
= 64; // Hop count
134 p_nra
->nd_ra_flags_reserved
= (ND_RA_FLAG_MANAGED
|ND_RA_FLAG_OTHER
); // Flags
135 p_nra
->nd_ra_router_lifetime
= 0xFFFF; // Lifetime
136 p_nra
->nd_ra_reachable
= 0; // Reachable time
137 p_nra
->nd_ra_retransmit
= 0; // Retrans timer
138 // Option PI after RA message (rfc4861)
139 pinfo
= (struct nd_opt_prefix_info
*) &p_nra
[1];
140 pinfo
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
141 pinfo
->nd_opt_pi_len
= 4;
142 pinfo
->nd_opt_pi_flags_reserved
= ND_OPT_PI_FLAG_ONLINK
| ND_OPT_PI_FLAG_AUTO
;
143 pinfo
->nd_opt_pi_valid_time
= htonl(2592000);
144 pinfo
->nd_opt_pi_preferred_time
= htonl(604800);
145 pinfo
->nd_opt_pi_reserved2
= 0;
146 pinfo
->nd_opt_pi_prefix_len
= 64; // prefix length
147 if (session
[s
].ipv6address
.s6_addr
[0])
149 // MSB 64bits of assigned IPv6 address to user (see radius attribut Framed-IPv6-Address)
150 memcpy(&pinfo
->nd_opt_pi_prefix
, &session
[s
].ipv6address
.s6_addr
[0], 8);
153 pinfo
->nd_opt_pi_prefix
= config
->ipv6_prefix
;
155 // // Length of payload (not header)
156 p_ip6_hdr
->ip6_plen
= htons(sizeof(*pinfo
) + sizeof(*p_nra
));
158 l
= sizeof(*pinfo
) + sizeof(*p_nra
) + sizeof(*p_ip6_hdr
);
160 /* Use pseudo hearder for checksum calculation */
161 memset(&pseudo_hdr
, 0, sizeof(pseudo_hdr
));
162 memcpy(&pseudo_hdr
.src
, &p_ip6_hdr
->ip6_src
, 16);
163 memcpy(&pseudo_hdr
.dest
, &p_ip6_hdr
->ip6_dst
, 16);
164 pseudo_hdr
.ulp_length
= htonl(sizeof(*pinfo
) + sizeof(*p_nra
)); // Lenght whitout Ipv6 header
165 pseudo_hdr
.nexthdr
= IPPROTO_ICMPV6
;
166 // Checksum is over the icmp6 payload plus the pseudo header
167 p_nra
->nd_ra_cksum
= ipv6_checksum(&pseudo_hdr
, (uint8_t *) p_nra
, (sizeof(*pinfo
) + sizeof(*p_nra
)));
169 tunnelsend(b
, l
+ (((uint8_t *) p_ip6_hdr
)-b
), t
); // send it...