2020-07-15 18:14:45 -04:00
package provider
import (
2020-10-12 10:55:08 -04:00
"context"
2020-07-15 18:14:45 -04:00
"fmt"
2020-10-12 15:29:58 -04:00
"math/rand"
2020-10-12 10:55:08 -04:00
"net"
"net/http"
2020-07-15 18:14:45 -04:00
2020-07-26 12:07:06 +00:00
"github.com/qdm12/gluetun/internal/constants"
2020-10-12 10:55:08 -04:00
"github.com/qdm12/gluetun/internal/firewall"
2020-07-26 12:07:06 +00:00
"github.com/qdm12/gluetun/internal/models"
2020-10-12 10:55:08 -04:00
"github.com/qdm12/golibs/files"
"github.com/qdm12/golibs/logging"
2020-07-15 18:14:45 -04:00
)
2020-08-25 19:38:50 -04:00
type nordvpn struct {
2020-10-12 15:29:58 -04:00
servers [ ] models . NordvpnServer
randSource rand . Source
2020-08-25 19:38:50 -04:00
}
2020-07-15 18:14:45 -04:00
2020-10-12 15:29:58 -04:00
func newNordvpn ( servers [ ] models . NordvpnServer , timeNow timeNowFunc ) * nordvpn {
2020-08-25 19:38:50 -04:00
return & nordvpn {
2020-10-12 15:29:58 -04:00
servers : servers ,
randSource : rand . NewSource ( timeNow ( ) . UnixNano ( ) ) ,
2020-08-25 19:38:50 -04:00
}
2020-07-15 18:14:45 -04:00
}
2020-10-18 17:15:42 -04:00
func ( n * nordvpn ) filterServers ( regions [ ] string , protocol models . NetworkProtocol , numbers [ ] uint16 ) ( servers [ ] models . NordvpnServer ) {
numbersStr := make ( [ ] string , len ( numbers ) )
for i := range numbers {
numbersStr [ i ] = fmt . Sprintf ( "%d" , numbers [ i ] )
}
for _ , server := range n . servers {
numberStr := fmt . Sprintf ( "%d" , server . Number )
switch {
case
protocol == constants . TCP && ! server . TCP ,
protocol == constants . UDP && ! server . UDP ,
filterByPossibilities ( server . Region , regions ) ,
filterByPossibilities ( numberStr , numbersStr ) :
default :
servers = append ( servers , server )
2020-07-15 18:14:45 -04:00
}
}
2020-07-23 01:46:28 +00:00
return servers
2020-07-15 18:14:45 -04:00
}
2020-10-12 15:29:58 -04:00
func ( n * nordvpn ) GetOpenVPNConnection ( selection models . ServerSelection ) ( connection models . OpenVPNConnection , err error ) { //nolint:dupl
2020-07-15 18:14:45 -04:00
var port uint16
switch {
case selection . Protocol == constants . UDP :
port = 1194
case selection . Protocol == constants . TCP :
port = 443
default :
2020-10-12 15:29:58 -04:00
return connection , fmt . Errorf ( "protocol %q is unknown" , selection . Protocol )
2020-07-15 18:14:45 -04:00
}
2020-07-23 01:46:28 +00:00
2020-10-12 20:21:26 +00:00
if selection . TargetIP != nil {
return models . OpenVPNConnection { IP : selection . TargetIP , Port : port , Protocol : selection . Protocol } , nil
2020-07-23 01:46:28 +00:00
}
2020-10-18 17:15:42 -04:00
servers := n . filterServers ( selection . Regions , selection . Protocol , selection . Numbers )
2020-10-12 20:21:26 +00:00
if len ( servers ) == 0 {
2020-10-18 17:15:42 -04:00
return connection , fmt . Errorf ( "no server found for region %s, protocol %s and numbers %v" , commaJoin ( selection . Regions ) , selection . Protocol , selection . Numbers )
2020-10-12 20:21:26 +00:00
}
connections := make ( [ ] models . OpenVPNConnection , len ( servers ) )
for i := range servers {
connections = append ( connections , models . OpenVPNConnection { IP : servers [ i ] . IP , Port : port , Protocol : selection . Protocol } )
2020-07-23 01:46:28 +00:00
}
2020-10-12 15:29:58 -04:00
return pickRandomConnection ( connections , n . randSource ) , nil
2020-07-15 18:14:45 -04:00
}
2020-10-12 15:29:58 -04:00
func ( n * nordvpn ) BuildConf ( connection models . OpenVPNConnection , verbosity , uid , gid int , root bool , cipher , auth string , extras models . ExtraConfigOptions ) ( lines [ ] string ) { //nolint:dupl
2020-07-15 18:14:45 -04:00
if len ( cipher ) == 0 {
cipher = aes256cbc
}
if len ( auth ) == 0 {
auth = "sha512"
}
lines = [ ] string {
"client" ,
"dev tun" ,
"nobind" ,
"persist-key" ,
"remote-cert-tls server" ,
// Nordvpn specific
"tun-mtu 1500" ,
"tun-mtu-extra 32" ,
"mssfix 1450" ,
"ping 15" ,
"ping-restart 0" ,
"ping-timer-rem" ,
"reneg-sec 0" ,
"comp-lzo no" ,
"fast-io" ,
"key-direction 1" ,
// Added constant values
"auth-nocache" ,
"mute-replay-warnings" ,
"pull-filter ignore \"auth-token\"" , // prevent auth failed loops
"auth-retry nointeract" ,
"remote-random" ,
"suppress-timestamps" ,
// Modified variables
fmt . Sprintf ( "verb %d" , verbosity ) ,
fmt . Sprintf ( "auth-user-pass %s" , constants . OpenVPNAuthConf ) ,
2020-10-12 15:29:58 -04:00
fmt . Sprintf ( "proto %s" , string ( connection . Protocol ) ) ,
fmt . Sprintf ( "remote %s %d" , connection . IP . String ( ) , connection . Port ) ,
2020-07-15 18:14:45 -04:00
fmt . Sprintf ( "cipher %s" , cipher ) ,
fmt . Sprintf ( "auth %s" , auth ) ,
}
if ! root {
lines = append ( lines , "user nonrootuser" )
}
lines = append ( lines , [ ] string {
"<ca>" ,
"-----BEGIN CERTIFICATE-----" ,
constants . NordvpnCertificate ,
"-----END CERTIFICATE-----" ,
"</ca>" ,
} ... )
lines = append ( lines , [ ] string {
"<tls-auth>" ,
"-----BEGIN OpenVPN Static key V1-----" ,
constants . NordvpnOpenvpnStaticKeyV1 ,
"-----END OpenVPN Static key V1-----" ,
"</tls-auth>" ,
"" ,
} ... )
return lines
}
2020-10-12 10:55:08 -04:00
func ( n * nordvpn ) PortForward ( ctx context . Context , client * http . Client ,
fileManager files . FileManager , pfLogger logging . Logger , gateway net . IP , fw firewall . Configurator ,
syncState func ( port uint16 ) ( pfFilepath models . Filepath ) ) {
2020-07-15 18:14:45 -04:00
panic ( "port forwarding is not supported for nordvpn" )
}