Skip to content
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
38 changes: 33 additions & 5 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,39 @@ var runCmd = &cobra.Command{
var centralCfg state.CentralCfg
file, err := os.ReadFile(centralPath)
if err != nil {
panic(err)
}
err = yaml.Unmarshal(file, &centralCfg)
if err != nil {
panic(err)
if !os.IsNotExist(err) {
panic(err)
}
var nodeCfg state.LocalCfg
file, err = os.ReadFile(nodePath)
if err != nil {
panic(err)
}
err = yaml.Unmarshal(file, &nodeCfg)
if err != nil {
panic(err)
}
if nodeCfg.Dist == nil {
panic("central.yaml not found and node.yaml has no dist config")
}
cfg, err := core.FetchConfig(nodeCfg.Dist.Url, nodeCfg.Dist.Key)
if err != nil {
panic(err)
}
bytes, err := yaml.Marshal(cfg)
if err != nil {
panic(err)
}
err = os.WriteFile(centralPath, bytes, 0700)
if err != nil {
panic(err)
}
centralCfg = *cfg
} else {
err = yaml.Unmarshal(file, &centralCfg)
if err != nil {
panic(err)
}
}

var nodeCfg state.LocalCfg
Expand Down
4 changes: 2 additions & 2 deletions core/nylon.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ func (n *Nylon) Init(s *state.State) error {
}

// check for central config updates
if s.Dist != nil {
for _, repo := range s.Dist.Repos {
if s.CentralCfg.Dist != nil {
for _, repo := range s.CentralCfg.Dist.Repos {
s.Log.Info("config source", "repo", repo)
}
s.Env.RepeatTask(checkForConfigUpdates, state.CentralUpdateDelay)
Expand Down
78 changes: 44 additions & 34 deletions core/nylon_distribution.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,48 +12,58 @@ import (
"gopkg.in/yaml.v3"
)

// fetches and unbundles central config from url
func FetchConfig(repoStr string, key state.NyPublicKey) (*state.CentralCfg, error) {
repo, err := url.Parse(repoStr)
if err != nil {
return nil, fmt.Errorf("failed to parse repo URL %s: %w", repoStr, err)
}
cfgBody := make([]byte, 0)

if repo.Scheme == "file" {
file, err := os.ReadFile(repo.Opaque)
if err != nil {
return nil, fmt.Errorf("failed to read file %s: %w", repo.Opaque, err)
}
cfgBody = file
} else if repo.Scheme == "http" || repo.Scheme == "https" {
res, err := http.Get(repo.String())
if err != nil {
return nil, fmt.Errorf("failed to fetch %s: %w", repo.String(), err)
}
cfgBody, err = io.ReadAll(res.Body)
if err != nil {
res.Body.Close()
return nil, fmt.Errorf("failed to read response from %s: %w", repo.String(), err)
}
err = res.Body.Close()
if err != nil {
return nil, fmt.Errorf("failed to close response from %s: %w", repo.String(), err)
}
}

config, err := state.UnbundleConfig(string(cfgBody), key)
if err != nil {
return nil, fmt.Errorf("failed to unbundle config from %s: %w", repoStr, err)
}
return config, nil
}

// responsible for central config distribution
func checkForConfigUpdates(s *state.State) error {
if s.Dist == nil {
if s.CentralCfg.Dist == nil {
return errors.New("nylon is not configured for automatic config distribution")
}
for _, repoStr := range s.Dist.Repos {
repo, err := url.Parse(repoStr)
if err != nil {
return err
}
for _, repoStr := range s.CentralCfg.Dist.Repos {
e := s.Env
go func() {
go func(repo string) {
err := func() error {
cfgBody := make([]byte, 0)

if repo.Scheme == "file" {
file, err := os.ReadFile(repo.Opaque)
if err != nil {
return err
}
cfgBody = file
} else if repo.Scheme == "http" || repo.Scheme == "https" {
res, err := http.Get(repo.String())
if err != nil {
return err
}
cfgBody, err = io.ReadAll(res.Body)
if err != nil {
return err
}
err = res.Body.Close()
if err != nil {
return err
}
}

config, err := state.UnbundleConfig(string(cfgBody), e.Dist.Key)
config, err := FetchConfig(repo, e.CentralCfg.Dist.Key)
if err != nil {
return err
}
if config.Timestamp > e.Timestamp && !s.Updating.Swap(true) {
e.Log.Info("Found a new config update in repo", "repo", repo.String())
e.Log.Info("Found a new config update in repo", "repo", repo)
bytes, err := yaml.Marshal(config)
if err != nil {
e.Log.Error("Error marshalling new config", "err", err.Error())
Expand All @@ -69,14 +79,14 @@ func checkForConfigUpdates(s *state.State) error {
err:
s.Updating.Store(false)
} else if state.DBG_log_repo_updates {
e.Log.Debug(fmt.Sprintf("found old update bundle at %s, skipping", repo.String()))
e.Log.Debug(fmt.Sprintf("found old update bundle at %s, skipping", repo))
}
return nil
}()
if err != nil && state.DBG_log_repo_updates {
e.Log.Error("Error updating config", "err", err.Error())
}
}()
}(repoStr)
}
return nil
}
5 changes: 4 additions & 1 deletion example/sample-node.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ nonetconfigure: false # Default: false - If enabled, Nylon will not configure th
usesystemrouting: false # Default: false - if enabled, Nylon will use the system route table to forward packets
logpath: "" # Default: "" - If set, Nylon will log to this file
interfacename: "" # Default: "" - If set, Nylon will use this interface name instead of the default "nylon" or utunx on macOS
disablerouting: false # Default: false - If true, Nylon will not route traffic through this node
disablerouting: false # Default: false - If true, Nylon will not route traffic through this node
dist: # Optional: If set, Nylon will bootstrap central.yaml from this URL if it does not exist already
url: https://static.example.com/network1.nybundle
key: 7PaN6DmAayz4KnDnsXSXJH+Oy0TFGeoM4FEbQfLriVY=
6 changes: 6 additions & 0 deletions state/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ type DistributionCfg struct {
Repos []string
}

type LocalDistributionCfg struct {
Key NyPublicKey
Url string
}

type CentralCfg struct {
Dist *DistributionCfg `yaml:",omitempty"`
Routers []RouterCfg
Expand Down Expand Up @@ -65,6 +70,7 @@ type LocalCfg struct {
Id NodeId
// Address that the data plane can be accessed by
Port uint16
Dist *LocalDistributionCfg `yaml:",omitempty"`
DisableRouting bool
UseSystemRouting bool
NoNetConfigure bool `yaml:",omitempty"`
Expand Down
6 changes: 6 additions & 0 deletions state/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ func NodeConfigValidator(node *LocalCfg) error {
return fmt.Errorf("interface name is invalid: %v", err)
}
}
if node.Dist != nil {
_, err := url.Parse(node.Dist.Url)
if err != nil {
return err
}
}
return nil
}

Expand Down
Loading