diff --git a/.gitignore b/.gitignore
index 0d68ec4bb8e..52322c48b94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,3 +72,4 @@ nbproject
test-driver
compile
stamp-h2
+.vscode/settings.json
diff --git a/src/Makefile.am b/src/Makefile.am
index 313d289fc8c..815c5792b2a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -12,4 +12,4 @@
MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in
-SUBDIRS = compat openvpn openvpnmsica openvpnserv plugins tapctl
+SUBDIRS = compat openvpn openvpnmsica openvpnserv plugins tapctl
diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index f0e0ad237d0..9a628234543 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -126,6 +126,7 @@ openvpn_SOURCES = \
syshead.h \
tls_crypt.c tls_crypt.h \
tun.c tun.h \
+ tun2tap.c tun2tap.h \
vlan.c vlan.h \
win32.h win32.c \
cryptoapi.h cryptoapi.c
diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h
index e448fc370dc..620e4c0c211 100644
--- a/src/openvpn/errlevel.h
+++ b/src/openvpn/errlevel.h
@@ -149,6 +149,7 @@
#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_TUN2TAP LOGLEV(7, 75, M_DEBUG) /* show tun2tap debug messages */
#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 */
diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c
index fd08f12df7c..e0369a590db 100644
--- a/src/openvpn/forward.c
+++ b/src/openvpn/forward.c
@@ -42,6 +42,7 @@
#include "dhcp.h"
#include "common.h"
#include "ssl_verify.h"
+#include "tun2tap.h"
#include "memdbg.h"
@@ -949,7 +950,6 @@ read_incoming_link(struct context *c)
status = link_socket_read(c->c2.link_socket,
&c->c2.buf,
&c->c2.from);
-
if (socket_connection_reset(c->c2.link_socket, status))
{
#if PORT_SHARE
@@ -1277,6 +1277,8 @@ read_incoming_tun(struct context *c)
c->c2.buf.len = read_tun(c->c1.tuntap, BPTR(&c->c2.buf), MAX_RW_SIZE_TUN(&c->c2.frame));
#endif /* ifdef _WIN32 */
+ check_tun2tap_send(c, TUN2TAP_FLAG_ENCAP);
+
#ifdef PACKET_TRUNCATION_CHECK
ipv4_packet_size_verify(BPTR(&c->c2.buf),
BLEN(&c->c2.buf),
@@ -1890,6 +1892,11 @@ process_outgoing_tun(struct context *c)
&c->c2.n_trunc_tun_write);
#endif
+ if (!check_tun2tap_send(c, TUN2TAP_FLAG_DECAP))
+ {
+ goto cleanup;
+ }
+
#ifdef _WIN32
size = write_tun_buffered(c->c1.tuntap, &c->c2.to_tun);
#else
@@ -1930,6 +1937,7 @@ process_outgoing_tun(struct context *c)
MAX_RW_SIZE_TUN(&c->c2.frame));
}
+cleanup:
buf_reset(&c->c2.to_tun);
perf_pop();
diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h
index ff898133d81..4842f245c40 100644
--- a/src/openvpn/forward.h
+++ b/src/openvpn/forward.h
@@ -50,6 +50,7 @@
#include "openvpn.h"
#include "occ.h"
#include "ping.h"
+#include "tun2tap.h"
#define IOW_TO_TUN (1<<0)
#define IOW_TO_LINK (1<<1)
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 70cd493a592..66cf92739a2 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1126,6 +1126,19 @@ do_genkey(const struct options *options)
}
}
+/*
+* post check for tun2tap
+*/
+void
+do_check_tun2tap(const struct options *options)
+{
+ if (options && options->tun2tap && dev_type_enum(options->dev, options->dev_type) != DEV_TYPE_TUN)
+ {
+ msg(M_FATAL|M_OPTERR,
+ "options --tun2tap should only be used in tun mode");
+ }
+}
+
/*
* Persistent TUN/TAP device management mode?
*/
@@ -1718,6 +1731,7 @@ do_init_tun(struct context *c)
c->c1.tuntap = init_tun(c->options.dev,
c->options.dev_type,
c->options.topology,
+ c->options.tun2tap,
c->options.ifconfig_local,
c->options.ifconfig_remote_netmask,
c->options.ifconfig_ipv6_local,
@@ -1823,10 +1837,77 @@ do_open_tun(struct context *c)
open_tun(c->options.dev, c->options.dev_type, c->options.dev_node,
c->c1.tuntap);
+ /*
+ * detect tun2tap
+ */
+ if (c->c1.tuntap->tun2tap && !c->options.lladdr){
+ char *lladdr_tmp = NULL;
+ char mac_addr[OPENVPN_ETH_ALEN] = {0};
+ char buf[4*OPENVPN_ETH_ALEN] = {0};
+ int i = 0;
+ int offset = 0;
+ ASSERT(rand_bytes((unsigned char *)mac_addr, OPENVPN_ETH_ALEN));
+ /* magic mac addr: 00:cc:xx:xx:xx:xx */
+ mac_addr[0] = 0;
+ mac_addr[1] = 0;
+ mac_addr[2] = 'c';
+ mac_addr[3] = 'c';
+ for(; i < OPENVPN_ETH_ALEN; i++){
+ if (i != OPENVPN_ETH_ALEN - 1){
+ offset += sprintf(buf+offset, "%02x:", (unsigned char)mac_addr[i]);
+ } else {
+ offset += sprintf(buf+offset, "%02x", (unsigned char)mac_addr[i]);
+ }
+ }
+ lladdr_tmp = (char *)malloc(strlen((const char *)buf) + 1);
+ memcpy(lladdr_tmp, buf, strlen((const char *)buf));
+ lladdr_tmp[strlen((const char *)buf)] = 0;
+ c->options.lladdr = lladdr_tmp;
+ }
/* set the hardware address */
if (c->options.lladdr)
{
- set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es);
+ int i = 0;
+ char *buf = strdup(c->options.lladdr);
+ char mac_addr[OPENVPN_ETH_ALEN] = {0};
+ unsigned int mac_addr_tmp[OPENVPN_ETH_ALEN] = {0};
+ int len = strlen(buf);
+ while(len-- > 0){
+ if (buf[len] >= 'A' && buf[len] <= 'Z'){
+ /* x-X=z-Z => x=z-Z+X */
+ buf[len] += 'a'- 'A';
+ }
+ }
+ sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x"
+ , &mac_addr_tmp[0]
+ , &mac_addr_tmp[1]
+ , &mac_addr_tmp[2]
+ , &mac_addr_tmp[3]
+ , &mac_addr_tmp[4]
+ , &mac_addr_tmp[5]
+ );
+ while(i < OPENVPN_ETH_ALEN)
+ {
+ mac_addr[i] = 0xff & mac_addr_tmp[i];
+ i++;
+ }
+ dmsg(D_TUN2TAP, "local addr is: %02x:%02x:%02x:%02x:%02x:%02x"
+ , (unsigned char)mac_addr[0]
+ , (unsigned char)mac_addr[1]
+ , (unsigned char)mac_addr[2]
+ , (unsigned char)mac_addr[3]
+ , (unsigned char)mac_addr[4]
+ , (unsigned char)mac_addr[5]
+ );
+ memcpy(c->options.lladdr_v, mac_addr, sizeof(mac_addr));
+ if (c->c1.tuntap->tun2tap && (mac_addr[0] & 1)){
+ msg(M_INFO, "mac %s is mcast addr (mac[0]&1 == true)", buf);
+ ASSERT(0);
+ }
+ /* set_lladdr is use command to set mac address for interface, we cant set mac for tun device */
+ if (TUNNEL_TYPE(c->c1.tuntap) == DEV_TYPE_TAP)
+ set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es);
+ free(buf);
}
/* do ifconfig */
diff --git a/src/openvpn/init.h b/src/openvpn/init.h
index 0e6258f0b8d..94aae9c53b8 100644
--- a/src/openvpn/init.h
+++ b/src/openvpn/init.h
@@ -56,6 +56,8 @@ bool print_openssl_info(const struct options *options);
bool do_genkey(const struct options *options);
+void do_check_tun2tap(const struct options *options);
+
bool do_persist_tuntap(const struct options *options, openvpn_net_ctx_t *ctx);
bool possibly_become_daemon(const struct options *options);
diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c
index 7f61350d8e5..27a203a2b44 100644
--- a/src/openvpn/multi.c
+++ b/src/openvpn/multi.c
@@ -295,7 +295,7 @@ void
multi_init(struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode)
{
int dev = DEV_TYPE_UNDEF;
-
+
msg(D_MULTI_LOW, "MULTI: multi_init called, r=%d v=%d",
t->options.real_hash_size,
t->options.virtual_hash_size);
@@ -2585,7 +2585,7 @@ multi_process_incoming_link(struct multi_context *m, struct multi_instance *inst
}
perf_pop();
- if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TUN)
+ if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TUN && !m->top.options.tun2tap)
{
/* extract packet source and dest addresses */
mroute_flags = mroute_extract_addr_from_packet(&src,
@@ -2663,7 +2663,7 @@ multi_process_incoming_link(struct multi_context *m, struct multi_instance *inst
}
#endif
}
- else if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TAP)
+ else if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TAP || m->top.options.tun2tap)
{
uint16_t vid = 0;
#ifdef ENABLE_PF
diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c
index dc7001dce6c..c9239662112 100644
--- a/src/openvpn/openvpn.c
+++ b/src/openvpn/openvpn.c
@@ -235,6 +235,9 @@ openvpn_main(int argc, char *argv[])
break;
}
+ /* check tun2tap for tun mode */
+ do_check_tun2tap(&c.options);
+
/* tun/tap persist command? */
if (do_persist_tuntap(&c.options, &c.net_ctx))
{
diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj
index 53ac5482a58..7df558e9ad9 100644
--- a/src/openvpn/openvpn.vcxproj
+++ b/src/openvpn/openvpn.vcxproj
@@ -198,6 +198,7 @@
+
@@ -288,6 +289,7 @@
+
diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters
index 80eb52b3895..1c505041c06 100644
--- a/src/openvpn/openvpn.vcxproj.filters
+++ b/src/openvpn/openvpn.vcxproj.filters
@@ -204,6 +204,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -479,6 +482,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 2d2089e3be6..ed200f96b78 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -2061,9 +2061,9 @@ options_postprocess_verify_ce(const struct options *options, const struct connec
}
- if (options->lladdr && dev != DEV_TYPE_TAP)
+ if (options->lladdr && (dev == DEV_TYPE_TUN && !options->tun2tap) && dev != DEV_TYPE_TAP)
{
- msg(M_USAGE, "--lladdr can only be used in --dev tap mode");
+ msg(M_USAGE, "--lladdr can only be used in --dev tap mode or tun2tap");
}
/*
@@ -3703,6 +3703,7 @@ options_string(const struct options *o,
tt = init_tun(o->dev,
o->dev_type,
o->topology,
+ o->tun2tap,
o->ifconfig_local,
o->ifconfig_remote_netmask,
o->ifconfig_ipv6_local,
@@ -3727,6 +3728,12 @@ options_string(const struct options *o,
buf_printf(&out, ",ifconfig %s", ios);
}
}
+
+ if (tt && tt->tun2tap)
+ {
+ buf_printf(&out, ",tun2tap");
+ }
+
if (tt_local)
{
free(tt);
@@ -5445,6 +5452,11 @@ add_option(struct options *options,
goto err;
}
}
+ else if (streq(p[0], "tun2tap") && !p[1])
+ {
+ /* check in post do_xxxx */
+ options->tun2tap = true;
+ }
else if (streq(p[0], "topology") && p[1] && !p[2])
{
VERIFY_PERMISSION(OPT_P_UP);
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index 375a4fc9712..2aeb19c65e9 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -213,7 +213,7 @@ struct options
/* persist parms */
bool persist_config;
int persist_mode;
-
+ bool tun2tap;
const char *key_pass_file;
bool show_ciphers;
bool show_digests;
@@ -248,6 +248,7 @@ struct options
const char *dev_type;
const char *dev_node;
const char *lladdr;
+ uint8_t lladdr_v[OPENVPN_ETH_ALEN];
int topology; /* one of the TOP_x values from proto.h */
const char *ifconfig_local;
const char *ifconfig_remote_netmask;
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index 8e692977e98..f26b03b8f2d 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -556,7 +556,7 @@ is_tun_p2p(const struct tuntap *tt)
bool tun = false;
if (tt->type == DEV_TYPE_TAP
- || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)
+ || (tt->type == DEV_TYPE_TUN && (tt->topology == TOP_SUBNET || tt->tun2tap))
|| tt->type == DEV_TYPE_NULL)
{
tun = false;
@@ -624,6 +624,7 @@ struct tuntap *
init_tun(const char *dev, /* --dev option */
const char *dev_type, /* --dev-type option */
int topology, /* one of the TOP_x values */
+ const bool tun2tap, /* --tun2tap */
const char *ifconfig_local_parm, /* --ifconfig parm 1 */
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 IPv6 */
@@ -644,6 +645,13 @@ init_tun(const char *dev, /* --dev option */
tt->type = dev_type_enum(dev, dev_type);
tt->topology = topology;
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ tt->tun2tap = tun2tap;
+ } else {
+ tt->tun2tap = false;
+ }
+
if (ifconfig_local_parm && ifconfig_remote_netmask_parm)
{
bool tun = false;
@@ -1150,7 +1158,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
argv_printf(&argv, "%s %s netmask 255.255.255.255", IFCONFIG_PATH,
ifname);
}
- else if (tt->topology == TOP_SUBNET)
+ else if (tt->topology == TOP_SUBNET || tt->tun2tap)
{
argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up", IFCONFIG_PATH,
ifname, ifconfig_local, ifconfig_local,
@@ -1169,7 +1177,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
solaris_error_close(tt, es, ifname, false);
}
- if (!tun && tt->topology == TOP_SUBNET)
+ if (!tun && (tt->topology == TOP_SUBNET || tt->tun2tap))
{
/* Add a network route for the local tun interface */
struct route_ipv4 r;
@@ -1200,7 +1208,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
IFCONFIG_PATH, ifname, ifconfig_local,
ifconfig_remote_netmask, tun_mtu);
}
- else if (tt->topology == TOP_SUBNET)
+ else if (tt->topology == TOP_SUBNET || tt->tun2tap)
{
remote_end = create_arbitrary_remote( tt );
argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up -link0",
@@ -1218,7 +1226,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig failed");
/* Add a network route for the local tun interface */
- if (!tun && tt->topology == TOP_SUBNET)
+ if (!tun && (tt->topology == TOP_SUBNET || tt->tun2tap))
{
struct route_ipv4 r;
CLEAR(r);
@@ -1238,7 +1246,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
IFCONFIG_PATH, ifname, ifconfig_local,
ifconfig_remote_netmask, tun_mtu);
}
- else if (tt->topology == TOP_SUBNET)
+ else if (tt->topology == TOP_SUBNET || tt->tun2tap)
{
remote_end = create_arbitrary_remote(tt);
argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up", IFCONFIG_PATH,
@@ -1260,7 +1268,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig failed");
/* Add a network route for the local tun interface */
- if (!tun && tt->topology == TOP_SUBNET)
+ if (!tun && (tt->topology == TOP_SUBNET || tt->tun2tap))
{
struct route_ipv4 r;
CLEAR(r);
@@ -1292,7 +1300,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
}
else
{
- if (tt->topology == TOP_SUBNET)
+ if (tt->topology == TOP_SUBNET || tt->tun2tap)
{
argv_printf(&argv, "%s %s %s %s netmask %s mtu %d up",
IFCONFIG_PATH, ifname, ifconfig_local, ifconfig_local,
@@ -1310,7 +1318,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
openvpn_execve_check(&argv, es, S_FATAL, "Mac OS X ifconfig failed");
/* Add a network route for the local tun interface */
- if (!tun && tt->topology == TOP_SUBNET)
+ if (!tun && (tt->topology == TOP_SUBNET || tt->tun2tap))
{
struct route_ipv4 r;
CLEAR(r);
@@ -1332,7 +1340,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
IFCONFIG_PATH, ifname, ifconfig_local,
ifconfig_remote_netmask, tun_mtu);
}
- else if (tt->topology == TOP_SUBNET)
+ else if (tt->topology == TOP_SUBNET || tt->tun2tap)
{
remote_end = create_arbitrary_remote( tt );
argv_printf(&argv, "%s %s %s %s mtu %d netmask %s up", IFCONFIG_PATH,
@@ -1349,7 +1357,7 @@ do_ifconfig_ipv4(struct tuntap *tt, const char *ifname, int tun_mtu,
openvpn_execve_check(&argv, es, S_FATAL, "FreeBSD ifconfig failed");
/* Add a network route for the local tun interface */
- if (!tun && tt->topology == TOP_SUBNET)
+ if (!tun && (tt->topology == TOP_SUBNET || tt->tun2tap))
{
struct route_ipv4 r;
CLEAR(r);
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h
index b38e7e90bff..6d7b9e594ba 100644
--- a/src/openvpn/tun.h
+++ b/src/openvpn/tun.h
@@ -149,7 +149,6 @@ struct tuntap
#define TUNNEL_TOPOLOGY(tt) ((tt) ? ((tt)->topology) : TOP_UNDEF)
int topology; /* one of the TOP_x values */
-
bool did_ifconfig_setup;
bool did_ifconfig_ipv6_setup;
@@ -157,6 +156,8 @@ struct tuntap
struct tuntap_options options; /* options set on command line */
+ bool tun2tap; /* options set on --tun2tap for tun mode */
+
char *actual_name; /* actual name of TUN/TAP dev, usually including unit number */
/* number of TX buffers */
@@ -168,6 +169,7 @@ struct tuntap
struct in6_addr local_ipv6;
struct in6_addr remote_ipv6;
+ uint8_t remote_mac_addr[OPENVPN_ETH_ALEN];
int netbits_ipv6;
#ifdef _WIN32
@@ -263,6 +265,7 @@ const char *guess_tuntap_dev(const char *dev,
struct tuntap *init_tun(const char *dev, /* --dev option */
const char *dev_type, /* --dev-type option */
int topology, /* one of the TOP_x values */
+ const bool tun2tap, /* --tun2tap */
const char *ifconfig_local_parm, /* --ifconfig parm 1 */
const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */
const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 / IPv6 */
diff --git a/src/openvpn/tun2tap.c b/src/openvpn/tun2tap.c
new file mode 100644
index 00000000000..5ca5378d9ca
--- /dev/null
+++ b/src/openvpn/tun2tap.c
@@ -0,0 +1,179 @@
+/*
+ * 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-2018 OpenVPN Inc
+ *
+ * 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.
+ *
+ * Author: pengtianabc@hotmail.com
+ * Date: 2020-4-12 11:17:33
+ * Function: simulate arp logical for tun device on client
+ * TODO: ship for server, but i think that not worth, most server is on linux that easy to use tap
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+#include "tun2tap.h"
+
+#include "memdbg.h"
+
+void build_arp_reply(struct context *c, struct openvpn_ethhdr *hdr_out, struct openvpn_arp *arp_in, struct openvpn_arp *arp_out);
+void build_arp_reply(struct context *c, struct openvpn_ethhdr *hdr_out, struct openvpn_arp *arp_in, struct openvpn_arp *arp_out)
+{
+ if (!c || !hdr_out || !arp_in || !arp_out)
+ {
+ return;
+ }
+ memset(hdr_out, 0, sizeof(*hdr_out));
+ memset(arp_out, 0, sizeof(*arp_out));
+ hdr_out->proto = htons(OPENVPN_ETH_P_ARP);
+ arp_out->mac_addr_type = htons(0x0001);
+ arp_out->proto_addr_type = htons(0x0800);
+ arp_out->mac_addr_size = 0x06;
+ arp_out->proto_addr_size = 0x04;
+ arp_out->arp_command = htons(ARP_REPLY);
+ memcpy(arp_out->mac_src, c->options.lladdr_v, OPENVPN_ETH_ALEN);
+ memcpy(arp_out->mac_dest, arp_in->mac_src, OPENVPN_ETH_ALEN);
+ memcpy(hdr_out->source, c->options.lladdr_v, OPENVPN_ETH_ALEN);
+ memcpy(hdr_out->dest, c->c1.tuntap->remote_mac_addr, OPENVPN_ETH_ALEN);
+ arp_out->ip_src = arp_in->ip_dest;
+ arp_out->ip_dest = arp_in->ip_src;
+}
+
+/*
+ * arp check and build for tun
+ */
+bool
+check_tun2tap_arp_dowork(struct context *c, int flag)
+{
+ int ret = true;
+ if (!c->options.tun2tap){
+ return ret;
+ }
+ if (TUN2TAP_FLAG_ENCAP == flag){
+ dmsg(D_TUN2TAP, "TUN2TAP: encap data from tun");
+ /* read from tun, check and send arp to link */
+ if ( BLEN(&c->c2.buf) >= sizeof(struct openvpn_iphdr)){
+ struct openvpn_ethhdr hdr = {0};
+ struct openvpn_iphdr *ip_hdr = (struct openvpn_iphdr *)BPTR(&c->c2.buf);
+ /*
+ struct openvpn_ipv6hdr *ipv6_hdr = (struct openvpn_ipv6hdr *)BPTR(&c->c2.buf);
+ */
+ int v = OPENVPN_IPH_GET_VER(ip_hdr->version_len);
+ memcpy(hdr.dest, c->c1.tuntap->remote_mac_addr, OPENVPN_ETH_ALEN);
+ memcpy(hdr.source, c->options.lladdr_v, OPENVPN_ETH_ALEN);
+ /*
+ * if client send the first packet to server after connected, remote_mac_addr is zero
+ * so we build a arp request to replace this packet.
+ */
+ if (0 == memcmp(hdr.dest, "\x00\x00\x00\x00\x00\x00", OPENVPN_ETH_ALEN)){
+ struct openvpn_arp arp = { 0 };
+ arp.mac_addr_type = htons(0x0001);
+ arp.proto_addr_type = htons(0x0800);
+ arp.mac_addr_size = 0x06;
+ arp.proto_addr_size = 0x04;
+ arp.arp_command = htons(ARP_REQUEST);
+ memcpy(arp.mac_src, hdr.source, OPENVPN_ETH_ALEN);
+ memcpy(arp.mac_dest, "\x00\x00\x00\x00\x00\x00", OPENVPN_ETH_ALEN);
+ memcpy(hdr.dest, "\xff\xff\xff\xff\xff\xff", OPENVPN_ETH_ALEN);
+ hdr.proto = htons(OPENVPN_ETH_P_ARP);
+ switch (v)
+ {
+ case 4:
+ arp.ip_src = ip_hdr->saddr;
+ arp.ip_dest = ip_hdr->daddr;
+ break;
+ case 6:
+ /*
+ do nothing, arp has been removed in ipv6
+ so we will not receive any ipv6 packet without mac
+ this case will never in
+ */
+ default:
+ break;
+ }
+ buf_clear(&c->c2.buf);
+ buf_write(&c->c2.buf, &hdr, sizeof(hdr));
+ buf_write(&c->c2.buf, &arp, sizeof(arp));
+ } else {
+ switch (v)
+ {
+ case 4:
+ hdr.proto = htons(OPENVPN_ETH_P_IPV4);
+ break;
+ case 6:
+ hdr.proto = htons(OPENVPN_ETH_P_IPV6);
+ default:
+ break;
+ }
+ ASSERT(buf_write_prepend(&c->c2.buf, &hdr, sizeof(hdr)));
+ }
+ }
+ } else if (TUN2TAP_FLAG_DECAP == flag){
+ dmsg(D_TUN2TAP, "TUN2TAP: decap data to tun");
+ /* will write to tun, check is arp request, and save remote addr */
+ if (BLEN(&c->c2.buf) >= sizeof(struct openvpn_ethhdr)){
+ struct openvpn_ethhdr *hdr = (struct openvpn_ethhdr *) BPTR(&c->c2.buf);
+ memcpy(c->c1.tuntap->remote_mac_addr, hdr->source, OPENVPN_ETH_ALEN);
+ if (hdr->proto == htons(OPENVPN_ETH_P_ARP)){
+ dmsg(D_TUN2TAP, "TUN2TAP: processing arp from tun");
+ if (BLEN(&c->c2.buf) >= sizeof(struct openvpn_ethhdr) + sizeof(struct openvpn_arp)){
+ struct openvpn_arp *arp_in = (struct openvpn_arp *)(BPTR(&c->c2.buf) + sizeof(struct openvpn_ethhdr));
+ if (arp_in->arp_command == htons(ARP_REPLY)){
+ dmsg(D_TUN2TAP, "TUN2TAP: ignore arp reply");
+ buf_clear(&c->c2.buf);
+ ret = false;
+ } else if (arp_in->arp_command == htons(ARP_REQUEST) ){
+ if (arp_in->ip_dest == htonl(c->c1.tuntap->local)){
+ /*
+ * build reply and write arp to link
+ */
+ struct openvpn_ethhdr hdr_out;
+ struct openvpn_arp arp_out;
+ build_arp_reply(c, &hdr_out, arp_in, &arp_out);
+ buf_clear(&c->c2.buf);
+ ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame)));
+ ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame)));
+ buf_write(&c->c2.buf, &hdr_out, sizeof(hdr_out));
+ buf_write(&c->c2.buf, &arp_out, sizeof(arp_out));
+ dmsg(D_TUN2TAP, "TUN2TAP: build arp reply success");
+ encrypt_sign(c, true);
+ } else {
+ dmsg(D_TUN2TAP, "TUN2TAP: ignore any arp request not to me dest:%x me:%x", ntohl(arp_in->ip_dest), c->c1.tuntap->local);
+ buf_clear(&c->c2.buf);
+ ret = false;
+ }
+ } else{
+ dmsg(D_TUN2TAP, "TUN2TAP: ignore uknown arp type: %x", ntohs(arp_in->arp_command));
+ buf_clear(&c->c2.buf);
+ ret = false;
+ }
+ }
+ } else {
+ dmsg(D_TUN2TAP, "TUN2TAP: trim ethhdr for tun");
+ buf_advance(&c->c2.to_tun, sizeof(struct openvpn_ethhdr));
+ }
+ }
+ }
+ return ret;
+}
diff --git a/src/openvpn/tun2tap.h b/src/openvpn/tun2tap.h
new file mode 100644
index 00000000000..5c64daec0ec
--- /dev/null
+++ b/src/openvpn/tun2tap.h
@@ -0,0 +1,44 @@
+/*
+ * 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-2018 OpenVPN Inc
+ *
+ * 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.
+ *
+ * Author: pengtianabc@hotmail.com
+ */
+
+#ifndef TUN2TAP_H
+#define TUN2TAP_H
+
+#include "init.h"
+#include "forward.h"
+#define TUN2TAP_FLAG_ENCAP 1
+#define TUN2TAP_FLAG_DECAP (1<<1)
+
+/*
+ * arp check and build for tun
+ */
+static inline bool
+check_tun2tap_send(struct context *c, int flag)
+{
+ bool check_tun2tap_arp_dowork(struct context *c, int flag);
+ return check_tun2tap_arp_dowork(c, flag);
+}
+
+#endif /* ifndef TUN2TAP_H */