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

Feat/ip from server #272

Merged
merged 14 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/dmsg/dmsg.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
dmsgsocks "github.com/skycoin/dmsg/cmd/dmsg-socks5/commands"
dmsgcurl "github.com/skycoin/dmsg/cmd/dmsgcurl/commands"
dmsghttp "github.com/skycoin/dmsg/cmd/dmsghttp/commands"
dmsgip "github.com/skycoin/dmsg/cmd/dmsgip/commands"
dmsgptycli "github.com/skycoin/dmsg/cmd/dmsgpty-cli/commands"
dmsgptyhost "github.com/skycoin/dmsg/cmd/dmsgpty-host/commands"
dmsgptyui "github.com/skycoin/dmsg/cmd/dmsgpty-ui/commands"
Expand All @@ -35,6 +36,7 @@ func init() {
dmsgcurl.RootCmd,
dmsgweb.RootCmd,
dmsgsocks.RootCmd,
dmsgip.RootCmd,
)
dmsgdisc.RootCmd.Use = "disc"
dmsgserver.RootCmd.Use = "server"
Expand All @@ -45,6 +47,7 @@ func init() {
dmsgptycli.RootCmd.Use = "cli"
dmsgptyhost.RootCmd.Use = "host"
dmsgptyui.RootCmd.Use = "ui"
dmsgip.RootCmd.Use = "ip"

var helpflag bool
RootCmd.SetUsageTemplate(help)
Expand Down
23 changes: 23 additions & 0 deletions cmd/dmsgip/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@



```


┌┬┐┌┬┐┌─┐┌─┐ ┬┌─┐
│││││└─┐│ ┬ │├─┘
─┴┘┴ ┴└─┘└─┘ ┴┴
DMSG ip utility

Usage:
dmsgip

Flags:
-c, --dmsg-disc string dmsg discovery url default:
http://dmsgd.skywire.dev
-l, --loglvl string [ debug | warn | error | fatal | panic | trace | info ] (default "fatal")
-s, --sk cipher.SecKey a random key is generated if unspecified
(default 0000000000000000000000000000000000000000000000000000000000000000)
-v, --version version for dmsgip

```
133 changes: 133 additions & 0 deletions cmd/dmsgip/commands/dmsgip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Package commands cmd/dmsgcurl/commands/dmsgcurl.go
package commands

import (
"context"
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"strings"

"github.com/skycoin/skywire-utilities/pkg/buildinfo"
"github.com/skycoin/skywire-utilities/pkg/cipher"
"github.com/skycoin/skywire-utilities/pkg/cmdutil"
"github.com/skycoin/skywire-utilities/pkg/logging"
"github.com/skycoin/skywire-utilities/pkg/skyenv"
"github.com/spf13/cobra"

"github.com/skycoin/dmsg/pkg/disc"
"github.com/skycoin/dmsg/pkg/dmsg"
)

var (
dmsgDisc string
sk cipher.SecKey
logLvl string
dmsgServers []string
)

func init() {
RootCmd.Flags().StringVarP(&dmsgDisc, "dmsg-disc", "c", "", "dmsg discovery url default:\n"+skyenv.DmsgDiscAddr)
RootCmd.Flags().StringVarP(&logLvl, "loglvl", "l", "fatal", "[ debug | warn | error | fatal | panic | trace | info ]\033[0m")
if os.Getenv("DMSGIP_SK") != "" {
sk.Set(os.Getenv("DMSGIP_SK")) //nolint
}
RootCmd.Flags().StringSliceVarP(&dmsgServers, "srv", "d", []string{}, "dmsg server public keys\n\r")
RootCmd.Flags().VarP(&sk, "sk", "s", "a random key is generated if unspecified\n\r")
}

// RootCmd containsa the root dmsgcurl command
var RootCmd = &cobra.Command{
Use: func() string {
return strings.Split(filepath.Base(strings.ReplaceAll(strings.ReplaceAll(fmt.Sprintf("%v", os.Args), "[", ""), "]", "")), " ")[0]
}(),
Short: "DMSG ip utility",
Long: `
┌┬┐┌┬┐┌─┐┌─┐ ┬┌─┐
│││││└─┐│ ┬ │├─┘
─┴┘┴ ┴└─┘└─┘ ┴┴
DMSG ip utility`,
SilenceErrors: true,
SilenceUsage: true,
DisableSuggestions: true,
DisableFlagsInUseLine: true,
Version: buildinfo.Version(),
PreRun: func(cmd *cobra.Command, args []string) {
if dmsgDisc == "" {
dmsgDisc = skyenv.DmsgDiscAddr
}
},
RunE: func(cmd *cobra.Command, args []string) error {
log := logging.MustGetLogger("dmsgip")

if logLvl != "" {
if lvl, err := logging.LevelFromString(logLvl); err == nil {
logging.SetLevel(lvl)
}
}

var srvs []cipher.PubKey
for _, srv := range dmsgServers {
var pk cipher.PubKey
if err := pk.Set(srv); err != nil {
return fmt.Errorf("failed to parse server public key: %w", err)
}
srvs = append(srvs, pk)
}

ctx, cancel := cmdutil.SignalContext(context.Background(), log)
defer cancel()

pk, err := sk.PubKey()
if err != nil {
pk, sk = cipher.GenerateKeyPair()
}

dmsgC, closeDmsg, err := startDmsg(ctx, log, pk, sk)
if err != nil {
log.WithError(err).Error("failed to start dmsg")
}
defer closeDmsg()

ip, err := dmsgC.LookupIP(ctx, srvs)
if err != nil {
log.WithError(err).Error("failed to lookup IP")
}

fmt.Printf("%v\n", ip)
fmt.Print("\n")
return nil
},
}

func startDmsg(ctx context.Context, log *logging.Logger, pk cipher.PubKey, sk cipher.SecKey) (dmsgC *dmsg.Client, stop func(), err error) {
dmsgC = dmsg.NewClient(pk, sk, disc.NewHTTP(dmsgDisc, &http.Client{}, log), &dmsg.Config{MinSessions: dmsg.DefaultMinSessions})
go dmsgC.Serve(context.Background())

stop = func() {
err := dmsgC.Close()
log.WithError(err).Debug("Disconnected from dmsg network.")
fmt.Printf("\n")
}
log.WithField("public_key", pk.String()).WithField("dmsg_disc", dmsgDisc).
Debug("Connecting to dmsg network...")

select {
case <-ctx.Done():
stop()
return nil, nil, ctx.Err()

case <-dmsgC.Ready():
log.Debug("Dmsg network ready.")
return dmsgC, stop, nil
}
}

// Execute executes root CLI command.
func Execute() {
if err := RootCmd.Execute(); err != nil {
log.Fatal("Failed to execute command: ", err)
}
}
44 changes: 44 additions & 0 deletions cmd/dmsgip/dmsgip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// package main cmd/dmsgcurl/dmsgcurl.go
package main

import (
cc "github.com/ivanpirog/coloredcobra"
"github.com/spf13/cobra"

"github.com/skycoin/dmsg/cmd/dmsgip/commands"
)

func init() {
var helpflag bool
commands.RootCmd.SetUsageTemplate(help)
commands.RootCmd.PersistentFlags().BoolVarP(&helpflag, "help", "h", false, "help for dmsgpty-cli")
commands.RootCmd.SetHelpCommand(&cobra.Command{Hidden: true})
commands.RootCmd.PersistentFlags().MarkHidden("help") //nolint
}

func main() {
cc.Init(&cc.Config{
RootCmd: commands.RootCmd,
Headings: cc.HiBlue + cc.Bold,
Commands: cc.HiBlue + cc.Bold,
CmdShortDescr: cc.HiBlue,
Example: cc.HiBlue + cc.Italic,
ExecName: cc.HiBlue + cc.Bold,
Flags: cc.HiBlue + cc.Bold,
FlagsDescr: cc.HiBlue,
NoExtraNewlines: true,
NoBottomNewline: true,
})

commands.Execute()
}

const help = "Usage:\r\n" +
" {{.UseLine}}{{if .HasAvailableSubCommands}}{{end}} {{if gt (len .Aliases) 0}}\r\n\r\n" +
"{{.NameAndAliases}}{{end}}{{if .HasAvailableSubCommands}}\r\n\r\n" +
"Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand)}}\r\n " +
"{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}\r\n\r\n" +
"Flags:\r\n" +
"{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}\r\n\r\n" +
"Global Flags:\r\n" +
"{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}\r\n\r\n"
73 changes: 72 additions & 1 deletion pkg/dmsg/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,78 @@ func (ce *Client) DialStream(ctx context.Context, addr Addr) (*Stream, error) {
return nil, ErrCannotConnectToDelegated
}

// LookupIP dails to dmsg servers for public IP of the client.
func (ce *Client) LookupIP(ctx context.Context, servers []cipher.PubKey) (myIP net.IP, err error) {

cancellabelCtx, cancel := context.WithCancel(ctx)
defer cancel()

if servers == nil {
entries, err := ce.discoverServers(cancellabelCtx, true)
if err != nil {
return nil, err
}
for _, entry := range entries {
servers = append(servers, entry.Static)
}
}

// Range client's delegated servers.
// See if we are already connected to a delegated server.
for _, srvPK := range servers {
if dSes, ok := ce.clientSession(ce.porter, srvPK); ok {
ip, err := dSes.LookupIP(Addr{PK: dSes.RemotePK(), Port: 1})
if err != nil {
ce.log.WithError(err).WithField("server_pk", srvPK).Warn("Failed to dial server for IP.")
continue
}

// If the client is test client then ignore Public IP check
if ce.conf.ClientType == "test" {
return ip, nil
}

// Check if the IP is public
if !netutil.IsPublicIP(ip) {
return nil, errors.New("received non-public IP address from dmsg server")
}
return ip, nil
}
}

// Range client's delegated servers.
// Attempt to connect to a delegated server.
// And Close it after getting the IP.
for _, srvPK := range servers {
dSes, err := ce.EnsureAndObtainSession(ctx, srvPK)
if err != nil {
continue
}
ip, err := dSes.LookupIP(Addr{PK: dSes.RemotePK(), Port: 1})
if err != nil {
ce.log.WithError(err).WithField("server_pk", srvPK).Warn("Failed to dial server for IP.")
continue
}
err = dSes.Close()
if err != nil {
ce.log.WithError(err).WithField("server_pk", srvPK).Warn("Failed to close session")
}

// If the client is test client then ignore Public IP check
if ce.conf.ClientType == "test" {
return ip, nil
}

// Check if the IP is public
if !netutil.IsPublicIP(ip) {
return nil, errors.New("received non-public IP address from dmsg server")
}
return ip, nil
}

return nil, ErrCannotConnectToDelegated
}

// Session obtains an established session.
func (ce *Client) Session(pk cipher.PubKey) (ClientSession, bool) {
return ce.clientSession(ce.porter, pk)
Expand Down Expand Up @@ -403,7 +475,6 @@ func (ce *Client) EnsureAndObtainSession(ctx context.Context, srvPK cipher.PubKe
if err != nil {
return ClientSession{}, err
}

return ce.dialSession(ctx, srvEntry)
}

Expand Down
44 changes: 44 additions & 0 deletions pkg/dmsg/client_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,50 @@ func (cs *ClientSession) DialStream(dst Addr) (dStr *Stream, err error) {
return dStr, err
}

// LookupIP attempts to dial a stream to the server for the IP address of the client.
func (cs *ClientSession) LookupIP(dst Addr) (myIP net.IP, err error) {
log := cs.log.
WithField("func", "ClientSession.LookupIP").
WithField("dst_addr", cs.rPK)

dStr, err := newInitiatingStream(cs)
if err != nil {
return nil, err
}

// Close stream on failure.
defer func() {
if err != nil {
log.WithError(err).
WithField("close_error", dStr.Close()).
Debug("Stream closed on failure.")
}
}()

// Prepare deadline.
if err = dStr.SetDeadline(time.Now().Add(HandshakeTimeout)); err != nil {
return nil, err
}

// Do stream handshake.
req, err := dStr.writeIPRequest(dst)
if err != nil {
return nil, err
}

myIP, err = dStr.readIPResponse(req)
if err != nil {
return nil, err
}

err = dStr.Close()
if err != nil {
return nil, err
}

return myIP, err
}

// serve accepts incoming streams from remote clients.
func (cs *ClientSession) serve() error {
defer func() {
Expand Down
Loading
Loading