/*
 * Copyright (c)2013-2021 ZeroTier, Inc.
 *
 * Use of this software is governed by the Business Source License included
 * in the LICENSE.TXT file in the project's root directory.
 *
 * Change Date: 2026-01-01
 *
 * On the date above, in accordance with the Business Source License, use
 * of this software will be governed by version 2.0 of the Apache License.
 */
/****/

/**
 * @file
 *
 * ZeroTier Node Service
 */

#ifndef ZTS_NODE_SERVICE_HPP
#define ZTS_NODE_SERVICE_HPP

#define ZTS_UNUSED_ARG(x) (void)x

#include "Binder.hpp"
#include "Mutex.hpp"
#include "Node.hpp"
#include "Phy.hpp"
#include "PortMapper.hpp"
#include "ZeroTierSockets.h"

#include <string>
#include <vector>

#define ZTS_SERVICE_THREAD_NAME        "ZTServiceThread"
#define ZTS_EVENT_CALLBACK_THREAD_NAME "ZTEventCallbackThread"
// Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and
// also bridged via ZeroTier to the same LAN traffic will (if the OS is sane)
// prefer WiFi.
#define ZT_IF_METRIC 5000
// How often to check for new multicast subscriptions on a tap device
#define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000
// How often to check for local interface addresses
#define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000

#ifdef __WINDOWS__
#include <windows.h>
#endif

namespace ZeroTier {

struct InetAddress;
class VirtualTap;
class MAC;
class Events;

/**
 * ZeroTier node service
 */
class NodeService {
  public:
    /**
     * Returned by node main if/when it terminates
     */
    enum ReasonForTermination {
        /**
         * Instance is still running
         */
        ONE_STILL_RUNNING = 0,

        /**
         * Normal shutdown
         */
        ONE_NORMAL_TERMINATION = 1,

        /**
         * A serious unrecoverable error has occurred
         */
        ONE_UNRECOVERABLE_ERROR = 2,

        /**
         * Your identity has collided with another
         */
        ONE_IDENTITY_COLLISION = 3
    };

    /**
     * Local settings for each network
     */
    struct NetworkSettings {
        /**
         * Allow this network to configure IP addresses and routes?
         */
        bool allowManaged;

        /**
         * Whitelist of addresses that can be configured by this network.
         * If empty and allowManaged is true, allow all
         * private/pseudoprivate addresses.
         */
        std::vector<InetAddress> allowManagedWhitelist;

        /**
         * Allow configuration of IPs and routes within global (Internet) IP
         * space?
         */
        bool allowGlobal;

        /**
         * Allow overriding of system default routes for "full tunnel"
         * operation?
         */
        bool allowDefault;
    };

    Phy<NodeService*> _phy;
    Node* _node;

    uint64_t _nodeId;
    unsigned int _primaryPort;
    unsigned int _secondaryPort;
    unsigned int _tertiaryPort;

    unsigned int _randomPortRangeStart;
    unsigned int _randomPortRangeEnd;

    volatile unsigned int _udpPortPickerCounter;

    std::map<uint64_t, unsigned int> peerCache;

    // Local configuration and memo-ized information from it
    Hashtable<uint64_t, std::vector<InetAddress> > _v4Hints;
    Hashtable<uint64_t, std::vector<InetAddress> > _v6Hints;
    Hashtable<uint64_t, std::vector<InetAddress> > _v4Blacklists;
    Hashtable<uint64_t, std::vector<InetAddress> > _v6Blacklists;
    std::vector<InetAddress> _globalV4Blacklist;
    std::vector<InetAddress> _globalV6Blacklist;
    std::vector<InetAddress> _allowManagementFrom;
    std::vector<std::string> _interfacePrefixBlacklist;
    Mutex _localConfig_m;

    std::vector<InetAddress> explicitBind;

