GithubHelp home page GithubHelp logo

infinisil / toponix Goto Github PK

View Code? Open in Web Editor NEW
4.0 4.0 0.0 13 KB

Toponix will be a bunch of Nix functions that can transform a simple network topology description into useful answers

Nix 100.00%
network-topology nix nixos ssh nixos-configuration nixops

toponix's Introduction

Toponix

Toponix is a Nix module that can transform a simple network topology description into useful answers such as “What are my options to get from host A to host B”. This will also work with declaring openvpn servers and remote port forwarding for ssh.

I am intending to use this for things like (which might come to this repo eventually):

  • Generating a script that sets up an ssh connection to a host, trying the best possible path but falling back to others.
  • Automatically setting up a working openvpn configuration for my machines, each of them automatically getting a static ip address
  • Automatically Setting up reverse port forwarding for the machines that don’t have a public ip address
  • Generating an ssh client config that declares hosts for all other machines

Is it done?

It is usable now, but not very useful, since the only thing it does right now is calculate the results, without actually being able to do anything useful with them. That part will come later. You can however process this output yourself already.

How-To

A config file for toponix looks like this:

{ config, ... }: {

  topology = {
    home = {
      pc = "192.168.1.25";
      laptop = "192.168.1.19";
    };
    server = "76.174.19.220";
    public = {
      laptop = null;
    };
  };

  rssh = {
    enable = true;
    ipPorts = n: toString (6726 + n);
    server = config.hosts.server;
    clients = with config.hosts; [
      pc
      laptop
    ];
  };

  openvpn = {
    enable = true;
    addresses = n: "10.176.75.${toString n}";
    server = config.hosts.server;
    clients = with config.hosts; [
      pc
      laptop
      otherserver
    ];
  };

}

Topology description

A network topology can be declared like this:

{

  topology = {
    home = {
      pc = "192.168.1.25";
      laptop = "192.168.1.19";
    };
    server = "76.174.19.220";
    public = {
      laptop = null;
    };
  };
}

Attributes that declare a string or null value directly at the top level (such as server) mean that it has such a public ip. Nested attributes (such as home and public) declare a subnet, everything within being private ips. Fixed strings as values mean that the ip is static, null values mean the ip is dynamic. Nodes can be declared a number of times (such as laptop), which means that it’s possible for this node to be at multiple locations.

The textual description of the above declared topology is: There is a server with a public ip 76.174.19.220. In the home network there’s a pc with a statically assigned ip 192.168.1.25, along with a laptop with static ip 192.168.1.19. The laptop can however also be in a public unknown subnet, where it has a private dynamic ip.

Options

Everything of importance is declared as an option, either ones for you to configure or ones that calculate a result (read only options). To evaluate options, write a file like test.nix:

import /path/to/toponix {
  configuration = /path/to/your/config.nix;
}

Then you can evaluate options with nix-instantiate and pipe the json output to jq to see it nicely structured. For example, to evaluate the topology options, use this:

nix-instantiate test.nix --strict --json -A config.topology | jq

The following subsections will only mention which options you’ll have to evaluate to get the result;

Direct connections

The direct option shows the direct connections from every to every node. With the above topology, it will result in

{
  laptop = {
    laptop = [ "127.0.0.1" ];
    pc = [ "192.168.1.25" ];
    server = [ "76.174.19.220" ];
  };
  pc = {
    laptop = [ "192.168.1.19" ];
    pc = [ "127.0.0.1" ];
    server = [ "76.174.19.220" ];
  };
  server = {
    laptop = [ ];
    pc = [ ];
    server = [ "127.0.0.1" ];
  };
}

Openvpn

Openvpn requires some settings to work, as seen in the example config above:

{ config, ... }: {
  openvpn = {
    enable = true;
    addresses = n: "10.74.10.${toString n}";
    server = config.hosts.server;
    clients = with config.hosts; [
      pc
      laptop
    ];
  };
}

addresses declare what static ip it should use for a certain host number. server declares which host should run the openvpn server. clients declares the order in which clients should be assigned an ip. When you add a new machine, you’ll want to add it at the bottom, as to keep the static ip assignment. Note that in this case the server will always get ip “10.74.10.1”, and the clients “10.74.10.2” and so on.

The result is in the option openvpn.paths, which looks like this:

{
  laptop = {
    laptop = [ "10.74.10.3" ];
    pc = [ "10.74.10.2" ];
    server = [ "10.74.10.1" ];
  };
  pc = {
    laptop = [ "10.74.10.3" ];
    pc = [ "10.74.10.2" ];
    server = [ "10.74.10.1" ];
  };
  server = {
    laptop = [ "10.74.10.3" ];
    pc = [ "10.74.10.2" ];
    server = [ "10.74.10.1" ];
  };
}

Reverse port forwarding

As with openvpn, reverse port forwarding requires some settings:

{ config, ... }: {
  rssh = {
    enable = true;
    ipPorts = n: toString (6726 + n);
    server = config.hosts.server;
    clients = with config.hosts; [
      pc
      laptop
    ];
  };
}

Here ipPorts declares which port to use on the server for the client with a certain number. server is the server to be used for reverse port forwarding. clients are the clients that should be set up.

The result is in the option rssh.paths, which looks like this:

{
  laptop = {
    laptop = [ "76.174.19.220:6728" ];
    pc = [ "76.174.19.220:6727" ];
    server = [ ];
  };
  pc = {
    laptop = [ "76.174.19.220:6728" ];
    pc = [ "76.174.19.220:6727" ];
    server = [ ];
  };
  server = {
    laptop = [ "localhost:6728" ];
    pc = [ "localhost:6727" ];
    server = [ ];
  };
}

Combined

Both openvpn and rssh have an enable options. What it does is add the result of it to an option combining all paths from all enabled modules (direct connections are always enabled though). This is the combinedPaths options, which looks like this:

{ 
  laptop = { 
    laptop = [ "127.0.0.1" ]; 
    pc = [ "192.168.1.25" "10.176.75.2" "76.174.19.220:6727" ]; 
    server = [ "76.174.19.220" "10.176.75.1" ];
  }; 
  pc = { 
    laptop = [ "192.168.1.19" "10.176.75.3" "76.174.19.220:6728" ]; 
    pc = [ "127.0.0.1" ]; 
    server = [ "76.174.19.220" "10.176.75.1" ];
  }; 
  server = { 
    laptop = [ "10.176.75.3" "localhost:6728" ]; 
    pc = [ "10.176.75.2" "localhost:6727" ]; 
    server = [ "127.0.0.1" ];
  };
}

Ideas/Todo

  • [X] Improve usability
  • [ ] Implement the things mentioned at the top
  • [ ] Ipv6 support
  • [ ] The parts should be easy to combine
  • [ ] Add some error messages
  • [ ] Have the remote port forwarding have an option to automatically use it for all clients that aren’t accessible from a host if it wouldn’t be used for it
  • [ ] Have results other than from/to mappings: Also return nixos config to be used for the hosts so everything works, ssh config as well possibly

toponix's People

Contributors

infinisil avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.