syshead.h \
tls_crypt.c tls_crypt.h \
tun.c tun.h \
+ vlan.c vlan.h \
win32.h win32.c \
cryptoapi.h cryptoapi.c
openvpn_LDADD = \
#define D_PF_DEBUG LOGLEV(7, 72, M_DEBUG) /* packet filter debugging, must also define PF_DEBUG in pf.h */
#define D_PUSH_DEBUG LOGLEV(7, 73, M_DEBUG) /* show push/pull debugging info */
+#define D_VLAN_DEBUG LOGLEV(7, 74, M_DEBUG) /* show VLAN tagging/untagging debug info */
+
#define D_HANDSHAKE_VERBOSE LOGLEV(8, 70, M_DEBUG) /* show detailed description of each handshake */
#define D_TLS_DEBUG_MED LOGLEV(8, 70, M_DEBUG) /* limited info from tls_session routines */
#define D_INTERVAL LOGLEV(8, 70, M_DEBUG) /* show interval.h debugging info */
#include "gremlin.h"
#include "mstats.h"
#include "ssl_verify.h"
+#include "vlan.h"
#include <inttypes.h>
#include "memdbg.h"
multi_bcast(struct multi_context *m,
const struct buffer *buf,
const struct multi_instance *sender_instance,
- const struct mroute_addr *sender_addr)
+ const struct mroute_addr *sender_addr,
+ uint16_t vid)
{
struct hash_iterator hi;
struct hash_element *he;
}
}
#endif /* ifdef ENABLE_PF */
+ if (vid != 0 && vid != mi->context.options.vlan_pvid)
+ {
+ continue;
+ }
multi_add_mbuf(m, mi, mb);
}
}
if (mroute_flags & MROUTE_EXTRACT_MCAST)
{
/* for now, treat multicast as broadcast */
- multi_bcast(m, &c->c2.to_tun, m->pending, NULL);
+ multi_bcast(m, &c->c2.to_tun, m->pending, NULL, 0);
}
else /* possible client to client routing */
{
struct mroute_addr edest;
mroute_addr_reset(&edest);
#endif
+ if (m->top.options.vlan_tagging)
+ {
+ if (vlan_is_tagged(&c->c2.to_tun))
+ {
+ /* Drop VLAN-tagged frame. */
+ msg(D_VLAN_DEBUG, "dropping incoming VLAN-tagged frame");
+ c->c2.to_tun.len = 0;
+ }
+ }
/* extract packet source and dest addresses */
mroute_flags = mroute_extract_addr_from_packet(&src,
&dest,
{
if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST))
{
- multi_bcast(m, &c->c2.to_tun, m->pending, NULL);
+ multi_bcast(m, &c->c2.to_tun, m->pending, NULL, 0);
}
else /* try client-to-client routing */
{
{
/* for now, treat multicast as broadcast */
#ifdef ENABLE_PF
- multi_bcast(m, &m->top.c2.buf, NULL, e2);
+ multi_bcast(m, &m->top.c2.buf, NULL, e2, 0);
#else
- multi_bcast(m, &m->top.c2.buf, NULL, NULL);
+ multi_bcast(m, &m->top.c2.buf, NULL, NULL, 0);
#endif
}
else
for (i = 0; i < parm.n_packets; ++i)
{
- multi_bcast(m, &buf, NULL, NULL);
+ multi_bcast(m, &buf, NULL, NULL, 0);
}
gc_free(&gc);
#include "mudp.h"
#include "mtcp.h"
#include "perf.h"
+#include "vlan.h"
#define MULTI_PREFIX_MAX_LENGTH 256
mi->context.c2.to_tun.len);
#endif
set_prefix(mi);
+ vlan_process_outgoing_tun(m, mi);
process_outgoing_tun(&mi->context);
ret = multi_process_post(m, mi, mpp_flags);
clear_prefix();
#include "win32.h"
#include "push.h"
#include "pool.h"
+#include "proto.h"
#include "helper.h"
#include "manage.h"
#include "forward.h"
"--plugin m [str]: Load plug-in module m passing str as an argument\n"
" to its initialization function.\n"
#endif
+ "--vlan-tagging : Enable 802.1Q-based VLAN tagging.\n"
+ "--vlan-pvid v : Sets the Port VLAN Identifier. Defaults to 1.\n"
#if P2MP
#if P2MP_SERVER
"\n"
o->route_method = ROUTE_METHOD_ADAPTIVE;
o->block_outside_dns = false;
#endif
+ o->vlan_accept = VLAN_ONLY_UNTAGGED_OR_PRIORITY;
+ o->vlan_pvid = 1;
#if P2MP_SERVER
o->real_hash_size = 256;
o->virtual_hash_size = 256;
#endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */
+static const char *
+print_vlan_accept(enum vlan_acceptable_frames mode)
+{
+ switch (mode)
+ {
+ case VLAN_ONLY_UNTAGGED_OR_PRIORITY:
+ return "untagged";
+ }
+ return NULL;
+}
+
#if P2MP
#ifndef ENABLE_SMALL
SHOW_STR(port_share_host);
SHOW_STR(port_share_port);
#endif
+ SHOW_BOOL(vlan_tagging);
+ msg(D_SHOW_PARMS, " vlan_accept = %s", print_vlan_accept (o->vlan_accept));
+ SHOW_INT(vlan_pvid);
#endif /* P2MP_SERVER */
SHOW_BOOL(client);
msg(M_USAGE, "--auth-user-pass-optional %s", postfix);
}
}
+
+ if (options->vlan_tagging && dev != DEV_TYPE_TAP)
+ {
+ msg(M_USAGE, "--vlan-tagging must be used with --dev tap");
+ }
+ if (!options->vlan_tagging)
+ {
+ if (options->vlan_pvid != defaults.vlan_pvid)
+ {
+ msg(M_USAGE, "--vlan-pvid requires --vlan-tagging");
+ }
+ }
}
else
{
{
msg(M_USAGE, "--stale-routes-check requires --mode server");
}
+
+ if (options->vlan_tagging)
+ {
+ msg(M_USAGE, "--vlan-tagging requires --mode server");
+ }
}
#endif /* P2MP_SERVER */
VERIFY_PERMISSION(OPT_P_GENERAL);
options->allow_recursive_routing = true;
}
+ else if (streq(p[0], "vlan-tagging") && !p[1])
+ {
+ VERIFY_PERMISSION(OPT_P_GENERAL);
+ options->vlan_tagging = true;
+ }
+ else if (streq(p[0], "vlan-pvid") && p[1] && !p[2])
+ {
+ VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_INSTANCE);
+ options->vlan_pvid = positive_atoi(p[1]);
+ if (options->vlan_pvid < OPENVPN_8021Q_MIN_VID
+ || options->vlan_pvid > OPENVPN_8021Q_MAX_VID)
+ {
+ msg(msglevel,
+ "the parameter of --vlan-pvid parameters must be >= %u and <= %u",
+ OPENVPN_8021Q_MIN_VID, OPENVPN_8021Q_MAX_VID);
+ goto err;
+ }
+ }
else
{
int i;
struct remote_entry *array[CONNECTION_LIST_SIZE];
};
+enum vlan_acceptable_frames
+{
+ VLAN_ONLY_UNTAGGED_OR_PRIORITY,
+};
+
struct remote_host_store
{
#define RH_HOST_LEN 80
int keying_material_exporter_length;
#endif
+ bool vlan_tagging;
+ enum vlan_acceptable_frames vlan_accept;
+ uint16_t vlan_pvid;
+
struct pull_filter_list *pull_filter_list;
/* Useful when packets sent by openvpn itself are not subject
#define OPENVPN_ETH_P_IPV4 0x0800 /* IPv4 protocol */
#define OPENVPN_ETH_P_IPV6 0x86DD /* IPv6 protocol */
#define OPENVPN_ETH_P_ARP 0x0806 /* ARP protocol */
+#define OPENVPN_ETH_P_8021Q 0x8100 /* 802.1Q protocol */
uint16_t proto; /* packet type ID field */
};
+struct openvpn_8021qhdr
+{
+ uint8_t dest[OPENVPN_ETH_ALEN]; /* destination ethernet addr */
+ uint8_t source[OPENVPN_ETH_ALEN]; /* source ethernet addr */
+
+ uint16_t tpid; /* 802.1Q Tag Protocol Identifier */
+#define OPENVPN_8021Q_MASK_PCP htons(0xE000) /* mask PCP out of pcp_cfi_vid */
+#define OPENVPN_8021Q_MASK_CFI htons(0x1000) /* mask CFI out of pcp_cfi_vid */
+#define OPENVPN_8021Q_MASK_VID htons(0x0FFF) /* mask VID out of pcp_cfi_vid */
+ uint16_t pcp_cfi_vid; /* bit fields, see IEEE 802.1Q */
+ uint16_t proto; /* contained packet type ID field */
+};
+
+/*
+ * Size difference between a regular Ethernet II header and an Ethernet II
+ * header with additional IEEE 802.1Q tagging.
+ */
+#define SIZE_ETH_TO_8021Q_HDR (sizeof(struct openvpn_8021qhdr) \
+ - sizeof(struct openvpn_ethhdr))
+
+
struct openvpn_arp {
#define ARP_MAC_ADDR_TYPE 0x0001
uint16_t mac_addr_type; /* 0x0001 */
#endif
+#define OPENVPN_8021Q_MIN_VID 1
+#define OPENVPN_8021Q_MAX_VID 4094
+
#endif /* ifndef PROTO_H */
--- /dev/null
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2019 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2010 Fabian Knittel <fabian.knittel@lettink.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if P2MP_SERVER
+
+#include "multi.h"
+#include "options.h"
+#include "vlan.h"
+
+/*
+ * Retrieve the VLAN Identifier (VID) from the IEEE 802.1Q header.
+ *
+ * @param hdr Pointer to the Ethernet header with IEEE 802.1Q tagging.
+ * @return Returns the VID in host byte order.
+ */
+static uint16_t
+vlanhdr_get_vid(const struct openvpn_8021qhdr *hdr)
+{
+ return ntohs(hdr->pcp_cfi_vid & OPENVPN_8021Q_MASK_VID);
+}
+
+/*
+ * vlan_is_tagged - check if a packet is VLAN-tagged
+ *
+ * Checks whether ethernet frame is VLAN-tagged.
+ *
+ * @param buf The ethernet frame.
+ * @return Returns true if the frame is VLAN-tagged, false otherwise.
+ */
+bool
+vlan_is_tagged(const struct buffer *buf)
+{
+ const struct openvpn_8021qhdr *vlanhdr;
+ uint16_t vid;
+
+ if (BLEN(buf) < sizeof(struct openvpn_8021qhdr))
+ {
+ /* frame too small to be VLAN-tagged */
+ return false;
+ }
+
+ vlanhdr = (const struct openvpn_8021qhdr *)BPTR(buf);
+
+ if (ntohs(vlanhdr->tpid) != OPENVPN_ETH_P_8021Q)
+ {
+ /* non tagged frame */
+ return false;
+ }
+
+ vid = vlanhdr_get_vid(vlanhdr);
+ if (vid == 0)
+ {
+ /* no vid: piority tagged only */
+ return false;
+ }
+
+ return true;
+}
+
+void
+vlan_process_outgoing_tun(struct multi_context *m, struct multi_instance *mi)
+{
+ if (!m->top.options.vlan_tagging)
+ {
+ return;
+ }
+
+ if (m->top.options.vlan_accept == VLAN_ONLY_UNTAGGED_OR_PRIORITY)
+ {
+ /* Packets forwarded to the TAP devices aren't VLAN-tagged. Only packets
+ * matching the PVID configured globally are allowed to be received
+ */
+ if (m->top.options.vlan_pvid != mi->context.options.vlan_pvid)
+ {
+ /* Packet is coming from the wrong VID, drop it. */
+ mi->context.c2.to_tun.len = 0;
+ }
+ }
+}
+
+#endif /* P2MP_SERVER */
--- /dev/null
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single TCP/UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2019 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2010 Fabian Knittel <fabian.knittel@lettink.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef VLAN_H
+#define VLAN_H
+
+#if P2MP_SERVER
+
+#include "buffer.h"
+#include "mroute.h"
+
+struct multi_context;
+struct multi_instance;
+
+bool
+vlan_is_tagged(const struct buffer *buf);
+
+void
+vlan_process_outgoing_tun(struct multi_context *m, struct multi_instance *mi);
+
+#endif /* P2MP_SERVER */
+
+#endif /* VLAN_H */