diff --git a/cmd/indra/seed.go b/cmd/indra/seed.go index 3ed48140..34f7153d 100644 --- a/cmd/indra/seed.go +++ b/cmd/indra/seed.go @@ -6,6 +6,7 @@ import ( "git-indra.lan/indra-labs/indra/pkg/interrupt" log2 "git-indra.lan/indra-labs/indra/pkg/proc/log" "git-indra.lan/indra-labs/indra/pkg/rpc" + "git-indra.lan/indra-labs/indra/pkg/rpc/client" "git-indra.lan/indra-labs/indra/pkg/seed" "github.com/multiformats/go-multiaddr" "github.com/spf13/cobra" @@ -85,6 +86,8 @@ var seedCmd = &cobra.Command{ log.I.Ln("rpc server is ready") } + client.Run(ctx) + // // P2P // diff --git a/pkg/rpc/client/client.go b/pkg/rpc/client/client.go index 59163dc0..603b2039 100644 --- a/pkg/rpc/client/client.go +++ b/pkg/rpc/client/client.go @@ -2,101 +2,64 @@ package client import ( "context" - "git-indra.lan/indra-labs/indra/pkg/rpc" - "github.com/multiformats/go-multiaddr" "github.com/tutorialedge/go-grpc-tutorial/chat" "golang.zx2c4.com/wireguard/conn" "golang.zx2c4.com/wireguard/device" "golang.zx2c4.com/wireguard/tun" "golang.zx2c4.com/wireguard/tun/netstack" "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "net" "net/netip" + "os" "strconv" ) var ( - DefaultClientIPAddr = netip.MustParseAddr("192.168.37.2") - DefaultServerIPAddr = netip.MustParseAddr("192.168.37.1") -) - -type Peer struct { - Endpoint multiaddr.Multiaddr - PublicKey *rpc.RPCPublicKey - PreSharedKey rpc.RPCPrivateKey - KeepAliveInterval uint8 -} - -type ClientConfig struct { - Key rpc.RPCPrivateKey - Peer *Peer -} - -var ( - DefaultClientConfig = &ClientConfig{ - Key: rpc.DecodePrivateKey("Aj9CfbE1pXEVxPfjSaTwdY3B4kYHbwsTSyT3nrc34ATN"), - Peer: &Peer{ - Endpoint: multiaddr.StringCast("/ip4/127.0.0.1/udp/18222"), - PublicKey: rpc.DecodePublicKey("G52UmsQpUmN2zFMkJaP9rwCvqQJzi1yHKA9RTrLJTk9f"), - KeepAliveInterval: 5, - }, - } -) - -type RPCClient struct { - device *device.Device + tunnel tun.Device network *netstack.Net -} + dev *device.Device +) -func (r *RPCClient) Start() { - r.device.Up() -} +func getNetworkInstance(options *dialOptions) (err error) { -func (rpc *RPCClient) Stop() { - rpc.device.Close() -} - -func NewClient(config *ClientConfig) (*RPCClient, error) { - - var err error - var r RPCClient - - var tunnel tun.Device - - if tunnel, r.network, err = netstack.CreateNetTUN([]netip.Addr{DefaultClientIPAddr}, []netip.Addr{}, 1420); check(err) { - return nil, err + if tunnel, network, err = netstack.CreateNetTUN([]netip.Addr{netip.MustParseAddr(options.peerRPCIP)}, []netip.Addr{}, 1420); check(err) { + return } - r.device = device.NewDevice(tunnel, conn.NewDefaultBind(), device.NewLogger(device.LogLevelError, "client ")) + dev = device.NewDevice(tunnel, conn.NewDefaultBind(), device.NewLogger(device.LogLevelVerbose, "client ")) - r.device.SetPrivateKey(config.Key.AsDeviceKey()) + dev.SetPrivateKey(options.key.AsDeviceKey()) deviceConf := "" + - "public_key=" + config.Peer.PublicKey.HexString() + "\n" + + "public_key=" + options.peerPubKey.HexString() + "\n" + "endpoint=0.0.0.0:18222" + "\n" + - "allowed_ip=" + DefaultServerIPAddr.String() + "/32\n" + - "persistent_keepalive_interval=" + strconv.Itoa(int(config.Peer.KeepAliveInterval)) + "\n" + "allowed_ip=" + options.peerRPCIP + "/32\n" + + "persistent_keepalive_interval=" + strconv.Itoa(options.keepAliveInterval) + "\n" - if err = r.device.IpcSet(deviceConf); check(err) { - return nil, err + if err = dev.IpcSet(deviceConf); check(err) { + return } + return nil +} + +func Run(ctx context.Context) { + + var err error var conn *grpc.ClientConn - //conn, err = grpc.Dial( - // "unix:///tmp/indra.sock", - // grpc.WithBlock(), - // grpc.WithTransportCredentials(insecure.NewCredentials()), + conn, err = Dial("unix:///tmp/indra.sock") + + //conn, err = DialContext(ctx, + // "noise://0.0.0.0:18222", + // WithPrivateKey("Aj9CfbE1pXEVxPfjSaTwdY3B4kYHbwsTSyT3nrc34ATN"), + // WithPeer("G52UmsQpUmN2zFMkJaP9rwCvqQJzi1yHKA9RTrLJTk9f"), + // WithKeepAliveInterval(5), //) - conn, err = grpc.DialContext(context.Background(), - DefaultServerIPAddr.String()+":80", - grpc.WithBlock(), - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithContextDialer(func(ctx context.Context, address string) (net.Conn, error) { - return r.network.DialContext(ctx, "tcp4", address) - })) + if err != nil { + check(err) + os.Exit(1) + } c := chat.NewChatServiceClient(conn) @@ -107,6 +70,4 @@ func NewClient(config *ClientConfig) (*RPCClient, error) { } log.I.F(response.Body) - - return &r, nil } diff --git a/pkg/rpc/client/dailer_options.go b/pkg/rpc/client/dailer_options.go new file mode 100644 index 00000000..0e225ad4 --- /dev/null +++ b/pkg/rpc/client/dailer_options.go @@ -0,0 +1,65 @@ +package client + +import "git-indra.lan/indra-labs/indra/pkg/rpc" + +// dialOptions configure a Dial call. dialOptions are set by the DialOption +// values passed to Dial. +type dialOptions struct { + key rpc.RPCPrivateKey + peerPubKey rpc.RPCPublicKey + peerRPCIP string + keepAliveInterval int +} + +// DialOption configures how we set up the connection. +type DialOption interface { + apply(*dialOptions) +} + +// funcDialOption wraps a function that modifies dialOptions into an +// implementation of the DialOption interface. +type funcDialOption struct { + f func(*dialOptions) +} + +func (fdo *funcDialOption) apply(do *dialOptions) { + fdo.f(do) +} + +func newFuncDialOption(f func(*dialOptions)) *funcDialOption { + return &funcDialOption{ + f: f, + } +} + +type joinDialOption struct { + opts []DialOption +} + +func (jdo *joinDialOption) apply(do *dialOptions) { + for _, opt := range jdo.opts { + opt.apply(do) + } +} + +func newJoinDialOption(opts ...DialOption) DialOption { + return &joinDialOption{opts: opts} +} + +func WithKeepAliveInterval(seconds int) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.keepAliveInterval = seconds + }) +} + +func WithPeer(pubKey string) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.peerPubKey = rpc.DecodePublicKey(pubKey) + }) +} + +func WithPrivateKey(key string) DialOption { + return newFuncDialOption(func(o *dialOptions) { + o.key = rpc.DecodePrivateKey(key) + }) +} diff --git a/pkg/rpc/client/dialer.go b/pkg/rpc/client/dialer.go new file mode 100644 index 00000000..99534fce --- /dev/null +++ b/pkg/rpc/client/dialer.go @@ -0,0 +1,47 @@ +package client + +import ( + "context" + "errors" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "net" + "strings" +) + +var ( + rpcEndpoint string = "192.168.37.1:80" +) + +func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *grpc.ClientConn, err error) { + + if strings.HasPrefix(target, "unix://") { + return grpc.Dial( + target, + grpc.WithTransportCredentials(insecure.NewCredentials()), + ) + } + + if !strings.HasPrefix(target, "noise://") { + return nil, errors.New("Unsupported protocol. Only unix:// or noise://") + } + + dialOpts := &dialOptions{peerRPCIP: "192.168.37.2"} + + for _, opt := range opts { + opt.apply(dialOpts) + } + + getNetworkInstance(dialOpts) + + return grpc.DialContext(ctx, + rpcEndpoint, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithContextDialer(func(ctx context.Context, address string) (net.Conn, error) { + return network.DialContext(ctx, "tcp4", address) + })) +} + +func Dial(target string, opts ...DialOption) (conn *grpc.ClientConn, err error) { + return DialContext(context.Background(), target, opts...) +} diff --git a/pkg/rpc/cmd.go b/pkg/rpc/cmd.go index 98104d2f..fa4f95fb 100644 --- a/pkg/rpc/cmd.go +++ b/pkg/rpc/cmd.go @@ -58,12 +58,17 @@ func configureTunnelKey() { func configureTunnelPort() { if viper.GetUint16(tunPortFlag) != NullPort { + + tunnelPort = int(viper.GetUint16(tunPortFlag)) + return } log.I.Ln("rpc tunnel port not provided, generating a random one.") viper.Set(tunPortFlag, genRandomPort(10000)) + + tunnelPort = int(viper.GetUint16(tunPortFlag)) } func configurePeerWhitelist() { diff --git a/pkg/rpc/keys.go b/pkg/rpc/keys.go index d7ae1c5b..1020876e 100644 --- a/pkg/rpc/keys.go +++ b/pkg/rpc/keys.go @@ -101,11 +101,11 @@ func (sk *RPCPublicKey) Decode(key string) { copy(sk[:], base58.Decode(key)) } -func DecodePublicKey(key string) *RPCPublicKey { +func DecodePublicKey(key string) RPCPublicKey { var pk RPCPublicKey pk.Decode(key) - return &pk + return pk }