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 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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
23 * @brief standard IP calculations for TUN interaction
24 * @author Philipp Toelke
25 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
31 * IP TTL we use for packets that we assemble (8 bit unsigned integer)
37 * Initialize an IPv4 header.
39 * @param ip header to initialize
40 * @param protocol protocol to use (i.e. IPPROTO_UDP)
41 * @param payload_length number of bytes of payload that follow (excluding IPv4 header)
42 * @param src source IP address to use
43 * @param dst destination IP address to use
46 GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip,
48 uint16_t payload_length,
49 const struct in_addr *src,
50 const struct in_addr *dst)
52 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_IPv4Header));
53 GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header));
54 memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header));
55 ip->header_length = sizeof (struct GNUNET_TUN_IPv4Header) / 4;
57 ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length);
58 ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
61 ip->protocol = protocol;
62 ip->source_address = *src;
63 ip->destination_address = *dst;
64 ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header));
69 * Initialize an IPv6 header.
71 * @param ip header to initialize
72 * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6
73 * @param payload_length number of bytes of payload that follow (excluding IPv6 header)
74 * @param src source IP address to use
75 * @param dst destination IP address to use
78 GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
80 uint16_t payload_length,
81 const struct in6_addr *src,
82 const struct in6_addr *dst)
84 GNUNET_assert (40 == sizeof (struct GNUNET_TUN_IPv6Header));
85 GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header));
86 memset (ip, 0, sizeof (struct GNUNET_TUN_IPv6Header));
88 ip->next_header = protocol;
89 ip->payload_length = htons ((uint16_t) payload_length);
90 ip->hop_limit = FRESH_TTL;
91 ip->destination_address = *dst;
92 ip->source_address = *src;
97 * Calculate IPv4 TCP checksum.
99 * @param ip ipv4 header fully initialized
100 * @param tcp TCP header (initialized except for CRC)
101 * @param payload the TCP payload
102 * @param payload_length number of bytes of TCP payload
105 GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
106 struct GNUNET_TUN_TcpHeader *tcp,
108 uint16_t payload_length)
113 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
114 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) ==
115 ntohs (ip->total_length));
116 GNUNET_assert (IPPROTO_TCP == ip->protocol);
119 sum = GNUNET_CRYPTO_crc16_step (0,
121 sizeof (struct in_addr) * 2);
122 tmp = htons (IPPROTO_TCP);
123 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
124 tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader));
125 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
126 sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader));
127 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
128 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
133 * Calculate IPv6 TCP checksum.
135 * @param ip ipv6 header fully initialized
136 * @param tcp header (initialized except for CRC)
137 * @param payload the TCP payload
138 * @param payload_length number of bytes of TCP payload
141 GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
142 struct GNUNET_TUN_TcpHeader *tcp,
144 uint16_t payload_length)
149 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
150 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) ==
151 ntohs (ip->payload_length));
152 GNUNET_assert (IPPROTO_TCP == ip->next_header);
154 sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr));
155 tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length);
156 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
157 tmp = htonl (IPPROTO_TCP);
158 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
159 sum = GNUNET_CRYPTO_crc16_step (sum, tcp,
160 sizeof (struct GNUNET_TUN_TcpHeader));
161 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
162 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
167 * Calculate IPv4 UDP checksum.
169 * @param ip ipv4 header fully initialized
170 * @param udp UDP header (initialized except for CRC)
171 * @param payload the UDP payload
172 * @param payload_length number of bytes of UDP payload
175 GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
176 struct GNUNET_TUN_UdpHeader *udp,
178 uint16_t payload_length)
183 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
184 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) ==
185 ntohs (ip->total_length));
186 GNUNET_assert (IPPROTO_UDP == ip->protocol);
188 udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */
189 sum = GNUNET_CRYPTO_crc16_step (0,
191 sizeof (struct in_addr) * 2);
192 tmp = htons (IPPROTO_UDP);
193 sum = GNUNET_CRYPTO_crc16_step (sum,
196 tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length);
197 sum = GNUNET_CRYPTO_crc16_step (sum,
200 sum = GNUNET_CRYPTO_crc16_step (sum,
202 sizeof (struct GNUNET_TUN_UdpHeader));
203 sum = GNUNET_CRYPTO_crc16_step (sum,
206 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
211 * Calculate IPv6 UDP checksum.
213 * @param ip ipv6 header fully initialized
214 * @param udp UDP header (initialized except for CRC)
215 * @param payload the UDP payload
216 * @param payload_length number of bytes of UDP payload
219 GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
220 struct GNUNET_TUN_UdpHeader *udp,
222 uint16_t payload_length)
227 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
228 ntohs (ip->payload_length));
229 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
231 GNUNET_assert (IPPROTO_UDP == ip->next_header);
234 sum = GNUNET_CRYPTO_crc16_step (0,
236 sizeof (struct in6_addr) * 2);
237 tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */
238 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
239 tmp = htons (ip->next_header);
240 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
241 sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader));
242 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
243 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
248 * Calculate ICMP checksum.
250 * @param icmp IMCP header (initialized except for CRC)
251 * @param payload the ICMP payload
252 * @param payload_length number of bytes of ICMP payload
255 GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp,
257 uint16_t payload_length)
261 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader));
263 sum = GNUNET_CRYPTO_crc16_step (0,
265 sizeof (struct GNUNET_TUN_IcmpHeader));
266 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
267 icmp->crc = GNUNET_CRYPTO_crc16_finish (sum);
272 * Check if two sockaddrs are equal.
274 * @param sa one address
275 * @param sb another address
276 * @param include_port also check ports
277 * @return #GNUNET_YES if they are equal
280 GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa,
281 const struct sockaddr *sb,
284 if (sa->sa_family != sb->sa_family)
287 switch (sa->sa_family)
291 const struct sockaddr_in *sa4 = (const struct sockaddr_in *) sa;
292 const struct sockaddr_in *sb4 = (const struct sockaddr_in *) sb;
293 return (sa4->sin_addr.s_addr == sb4->sin_addr.s_addr);
297 const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa;
298 const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb;
300 return (0 == memcmp(&sa6->sin6_addr,
302 sizeof (struct in6_addr)));
306 return GNUNET_SYSERR;