public void Connect(IReadOnlyList <VpnHost> servers, VpnConfig config, VpnProtocol protocol, VpnCredentials credentials) { ApplyNetworkSettings(); _origin.Connect(servers, config, protocol, credentials); }
public void Connect(IReadOnlyList <VpnHost> servers, VpnConfig config, VpnProtocol protocol, VpnCredentials credentials) { AddDefaultGateway(); _origin.Connect(servers, config, protocol, credentials); }
public void Connect(VpnEndpoint endpoint, VpnCredentials credentials, VpnConfig config) { _config = config; _endpoint = endpoint; _credentials = credentials; _connectAction.Run(); }
private static VpnCredentialsContract Map(VpnCredentials credentials) { return(new VpnCredentialsContract { Username = credentials.Username, Password = credentials.Password }); }
public void TestInitialize() { _logger = Substitute.For <ILogger>(); _taskQueue = new TaskQueue(); _origin = Substitute.For <ISingleVpnConnection>(); _endpoint = new VpnEndpoint(new VpnHost("proton.vpn", "135.27.46.203"), VpnProtocol.OpenVpnTcp, 777); _credentials = new VpnCredentials("username", "password"); _config = new VpnConfig(new Dictionary <VpnProtocol, IReadOnlyCollection <int> >(), new List <string>()); }
public void TestInitialize() { _logger = Substitute.For <ILogger>(); _taskQueue = new TaskQueue(); _origin = Substitute.For <ISingleVpnConnection>(); _endpoint = new VpnEndpoint(new VpnHost("proton.vpn", "135.27.46.203", string.Empty), VpnProtocol.OpenVpnTcp, 777); _credentials = new VpnCredentials("username", "password"); _config = new VpnConfig(new Dictionary <VpnProtocol, IReadOnlyCollection <int> >(), SplitTunnelMode.Disabled, useTunAdapter: false); }
private static VpnCredentialsContract Map(VpnCredentials credentials) { return(new() { Username = credentials.Username, Password = credentials.Password, ClientCertPem = credentials.ClientCertPem, ClientKeyPair = credentials.ClientKeyPair == null ? null : new AsymmetricKeyPairContract(credentials.ClientKeyPair) }); }
public VpnConnectionRequest( IReadOnlyList <VpnHost> servers, VpnProtocol protocol, VpnConfig config, VpnCredentials credentials) { Servers = servers; Protocol = protocol; Config = config; Credentials = credentials; }
public void Connect(IReadOnlyList <VpnHost> servers, VpnConfig config, VpnCredentials credentials) { _servers = servers; _config = config; _credentials = credentials; _connectRequested = true; _disconnectedReceived = false; Queued(Connect); }
public void TestInitialize() { _logger = Substitute.For <ILogger>(); _taskQueue = new TaskQueue(); _origin = Substitute.For <ISingleVpnConnection>(); _endpoint = new VpnEndpoint(new VpnHost("proton.vpn", "135.27.46.203", string.Empty, null), VpnProtocol.OpenVpnTcp, 777); _credentials = new VpnCredentials("username", "password", "cert", new AsymmetricKeyPair( new SecretKey("U2VjcmV0S2V5", KeyAlgorithm.Unknown), new PublicKey("UHVibGljS2V5", KeyAlgorithm.Unknown))); _config = new VpnConfig(new VpnConfigParameters()); }
public void Connect(VpnEndpoint endpoint, VpnCredentials credentials, VpnConfig config) { _vpnEndpoint = endpoint; _vpnCredentials = credentials; _config = config; _cancellationHandle.Cancel(); var cancellationToken = _cancellationHandle.Token; _disconnectDelay = Task.Delay(DisconnectDelay, cancellationToken); Queued(ScanPorts, cancellationToken); }
public void Connect(VpnEndpoint endpoint, VpnCredentials credentials, VpnConfig config) { _endpoint = endpoint; _credentials = credentials; _config = config; _connectRequested = true; _disconnectRequested = false; _disconnectError = VpnError.Unknown; _logger.Info("HandlingRequestsWrapper: Connect requested, queuing Connect"); Queued(Connect); }
public void Connect(VpnEndpoint endpoint, VpnCredentials credentials, VpnConfig config) { if (endpoint.Server.X25519PublicKey == null) { InvokeStateChange(VpnStatus.Disconnected, VpnError.MissingServerPublicKey); return; } _credentials = credentials; _endpoint = endpoint; _vpnConfig = config; _connectAction.Run(); }
public void Connect(IReadOnlyList <VpnHost> servers, VpnConfig config, VpnProtocol protocol, VpnCredentials credentials) { _reconnectPending = false; _reconnecting = false; _disconnecting = false; _protocol = protocol; _credentials = credentials; _config = config; _candidates.Set(servers); _candidates.Reset(); _endpoint = _candidates.Next(_protocol); _origin.Connect(_endpoint, credentials, config); }
/// <summary> /// Primary VPN connect method, doesn't finish until disconnect. /// This method will raise <see cref="TransportStatsChanged"/>, <see cref="VpnStateChanged"/> /// </summary> /// <param name="credentials"><see cref="VpnCredentials"/> (username and password) for authenticating to VPN server</param> /// <param name="endpoint"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public async Task StartVpnConnection(VpnCredentials credentials, VpnEndpoint endpoint, CancellationToken cancellationToken) { _lastError = VpnError.None; _credentials = credentials; _endpoint = endpoint; _sendingFailed = false; _disconnectRequested = false; _disconnectAccepted = false; while (!cancellationToken.IsCancellationRequested && !_sendingFailed) { ReceivedManagementMessage message = await Receive(); if (message.IsChannelDisconnected) { if (!_disconnectRequested && _lastError == VpnError.None) { _lastError = VpnError.Unknown; } OnVpnStateChanged(VpnStatus.Disconnecting); return; } if (!cancellationToken.IsCancellationRequested) { HandleMessage(message); } } if (!_sendingFailed) { await SendExit(); } if (!cancellationToken.IsCancellationRequested && _sendingFailed) { OnVpnStateChanged(VpnStatus.Disconnecting); } }
public void Connect(VpnEndpoint endpoint, VpnCredentials credentials, VpnConfig config) { _origin.Connect(endpoint, credentials, config); }
public void Connect(VpnEndpoint endpoint, VpnCredentials credentials, VpnConfig config) { _vpnProtocol = config.VpnProtocol; VpnConnection.Connect(endpoint, credentials, config); }
/// <summary> /// Configures OpenVPN on a manager node. /// </summary> /// <param name="manager">The manager.</param> private void ConfigManagerVpn(SshProxy <NodeDefinition> manager) { // Upload the setup and configuration files. // // NOTE: // // These steps are redundant and will be repeated during the // common node configuration, but we need some of the scripts // here, before that happens. manager.CreateHiveHostFolders(); manager.UploadConfigFiles(hive.Definition); manager.UploadResources(hive.Definition); // Install OpenVPN. manager.Status = "vpn install"; manager.SudoCommand("safe-apt-get update"); manager.SudoCommand("safe-apt-get install -yq openvpn"); // Configure OpenVPN. var nodesSubnet = NetworkCidr.Parse(hive.Definition.Network.NodesSubnet); var vpnSubnet = NetworkCidr.Parse(manager.Metadata.VpnPoolSubnet); var duplicateCN = hive.Definition.Vpn.AllowSharedCredentials ? "duplicate-cn" : ";duplicate-cn"; var vpnServerAddress = NetHelper.UintToAddress(NetHelper.AddressToUint(vpnSubnet.Address) + 1); var serverConf = $@"#------------------------------------------------------------------------------ # OpenVPN config file customized for the [{manager.Name}] neonHIVE manager node. # OpenVPN listening port. port {NetworkPorts.OpenVPN} # Enable TCP and/or UDP transports. proto tcp ;proto udp # Set packet tunneling mode. dev tun # SSL/TLS root certificate (ca), certificate # (cert), and private key (key). Each client # and the server must have their own cert and # key file. The server and all clients will # use the same ca file. # # See the [easy-rsa] directory for a series # of scripts for generating RSA certificates # and private keys. Remember to use # a unique Common Name for the server # and each of the client certificates. # # Any X509 key management system can be used. # OpenVPN can also use a PKCS #12 formatted key file # (see [pkcs12] directive in man page). ca ca.crt cert server.crt key server.key # This file should be kept secret # Diffie hellman parameters (2048-bit) generated via: # # openssl dhparam -out dhparam.pem 2048 # dh dhparam.pem # The currently recommended topology. topology subnet # Configure server mode and supply a VPN subnet # for OpenVPN to draw client addresses from. # The server will take {vpnServerAddress} for itself, # the rest will be made available to clients. # Each client will be able to reach the server # on {vpnServerAddress}. Comment this line out if you are # ethernet bridging. See the man page for more info. server {vpnSubnet.Address} {vpnSubnet.Mask} # Maintain a record of client virtual IP address # associations in this file. If OpenVPN goes down or # is restarted, reconnecting clients can be assigned # the same virtual IP address from the pool that was # previously assigned. ;ifconfig-pool-persist ipp.txt # Push routes to the client to allow it # to reach other private subnets behind # the server. Remember that these # private subnets will also need # to know to route the OpenVPN client # address pool ({vpnSubnet.Address}) # back to this specific OpenVPN server. push ""route {nodesSubnet.Address} {nodesSubnet.Mask}"" # Uncomment this directive if multiple clients # might connect with the same certificate/key # files or common names. This is recommended # only for testing purposes. For production use, # each client should have its own certificate/key # pair. {duplicateCN} # The keepalive directive causes ping-like # messages to be sent back and forth over # the link so that each side knows when # the other side has gone down. # Ping every 10 seconds, assume that remote # peer is down if no ping received during # a 120 second time period. keepalive 10 120 # For extra security beyond that provided # by SSL/TLS, create an [HMAC firewall] # to help block DoS attacks and UDP port flooding. # # Generate with: # openvpn --genkey --secret ta.key # # The server and each client must have # a copy of this key. # The second parameter should be '0' # on the server and '1' on the clients. tls-auth ta.key 0 # This file is secret # Select a cryptographic cipher. # This config item must be copied to # the client config file as well. cipher AES-256-CBC # Enable compression on the VPN link. # Don't enable this unless it is also # enabled in the client config file. # # We're not enabling this due to the # VORACLE security vulnerablity: # # https://community.openvpn.net/openvpn/wiki/VORACLE # # The maximum number of concurrently connected # clients we want to allow. max-clients {VpnOptions.ServerAddressCount - 2} # This macro sets the TCP_NODELAY socket flag on # the server as well as pushes it to connecting # clients. The TCP_NODELAY flag disables the Nagle # algorithm on TCP sockets causing packets to be # transmitted immediately with low latency, rather # than waiting a short period of time in order to # aggregate several packets into a larger containing # packet. In VPN applications over TCP, TCP_NODELAY # is generally a good latency optimization. tcp-nodelay # It's a good idea to reduce the OpenVPN # daemon's privileges after initialization. # # You can uncomment this out on # non-Windows systems. ;user nobody ;group nobody # The persist options will try to avoid # accessing certain resources on restart # that may no longer be accessible because # of the privilege downgrade. persist-key persist-tun # Output a short status file showing # current connections, truncated # and rewritten every minute. status openvpn-status.log # By default, log messages will go to the syslog (ork # on Windows, if running as a service, they will go to # the [\Program Files\OpenVPN\log] directory). # Use log or log-append to override this default. # [log] will truncate the log file on OpenVPN startup, # while [log-append] will append to it. Use one # or the other (but not both). log /var/log/openvpn.log ;log-append openvpn.log # Set the appropriate level of log # file verbosity. # # 0 is silent, except for fatal errors # 4 is reasonable for general usage # 5 and 6 can help to debug connection problems # 9 is extremely verbose verb 4 # Silence repeating messages. At most 20 # sequential messages of the same message # category will be output to the log. ;mute 20 "; manager.Status = "vpn config"; manager.SudoCommand("mkdir -p /etc/openvpn"); manager.UploadText("/etc/openvpn/server.conf", serverConf); manager.UploadText("/etc/openvpn/ca.crt", vpnCaFiles.GetCert("ca")); manager.UploadText("/etc/openvpn/server.crt", vpnCaFiles.GetCert("server")); manager.UploadText("/etc/openvpn/server.key", vpnCaFiles.GetKey("server")); manager.SudoCommand("chmod 600", "/etc/openvpn/server.key"); // This is a secret! manager.UploadText("/etc/openvpn/ta.key", vpnCaFiles.GetTaKey()); manager.SudoCommand("chmod 600", "/etc/openvpn/ta.key"); // This is a secret too! manager.UploadText("/etc/openvpn/dhparam.pem", vpnCaFiles.GetDHParam()); // Initialize the [root] user's credentials. vpnCredentials = new VpnCredentials() { CaCert = vpnCaFiles.GetCert("ca"), UserCert = vpnCaFiles.GetCert(HiveConst.RootUser), UserKey = vpnCaFiles.GetKey(HiveConst.RootUser), TaKey = vpnCaFiles.GetTaKey(), CaZipKey = VpnCaFiles.GenerateKey(), CaZip = vpnCaFiles.ToZipBytes() }; // Upload the initial (empty) Certificate Revocation List (CRL) file and then // upload a OpenVPN systemd unit drop-in so that it will recognize revoked certificates. manager.UploadText("/etc/openvpn/crl.pem", vpnCaFiles.GetFile("crl.pem")); manager.SudoCommand("chmod 664", "/etc/openvpn/crl.pem"); // OpenVPN needs to be able to read this after having its privileges downgraded. var openVpnUnit = @"[Unit] Description=OpenVPN connection to %i PartOf=openvpn.service ReloadPropagatedFrom=openvpn.service Before=systemd-user-sessions.service Documentation=man:openvpn(8) Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] PrivateTmp=true KillMode=mixed Type=forking ExecStart=/usr/sbin/openvpn --daemon ovpn-%i --status /run/openvpn/%i.status 10 --cd /etc/openvpn --script-security 2 --config /etc/openvpn/%i.conf --writepid /run/openvpn/%i.pid --crl-verify /etc/openvpn/crl.pem PIDFile=/run/openvpn/%i.pid ExecReload=/bin/kill -HUP $MAINPID WorkingDirectory=/etc/openvpn ProtectSystem=yes CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_AUDIT_WRITE LimitNPROC=10 DeviceAllow=/dev/null rw DeviceAllow=/dev/net/tun rw [Install] WantedBy=multi-user.target "; manager.UploadText("/etc/systemd/system/[email protected]", openVpnUnit); manager.SudoCommand("chmod 644 /etc/systemd/system/[email protected]"); // Do a daemon-reload so systemd will be aware of the new drop-in. manager.SudoCommand("systemctl disable openvpn"); manager.SudoCommand("systemctl daemon-reload"); // Enable and restart OpenVPN. manager.SudoCommand("systemctl enable openvpn"); manager.SudoCommand("systemctl restart openvpn"); //----------------------------------------------------------------- // SPECIAL NOTE: // // I figured out that I need this lovely bit of code after banging my head on the desk for // 12 freaking days. The problem was getting OpenVPN to work in Windows Azure (this will // also probably impact other cloud environments). // // Azure implements VNETs as layer 3 overlays. This means that the host network interfaces // are not actually on an ethernet segment and the VPN default gateway is actually handling // all of the ARP packets, routing between the VNET subnets, load balancers, and the Internet. // This is problematic for OpenVPN traffic because the VPN client IP address space is not // part of the VNET which means the VNET gateway is not able to route packets from hive // hosts back to the manager's OpenVPN client addresses by default. // // The solution is to configure the managers with secondary NIC cards in a different subnet // and provision special Azure user-defined routes that direct VPN return packets to the // correct manager. // // I figured this part out the second day. The problem was though that it simply didn't work. // From an external VPN client, I would try to ping a worker node through OpenVPN running on // a manager. I'd see the ping traffic: // // 1. manager/tun0: request // 2. manager/eth1: request // 3. worker/eth0: request // 4. worker/eth0: reply // 5. manager/eth0: reply // 6: NOTHING! EXPECTED: manager/tun0: reply // // So the problem was that I could see the ICMP ping request hit the various interfaces // on the manager and be received by the worker. I'd then see the worker send the reply, // and be routed via the user-defined Azure rult back to the manager. The problem was // that the packet was simply dropped there. It never made it back to tun0 so OpenVPN // could forward it back to the client. // // After days and days of trying to learn about Linux routing, iptables and policy rules, // I finally ran across this posting for the second time: // // https://unix.stackexchange.com/questions/21093/output-traffic-on-different-interfaces-based-on-destination-port // // This was the key. I ran across this a few days ago and didn't read it closely enough. // It made more sense after learning more about this stuff. // // Linux has a built-in IP address spoofing filter enabled by default. This filter has the // kernel discard any packets whose source address doesn't match the IP address/route implied // by the remote interface that transmitted the packet. This is exactly what's happening // when Azure forwards the VPN return packets via the user-defined route. I'd see return // packets hit eth0 on the manager, be processed by the low-level RAW and MANGLE iptables // and then they'd disappear. // // The solution is simply to disable the spoofing filter. I'm going to go ahead and do this // for all interfaces which should be fine for hives hosted in cloud environments, because the // VNET/Load Balancer/Security Groups will be used to lock things down. Local hives will // need to be manually placed behind a suitable router/firewall as well. // // For robustness, I'm going to deploy this as a service daemon that polls the filter state // for each interface every 5 seconds, and disables any enabled filters. This will ensure // that the filters will always be disabled, even as interfaces are bought up and down. var disableSpoofUnit = $@"[Unit] Description=Disable Network Anti-Spoofing Filters Documentation= After= Requires= Before= [Service] Type=simple ExecStart={HiveHostFolders.Bin}/disable-spoof-filters.sh [Install] WantedBy=multi-user.target "; var disableSpoofScript = @"#!/bin/bash #------------------------------------------------------------------------------ # This script is a deployed as a service to ensure that the Linux anti-spoofing # filters are disabled for the network interfaces on manager nodes hosting # OpenVPN. This is required to allow VPN return traffic from other nodes to # routed back to tun0 and ultimately, connected VPN clients. # # Note that it appears that we need to disable the filter for all interfaces # for this to actually work. while : do flush=false for f in /proc/sys/net/ipv4/conf/*/rp_filter do filter_enabled=$(cat $f) if [ ""$filter_enabled"" == ""1"" ] ; then echo 0 > $f flush=true fi done if [ ""$flush"" == ""true"" ] ; then echo 1 > /proc/sys/net/ipv4/route/flush fi sleep 5 done"; manager.UploadText("/lib/systemd/system/disable-spoof-filters.service", disableSpoofUnit); manager.SudoCommand("chmod 644 /lib/systemd/system/disable-spoof-filters.service"); manager.UploadText($"{HiveHostFolders.Bin}/disable-spoof-filters.sh", disableSpoofScript); manager.SudoCommand($"chmod 770 {HiveHostFolders.Bin}/disable-spoof-filters.sh"); manager.SudoCommand("systemctl enable disable-spoof-filters"); manager.SudoCommand("systemctl restart disable-spoof-filters"); }
public void Connect(IReadOnlyList <VpnHost> servers, VpnConfig config, VpnCredentials credentials) { _origin.Connect(servers, config, credentials); }