diff options
Diffstat (limited to 'src/openvpn/tun.h')
-rw-r--r-- | src/openvpn/tun.h | 234 |
1 files changed, 217 insertions, 17 deletions
diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 54e1dfa..99826cf 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -27,6 +27,8 @@ #ifdef _WIN32 #include <winioctl.h> #include <tap-windows.h> +#include <setupapi.h> +#include <cfgmgr32.h> #endif #include "buffer.h" @@ -36,6 +38,18 @@ #include "event.h" #include "proto.h" #include "misc.h" +#include "networking.h" +#include "ring_buffer.h" + +#ifdef _WIN32 +#define WINTUN_COMPONENT_ID "wintun" + +enum windows_driver_type { + WINDOWS_DRIVER_UNSPECIFIED, + WINDOWS_DRIVER_TAP_WINDOWS6, + WINDOWS_DRIVER_WINTUN +}; +#endif #if defined(_WIN32) || defined(TARGET_ANDROID) @@ -98,6 +112,12 @@ struct tuntap_options { in_addr_t nbdd[N_DHCP_ADDR]; int nbdd_len; +#define N_SEARCH_LIST_LEN 10 /* Max # of entries in domin-search list */ + + /* SEARCH (119), MacOS, Linux, Win10 1809+ */ + const char *domain_search_list[N_SEARCH_LIST_LEN]; + int domain_search_list_len; + /* DISABLE_NBT (43, Vendor option 001) */ bool disable_nbt; @@ -138,7 +158,6 @@ struct tuntap bool did_ifconfig_setup; bool did_ifconfig_ipv6_setup; - bool did_ifconfig; bool persistent_if; /* if existed before, keep on program end */ @@ -152,7 +171,6 @@ struct tuntap /* ifconfig parameters */ in_addr_t local; in_addr_t remote_netmask; - in_addr_t broadcast; struct in6_addr local_ipv6; struct in6_addr remote_ipv6; @@ -175,10 +193,16 @@ struct tuntap * ~0 if undefined */ DWORD adapter_index; + enum windows_driver_type windows_driver; int standby_iter; + + HANDLE wintun_send_ring_handle; + HANDLE wintun_receive_ring_handle; + struct tun_ring *wintun_send_ring; + struct tun_ring *wintun_receive_ring; #else /* ifdef _WIN32 */ int fd; /* file descriptor for TUN/TAP dev */ -#endif +#endif /* ifdef _WIN32 */ #ifdef TARGET_SOLARIS int ip_fd; @@ -205,6 +229,20 @@ tuntap_defined(const struct tuntap *tt) #endif } +#ifdef _WIN32 +static inline bool +tuntap_is_wintun(struct tuntap *tt) +{ + return tt && tt->windows_driver == WINDOWS_DRIVER_WINTUN; +} + +static inline bool +tuntap_ring_empty(struct tuntap *tt) +{ + return tuntap_is_wintun(tt) && (tt->wintun_send_ring->head == tt->wintun_send_ring->tail); +} +#endif + /* * Function prototypes */ @@ -212,7 +250,7 @@ tuntap_defined(const struct tuntap *tt) void open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt); -void close_tun(struct tuntap *tt); +void close_tun(struct tuntap *tt, openvpn_net_ctx_t *ctx); int write_tun(struct tuntap *tt, uint8_t *buf, int len); @@ -220,7 +258,8 @@ int read_tun(struct tuntap *tt, uint8_t *buf, int len); void tuncfg(const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, - const char *groupname, const struct tuntap_options *options); + const char *groupname, const struct tuntap_options *options, + openvpn_net_ctx_t *ctx); const char *guess_tuntap_dev(const char *dev, const char *dev_type, @@ -238,7 +277,8 @@ struct tuntap *init_tun(const char *dev, /* --dev option */ struct addrinfo *local_public, struct addrinfo *remote_public, const bool strict_warn, - struct env_set *es); + struct env_set *es, + openvpn_net_ctx_t *ctx); void init_tun_post(struct tuntap *tt, const struct frame *frame, @@ -247,10 +287,17 @@ void init_tun_post(struct tuntap *tt, void do_ifconfig_setenv(const struct tuntap *tt, struct env_set *es); -void do_ifconfig(struct tuntap *tt, - const char *actual, /* actual device name */ - int tun_mtu, - const struct env_set *es); +/** + * do_ifconfig - configure the tunnel interface + * + * @param tt the tuntap interface context + * @param ifname the human readable interface name + * @param mtu the MTU value to set the interface to + * @param es the environment to be used when executing the commands + * @param ctx the networking API opaque context + */ +void do_ifconfig(struct tuntap *tt, const char *ifname, int tun_mtu, + const struct env_set *es, openvpn_net_ctx_t *ctx); bool is_dev_type(const char *dev, const char *dev_type, const char *match_type); @@ -266,7 +313,7 @@ void check_subnet_conflict(const in_addr_t ip, const in_addr_t netmask, const char *prefix); -void warn_on_use_of_common_subnets(void); +void warn_on_use_of_common_subnets(openvpn_net_ctx_t *ctx); /* * Inline functions @@ -327,11 +374,10 @@ route_order(void) #ifdef _WIN32 -#define TUN_PASS_BUFFER - struct tap_reg { const char *guid; + enum windows_driver_type windows_driver; struct tap_reg *next; }; @@ -342,6 +388,13 @@ struct panel_reg struct panel_reg *next; }; +struct device_instance_id_interface +{ + const char *net_cfg_instance_id; + const char *device_interface_list; + struct device_instance_id_interface *next; +}; + int ascii2ipset(const char *name); const char *ipset2ascii(int index); @@ -457,10 +510,158 @@ read_tun_buffered(struct tuntap *tt, struct buffer *buf) return tun_finalize(tt->hand, &tt->reads, buf); } +static inline ULONG +wintun_ring_packet_align(ULONG size) +{ + return (size + (WINTUN_PACKET_ALIGN - 1)) & ~(WINTUN_PACKET_ALIGN - 1); +} + +static inline ULONG +wintun_ring_wrap(ULONG value) +{ + return value & (WINTUN_RING_CAPACITY - 1); +} + +static inline void +read_wintun(struct tuntap *tt, struct buffer *buf) +{ + struct tun_ring *ring = tt->wintun_send_ring; + ULONG head = ring->head; + ULONG tail = ring->tail; + ULONG content_len; + struct TUN_PACKET *packet; + ULONG aligned_packet_size; + + *buf = tt->reads.buf_init; + buf->len = 0; + + if ((head >= WINTUN_RING_CAPACITY) || (tail >= WINTUN_RING_CAPACITY)) + { + msg(M_INFO, "Wintun: ring capacity exceeded"); + buf->len = -1; + return; + } + + if (head == tail) + { + /* nothing to read */ + return; + } + + content_len = wintun_ring_wrap(tail - head); + if (content_len < sizeof(struct TUN_PACKET_HEADER)) + { + msg(M_INFO, "Wintun: incomplete packet header in send ring"); + buf->len = -1; + return; + } + + packet = (struct TUN_PACKET *) &ring->data[head]; + if (packet->size > WINTUN_MAX_PACKET_SIZE) + { + msg(M_INFO, "Wintun: packet too big in send ring"); + buf->len = -1; + return; + } + + aligned_packet_size = wintun_ring_packet_align(sizeof(struct TUN_PACKET_HEADER) + packet->size); + if (aligned_packet_size > content_len) + { + msg(M_INFO, "Wintun: incomplete packet in send ring"); + buf->len = -1; + return; + } + + buf_write(buf, packet->data, packet->size); + + head = wintun_ring_wrap(head + aligned_packet_size); + ring->head = head; +} + +static inline bool +is_ip_packet_valid(const struct buffer *buf) +{ + const struct openvpn_iphdr *ih = (const struct openvpn_iphdr *)BPTR(buf); + + if (OPENVPN_IPH_GET_VER(ih->version_len) == 4) + { + if (BLEN(buf) < sizeof(struct openvpn_iphdr)) + { + return false; + } + } + else if (OPENVPN_IPH_GET_VER(ih->version_len) == 6) + { + if (BLEN(buf) < sizeof(struct openvpn_ipv6hdr)) + { + return false; + } + } + else + { + return false; + } + + return true; +} + +static inline int +write_wintun(struct tuntap *tt, struct buffer *buf) +{ + struct tun_ring *ring = tt->wintun_receive_ring; + ULONG head = ring->head; + ULONG tail = ring->tail; + ULONG aligned_packet_size; + ULONG buf_space; + struct TUN_PACKET *packet; + + /* wintun marks ring as corrupted (overcapacity) if it receives invalid IP packet */ + if (!is_ip_packet_valid(buf)) + { + msg(D_LOW, "write_wintun(): drop invalid IP packet"); + return 0; + } + + if ((head >= WINTUN_RING_CAPACITY) || (tail >= WINTUN_RING_CAPACITY)) + { + msg(M_INFO, "write_wintun(): head/tail value is over capacity"); + return -1; + } + + aligned_packet_size = wintun_ring_packet_align(sizeof(struct TUN_PACKET_HEADER) + BLEN(buf)); + buf_space = wintun_ring_wrap(head - tail - WINTUN_PACKET_ALIGN); + if (aligned_packet_size > buf_space) + { + msg(M_INFO, "write_wintun(): ring is full"); + return 0; + } + + /* copy packet size and data into ring */ + packet = (struct TUN_PACKET * )&ring->data[tail]; + packet->size = BLEN(buf); + memcpy(packet->data, BPTR(buf), BLEN(buf)); + + /* move ring tail */ + ring->tail = wintun_ring_wrap(tail + aligned_packet_size); + if (ring->alertable != 0) + { + SetEvent(tt->rw_handle.write); + } + + return BLEN(buf); +} + static inline int write_tun_buffered(struct tuntap *tt, struct buffer *buf) { - return tun_write_win32(tt, buf); + if (tt->windows_driver == WINDOWS_DRIVER_WINTUN) + { + return write_wintun(tt, buf); + } + else + { + return tun_write_win32(tt, buf); + } } #else /* ifdef _WIN32 */ @@ -504,7 +705,7 @@ tun_event_handle(const struct tuntap *tt) #endif } -static inline unsigned int +static inline void tun_set(struct tuntap *tt, struct event_set *es, unsigned int rwflags, @@ -523,14 +724,13 @@ tun_set(struct tuntap *tt, } } #ifdef _WIN32 - if (rwflags & EVENT_READ) + if (tt->windows_driver == WINDOWS_DRIVER_TAP_WINDOWS6 && (rwflags & EVENT_READ)) { tun_read_queue(tt, 0); } #endif tt->rwflags_debug = rwflags; } - return rwflags; } const char *tun_stat(const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc); |