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 */
41static uint16_t
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 */
53static void
54vlanhdr_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 */
81int16_t
82vlan_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 */
99 {
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 */
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 {
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 */
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 */
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
172drop:
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 */
185void
186vlan_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? */
224 {
225 goto drop;
226 }
227
228 vlanhdr = (struct openvpn_8021qhdr *)buf_prepend(buf,
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
252drop:
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 */
265bool
266vlan_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
295void
297{
298 if (!m->top.options.vlan_tagging)
299 {
300 return;
301 }
302
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 */
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
320 {
321 /* Packets need to be VLAN-tagged, because the packet's VID does not
322 * match the port's PVID. */
324 }
325 }
327 {
328 /* All packets on the port (the tap device) need to be VLAN-tagged. */
330 }
331}
#define BPTR(buf)
Definition buffer.h:124
static bool buf_advance(struct buffer *buf, int size)
Definition buffer.h:618
static uint8_t * buf_prepend(struct buffer *buf, int size)
Definition buffer.h:606
#define BLEN(buf)
Definition buffer.h:127
static int buf_reverse_capacity(const struct buffer *buf)
Definition buffer.h:577
#define D_VLAN_DEBUG
Definition errlevel.h:154
Header file for server-mode related structures and functions.
#define msg(flags,...)
Definition error.h:144
@ VLAN_ONLY_UNTAGGED_OR_PRIORITY
Definition options.h:221
@ VLAN_ALL
Definition options.h:222
@ VLAN_ONLY_TAGGED
Definition options.h:220
#define OPENVPN_ETH_P_8021Q
Definition proto.h:62
#define SIZE_ETH_TO_8021Q_HDR
Definition proto.h:83
#define OPENVPN_8021Q_MASK_VID
Definition proto.h:74
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
struct buffer to_tun
Definition openvpn.h:378
Contains all state information for one tunnel.
Definition openvpn.h:476
struct context_2 c2
Level 2 context.
Definition openvpn.h:516
struct options options
Options loaded from command line or configuration file.
Definition openvpn.h:477
Main OpenVPN server state structure.
Definition multi.h:163
struct context top
Storage structure for process-wide configuration.
Definition multi.h:202
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:71
uint16_t pcp_cfi_vid
Definition proto.h:75
uint16_t proto
Definition proto.h:76
uint16_t proto
Definition proto.h:63
enum vlan_acceptable_frames vlan_accept
Definition options.h:711
bool vlan_tagging
Definition options.h:710
uint16_t vlan_pvid
Definition options.h:712
int16_t vlan_decapsulate(const struct context *c, struct buffer *buf)
Definition vlan.c:82
void vlan_process_outgoing_tun(struct multi_context *m, struct multi_instance *mi)
Definition vlan.c:296
static void vlanhdr_set_vid(struct openvpn_8021qhdr *hdr, const uint16_t vid)
Definition vlan.c:54
static uint16_t vlanhdr_get_vid(const struct openvpn_8021qhdr *hdr)
Definition vlan.c:42
void vlan_encapsulate(const struct context *c, struct buffer *buf)
Definition vlan.c:186
bool vlan_is_tagged(const struct buffer *buf)
Definition vlan.c:266