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