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 <=
54 UINT16_MAX - sizeof(struct GNUNET_TUN_IPv4Header));
55 memset(ip, 0, sizeof(struct GNUNET_TUN_IPv4Header));
56 ip->header_length = sizeof(struct GNUNET_TUN_IPv4Header) / 4;
59 htons(sizeof(struct GNUNET_TUN_IPv4Header) + payload_length);
61 (uint16_t)GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, 65536);
63 ip->protocol = protocol;
64 ip->source_address = *src;
65 ip->destination_address = *dst;
67 GNUNET_CRYPTO_crc16_n(ip, sizeof(struct GNUNET_TUN_IPv4Header));
72 * Initialize an IPv6 header.
74 * @param ip header to initialize
75 * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6
76 * @param payload_length number of bytes of payload that follow (excluding IPv6 header)
77 * @param src source IP address to use
78 * @param dst destination IP address to use
81 GNUNET_TUN_initialize_ipv6_header(struct GNUNET_TUN_IPv6Header *ip,
83 uint16_t payload_length,
84 const struct in6_addr *src,
85 const struct in6_addr *dst)
87 GNUNET_assert(40 == sizeof(struct GNUNET_TUN_IPv6Header));
88 GNUNET_assert(payload_length <=
89 UINT16_MAX - sizeof(struct GNUNET_TUN_IPv6Header));
90 memset(ip, 0, sizeof(struct GNUNET_TUN_IPv6Header));
92 ip->next_header = protocol;
93 ip->payload_length = htons((uint16_t)payload_length);
94 ip->hop_limit = FRESH_TTL;
95 ip->destination_address = *dst;
96 ip->source_address = *src;
101 * Calculate IPv4 TCP checksum.
103 * @param ip ipv4 header fully initialized
104 * @param tcp TCP header (initialized except for CRC)
105 * @param payload the TCP payload
106 * @param payload_length number of bytes of TCP payload
109 GNUNET_TUN_calculate_tcp4_checksum(const struct GNUNET_TUN_IPv4Header *ip,
110 struct GNUNET_TUN_TcpHeader *tcp,
112 uint16_t payload_length)
117 GNUNET_assert(20 == sizeof(struct GNUNET_TUN_TcpHeader));
118 GNUNET_assert(payload_length + sizeof(struct GNUNET_TUN_IPv4Header) +
119 sizeof(struct GNUNET_TUN_TcpHeader) ==
120 ntohs(ip->total_length));
121 GNUNET_assert(IPPROTO_TCP == ip->protocol);
124 sum = GNUNET_CRYPTO_crc16_step(0,
126 sizeof(struct in_addr) * 2);
127 tmp = htons(IPPROTO_TCP);
128 sum = GNUNET_CRYPTO_crc16_step(sum, &tmp, sizeof(uint16_t));
129 tmp = htons(payload_length + sizeof(struct GNUNET_TUN_TcpHeader));
130 sum = GNUNET_CRYPTO_crc16_step(sum, &tmp, sizeof(uint16_t));
132 GNUNET_CRYPTO_crc16_step(sum, tcp, sizeof(struct GNUNET_TUN_TcpHeader));
133 sum = GNUNET_CRYPTO_crc16_step(sum, payload, payload_length);
134 tcp->crc = GNUNET_CRYPTO_crc16_finish(sum);
139 * Calculate IPv6 TCP checksum.
141 * @param ip ipv6 header fully initialized
142 * @param tcp header (initialized except for CRC)
143 * @param payload the TCP payload
144 * @param payload_length number of bytes of TCP payload
147 GNUNET_TUN_calculate_tcp6_checksum(const struct GNUNET_TUN_IPv6Header *ip,
148 struct GNUNET_TUN_TcpHeader *tcp,
150 uint16_t payload_length)
155 GNUNET_assert(20 == sizeof(struct GNUNET_TUN_TcpHeader));
156 GNUNET_assert(payload_length + sizeof(struct GNUNET_TUN_TcpHeader) ==
157 ntohs(ip->payload_length));
158 GNUNET_assert(IPPROTO_TCP == ip->next_header);
160 sum = GNUNET_CRYPTO_crc16_step(0,
162 2 * sizeof(struct in6_addr));
163 tmp = htonl(sizeof(struct GNUNET_TUN_TcpHeader) + payload_length);
164 sum = GNUNET_CRYPTO_crc16_step(sum, &tmp, sizeof(uint32_t));
165 tmp = htonl(IPPROTO_TCP);
166 sum = GNUNET_CRYPTO_crc16_step(sum, &tmp, sizeof(uint32_t));
168 GNUNET_CRYPTO_crc16_step(sum, tcp, sizeof(struct GNUNET_TUN_TcpHeader));
169 sum = GNUNET_CRYPTO_crc16_step(sum, payload, payload_length);
170 tcp->crc = GNUNET_CRYPTO_crc16_finish(sum);
175 * Calculate IPv4 UDP checksum.
177 * @param ip ipv4 header fully initialized
178 * @param udp UDP header (initialized except for CRC)
179 * @param payload the UDP payload
180 * @param payload_length number of bytes of UDP payload
183 GNUNET_TUN_calculate_udp4_checksum(const struct GNUNET_TUN_IPv4Header *ip,
184 struct GNUNET_TUN_UdpHeader *udp,
186 uint16_t payload_length)
191 GNUNET_assert(8 == sizeof(struct GNUNET_TUN_UdpHeader));
192 GNUNET_assert(payload_length + sizeof(struct GNUNET_TUN_IPv4Header) +
193 sizeof(struct GNUNET_TUN_UdpHeader) ==
194 ntohs(ip->total_length));
195 GNUNET_assert(IPPROTO_UDP == ip->protocol);
198 0; /* technically optional, but we calculate it anyway, just to be sure */
199 sum = GNUNET_CRYPTO_crc16_step(0,
201 sizeof(struct in_addr) * 2);
202 tmp = htons(IPPROTO_UDP);
203 sum = GNUNET_CRYPTO_crc16_step(sum, &tmp, sizeof(uint16_t));
204 tmp = htons(sizeof(struct GNUNET_TUN_UdpHeader) + payload_length);
205 sum = GNUNET_CRYPTO_crc16_step(sum, &tmp, sizeof(uint16_t));
207 GNUNET_CRYPTO_crc16_step(sum, udp, sizeof(struct GNUNET_TUN_UdpHeader));
208 sum = GNUNET_CRYPTO_crc16_step(sum, payload, payload_length);
209 udp->crc = GNUNET_CRYPTO_crc16_finish(sum);
214 * Calculate IPv6 UDP checksum.
216 * @param ip ipv6 header fully initialized
217 * @param udp UDP header (initialized except for CRC)
218 * @param payload the UDP payload
219 * @param payload_length number of bytes of UDP payload
222 GNUNET_TUN_calculate_udp6_checksum(const struct GNUNET_TUN_IPv6Header *ip,
223 struct GNUNET_TUN_UdpHeader *udp,
225 uint16_t payload_length)
230 GNUNET_assert(payload_length + sizeof(struct GNUNET_TUN_UdpHeader) ==
231 ntohs(ip->payload_length));
232 GNUNET_assert(payload_length + sizeof(struct GNUNET_TUN_UdpHeader) ==
234 GNUNET_assert(IPPROTO_UDP == ip->next_header);
237 sum = GNUNET_CRYPTO_crc16_step(0,
239 sizeof(struct in6_addr) * 2);
240 tmp = htons(sizeof(struct GNUNET_TUN_UdpHeader) +
241 payload_length); /* aka udp->len */
242 sum = GNUNET_CRYPTO_crc16_step(sum, &tmp, sizeof(uint32_t));
243 tmp = htons(ip->next_header);
244 sum = GNUNET_CRYPTO_crc16_step(sum, &tmp, sizeof(uint32_t));
246 GNUNET_CRYPTO_crc16_step(sum, udp, sizeof(struct GNUNET_TUN_UdpHeader));
247 sum = GNUNET_CRYPTO_crc16_step(sum, payload, payload_length);
248 udp->crc = GNUNET_CRYPTO_crc16_finish(sum);
253 * Calculate ICMP checksum.
255 * @param icmp IMCP header (initialized except for CRC)
256 * @param payload the ICMP payload
257 * @param payload_length number of bytes of ICMP payload
260 GNUNET_TUN_calculate_icmp_checksum(struct GNUNET_TUN_IcmpHeader *icmp,
262 uint16_t payload_length)
266 GNUNET_assert(8 == sizeof(struct GNUNET_TUN_IcmpHeader));
269 GNUNET_CRYPTO_crc16_step(0, icmp, sizeof(struct GNUNET_TUN_IcmpHeader));
270 sum = GNUNET_CRYPTO_crc16_step(sum, payload, payload_length);
271 icmp->crc = GNUNET_CRYPTO_crc16_finish(sum);
276 * Check if two sockaddrs are equal.
278 * @param sa one address
279 * @param sb another address
280 * @param include_port also check ports
281 * @return #GNUNET_YES if they are equal
284 GNUNET_TUN_sockaddr_cmp(const struct sockaddr *sa,
285 const struct sockaddr *sb,
288 if (sa->sa_family != sb->sa_family)
291 switch (sa->sa_family)
294 const struct sockaddr_in *sa4 = (const struct sockaddr_in *)sa;
295 const struct sockaddr_in *sb4 = (const struct sockaddr_in *)sb;
296 if ((include_port) && (sa4->sin_port != sb4->sin_port))
298 return(sa4->sin_addr.s_addr == sb4->sin_addr.s_addr);
302 const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *)sa;
303 const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *)sb;
305 if ((include_port) && (sa6->sin6_port != sb6->sin6_port))
308 0 == memcmp(&sa6->sin6_addr, &sb6->sin6_addr, sizeof(struct in6_addr)));
313 return GNUNET_SYSERR;