diff --git a/cmd/zerotier/cli/help.go b/cmd/zerotier/cli/help.go index 85e97b314..619fa7480 100644 --- a/cmd/zerotier/cli/help.go +++ b/cmd/zerotier/cli/help.go @@ -36,6 +36,7 @@ Common Operations: help Show this help version Print version + now [duration] Print current time [-]#[ms|s|m|h] ยท status Show node status and configuration diff --git a/cmd/zerotier/zerotier.go b/cmd/zerotier/zerotier.go index 41d6bef9c..d5d76c17f 100644 --- a/cmd/zerotier/zerotier.go +++ b/cmd/zerotier/zerotier.go @@ -22,6 +22,7 @@ import ( "runtime" "runtime/debug" "strings" + "time" "zerotier/cmd/zerotier/cli" "zerotier/pkg/zerotier" @@ -133,6 +134,22 @@ func main() { cli.Help() case "version": fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision) + case "now": + if len(args) > 2 { + cli.Help() + exitCode = 1 + } else if len(args) == 2 { + d, err := time.ParseDuration(args[1]) + if err == nil { + fmt.Printf("%d\n", zerotier.TimeMs() + d.Milliseconds()) + } else { + fmt.Printf("FATAL: invalid duration \"%s\": %s\n", args[1], err.Error()) + exitCode = 1 + } + } else { + fmt.Printf("%d\n", zerotier.TimeMs()) + } + case "service": exitCode = cli.Service(basePath, cmdArgs) case "status", "info": diff --git a/core/Node.cpp b/core/Node.cpp index 24fbf0d0f..a5b7fd9e3 100644 --- a/core/Node.cpp +++ b/core/Node.cpp @@ -212,20 +212,6 @@ ZT_ResultCode Node::processVirtualNetworkFrame( } } -ZT_ResultCode Node::processHTTPResponse( - void *tptr, - int64_t now, - void *requestId, - int responseCode, - const char **headerNames, - const char **headerValues, - const void *body, - unsigned int bodySize, - unsigned int flags) -{ - return ZT_RESULT_OK; -} - ZT_ResultCode Node::processBackgroundTasks( void *tPtr, int64_t now, @@ -966,27 +952,6 @@ enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( } } -enum ZT_ResultCode ZT_Node_processHTTPResponse( - ZT_Node *node, - void *tptr, - int64_t now, - void *requestId, - int responseCode, - const char **headerNames, - const char **headerValues, - const void *body, - unsigned int bodySize, - unsigned int flags) -{ - try { - return reinterpret_cast(node)->processHTTPResponse(tptr, now, requestId, responseCode, headerNames, headerValues, body, bodySize, flags); - } catch (std::bad_alloc &exc) { - return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY; - } catch (...) { - return ZT_RESULT_ERROR_INTERNAL; - } -} - enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node, void *tptr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline) { try { diff --git a/core/Node.hpp b/core/Node.hpp index 2fd0f344b..a38a167c9 100644 --- a/core/Node.hpp +++ b/core/Node.hpp @@ -71,17 +71,6 @@ public: unsigned int frameLength, volatile int64_t *nextBackgroundTaskDeadline); - ZT_ResultCode processHTTPResponse( - void *tptr, - int64_t now, - void *requestId, - int responseCode, - const char **headerNames, - const char **headerValues, - const void *body, - unsigned int bodySize, - unsigned int flags); - ZT_ResultCode processBackgroundTasks( void *tPtr, int64_t now, diff --git a/core/zerotier.h b/core/zerotier.h index a9c0e0344..1b21be135 100644 --- a/core/zerotier.h +++ b/core/zerotier.h @@ -1872,29 +1872,6 @@ typedef int (*ZT_WirePacketSendFunction)( unsigned int, /* Packet length */ unsigned int); /* TTL or 0 to use default */ -/** - * Function to initiate HTTP requests - * - * The supplied HTTP request identifier is an opaque pointer that must - * be returned via ZT_Node_processHttpResponse(). If this handler is - * implemented then ZT_Node_processHttpResponse() must be called for - * each call made by the core to this. This function itself does not - * return any error code; use processHttpResponse() for that. It may - * be called directly from inside the implementation of this. - */ -typedef void (*ZT_HTTPRequestFunction)( - ZT_Node *, /* Node */ - void *, /* User ptr */ - void *, /* Thread ptr */ - void *, /* HTTP request identifier */ - const char *, /* HTTP method (GET, HEAD, etc.) */ - const char *, /* URL */ - const char **, /* Header names, NULL terminated */ - const char **, /* Header values, NULL terminated */ - const void *, /* Request body or NULL if none */ - unsigned int, /* Length of request body in bytes */ - unsigned int); /* Flags */ - /** * Function to check whether a path should be used for ZeroTier traffic * @@ -1973,11 +1950,6 @@ struct ZT_Node_Callbacks */ ZT_WirePacketSendFunction wirePacketSendFunction; - /** - * RECOMMENDED: Function to initiate HTTP requests - */ - ZT_HTTPRequestFunction httpRequestFunction; - /** * REQUIRED: Function to inject frames into a virtual network's TAP */ @@ -2128,33 +2100,6 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processVirtualNetworkFrame( int isZtBuffer, volatile int64_t *nextBackgroundTaskDeadline); -/** - * Process a response from HTTP requests initiated via API callback - * - * @param node Node instance - * @param tptr Thread pointer to pass to functions/callbacks resulting from this call - * @param now Current clock in milliseconds - * @param requestId Opaque pointer provided via the requesting callback - * @param responseCode HTTP response code (e.g. 200, 500) - * @param headerNames HTTP header names, terminated by a NULL pointer - * @param headerValues HTTP header values corresponding with each name - * @param body Response body or NULL if none - * @param bodySize Size of response body in bytes - * @param flags Response flags - * @return OK (0) or error code if a fatal error condition has occurred - */ -ZT_SDK_API enum ZT_ResultCode ZT_Node_processHTTPResponse( - ZT_Node *node, - void *tptr, - int64_t now, - void *requestId, - int responseCode, - const char **headerNames, - const char **headerValues, - const void *body, - unsigned int bodySize, - unsigned int flags); - /** * Perform periodic background operations * diff --git a/pkg/zerotier/api.go b/pkg/zerotier/api.go index c87ff1a58..9ce82dfe3 100644 --- a/pkg/zerotier/api.go +++ b/pkg/zerotier/api.go @@ -554,12 +554,35 @@ func createAPIServer(basePath string, node *Node) (*http.Server, *http.Server, e } } + if len(queriedSerialNo) == CertificateSerialNoSize && !bytes.Equal(queriedSerialNo, lc.Certificate.SerialNo) { + _ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"certificate serial does not match serial in path"}) + return + } + + err := node.AddCertificate(lc.Certificate, lc.LocalTrust) + if err == nil { + _ = apiSendObj(out, req, http.StatusOK, lc) + } else { + _ = apiSendObj(out, req, http.StatusBadRequest, &APIErr{"certificate rejected: " + err.Error()}) + } + } else if req.Method == http.MethodDelete { if len(queriedSerialNo) == CertificateSerialNoSize { - } else { - _ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"certificate not found"}) + certs, err := node.ListCertificates() + if err != nil { + _ = apiSendObj(out, req, http.StatusInternalServerError, &APIErr{"unexpected error"}) + return + } + for _, c := range certs { + if bytes.Equal(c.Certificate.SerialNo, queriedSerialNo) { + _ = node.DeleteCertificate(queriedSerialNo) + _ = apiSendObj(out, req, http.StatusOK, c) + return + } + } } + _ = apiSendObj(out, req, http.StatusNotFound, &APIErr{"certificate not found"}) } else { out.Header().Set("Allow", "GET, HEAD, PUT, POST, DELETE")