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