libcoap 4.3.5-develop-4c7ce99
|
coap_proxy, coap_proxy_forward_request, coap_proxy_forward_response, coap_verify_proxy_scheme_supported - Work with CoAP proxies
#include <coap3/coap.h>
int coap_proxy_forward_request(coap_session_t *req_session, const coap_pdu_t *request, coap_pdu_t *response, coap_resource_t *resource, coap_cache_key_t *cache_key, coap_proxy_server_list_t *server_list);
coap_response_t coap_proxy_forward_response(coap_session_t *rsp_session, const coap_pdu_t *received, coap_cache_key_t **cache_key);
int coap_verify_proxy_scheme_supported(coap_uri_scheme_t scheme);
For specific (D)TLS library support, link with -lcoap-3-notls, -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls, -lcoap-3-wolfssl or -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default (D)TLS library support.
To simplify CoAP proxy requirements, proxy forwarding functionality is provided by libcoap for matching forwarded requests with returning responses.
Two principal types of Proxy are supported.
Reverse
The reverse proxy intercepts all the traffic from the clients and sends off all of the requests to a defined (usually internal and protected) upstream server and passes back any responses to the requesting client. There is no differentiation between requests that contain a Proxy-Uri or Proxy-Scheme option and those that do not.
Forward
The forward proxy receives any request from the client that contains a Proxy-Uri or Proxy-Scheme option and then forwards the request to an upstream server. This server can either be derived from the Proxy-Uri or Proxy-Scheme option or be an explicitly configured server. The returning response is then sent back to the initiating client. If the determined IP address of the forward server matches one of the list of defined names this proxy server is known by, then the request is handled locally and not forwarded.
The forward proxy has two modes of working. The first, forward-dynamic, takes the information from the Proxy-Uri or Proxy-Scheme and forwards the request to the dynamically derived upstream server. The second, forward-static always forwards the request to the defined upstream server.
Before any of the proxy types pass on any information they, optionally, can strip out and appropriately replace any Proxy-Uri or Proxy-Scheme options to stop the upstream server from trying to do any further Proxy operations.
NOTE: In the general case, reverse and forward-dynamic should be stripped, but forward-static not.
It is possible to define multiple upstream servers for reverse and forward-static proxy types. These will then be allocated to each new client session in a round-robin fashion.
For the forward-dynamic proxy type, a dummy server needs to be defined if any specific PKI/PSK or OSCORE is required for the ongoing session to the dynamically determined upstream server. If client anonymous PKI only is required for ongoing encrypted sessions, then this dummy server does not need to be defined.
For each upstream server, client sessions can all be multiplexed over a single upstream server session, or there can be the same number of upstream server sessions as there are client sessions.
The proxy logic will convert between supported protocals - e.g. coap <> coaps+tcp for the incoming and upstream session. Conversions to/from http(s) are not currently supported.
The resourse handler to handle forward proxy requests is defined using coap_resource_proxy_uri_init2(3).
The resource handler to handle reverse proxy requests is defined using coap_resource_reverse_proxy_init(3).
Function: coap_proxy_forward_request()
typedef enum { COAP_PROXY_REVERSE, /* Act as a reverse proxy */ COAP_PROXY_REVERSE_STRIP, /* Act as a reverse proxy, strip out any proxy options */ COAP_PROXY_FORWARD_STATIC, /* Act as a forward-static proxy */ COAP_PROXY_FORWARD_STATIC_STRIP, /* Act as a forward-static proxy, strip out any proxy options */ COAP_PROXY_FORWARD_DYNAMIC, /* Act as a forward-dynamic proxy using the request's Proxy-Uri or Proxy-Scheme options to determine server */ COAP_PROXY_FORWARD_DYNAMIC_STRIP, /* Act as a forward-dynamic proxy, strip out proxy options */ } coap_proxy_t; typedef struct coap_proxy_server_t { coap_uri_t uri; /* host and port define the server, scheme method */ coap_dtls_pki_t *dtls_pki; /* PKI configuration to use if not NULL */ coap_dtls_cpsk_t *dtls_cpsk; /* PSK configuration to use if not NULL */ coap_oscore_conf_t *oscore_conf; /* OSCORE configuration if not NULL */ } coap_proxy_server_t; typedef struct coap_proxy_server_list_t { coap_proxy_server_t *entry; /* Set of servers to connect to */ size_t entry_count; /* The number of servers in entry list */ size_t next_entry; /* Next server to use (% entry_count) */ coap_proxy_t type; /* The proxy type */ int track_client_session; /* If 1, track individual connections to upstream server, else 0 for all clients to share the same ongoing session */ unsigned int idle_timeout_secs; /* Proxy upstream session idle timeout (0 is no timeout) */ } coap_proxy_server_list_t;
The coap_proxy_forward_request() function is called from a request handler when the request needs to be forwarded to an upstream server with a possible change in protocol. req_session, request, response and resource are as provided to the application’s request handler. cache_key can be a cache_key generated from the request PDU or NULL. This cache_key will get passed into coap_proxy_forward_response() when handling the response. server_list defines the characteristics of zero or more of the upstream servers to connect to. The definitions can cover the following
Acting as a reverse proxy - connect to defined internal server (possibly round robin load balancing over multiple servers). Acting as a forward-dynamic proxy - connect to host defined in Proxy-Uri or Proxy-Scheme with Uri-Host (and maybe Uri-Port). Acting as a forward-static proxy - connect to defined upstream server (possibly round robin load balancing over multiple servers).
If the entry_count of coap_proxy_server_list_t is more than 1, then the ongoing session for each new request will get round-robined through the set of defined servers. If the entry_count of coap_proxy_server_list_t is 0, then the proxy type can only be forward-dynamic.
The response PDU is updated with the appropriate CoAP response code, and so the caller does not need to update this on error detection after calling coap_proxy_forward_request().
coap_proxy_forward_request() will establish a new ongoing session to the upstream server as and when required.
Function: coap_proxy_forward_response()
The coap_proxy_forward_response() function is used to forward on any response that comes back from the back-end server and given to the application’s response handler. It will be forwarded on to the originating client doing any necessary changes in protocol. rsp_session is the session given to the application’s response handler (created by coap_proxy_forward_request()), received is the received PDU. If the cache_key parameter is not NULL, then it will get updated with the cache_key provided to the coap_proxy_forward_request() request. The caller should delete this cache key (unless the client request set up an Observe and there will be unsolicited responses). If cache_key is not defined, but a cache_key was passed into coap_proxy_forward_request() then it will get deleted.
Function: coap_verify_proxy_scheme_supported()
The coap_verify_proxy_scheme_supported() function verifies that the requested URI scheme type scheme is supported for an ongoing connection.
coap_proxy_forward_request() and coap_verify_proxy_scheme_supported() return 1 on success and 0 on failure.
coap_proxy_forward_response() returns one of COAP_RESPONSE_OK or COAP_RESPONSE_FAIL.
Reverse Proxy Set Up
#include <coap3/coap.h> static const coap_uri_t uri = { .host = {sizeof("1.2.3.4")-1, (const uint8_t *)"1.2.3.4"}, .port = 5683, .path = {0, NULL}, .query = {0, NULL}, .scheme = COAP_URI_SCHEME_COAP /* Set to COAPS or COAPS_TCP for PSK/PKI */ }; static coap_proxy_server_t redirect_server[] = { /* * Could be multiple of these with different uri/encryption for doing * a round-robin */ { .uri = uri, .dtls_pki = NULL, /* Define if PKI is to be used for upstream session */ .dtls_cpsk = NULL, /* Define if PSK is to be used for upstream session */ .oscore_conf = NULL /* Define if OSCORE is to be used for upstream session */ } }; static coap_proxy_server_list_t reverse_proxy = { .entry = redirect_server, .entry_count = sizeof(redirect_server)/sizeof(redirect_server[0]), .next_entry = 0, .type = COAP_PROXY_REVERSE_STRIP, .track_client_session = 0, .idle_timeout_secs = 300 }; static void hnd_reverse_proxy_uri(coap_resource_t *resource, coap_session_t *req_session, const coap_pdu_t *request, const coap_string_t *query COAP_UNUSED, coap_pdu_t *response) { if (!coap_proxy_forward_request(req_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 *rsp_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(rsp_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 */ }
Forward-dynamic Proxy Set Up (server derived from Proxy-Uri or Proxy-Scheme options
#include <coap3/coap.h> static const char *proxy_host_name_list[2] = { "myservername", "1.2.3.5" /* my server IP */ }; static coap_proxy_server_list_t forward_dynamic_proxy = { .entry = NULL, /* Include dummy server with encryption definitions if needed */ .entry_count = 0, /* if 0 and encryption, client anonymous PKI used */ .next_entry = 0, .type = COAP_PROXY_FORWARD_DYNAMIC_STRIP, .track_client_session = 0, .idle_timeout_secs = 10 }; static void hnd_forward_proxy_uri(coap_resource_t *resource, coap_session_t *req_session, const coap_pdu_t *request, const coap_string_t *query COAP_UNUSED, coap_pdu_t *response) { if (!coap_proxy_forward_request(req_session, request, response, resource, NULL, &forward_dynamic_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 *rsp_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(rsp_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, sizeof(proxy_host_name_list)/sizeof(proxy_host_name_list[0]), 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 */ }
Forward-static Proxy Set Up (to relay to defined server)
#include <coap3/coap.h> static const char *proxy_host_name_list[2] = { "myservername", "1.2.3.5" /* my server IP */ }; static const coap_uri_t uri = { .host = {sizeof("1.2.3.4")-1, (const uint8_t *)"1.2.3.4"}, .port = 5683, .path = {0, NULL}, .query = {0, NULL}, .scheme = COAP_URI_SCHEME_COAP /* Set to COAPS or COAPS_TCP for PSK/PKI */ }; static coap_proxy_server_t forward_static_server[] = { /* Could be multiple of these with different uri for doing a round-robin */ { .uri = uri, .dtls_pki = NULL, /* Define if PKI is to be used for upstream session */ .dtls_cpsk = NULL, /* Define if PSK is to be used for upstream session */ .oscore_conf = NULL /* Define if OSCORE is to be used for upstream session */ } }; static coap_proxy_server_list_t forward_static_proxy = { .entry = forward_static_server, .entry_count = sizeof(forward_static_server)/sizeof(forward_static_server[0]), .next_entry = 0, .type = COAP_PROXY_FORWARD_STATIC, .track_client_session = 0, .idle_timeout_secs = 300 }; static void hnd_onward_proxy_uri(coap_resource_t *resource, coap_session_t *req_session, const coap_pdu_t *request, const coap_string_t *query COAP_UNUSED, coap_pdu_t *response) { if (!coap_proxy_forward_request(req_session, request, response, resource, NULL, &forward_static_proxy)) { coap_log_debug("hnd_onward_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 *rsp_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(rsp_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_onward_proxy_uri, sizeof(proxy_host_name_list)/sizeof(proxy_host_name_list[0]), 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 */ }
See
"RFC7252: The Constrained Application Protocol (CoAP)"
for further information.
Please raise an issue on GitHub at https://github.com/obgm/libcoap/issues to report any bugs.
Please raise a Pull Request at https://github.com/obgm/libcoap/pulls for any fixes.