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-2022 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
vlanhdr_get_vid(const struct openvpn_8021qhdr * hdr)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
vlanhdr_set_vid(struct openvpn_8021qhdr * hdr,const uint16_t vid)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
vlan_decapsulate(const struct context * c,struct buffer * buf)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
vlan_encapsulate(const struct context * c,struct buffer * buf)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
vlan_is_tagged(const struct buffer * buf)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
vlan_process_outgoing_tun(struct multi_context * m,struct multi_instance * mi)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 }
334