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-2023 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
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 {
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 */
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 
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? */
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 
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
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  }
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. */
330  }
331 }
options::vlan_tagging
bool vlan_tagging
Definition: options.h:694
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:636
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:696
buf_prepend
static uint8_t * buf_prepend(struct buffer *buf, int size)
Definition: buffer.h:624
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:695
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:150
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:595