OpenVPN
src
openvpn
vlan.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 Technologies, Inc. <sales@openvpn.net>
9
* Copyright (C) 2010 Fabian Knittel <fabian.knittel@lettink.de>
10
*
11
* This program is free software; you can redistribute it and/or modify
12
* it under the terms of the GNU General Public License version 2
13
* as published by the Free Software Foundation.
14
*
15
* This program is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
19
*
20
* You should have received a copy of the GNU General Public License along
21
* with this program; if not, write to the Free Software Foundation, Inc.,
22
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
*/
24
25
#ifdef HAVE_CONFIG_H
26
#include "
config.h
"
27
#endif
28
29
#include "
syshead.h
"
30
31
#include "
multi.h
"
32
#include "
options.h
"
33
#include "
vlan.h
"
34
35
/*
36
* Retrieve the VLAN Identifier (VID) from the IEEE 802.1Q header.
37
*
38
* @param hdr Pointer to the Ethernet header with IEEE 802.1Q tagging.
39
* @return Returns the VID in host byte order.
40
*/
41
static
uint16_t
42
vlanhdr_get_vid
(
const
struct
openvpn_8021qhdr
*hdr)
43
{
44
return
ntohs(hdr->
pcp_cfi_vid
&
OPENVPN_8021Q_MASK_VID
);
45
}
46
47
/*
48
* Set the VLAN Identifier (VID) in an IEEE 802.1Q header.
49
*
50
* @param hdr Pointer to the Ethernet header with IEEE 802.1Q tagging.
51
* @param vid The VID to set (in host byte order).
52
*/
53
static
void
54
vlanhdr_set_vid
(
struct
openvpn_8021qhdr
*hdr,
const
uint16_t vid)
55
{
56
hdr->
pcp_cfi_vid
= (hdr->
pcp_cfi_vid
& ~
OPENVPN_8021Q_MASK_VID
)
57
| (htons(vid) &
OPENVPN_8021Q_MASK_VID
);
58
}
59
60
/*
61
* vlan_decapsulate - remove 802.1q header and return VID
62
*
63
* For vlan_accept == VLAN_ONLY_UNTAGGED_OR_PRIORITY:
64
* Only untagged frames and frames that are priority-tagged (VID == 0) are
65
* accepted. (This means that VLAN-tagged frames are dropped.) For frames
66
* that aren't dropped, the global vlan_pvid is returned as VID.
67
*
68
* For vlan_accept == VLAN_ONLY_TAGGED:
69
* If a frame is VLAN-tagged the tagging is removed and the embedded VID is
70
* returned. Any included priority information is lost.
71
* If a frame isn't VLAN-tagged, the frame is dropped.
72
*
73
* For vlan_accept == VLAN_ALL:
74
* Accepts both VLAN-tagged and untagged (or priority-tagged) frames and
75
* and handles them as described above.
76
*
77
* @param c The global context.
78
* @param buf The ethernet frame.
79
* @return Returns -1 if the frame is dropped or the VID if it is accepted.
80
*/
81
int16_t
82
vlan_decapsulate
(
const
struct
context
*c,
struct
buffer
*buf)
83
{
84
const
struct
openvpn_8021qhdr
*vlanhdr;
85
struct
openvpn_ethhdr
*ethhdr;
86
uint16_t vid;
87
88
/* assume untagged frame */
89
if
(
BLEN
(buf) <
sizeof
(*ethhdr))
90
{
91
goto
drop;
92
}
93
94
ethhdr = (
struct
openvpn_ethhdr
*)
BPTR
(buf);
95
if
(ethhdr->
proto
!= htons(
OPENVPN_ETH_P_8021Q
))
96
{
97
/* reject untagged frame */
98
if
(c->
options
.
vlan_accept
==
VLAN_ONLY_TAGGED
)
99
{
100
msg
(
D_VLAN_DEBUG
,
101
"dropping frame without vlan-tag (proto/len 0x%04x)"
,
102
ntohs(ethhdr->
proto
));
103
goto
drop;
104
}
105
106
/* untagged frame is accepted and associated with the global VID */
107
msg
(
D_VLAN_DEBUG
,
108
"assuming pvid for frame without vlan-tag, pvid: %u (proto/len 0x%04x)"
,
109
c->
options
.
vlan_pvid
, ntohs(ethhdr->
proto
));
110
111
return
c->
options
.
vlan_pvid
;
112
}
113
114
/* tagged frame */
115
if
(
BLEN
(buf) <
sizeof
(*vlanhdr))
116
{
117
goto
drop;
118
}
119
120
vlanhdr = (
const
struct
openvpn_8021qhdr
*)
BPTR
(buf);
121
vid =
vlanhdr_get_vid
(vlanhdr);
122
123
switch
(c->
options
.
vlan_accept
)
124
{
125
case
VLAN_ONLY_UNTAGGED_OR_PRIORITY
:
126
/* VLAN-tagged frame: drop packet */
127
if
(vid != 0)
128
{
129
msg
(
D_VLAN_DEBUG
,
"dropping frame with vlan-tag, vid: %u (proto/len 0x%04x)"
,
130
vid, ntohs(vlanhdr->
proto
));
131
goto
drop;
132
}
133
134
/* vid == 0 means prio-tagged packet: don't drop and fall-through */
135
case
VLAN_ONLY_TAGGED
:
136
case
VLAN_ALL
:
137
/* tagged frame can be accepted: extract vid and strip encapsulation */
138
139
/* in case of prio-tagged frame (vid == 0), assume the sender
140
* knows what he is doing and forward the packet as it is, so to
141
* keep the priority information intact.
142
*/
143
if
(vid == 0)
144
{
145
/* return the global VID for priority-tagged frames */
146
return
c->
options
.
vlan_pvid
;
147
}
148
149
/* here we have a proper VLAN tagged frame: perform decapsulation
150
* and return embedded VID
151
*/
152
msg
(
D_VLAN_DEBUG
,
153
"removing vlan-tag from frame: vid: %u, wrapped proto/len: 0x%04x"
,
154
vid, ntohs(vlanhdr->
proto
));
155
156
/* save inner protocol to be restored later after decapsulation */
157
uint16_t
proto
= vlanhdr->
proto
;
158
/* move the buffer head forward to adjust the headroom to a
159
* non-tagged frame
160
*/
161
buf_advance
(buf,
SIZE_ETH_TO_8021Q_HDR
);
162
/* move the content of the 802.1q header to the new head, so that
163
* src/dst addresses are copied over
164
*/
165
ethhdr = memmove(
BPTR
(buf), vlanhdr,
sizeof
(*ethhdr));
166
/* restore the inner protocol value */
167
ethhdr->
proto
=
proto
;
168
169
return
vid;
170
}
171
172
drop:
173
buf->
len
= 0;
174
return
-1;
175
}
176
177
/*
178
* vlan_encapsulate - add 802.1q header and set the context related VID
179
*
180
* Assumes vlan_accept == VLAN_ONLY_TAGGED
181
*
182
* @param c The current context.
183
* @param buf The ethernet frame to encapsulate.
184
*/
185
void
186
vlan_encapsulate
(
const
struct
context
*c,
struct
buffer
*buf)
187
{
188
const
struct
openvpn_ethhdr
*ethhdr;
189
struct
openvpn_8021qhdr
*vlanhdr;
190
191
if
(
BLEN
(buf) <
sizeof
(*ethhdr))
192
{
193
goto
drop;
194
}
195
196
ethhdr = (
const
struct
openvpn_ethhdr
*)
BPTR
(buf);
197
if
(ethhdr->
proto
== htons(
OPENVPN_ETH_P_8021Q
))
198
{
199
/* Priority-tagged frame. (VLAN-tagged frames have been dropped before
200
* getting to this point)
201
*/
202
203
/* Frame too small for header type? */
204
if
(
BLEN
(buf) <
sizeof
(*vlanhdr))
205
{
206
goto
drop;
207
}
208
209
vlanhdr = (
struct
openvpn_8021qhdr
*)
BPTR
(buf);
210
211
/* sanity check: ensure this packet is really just prio-tagged */
212
uint16_t vid =
vlanhdr_get_vid
(vlanhdr);
213
if
(vid != 0)
214
{
215
goto
drop;
216
}
217
}
218
else
219
{
220
/* Untagged frame. */
221
222
/* Not enough head room for VLAN tag? */
223
if
(
buf_reverse_capacity
(buf) <
SIZE_ETH_TO_8021Q_HDR
)
224
{
225
goto
drop;
226
}
227
228
vlanhdr = (
struct
openvpn_8021qhdr
*)
buf_prepend
(buf,
229
SIZE_ETH_TO_8021Q_HDR
);
230
231
/* Initialise VLAN/802.1q header.
232
* Move the Eth header so to keep dst/src addresses the same and then
233
* assign the other fields.
234
*
235
* Also, save the inner protocol first, so that it can be restored later
236
* after the memmove()
237
*/
238
uint16_t
proto
= ethhdr->
proto
;
239
memmove(vlanhdr, ethhdr,
sizeof
(*ethhdr));
240
vlanhdr->
tpid
= htons(
OPENVPN_ETH_P_8021Q
);
241
vlanhdr->
pcp_cfi_vid
= 0;
242
vlanhdr->
proto
=
proto
;
243
}
244
245
/* set the VID corresponding to the current context (client) */
246
vlanhdr_set_vid
(vlanhdr, c->
options
.
vlan_pvid
);
247
248
msg
(
D_VLAN_DEBUG
,
"tagging frame: vid %u (wrapping proto/len: %04x)"
,
249
c->
options
.
vlan_pvid
, vlanhdr->
proto
);
250
return
;
251
252
drop:
253
/* Drop the frame. */
254
buf->
len
= 0;
255
}
256
257
/*
258
* vlan_is_tagged - check if a packet is VLAN-tagged
259
*
260
* Checks whether ethernet frame is VLAN-tagged.
261
*
262
* @param buf The ethernet frame.
263
* @return Returns true if the frame is VLAN-tagged, false otherwise.
264
*/
265
bool
266
vlan_is_tagged
(
const
struct
buffer
*buf)
267
{
268
const
struct
openvpn_8021qhdr
*vlanhdr;
269
uint16_t vid;
270
271
if
(
BLEN
(buf) <
sizeof
(
struct
openvpn_8021qhdr
))
272
{
273
/* frame too small to be VLAN-tagged */
274
return
false
;
275
}
276
277
vlanhdr = (
const
struct
openvpn_8021qhdr
*)
BPTR
(buf);
278
279
if
(ntohs(vlanhdr->
tpid
) !=
OPENVPN_ETH_P_8021Q
)
280
{
281
/* non tagged frame */
282
return
false
;
283
}
284
285
vid =
vlanhdr_get_vid
(vlanhdr);
286
if
(vid == 0)
287
{
288
/* no vid: piority tagged only */
289
return
false
;
290
}
291
292
return
true
;
293
}
294
295
void
296
vlan_process_outgoing_tun
(
struct
multi_context
*m,
struct
multi_instance
*mi)
297
{
298
if
(!m->
top
.
options
.
vlan_tagging
)
299
{
300
return
;
301
}
302
303
if
(m->
top
.
options
.
vlan_accept
==
VLAN_ONLY_UNTAGGED_OR_PRIORITY
)
304
{
305
/* Packets forwarded to the TAP devices aren't VLAN-tagged. Only packets
306
* matching the PVID configured globally are allowed to be received
307
*/
308
if
(m->
top
.
options
.
vlan_pvid
!= mi->
context
.
options
.
vlan_pvid
)
309
{
310
/* Packet is coming from the wrong VID, drop it. */
311
mi->
context
.
c2
.
to_tun
.
len
= 0;
312
}
313
}
314
else
if
(m->
top
.
options
.
vlan_accept
==
VLAN_ALL
)
315
{
316
/* Packets either need to be VLAN-tagged or not, depending on the
317
* packet's originating VID and the port's native VID (PVID). */
318
319
if
(m->
top
.
options
.
vlan_pvid
!= mi->
context
.
options
.
vlan_pvid
)
320
{
321
/* Packets need to be VLAN-tagged, because the packet's VID does not
322
* match the port's PVID. */
323
vlan_encapsulate
(&mi->
context
, &mi->
context
.
c2
.
to_tun
);
324
}
325
}
326
else
if
(m->
top
.
options
.
vlan_accept
==
VLAN_ONLY_TAGGED
)
327
{
328
/* All packets on the port (the tap device) need to be VLAN-tagged. */
329
vlan_encapsulate
(&mi->
context
, &mi->
context
.
c2
.
to_tun
);
330
}
331
}
options::vlan_tagging
bool vlan_tagging
Definition:
options.h:693
multi_instance
Server-mode state structure for one single VPN tunnel.
Definition:
multi.h:101
VLAN_ONLY_UNTAGGED_OR_PRIORITY
@ VLAN_ONLY_UNTAGGED_OR_PRIORITY
Definition:
options.h:208
buffer::len
int len
Length in bytes of the actual content within the allocated memory.
Definition:
buffer.h:66
context
Contains all state information for one tunnel.
Definition:
openvpn.h:476
vlan.h
VLAN_ONLY_TAGGED
@ VLAN_ONLY_TAGGED
Definition:
options.h:207
D_VLAN_DEBUG
#define D_VLAN_DEBUG
Definition:
errlevel.h:154
options.h
SIZE_ETH_TO_8021Q_HDR
#define SIZE_ETH_TO_8021Q_HDR
Definition:
proto.h:84
openvpn_8021qhdr
Definition:
proto.h:67
context::c2
struct context_2 c2
Level 2 context.
Definition:
openvpn.h:517
OPENVPN_8021Q_MASK_VID
#define OPENVPN_8021Q_MASK_VID
Definition:
proto.h:75
buf_advance
static bool buf_advance(struct buffer *buf, int size)
Definition:
buffer.h:623
multi_context::top
struct context top
Storage structure for process-wide configuration.
Definition:
multi.h:195
BLEN
#define BLEN(buf)
Definition:
buffer.h:127
vlan_process_outgoing_tun
void vlan_process_outgoing_tun(struct multi_context *m, struct multi_instance *mi)
Definition:
vlan.c:296
vlan_decapsulate
int16_t vlan_decapsulate(const struct context *c, struct buffer *buf)
Definition:
vlan.c:82
context::options
struct options options
Options loaded from command line or configuration file.
Definition:
openvpn.h:478
OPENVPN_ETH_P_8021Q
#define OPENVPN_ETH_P_8021Q
Definition:
proto.h:63
vlan_encapsulate
void vlan_encapsulate(const struct context *c, struct buffer *buf)
Definition:
vlan.c:186
multi.h
buffer
Wrapper structure for dynamically allocated memory.
Definition:
buffer.h:60
openvpn_ethhdr::proto
uint16_t proto
Definition:
proto.h:64
openvpn_8021qhdr::proto
uint16_t proto
Definition:
proto.h:77
syshead.h
BPTR
#define BPTR(buf)
Definition:
buffer.h:124
openvpn_8021qhdr::pcp_cfi_vid
uint16_t pcp_cfi_vid
Definition:
proto.h:76
vlanhdr_set_vid
static void vlanhdr_set_vid(struct openvpn_8021qhdr *hdr, const uint16_t vid)
Definition:
vlan.c:54
options::vlan_pvid
uint16_t vlan_pvid
Definition:
options.h:695
buf_prepend
static uint8_t * buf_prepend(struct buffer *buf, int size)
Definition:
buffer.h:611
multi_context
Main OpenVPN server state structure.
Definition:
multi.h:155
openvpn_8021qhdr::tpid
uint16_t tpid
Definition:
proto.h:72
VLAN_ALL
@ VLAN_ALL
Definition:
options.h:209
openvpn_ethhdr
Definition:
proto.h:55
context_2::to_tun
struct buffer to_tun
Definition:
openvpn.h:379
config.h
options::vlan_accept
enum vlan_acceptable_frames vlan_accept
Definition:
options.h:694
vlanhdr_get_vid
static uint16_t vlanhdr_get_vid(const struct openvpn_8021qhdr *hdr)
Definition:
vlan.c:42
msg
#define msg(flags,...)
Definition:
error.h:144
vlan_is_tagged
bool vlan_is_tagged(const struct buffer *buf)
Definition:
vlan.c:266
multi_instance::context
struct context context
The context structure storing state for this VPN tunnel.
Definition:
multi.h:136
buf_reverse_capacity
static int buf_reverse_capacity(const struct buffer *buf)
Definition:
buffer.h:582
Generated by
1.8.17