aboutsummaryrefslogtreecommitdiff
path: root/src/util/tun.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/tun.c')
-rw-r--r--src/util/tun.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/util/tun.c b/src/util/tun.c
new file mode 100644
index 000000000..f85f72209
--- /dev/null
+++ b/src/util/tun.c
@@ -0,0 +1,309 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 Christian Grothoff
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file tun/tun.c
21 * @brief standard IP calculations for TUN interaction
22 * @author Philipp Toelke
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_tun_lib.h"
27
28/**
29 * IP TTL we use for packets that we assemble (8 bit unsigned integer)
30 */
31#define FRESH_TTL 64
32
33
34/**
35 * Initialize an IPv4 header.
36 *
37 * @param ip header to initialize
38 * @param protocol protocol to use (i.e. IPPROTO_UDP)
39 * @param payload_length number of bytes of payload that follow (excluding IPv4 header)
40 * @param src source IP address to use
41 * @param dst destination IP address to use
42 */
43void
44GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip,
45 uint8_t protocol,
46 uint16_t payload_length,
47 const struct in_addr *src,
48 const struct in_addr *dst)
49{
50 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_IPv4Header));
51 GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header));
52 memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header));
53 ip->header_length = sizeof (struct GNUNET_TUN_IPv4Header) / 4;
54 ip->version = 4;
55 ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length);
56 ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
57 65536);
58 ip->ttl = FRESH_TTL;
59 ip->protocol = protocol;
60 ip->source_address = *src;
61 ip->destination_address = *dst;
62 ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header));
63}
64
65
66/**
67 * Initialize an IPv6 header.
68 *
69 * @param ip header to initialize
70 * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6
71 * @param payload_length number of bytes of payload that follow (excluding IPv6 header)
72 * @param src source IP address to use
73 * @param dst destination IP address to use
74 */
75void
76GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
77 uint8_t protocol,
78 uint16_t payload_length,
79 const struct in6_addr *src,
80 const struct in6_addr *dst)
81{
82 GNUNET_assert (40 == sizeof (struct GNUNET_TUN_IPv6Header));
83 GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header));
84 memset (ip, 0, sizeof (struct GNUNET_TUN_IPv6Header));
85 ip->version = 6;
86 ip->next_header = protocol;
87 ip->payload_length = htons ((uint16_t) payload_length);
88 ip->hop_limit = FRESH_TTL;
89 ip->destination_address = *dst;
90 ip->source_address = *src;
91}
92
93
94/**
95 * Calculate IPv4 TCP checksum.
96 *
97 * @param ip ipv4 header fully initialized
98 * @param tcp TCP header (initialized except for CRC)
99 * @param payload the TCP payload
100 * @param payload_length number of bytes of TCP payload
101 */
102void
103GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
104 struct GNUNET_TUN_TcpHeader *tcp,
105 const void *payload,
106 uint16_t payload_length)
107{
108 uint32_t sum;
109 uint16_t tmp;
110
111 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
112 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) ==
113 ntohs (ip->total_length));
114 GNUNET_assert (IPPROTO_TCP == ip->protocol);
115
116 tcp->crc = 0;
117 sum = GNUNET_CRYPTO_crc16_step (0,
118 &ip->source_address,
119 sizeof (struct in_addr) * 2);
120 tmp = htons (IPPROTO_TCP);
121 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
122 tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader));
123 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
124 sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader));
125 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
126 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
127}
128
129
130/**
131 * Calculate IPv6 TCP checksum.
132 *
133 * @param ip ipv6 header fully initialized
134 * @param tcp header (initialized except for CRC)
135 * @param payload the TCP payload
136 * @param payload_length number of bytes of TCP payload
137 */
138void
139GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
140 struct GNUNET_TUN_TcpHeader *tcp,
141 const void *payload,
142 uint16_t payload_length)
143{
144 uint32_t sum;
145 uint32_t tmp;
146
147 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
148 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) ==
149 ntohs (ip->payload_length));
150 GNUNET_assert (IPPROTO_TCP == ip->next_header);
151 tcp->crc = 0;
152 sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr));
153 tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length);
154 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
155 tmp = htonl (IPPROTO_TCP);
156 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
157 sum = GNUNET_CRYPTO_crc16_step (sum, tcp,
158 sizeof (struct GNUNET_TUN_TcpHeader));
159 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
160 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
161}
162
163
164/**
165 * Calculate IPv4 UDP checksum.
166 *
167 * @param ip ipv4 header fully initialized
168 * @param udp UDP header (initialized except for CRC)
169 * @param payload the UDP payload
170 * @param payload_length number of bytes of UDP payload
171 */
172void
173GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
174 struct GNUNET_TUN_UdpHeader *udp,
175 const void *payload,
176 uint16_t payload_length)
177{
178 uint32_t sum;
179 uint16_t tmp;
180
181 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
182 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) ==
183 ntohs (ip->total_length));
184 GNUNET_assert (IPPROTO_UDP == ip->protocol);
185
186 udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */
187 sum = GNUNET_CRYPTO_crc16_step (0,
188 &ip->source_address,
189 sizeof (struct in_addr) * 2);
190 tmp = htons (IPPROTO_UDP);
191 sum = GNUNET_CRYPTO_crc16_step (sum,
192 &tmp,
193 sizeof (uint16_t));
194 tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length);
195 sum = GNUNET_CRYPTO_crc16_step (sum,
196 &tmp,
197 sizeof (uint16_t));
198 sum = GNUNET_CRYPTO_crc16_step (sum,
199 udp,
200 sizeof (struct GNUNET_TUN_UdpHeader));
201 sum = GNUNET_CRYPTO_crc16_step (sum,
202 payload,
203 payload_length);
204 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
205}
206
207
208/**
209 * Calculate IPv6 UDP checksum.
210 *
211 * @param ip ipv6 header fully initialized
212 * @param udp UDP header (initialized except for CRC)
213 * @param payload the UDP payload
214 * @param payload_length number of bytes of UDP payload
215 */
216void
217GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
218 struct GNUNET_TUN_UdpHeader *udp,
219 const void *payload,
220 uint16_t payload_length)
221{
222 uint32_t sum;
223 uint32_t tmp;
224
225 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
226 ntohs (ip->payload_length));
227 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
228 ntohs (udp->len));
229 GNUNET_assert (IPPROTO_UDP == ip->next_header);
230
231 udp->crc = 0;
232 sum = GNUNET_CRYPTO_crc16_step (0,
233 &ip->source_address,
234 sizeof (struct in6_addr) * 2);
235 tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */
236 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
237 tmp = htons (ip->next_header);
238 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
239 sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader));
240 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
241 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
242}
243
244
245/**
246 * Calculate ICMP checksum.
247 *
248 * @param icmp IMCP header (initialized except for CRC)
249 * @param payload the ICMP payload
250 * @param payload_length number of bytes of ICMP payload
251 */
252void
253GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp,
254 const void *payload,
255 uint16_t payload_length)
256{
257 uint32_t sum;
258
259 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader));
260 icmp->crc = 0;
261 sum = GNUNET_CRYPTO_crc16_step (0,
262 icmp,
263 sizeof (struct GNUNET_TUN_IcmpHeader));
264 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
265 icmp->crc = GNUNET_CRYPTO_crc16_finish (sum);
266}
267
268
269/**
270 * Check if two sockaddrs are equal.
271 *
272 * @param sa one address
273 * @param sb another address
274 * @param include_port also check ports
275 * @return #GNUNET_YES if they are equal
276 */
277int
278GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa,
279 const struct sockaddr *sb,
280 int include_port)
281{
282 if (sa->sa_family != sb->sa_family)
283 return GNUNET_NO;
284
285 switch (sa->sa_family)
286 {
287 case AF_INET:
288 {
289 const struct sockaddr_in *sa4 = (const struct sockaddr_in *) sa;
290 const struct sockaddr_in *sb4 = (const struct sockaddr_in *) sb;
291 return (sa4->sin_addr.s_addr == sb4->sin_addr.s_addr);
292 }
293 case AF_INET6:
294 {
295 const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa;
296 const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb;
297
298 return (0 == memcmp(&sa6->sin6_addr,
299 &sb6->sin6_addr,
300 sizeof (struct in6_addr)));
301 }
302 default:
303 GNUNET_break (0);
304 return GNUNET_SYSERR;
305 }
306}
307
308
309/* end of tun.c */