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