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