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-2024 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 #endif
27 
28 #include "syshead.h"
29 
30 #include "proto.h"
31 #include "error.h"
32 
33 #include "memdbg.h"
34 
35 /*
36  * If raw tunnel packet is IPv<X>, return true and increment
37  * buffer offset to start of IP header.
38  */
39 static bool
40 is_ipv_X(int tunnel_type, struct buffer *buf, int ip_ver)
41 {
42  int offset;
43  uint16_t proto;
44  const struct openvpn_iphdr *ih;
45 
46  verify_align_4(buf);
47  if (tunnel_type == DEV_TYPE_TUN)
48  {
49  if (BLEN(buf) < sizeof(struct openvpn_iphdr))
50  {
51  return false;
52  }
53  offset = 0;
54  }
55  else if (tunnel_type == DEV_TYPE_TAP)
56  {
57  const struct openvpn_ethhdr *eh;
58  if (BLEN(buf) < (sizeof(struct openvpn_ethhdr)
59  + sizeof(struct openvpn_iphdr)))
60  {
61  return false;
62  }
63  eh = (const struct openvpn_ethhdr *)BPTR(buf);
64 
65  /* start by assuming this is a standard Eth fram */
66  proto = eh->proto;
67  offset = sizeof(struct openvpn_ethhdr);
68 
69  /* if this is a 802.1q frame, parse the header using the according
70  * format
71  */
72  if (proto == htons(OPENVPN_ETH_P_8021Q))
73  {
74  const struct openvpn_8021qhdr *evh;
75  if (BLEN(buf) < (sizeof(struct openvpn_ethhdr)
76  + sizeof(struct openvpn_iphdr)))
77  {
78  return false;
79  }
80 
81  evh = (const struct openvpn_8021qhdr *)BPTR(buf);
82 
83  proto = evh->proto;
84  offset = sizeof(struct openvpn_8021qhdr);
85  }
86 
87  if (ntohs(proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4))
88  {
89  return false;
90  }
91  }
92  else
93  {
94  return false;
95  }
96 
97  ih = (const struct openvpn_iphdr *)(BPTR(buf) + offset);
98 
99  /* IP version is stored in the same bits for IPv4 or IPv6 header */
100  if (OPENVPN_IPH_GET_VER(ih->version_len) == ip_ver)
101  {
102  return buf_advance(buf, offset);
103  }
104  else
105  {
106  return false;
107  }
108 }
109 
110 bool
111 is_ipv4(int tunnel_type, struct buffer *buf)
112 {
113  return is_ipv_X( tunnel_type, buf, 4 );
114 }
115 bool
116 is_ipv6(int tunnel_type, struct buffer *buf)
117 {
118  return is_ipv_X( tunnel_type, buf, 6 );
119 }
120 
121 
122 uint16_t
123 ip_checksum(const sa_family_t af, const uint8_t *payload, const int len_payload,
124  const uint8_t *src_addr, const uint8_t *dest_addr, const int proto)
125 {
126  uint32_t sum = 0;
127  int addr_len = (af == AF_INET) ? 4 : 16;
128 
129  /*
130  * make 16 bit words out of every two adjacent 8 bit words and */
131  /* calculate the sum of all 16 bit words
132  */
133  for (int i = 0; i < len_payload; i += 2)
134  {
135  sum += (uint16_t)(((payload[i] << 8) & 0xFF00)
136  +((i + 1 < len_payload) ? (payload[i + 1] & 0xFF) : 0));
137 
138  }
139 
140  /*
141  * add the pseudo header which contains the IP source and destination
142  * addresses
143  */
144  for (int i = 0; i < addr_len; i += 2)
145  {
146  sum += (uint16_t)((src_addr[i] << 8) & 0xFF00) + (src_addr[i + 1] & 0xFF);
147 
148  }
149  for (int i = 0; i < addr_len; i += 2)
150  {
151  sum += (uint16_t)((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i + 1] & 0xFF);
152  }
153 
154  /* the length of the payload */
155  sum += (uint16_t)len_payload;
156 
157  /* The next header or proto field*/
158  sum += (uint16_t)proto;
159 
160  /*
161  * keep only the last 16 bits of the 32 bit calculated sum and add
162  * the carries
163  */
164  while (sum >> 16)
165  {
166  sum = (sum & 0xFFFF) + (sum >> 16);
167  }
168 
169  /* Take the one's complement of sum */
170  return ((uint16_t) ~sum);
171 }
172 
173 #ifdef PACKET_TRUNCATION_CHECK
174 
175 void
176 ipv4_packet_size_verify(const uint8_t *data,
177  const int size,
178  const int tunnel_type,
179  const char *prefix,
180  counter_type *errors)
181 {
182  if (size > 0)
183  {
184  struct buffer buf;
185 
186  buf_set_read(&buf, data, size);
187 
188  if (is_ipv4(tunnel_type, &buf))
189  {
190  const struct openvpn_iphdr *pip;
191  int hlen;
192  int totlen;
193  const char *msgstr = "PACKET SIZE INFO";
194  unsigned int msglevel = D_PACKET_TRUNC_DEBUG;
195 
196  if (BLEN(&buf) < (int) sizeof(struct openvpn_iphdr))
197  {
198  return;
199  }
200 
201  verify_align_4(&buf);
202  pip = (struct openvpn_iphdr *) BPTR(&buf);
203 
204  hlen = OPENVPN_IPH_GET_LEN(pip->version_len);
205  totlen = ntohs(pip->tot_len);
206 
207  if (BLEN(&buf) != totlen)
208  {
209  msgstr = "PACKET TRUNCATION ERROR";
210  msglevel = D_PACKET_TRUNC_ERR;
211  if (errors)
212  {
213  ++(*errors);
214  }
215  }
216 
217  msg(msglevel, "%s %s: size=%d totlen=%d hlen=%d errcount=" counter_format,
218  msgstr,
219  prefix,
220  BLEN(&buf),
221  totlen,
222  hlen,
223  errors ? *errors : (counter_type)0);
224  }
225  }
226 }
227 
228 #endif /* ifdef PACKET_TRUNCATION_CHECK */
error.h
DEV_TYPE_TUN
#define DEV_TYPE_TUN
Definition: proto.h:37
D_PACKET_TRUNC_ERR
#define D_PACKET_TRUNC_ERR
Definition: errlevel.h:100
D_PACKET_TRUNC_DEBUG
#define D_PACKET_TRUNC_DEBUG
Definition: errlevel.h:143
is_ipv6
bool is_ipv6(int tunnel_type, struct buffer *buf)
Definition: proto.c:116
sa_family_t
unsigned short sa_family_t
Definition: syshead.h:385
openvpn_8021qhdr
Definition: proto.h:67
buf_advance
static bool buf_advance(struct buffer *buf, int size)
Definition: buffer.h:623
counter_type
uint64_t counter_type
Definition: common.h:30
BLEN
#define BLEN(buf)
Definition: buffer.h:127
proto.h
OPENVPN_ETH_P_8021Q
#define OPENVPN_ETH_P_8021Q
Definition: proto.h:63
OPENVPN_ETH_P_IPV4
#define OPENVPN_ETH_P_IPV4
Definition: proto.h:60
verify_align_4
#define verify_align_4(ptr)
Definition: buffer.h:996
DEV_TYPE_TAP
#define DEV_TYPE_TAP
Definition: proto.h:38
buffer
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
openvpn_ethhdr::proto
uint16_t proto
Definition: proto.h:64
openvpn_iphdr::tot_len
uint16_t tot_len
Definition: proto.h:112
openvpn_8021qhdr::proto
uint16_t proto
Definition: proto.h:77
syshead.h
BPTR
#define BPTR(buf)
Definition: buffer.h:124
is_ipv_X
static bool is_ipv_X(int tunnel_type, struct buffer *buf, int ip_ver)
Definition: proto.c:40
counter_format
#define counter_format
Definition: common.h:31
openvpn_ethhdr
Definition: proto.h:55
OPENVPN_IPH_GET_VER
#define OPENVPN_IPH_GET_VER(v)
Definition: proto.h:107
openvpn_iphdr::version_len
uint8_t version_len
Definition: proto.h:109
config.h
is_ipv4
bool is_ipv4(int tunnel_type, struct buffer *buf)
Definition: proto.c:111
openvpn_iphdr
Definition: proto.h:106
memdbg.h
OPENVPN_IPH_GET_LEN
#define OPENVPN_IPH_GET_LEN(v)
Definition: proto.h:108
msg
#define msg(flags,...)
Definition: error.h:144
ip_checksum
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:123
buf_set_read
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Definition: buffer.h:348
OPENVPN_ETH_P_IPV6
#define OPENVPN_ETH_P_IPV6
Definition: proto.h:61
buffer::data
uint8_t * data
Pointer to the allocated memory.
Definition: buffer.h:68