[Proposal] Network API changes
reconbot opened this issue · 1 comments
I have some ideas around restructuring the tessel API to allow for both a good experience and a low level control. There are a LOT of options we could allow setting but I think a few high level modes built on underlying primitives is the right approach.
I think we should start at a high level and slowly expose building blocks as we move them from shell commands to APIs.
This should be considered DRAFT and a work in progress, I had intended to whiteboard it with @HipsterBrown but we didn't get a chance and I want to lay this out. (Nick, this is actually more simple than my first draft.)
Goals
If we go too deep into virtual interfaces, vlans, custom configurations for NAT, etc. there be dragons. I'm shooting for 3 presets.
- wifiClient
- wifiAP
- captiveAP
Proposed API
The api is setup around a few configuration "state machines" and a few event based state machines based upon the physical state of the device. Interfaces are in a state, daemons are in a state, and "modes" orchestrate other states.
Everything would be under tessel.network
like it is now.
Modes
Modes would use the underlying API's to achieve the 3 presets. If someone wants to modify the configuration after setting up one of these presets, that should work as expected. I think these modes are all most people should ever need to interact with. Leaving the building blocks for internal and advanced use. They'll forward events and control the underlying components.
wifiClient
Connect to a wifi network and bridge the ethernetwifiAP
"Act as a router", wifi AP, NAT (wireless -> wired), wired is set to DHCP, Wifi is set to a static IP, DNS forwarding and DHCPD are enabled.captiveAP
SuperSet ofwifiAP
but resolve all DNS queries to an address (default the tessel, allows a whitelisted domain) and rewrites all outbound traffic to the tesssel, has a function call to allow a client full access to the internet (if there is internet one)
Examples
let {wifiClient, wifiAP, interfaces} = tessel.network;
wifiClient.connect({ssid, pw});
wifiClient.on('connected', (wifiNetworkInfo, ipInfo) => {
// both wifi and interface connection events have fired
console.log(wifiNetworkInfo, ipInfo);
});
wifiClient.on('disconnected', () => console.log('lost connection to wifi router'));
interfaces.wired.off(); // save power
// another example
wifiAP.start({ssid, pw})
wifiAP.stop();
wifiAP.on('connected', (wiredExternalIPInfo, wifiInternalIPInfo) => {
// yay!
});
// Visit my page!
captiveAP.start({ssid, pw, url});
captiveAP.stop();
Daemons
I'm not yet sure of the busybox equivalent of these services. I can imagine using a tessel to bridge a network and provide an AP but not want to use NAT or DHCPD. None of the "modes" allow for that but it would be easy to setup with the right apis.
- DHCPD (gives IP's)
- DNSMASQ (forwards or redirects DNS lookups)
- IPTABLES (not really a daemon but provided by the kernel) allows for captive portal, and NAT
Interfaces
tessel.network.wifi
Wifi has 4 configuration states, this manages the state of the wifi connection, not the physical hardware.
- disconnected (not "physically" connected to anything not even trying to)
- AP mode (broadcasts an SSID and accecpts network joins
- Client mode (connect the wifi interface to an SSID)
- Ad Hock Mode (nobody ever uses this but used to connect to non SSID devices)
defaults to disconnected
as it is now.
It also has 3 physical states with events
connected
(when connected in client mode, or set toap
orad hock
mode)connecting
(when trying to join a network)disconnected
(when failed to join a network, or in a disconnected config state)
tessel.network.interfaces
interfaces
are the actual linux interface settings. I'm conflicted if we should call them wifi
and wired
or eth0
and wlan0
. One is easier to understand but the other is much more flexible if we ever have multi interface support (eg, broadcasting two ssid's or having two IPs). Since we're going for the non advanced usecase we should probably keep it simple.
interfaces.wired
and interfaces.wifi
would have 4 configuration states.
- off (powered off to save power consumption)
- static (lets user set a ip4 and/or ip6 ip/gateway and netmask)
- DHCP (which updates automatically DNS too)
- Bridge (we ignore all the settings and bridge to the other interface, only one interface can be in this mode at a time)
wired
would default to bridge, wifi
DHCP as it is now.
The physical states would be as following
- Off
- disconnected (physically)
- connected (connected via wifi or wire, but set to DHCP and without an IP)
- connected with IP (got a DCHP server assigned IP)
- connected with Auto IP (DHCP timed out)
tessel.network.dns
This is a system level setting that would take effect in all modes of operation (resolve.conf basically)
- Auto (from a DHCP'd interface) (default)
- Static (1+ server IPs set manually, overides any DHCP setting)
let {wifiClient, wifiAP, interfaces} = tessel.network;
Does this mean there will be
- tessel.network.wifi
- tessel.network.wifiClient
- tessel.network.wifiAP?
Can we not? Can we just do:
- tessel.network.wifi
- tessel.network.wifi.client
- tessel.network.wifi.ap
?