c1e7cbcb2b7738c7f2c1391f44512a76a5ea85fa
[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   memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header));
54   ip->header_length =  sizeof (struct GNUNET_TUN_IPv4Header) / 4;
55   ip->version = 4;
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->ttl = FRESH_TTL;
60   ip->protocol = protocol;
61   ip->source_address = *src;
62   ip->destination_address = *dst;
63   ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header));
64 }
65
66
67 /**
68  * Initialize an IPv6 header.
69  *
70  * @param ip header to initialize
71  * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6
72  * @param payload_length number of bytes of payload that follow (excluding IPv4 header)
73  * @param src source IP address to use
74  * @param dst destination IP address to use
75  */
76 void
77 GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
78                                    uint8_t protocol,
79                                    uint16_t payload_length,
80                                    const struct in6_addr *src,
81                                    const struct in6_addr *dst)
82 {
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 (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) ==
112                  ntohs (ip->total_length));
113   GNUNET_assert (IPPROTO_TCP == ip->protocol);
114
115   tcp->crc = 0;
116   sum = GNUNET_CRYPTO_crc16_step (0, 
117                                   &ip->source_address,
118                                   sizeof (struct in_addr) * 2);
119   tmp = htons (IPPROTO_TCP);
120   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
121   tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader));
122   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
123   sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader));
124   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
125   tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
126 }
127
128
129 /**
130  * Calculate IPv6 TCP checksum.
131  *
132  * @param ip ipv6 header fully initialized
133  * @param tcp header (initialized except for CRC)
134  * @param payload the TCP payload
135  * @param payload_length number of bytes of TCP payload
136  */
137 void
138 GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
139                                     struct GNUNET_TUN_TcpHeader *tcp,
140                                     const void *payload,
141                                     uint16_t payload_length)
142 {
143   uint32_t sum;
144   uint32_t tmp;
145
146   GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) ==
147                  ntohs (ip->payload_length));
148   GNUNET_assert (IPPROTO_TCP == ip->next_header);
149   tcp->crc = 0;
150   sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr));
151   tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length);
152   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
153   tmp = htonl (IPPROTO_TCP);
154   sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
155   sum = GNUNET_CRYPTO_crc16_step (sum, tcp,
156                                   sizeof (struct GNUNET_TUN_TcpHeader));
157   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
158   tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
159 }
160
161
162 /**
163  * Calculate IPv4 UDP checksum.
164  *
165  * @param ip ipv4 header fully initialized
166  * @param udp UDP header (initialized except for CRC)
167  * @param payload the UDP payload
168  * @param payload_length number of bytes of UDP payload
169  */
170 void
171 GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
172                                     struct GNUNET_TUN_UdpHeader *udp,
173                                     const void *payload,
174                                     uint16_t payload_length)
175 {
176   uint32_t sum;
177   uint16_t tmp;
178
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   icmp->crc = 0;
257   sum = GNUNET_CRYPTO_crc16_step (0,
258                                   icmp,
259                                   sizeof (struct GNUNET_TUN_IcmpHeader));
260   sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
261   icmp->crc = GNUNET_CRYPTO_crc16_finish (sum);
262 }
263
264
265 /* end of tun.c */