diff --git a/controllers/ext_client.go b/controllers/ext_client.go index d420b71a..5faf6bdc 100644 --- a/controllers/ext_client.go +++ b/controllers/ext_client.go @@ -214,7 +214,7 @@ func getExtClientConf(w http.ResponseWriter, r *http.Request) { if network.DefaultKeepalive != 0 { keepalive = "PersistentKeepalive = " + strconv.Itoa(int(network.DefaultKeepalive)) } - gwendpoint := gwnode.EndpointIP.String() + ":" + strconv.Itoa(host.ListenPort) + gwendpoint := host.EndpointIP.String() + ":" + strconv.Itoa(host.ListenPort) newAllowedIPs := network.AddressRange if newAllowedIPs != "" && network.AddressRange6 != "" { newAllowedIPs += "," @@ -338,12 +338,11 @@ func createExtClient(w http.ResponseWriter, r *http.Request) { logger.Log(0, r.Header.Get("user"), fmt.Sprintf("failed to get ingress gateway host for node [%s] info: %v", nodeid, err)) logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal")) - return listenPort := host.LocalListenPort - if node.Proxy { + if host.ProxyEnabled { listenPort = host.ProxyListenPort } - extclient.IngressGatewayEndpoint = node.EndpointIP.String() + ":" + strconv.FormatInt(int64(listenPort), 10) + extclient.IngressGatewayEndpoint = host.EndpointIP.String() + ":" + strconv.FormatInt(int64(listenPort), 10) extclient.Enabled = true parentNetwork, err := logic.GetNetwork(networkName) diff --git a/controllers/node.go b/controllers/node.go index 863f53a1..be7445ac 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -95,6 +95,14 @@ func authenticate(response http.ResponseWriter, request *http.Request) { } } host, err := logic.GetHost(result.HostID.String()) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Message = err.Error() + logger.Log(0, request.Header.Get("user"), + "error retrieving host: ", err.Error()) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } err = bcrypt.CompareHashAndPassword([]byte(host.HostPass), []byte(authRequest.Password)) if err != nil { @@ -485,7 +493,7 @@ func getNode(w http.ResponseWriter, r *http.Request) { ServerConfig: server, PeerIDs: peerUpdate.PeerIDs, } - if node.Proxy { + if host.ProxyEnabled { proxyPayload, err := logic.GetPeersForProxy(&node, false) if err == nil { response.ProxyUpdate = proxyPayload @@ -985,6 +993,12 @@ func deleteNode(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) return } + host, err := logic.GetHost(node.HostID.String()) + if err != nil { + logger.Log(0, "error retrieving host for node", node.ID.String(), err.Error()) + logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest")) + return + } if r.Header.Get("ismaster") != "yes" { username := r.Header.Get("user") if username != "" && !doesUserOwnNode(username, params["network"], nodeid) { @@ -996,7 +1010,7 @@ func deleteNode(w http.ResponseWriter, r *http.Request) { logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete node"), "internal")) return } - if node.Proxy { + if host.ProxyEnabled { mq.ProxyUpdate(&manager.ProxyManagerPayload{ Action: manager.DeleteNetwork, Network: node.Network, diff --git a/logic/gateway.go b/logic/gateway.go index b3415329..f4115201 100644 --- a/logic/gateway.go +++ b/logic/gateway.go @@ -46,7 +46,7 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro } node.IsEgressGateway = true node.EgressGatewayRanges = gateway.Ranges - node.EgressGatewayNatEnabled = gateway.NatEnabled + node.EgressGatewayNatEnabled = models.ParseBool(gateway.NatEnabled) node.EgressGatewayRequest = gateway // store entire request for use when preserving the egress gateway postUpCmd := "" postDownCmd := "" @@ -335,7 +335,7 @@ func firewallNFTCommandsCreateIngress(networkInterface string) (string, string) } // firewallNFTCommandsCreateEgress - used to centralize firewall command maintenance for creating an egress gateway using the nftables firewall. -func firewallNFTCommandsCreateEgress(networkInterface string, gatewayInterface string, gatewayranges []string, egressNatEnabled string, ipv4, ipv6 bool) (string, string) { +func firewallNFTCommandsCreateEgress(networkInterface string, gatewayInterface string, gatewayranges []string, egressNatEnabled bool, ipv4, ipv6 bool) (string, string) { // spacing around ; is important for later parsing of postup/postdown in wireguard/common.go postUp := "" postDown := "" @@ -351,7 +351,7 @@ func firewallNFTCommandsCreateEgress(networkInterface string, gatewayInterface s postDown += "nft flush table filter ; " - if egressNatEnabled == "yes" { + if egressNatEnabled { postUp += "nft add table nat ; " postUp += "nft add chain nat postrouting ; " postUp += "nft add rule ip nat postrouting oifname " + gatewayInterface + " counter masquerade ; " @@ -368,7 +368,7 @@ func firewallNFTCommandsCreateEgress(networkInterface string, gatewayInterface s postDown += "nft flush table ip6 filter ; " - if egressNatEnabled == "yes" { + if egressNatEnabled { postUp += "nft add table ip6 nat ; " postUp += "nft 'add chain ip6 nat prerouting { type nat hook prerouting priority 0 ;}' ; " postUp += "nft 'add chain ip6 nat postrouting { type nat hook postrouting priority 0 ;}' ; " @@ -411,7 +411,7 @@ func firewallIPTablesCommandsCreateIngress(networkInterface string, ipv4, ipv6 b } // firewallIPTablesCommandsCreateEgress - used to centralize firewall command maintenance for creating an egress gateway using the iptables firewall. -func firewallIPTablesCommandsCreateEgress(networkInterface string, gatewayInterface string, egressNatEnabled string, ipv4, ipv6 bool) (string, string) { +func firewallIPTablesCommandsCreateEgress(networkInterface string, gatewayInterface string, egressNatEnabled bool, ipv4, ipv6 bool) (string, string) { // spacing around ; is important for later parsing of postup/postdown in wireguard/common.go postUp := "" postDown := "" @@ -421,7 +421,7 @@ func firewallIPTablesCommandsCreateEgress(networkInterface string, gatewayInterf postDown += "iptables -D FORWARD -i " + networkInterface + " -j ACCEPT ; " postDown += "iptables -D FORWARD -o " + networkInterface + " -j ACCEPT ; " - if egressNatEnabled == "yes" { + if egressNatEnabled { postUp += "iptables -t nat -A POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; " postDown += "iptables -t nat -D POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; " } @@ -432,7 +432,7 @@ func firewallIPTablesCommandsCreateEgress(networkInterface string, gatewayInterf postDown += "ip6tables -D FORWARD -i " + networkInterface + " -j ACCEPT ; " postDown += "ip6tables -D FORWARD -o " + networkInterface + " -j ACCEPT ; " - if egressNatEnabled == "yes" { + if egressNatEnabled { postUp += "ip6tables -t nat -A POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; " postDown += "ip6tables -t nat -D POSTROUTING -o " + gatewayInterface + " -j MASQUERADE ; " } diff --git a/logic/peers.go b/logic/peers.go index ce9a7dc8..613d719f 100644 --- a/logic/peers.go +++ b/logic/peers.go @@ -40,12 +40,16 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (manager.ProxyManagerPa if !onlyPeers { if node.IsRelayed { relayNode := FindRelay(node) + relayHost, err := GetHost(relayNode.ID.String()) + if err != nil { + return proxyPayload, err + } if relayNode != nil { host, err := GetHost(relayNode.HostID.String()) if err != nil { logger.Log(0, "error retrieving host for relay node", relayNode.HostID.String(), err.Error()) } - relayEndpoint, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayNode.EndpointIP, host.LocalListenPort)) + relayEndpoint, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayHost.EndpointIP, host.LocalListenPort)) if err != nil { logger.Log(1, "failed to resolve relay node endpoint: ", err.Error()) } @@ -74,7 +78,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (manager.ProxyManagerPa if err != nil { logger.Log(0, "error retrieving host for relayNode", relayedNode.ID.String(), err.Error()) } - relayedEndpoint, udpErr := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayedNode.EndpointIP, host.LocalListenPort)) + relayedEndpoint, udpErr := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayedHost.EndpointIP, host.LocalListenPort)) if udpErr == nil { relayPeersMap[host.PublicKey.String()] = proxy_models.RelayedConf{ RelayedPeerEndpoint: relayedEndpoint, @@ -101,7 +105,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (manager.ProxyManagerPa if err != nil { continue } - proxyStatus := peer.Proxy + proxyStatus := host.ProxyEnabled listenPort := host.LocalListenPort if proxyStatus { listenPort = host.ProxyListenPort @@ -113,9 +117,9 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (manager.ProxyManagerPa } - endpoint, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", peer.EndpointIP, listenPort)) + endpoint, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", host.EndpointIP, listenPort)) if err != nil { - logger.Log(1, "failed to resolve udp addr for node: ", peer.ID.String(), peer.EndpointIP.String(), err.Error()) + logger.Log(1, "failed to resolve udp addr for node: ", peer.ID.String(), host.EndpointIP.String(), err.Error()) continue } allowedips := GetAllowedIPs(node, &peer, nil, false) @@ -145,7 +149,7 @@ func GetPeersForProxy(node *models.Node, onlyPeers bool) (manager.ProxyManagerPa logger.Log(0, "error retrieving host for relayNode", relayNode.ID.String(), err.Error()) continue } - relayTo, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayNode.EndpointIP, relayHost.LocalListenPort)) + relayTo, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", relayHost.EndpointIP, relayHost.LocalListenPort)) if err == nil { peerConfMap[host.PublicKey.String()] = proxy_models.PeerConf{ @@ -215,8 +219,11 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) { if err != nil { return models.PeerUpdate{}, err } - - if node.IsRelayed && !node.Proxy { + host, err := GetHost(node.ID.String()) + if err != nil { + return peerUpdate, err + } + if node.IsRelayed && !host.ProxyEnabled { return GetPeerUpdateForRelayedNode(node, udppeers) } @@ -224,6 +231,11 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) { // #2 Set local address: set_local - could be a LOT BETTER and fix some bugs with additional logic // #3 Set allowedips: set_allowedips for _, peer := range currentPeers { + peerHost, err := GetHost(peer.ID.String()) + if err != nil { + logger.Log(0, "error retrieving host for peer", node.ID.String(), err.Error()) + return models.PeerUpdate{}, err + } if peer.ID == node.ID { //skip yourself continue @@ -237,7 +249,7 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) { var setEndpoint = true if peer.IsRelayed { - if !peer.Proxy && !(node.IsRelay && ncutils.StringSliceContains(node.RelayAddrs, peer.PrimaryAddress())) { + if !peerHost.ProxyEnabled && !(node.IsRelay && ncutils.StringSliceContains(node.RelayAddrs, peer.PrimaryAddress())) { //skip -- will be added to relay continue } else if node.IsRelay && ncutils.StringSliceContains(node.RelayAddrs, peer.PrimaryAddress()) { @@ -261,16 +273,11 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) { logger.Log(0, "error retrieving host for node", node.ID.String(), err.Error()) return models.PeerUpdate{}, err } - peerHost, err := GetHost(peer.HostID.String()) - if err != nil { - logger.Log(0, "error retrieving host for peer", node.ID.String(), err.Error()) - return models.PeerUpdate{}, err - } - if node.EndpointIP.String() == peer.EndpointIP.String() { + if host.EndpointIP.String() == peerHost.EndpointIP.String() { //peer is on same network // set_local if host.LocalAddress.String() != peerHost.LocalAddress.String() && peerHost.LocalAddress.IP != nil { - peer.EndpointIP = peerHost.LocalAddress.IP + peerHost.EndpointIP = peerHost.LocalAddress.IP if peerHost.LocalListenPort != 0 { peerHost.ListenPort = peerHost.LocalListenPort } @@ -308,14 +315,14 @@ func GetPeerUpdate(node *models.Node) (models.PeerUpdate, error) { peerHost.ListenPort = peerHost.LocalListenPort } - endpoint := peer.EndpointIP.String() + ":" + strconv.FormatInt(int64(peerHost.ListenPort), 10) + endpoint := peerHost.EndpointIP.String() + ":" + strconv.FormatInt(int64(peerHost.ListenPort), 10) address, err = net.ResolveUDPAddr("udp", endpoint) if err != nil { return models.PeerUpdate{}, err } } fetchRelayedIps := true - if node.Proxy { + if host.ProxyEnabled { fetchRelayedIps = false } allowedips := GetAllowedIPs(node, &peer, metrics, fetchRelayedIps) @@ -741,7 +748,7 @@ func GetPeerUpdateForRelayedNode(node *models.Node, udppeers map[string]string) listenPort = relayHost.LocalListenPort } - endpoint := relay.EndpointIP.String() + ":" + strconv.FormatInt(int64(listenPort), 10) + endpoint := relayHost.EndpointIP.String() + ":" + strconv.FormatInt(int64(listenPort), 10) address, err := net.ResolveUDPAddr("udp", endpoint) if err != nil { return models.PeerUpdate{}, err @@ -781,6 +788,11 @@ func getEgressIPs(node, peer *models.Node) []net.IPNet { if err != nil { logger.Log(0, "error retrieving host for node", node.ID.String(), err.Error()) } + peerHost, err := GetHost(peer.ID.String()) + if err != nil { + logger.Log(0, "error retrieving host for peer", peer.ID.String(), err.Error()) + } + //check for internet gateway internetGateway := false if slices.Contains(peer.EgressGatewayRanges, "0.0.0.0/0") || slices.Contains(peer.EgressGatewayRanges, "::/0") { @@ -793,9 +805,9 @@ func getEgressIPs(node, peer *models.Node) []net.IPNet { logger.Log(1, "could not parse gateway IP range. Not adding ", iprange) continue // if can't parse CIDR } - nodeEndpointArr := strings.Split(peer.EndpointIP.String(), ":") // getting the public ip of node + nodeEndpointArr := strings.Split(peerHost.EndpointIP.String(), ":") // getting the public ip of node if ipnet.Contains(net.ParseIP(nodeEndpointArr[0])) && !internetGateway { // ensuring egress gateway range does not contain endpoint of node - logger.Log(2, "egress IP range of ", iprange, " overlaps with ", node.EndpointIP.String(), ", omitting") + logger.Log(2, "egress IP range of ", iprange, " overlaps with ", host.EndpointIP.String(), ", omitting") continue // skip adding egress range if overlaps with node's ip } // TODO: Could put in a lot of great logic to avoid conflicts / bad routes @@ -814,11 +826,13 @@ func getEgressIPs(node, peer *models.Node) []net.IPNet { func getNodeAllowedIPs(peer, node *models.Node) []net.IPNet { var allowedips = []net.IPNet{} - + host, err := GetHost(node.ID.String()) + if err != nil { + logger.Log(0, "error retrieving host for node", node.ID.String(), err.Error()) + } if peer.Address.IP != nil { allowedips = append(allowedips, peer.Address) } - if peer.Address6.IP != nil { allowedips = append(allowedips, peer.Address6) } @@ -827,7 +841,7 @@ func getNodeAllowedIPs(peer, node *models.Node) []net.IPNet { // parsing as a CIDR first. If valid CIDR, append if _, ipnet, err := net.ParseCIDR(allowedIp); err == nil { - nodeEndpointArr := strings.Split(node.EndpointIP.String(), ":") + nodeEndpointArr := strings.Split(host.EndpointIP.String(), ":") if !ipnet.Contains(net.IP(nodeEndpointArr[0])) && ipnet.IP.String() != peer.Address.IP.String() { // don't need to add an allowed ip that already exists.. allowedips = append(allowedips, *ipnet) } diff --git a/models/host.go b/models/host.go index 8d2031ad..1f515640 100644 --- a/models/host.go +++ b/models/host.go @@ -41,3 +41,21 @@ type Host struct { IsK8S bool `json:"isk8s" yaml:"isk8s"` IsStatic bool `json:"isstatic" yaml:"isstatic"` } + +// FormatBool converts a boolean to a [yes|no] string +func FormatBool(b bool) string { + s := "no" + if b { + s = "yes" + } + return s +} + +// ParseBool parses a [yes|no] string to boolean value +func ParseBool(s string) bool { + b := false + if s == "yes" { + b = true + } + return b +} diff --git a/mq/handlers.go b/mq/handlers.go index 365c8fd8..4ea670b1 100644 --- a/mq/handlers.go +++ b/mq/handlers.go @@ -57,9 +57,9 @@ func Ping(client mqtt.Client, msg mqtt.Message) { node.SetLastCheckIn() host.Version = checkin.Version node.Connected = checkin.Connected - node.Interfaces = checkin.Ifaces - for i := range node.Interfaces { - node.Interfaces[i].AddressString = node.Interfaces[i].Address.String() + host.Interfaces = checkin.Ifaces + for i := range host.Interfaces { + host.Interfaces[i].AddressString = host.Interfaces[i].Address.String() } if err := logic.UpdateNode(&node, &node); err != nil { logger.Log(0, "error updating node", node.ID.String(), " on checkin", err.Error()) diff --git a/mq/publishers.go b/mq/publishers.go index f6e28ccc..b7232edb 100644 --- a/mq/publishers.go +++ b/mq/publishers.go @@ -49,12 +49,16 @@ func PublishProxyPeerUpdate(node *models.Node) error { // PublishSinglePeerUpdate --- determines and publishes a peer update to one node func PublishSinglePeerUpdate(node *models.Node) error { + host, err := logic.GetHost(node.ID.String()) + if err != nil { + return nil + } peerUpdate, err := logic.GetPeerUpdate(node) if err != nil { return err } - if node.Proxy { + if host.ProxyEnabled { proxyUpdate, err := logic.GetPeersForProxy(node, false) if err != nil { return err @@ -73,7 +77,10 @@ func PublishSinglePeerUpdate(node *models.Node) error { // PublishPeerUpdate --- publishes a peer update to all the peers of a node func PublishExtPeerUpdate(node *models.Node) error { - var err error + host, err := logic.GetHost(node.ID.String()) + if err != nil { + return nil + } if !servercfg.IsMessageQueueBackend() { return nil } @@ -85,7 +92,7 @@ func PublishExtPeerUpdate(node *models.Node) error { if err != nil { return err } - if node.Proxy { + if host.ProxyEnabled { proxyUpdate, err := logic.GetPeersForProxy(node, false) if err == nil { peerUpdate.ProxyUpdate = proxyUpdate @@ -101,7 +108,10 @@ func PublishExtPeerUpdate(node *models.Node) error { // NodeUpdate -- publishes a node update func NodeUpdate(node *models.Node) error { - var err error + host, err := logic.GetHost(node.ID.String()) + if err != nil { + return nil + } if !servercfg.IsMessageQueueBackend() { return nil } @@ -120,7 +130,7 @@ func NodeUpdate(node *models.Node) error { logger.Log(2, "error publishing node update to peer ", node.ID.String(), err.Error()) return err } - if node.Proxy { + if host.ProxyEnabled { err = PublishProxyPeerUpdate(node) if err != nil { logger.Log(1, "failed to publish proxy update to node", node.ID.String(), "on network", node.Network, ":", err.Error()) @@ -132,7 +142,11 @@ func NodeUpdate(node *models.Node) error { // ProxyUpdate -- publishes updates to peers related to proxy func ProxyUpdate(proxyPayload *manager.ProxyManagerPayload, node *models.Node) error { - if !servercfg.IsMessageQueueBackend() || !node.Proxy { + host, err := logic.GetHost(node.ID.String()) + if err != nil { + return nil + } + if !servercfg.IsMessageQueueBackend() || !host.ProxyEnabled { return nil } logger.Log(3, "publishing proxy update to "+node.ID.String())