Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route encryption #444

Merged
merged 13 commits into from
Aug 7, 2020
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