OpenVPN
proto.c
Go to the documentation of this file.
1 /*
2  * OpenVPN -- An application to securely tunnel IP networks
3  * over a single TCP/UDP port, with support for SSL/TLS-based
4  * session authentication and key exchange,
5  * packet encryption, packet authentication, and
6  * packet compression.
7  *
8  * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2
12  * as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29 
30 #include "syshead.h"
31 
32 #include "proto.h"
33 #include "error.h"
34 
35 #include "memdbg.h"
36 
37 /*
38  * If raw tunnel packet is IPv<X>, return true and increment
39  * buffer offset to start of IP header.
40  */
41 static bool
42 is_ipv_X(int tunnel_type, struct buffer *buf, int ip_ver)
43 {
44  int offset;
45  uint16_t proto;
46  const struct openvpn_iphdr *ih;
47 
48  verify_align_4(buf);
49  if (tunnel_type == DEV_TYPE_TUN)
50  {
51  if (BLEN(buf) < sizeof(struct openvpn_iphdr))
52  {
53  return false;
54  }
55  offset = 0;
56  }
57  else if (tunnel_type == DEV_TYPE_TAP)
58  {
59  const struct openvpn_ethhdr *eh;
60  if (BLEN(buf) < (sizeof(struct openvpn_ethhdr)
61  + sizeof(struct openvpn_iphdr)))
62  {
63  return false;
64  }
65  eh = (const struct openvpn_ethhdr *)BPTR(buf);
66 
67  /* start by assuming this is a standard Eth fram */
68  proto = eh->proto;
69  offset = sizeof(struct openvpn_ethhdr);
70 
71  /* if this is a 802.1q frame, parse the header using the according
72  * format
73  */
74  if (proto == htons(OPENVPN_ETH_P_8021Q))
75  {
76  const struct openvpn_8021qhdr *evh;
77  if (BLEN(buf) < (sizeof(struct openvpn_ethhdr)
78  + sizeof(struct openvpn_iphdr)))
79  {
80  return false;
81  }
82 
83  evh = (const struct openvpn_8021qhdr *)BPTR(buf);
84 
85  proto = evh->proto;
86  offset = sizeof(struct openvpn_8021qhdr);
87  }
88 
89  if (ntohs(proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4))
90  {
91  return false;
92  }
93  }
94  else
95  {
96  return false;
97  }
98 
99  ih = (const struct openvpn_iphdr *)(BPTR(buf) + offset);
100 
101  /* IP version is stored in the same bits for IPv4 or IPv6 header */
102  if (OPENVPN_IPH_GET_VER(ih->version_len) == ip_ver)
103  {
104  return buf_advance(buf, offset);
105  }
106  else
107  {
108  return false;
109  }
110 }
111 
112 bool
113 is_ipv4(int tunnel_type, struct buffer *buf)
114 {
115  return is_ipv_X( tunnel_type, buf, 4 );
116 }
117 bool
118 is_ipv6(int tunnel_type, struct buffer *buf)
119 {
120  return is_ipv_X( tunnel_type, buf, 6 );
121 }
122 
123 
124 uint16_t
125 ip_checksum(const sa_family_t af, const uint8_t *payload, const int len_payload,
126  const uint8_t *src_addr, const uint8_t *dest_addr, const int proto)
127 {
128  uint32_t sum = 0;
129  int addr_len = (af == AF_INET) ? 4 : 16;
130 
131  /*
132  * make 16 bit words out of every two adjacent 8 bit words and */
133  /* calculate the sum of all 16 bit words
134  */
135  for (int i = 0; i < len_payload; i += 2)
136  {
137  sum += (uint16_t)(((payload[i] << 8) & 0xFF00)
138  +((i + 1 < len_payload) ? (payload[i + 1] & 0xFF) : 0));
139 
140  }
141 
142  /*
143  * add the pseudo header which contains the IP source and destination
144  * addresses
145  */
146  for (int i = 0; i < addr_len; i += 2)
147  {
148  sum += (uint16_t)((src_addr[i] << 8) & 0xFF00) + (src_addr[i + 1] & 0xFF);
149 
150  }
151  for (int i = 0; i < addr_len; i += 2)
152  {
153  sum += (uint16_t)((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i + 1] & 0xFF);
154  }
155 
156  /* the length of the payload */
157  sum += (uint16_t)len_payload;
158 
159  /* The next header or proto field*/
160  sum += (uint16_t)proto;
161 
162  /*
163  * keep only the last 16 bits of the 32 bit calculated sum and add
164  * the carries
165  */
166  while (sum >> 16)
167  {
168  sum = (sum & 0xFFFF) + (sum >> 16);
169  }
170 
171  /* Take the one's complement of sum */
172  return ((uint16_t) ~sum);
173 }
174 
175 #ifdef PACKET_TRUNCATION_CHECK
176 
177 void
178 ipv4_packet_size_verify(const uint8_t *data,
179  const int size,
180  const int tunnel_type,
181  const char *prefix,
182  counter_type *errors)
183 {
184  if (size > 0)
185  {
186  struct buffer buf;
187 
188  buf_set_read(&buf, data, size);
189 
190  if (is_ipv4(tunnel_type, &buf))
191  {
192  const struct openvpn_iphdr *pip;
193  int hlen;
194  int totlen;
195  const char *msgstr = "PACKET SIZE INFO";
196  unsigned int msglevel = D_PACKET_TRUNC_DEBUG;
197 
198  if (BLEN(&buf) < (int) sizeof(struct openvpn_iphdr))
199  {
200  return;
201  }
202 
203  verify_align_4(&buf);
204  pip = (struct openvpn_iphdr *) BPTR(&buf);
205 
206  hlen = OPENVPN_IPH_GET_LEN(pip->version_len);
207  totlen = ntohs(pip->tot_len);
208 
209  if (BLEN(&buf) != totlen)
210  {
211  msgstr = "PACKET TRUNCATION ERROR";
212  msglevel = D_PACKET_TRUNC_ERR;
213  if (errors)
214  {
215  ++(*errors);
216  }
217  }
218 
219  msg(msglevel, "%s %s: size=%d totlen=%d hlen=%d errcount=" counter_format,
220  msgstr,
221  prefix,
222  BLEN(&buf),
223  totlen,
224  hlen,
225  errors ? *errors : (counter_type)0);
226  }
227  }
228 }
229 
230 #endif /* ifdef PACKET_TRUNCATION_CHECK */
uint8_t version_len
Definition: proto.h:109
#define OPENVPN_IPH_GET_LEN(v)
Definition: proto.h:108
#define OPENVPN_ETH_P_IPV6
Definition: proto.h:61
#define D_PACKET_TRUNC_DEBUG
Definition: errlevel.h:141
uint16_t proto
Definition: proto.h:77
static bool buf_advance(struct buffer *buf, int size)
Definition: buffer.h:639
#define OPENVPN_ETH_P_8021Q
Definition: proto.h:63
unsigned short sa_family_t
Definition: syshead.h:448
#define D_PACKET_TRUNC_ERR
Definition: errlevel.h:101
#define OPENVPN_IPH_GET_VER(v)
Definition: proto.h:107
uint16_t proto
Definition: proto.h:64
#define BPTR(buf)
Definition: buffer.h:124
uint16_t ip_checksum(const sa_family_t af, const uint8_t *payload, const int len_payload, const uint8_t *src_addr, const uint8_t *dest_addr, const int proto)
Calculates an IP or IPv6 checksum with a pseudo header as required by TCP, UDP and ICMPv6...
Definition: proto.c:125
#define counter_format
Definition: common.h:39
#define OPENVPN_ETH_P_IPV4
Definition: proto.h:60
#define DEV_TYPE_TUN
Definition: proto.h:37
unsigned __int32 uint32_t
Definition: config-msvc.h:157
unsigned int counter_type
Definition: common.h:38
#define msg
Definition: error.h:173
uint8_t * data
Pointer to the allocated memory.
Definition: buffer.h:68
#define BLEN(buf)
Definition: buffer.h:127
unsigned __int8 uint8_t
Definition: config-msvc.h:159
uint16_t tot_len
Definition: proto.h:112
bool is_ipv6(int tunnel_type, struct buffer *buf)
Definition: proto.c:118
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
static bool is_ipv_X(int tunnel_type, struct buffer *buf, int ip_ver)
Definition: proto.c:42
#define verify_align_4(ptr)
Definition: buffer.h:981
bool is_ipv4(int tunnel_type, struct buffer *buf)
Definition: proto.c:113
unsigned __int16 uint16_t
Definition: config-msvc.h:158
static void buf_set_read(struct buffer *buf, const uint8_t *data, int size)
Definition: buffer.h:335
#define DEV_TYPE_TAP
Definition: proto.h:38