diff --git a/OpenVPN Adapter/OpenVPNClient.h b/OpenVPN Adapter/OpenVPNClient.h new file mode 100644 index 0000000..08cb11c --- /dev/null +++ b/OpenVPN Adapter/OpenVPNClient.h @@ -0,0 +1,99 @@ +// +// OpenVPNClient.h +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 11.01.2018. +// + +#import + +#include + +@class NEIPv4Route; +@class NEIPv6Route; +@class NEProxyServer; + +typedef NS_ENUM(NSInteger, OpenVPNProxyServerProtocol) { + OpenVPNProxyServerProtocolHTTP, + OpenVPNProxyServerProtocolHTTPS +}; + +NS_ASSUME_NONNULL_BEGIN + +@protocol OpenVPNClientDelegate +- (BOOL)setRemoteAddress:(NSString *)address; + +- (BOOL)addIPV4Address:(NSString *)address subnetMask:(NSString *)subnetMask gateway:(nullable NSString *)gateway; +- (BOOL)addIPV6Address:(NSString *)address prefixLength:(NSNumber *)prefixLength gateway:(nullable NSString *)gateway; + +- (BOOL)addIPV4Route:(NEIPv4Route *)route; +- (BOOL)addIPV6Route:(NEIPv6Route *)route; +- (BOOL)excludeIPV4Route:(NEIPv4Route *)route; +- (BOOL)excludeIPV6Route:(NEIPv6Route *)route; + +- (BOOL)addDNS:(NSString *)dns; +- (BOOL)addSearchDomain:(NSString *)domain; + +- (BOOL)setMTU:(NSNumber *)mtu; +- (BOOL)setSessionName:(NSString *)name; + +- (BOOL)addProxyBypassHost:(NSString *)bypassHost; +- (BOOL)setProxyAutoConfigurationURL:(NSURL *)url; +- (BOOL)setProxyServer:(NEProxyServer *)server protocol:(OpenVPNProxyServerProtocol)protocol; + +- (BOOL)establishTunnel; +- (CFSocketNativeHandle)socketHandle; + +- (void)clientEvent:(NSString *)eventName message:(nullable NSString *)message; +- (void)clientError:(NSString *)errorName fatal:(BOOL)fatal message:(nullable NSString *)message; +- (void)clientLog:(NSString *)logMessage; + +- (void)tick; + +- (void)resetSettings; +@end + +using namespace openvpn; + +class OpenVPNClient : public ClientAPI::OpenVPNClient { +public: + OpenVPNClient(id _delegate); + + bool tun_builder_new() override; + + bool tun_builder_set_remote_address(const std::string& address, bool ipv6) override; + bool tun_builder_add_address(const std::string& address, int prefix_length, const std::string& gateway, + bool ipv6, bool net30) override; + bool tun_builder_reroute_gw(bool ipv4, bool ipv6, unsigned int flags) override; + bool tun_builder_add_route(const std::string& address, int prefix_length, int metric, bool ipv6) override; + bool tun_builder_exclude_route(const std::string& address, int prefix_length, int metric, bool ipv6) override; + bool tun_builder_add_dns_server(const std::string& address, bool ipv6) override; + bool tun_builder_add_search_domain(const std::string& domain) override; + bool tun_builder_set_mtu(int mtu) override; + bool tun_builder_set_session_name(const std::string& name) override; + bool tun_builder_add_proxy_bypass(const std::string& bypass_host) override; + bool tun_builder_set_proxy_auto_config_url(const std::string& urlString) override; + bool tun_builder_set_proxy_http(const std::string& host, int port) override; + bool tun_builder_set_proxy_https(const std::string& host, int port) override; + bool tun_builder_set_block_ipv6(bool block_ipv6) override; + + int tun_builder_establish() override; + bool tun_builder_persist() override; + void tun_builder_teardown(bool disconnect) override; + + bool socket_protect(int socket) override; + bool pause_on_connection_timeout() override; + + void external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq) override; + void external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq) override; + + void event(const ClientAPI::Event& event) override; + void log(const ClientAPI::LogInfo& log) override; + + void clock_tick() override; + +private: + __weak id delegate; +}; + +NS_ASSUME_NONNULL_END diff --git a/OpenVPN Adapter/OpenVPNClient.mm b/OpenVPN Adapter/OpenVPNClient.mm new file mode 100644 index 0000000..efdb96f --- /dev/null +++ b/OpenVPN Adapter/OpenVPNClient.mm @@ -0,0 +1,169 @@ +// +// OpenVPNClient.m +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 11.01.2018. +// + +#define INVALID_SOCKET -1 + +#import "OpenVPNClient.h" + +#import + +#include + +using ::IPv4::Addr; + +OpenVPNClient::OpenVPNClient(id delegate): ClientAPI::OpenVPNClient() { + this->delegate = delegate; +} + +bool OpenVPNClient::tun_builder_new() { + [this->delegate resetSettings]; + return true; +} + +bool OpenVPNClient::tun_builder_set_remote_address(const std::string &address, bool ipv6) { + NSString *remoteAddress = [NSString stringWithUTF8String:address.c_str()]; + return [this->delegate setRemoteAddress:remoteAddress]; +} + +bool OpenVPNClient::tun_builder_add_address(const std::string &address, int prefix_length, const std::string &gateway, bool ipv6, bool net30) { + NSString *localAddress = [NSString stringWithUTF8String:address.c_str()]; + NSString *gatewayAddress = gateway.length() == 0 || gateway.compare("UNSPEC") == 0 ? nil : + [NSString stringWithUTF8String:gateway.c_str()]; + + if (ipv6) { + return [this->delegate addIPV6Address:localAddress prefixLength:@(prefix_length) gateway:gatewayAddress]; + } else { + NSString *subnetMask = [NSString stringWithUTF8String:Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()]; + return [this->delegate addIPV4Address:localAddress subnetMask:subnetMask gateway:gatewayAddress]; + } +} + +bool OpenVPNClient::tun_builder_reroute_gw(bool ipv4, bool ipv6, unsigned int flags) { + if (ipv4 && ![this->delegate addIPV4Route:[NEIPv4Route defaultRoute]]) { + return false; + } + + if (ipv6 && ![this->delegate addIPV6Route:[NEIPv6Route defaultRoute]]) { + return false; + } + + return true; +} + +bool OpenVPNClient::tun_builder_add_route(const std::string& address, int prefix_length, int metric, bool ipv6) { + NSString *routeAddress = [NSString stringWithUTF8String:address.c_str()]; + + if (ipv6) { + NEIPv6Route *route = [[NEIPv6Route alloc] initWithDestinationAddress:routeAddress networkPrefixLength:@(prefix_length)]; + return [this->delegate addIPV6Route:route]; + } else { + NSString *subnetMask = [NSString stringWithUTF8String:Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()]; + NEIPv4Route *route = [[NEIPv4Route alloc] initWithDestinationAddress:routeAddress subnetMask:subnetMask]; + return [this->delegate addIPV4Route:route]; + } +} + +bool OpenVPNClient::tun_builder_exclude_route(const std::string& address, int prefix_length, int metric, bool ipv6) { + NSString *routeAddress = [NSString stringWithUTF8String:address.c_str()]; + + if (ipv6) { + NEIPv6Route *route = [[NEIPv6Route alloc] initWithDestinationAddress:routeAddress networkPrefixLength:@(prefix_length)]; + return [this->delegate excludeIPV6Route:route]; + } else { + NSString *subnetMask = [NSString stringWithUTF8String:Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()]; + NEIPv4Route *route = [[NEIPv4Route alloc] initWithDestinationAddress:routeAddress subnetMask:subnetMask]; + return [this->delegate excludeIPV4Route:route]; + } +} + +bool OpenVPNClient::tun_builder_add_dns_server(const std::string& address, bool ipv6) { + NSString *dns = [NSString stringWithUTF8String:address.c_str()]; + return [this->delegate addDNS:dns]; +} + +bool OpenVPNClient::tun_builder_add_search_domain(const std::string& domain) { + NSString *searchDomain = [NSString stringWithUTF8String:domain.c_str()]; + return [this->delegate addSearchDomain:searchDomain]; +} + +bool OpenVPNClient::tun_builder_set_mtu(int mtu) { + return [this->delegate setMTU:@(mtu)]; +} + +bool OpenVPNClient::tun_builder_set_session_name(const std::string& name) { + NSString *sessionName = [NSString stringWithUTF8String:name.c_str()]; + return [this->delegate setSessionName:sessionName]; +} + +bool OpenVPNClient::tun_builder_add_proxy_bypass(const std::string& bypass_host) { + NSString *bypassHost = [NSString stringWithUTF8String:bypass_host.c_str()]; + return [this->delegate addProxyBypassHost:bypassHost]; +} + +bool OpenVPNClient::tun_builder_set_proxy_auto_config_url(const std::string& url) { + NSURL *configURL = [[NSURL alloc] initWithString:[NSString stringWithUTF8String:url.c_str()]]; + return [this->delegate setProxyAutoConfigurationURL:configURL]; +} + +bool OpenVPNClient::tun_builder_set_proxy_http(const std::string& host, int port) { + NSString *proxyHost = [NSString stringWithUTF8String:host.c_str()]; + NEProxyServer *proxyServer = [[NEProxyServer alloc] initWithAddress:proxyHost port:port]; + return [this->delegate setProxyServer:proxyServer protocol:OpenVPNProxyServerProtocolHTTP]; +} + +bool OpenVPNClient::tun_builder_set_proxy_https(const std::string& host, int port) { + NSString *proxyHost = [NSString stringWithUTF8String:host.c_str()]; + NEProxyServer *proxyServer = [[NEProxyServer alloc] initWithAddress:proxyHost port:port]; + return [this->delegate setProxyServer:proxyServer protocol:OpenVPNProxyServerProtocolHTTPS]; +} + +bool OpenVPNClient::tun_builder_set_block_ipv6(bool block_ipv6) { + return block_ipv6; +} + +int OpenVPNClient::tun_builder_establish() { + return [this->delegate establishTunnel] ? [this->delegate socketHandle] : INVALID_SOCKET; +} + +bool OpenVPNClient::tun_builder_persist() { + return true; +} + +void OpenVPNClient::tun_builder_teardown(bool disconnect) { + [this->delegate resetSettings]; +} + +bool OpenVPNClient::socket_protect(int socket) { + return true; +} + +bool OpenVPNClient::pause_on_connection_timeout() { + return false; +} + +void OpenVPNClient::external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq) { } +void OpenVPNClient::external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq) { } + +void OpenVPNClient::event(const ClientAPI::Event& ev) { + NSString *name = [NSString stringWithUTF8String:ev.name.c_str()]; + NSString *message = [NSString stringWithUTF8String:ev.info.c_str()]; + + if (ev.error) { + [this->delegate clientError:name fatal:ev.fatal message:message.length ? message : nil]; + } else { + [this->delegate clientEvent:name message:message.length ? message : nil]; + } +} + +void OpenVPNClient::log(const ClientAPI::LogInfo& log) { + NSString *logMessage = [NSString stringWithUTF8String:log.text.c_str()]; + [this->delegate clientLog:logMessage]; +} + +void OpenVPNClient::clock_tick() { + [this->delegate tick]; +}