Skip to content

Commit

Permalink
Merge pull request #444 from Darkren/feature/route-encryption
Browse files Browse the repository at this point in the history
Route encryption
  • Loading branch information
jdknives authored Aug 7, 2020
2 parents 50f18fd + 82d28ed commit 794e80a
Show file tree
Hide file tree
Showing 30 changed files with 608 additions and 450 deletions.
14 changes: 1 addition & 13 deletions cmd/apps/vpn-client/vpn-client.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,6 @@ func main() {
}
}

var noiseCreds vpn.NoiseCredentials
if localPK.Null() && !localSK.Null() {
var err error
noiseCreds, err = vpn.NewNoiseCredentialsFromSK(localSK)
if err != nil {
log.WithError(err).Fatalln("error creating noise credentials")
}
} else {
noiseCreds = vpn.NewNoiseCredentials(localSK, localPK)
}

appClient := app.NewClient(nil)
defer appClient.Close()

Expand All @@ -99,8 +88,7 @@ func main() {
log.Infof("Dialed %s", appConn.RemoteAddr())

vpnClientCfg := vpn.ClientConfig{
Passcode: *passcode,
Credentials: noiseCreds,
Passcode: *passcode,
}
vpnClient, err := vpn.NewClient(vpnClientCfg, log, appConn)
if err != nil {
Expand Down
14 changes: 1 addition & 13 deletions cmd/apps/vpn-server/vpn-server.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,6 @@ func main() {
}
}

var noiseCreds vpn.NoiseCredentials
if localPK.Null() && !localSK.Null() {
var err error
noiseCreds, err = vpn.NewNoiseCredentialsFromSK(localSK)
if err != nil {
log.WithError(err).Fatalln("error creating noise credentials")
}
} else {
noiseCreds = vpn.NewNoiseCredentials(localSK, localPK)
}

appClient := app.NewClient(nil)
defer appClient.Close()

Expand All @@ -78,8 +67,7 @@ func main() {
log.Infof("Got app listener, bound to %d", vpnPort)

srvCfg := vpn.ServerConfig{
Passcode: *passcode,
Credentials: noiseCreds,
Passcode: *passcode,
}
srv, err := vpn.NewServer(srvCfg, log)
if err != nil {
Expand Down
19 changes: 19 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6 h1:Apvc
github.com/AudriusButkevicius/pfilter v0.0.0-20190627213056-c55ef6137fc6/go.mod h1:1N0EEx/irz4B1qV17wW82TFbjQrE7oX316Cki6eDY0Q=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/SkycoinProject/dmsg v0.0.0-20200306152741-acee74fa4514/go.mod h1:DzykXMLlx6Fx0fGjZsCIRas/MIvxW8DZpmDA6f2nCRk=
github.com/SkycoinProject/dmsg v0.2.0/go.mod h1:MiX+UG/6fl3g+9rS13/fq7BwUQ2eOlg1yOBOnNf6J6A=
github.com/SkycoinProject/dmsg v0.2.3 h1:x6Wok/CXnAWdngMQ1q0sOiP81r9G21EeP4jnDfxEEJk=
github.com/SkycoinProject/dmsg v0.2.3/go.mod h1:qLrCsFiggHokPHyHH8069v6DawaD16SiUc8ml9W7CEo=
github.com/SkycoinProject/skycoin v0.26.0/go.mod h1:xqPLOKh5B6GBZlGA7B5IJfQmCy7mwimD9NlqxR3gMXo=
github.com/SkycoinProject/skycoin v0.27.0 h1:N3IHxj8ossHOcsxLYOYugT+OaELLncYHJHxbbYLPPmY=
github.com/SkycoinProject/skycoin v0.27.0/go.mod h1:xqPLOKh5B6GBZlGA7B5IJfQmCy7mwimD9NlqxR3gMXo=
github.com/SkycoinProject/skywire-mainnet v0.0.0-20200309204032-14af5342da86/go.mod h1:xuOpE5ZZU2kR39u0tJWtOpak/sJpnEFj1HpTxtyPU/A=
github.com/SkycoinProject/skywire-mainnet v0.2.3 h1:jxSLVPO4oGHt7m0PoBR5yVTuz49CV4Z3JM4RgqkDi+A=
github.com/SkycoinProject/skywire-mainnet v0.2.3/go.mod h1:V4GfusVnax+suHTKdrz7ToC0yqsevtMxqyKLcDVnWSs=
github.com/SkycoinProject/yamux v0.0.0-20191213015001-a36efeefbf6a h1:6nHCJqh7trsuRcpMC5JmtDukUndn2VC9sY64K6xQ7hQ=
github.com/SkycoinProject/yamux v0.0.0-20191213015001-a36efeefbf6a/go.mod h1:IaE1dxncLQs4RJcQTZPikJfAZY4szH87u2h0lT0SDuM=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
Expand Down Expand Up @@ -47,6 +59,7 @@ github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6 h1:u/UEqS66A5ckRmS4yNp
github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
Expand Down Expand Up @@ -144,8 +157,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
Expand Down Expand Up @@ -180,6 +195,7 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.3.0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/profile v1.5.0 h1:042Buzk+NhDI+DeSAA62RwJL8VAuZUMQZUjCsRz1Mug=
github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand Down Expand Up @@ -275,6 +291,8 @@ github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lL
github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
Expand Down Expand Up @@ -321,6 +339,7 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
2 changes: 1 addition & 1 deletion internal/utclient/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestClientAuth(t *testing.T) {

case fmt.Sprintf("/security/nonces/%s", testPubKey):
if _, err := fmt.Fprintf(w, `{"edge": "%s", "next_nonce": 1}`, testPubKey); err != nil {
t.Errorf("Failed to write nonce response: %w", err)
t.Errorf("Failed to write nonce response: %v", err)
}

default:
Expand Down
33 changes: 9 additions & 24 deletions internal/vpn/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func NewClient(cfg ClientConfig, l logrus.FieldLogger, conn net.Conn) (*Client,

// Serve performs handshake with the server, sets up routing and starts handling traffic.
func (c *Client) Serve() error {
tunIP, tunGateway, encrypt, err := c.shakeHands()
tunIP, tunGateway, err := c.shakeHands()
if err != nil {
return fmt.Errorf("error during client/server handshake: %w", err)
}
Expand Down Expand Up @@ -137,34 +137,20 @@ func (c *Client) Serve() error {
return fmt.Errorf("error routing traffic through TUN %s: %w", tun.Name(), err)
}

rw := io.ReadWriter(c.conn)
if encrypt {
c.log.Infoln("Enabling encryption...")

rw, err = WrapRWWithNoise(c.conn, true, c.cfg.Credentials.PK, c.cfg.Credentials.SK)
if err != nil {
return fmt.Errorf("failed to enable encryption: %w", err)
}

c.log.Infoln("Encryption enabled")
} else {
c.log.Infoln("Encryption disabled")
}

connToTunDoneCh := make(chan struct{})
tunToConnCh := make(chan struct{})
// read all system traffic and pass it to the remote VPN server
go func() {
defer close(connToTunDoneCh)

if _, err := io.Copy(tun, rw); err != nil {
if _, err := io.Copy(tun, c.conn); err != nil {
c.log.WithError(err).Errorf("Error resending traffic from TUN %s to VPN server", tun.Name())
}
}()
go func() {
defer close(tunToConnCh)

if _, err := io.Copy(rw, tun); err != nil {
if _, err := io.Copy(c.conn, tun); err != nil {
c.log.WithError(err).Errorf("Error resending traffic from VPN server to TUN %s", tun.Name())
}
}()
Expand Down Expand Up @@ -302,38 +288,37 @@ func stcpEntitiesFromEnv() ([]net.IP, error) {
return stcpEntities, nil
}

func (c *Client) shakeHands() (TUNIP, TUNGateway net.IP, encrypt bool, err error) {
func (c *Client) shakeHands() (TUNIP, TUNGateway net.IP, err error) {
unavailableIPs, err := LocalNetworkInterfaceIPs()
if err != nil {
return nil, nil, false, fmt.Errorf("error getting unavailable private IPs: %w", err)
return nil, nil, fmt.Errorf("error getting unavailable private IPs: %w", err)
}

unavailableIPs = append(unavailableIPs, c.defaultGateway)

cHello := ClientHello{
UnavailablePrivateIPs: unavailableIPs,
Passcode: c.cfg.Passcode,
EnableEncryption: c.cfg.Credentials.IsValid(),
}

c.log.Debugf("Sending client hello: %v", cHello)

if err := WriteJSON(c.conn, &cHello); err != nil {
return nil, nil, false, fmt.Errorf("error sending client hello: %w", err)
return nil, nil, fmt.Errorf("error sending client hello: %w", err)
}

var sHello ServerHello
if err := ReadJSON(c.conn, &sHello); err != nil {
return nil, nil, false, fmt.Errorf("error reading server hello: %w", err)
return nil, nil, fmt.Errorf("error reading server hello: %w", err)
}

c.log.Debugf("Got server hello: %v", sHello)

if sHello.Status != HandshakeStatusOK {
return nil, nil, false, fmt.Errorf("got status %d (%s) from the server", sHello.Status, sHello.Status)
return nil, nil, fmt.Errorf("got status %d (%s) from the server", sHello.Status, sHello.Status)
}

return sHello.TUNIP, sHello.TUNGateway, sHello.EncryptionEnabled, nil
return sHello.TUNIP, sHello.TUNGateway, nil
}

func ipFromEnv(key string) (net.IP, error) {
Expand Down
3 changes: 0 additions & 3 deletions internal/vpn/client_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,4 @@ package vpn
// ClientConfig is a configuration for VPN client.
type ClientConfig struct {
Passcode string
// TODO: handle this properly
EnableEncryption bool
Credentials NoiseCredentials
}
1 change: 0 additions & 1 deletion internal/vpn/client_hello.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@ import "net"
type ClientHello struct {
UnavailablePrivateIPs []net.IP `json:"unavailable_private_ips"`
Passcode string `json:"passcode"`
EnableEncryption bool `json:"enable_encryption"`
}
43 changes: 12 additions & 31 deletions internal/vpn/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (s *Server) closeConn(conn net.Conn) {
func (s *Server) serveConn(conn net.Conn) {
defer s.closeConn(conn)

tunIP, tunGateway, encrypt, err := s.shakeHands(conn)
tunIP, tunGateway, err := s.shakeHands(conn)
if err != nil {
s.log.WithError(err).Errorf("Error negotiating with client %s", conn.RemoteAddr())
return
Expand All @@ -166,34 +166,19 @@ func (s *Server) serveConn(conn net.Conn) {
return
}

rw := io.ReadWriter(conn)
if encrypt {
s.log.Infoln("Enabling encryption...")

rw, err = WrapRWWithNoise(conn, false, s.cfg.Credentials.PK, s.cfg.Credentials.SK)
if err != nil {
s.log.WithError(err).Errorln("Failed to enable encryption")
return
}

s.log.Infoln("Encryption enabled")
} else {
s.log.Infoln("Encryption disabled")
}

connToTunDoneCh := make(chan struct{})
tunToConnCh := make(chan struct{})
go func() {
defer close(connToTunDoneCh)

if _, err := io.Copy(tun, rw); err != nil {
if _, err := io.Copy(tun, conn); err != nil {
s.log.WithError(err).Errorf("Error resending traffic from VPN client to TUN %s", tun.Name())
}
}()
go func() {
defer close(tunToConnCh)

if _, err := io.Copy(rw, tun); err != nil {
if _, err := io.Copy(conn, tun); err != nil {
s.log.WithError(err).Errorf("Error resending traffic from TUN %s to VPN client", tun.Name())
}
}()
Expand All @@ -205,27 +190,23 @@ func (s *Server) serveConn(conn net.Conn) {
}
}

func (s *Server) shakeHands(conn net.Conn) (tunIP, tunGateway net.IP, encrypt bool, err error) {
func (s *Server) shakeHands(conn net.Conn) (tunIP, tunGateway net.IP, err error) {
var cHello ClientHello
if err := ReadJSON(conn, &cHello); err != nil {
return nil, nil, false, fmt.Errorf("error reading client hello: %w", err)
return nil, nil, fmt.Errorf("error reading client hello: %w", err)
}

s.log.Debugf("Got client hello: %v", cHello)

// enable encryption if credentials are all set and client requested it
encrypt = cHello.EnableEncryption && s.cfg.Credentials.IsValid()
sHello := ServerHello{
EncryptionEnabled: encrypt,
}
var sHello ServerHello

if s.cfg.Passcode != "" && cHello.Passcode != s.cfg.Passcode {
sHello.Status = HandshakeStatusForbidden
if err := WriteJSON(conn, &sHello); err != nil {
s.log.WithError(err).Errorln("Error sending server hello")
}

return nil, nil, false, errors.New("got wrong passcode from client")
return nil, nil, errors.New("got wrong passcode from client")
}

for _, ip := range cHello.UnavailablePrivateIPs {
Expand All @@ -236,7 +217,7 @@ func (s *Server) shakeHands(conn net.Conn) (tunIP, tunGateway net.IP, encrypt bo
s.log.WithError(err).Errorln("Error sending server hello")
}

return nil, nil, false, fmt.Errorf("error reserving IP %s: %w", ip.String(), err)
return nil, nil, fmt.Errorf("error reserving IP %s: %w", ip.String(), err)
}
}

Expand All @@ -247,7 +228,7 @@ func (s *Server) shakeHands(conn net.Conn) (tunIP, tunGateway net.IP, encrypt bo
s.log.WithError(err).Errorln("Error sending server hello")
}

return nil, nil, false, fmt.Errorf("error getting free subnet IP: %w", err)
return nil, nil, fmt.Errorf("error getting free subnet IP: %w", err)
}

subnetOctets, err := fetchIPv4Octets(subnet)
Expand All @@ -257,7 +238,7 @@ func (s *Server) shakeHands(conn net.Conn) (tunIP, tunGateway net.IP, encrypt bo
s.log.WithError(err).Errorln("Error sending server hello")
}

return nil, nil, false, fmt.Errorf("error breaking IP into octets: %w", err)
return nil, nil, fmt.Errorf("error breaking IP into octets: %w", err)
}

// basically IP address comprised of `subnetOctets` items is the IP address of the subnet,
Expand All @@ -278,8 +259,8 @@ func (s *Server) shakeHands(conn net.Conn) (tunIP, tunGateway net.IP, encrypt bo
sHello.TUNGateway = cTUNGateway

if err := WriteJSON(conn, &sHello); err != nil {
return nil, nil, false, fmt.Errorf("error finishing hadnshake: error sending server hello: %w", err)
return nil, nil, fmt.Errorf("error finishing hadnshake: error sending server hello: %w", err)
}

return sTUNIP, sTUNGateway, encrypt, nil
return sTUNIP, sTUNGateway, nil
}
3 changes: 1 addition & 2 deletions internal/vpn/server_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ package vpn

// ServerConfig is a configuration for VPN server.
type ServerConfig struct {
Passcode string
Credentials NoiseCredentials
Passcode string
}
7 changes: 3 additions & 4 deletions internal/vpn/server_hello.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import "net"

// ServerHello is a message sent by server during the Client/Server handshake.
type ServerHello struct {
Status HandshakeStatus `json:"status"`
EncryptionEnabled bool `json:"encryption_enabled"`
TUNIP net.IP `json:"tun_ip"`
TUNGateway net.IP `json:"tun_gateway"`
Status HandshakeStatus `json:"status"`
TUNIP net.IP `json:"tun_ip"`
TUNGateway net.IP `json:"tun_gateway"`
}
9 changes: 3 additions & 6 deletions pkg/app/appnet/mock_networker.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 794e80a

Please sign in to comment.