add nonstring attribute to silence warning
[oweals/gnunet.git] / src / util / tun.c
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      SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21 /**
22  * @file tun/tun.c
23  * @brief standard IP calculations for TUN interaction
24  * @author Philipp Toelke
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29
30 /**
31  * IP TTL we use for packets that we assemble (8 bit unsigned integer)
32  */
33 #define FRESH_TTL 64
34
35
36 /**
37  * Initialize an IPv4 header.
38  *
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
44  */
45 void
46 GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip,
47                                    uint8_t protocol,
48                                    uint16_t payload_length,
49                                    const struct in_addr *src,
50                                    const struct in_addr *dst)
51 {
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;
56   ip->version = 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,
59                                                             65536);
60   ip->ttl = FRESH_TTL;
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));
65 }
66
67
68 /**
69  * Initialize an IPv6 header.
70  *
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
76  */
77 void
78 GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
79                                    uint8_t protocol,
80                                    uint16_t payload_length,
81                                    const struct in6_addr *src,
82                                    const struct in6_addr *dst)
83 {
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));
87   ip->version = 6;
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;
93 }
94
95
96 /**
97  * Calculate IPv4 TCP checksum.
98  *
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
103  */
104 void
105 GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
106                                     struct GNUNET_TUN_TcpHeader *tcp,
107                                     const void *payload,
108                                     uint16_t payload_length)
109 {
110   uint32_t sum;
111   uint16_t tmp;
112
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);
117
118   tcp->crc = 0;
119   sum = GNUNET_CRYPTO_crc16_step (0,
120                                   &ip->source_address,
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);
129 }
130
131
132 /**
133  * Calculate IPv6 TCP checksum.
134  *
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
139  */
140 void
141 GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
142                                     struct GNUNET_TUN_TcpHeader *tcp,
143                                     const void *payload,
144                                     uint16_t payload_length)
145 {
146   uint32_t sum;
147   uint32_t tmp;
148
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);
153   tcp->crc = 0;
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);
163 }
164
165
166 /**
167  * Calculate IPv4 UDP checksum.
168  *
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
173  */
174 void
175 GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
176                                     struct GNUNET_TUN_UdpHeader *udp,
177                                     const void *payload,
178                                     uint16_t payload_length)
179 {
180   uint32_t sum;
181   uint16_t tmp;
182
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);
187
188   udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */
189   sum = GNUNET_CRYPTO_crc16_step (0,
190                                   &ip->source_address,
191                                   sizeof (struct in_addr) * 2);
192   tmp = htons (IPPROTO_UDP);
193   sum = GNUNET_CRYPTO_crc16_step (sum,
194                                   &tmp,
195                                   sizeof (uint16_t));
196   tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length);
197   sum = GNUNET_CRYPTO_crc16_step (sum,
198                                   &tmp,
199                                   sizeof (uint16_t));
200   sum = GNUNET_CRYPTO_crc16_step (sum,
201                                   udp,
202                                   sizeof (struct GNUNET_TUN_UdpHeader));
203   sum = GNUNET_CRYPTO_crc16_step (sum,
204                                   payload,
205                                   payload_length);
206   udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
207 }
208
209
210 /**
211  * Calculate IPv6 UDP checksum.
212  *
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
217  */
218 void
219 GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
220                                     struct GNUNET_TUN_UdpHeader *udp,
221                                     const void *payload,
222                                     uint16_t payload_length)
223 {
224   uint32_t sum;
225   uint32_t tmp;
226
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) ==
230                  ntohs (udp->len));
231   GNUNET_assert (IPPROTO_UDP == ip->next_header);
232
233   udp->crc = 0;
234   sum = GNUNET_CRYPTO_crc16_step (0,
235                                   &ip->source_address,
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);
244 }
245
246
247 /**
248  * Calculate ICMP checksum.
249  *
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
253  */
254 void
255 GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp,
256                                     const void *payload,
257                                     uint16_t payload_length)
258 {
259   uint32_t sum;
260
261   GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader));
262   icmp->crc = 0;
263   sum = GNUNET_CRYPTO_crc16_step (0,
264                                   icmp,
265                                   sizeof (struct GNUNET_TUN_IcmpHeader));
266   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
267   icmp->crc = GNUNET_CRYPTO_crc16_finish (sum);
268 }
269
270
271 /**
272  * Check if two sockaddrs are equal.
273  *
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
278  */
279 int
280 GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa,
281                          const struct sockaddr *sb,
282                          int include_port)
283 {
284   if (sa->sa_family != sb->sa_family)
285     return GNUNET_NO;
286
287   switch (sa->sa_family)
288   {
289   case AF_INET:
290     {
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);
294     }
295   case AF_INET6:
296     {
297       const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa;
298       const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb;
299
300       return (0 == memcmp(&sa6->sin6_addr,
301                           &sb6->sin6_addr,
302                           sizeof (struct in6_addr)));
303     }
304   default:
305     GNUNET_break (0);
306     return GNUNET_SYSERR;
307   }
308 }
309
310
311 /* end of tun.c */