    /*
     * To attempt to handle NAT/gateway craziness we use three local UDP
     * ports:
     *
     * [0] is the normal/default port, usually 9993
     * [1] is a port derived from our ZeroTier address
     * [2] is a port computed from the normal/default for use with
     * uPnP/NAT-PMP mappings
     *
     * [2] exists because on some gateways trying to do regular NAT-t
     * interferes destructively with uPnP port mapping behavior in very
     * weird buggy ways. It's only used if uPnP/NAT-PMP is enabled in this
     * build.
     */
    unsigned int _ports[3] = { 0 };
    Binder _binder;

    // Time we last received a packet from a global address
    uint64_t _lastDirectReceiveFromGlobal;

    // Last potential sleep/wake event
    uint64_t _lastRestart;

    // Deadline for the next background task service function
    volatile int64_t _nextBackgroundTaskDeadline;

    // Configured networks
    struct NetworkState {
        NetworkState() : tap((VirtualTap*)0)
        {
            // Real defaults are in network 'up' code in network event
            // handler
            settings.allowManaged = true;
            settings.allowGlobal = false;
            settings.allowDefault = false;
        }

        VirtualTap* tap;
        ZT_VirtualNetworkConfig config;   // memcpy() of raw config from core
        std::vector<InetAddress> managedIps;
        NetworkSettings settings;
    };
    std::map<uint64_t, NetworkState> _nets;

    /** Lock to control access to network configuration data */
    Mutex _nets_m;
    /** Lock to control access to storage data */
    Mutex _store_m;
    /** Lock to control access to service run state */
    Mutex _run_m;
    // Set to false to force service to stop
    volatile bool _run;
    /** Lock to control access to termination reason */
    Mutex _termReason_m;
    // Termination status information
    ReasonForTermination _termReason;

    std::string _fatalErrorMessage;

    // uPnP/NAT-PMP port mapper if enabled
    bool _allowPortMapping;
#ifdef ZT_USE_MINIUPNPC
    PortMapper* _portMapper;
#endif
    bool _allowSecondaryPort;

    uint8_t _allowNetworkCaching;
    uint8_t _allowPeerCaching;
    uint8_t _allowIdentityCaching;
    uint8_t _allowRootSetCaching;

    char _publicIdStr[ZT_IDENTITY_STRING_BUFFER_LENGTH] = { 0 };
    char _secretIdStr[ZT_IDENTITY_STRING_BUFFER_LENGTH] = { 0 };

    bool _userDefinedWorld;
    char _rootsData[ZTS_STORE_DATA_LEN] = { 0 };
    int _rootsDataLen = 0;

    /** Whether the node has successfully come online */
    bool _nodeIsOnline;

    /** Whether we allow the NodeService to generate events for the user */
    bool _eventsEnabled;

    /** Storage path defined by the user */
    std::string _homePath;

    /** System to ingest events from this class and emit them to the user */
    Events* _events;

    NodeService();
    ~NodeService();

    /** Main service loop */
    ReasonForTermination run();

    ReasonForTermination reasonForTermination() const;

    std::string fatalErrorMessage() const;

    /** Stop the node and service */
    void terminate();

    /** Apply or update managed IPs for a configured network */
    void syncManagedStuff(NetworkState& n);

    void phyOnDatagram(
        PhySocket* sock,
        void** uptr,
        const struct sockaddr* localAddr,
        const struct sockaddr* from,
        void* data,
        unsigned long len);

    int nodeVirtualNetworkConfigFunction(
        uint64_t net_id,
        void** nuptr,
        enum ZT_VirtualNetworkConfigOperation op,
        const ZT_VirtualNetworkConfig* nwc);

    void nodeEventCallback(enum ZT_Event event, const void* metaData);

    zts_net_info_t* prepare_network_details_msg(const NetworkState& n);

    void generateSyntheticEvents();

    void sendEventToUser(unsigned int zt_event_code, const void* obj, unsigned int len = 0);

    /** Join a network */
    int join(uint64_t net_id);

    /** Leave a network */
    int leave(uint64_t net_id);

    /** Return whether the network is ready for transport services */
    bool networkIsReady(uint64_t net_id) const;

    /** Lock the service so we can perform queries */
    void obtainLock() const;

    /** Unlock the service */
    void releaseLock() const;

