auto-provide OS_IPK paths in [paths] of config
[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 <=
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;
57   ip->version = 4;
58   ip->total_length =
59     htons (sizeof(struct GNUNET_TUN_IPv4Header) + payload_length);
60   ip->identification =
61     (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 65536);
62   ip->ttl = FRESH_TTL;
63   ip->protocol = protocol;
64   ip->source_address = *src;
65   ip->destination_address = *dst;
66   ip->checksum =
67     GNUNET_CRYPTO_crc16_n (ip, sizeof(struct GNUNET_TUN_IPv4Header));
68 }
69
70
71 /**
72  * Initialize an IPv6 header.
73  *
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
79  */
80 void
81 GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
82                                    uint8_t protocol,
83                                    uint16_t payload_length,
84                                    const struct in6_addr *src,
85                                    const struct in6_addr *dst)
86 {
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));
91   ip->version = 6;
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;
97 }
98
99
100 /**
101  * Calculate IPv4 TCP checksum.
102  *
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
107  */
108 void
109 GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
110                                     struct GNUNET_TUN_TcpHeader *tcp,
111                                     const void *payload,
112                                     uint16_t payload_length)
113 {
114   uint32_t sum;
115   uint16_t tmp;
116
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);
122
123   tcp->crc = 0;
124   sum = GNUNET_CRYPTO_crc16_step (0,
125                                   &ip->source_address,
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));
131   sum =
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);
135 }
136
137
138 /**
139  * Calculate IPv6 TCP checksum.
140  *
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
145  */
146 void
147 GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
148                                     struct GNUNET_TUN_TcpHeader *tcp,
149                                     const void *payload,
150                                     uint16_t payload_length)
151 {
152   uint32_t sum;
153   uint32_t tmp;
154
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);
159   tcp->crc = 0;
160   sum = GNUNET_CRYPTO_crc16_step (0,
161                                   &ip->source_address,
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));
167   sum =
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);
171 }
172
173
174 /**
175  * Calculate IPv4 UDP checksum.
176  *
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
181  */
182 void
183 GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
184                                     struct GNUNET_TUN_UdpHeader *udp,
185                                     const void *payload,
186                                     uint16_t payload_length)
187 {
188   uint32_t sum;
189   uint16_t tmp;
190
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);
196
197   udp->crc =
198     0; /* technically optional, but we calculate it anyway, just to be sure */
199   sum = GNUNET_CRYPTO_crc16_step (0,
200                                   &ip->source_address,
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));
206   sum =
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);
210 }
211
212
213 /**
214  * Calculate IPv6 UDP checksum.
215  *
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
220  */
221 void
222 GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
223                                     struct GNUNET_TUN_UdpHeader *udp,
224                                     const void *payload,
225                                     uint16_t payload_length)
226 {
227   uint32_t sum;
228   uint32_t tmp;
229
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) ==
233                  ntohs (udp->len));
234   GNUNET_assert (IPPROTO_UDP == ip->next_header);
235
236   udp->crc = 0;
237   sum = GNUNET_CRYPTO_crc16_step (0,
238                                   &ip->source_address,
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));
245   sum =
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);
249 }
250
251
252 /**
253  * Calculate ICMP checksum.
254  *
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
258  */
259 void
260 GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp,
261                                     const void *payload,
262                                     uint16_t payload_length)
263 {
264   uint32_t sum;
265
266   GNUNET_assert (8 == sizeof(struct GNUNET_TUN_IcmpHeader));
267   icmp->crc = 0;
268   sum =
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);
272 }
273
274
275 /**
276  * Check if two sockaddrs are equal.
277  *
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
282  */
283 int
284 GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa,
285                          const struct sockaddr *sb,
286                          int include_port)
287 {
288   if (sa->sa_family != sb->sa_family)
289     return GNUNET_NO;
290
291   switch (sa->sa_family)
292   {
293   case AF_INET: {
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))
297         return GNUNET_NO;
298       return(sa4->sin_addr.s_addr == sb4->sin_addr.s_addr);
299     }
300
301   case AF_INET6: {
302       const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa;
303       const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb;
304
305       if ((include_port) && (sa6->sin6_port != sb6->sin6_port))
306         return GNUNET_NO;
307       return(
308         0 == memcmp (&sa6->sin6_addr, &sb6->sin6_addr, sizeof(struct
309                                                               in6_addr)));
310     }
311
312   default:
313     GNUNET_break (0);
314     return GNUNET_SYSERR;
315   }
316 }
317
318
319 /* end of tun.c */