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
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 {
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 */
101  {
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 */
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  {
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  */
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  */
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? */
226  {
227  goto drop;
228  }
229 
230  vlanhdr = (struct openvpn_8021qhdr *)buf_prepend(buf,
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
299 {
300  if (!m->top.options.vlan_tagging)
301  {
302  return;
303  }
304 
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  */
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 
322  {
323  /* Packets need to be VLAN-tagged, because the packet's VID does not
324  * match the port's PVID. */
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. */
332  }
333 }
struct options options
Options loaded from command line or configuration file.
Definition: openvpn.h:505
uint16_t proto
Definition: proto.h:77
static bool buf_advance(struct buffer *buf, int size)
Definition: buffer.h:639
Contains all state information for one tunnel.
Definition: openvpn.h:503
#define OPENVPN_ETH_P_8021Q
Definition: proto.h:63
void vlan_encapsulate(const struct context *c, struct buffer *buf)
Definition: vlan.c:188
uint16_t proto
Definition: proto.h:64
void vlan_process_outgoing_tun(struct multi_context *m, struct multi_instance *mi)
Definition: vlan.c:298
static int buf_reverse_capacity(const struct buffer *buf)
Definition: buffer.h:598
int len
Length in bytes of the actual content within the allocated memory.
Definition: buffer.h:66
bool vlan_is_tagged(const struct buffer *buf)
Definition: vlan.c:268
#define BPTR(buf)
Definition: buffer.h:124
static uint8_t * buf_prepend(struct buffer *buf, int size)
Definition: buffer.h:627
uint16_t vlan_pvid
Definition: options.h:644
struct context context
The context structure storing state for this VPN tunnel.
Definition: multi.h:133
bool vlan_tagging
Definition: options.h:642
uint16_t pcp_cfi_vid
Definition: proto.h:76
#define msg
Definition: error.h:173
struct context_2 c2
Level 2 context.
Definition: openvpn.h:544
uint16_t tpid
Definition: proto.h:72
static uint16_t vlanhdr_get_vid(const struct openvpn_8021qhdr *hdr)
Definition: vlan.c:44
#define BLEN(buf)
Definition: buffer.h:127
enum vlan_acceptable_frames vlan_accept
Definition: options.h:643
#define D_VLAN_DEBUG
Definition: errlevel.h:152
Main OpenVPN server state structure.
Definition: multi.h:152
int16_t vlan_decapsulate(const struct context *c, struct buffer *buf)
Definition: vlan.c:84
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
struct context top
Storage structure for process-wide configuration.
Definition: multi.h:199
unsigned __int16 uint16_t
Definition: config-msvc.h:158
Server-mode state structure for one single VPN tunnel.
Definition: multi.h:100
struct buffer to_tun
Definition: openvpn.h:398
#define SIZE_ETH_TO_8021Q_HDR
Definition: proto.h:84
static void vlanhdr_set_vid(struct openvpn_8021qhdr *hdr, const uint16_t vid)
Definition: vlan.c:56
__int16 int16_t
Definition: config-msvc.h:162
#define OPENVPN_8021Q_MASK_VID
Definition: proto.h:75