first batch of license fixes (boring)
[oweals/gnunet.git] / src / tun / 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 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
16 /**
17  * @file tun/tun.c
18  * @brief standard IP calculations for TUN interaction
19  * @author Philipp Toelke
20  * @author Christian Grothoff
21  */
22 #include "platform.h"
23 #include "gnunet_tun_lib.h"
24
25 /**
26  * IP TTL we use for packets that we assemble (8 bit unsigned integer)
27  */
28 #define FRESH_TTL 64
29
30
31 /**
32  * Initialize an IPv4 header.
33  *
34  * @param ip header to initialize
35  * @param protocol protocol to use (i.e. IPPROTO_UDP)
36  * @param payload_length number of bytes of payload that follow (excluding IPv4 header)
37  * @param src source IP address to use
38  * @param dst destination IP address to use
39  */
40 void
41 GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip,
42                                    uint8_t protocol,
43                                    uint16_t payload_length,
44                                    const struct in_addr *src,
45                                    const struct in_addr *dst)
46 {
47   GNUNET_assert (20 == sizeof (struct GNUNET_TUN_IPv4Header));
48   GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header));
49   memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header));
50   ip->header_length =  sizeof (struct GNUNET_TUN_IPv4Header) / 4;
51   ip->version = 4;
52   ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length);
53   ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
54                                                             65536);
55   ip->ttl = FRESH_TTL;
56   ip->protocol = protocol;
57   ip->source_address = *src;
58   ip->destination_address = *dst;
59   ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header));
60 }
61
62
63 /**
64  * Initialize an IPv6 header.
65  *
66  * @param ip header to initialize
67  * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6
68  * @param payload_length number of bytes of payload that follow (excluding IPv6 header)
69  * @param src source IP address to use
70  * @param dst destination IP address to use
71  */
72 void
73 GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
74                                    uint8_t protocol,
75                                    uint16_t payload_length,
76                                    const struct in6_addr *src,
77                                    const struct in6_addr *dst)
78 {
79   GNUNET_assert (40 == sizeof (struct GNUNET_TUN_IPv6Header));
80   GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header));
81   memset (ip, 0, sizeof (struct GNUNET_TUN_IPv6Header));
82   ip->version = 6;
83   ip->next_header = protocol;
84   ip->payload_length = htons ((uint16_t) payload_length);
85   ip->hop_limit = FRESH_TTL;
86   ip->destination_address = *dst;
87   ip->source_address = *src;
88 }
89
90
91 /**
92  * Calculate IPv4 TCP checksum.
93  *
94  * @param ip ipv4 header fully initialized
95  * @param tcp TCP header (initialized except for CRC)
96  * @param payload the TCP payload
97  * @param payload_length number of bytes of TCP payload
98  */
99 void
100 GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
101                                     struct GNUNET_TUN_TcpHeader *tcp,
102                                     const void *payload,
103                                     uint16_t payload_length)
104 {
105   uint32_t sum;
106   uint16_t tmp;
107
108   GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
109   GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) ==
110                  ntohs (ip->total_length));
111   GNUNET_assert (IPPROTO_TCP == ip->protocol);
112
113   tcp->crc = 0;
114   sum = GNUNET_CRYPTO_crc16_step (0,
115                                   &ip->source_address,
116                                   sizeof (struct in_addr) * 2);
117   tmp = htons (IPPROTO_TCP);
118   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
119   tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader));
120   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
121   sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader));
122   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
123   tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
124 }
125
126
127 /**
128  * Calculate IPv6 TCP checksum.
129  *
130  * @param ip ipv6 header fully initialized
131  * @param tcp header (initialized except for CRC)
132  * @param payload the TCP payload
133  * @param payload_length number of bytes of TCP payload
134  */
135 void
136 GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
137                                     struct GNUNET_TUN_TcpHeader *tcp,
138                                     const void *payload,
139                                     uint16_t payload_length)
140 {
141   uint32_t sum;
142   uint32_t tmp;
143
144   GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
145   GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) ==
146                  ntohs (ip->payload_length));
147   GNUNET_assert (IPPROTO_TCP == ip->next_header);
148   tcp->crc = 0;
149   sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr));
150   tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length);
151   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
152   tmp = htonl (IPPROTO_TCP);
153   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
154   sum = GNUNET_CRYPTO_crc16_step (sum, tcp,
155                                   sizeof (struct GNUNET_TUN_TcpHeader));
156   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
157   tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
158 }
159
160
161 /**
162  * Calculate IPv4 UDP checksum.
163  *
164  * @param ip ipv4 header fully initialized
165  * @param udp UDP header (initialized except for CRC)
166  * @param payload the UDP payload
167  * @param payload_length number of bytes of UDP payload
168  */
169 void
170 GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
171                                     struct GNUNET_TUN_UdpHeader *udp,
172                                     const void *payload,
173                                     uint16_t payload_length)
174 {
175   uint32_t sum;
176   uint16_t tmp;
177
178   GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
179   GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) ==
180                  ntohs (ip->total_length));
181   GNUNET_assert (IPPROTO_UDP == ip->protocol);
182
183   udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */
184   sum = GNUNET_CRYPTO_crc16_step (0,
185                                   &ip->source_address,
186                                   sizeof (struct in_addr) * 2);
187   tmp = htons (IPPROTO_UDP);
188   sum = GNUNET_CRYPTO_crc16_step (sum,
189                                   &tmp,
190                                   sizeof (uint16_t));
191   tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length);
192   sum = GNUNET_CRYPTO_crc16_step (sum,
193                                   &tmp,
194                                   sizeof (uint16_t));
195   sum = GNUNET_CRYPTO_crc16_step (sum,
196                                   udp,
197                                   sizeof (struct GNUNET_TUN_UdpHeader));
198   sum = GNUNET_CRYPTO_crc16_step (sum,
199                                   payload,
200                                   payload_length);
201   udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
202 }
203
204
205 /**
206  * Calculate IPv6 UDP checksum.
207  *
208  * @param ip ipv6 header fully initialized
209  * @param udp UDP header (initialized except for CRC)
210  * @param payload the UDP payload
211  * @param payload_length number of bytes of UDP payload
212  */
213 void
214 GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
215                                     struct GNUNET_TUN_UdpHeader *udp,
216                                     const void *payload,
217                                     uint16_t payload_length)
218 {
219   uint32_t sum;
220   uint32_t tmp;
221
222   GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
223                  ntohs (ip->payload_length));
224   GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
225                  ntohs (udp->len));
226   GNUNET_assert (IPPROTO_UDP == ip->next_header);
227
228   udp->crc = 0;
229   sum = GNUNET_CRYPTO_crc16_step (0,
230                                   &ip->source_address,
231                                   sizeof (struct in6_addr) * 2);
232   tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */
233   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
234   tmp = htons (ip->next_header);
235   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
236   sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader));
237   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
238   udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
239 }
240
241
242 /**
243  * Calculate ICMP checksum.
244  *
245  * @param icmp IMCP header (initialized except for CRC)
246  * @param payload the ICMP payload
247  * @param payload_length number of bytes of ICMP payload
248  */
249 void
250 GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp,
251                                     const void *payload,
252                                     uint16_t payload_length)
253 {
254   uint32_t sum;
255
256   GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader));
257   icmp->crc = 0;
258   sum = GNUNET_CRYPTO_crc16_step (0,
259                                   icmp,
260                                   sizeof (struct GNUNET_TUN_IcmpHeader));
261   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
262   icmp->crc = GNUNET_CRYPTO_crc16_finish (sum);
263 }
264
265
266 /**
267  * Check if two sockaddrs are equal.
268  *
269  * @param sa one address
270  * @param sb another address
271  * @param include_port also check ports
272  * @return #GNUNET_YES if they are equal
273  */
274 int
275 GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa,
276                          const struct sockaddr *sb,
277                          int include_port)
278 {
279   if (sa->sa_family != sb->sa_family)
280     return GNUNET_NO;
281
282   switch (sa->sa_family)
283   {
284   case AF_INET:
285     {
286       const struct sockaddr_in *sa4 = (const struct sockaddr_in *) sa;
287       const struct sockaddr_in *sb4 = (const struct sockaddr_in *) sb;
288       return (sa4->sin_addr.s_addr == sb4->sin_addr.s_addr);
289     }
290   case AF_INET6:
291     {
292       const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa;
293       const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb;
294
295       return (0 == memcmp(&sa6->sin6_addr,
296                           &sb6->sin6_addr,
297                           sizeof (struct in6_addr)));
298     }
299   default:
300     GNUNET_break (0);
301     return GNUNET_SYSERR;
302   }
303 }
304
305
306 /* end of tun.c */