connect to ext clients using proxy

This commit is contained in:
Abhishek Kondur
2022-11-26 22:40:11 +05:30
parent d0d9bc5ecd
commit c4ef546cd0
5 changed files with 177 additions and 232 deletions

View File

@@ -172,8 +172,7 @@ func (m *ManagerAction) processPayload() (*wg.WGIface, error) {
var ok bool
if wgProxyConf, ok = common.WgIFaceMap[m.Payload.InterfaceName]; !ok {
for i := len(m.Payload.Peers) - 1; i >= 0; i-- {
if !m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].Proxy &&
!m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].IsAttachedExtClient {
if !m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].Proxy {
log.Println("-----------> skipping peer, proxy is off: ", m.Payload.Peers[i].PublicKey)
if err := wgIface.Update(m.Payload.Peers[i], false); err != nil {
log.Println("falied to update peer: ", err)
@@ -181,11 +180,6 @@ func (m *ManagerAction) processPayload() (*wg.WGIface, error) {
m.Payload.Peers = append(m.Payload.Peers[:i], m.Payload.Peers[i+1:]...)
continue
}
if m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].IsAttachedExtClient {
if err := wgIface.Update(m.Payload.Peers[i], false); err != nil {
log.Println("falied to update peer: ", err)
}
}
}
return wgIface, nil
}
@@ -212,16 +206,7 @@ func (m *ManagerAction) processPayload() (*wg.WGIface, error) {
for i := len(m.Payload.Peers) - 1; i >= 0; i-- {
if currentPeer, ok := wgProxyConf.PeerMap[m.Payload.Peers[i].PublicKey.String()]; ok {
// handles ext clients
if common.IsIngressGateway && m.Payload.PeerMap[m.Payload.Peers[i].PublicKey.String()].IsAttachedExtClient {
// check if sniffer already exists otherwise start one
if _, ok := common.ExtClientsWaitTh[m.Payload.Peers[i].PublicKey.String()]; ok {
log.Println("Ext client th already exists....,removing")
m.Payload.Peers = append(m.Payload.Peers[:i], m.Payload.Peers[i+1:]...)
}
if currentPeer.Config.IsAttachedExtClient {
continue
}
// check if proxy is off for the peer
@@ -307,12 +292,22 @@ func (m *ManagerAction) processPayload() (*wg.WGIface, error) {
// sync peer map with new update
for _, currPeerI := range wgProxyConf.PeerMap {
if _, ok := m.Payload.PeerMap[currPeerI.Config.Key]; !ok {
if currPeerI.Config.IsAttachedExtClient {
log.Println("------> Deleting ExtClient Watch Thread: ", currPeerI.Config.Key)
if val, ok := common.ExtClientsWaitTh[currPeerI.Config.Key]; ok {
val.CancelFunc()
delete(common.ExtClientsWaitTh, currPeerI.Config.Key)
}
log.Println("-----> Deleting Ext Client from Src Ip Map: ", currPeerI.Config.Key)
delete(common.ExtSourceIpMap, currPeerI.Proxy.Config.PeerConf.Endpoint.String())
}
currPeerI.Proxy.Cancel()
// delete peer from interface
log.Println("CurrPeer Not Found, Deleting Peer from Interface: ", currPeerI.Config.Key)
if err := wgIface.RemovePeer(currPeerI.Config.Key); err != nil {
log.Println("failed to remove peer: ", currPeerI.Config.Key, err)
}
delete(common.PeerKeyHashMap, fmt.Sprintf("%x", md5.Sum([]byte(currPeerI.Config.Key))))
delete(wgProxyConf.PeerMap, currPeerI.Config.Key)
}
@@ -322,21 +317,6 @@ func (m *ManagerAction) processPayload() (*wg.WGIface, error) {
common.WgIFaceMap[m.Payload.InterfaceName] = wgProxyConf
// if peers, ok := common.WgIFaceMap[iface]; ok {
// log.Println("########------------> CLEANING UP: ", iface)
// for _, peerI := range peers {
// peerI.Proxy.Cancel()
// }
// }
// delete(common.WgIFaceMap, iface)
// delete(common.PeerAddrMap, iface)
// if waitThs, ok := common.ExtClientsWaitTh[iface]; ok {
// for _, cancelF := range waitThs {
// cancelF()
// }
// delete(common.ExtClientsWaitTh, iface)
// }
log.Println("CLEANED UP..........")
return wgIface, nil
}
@@ -439,6 +419,7 @@ func (m *ManagerAction) AddInterfaceToProxy() error {
IsAttachedExtClient: peerConf.IsAttachedExtClient,
Endpoint: peer.Endpoint,
}
common.ExtSourceIpMap[peer.Endpoint.String()] = common.RemotePeer{
Interface: wgInterface.Name,
PeerKey: peer.PublicKey.String(),

View File

@@ -2,87 +2,30 @@ package packet
import (
"bytes"
"crypto/hmac"
"crypto/subtle"
"encoding/base64"
"encoding/binary"
"encoding/hex"
"errors"
"hash"
"log"
"net"
"time"
"github.com/gravitl/netmaker/nm-proxy/wg"
"github.com/gravitl/netmaker/nm-proxy/common"
"golang.org/x/crypto/blake2s"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/curve25519"
"golang.org/x/crypto/poly1305"
"golang.zx2c4.com/wireguard/tai64n"
)
var (
InitialChainKey [blake2s.Size]byte
InitialHash [blake2s.Size]byte
ZeroNonce [chacha20poly1305.NonceSize]byte
)
func init() {
InitialChainKey = blake2s.Sum256([]byte(NoiseConstruction))
mixHash(&InitialHash, &InitialChainKey, []byte(WGIdentifier))
}
func mixKey(dst, c *[blake2s.Size]byte, data []byte) {
KDF1(dst, c[:], data)
}
func mixHash(dst, h *[blake2s.Size]byte, data []byte) {
hash, _ := blake2s.New256(nil)
hash.Write(h[:])
hash.Write(data)
hash.Sum(dst[:0])
hash.Reset()
}
func HMAC1(sum *[blake2s.Size]byte, key, in0 []byte) {
mac := hmac.New(func() hash.Hash {
h, _ := blake2s.New256(nil)
return h
}, key)
mac.Write(in0)
mac.Sum(sum[:0])
}
func HMAC2(sum *[blake2s.Size]byte, key, in0, in1 []byte) {
mac := hmac.New(func() hash.Hash {
h, _ := blake2s.New256(nil)
return h
}, key)
mac.Write(in0)
mac.Write(in1)
mac.Sum(sum[:0])
}
func KDF1(t0 *[blake2s.Size]byte, key, input []byte) {
HMAC1(t0, key, input)
HMAC1(t0, t0[:], []byte{0x1})
}
const (
NoiseConstruction = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
WGIdentifier = "WireGuard v1 zx2c4 Jason@zx2c4.com"
WGLabelMAC1 = "mac1----"
WGLabelCookie = "cookie--"
)
const (
MessageInitiationType = 1
MessageResponseType = 2
MessageCookieReplyType = 3
MessageTransportType = 4
)
const (
NoisePublicKeySize = 32
NoisePrivateKeySize = 32
NoisePresharedKeySize = 32
)
type (
NoisePublicKey [NoisePublicKeySize]byte
NoisePrivateKey [NoisePrivateKeySize]byte
NoisePresharedKey [NoisePresharedKeySize]byte
NoiseNonce uint64 // padded to 12-bytes
)
type MessageInitiation struct {
Type uint32
@@ -94,54 +37,7 @@ type MessageInitiation struct {
MAC2 [blake2s.Size128]byte
}
var (
InitialChainKey [blake2s.Size]byte
InitialHash [blake2s.Size]byte
ZeroNonce [chacha20poly1305.NonceSize]byte
)
func KDF2(t0, t1 *[blake2s.Size]byte, key, input []byte) {
var prk [blake2s.Size]byte
HMAC1(&prk, key, input)
HMAC1(t0, prk[:], []byte{0x1})
HMAC2(t1, prk[:], t0[:], []byte{0x2})
setZero(prk[:])
}
func setZero(arr []byte) {
for i := range arr {
arr[i] = 0
}
}
func isZero(val []byte) bool {
acc := 1
for _, b := range val {
acc &= subtle.ConstantTimeByteEq(b, 0)
}
return acc == 1
}
func uapiCfg(cfg ...string) string {
if len(cfg)%2 != 0 {
panic("odd number of args to uapiReader")
}
buf := new(bytes.Buffer)
for i, s := range cfg {
buf.WriteString(s)
sep := byte('\n')
if i%2 == 0 {
sep = '='
}
buf.WriteByte(sep)
}
return buf.String()
}
func sharedSecret(sk *NoisePrivateKey, pk NoisePublicKey) (ss [NoisePublicKeySize]byte) {
apk := (*[NoisePublicKeySize]byte)(&pk)
ask := (*[NoisePrivateKeySize]byte)(sk)
curve25519.ScalarMult(&ss, ask, apk)
return ss
}
func ConsumeHandshakeMsg(buf []byte, devicePubKey NoisePublicKey, devicePrivKey NoisePrivateKey) (string, error) {
func ConsumeHandshakeInitiationMsg(initiator bool, buf []byte, src *net.UDPAddr, devicePubKey NoisePublicKey, devicePrivKey NoisePrivateKey) error {
var (
hash [blake2s.Size]byte
@@ -153,13 +49,13 @@ func ConsumeHandshakeMsg(buf []byte, devicePubKey NoisePublicKey, devicePrivKey
err = binary.Read(reader, binary.LittleEndian, &msg)
if err != nil {
log.Println("Failed to decode initiation message")
return "", err
return err
}
if msg.Type != MessageInitiationType {
return "", errors.New("not handshake initiate message")
return errors.New("not handshake initiation message")
}
log.Println("-----> HandSHAKE MESSAGE")
log.Println("-----> ConsumeHandshakeInitiationMsg, Intitator: ", initiator)
mixHash(&hash, &InitialHash, devicePubKey[:])
mixHash(&hash, &hash, msg.Ephemeral[:])
mixKey(&chainKey, &InitialChainKey, msg.Ephemeral[:])
@@ -169,79 +65,21 @@ func ConsumeHandshakeMsg(buf []byte, devicePubKey NoisePublicKey, devicePrivKey
var key [chacha20poly1305.KeySize]byte
ss := sharedSecret(&devicePrivKey, msg.Ephemeral)
if isZero(ss[:]) {
return "", errors.New("no secret")
return errors.New("no secret")
}
KDF2(&chainKey, &key, chainKey[:], ss[:])
aead, _ := chacha20poly1305.New(key[:])
_, err = aead.Open(peerPK[:0], ZeroNonce[:], msg.Static[:], hash[:])
if err != nil {
return "", err
}
setZero(hash[:])
setZero(chainKey[:])
return base64.StdEncoding.EncodeToString(peerPK[:]), nil
}
func loadExactHex(dst []byte, src string) error {
slice, err := hex.DecodeString(src)
if err != nil {
return err
}
if len(slice) != len(dst) {
return errors.New("hex string does not fit the slice")
log.Println("--------> Got HandShake from peer: ", base64.StdEncoding.EncodeToString(peerPK[:]), src)
if val, ok := common.ExtClientsWaitTh[base64.StdEncoding.EncodeToString(peerPK[:])]; ok {
val.CommChan <- src
time.Sleep(time.Second * 3)
}
copy(dst, slice)
setZero(hash[:])
setZero(chainKey[:])
return nil
}
func (key NoisePrivateKey) IsZero() bool {
var zero NoisePrivateKey
return key.Equals(zero)
}
func (key NoisePrivateKey) Equals(tar NoisePrivateKey) bool {
return subtle.ConstantTimeCompare(key[:], tar[:]) == 1
}
func (key *NoisePrivateKey) FromHex(src string) (err error) {
err = loadExactHex(key[:], src)
key.clamp()
return
}
func (key *NoisePrivateKey) FromMaybeZeroHex(src string) (err error) {
err = loadExactHex(key[:], src)
if key.IsZero() {
return
}
key.clamp()
return
}
func (sk *NoisePrivateKey) clamp() {
sk[0] &= 248
sk[31] = (sk[31] & 127) | 64
}
func (key *NoisePublicKey) FromHex(src string) error {
return loadExactHex(key[:], src)
}
func (key NoisePublicKey) IsZero() bool {
var zero NoisePublicKey
return key.Equals(zero)
}
func (key NoisePublicKey) Equals(tar NoisePublicKey) bool {
return subtle.ConstantTimeCompare(key[:], tar[:]) == 1
}
func (key *NoisePresharedKey) FromHex(src string) error {
return loadExactHex(key[:], src)
}
func GetDeviceKeys(ifaceName string) (NoisePrivateKey, NoisePublicKey, error) {
wgPrivKey := wg.GetWgIfacePrivKey(ifaceName)
wgPubKey := wg.GetWgIfacePubKey(ifaceName)
return wgPrivKey, wgPubKey, nil
}

98
nm-proxy/packet/utils.go Normal file
View File

@@ -0,0 +1,98 @@
package packet
import (
"crypto/hmac"
"crypto/subtle"
"hash"
"github.com/gravitl/netmaker/nm-proxy/wg"
"golang.org/x/crypto/blake2s"
"golang.org/x/crypto/curve25519"
)
const (
MessageInitiationType = 1
NoisePublicKeySize = 32
NoisePrivateKeySize = 32
NoiseConstruction = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"
WGIdentifier = "WireGuard v1 zx2c4 Jason@zx2c4.com"
WGLabelMAC1 = "mac1----"
WGLabelCookie = "cookie--"
)
func mixKey(dst, c *[blake2s.Size]byte, data []byte) {
KDF1(dst, c[:], data)
}
func mixHash(dst, h *[blake2s.Size]byte, data []byte) {
hash, _ := blake2s.New256(nil)
hash.Write(h[:])
hash.Write(data)
hash.Sum(dst[:0])
hash.Reset()
}
func HMAC1(sum *[blake2s.Size]byte, key, in0 []byte) {
mac := hmac.New(func() hash.Hash {
h, _ := blake2s.New256(nil)
return h
}, key)
mac.Write(in0)
mac.Sum(sum[:0])
}
func HMAC2(sum *[blake2s.Size]byte, key, in0, in1 []byte) {
mac := hmac.New(func() hash.Hash {
h, _ := blake2s.New256(nil)
return h
}, key)
mac.Write(in0)
mac.Write(in1)
mac.Sum(sum[:0])
}
func KDF1(t0 *[blake2s.Size]byte, key, input []byte) {
HMAC1(t0, key, input)
HMAC1(t0, t0[:], []byte{0x1})
}
func KDF2(t0, t1 *[blake2s.Size]byte, key, input []byte) {
var prk [blake2s.Size]byte
HMAC1(&prk, key, input)
HMAC1(t0, prk[:], []byte{0x1})
HMAC2(t1, prk[:], t0[:], []byte{0x2})
setZero(prk[:])
}
func setZero(arr []byte) {
for i := range arr {
arr[i] = 0
}
}
func isZero(val []byte) bool {
acc := 1
for _, b := range val {
acc &= subtle.ConstantTimeByteEq(b, 0)
}
return acc == 1
}
func GetDeviceKeys(ifaceName string) (NoisePrivateKey, NoisePublicKey, error) {
wgPrivKey := wg.GetWgIfacePrivKey(ifaceName)
wgPubKey := wg.GetWgIfacePubKey(ifaceName)
return wgPrivKey, wgPubKey, nil
}
type (
NoisePublicKey [NoisePublicKeySize]byte
NoisePrivateKey [NoisePrivateKeySize]byte
)
func sharedSecret(sk *NoisePrivateKey, pk NoisePublicKey) (ss [NoisePublicKeySize]byte) {
apk := (*[NoisePublicKeySize]byte)(&pk)
ask := (*[NoisePrivateKeySize]byte)(sk)
curve25519.ScalarMult(&ss, ask, apk)
return ss
}

View File

@@ -69,6 +69,34 @@ func (p *Proxy) ProxyToRemote() {
if err != nil {
log.Println("failed to process pkt before sending: ", err)
}
} else {
// unknown peer to proxy -> check if extclient and handle it
// consume handshake message for ext clients
// msgType := binary.LittleEndian.Uint32(buf[:n])
// switch msgType {
// case models.MessageInitiationType:
// devPriv, devPubkey, err := packet.GetDeviceKeys(common.InterfaceName)
// if err == nil {
// err := packet.ConsumeHandshakeInitiationMsg(true, buf[:n], p.RemoteConn, devPubkey, devPriv)
// if err != nil {
// log.Println("---------> @@@ failed to decode HS: ", err)
// }
// } else {
// log.Println("failed to get device keys: ", err)
// }
// case models.MessageResponseType:
// devPriv, devPubkey, err := packet.GetDeviceKeys(common.InterfaceName)
// if err == nil {
// err := packet.ConsumeMessageResponse(true, buf[:n], p.RemoteConn, devPubkey, devPriv)
// if err != nil {
// log.Println("---------> @@@ failed to decode HS: ", err)
// }
// } else {
// log.Println("failed to get device keys: ", err)
// }
// }
}
log.Printf("PROXING TO REMOTE!!!---> %s >>>>> %s >>>>> %s [[ SrcPeerHash: %s, DstPeerHash: %s ]]\n",

View File

@@ -2,6 +2,7 @@ package server
import (
"context"
"encoding/binary"
"fmt"
"log"
"net"
@@ -60,12 +61,11 @@ func (p *ProxyServer) Listen(ctx context.Context) {
log.Println("RECV ERROR: ", err)
continue
}
orgN := n
//go func(buffer []byte, source *net.UDPAddr, n int) {
origBufferLen := n
var srcPeerKeyHash, dstPeerKeyHash string
n, srcPeerKeyHash, dstPeerKeyHash = packet.ExtractInfo(buffer, n)
log.Printf("--------> RECV PKT , [SRCKEYHASH: %s], SourceIP: [%s] \n", srcPeerKeyHash, source.IP.String())
//log.Printf("--------> RECV PKT , [SRCKEYHASH: %s], SourceIP: [%s] \n", srcPeerKeyHash, source.IP.String())
if _, ok := common.WgIfaceKeyMap[dstPeerKeyHash]; !ok {
// if common.IsIngressGateway {
@@ -139,7 +139,7 @@ func (p *ProxyServer) Listen(ctx context.Context) {
log.Printf("PROXING TO LOCAL!!!---> %s <<<< %s <<<<<<<< %s [[ RECV PKT [SRCKEYHASH: %s], [DSTKEYHASH: %s], SourceIP: [%s] ]]\n",
peerI.Proxy.LocalConn.RemoteAddr(), peerI.Proxy.LocalConn.LocalAddr(),
fmt.Sprintf("%s:%d", source.IP.String(), source.Port), srcPeerKeyHash, dstPeerKeyHash, source.IP.String())
_, err = peerI.Proxy.LocalConn.Write(buffer[:orgN])
_, err = peerI.Proxy.LocalConn.Write(buffer[:origBufferLen])
if err != nil {
log.Println("Failed to proxy to Wg local interface: ", err)
//continue
@@ -149,22 +149,22 @@ func (p *ProxyServer) Listen(ctx context.Context) {
}
}
}
// unknown peer to proxy -> check if extclient and handle it
// consume handshake message for ext clients
msgType := binary.LittleEndian.Uint32(buffer[:4])
switch msgType {
case packet.MessageInitiationType:
devPriv, devPubkey, err := packet.GetDeviceKeys(common.InterfaceName)
if err == nil {
peerPubKey, err := packet.ConsumeHandshakeMsg(buffer[:orgN], devPubkey, devPriv)
err := packet.ConsumeHandshakeInitiationMsg(false, buffer[:origBufferLen], source, devPubkey, devPriv)
if err != nil {
log.Println("---------> @@@ failed to decode HS: ", err)
} else {
log.Println("--------> Got HandShake from peer: ", peerPubKey, source)
if val, ok := common.ExtClientsWaitTh[peerPubKey]; ok {
val.CommChan <- source
}
}
} else {
log.Println("failed to get device keys: ", err)
}
}
}