[Openvpn-devel] [PATCH 3/7] vlan: Add global, per-client 802.1q-based options

2016-04-03 Thread Mike Auty
This patch add the new global "--vlan-tagging" boolean switch.  This specifies
whether openvpn should handle 802.1q tagged packets in any way.

This patch also adds the new global '--vlan-accept tagged|untagged|all' which
specifies the behaviour of the tap device with regards to 802.1q vlan tagged
packets.

This patch also adds the new "--vlan-pvid" integer option.  The option is valid
in server mode and can be set in a client context (e.g. from the client-connect
hook).  It defaults to 1.

 The value indicates which VID (VLAN identifier) to associate with a client
 or (in global context) with the tap device.
 It also serves as the Port VLAN Identifier, i.e. the VID to use for incoming
 and outgoing untagged or priority-tagged frames.

 The client will only receive packets which belong to the same VLAN.

These options have no immediate effect yet, but will be used by later patches.

Patch authored by Fabian Knittel .

Signed-off-by: Fabian Knittel 
---
 src/openvpn/options.c | 85 +++
 1 file changed, 85 insertions(+)

diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 02def3a..7616f23 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -477,6 +477,11 @@ static const char usage_message[] =
   "  sessions to a web server at host:port.  dir specifies 
an\n"
   "  optional directory to write origin IP:port data.\n"
 #endif
+#ifdef ENABLE_VLAN_TAGGING
+  "--vlan-tagging  : Enable 802.1Q-based VLAN tagging.\n"
+  "--vlan-accept tagged|untagged|all : Set VLAN tagging mode. Default is 
'all'.\n"
+  "--vlan-pvid v   : Sets the Port VLAN Identifier. Defaults to 1.\n"
+#endif
 #endif
   "\n"
   "Client options (when connecting to a multi-client server):\n"
@@ -852,6 +857,10 @@ init_options (struct options *o, const bool init_gc)
 #ifdef ENABLE_PKCS11
   o->pkcs11_pin_cache_period = -1;
 #endif /* ENABLE_PKCS11 */
+#ifdef ENABLE_VLAN_TAGGING
+  o->vlan_accept = VAF_ALL;
+  o->vlan_pvid = 1;
+#endif

 /* tmp is only used in P2MP server context */
 #if P2MP_SERVER
