2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 Christian Grothoff
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU 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.
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.
18 * @brief standard IP calculations for TUN interaction
19 * @author Philipp Toelke
20 * @author Christian Grothoff
23 #include "gnunet_tun_lib.h"
26 * IP TTL we use for packets that we assemble (8 bit unsigned integer)
32 * Initialize an IPv4 header.
34 * @param ip header to initialize
35 * @param protocol protocol to use (i.e. IPPROTO_UDP)
36 * @param payload_length number of bytes of payload that follow (excluding IPv4 header)
37 * @param src source IP address to use
38 * @param dst destination IP address to use
41 GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip,
43 uint16_t payload_length,
44 const struct in_addr *src,
45 const struct in_addr *dst)
47 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_IPv4Header));
48 GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header));
49 memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header));
50 ip->header_length = sizeof (struct GNUNET_TUN_IPv4Header) / 4;
52 ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length);
53 ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
56 ip->protocol = protocol;
57 ip->source_address = *src;
58 ip->destination_address = *dst;
59 ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header));
64 * Initialize an IPv6 header.
66 * @param ip header to initialize
67 * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6
68 * @param payload_length number of bytes of payload that follow (excluding IPv6 header)
69 * @param src source IP address to use
70 * @param dst destination IP address to use
73 GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
75 uint16_t payload_length,
76 const struct in6_addr *src,
77 const struct in6_addr *dst)
79 GNUNET_assert (40 == sizeof (struct GNUNET_TUN_IPv6Header));
80 GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header));
81 memset (ip, 0, sizeof (struct GNUNET_TUN_IPv6Header));
83 ip->next_header = protocol;
84 ip->payload_length = htons ((uint16_t) payload_length);
85 ip->hop_limit = FRESH_TTL;
86 ip->destination_address = *dst;
87 ip->source_address = *src;
92 * Calculate IPv4 TCP checksum.
94 * @param ip ipv4 header fully initialized
95 * @param tcp TCP header (initialized except for CRC)
96 * @param payload the TCP payload
97 * @param payload_length number of bytes of TCP payload
100 GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
101 struct GNUNET_TUN_TcpHeader *tcp,
103 uint16_t payload_length)
108 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
109 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) ==
110 ntohs (ip->total_length));
111 GNUNET_assert (IPPROTO_TCP == ip->protocol);
114 sum = GNUNET_CRYPTO_crc16_step (0,
116 sizeof (struct in_addr) * 2);
117 tmp = htons (IPPROTO_TCP);
118 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
119 tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader));
120 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
121 sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader));
122 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
123 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
128 * Calculate IPv6 TCP checksum.
130 * @param ip ipv6 header fully initialized
131 * @param tcp header (initialized except for CRC)
132 * @param payload the TCP payload
133 * @param payload_length number of bytes of TCP payload
136 GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
137 struct GNUNET_TUN_TcpHeader *tcp,
139 uint16_t payload_length)
144 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
145 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) ==
146 ntohs (ip->payload_length));
147 GNUNET_assert (IPPROTO_TCP == ip->next_header);
149 sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr));
150 tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length);
151 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
152 tmp = htonl (IPPROTO_TCP);
153 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
154 sum = GNUNET_CRYPTO_crc16_step (sum, tcp,
155 sizeof (struct GNUNET_TUN_TcpHeader));
156 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
157 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
162 * Calculate IPv4 UDP checksum.
164 * @param ip ipv4 header fully initialized
165 * @param udp UDP header (initialized except for CRC)
166 * @param payload the UDP payload
167 * @param payload_length number of bytes of UDP payload
170 GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
171 struct GNUNET_TUN_UdpHeader *udp,
173 uint16_t payload_length)
178 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
179 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) ==
180 ntohs (ip->total_length));
181 GNUNET_assert (IPPROTO_UDP == ip->protocol);
183 udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */
184 sum = GNUNET_CRYPTO_crc16_step (0,
186 sizeof (struct in_addr) * 2);
187 tmp = htons (IPPROTO_UDP);
188 sum = GNUNET_CRYPTO_crc16_step (sum,
191 tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length);
192 sum = GNUNET_CRYPTO_crc16_step (sum,
195 sum = GNUNET_CRYPTO_crc16_step (sum,
197 sizeof (struct GNUNET_TUN_UdpHeader));
198 sum = GNUNET_CRYPTO_crc16_step (sum,
201 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
206 * Calculate IPv6 UDP checksum.
208 * @param ip ipv6 header fully initialized
209 * @param udp UDP header (initialized except for CRC)
210 * @param payload the UDP payload
211 * @param payload_length number of bytes of UDP payload
214 GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
215 struct GNUNET_TUN_UdpHeader *udp,
217 uint16_t payload_length)
222 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
223 ntohs (ip->payload_length));
224 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
226 GNUNET_assert (IPPROTO_UDP == ip->next_header);
229 sum = GNUNET_CRYPTO_crc16_step (0,
231 sizeof (struct in6_addr) * 2);
232 tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */
233 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
234 tmp = htons (ip->next_header);
235 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
236 sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader));
237 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
238 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
243 * Calculate ICMP checksum.
245 * @param icmp IMCP header (initialized except for CRC)
246 * @param payload the ICMP payload
247 * @param payload_length number of bytes of ICMP payload
250 GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp,
252 uint16_t payload_length)
256 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader));
258 sum = GNUNET_CRYPTO_crc16_step (0,
260 sizeof (struct GNUNET_TUN_IcmpHeader));
261 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
262 icmp->crc = GNUNET_CRYPTO_crc16_finish (sum);
267 * Check if two sockaddrs are equal.
269 * @param sa one address
270 * @param sb another address
271 * @param include_port also check ports
272 * @return #GNUNET_YES if they are equal
275 GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa,
276 const struct sockaddr *sb,
279 if (sa->sa_family != sb->sa_family)
282 switch (sa->sa_family)
286 const struct sockaddr_in *sa4 = (const struct sockaddr_in *) sa;
287 const struct sockaddr_in *sb4 = (const struct sockaddr_in *) sb;
288 return (sa4->sin_addr.s_addr == sb4->sin_addr.s_addr);
292 const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa;
293 const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb;
295 return (0 == memcmp(&sa6->sin6_addr,
297 sizeof (struct in6_addr)));
301 return GNUNET_SYSERR;