- changes
[oweals/gnunet.git] / src / tun / tun.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010, 2011, 2012 Christian Grothoff
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
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_tun_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 (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header));
53   ip->header_length =  sizeof (struct GNUNET_TUN_IPv4Header) / 4;
54   ip->version = 4;
55   ip->diff_serv = 0;
56   ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length);
57   ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 
58                                                             65536);
59   ip->flags = 0;
60   ip->fragmentation_offset = 0;
61   ip->ttl = FRESH_TTL;
62   ip->protocol = protocol;
63   ip->checksum = 0;
64   ip->source_address = *src;
65   ip->destination_address = *dst;
66   ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header));
67 }
68
69
70 /**
71  * Initialize an IPv6 header.
72  *
73  * @param ip header to initialize
74  * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6
75  * @param payload_length number of bytes of payload that follow (excluding IPv4 header)
76  * @param src source IP address to use
77  * @param dst destination IP address to use
78  */
79 void
80 GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
81                                    uint8_t protocol,
82                                    uint16_t payload_length,
83                                    const struct in6_addr *src,
84                                    const struct in6_addr *dst)
85 {
86   GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header));
87   ip->traffic_class_h = 0;
88   ip->version = 6;
89   ip->traffic_class_l = 0;
90   ip->flow_label = 0;
91   ip->next_header = protocol;
92   ip->payload_length = htons ((uint16_t) payload_length);
93   ip->hop_limit = FRESH_TTL;
94   ip->destination_address = *dst;
95   ip->source_address = *src;  
96 }
97
98
99 /**
100  * Calculate IPv4 TCP checksum.
101  *
102  * @param ip ipv4 header fully initialized
103  * @param tcp TCP header (initialized except for CRC)
104  * @param payload the TCP payload
105  * @param payload_length number of bytes of TCP payload
106  */
107 void
108 GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
109                                     struct GNUNET_TUN_TcpHeader *tcp,
110                                     const void *payload,
111                                     uint16_t payload_length)
112 {
113   uint32_t sum;
114   uint32_t tmp;
115
116   GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) ==
117                  ntohs (ip->total_length));
118   GNUNET_assert (IPPROTO_TCP == ip->protocol);
119
120   tcp->crc = 0;
121   sum = GNUNET_CRYPTO_crc16_step (0, 
122                                   &ip->source_address,
123                                   sizeof (struct in_addr) * 2);
124   tmp = htonl ((IPPROTO_TCP << 16) | (payload_length + sizeof (struct GNUNET_TUN_TcpHeader)));
125   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_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 (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) ==
150                  ntohs (ip->payload_length));
151   GNUNET_assert (IPPROTO_TCP == ip->next_header);
152   tcp->crc = 0;
153   sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr));
154   tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length);
155   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
156   tmp = htonl (IPPROTO_TCP);
157   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
158   sum = GNUNET_CRYPTO_crc16_step (sum, tcp,
159                                   sizeof (struct GNUNET_TUN_TcpHeader));
160   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
161   tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
162 }
163
164
165 /**
166  * Calculate IPv4 UDP checksum.
167  *
168  * @param ip ipv4 header fully initialized
169  * @param udp UDP header (initialized except for CRC)
170  * @param payload the UDP payload
171  * @param payload_length number of bytes of UDP payload
172  */
173 void
174 GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
175                                     struct GNUNET_TUN_UdpHeader *udp,
176                                     const void *payload,
177                                     uint16_t payload_length)
178 {
179   uint32_t sum;
180   uint16_t tmp;
181
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   icmp->crc = 0;
260   sum = GNUNET_CRYPTO_crc16_step (0,
261                                   icmp,
262                                   sizeof (struct GNUNET_TUN_IcmpHeader));
263   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
264   icmp->crc = GNUNET_CRYPTO_crc16_finish (sum);
265 }
266
267
268 /* end of tun.c */