@@ -1160,6 +1169,23 @@ dhcp_option_address_parse (const char *name, const char 
*parm, in_addr_t *array,

 #endif

+#ifdef ENABLE_VLAN_TAGGING
+static const char *
+print_vlan_accept (enum vlan_acceptable_frames mode)
+{
+  switch (mode)
+   {
+case VAF_ONLY_VLAN_TAGGED:
+  return "tagged";
+case VAF_ONLY_UNTAGGED_OR_PRIORITY:
+  return "untagged";
+case VAF_ALL:
+  return "all";
+   }
+  return NULL;
+}
+#endif
+
 #if P2MP

 #ifndef ENABLE_SMALL
@@ -1225,6 +1251,11 @@ show_p2mp_parms (const struct options *o)
   SHOW_STR (port_share_host);
   SHOW_STR (port_share_port);
 #endif
+#ifdef ENABLE_VLAN_TAGGING
+  SHOW_BOOL (vlan_tagging);
+  msg (D_SHOW_PARMS, "  vlan_accept = %s", print_vlan_accept (o->vlan_accept));
+  SHOW_INT (vlan_pvid);
+#endif
 #endif /* P2MP_SERVER */

   SHOW_BOOL (client);
@@ -2076,6 +2107,17 @@ options_postprocess_verify_ce (const struct options 
*options, const struct conne
  if ((options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) && !ccnr)
msg (M_USAGE, "--auth-user-pass-optional %s", postfix);
}
+#ifdef ENABLE_VLAN_TAGGING
+  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_accept != defaults.vlan_accept)
+   msg (M_USAGE, "--vlan-accept requires --vlan-tagging");
+ if (options->vlan_pvid != defaults.vlan_pvid)
+   msg (M_USAGE, "--vlan-pvid requires --vlan-tagging");
+   }
+#endif
 }
   else
 {
@@ -2122,6 +2164,10 @@ options_postprocess_verify_ce (const struct options 
*options, const struct conne
   if (options->port_share_host || options->port_share_port)
msg (M_USAGE, "--port-share requires TCP server mode (--mode server 
--proto tcp-server)");
 #endif
+#ifdef ENABLE_VLAN_TAGGING
+  if (options->vlan_tagging)
+   msg (M_USAGE, "--vlan-tagging requires --mode server");
+#endif

   if (options->stale_routes_check_interval)
 msg (M_USAGE, "--stale-routes-check requires --mode server");
@@ -7178,6 +7224,45 @@ add_option (struct options *options,
   options->keying_material_exporter_length = ekm_length;
 }
 #endif
+#ifdef ENABLE_VLAN_TAGGING
+  else if (streq (p[0], "vlan-tagging"))
+{
+  VERIFY_PERMISSION (OPT_P_GENERAL);
+  options->vlan_tagging = true;
+}
+  else if (streq (p[0], "vlan-accept") && p[1])
+{
+  VERIFY_PERMISSION (OPT_P_GENERAL);
+  if (streq (p[1], "tagged"))
+   {
+ options->vlan_accept = VAF_ONLY_VLAN_TAGGED;
+   }
+  else if (streq (p[1], "untagged"))
+   {
+ options->vlan_accept = VAF_ONLY_UNTAGGED_OR_PRIORITY;
+   }
+  else if (streq (p[1], "all"))
+   {
+ options->vlan_accept = VAF_ALL;
+   }
+  else
+   {
+ msg (msglevel

[Openvpn-devel] [PATCH 2/7] vlan: Add various definitions and 802.1Q structure

2016-04-03 Thread Mike Auty
This patch provides all the #DEFINES necessary for the 802.1q.

sf.net tracker:


Discussed on the IRC meeting March 4, 2010 in #openvpn-discussions.


This includes an additional length check that was not in the original
patch:

Currently is_ipv4() only checks whether the frame is large enough for
struct openvpn_ethhdr. In case of an 802.1Q packet the function now
also checks whether the frame is large enough for struct openvpn_8021qhdr,
which is 4 bytes larger than struct openvpn_ethhdr.

Patch authored by David Sommerseth  and 
Fabian Knittel .

Co-authored-by: David Sommerseth 
Signed-off-by: Fabian Knittel 
---
 src/openvpn/errlevel.h |  2 ++
 src/openvpn/options.h  | 15 +++
 src/openvpn/proto.c| 19 ---
 src/openvpn/proto.h| 26 ++
 4 files changed, 59 insertions(+), 3 deletions(-)

diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h
index da600ab..191c763 100644
--- a/src/openvpn/errlevel.h
+++ b/src/openvpn/errlevel.h
@@ -148,6 +148,8 @@
 #define D_PF_DROPPED_BCAST   LOGLEV(7, 71, M_DEBUG)  /* packet filter dropped 
a broadcast packet */
 #define D_PF_DEBUG   LOGLEV(7, 72, M_DEBUG)  /* packet filter 
debugging, must also define PF_DEBUG in pf.h */

+#define D_VLAN_DEBUG LOGLEV(7, 72, 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 */
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index 23d3992..72ee702 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -155,6 +155,15 @@ struct remote_list
   struct remote_entry *array[CONNECTION_LIST_SIZE];
 };

+#ifdef ENABLE_VLAN_TAGGING
+enum vlan_acceptable_frames
+{
+  VAF_ONLY_VLAN_TAGGED,
+  VAF_ONLY_UNTAGGED_OR_PRIORITY,
+  VAF_ALL,
+};
+#endif
+
 struct remote_host_store
 {
 # define RH_HOST_LEN 80
@@ -597,6 +606,12 @@ struct options
   const char *keying_material_exporter_label;
   int keying_material_exporter_length;
 #endif
+
+#ifdef ENABLE_VLAN_TAGGING
+  bool vlan_tagging;
+  enum vlan_acceptable_frames vlan_accept;
+  uint16_t vlan_pvid;
+#endif
 };

 #define streq(x, y) (!strcmp((x), (y)))
diff --git a/src/openvpn/proto.c b/src/openvpn/proto.c
index 7b58e6a..2921a6e 100644
--- a/src/openvpn/proto.c
+++ b/src/openvpn/proto.c
@@ -60,9 +60,22 @@ is_ipv_X ( int tunnel_type, struct buffer *buf, int ip_ver )
  + sizeof (struct openvpn_iphdr)))
return false;
   eh = (const struct openvpn_ethhdr *) BPTR (buf);
-  if (ntohs (eh->proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : 
OPENVPN_ETH_P_IPV4))
-   return false;
-  offset = sizeof (struct openvpn_ethhdr);
+  if (ntohs (eh->proto) == OPENVPN_ETH_P_8021Q) {
+const struct openvpn_8021qhdr *evh;
+if (BLEN (buf) < (int)(sizeof (struct openvpn_8021qhdr)
+   + sizeof (struct openvpn_iphdr)))
+ return false;
+evh = (const struct openvpn_8021qhdr *) BPTR (buf);
+if (ntohs (evh->proto) !=
+   (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4))
+  return false;
+else
+  offset = sizeof (struct openvpn_8021qhdr);
+  } else if (ntohs (eh->proto) !=
+ (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4))
+return false;
+  else
+offset = sizeof (struct openvpn_ethhdr);
 }
   else
 return false;
diff --git a/src/openvpn/proto.h b/src/openvpn/proto.h
index f91e787..428d10f 100644
--- a/src/openvpn/proto.h
+++ b/src/openvpn/proto.h
@@ -61,9 +61,29 @@ struct openvpn_ethhdr
 # define OPENVPN_ETH_P_IPV4   0x0800  /* IPv4 protocol */
 # define OPENVPN_ETH_P_IPV6   0x86DD  /* IPv6 protocol */
 # define OPENVPN_ETH_P_ARP0x0806  /* 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_VID htons (0x0FFF) /* mask VID out of pcp_cfi_vid 
*/
+# 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 
*/
+  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 IE

[Openvpn-devel] [PATCH 7/7] vlan: document the --vlan-* flags in openvpn.8 man page

2016-04-03 Thread Mike Auty
Documents the --vlan-tagging, --vlan-accept and --vlan-pvid tags
in the openvpn man page.

Patch authored by Fabian Knittel .

Co-authored-by: Mike Auty 
Signed-off-by: Fabian Knittel 
---
 doc/openvpn.8 | 104 ++
 1 file changed, 104 insertions(+)

diff --git a/doc/openvpn.8 b/doc/openvpn.8
index 628d877..a5ac3a8 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -3290,6 +3290,7 @@ without needing to restart the server.
 The following
 options are legal in a client-specific context:
 .B \-\-push, \-\-push\-reset, \-\-iroute, \-\-ifconfig\-push,
+.B \-\-vlan\-pvid
 and
 .B \-\-config.
 .\"*
@@ -3753,6 +3754,109 @@ connection is torn down.

 Not implemented on Windows.
 .\"*
+.TP
+.B \-\-vlan\-tagging
+Turns the OpenVPN server instance into a switch that understands VLAN-tagging,
+based on IEEE 802.1Q.
+
+The tap device and each of the connecting clients is seen as a port of the
+switch. All client ports are in untagged mode and the tap device is
+VLAN-tagged, untagged or accepts both, depending on the
+.B \-\-vlan\-accept
+setting.
+
+Ethernet frames with a prepended 802.1Q tag are called "tagged". If the VLAN
+Identifier (VID) field in such a tag is non-zero, the frame is called
+"VLAN-tagged". If the VID is zero, but the Priority Control Point (PCP) field
+is non-zero, the frame is called "prio-tagged". If there is no 802.1Q tag, the
+frame is "untagged".
+
+Using the
+.B \-\-vlan\-pvid v
+option once per client, each port can be associated with a certain VID. Packets
+can only be distributed between ports with a matching VID. Therefore, clients
+with differing VIDs are completely separated from one-another, even if
+.B \-\-client-to-client
+is activated.
+
+The filtering of packets takes place in the OpenVPN server. Clients do not
+need support for VLAN tagging.
+
+The
+.B \-\-vlan\-tagging
+option is off by default. While turned off, OpenVPN
+does no parsing and accepts any Ethernet frames.
+
+The option can only be activated in
+.B \-\-dev tap
+mode.
+
+.\"*
+.TP
+.B \-\-vlan\-accept all | tagged | untagged
+Allows the tap device's VLAN tagging policy to be configured. You can choose
+between the following modes:
+
+.B all
+(default) -- Admit all frames.
+.br
+.B tagged
+-- Admit only VLAN-tagged frames.
+.br
+.B untagged
+-- Admit only untagged and priority-tagged frames.
+
+(Note: Some vendors refer to switch ports running in
+.B tagged
+mode as "trunk ports" and switch ports running in
+.B untagged
+mode as "access ports".)
+
+Incoming untagged or priority-tagged packets from clients are assigned with the
+client's Port VLAN Identifier (PVID) as their VID. In
+.B untagged
+mode, incoming untagged or priority-tagged packets on the tap device are
+associated with the global
+.B \-\-vlan\-pvid
+setting. In
+.B tagged
+mode, any incoming untagged or priority-tagged packets are dropped. For
+VLAN-tagged packets, any priority information is lost as soon as the
+VLAN-tagging is removed.
+
+In
+.B tagged
+mode, packets going out through the tap device are VLAN-tagged with the
+originating client's VID.
+
+In
+.B all
+mode, incoming tagged packets are handled the same way as in
+.B tagged
+mode. Incoming untagged packets are handled as in
+.B untagged
+mode. Outgoing packets are tagged, unless the VID matches the global PVID, in
+which case the packets go out untagged.
+.\"*
+.TP
+.B \-\-vlan\-pvid v
+Specifies which VLAN identifier a "port" is associated with. Not valid without
+\fB\-\-vlan\-tagging\fR.
+
+In client context, the setting specifies which VLAN identifier a client is
+associated with. In global context, the tap device's VLAN identifier is set.
+The latter only makes sense in
+.B \-\-vlan\-accept untagged
+and
+.B \-\-vlan\-accept all
+mode.
+
+Valid values for
+.B v
+go from 1 through to 4094. Defaults to 1.
+
+In some switch implementations, the PVID is also referred to as "Native VLAN".
+.\"*
 .SS Client Mode
 Use client mode when connecting to an OpenVPN server
 which has
-- 
2.7.1



[Openvpn-devel] [PATCH 1/7] vlan: add compile-time option ENABLE_VLAN_TAGGING

2016-04-03 Thread Mike Auty
The option can be disabled via "./configure --disable-vlan-tagging".

Patch authored by Fabian Knittel .

Signed-off-by: Fabian Knittel 
---
 configure.ac | 10 ++
 1 file changed, 10 insertions(+)

diff --git a/configure.ac b/configure.ac
index b75d51f..89556c4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -271,6 +271,12 @@ AC_ARG_ENABLE(
[enable_async_push="no"]
 )

+AC_ARG_ENABLE(vlan-tagging,
+   [  --disable-vlan-tagging  Disable support for 802.1Q-based VLAN 
tagging],
+   [VLAN_TAGGING="$enableval"],
+   [VLAN_TAGGING="yes"]
+)
+
 AC_ARG_WITH(
[special-build],
[AS_HELP_STRING([--with-special-build=STRING], [specify special build 
string])],
@@ -1163,6 +1169,10 @@ if test "${enable_async_push}" = "yes"; then
)
 fi

+if test "$VLAN_TAGGING" = "yes"; then
+   AC_DEFINE(ENABLE_VLAN_TAGGING, 1, [Enable 802.1Q-based VLAN 
tagging/untagging])
+fi
+
 CONFIGURE_DEFINES="`set | grep '^enable_.*=' ; set | grep '^with_.*='`"
 AC_DEFINE_UNQUOTED([CONFIGURE_DEFINES], ["`echo ${CONFIGURE_DEFINES}`"], 
[Configuration settings])

-- 
2.7.1



[Openvpn-devel] [PATCH 4/7] vlan: Add in functions for working with 802.1q vlan, headers.

2016-04-03 Thread Mike Auty
This patch adds in functions for extracting data from the 802.1q header.

The vlan_hdr_* functions now expect and return the values in host byte
order.  The callee doesn't need to perform any kind of conversion.

These functions are not used yet, but will be used in future patches.

Patch authored by Fabian Knittel .

Signed-off-by: Fabian Knittel 
---
 src/openvpn/proto.h | 70 +
 1 file changed, 70 insertions(+)

diff --git a/src/openvpn/proto.h b/src/openvpn/proto.h
index 428d10f..b24fd28 100644
--- a/src/openvpn/proto.h
+++ b/src/openvpn/proto.h
@@ -258,6 +258,76 @@ void ipv4_packet_size_verify (const uint8_t *data,
 # define OPENVPN_8021Q_MIN_VID 1
 # define OPENVPN_8021Q_MAX_VID 4094

+/*
+ * Retrieve the Priority Code Point (PCP) from the IEEE 802.1Q header.
+ *
+ * @param hdr Pointer to the Ethernet header with IEEE 802.1Q tagging.
+ * @returnReturns the PCP in host byte order.
+ */
+static inline uint16_t
+vlanhdr_get_pcp (const struct openvpn_8021qhdr *hdr)
+{
+  return ntohs (hdr->pcp_cfi_vid & OPENVPN_8021Q_MASK_PCP);
+}
+/*
+ * Retrieve the Canonical Format Indicator (CFI) from the IEEE 802.1Q header.
+ *
+ * @param hdr Pointer to the Ethernet header with IEEE 802.1Q tagging.
+ * @returnReturns the CFI in host byte order.
+ */
+static inline uint16_t
+vlanhdr_get_cfi (const struct openvpn_8021qhdr *hdr)
+{
+  return ntohs (hdr->pcp_cfi_vid & OPENVPN_8021Q_MASK_CFI);
+}
+/*
+ * Retrieve the VLAN Identifier (VID) from the IEEE 802.1Q header.
+ *
+ * @param hdr Pointer to the Ethernet header with IEEE 802.1Q tagging.
+ * @returnReturns the VID in host byte order.
+ */
+static inline uint16_t
+vlanhdr_get_vid (const struct openvpn_8021qhdr *hdr)
+{
+  return ntohs (hdr->pcp_cfi_vid & OPENVPN_8021Q_MASK_VID);
+}
+
+/*
+ * Set the Priority Code Point (PCP) in an IEEE 802.1Q header.
+ *
+ * @param hdr Pointer to the Ethernet header with IEEE 802.1Q tagging.
+ * @param pcp The PCP to set (in host byte order).
+ */
+static inline void
+vlanhdr_set_pcp (struct openvpn_8021qhdr *hdr, const uint16_t pcp)
+{
+  hdr->pcp_cfi_vid = (hdr->pcp_cfi_vid & ~OPENVPN_8021Q_MASK_PCP) |
+(htons (pcp) & OPENVPN_8021Q_MASK_PCP);
+}
+/*
+ * Set the Canonical Format Indicator (CFI) in an IEEE 802.1Q header.
+ *
+ * @param hdr Pointer to the Ethernet header with IEEE 802.1Q tagging.
+ * @param cfi The CFI to set (in host byte order).
+ */
+static inline void
+vlanhdr_set_cfi (struct openvpn_8021qhdr *hdr, const uint16_t cfi)
+{
+  hdr->pcp_cfi_vid = (hdr->pcp_cfi_vid & ~OPENVPN_8021Q_MASK_CFI) |
+(htons (cfi) & OPENVPN_8021Q_MASK_CFI);
+}
+/*
+ * Set the VLAN Identifier (VID) in an IEEE 802.1Q header.
+ *
+ * @param hdr Pointer to the Ethernet header with IEEE 802.1Q tagging.
+ * @param vid The VID to set (in host byte order).
+ */
+static inline void
+vlanhdr_set_vid (struct openvpn_8021qhdr *hdr, const uint16_t vid)
+{
+  hdr->pcp_cfi_vid = (hdr->pcp_cfi_vid & ~OPENVPN_8021Q_MASK_VID) |
+(htons (vid) & OPENVPN_8021Q_MASK_VID);
+}
 #endif

 #endif
-- 
2.7.1



[Openvpn-devel] [PATCH 0/7] Vlan support for openvpn

2016-04-03 Thread Mike Auty
Hi there,

This is the start of a 7-patch set to add vlan support to openvpn, as
authored by Fabian Knittel.

This a squashed patchset (originally numbering 21 patches, but now
reduced to 7).  These were originally written up to four years ago, and
have been maintained (at sparse intervals) by the original author.  He's
made use of them in production at a large university for the past four
years, and I'm keen to implement them in a medium sized international
organization.

These were slated for inclusion in openvpn four years ago but were never
fully reviewed.  I tried asking for these to be included back in
January, but was told that the patches were too numerous to be reviewed.
 I've therefore squashed the patches down and merged the comments in
order to create this patchset.

I contacted the original author asking if he could do the squashing, but
got no reply for a month.  I then contacted him again with my attempt
asking him if he was happy with the attribution and merging of the
comments and gave him a month to review them and provide a response.
I've still had no reply and am therefore submitting them to the list.

The original author's repository is available at [1].  I'm currently
maintaining the original patchset against the current master at [2], but
I'm relatively new to using git for interacting with large projects, so
didn't add the patches into a branch unfortunately.  The recent
conversations (including previous history) are available at [3].

Please let me know what further I'll need to do in order to help get
these patches included upstream?

Thanks,

Mike  5:)

[1] https://github.com/fknittel/openvpn
[2] https://github.com/ikelos/openvpn
[3] https://sourceforge.net/p/openvpn/mailman/message/34750695/



signature.asc
Description: OpenPGP digital signature


[Openvpn-devel] [PATCH 5/7] vlan: Add the 802.1q vlan id to appropriate calls.

2016-04-03 Thread Mike Auty
This patch ensures that a vlan ID is passed to all necessary function
calls.

These changes are not yet used and the vlan ID is always defined as 0.

This will be used by future patches that will change the vid variable.

Patch authored by Fabian Knittel .

Signed-off-by: Fabian Knittel 
---
 src/openvpn/mroute.c | 42 --
 src/openvpn/mroute.h |  8 +---
 src/openvpn/multi.c  | 32 +++-
 3 files changed, 60 insertions(+), 22 deletions(-)

diff --git a/src/openvpn/mroute.c b/src/openvpn/mroute.c
index 972f1dd..ae84a70 100644
--- a/src/openvpn/mroute.c
+++ b/src/openvpn/mroute.c
@@ -210,12 +210,28 @@ mroute_extract_addr_ipv4 (struct mroute_addr *src,
   return ret;
 }

+static void mroute_copy_ether_to_addr(struct mroute_addr *maddr,
+ const uint8_t *eth_addr,
+ uint16_t vid)
+{
+  maddr->type = MR_ADDR_ETHER;
+  maddr->netbits = 0;
+  memcpy (maddr->addr, eth_addr, 6);
+#ifdef ENABLE_VLAN_TAGGING
+  maddr->len = 8;
+  memcpy (maddr->addr + 6, &vid, 2);
+#else
+  maddr->len = 6;
+#endif
+}
+
 unsigned int
 mroute_extract_addr_ether (struct mroute_addr *src,
   struct mroute_addr *dest,
   struct mroute_addr *esrc,
   struct mroute_addr *edest,
-  const struct buffer *buf)
+  const struct buffer *buf,
+  uint16_t vid)
 {
   unsigned int ret = 0;
   if (BLEN (buf) >= (int) sizeof (struct openvpn_ethhdr))
@@ -223,17 +239,11 @@ mroute_extract_addr_ether (struct mroute_addr *src,
   const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR 
(buf);
   if (src)
{
- src->type = MR_ADDR_ETHER;
- src->netbits = 0;
- src->len = 6;
- memcpy (src->addr, eth->source, 6);
+  mroute_copy_ether_to_addr(src, eth->source, vid);
}
   if (dest)
{
- dest->type = MR_ADDR_ETHER;
- dest->netbits = 0;
- dest->len = 6;
- memcpy (dest->addr, eth->dest, 6);
+  mroute_copy_ether_to_addr(dest, eth->dest, vid);

  /* ethernet broadcast/multicast packet? */
  if (is_mac_mcast_addr (eth->dest))
@@ -248,7 +258,16 @@ mroute_extract_addr_ether (struct mroute_addr *src,
  struct buffer b = *buf;
  if (buf_advance (&b, sizeof (struct openvpn_ethhdr)))
{
- switch (ntohs (eth->proto))
+ uint16_t proto = ntohs (eth->proto);
+ if (proto == OPENVPN_ETH_P_8021Q &&
+ BLEN (buf) >= (int) sizeof (struct openvpn_8021qhdr))
+   {
+ const struct openvpn_8021qhdr *tag = (const struct 
openvpn_8021qhdr *) BPTR (buf);
+ proto = ntohs (tag->proto);
+ buf_advance (&b, SIZE_ETH_TO_8021Q_HDR);
+   }
+
+ switch (proto)
{
case OPENVPN_ETH_P_IPV4:
  ret |= (mroute_extract_addr_ipv4 (esrc, edest, &b) << 
MROUTE_SEC_SHIFT);
@@ -391,6 +410,9 @@ mroute_addr_print_ex (const struct mroute_addr *ma,
{
case MR_ADDR_ETHER:
  buf_printf (&out, "%s", format_hex_ex (ma->addr, 6, 0, 1, ":", gc)); 
+#ifdef ENABLE_VLAN_TAGGING
+ buf_printf (&out, "@%u", *(uint16_t*)(ma->addr + 6));
+#endif
  break;
case MR_ADDR_IPV4:
  {
diff --git a/src/openvpn/mroute.h b/src/openvpn/mroute.h
index 608f70b..175dd2a 100644
--- a/src/openvpn/mroute.h
+++ b/src/openvpn/mroute.h
@@ -138,7 +138,8 @@ mroute_extract_addr_from_packet (struct mroute_addr *src,
 struct mroute_addr *esrc,
 struct mroute_addr *edest,
 const struct buffer *buf,
-int tunnel_type)
+int tunnel_type,
+uint16_t vid)
 {
   unsigned int mroute_extract_addr_ipv4 (struct mroute_addr *src,
 struct mroute_addr *dest,
@@ -148,13 +149,14 @@ mroute_extract_addr_from_packet (struct mroute_addr *src,
  struct mroute_addr *dest,
  struct mroute_addr *esrc,
  struct mroute_addr *edest,
- const struct buffer *buf);
+ const struct buffer *buf,
+ uint16_t vid);
   unsigned int ret = 0;
   verify_align_4 (buf);
   if (tunnel_type == DEV_TYPE_TUN)
 ret = mroute_extract_addr_ipv4 (src, dest, buf);
   else if (tunnel_type == DEV_TYPE_TAP)
-ret = mroute_extract_addr_ether (src, dest, esrc, edest, buf);
+ret = mroute_extract_addr_ether (src, dest, esrc, edest, buf, vid);
   return ret;
 }

diff

[Openvpn-devel] [PATCH 6/7] vlan: Prepend and remove VLAN identifiers on outgoing and, incoming frames

2016-04-03 Thread Mike Auty
This patch adds parsing of the IEEE 802.1Q headers for incoming and outgoing
ethernet frames.

For frames coming in from the tap device, the 802.1Q header is parsed and
translated into a regular Ethernet II header.

For frames where the Priority Code Point (PCP) is non-zero, the 802.1Q tagging
behaviour is to completely drop the tagging.  Some tagging-aware appliances
that set both the VID and PCP fields would cause OpenVPN to forward
prio-tagged frames to clients, which wouldn't understand and therefore
drop them.

The only case where the tagging is kept is when the frame isn't vlan-tagged and
only prio-tagged.  In that case the sender clearly wanted to send a tagged
frame on an otherwise untagged network and we honour that decision by not
fiddling with it.

For frames going out over the tap interface, the Ethernet II header is
replaced with a 802.1Q-based header.  PCP and CFI are permanently set to 0,
unless the frame was a frame tagged only with priority, in which case the 
priority
is copied across.  The VID is set according to the instance's vlan_pvid value
(also see patch adding the "--vlan-pvid" option).

In "--vlan-accept untagged" mode, VLAN-tagged frames coming in from the tap
device are dropped.  Untagged or priority tagged frames are assigned the VID of
the global "--vlan-pvid" setting.  Outgoing frames are sent untagged or
priority-tagged. Outgoing frames are dropped if the VID does not match the
global "--vlan-pvid" setting.

In "--vlan-accept all" mode, VLAN-tagged frames coming in from the tap device
are handled the same way as in the "tagged" mode. Untagged or priority
tagged frames are handled the same was as in "untagged" mode. Outgoing frames
are tagged if they don't match the global tag_pvid value. Otherwise they go
out untagged.

Broadcasts from client to client or from tap interface to clients are now
filtered based on whether the client belongs to the correct VLAN id.

Thanks for suggestions and code snippets to Peter Stuge.

Patch authored by Fabian Knittel .

Signed-off-by: Fabian Knittel 
---
 src/openvpn/multi.c | 216 
 src/openvpn/multi.h |  33 
 2 files changed, 249 insertions(+)

diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 61180f6..09bd947 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -6,6 +6,7 @@
  * packet compression.
  *
  *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. 
+ *  Copyright (C) 2010  Fabian Knittel 
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
@@ -2135,6 +2136,10 @@ multi_bcast (struct multi_context *m,
}
}
 #endif
+#ifdef ENABLE_VLAN_TAGGING
+ if (vid != 0 && vid != mi->context.options.vlan_pvid)
+   continue;
+#endif
  multi_add_mbuf (m, mi, mb);
}
}
@@ -2350,6 +2355,37 @@ done:
 gc_free (&gc);
 }

+#ifdef ENABLE_VLAN_TAGGING
+/*
+ * Decides whether or not to drop an ethernet frame.  VLAN-tagged frames are
+ * dropped.  All other frames are accepted.
+ *
+ * @param buf The ethernet frame.
+ * @returnReturns true if the frame should be dropped, false otherwise.
+ */
+static bool
+buf_filter_incoming_8021q_vlan_tag (const struct buffer *buf)
+{
+  const struct openvpn_8021qhdr *vlanhdr;
+  uint16_t vid;
+
+  if (BLEN (buf) < (int) sizeof (struct openvpn_8021qhdr))
+return false; /* Frame too small.  */
+
+  vlanhdr = (const struct openvpn_8021qhdr *) BPTR (buf);
+
+  if (ntohs (vlanhdr->tpid) != OPENVPN_ETH_P_8021Q)
+return false; /* Frame is untagged.  */
+
+  vid = vlanhdr_get_vid (vlanhdr);
+  if (vid == 0)
+return false; /* Frame only priority-tagged.  */
+
+  msg (D_VLAN_DEBUG, "dropping VLAN-tagged incoming frame, vid: %u", vid);
+  return true;
+}
+#endif
+
 /*
  * Process packets in the TCP/UDP socket -> TUN/TAP interface direction,
  * i.e. client -> server direction.
@@ -2502,6 +2538,18 @@ multi_process_incoming_link (struct multi_context *m, 
struct multi_instance *ins
  struct mroute_addr edest;
  mroute_addr_reset (&edest);
 #endif
+#ifdef ENABLE_VLAN_TAGGING
+ if (m->top.options.vlan_tagging)
+   {
+ if (buf_filter_incoming_8021q_vlan_tag (&c->c2.to_tun))
+   {
+ /* Drop VLAN-tagged frame. */
+ c->c2.to_tun.len = 0;
+   }
+ else
+   vid = c->options.vlan_pvid;
+   }
+#endif
  /* extract packet source and dest addresses */
  mroute_flags = mroute_extract_addr_from_packet (&src,
  &dest,
@@ -2582,6 +2630,165 @@ multi_process_incoming_link (struct multi_context *m, 
struct multi_instance *ins
   return ret;
 }

+#ifdef ENABLE_VLAN_TAGGING
+/*
+ * For vlan_accept == VAF

Re: [Openvpn-devel] [PATCH 3/7] vlan: Add global, per-client 802.1q-based options

2016-04-03 Thread Jonathan K. Bullard
On Sun, Apr 3, 2016 at 2:51 PM, Mike Auty  wrote:
>
> This patch add the new global "--vlan-tagging" boolean switch.  This specifies
> whether openvpn should handle 802.1q tagged packets in any way.
>
> This patch also adds the new global '--vlan-accept tagged|untagged|all' which
> specifies the behaviour of the tap device with regards to 802.1q vlan tagged
> packets.
>
> This patch also adds the new "--vlan-pvid" integer option.




> @@ -7178,6 +7224,45 @@ add_option (struct options *options,
>options->keying_material_exporter_length = ekm_length;
>  }
>  #endif
> +#ifdef ENABLE_VLAN_TAGGING
> +  else if (streq (p[0], "vlan-tagging"))
> +{
> +  VERIFY_PERMISSION (OPT_P_GENERAL);
> +  options->vlan_tagging = true;
> +}
> +  else if (streq (p[0], "vlan-accept") && p[1])
> +{
> +  VERIFY_PERMISSION (OPT_P_GENERAL);
> +  if (streq (p[1], "tagged"))
> +   {
> + options->vlan_accept = VAF_ONLY_VLAN_TAGGED;
> +   }
> +  else if (streq (p[1], "untagged"))
> +   {
> + options->vlan_accept = VAF_ONLY_UNTAGGED_OR_PRIORITY;
> +   }
> +  else if (streq (p[1], "all"))
> +   {
> + options->vlan_accept = VAF_ALL;
> +   }
> +  else
> +   {
> + msg (msglevel, "--vlan-accept must be 'tagged', 'untagged' or 
> 'all'");
> + goto err;
> +   }
> +}
> +  else if (streq (p[0], "vlan-pvid") && p[1])
> +{
> +  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;
> +   }
> +}
> +#endif
>else
>  {
>int i;


NAK. This should include testing for extra parameters supplied in
error with the options, as the rest of the option-handling code does.
Something like the following (for each of the three new options):

+  else if (streq (p[0], "vlan-tagging") && !p[1])



Re: [Openvpn-devel] [PATCH 3/7] vlan: Add global, per-client 802.1q-based options

2016-04-03 Thread Mike Auty
On 03/04/16 22:10, Jonathan K. Bullard wrote:
> 
> NAK. This should include testing for extra parameters supplied in
> error with the options, as the rest of the option-handling code does.
> Something like the following (for each of the three new options):
> 
> +  else if (streq (p[0], "vlan-tagging") && !p[1])
> 

Thanks for reviewing the patches!  5:)

That should be reasonable to add in, I'll try and do that in the next
couple of days (and try and change round my git repo so that I can keep
the patch versions in separate branches).

Could you let me know if I should be resending all the patches for the
next version, or just the ones that have changed?

Mike  5:)



signature.asc
Description: OpenPGP digital signature


Re: [Openvpn-devel] [PATCH 3/7] vlan: Add global, per-client 802.1q-based options

2016-04-03 Thread David Sommerseth
On 03/04/16 23:40, Mike Auty wrote:
> On 03/04/16 22:10, Jonathan K. Bullard wrote:
>>
>> NAK. This should include testing for extra parameters supplied in
>> error with the options, as the rest of the option-handling code does.
>> Something like the following (for each of the three new options):
>>
>> +  else if (streq (p[0], "vlan-tagging") && !p[1])
>>
> 
> Thanks for reviewing the patches!  5:)
> 
> That should be reasonable to add in, I'll try and do that in the next
> couple of days (and try and change round my git repo so that I can keep
> the patch versions in separate branches).
> 
> Could you let me know if I should be resending all the patches for the
> next version, or just the ones that have changed?

As long as it is a change only affecting a single patch, then resending an
updated version of that patch is generally fine.

When updating patches, please ensure that the subject line states for example
"PATCH v2".  That is easily done by adding --subject-prefix="PATCH v2" to the
git command lines creating the patch.

Second detail is to add a "revision history" in the git commit log.  See
commit a24dd2e31f196c76 as an example.


-- 
kind regards,

David Sommerseth