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