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 */
39static bool
40is_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
110bool
111is_ipv4(int tunnel_type, struct buffer *buf)
112{
113 return is_ipv_X( tunnel_type, buf, 4 );
114}
115bool
116is_ipv6(int tunnel_type, struct buffer *buf)
117{
118 return is_ipv_X( tunnel_type, buf, 6 );
119}
120
121
122uint16_t
123ip_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
175void
176ipv4_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 */
#define BPTR(buf)
Definition buffer.h:124
static bool buf_advance(struct buffer *buf, int size)
Definition buffer.h:618
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Definition buffer.h:348
#define verify_align_4(ptr)
Definition buffer.h:991
#define BLEN(buf)
Definition buffer.h:127
uint64_t counter_type
Definition common.h:30
#define counter_format
Definition common.h:31
#define D_PACKET_TRUNC_ERR
Definition errlevel.h:100
#define D_PACKET_TRUNC_DEBUG
Definition errlevel.h:143
#define msg(flags,...)
Definition error.h:144
bool is_ipv4(int tunnel_type, struct buffer *buf)
Definition proto.c:111
bool is_ipv6(int tunnel_type, struct buffer *buf)
Definition proto.c:116
static bool is_ipv_X(int tunnel_type, struct buffer *buf, int ip_ver)
Definition proto.c:40
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
#define OPENVPN_ETH_P_8021Q
Definition proto.h:62
#define OPENVPN_IPH_GET_LEN(v)
Definition proto.h:94
#define DEV_TYPE_TAP
Definition proto.h:37
#define OPENVPN_ETH_P_IPV6
Definition proto.h:60
#define DEV_TYPE_TUN
Definition proto.h:36
#define OPENVPN_ETH_P_IPV4
Definition proto.h:59
#define OPENVPN_IPH_GET_VER(v)
Definition proto.h:93
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
uint8_t * data
Pointer to the allocated memory.
Definition buffer.h:68
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
uint16_t proto
Definition proto.h:76
uint16_t proto
Definition proto.h:63
uint16_t tot_len
Definition proto.h:98
uint8_t version_len
Definition proto.h:95
unsigned short sa_family_t
Definition syshead.h:395