From 3d790a5964cca986733fdd495152b7b2f942ad57 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Fri, 16 Aug 2024 12:35:48 +0100 Subject: [PATCH] reverse-proxy: Provide dedicated reverse-proxy handler setup function --- examples/coap-server.c | 12 +--- include/coap3/coap_resource.h | 23 ++++++- libcoap-3.map | 1 + libcoap-3.sym | 1 + man/Makefile.am | 1 + man/coap_proxy.txt.in | 125 +++++++++++++++++++++++++++++++++- man/coap_resource.txt.in | 27 +++++++- src/coap_resource.c | 32 ++++++++- 8 files changed, 204 insertions(+), 18 deletions(-) diff --git a/examples/coap-server.c b/examples/coap-server.c index 8cb926a6bf..d403901a7e 100644 --- a/examples/coap-server.c +++ b/examples/coap-server.c @@ -1122,15 +1122,7 @@ init_resources(coap_context_t *ctx) { #if COAP_PROXY_SUPPORT if (reverse_proxy.entry_count) { /* Create a reverse proxy resource to handle PUTs */ - r = coap_resource_unknown_init2(hnd_reverse_proxy_uri, - COAP_RESOURCE_HANDLE_WELLKNOWN_CORE); - /* Add in handling other requests as well */ - coap_register_handler(r, COAP_REQUEST_GET, hnd_reverse_proxy_uri); - coap_register_handler(r, COAP_REQUEST_POST, hnd_reverse_proxy_uri); - coap_register_handler(r, COAP_REQUEST_DELETE, hnd_reverse_proxy_uri); - coap_register_handler(r, COAP_REQUEST_FETCH, hnd_reverse_proxy_uri); - coap_register_handler(r, COAP_REQUEST_PATCH, hnd_reverse_proxy_uri); - coap_register_handler(r, COAP_REQUEST_IPATCH, hnd_reverse_proxy_uri); + r = coap_resource_reverse_proxy_init(hnd_reverse_proxy_uri, 0); coap_add_resource(ctx, r); coap_register_event_handler(ctx, proxy_event_handler); coap_register_response_handler(ctx, reverse_response_handler); @@ -1840,7 +1832,7 @@ cmdline_proxy(char *arg) { new_entry = realloc(forward_proxy.entry, (forward_proxy.entry_count + 1)*sizeof(forward_proxy.entry[0])); if (!new_entry) { - coap_log_err("CoAP Reverse-Proxy realloc() error\n"); + coap_log_err("CoAP Proxy realloc() error\n"); return 0; } forward_proxy.entry = new_entry; diff --git a/include/coap3/coap_resource.h b/include/coap3/coap_resource.h index b4661dcaa4..58f13e5c99 100644 --- a/include/coap3/coap_resource.h +++ b/include/coap3/coap_resource.h @@ -226,8 +226,8 @@ coap_resource_t *coap_resource_unknown_init(coap_method_handler_t put_handler); * DELETE handler specified for the resource removal) or by maintaining an * active resource list. * - * Note: There can only be one unknown resource handler per context - attaching - * a new one overrides the previous definition. + * Note: There can only be one unknown or reverse-proxy resource handler per + * context - attaching a new one overrides the previous definition. * * Note: It is not possible to observe the unknown resource with a GET request * - a separate resource needs to be created by the PUT (or POST) @@ -286,6 +286,25 @@ coap_resource_t *coap_resource_proxy_uri_init2(coap_method_handler_t handler, const char *host_name_list[], int flags); +/** + * Creates a new resource object for the reverse-proxy resource handler with + * control over multicast request packets. + * + * Note: There can only be one reverse-proxy or unknown resource handler per + * context - attaching a new one overrides the previous definition. + * + * This function returns the new coap_resource_t object. + * + * @param handler The PUT/POST/GET etc. handler that handles all the reverse-proxy + * requests including .well-known-core. + * @param flags Zero or more COAP_RESOURCE_FLAGS_*MCAST* ored together to + * indicate what to do with multicast packets. + * + * @return A pointer to the new object or @c NULL on error. + */ +coap_resource_t *coap_resource_reverse_proxy_init(coap_method_handler_t handler, + int flags); + /** * Returns the resource identified by the unique string @p uri_path. If no * resource was found, this function returns @c NULL. diff --git a/libcoap-3.map b/libcoap-3.map index db0fa08ff0..6ad63a06cc 100644 --- a/libcoap-3.map +++ b/libcoap-3.map @@ -226,6 +226,7 @@ global: coap_resource_proxy_uri_init2; coap_resource_proxy_uri_init; coap_resource_release_userdata_handler; + coap_resource_reverse_proxy_init; coap_resource_set_dirty; coap_resource_set_get_observable; coap_resource_set_mode; diff --git a/libcoap-3.sym b/libcoap-3.sym index 208ebb311d..ce69b88c81 100644 --- a/libcoap-3.sym +++ b/libcoap-3.sym @@ -224,6 +224,7 @@ coap_resource_notify_observers coap_resource_proxy_uri_init coap_resource_proxy_uri_init2 coap_resource_release_userdata_handler +coap_resource_reverse_proxy_init coap_resource_set_dirty coap_resource_set_get_observable coap_resource_set_mode diff --git a/man/Makefile.am b/man/Makefile.am index 18ecde472d..c99ba083bf 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -195,6 +195,7 @@ install-man: install-man3 install-man5 install-man7 @echo ".so man3/coap_recovery.3" > coap_session_set_probing_rate.3 @echo ".so man3/coap_recovery.3" > coap_session_get_probing_rate.3 @echo ".so man3/coap_recovery.3" > coap_debug_set_packet_loss.3 + @echo ".so man3/coap_resource.3" > coap_delete_resource.3 @echo ".so man3/coap_resource.3" > coap_resource_set_mode.3 @echo ".so man3/coap_resource.3" > coap_resource_set_userdata.3 @echo ".so man3/coap_resource.3" > coap_resource_get_userdata.3 diff --git a/man/coap_proxy.txt.in b/man/coap_proxy.txt.in index a83810fddf..203b1a2a72 100644 --- a/man/coap_proxy.txt.in +++ b/man/coap_proxy.txt.in @@ -41,8 +41,11 @@ or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with DESCRIPTION ----------- -To simplify some of the CoAP proxy requirements, some of the functionaliy -is provided by libcoap. +To simplify some of the CoAP proxy requirements, some of the proxy forwarding +functionality is provided by libcoap. + +The resourse handlers to handle forward or reverse proxy requests are defined using +*coap_resource_proxy_uri_init2*(3) or coap_resource_reverse_proxy_init*(3). FUNCTIONS --------- @@ -81,6 +84,124 @@ return 1 on success and 0 on failure. *coap_proxy_forward_response*() returns one of COAP_RESPONSE_OK or COAP_RESPONSE_FAIL. +EXAMPLES +-------- +*Forward Proxy Set Up* + +[source, c] +---- +#include + +static size_t proxy_host_name_count = 0; +static const char **proxy_host_name_list = NULL; +static coap_proxy_server_list_t forward_proxy = { NULL, 0, 0, COAP_PROXY_FORWARD, 0, 300}; + +static void +hnd_forward_proxy_uri(coap_resource_t *resource, + coap_session_t *session, + const coap_pdu_t *request, + const coap_string_t *query COAP_UNUSED, + coap_pdu_t *response) { + + if (!coap_proxy_forward_request(session, request, response, resource, + NULL, &forward_proxy)) { + coap_log_debug("hnd_forward_proxy_uri: Failed to forward PDU\n"); + /* Non ACK response code set on error detection */ + } + + /* Leave response code as is */ +} + +static coap_response_t +proxy_response_handler(coap_session_t *session, + const coap_pdu_t *sent COAP_UNUSED, + const coap_pdu_t *received, + const coap_mid_t id COAP_UNUSED) { + return coap_proxy_forward_response(session, received, NULL); +} + +static void +init_resources(coap_context_t *ctx) { + + coap_resource_t *r; + + /* See coap_resource_proxy_uri_init2(3) */ + r = coap_resource_proxy_uri_init2(hnd_forward_proxy_uri, proxy_host_name_count, + proxy_host_name_list, 0); + coap_add_resource(ctx, r); + coap_register_response_handler(ctx, proxy_response_handler); + /* Add in event or nack handlers if required */ +} + +static void +init_proxy_info(coap_uri_t *proxy_uri, const char *proxy_host_name) { + coap_proxy_server_t *new_entry; + + new_entry = realloc(forward_proxy.entry, + (forward_proxy.entry_count + 1)*sizeof(forward_proxy.entry[0])); + + if (!new_entry) { + coap_log_err("CoAP Proxy realloc() error\n"); + return; + } + /* Can have multiple of these upstream proxy hosts for doing round robin etc. */ + forward_proxy.entry = new_entry; + memset(&forward_proxy.entry[forward_proxy.entry_count], 0, sizeof(forward_proxy.entry[0])); + forward_proxy.entry[forward_proxy.entry_count].uri = *proxy_uri; + forward_proxy.entry_count++; + + /* The proxy host could be known by multile names - add them all in */ + proxy_host_name_count = 0; + proxy_host_name_list = coap_malloc(proxy_host_name_count * sizeof(char *)); + proxy_host_name_list[0] = proxy_host_name; +} +---- + +*Reverse Proxy Set Up* + +[source, c] +---- +#include + +static coap_proxy_server_list_t reverse_proxy = { NULL, 0, 0, COAP_PROXY_REVERSE_STRIP, 0, 10}; + +static void +hnd_reverse_proxy_uri(coap_resource_t *resource, + coap_session_t *session, + const coap_pdu_t *request, + const coap_string_t *query COAP_UNUSED, + coap_pdu_t *response) { + + if (!coap_proxy_forward_request(session, request, response, resource, + NULL, &reverse_proxy)) { + coap_log_debug("hnd_reverse_proxy: Failed to forward PDU\n"); + /* Non ACK response code set on error detection */ + } + + /* Leave response code as is */ +} + +static coap_response_t +proxy_response_handler(coap_session_t *session, + const coap_pdu_t *sent COAP_UNUSED, + const coap_pdu_t *received, + const coap_mid_t id COAP_UNUSED) { + return coap_proxy_forward_response(session, received, NULL); +} + +static void +init_resources(coap_context_t *ctx) { + + coap_resource_t *r; + + /* See coap_resource_reverse_proxy_init(3) */ + r = coap_resource_reverse_proxy_init(hnd_reverse_proxy_uri, 0); + coap_add_resource(ctx, r); + coap_register_response_handler(ctx, proxy_response_handler); + /* Add in event or nack handlers if required */ +} +---- + FURTHER INFORMATION ------------------- See diff --git a/man/coap_resource.txt.in b/man/coap_resource.txt.in index 057119ab83..739ac9aa70 100644 --- a/man/coap_resource.txt.in +++ b/man/coap_resource.txt.in @@ -16,6 +16,7 @@ coap_resource_unknown_init, coap_resource_unknown_init2, coap_resource_proxy_uri_init, coap_resource_proxy_uri_init2, +coap_resource_reverse_proxy_init, coap_add_resource, coap_delete_resource, coap_resource_set_mode, @@ -47,6 +48,9 @@ _proxy_handler_, size_t _host_name_count_, const char *_host_name_list_[]);* _proxy_handler_, size_t _host_name_count_, const char *_host_name_list_[], int _flags_);* +*coap_resource_t *coap_resource_reverse_proxy_init(coap_method_handler_t +_rev_proxy_handler_, int _flags_);* + *void coap_add_resource(coap_context_t *_context_, coap_resource_t *_resource_);* @@ -224,6 +228,9 @@ _resource_ to handle PUT requests to resources that are unknown. Additional handlers can be added to this resource if required. _flags_ can be zero or more of the COAP_RESOURCE_FLAGS MCAST definitions. +*NOTE:* There can only be one reverse-proxy or unknown resource handler per +context - attaching a new one overrides the previous definition. + *Function: coap_resource_proxy_uri_init()* The *coap_resource_proxy_uri_init*() function returns a newly created @@ -248,6 +255,20 @@ _host_name_count_. This is used to check whether the current endpoint is the proxy target address, or the request has to be passed on to an upstream server. _flags_ can be zero or more COAP_RESOURCE_FLAGS MCAST definitions. +*NOTE:* There can only be one proxy resource handler per +context - attaching a new one overrides the previous definition. + +*Function: coap_resource_reverse_proxy_init()* + +The *coap_resource_reverse_proxy_init*() function returns a newly created +_resource_ of type _coap_resource_t_ *. _rev_proxy_handler_ is automatically added +to the _resource_ to handle all the PUT/POST/GET etc. requests including +.well-known/core. There is no need to add explicit request type handlers. +_flags_ can be zero or more COAP_RESOURCE_FLAGS MCAST definitions. + +*NOTE:* There can only be one reverse-proxy or unknown resource handler per +context - attaching a new one overrides the previous definition. + *Function: coap_add_resource()* The *coap_add_resource*() function registers the given _resource_ with the @@ -319,9 +340,9 @@ The _query_filter_ is usually defined by the CoAP Uri-Query options as a query. RETURN VALUES ------------- *coap_resource_init*(), *coap_resource_unknown_init*(), -*coap_resource_unknown_init2*(), *coap_resource_proxy_uri_init*() and -*coap_resource_proxy_uri_init2*() return a newly created resource -or NULL if there is a malloc failure. +*coap_resource_unknown_init2*(), *coap_resource_proxy_uri_init*(), +*coap_resource_proxy_uri_init2*() and *coap_resource_reverse_proxy_init*() +return a newly created resource or NULL if there is a malloc failure. *coap_delete_resource*() returns 0 on failure (_resource_ not found), 1 on success. diff --git a/src/coap_resource.c b/src/coap_resource.c index 6c71d271b8..90d69823f7 100644 --- a/src/coap_resource.c +++ b/src/coap_resource.c @@ -305,7 +305,7 @@ coap_resource_unknown_init2(coap_method_handler_t put_handler, int flags) { r->flags = flags & ~COAP_RESOURCE_FLAGS_RELEASE_URI; coap_register_handler(r, COAP_REQUEST_PUT, put_handler); } else { - coap_log_debug("coap_resource_unknown_init: no memory left\n"); + coap_log_debug("coap_resource_unknown_init2: no memory left\n"); } return r; @@ -375,6 +375,36 @@ coap_resource_proxy_uri_init(coap_method_handler_t handler, host_name_list, 0); } +static const uint8_t coap_rev_proxy_resource_uri[] = + "- Rev Proxy -"; + +coap_resource_t * +coap_resource_reverse_proxy_init(coap_method_handler_t handler, int flags) { + coap_resource_t *r; + + r = (coap_resource_t *)coap_malloc_type(COAP_RESOURCE, sizeof(coap_resource_t)); + if (r) { + memset(r, 0, sizeof(coap_resource_t)); + r->is_unknown = 1; + /* Something unlikely to be used, but it shows up in the logs */ + r->uri_path = coap_new_str_const(coap_rev_proxy_resource_uri, + sizeof(coap_rev_proxy_resource_uri)-1); + r->flags = flags & ~COAP_RESOURCE_FLAGS_RELEASE_URI; + r->flags |= COAP_RESOURCE_HANDLE_WELLKNOWN_CORE; + coap_register_handler(r, COAP_REQUEST_PUT, handler); + coap_register_handler(r, COAP_REQUEST_GET, handler); + coap_register_handler(r, COAP_REQUEST_POST, handler); + coap_register_handler(r, COAP_REQUEST_DELETE, handler); + coap_register_handler(r, COAP_REQUEST_FETCH, handler); + coap_register_handler(r, COAP_REQUEST_PATCH, handler); + coap_register_handler(r, COAP_REQUEST_IPATCH, handler); + } else { + coap_log_debug("coap_resource_rev_proxy_init: no memory left\n"); + } + + return r; +} + coap_attr_t * coap_add_attr(coap_resource_t *resource, coap_str_const_t *name,