mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-11-15 08:32:06 +01:00
355 lines
10 KiB
Go
355 lines
10 KiB
Go
package service
|
|
|
|
import (
|
|
//"github.com/docker/libcontainer/netlink"
|
|
"github.com/mame82/P4wnP1_go/netlink"
|
|
"net"
|
|
"log"
|
|
"io/ioutil"
|
|
"os"
|
|
"fmt"
|
|
|
|
pb "github.com/mame82/P4wnP1_go/proto"
|
|
"errors"
|
|
)
|
|
|
|
var (
|
|
ErrUnmanagedInterface = errors.New("Not a managed network interface")
|
|
)
|
|
|
|
func NewNetworkManager() (nm *NetworkManager, err error){
|
|
nm = &NetworkManager{
|
|
ManagedInterfaces: make(map[string]*NetworkInterfaceManager),
|
|
}
|
|
|
|
// Add managed interfaces
|
|
|
|
// USB
|
|
err = nm.AddManagedInterface(GetDefaultNetworkSettingsUSB())
|
|
if err != nil { return }
|
|
// WiFi
|
|
err = nm.AddManagedInterface(GetDefaultNetworkSettingsWiFi())
|
|
if err != nil { return }
|
|
// Bluetooth
|
|
err = nm.AddManagedInterface(GetDefaultNetworkSettingsBluetooth())
|
|
if err != nil { return }
|
|
|
|
//ToDo: Deploy all settings once, to assure consistency of server state and real adapter configuration
|
|
|
|
return nm, nil
|
|
}
|
|
|
|
|
|
type NetworkManager struct {
|
|
ManagedInterfaces map[string]*NetworkInterfaceManager
|
|
}
|
|
|
|
func (nm *NetworkManager) AddManagedInterface(startupConfig *pb.EthernetInterfaceSettings) (err error) {
|
|
nim,err := NewNetworkInterfaceManager(startupConfig.Name, startupConfig)
|
|
if err != nil { return err }
|
|
nm.ManagedInterfaces[startupConfig.Name] = nim
|
|
return
|
|
}
|
|
|
|
func (nm *NetworkManager) GetManagedInterfaceNames() (ifnames []string) {
|
|
ifnames = make([]string, len(nm.ManagedInterfaces))
|
|
i:=0
|
|
for name,_ := range nm.ManagedInterfaces {
|
|
ifnames[i] = name
|
|
i += 1
|
|
}
|
|
return
|
|
}
|
|
|
|
func (nm *NetworkManager) GetManagedInterface(name string) (nim *NetworkInterfaceManager, err error) {
|
|
if nim, exists := nm.ManagedInterfaces[name]; exists {
|
|
return nim, nil
|
|
} else {
|
|
return nil, ErrUnmanagedInterface
|
|
}
|
|
}
|
|
|
|
|
|
|
|
type NetworkInterfaceState struct {
|
|
InterfacePresent bool
|
|
CurrentSettings *pb.EthernetInterfaceSettings
|
|
}
|
|
|
|
// ToDo: interface watcher (up/down --> auto redeploy)
|
|
type NetworkInterfaceManager struct {
|
|
InterfaceName string
|
|
state *NetworkInterfaceState
|
|
}
|
|
|
|
func (nim *NetworkInterfaceManager) GetState() (res *NetworkInterfaceState) {
|
|
return nim.state
|
|
}
|
|
|
|
func (nim *NetworkInterfaceManager) ReDeploy() (err error) {
|
|
/*
|
|
if settings, existing := ServiceState.StoredNetworkSettings[ifName]; existing {
|
|
log.Printf("Redeploying stored Network settings for interface '%s' ...\n", ifName)
|
|
return ConfigureInterface(settings)
|
|
} else {
|
|
return errors.New(fmt.Sprintf("No stored interface settings found for '%s'\n", ifName))
|
|
}
|
|
*/
|
|
return nim.DeploySettings(nim.state.CurrentSettings)
|
|
}
|
|
|
|
func (nim *NetworkInterfaceManager) DeploySettings(settings *pb.EthernetInterfaceSettings) (err error) {
|
|
//Get Interface
|
|
iface, err := net.InterfaceByName(settings.Name)
|
|
if err != nil {
|
|
nim.state.InterfacePresent = false
|
|
//return err
|
|
return nil //Not having the interface present isn't an error
|
|
} else {
|
|
nim.state.InterfacePresent = true
|
|
}
|
|
|
|
//stop DHCP server / client if still running
|
|
running, _, err := IsDHCPServerRunning(settings.Name)
|
|
if (err == nil) && running {StopDHCPServer(settings.Name)}
|
|
running, _, err = IsDHCPClientRunning(settings.Name)
|
|
if (err == nil) && running {StopDHCPClient(settings.Name)}
|
|
|
|
switch settings.Mode {
|
|
case pb.EthernetInterfaceSettings_MANUAL:
|
|
//Generate net
|
|
ipNet, err := IpNetFromIPv4AndNetmask(settings.IpAddress4, settings.Netmask4)
|
|
if err != nil { return err }
|
|
|
|
//Flush old IPs
|
|
netlink.NetworkLinkFlush(iface)
|
|
//set IP
|
|
log.Printf("Setting Interface %s to IP %s\n", iface.Name, settings.IpAddress4)
|
|
netlink.NetworkLinkAddIp(iface, net.ParseIP(settings.IpAddress4), ipNet)
|
|
|
|
if settings.Enabled {
|
|
log.Printf("Setting Interface %s to UP\n", iface.Name)
|
|
err = netlink.NetworkLinkUp(iface)
|
|
if err != nil { return err }
|
|
log.Printf("Setting Interface %s to MULTICAST to ON\n", iface.Name)
|
|
err = netlink.NetworkSetMulticast(iface, true)
|
|
if err != nil { return err }
|
|
|
|
} else {
|
|
log.Printf("Setting Interface %s to DOWN\n", iface.Name)
|
|
err = netlink.NetworkLinkDown(iface)
|
|
if err != nil { return err }
|
|
}
|
|
|
|
case pb.EthernetInterfaceSettings_DHCP_SERVER:
|
|
//Generate net
|
|
ipNet, err := IpNetFromIPv4AndNetmask(settings.IpAddress4, settings.Netmask4)
|
|
if err != nil { return err }
|
|
|
|
//Flush old IPs
|
|
netlink.NetworkLinkFlush(iface)
|
|
//set IP
|
|
log.Printf("Setting Interface %s to IP %s\n", iface.Name, settings.IpAddress4)
|
|
netlink.NetworkLinkAddIp(iface, net.ParseIP(settings.IpAddress4), ipNet)
|
|
|
|
if settings.Enabled {
|
|
log.Printf("Setting Interface %s to UP\n", iface.Name)
|
|
err = netlink.NetworkLinkUp(iface)
|
|
if err != nil { return err }
|
|
log.Printf("Setting Interface %s to MULTICAST to ON\n", iface.Name)
|
|
err = netlink.NetworkSetMulticast(iface, true)
|
|
if err != nil { return err }
|
|
|
|
|
|
//check DhcpServerSettings
|
|
if settings.DhcpServerSettings == nil {
|
|
err = errors.New(fmt.Sprintf("Ethernet configuration for interface %s is set to DHCP Server mode, but doesn't provide DhcpServerSettings", settings.Name))
|
|
log.Println(err)
|
|
return err
|
|
}
|
|
ifName := settings.Name
|
|
confName := NameConfigFileDHCPSrv(ifName)
|
|
err = DHCPCreateConfigFile(settings.DhcpServerSettings, confName)
|
|
if err != nil {return err}
|
|
//stop already running DHCPServers for the interface
|
|
StopDHCPServer(ifName)
|
|
|
|
//special case: if the interface name is USB_ETHERNET_BRIDGE_NAME, we delete the old lease file
|
|
// the flushing of still running leases is needed, as after USB reinit, RNDIS hosts aren't guaranteed to
|
|
// receive the sam MAC, which would effectivly block reusing of a lease for the same IP (a problem, as in
|
|
// typical DHCP server configurations for USB Ethernet, the same remote IP should be offered every time)
|
|
if settings.Name == USB_ETHERNET_BRIDGE_NAME {
|
|
log.Printf("Reconfiguration of USB Ethernert interface as DHCP server, trying to delete old lease file ...\n")
|
|
errD := os.Remove(settings.DhcpServerSettings.LeaseFile)
|
|
if errD == nil {
|
|
log.Println(" ... old lease file deleted successfull")
|
|
} else {
|
|
log.Printf(" ... old lease couldn't be deleted (Fetching a new DHCP lease could take a while on USB ethernet)!\n\tReason: %v\n", errD)
|
|
}
|
|
}
|
|
|
|
//start the DHCP server
|
|
err = StartDHCPServer(ifName, confName)
|
|
if err != nil {return err}
|
|
} else {
|
|
log.Printf("Setting Interface %s to DOWN\n", iface.Name)
|
|
err = netlink.NetworkLinkDown(iface)
|
|
}
|
|
if err != nil { return err }
|
|
case pb.EthernetInterfaceSettings_DHCP_CLIENT:
|
|
netlink.NetworkLinkFlush(iface)
|
|
if settings.Enabled {
|
|
log.Printf("Setting Interface %s to UP\n", iface.Name)
|
|
err = netlink.NetworkLinkUp(iface)
|
|
if err != nil { return err }
|
|
log.Printf("Setting Interface %s to MULTICAST to ON\n", iface.Name)
|
|
err = netlink.NetworkSetMulticast(iface, true)
|
|
if err != nil { return err }
|
|
|
|
StartDHCPClient(settings.Name)
|
|
} else {
|
|
log.Printf("Setting Interface %s to DOWN\n", iface.Name)
|
|
err = netlink.NetworkLinkDown(iface)
|
|
if err != nil { return err }
|
|
}
|
|
|
|
}
|
|
|
|
//Store latest settings
|
|
settings.SettingsInUse = true
|
|
|
|
//ServiceState.StoredNetworkSettings[settings.Name] = settings
|
|
nim.state.CurrentSettings = settings
|
|
|
|
return nil
|
|
}
|
|
|
|
func NewNetworkInterfaceManager(ifaceName string, startupSettings *pb.EthernetInterfaceSettings) (nim *NetworkInterfaceManager, err error) {
|
|
nim = &NetworkInterfaceManager{
|
|
InterfaceName: ifaceName,
|
|
state: &NetworkInterfaceState{},
|
|
}
|
|
nim.state.CurrentSettings = startupSettings
|
|
nim.ReDeploy()
|
|
|
|
// Deploy startup configuration, to have an initial, defined state
|
|
|
|
/*
|
|
// Startup settings (always DHCP client, Interface up)
|
|
nim.state.CurrentSettings = &pb.EthernetInterfaceSettings{
|
|
Name: ifaceName,
|
|
Mode: pb.EthernetInterfaceSettings_DHCP_CLIENT,
|
|
Enabled: true,
|
|
SettingsInUse: true,
|
|
DhcpServerSettings: &pb.DHCPServerSettings{
|
|
CallbackScript: "",
|
|
DoNotBindInterface: false,
|
|
LeaseFile: nameLeaseFileDHCPSrv(ifaceName),
|
|
ListenInterface: ifaceName,
|
|
ListenPort: 0,
|
|
NotAuthoritative: false,
|
|
Options: map[uint32]string{
|
|
3: "",
|
|
6: "",
|
|
},
|
|
Ranges: []*pb.DHCPServerRange{},
|
|
StaticHosts: []*pb.DHCPServerStaticHost{},
|
|
},
|
|
}
|
|
*/
|
|
|
|
return
|
|
}
|
|
|
|
|
|
/* HELPER */
|
|
func nameLeaseFileDHCPSrv(nameIface string) (lf string) {
|
|
return "/tmp/dnsmasq_" + nameIface + ".leases"
|
|
}
|
|
|
|
func ParseIPv4Mask(maskstr string) (net.IPMask, error) {
|
|
mask := net.ParseIP(maskstr)
|
|
if mask == nil { return nil, errors.New("Couldn't parse netmask") }
|
|
|
|
net.ParseCIDR(maskstr)
|
|
return net.IPv4Mask(mask[12], mask[13], mask[14], mask[15]), nil
|
|
}
|
|
|
|
func IpNetFromIPv4AndNetmask(ipv4 string, netmask string) (*net.IPNet, error) {
|
|
mask, err := ParseIPv4Mask(netmask)
|
|
if err != nil { return nil, err }
|
|
|
|
ip := net.ParseIP(ipv4)
|
|
if mask == nil { return nil, errors.New("Couldn't parse IP") }
|
|
|
|
netw := ip.Mask(mask)
|
|
|
|
return &net.IPNet{IP: netw, Mask: mask}, nil
|
|
}
|
|
|
|
|
|
|
|
func CreateBridge(name string) (err error) {
|
|
return netlink.CreateBridge(name, false)
|
|
}
|
|
|
|
func setInterfaceMac(name string, mac string) error {
|
|
return netlink.SetMacAddress(name, mac)
|
|
}
|
|
|
|
func DeleteBridge(name string) error {
|
|
return netlink.DeleteBridge(name)
|
|
}
|
|
|
|
//Uses sysfs (not IOCTL)
|
|
func SetBridgeSTP(name string, stp_on bool) (err error) {
|
|
value := "0"
|
|
if (stp_on) { value = "1" }
|
|
return ioutil.WriteFile(fmt.Sprintf("/sys/class/net/%s/bridge/stp_state", name), []byte(value), os.ModePerm)
|
|
}
|
|
|
|
func SetBridgeForwardDelay(name string, fd uint) (err error) {
|
|
return ioutil.WriteFile(fmt.Sprintf("/sys/class/net/%s/bridge/forward_delay", name), []byte(fmt.Sprintf("%d", fd)), os.ModePerm)
|
|
}
|
|
|
|
|
|
|
|
func CheckInterfaceExistence(name string) (res bool, err error) {
|
|
_, err = net.InterfaceByName(name)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return true, err
|
|
}
|
|
|
|
func NetworkLinkUp(name string) (err error) {
|
|
iface, err := net.InterfaceByName(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = netlink.NetworkLinkUp(iface)
|
|
return
|
|
}
|
|
|
|
func AddInterfaceToBridgeIfExistent(bridgeName string, ifName string) (err error) {
|
|
br, err := net.InterfaceByName(bridgeName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
iface, err := net.InterfaceByName(ifName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = netlink.AddToBridge(iface, br)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
log.Printf("Interface %s added to bridge %s", ifName, bridgeName)
|
|
|
|
//enable interface
|
|
NetworkLinkUp(ifName)
|
|
return nil
|
|
}
|