    /** Return number of assigned addresses on the network. Service must be locked. */
    int addressCount(uint64_t net_id) const;

    /** Return number of managed routes on the network. Service must be locked. */
    int routeCount(uint64_t net_id) const;

    /** Return number of multicast subscriptions on the network. Service must be locked. */
    int multicastSubCount(uint64_t net_id) const;

    /** Return peer info for a given MAC address. */
    int getPeer(uint64_t net_id, uint64_t mac, zts_peer_info_t* peerInfo) const;

    /** Return number of known physical paths to the peer. Service must be locked. */
    int pathCount(uint64_t peer_id) const;

    int getAddrAtIdx(uint64_t net_id, unsigned int idx, char* dst, unsigned int len);

    int getRouteAtIdx(
        uint64_t net_id,
        unsigned int idx,
        char* target,
        char* via,
        unsigned int len,
        uint16_t* flags,
        uint16_t* metric);

    int getMulticastSubAtIdx(uint64_t net_id, unsigned int idx, uint64_t* mac, uint32_t* adi);

    int getPathAtIdx(uint64_t peer_id, unsigned int idx, char* path, unsigned int len);

    /** Orbit a moon */
    int orbit(uint64_t moonWorldId, uint64_t moonSeed);

    /** De-orbit a moon */
    int deorbit(uint64_t moonWorldId);

    /** Return the integer-form of the node's identity */
    uint64_t getNodeId();

    /** Gets the node's identity */
    int getIdentity(char* keypair, unsigned int* len);

    /** Set the node's identity */
    int setIdentity(const char* keypair, unsigned int len);

    void nodeStatePutFunction(enum ZT_StateObjectType type, const uint64_t id[2], const void* data, unsigned int len);

    int nodeStateGetFunction(enum ZT_StateObjectType type, const uint64_t id[2], void* data, unsigned int maxlen);

    int nodeWirePacketSendFunction(
        const int64_t localSocket,
        const struct sockaddr_storage* addr,
        const void* data,
        unsigned int len,
        unsigned int ttl);

    void nodeVirtualNetworkFrameFunction(
        uint64_t net_id,
        void** nuptr,
        uint64_t sourceMac,
        uint64_t destMac,
        unsigned int etherType,
        unsigned int vlanId,
        const void* data,
        unsigned int len);

    int nodePathCheckFunction(uint64_t ztaddr, const int64_t localSocket, const struct sockaddr_storage* remoteAddr);

    int nodePathLookupFunction(uint64_t ztaddr, unsigned int family, struct sockaddr_storage* result);

    void tapFrameHandler(
        uint64_t net_id,
        const MAC& from,
        const MAC& to,
        unsigned int etherType,
        unsigned int vlanId,
        const void* data,
        unsigned int len);

    int shouldBindInterface(const char* ifname, const InetAddress& ifaddr);

    int _trialBind(unsigned int port);

    /** Return whether the NodeService is running */
    int isRunning() const;

    /** Return whether the node is online */
    int nodeIsOnline() const;

    /** Instruct the NodeService on where to look for identity files and caches */
    int setHomePath(const char* homePath);

    /** Set the primary port */
    int setPrimaryPort(unsigned short primaryPort);

    /** Set random range to select backup ports from */
    int setRandomPortRange(unsigned short startPort, unsigned short endPort);

    /** Get the primary port */
    unsigned short getPrimaryPort() const;

    /** Allow or disallow port-mapping */
    int allowPortMapping(unsigned int allowed);

    /** Allow or disallow backup port */
    int allowSecondaryPort(unsigned int allowed);

    /** Set the event system instance used to convey messages to the user */
    int setUserEventSystem(Events* events);

    void enableEvents();

    /** Set the roots definition */
    int setRoots(const void* data, unsigned int len);

    /** Add Interface prefix to blacklist (prevents ZeroTier from using that interface) */
    int addInterfacePrefixToBlacklist(const char* prefix, unsigned int len);

    /** Return the MAC Address of the node in the given network */
    uint64_t getMACAddress(uint64_t net_id) const;

    /** Get the string format name of a network */
    int getNetworkName(uint64_t net_id, char* dst, unsigned int len) const;

