uncrustify as demanded.
[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 in6_addr)));
309     }
310
311     default:
312       GNUNET_break(0);
313       return GNUNET_SYSERR;
314     }
315 }
316
317
318 /* end of tun.c */