    /** Allow ZeroTier to cache peer hints to storage */
    int allowPeerCaching(unsigned int allowed);

    /** Allow ZeroTier to cache network info to storage */
    int allowNetworkCaching(unsigned int allowed);

    /** Allow ZeroTier to write identities to storage */
    int allowIdentityCaching(unsigned int allowed);

    /** Allow ZeroTier to cache root definitions to storage */
    int allowRootSetCaching(unsigned int allowed);

    /** Return whether broadcast is enabled on the given network */
    int getNetworkBroadcast(uint64_t net_id);

    /** Return the MTU of the given network */
    int getNetworkMTU(uint64_t net_id);

    /** Return whether the network is public or private */
    int getNetworkType(uint64_t net_id);

    /** Return the status of the network join */
    int getNetworkStatus(uint64_t net_id);

    /** Get the first address assigned by the network */
    int getFirstAssignedAddr(uint64_t net_id, unsigned int family, struct zts_sockaddr_storage* addr);

    /** Get an array of assigned addresses for the given network */
    int getAllAssignedAddr(uint64_t net_id, struct zts_sockaddr_storage* addr, unsigned int* count);

    /** Return whether a managed route of the given family has been assigned by the network */
    int networkHasRoute(uint64_t net_id, unsigned int family);

    /** Return whether an address of the given family has been assigned by the network */
    int addrIsAssigned(uint64_t net_id, unsigned int family);

    void phyOnTcpConnect(PhySocket* sock, void** uptr, bool success)
    {
        ZTS_UNUSED_ARG(sock);
        ZTS_UNUSED_ARG(uptr);
        ZTS_UNUSED_ARG(success);
    }
    void phyOnTcpAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN, const struct sockaddr* from)
    {
        ZTS_UNUSED_ARG(sockL);
        ZTS_UNUSED_ARG(sockN);
        ZTS_UNUSED_ARG(uptrL);
        ZTS_UNUSED_ARG(uptrN);
        ZTS_UNUSED_ARG(from);
    }
    void phyOnTcpClose(PhySocket* sock, void** uptr)
    {
        ZTS_UNUSED_ARG(sock);
        ZTS_UNUSED_ARG(uptr);
    }
    void phyOnTcpData(PhySocket* sock, void** uptr, void* data, unsigned long len)
    {
        ZTS_UNUSED_ARG(sock);
        ZTS_UNUSED_ARG(uptr);
        ZTS_UNUSED_ARG(data);
        ZTS_UNUSED_ARG(len);
    }
    void phyOnTcpWritable(PhySocket* sock, void** uptr)
    {
        ZTS_UNUSED_ARG(sock);
        ZTS_UNUSED_ARG(uptr);
    }
    void phyOnFileDescriptorActivity(PhySocket* sock, void** uptr, bool readable, bool writable)
    {
        ZTS_UNUSED_ARG(sock);
        ZTS_UNUSED_ARG(uptr);
        ZTS_UNUSED_ARG(readable);
        ZTS_UNUSED_ARG(writable);
    }
    void phyOnUnixAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN)
    {
        ZTS_UNUSED_ARG(sockL);
        ZTS_UNUSED_ARG(sockN);
        ZTS_UNUSED_ARG(uptrL);
        ZTS_UNUSED_ARG(uptrN);
    }
    void phyOnUnixClose(PhySocket* sock, void** uptr)
    {
        ZTS_UNUSED_ARG(sock);
        ZTS_UNUSED_ARG(uptr);
    }
    void phyOnUnixData(PhySocket* sock, void** uptr, void* data, unsigned long len)
    {
        ZTS_UNUSED_ARG(sock);
        ZTS_UNUSED_ARG(uptr);
        ZTS_UNUSED_ARG(data);
        ZTS_UNUSED_ARG(len);
    }

    void phyOnUnixWritable(PhySocket* sock, void** uptr)
    {
        ZTS_UNUSED_ARG(sock);
        ZTS_UNUSED_ARG(uptr);
    }
};

}   // namespace ZeroTier

#endif
