Skip to content

Commit

Permalink
Proxy: Update Proxy support for Proxy-Uri: CoAP option
Browse files Browse the repository at this point in the history
Add code to better support the Proxy-Uri: and Proxy-Scheme: CoAP Options.

examples/client.c:

Make sure that the Proxy-Uri: option is added (if set) when clearing down an
observation (fixes obgm#112).
Check that Proxy-Uri: option has a maximum data length of 1034 bytes.
Handle user defined Proxy-Scheme: option correctly.
Update -P option to include scheme to be used when connecting to the proxy.

examples/coap-server.c:

Add in hnd_proxy_uri() handler function. This has support for a direct or ongoing
proxy connection for the coap* protocols. The ongoing connection is set up as a
different CoAP session and is assocated with the incoming session for relaying
requests / responses.

Internal functions taken from client.c are used where appropriate.

Proxy support code has a SERVER_CAN_PROXY wrapper, so footprint can easily be
reduced if required.

New -P and -u options added to support ongoing connections.

include/coap2/net.h:

Add in tracking the proxy uri handler into coap_context_t.

include/coap2/resource.h:

Track whether a resource definition is for Proxy-Uri:/Proxy-Scheme:.
Define the coap_resource_proxy_uri_init() function for handling the Proxy-Uri:
option or Proxy-Scheme: option in an incoming request.

include/coap2/uri.h:

Add in COAP_URI_SCHEME_HTTP and COAP_URI_SCHEME_HTTPS as valid Proxy-Uri:
schemes.
Define the coap_split_proxy_uri() function (similar to coap_split_uri() but
supports the proxy extras.  Both now use a common sub function internally.

libcoap-2.map:
libcoap-2.sym:

Expose the new coap_resource_proxy_uri_init() and coap_split_proxy_uri()
functions.

man/Makefile.am:

Handle coap_resource_get_userdata(3) now being over the 10 definition limit
in man/coap_resource.txt.in.

man/coap-client.txt.in:

Update documentation for the -P option.

man/coap-server.txt.in:

Document the new -P proxy option.
Document the new -u user option.

man/coap_resource.txt.in:

Include documentation for coap_resource_proxy_uri_init().

src/coap_debug.c:

Output the Proxy-Scheme: Option as text.

src/net.c:

Sanity check and handle COAP_OPTION_PROXY_URI and COAP_OPTION_PROXY_SCHEME
in handle_request().

src/resource.c:

Add in coap_resource_proxy_uri_init() function.
Handle the addition of a proxy uri handler in coap_add_resource().

src/uri.c:

Rename coap_split_uri() to coap_split_uri_sub() and add in extra proxy
handling support based on input parameters.

Create new coap_split_uri() and coap_split_proxy_uri() which call
coap_split_uri_sub() appropriately.

TODO:

Remove reference to Proxy support required

src/coap_gnutls.c:

Fix a double deallocate found during testing
  • Loading branch information
mrdeep1 committed Oct 28, 2020
1 parent db4c9da commit e4b585c
Show file tree
Hide file tree
Showing 17 changed files with 1,200 additions and 114 deletions.
2 changes: 0 additions & 2 deletions TODO
Expand Up @@ -11,8 +11,6 @@ Classification of issues:
=================
* CRITICAL ISSUES
=================
-> Proxy functionality
-> A coap-server should be able to act as proxy server

================
* SERIOUS ISSUES
Expand Down
170 changes: 107 additions & 63 deletions examples/client.c
Expand Up @@ -56,8 +56,9 @@ static coap_optlist_t *optlist = NULL;
/* Request URI.
* TODO: associate the resources with transaction id and make it expireable */
static coap_uri_t uri;
static coap_string_t proxy = { 0, NULL };
static uint16_t proxy_port = COAP_DEFAULT_PORT;
static coap_uri_t proxy = { {0, NULL}, 0, {0, NULL}, {0, NULL}, 0 };
static int proxy_scheme_option = 0;
static int uri_host_option = 0;
static unsigned int ping_seconds = 0;

/* reading is done when this flag is set */
Expand Down Expand Up @@ -202,7 +203,7 @@ coap_new_request(coap_context_t *ctx,
else {
unsigned char buf[4];
coap_add_option(pdu,
COAP_OPTION_SIZE1,
COAP_OPTION_SIZE1, /* 60 */
coap_encode_var_safe8(buf, sizeof(buf), length),
buf);

Expand Down Expand Up @@ -237,17 +238,21 @@ clear_obs(coap_context_t *ctx, coap_session_t *session) {
}

for (option = optlist; option; option = option->next ) {
if (option->number == COAP_OPTION_URI_HOST) {
switch (option->number) {
case COAP_OPTION_URI_HOST : /* 3 */
if (!coap_add_option(pdu, option->number, option->length,
option->data)) {
goto error;
}
break;
default:
;
}
}

/* Observe option comes after Uri-Host, but before the others */
if (!coap_add_option(pdu,
COAP_OPTION_OBSERVE,
COAP_OPTION_OBSERVE, /* 6 */
coap_encode_var_safe(buf, sizeof(buf), COAP_OBSERVE_CANCEL),
buf)) {
coap_log(LOG_CRIT, "cannot add option Observe: %u\n", COAP_OBSERVE_CANCEL);
Expand All @@ -274,10 +279,23 @@ clear_obs(coap_context_t *ctx, coap_session_t *session) {
block.num = 0;
block.m = 0;
coap_add_option(pdu,
COAP_OPTION_BLOCK2,
COAP_OPTION_BLOCK2, /* 23 */
coap_encode_var_safe(buf, sizeof(buf), (block.num << 4 | block.m << 3 | block.szx)),
buf);
}
for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_PROXY_URI : /* 35 */
case COAP_OPTION_PROXY_SCHEME : /* 39 */
if (!coap_add_option(pdu, option->number, option->length,
option->data)) {
goto error;
}
break;
default:
;
}
}

if (coap_get_log_level() < LOG_DEBUG)
coap_show_pdu(LOG_INFO, pdu);
Expand Down Expand Up @@ -382,7 +400,7 @@ nack_handler(coap_context_t *context UNUSED_PARAM,
break;
case COAP_NACK_ICMP_ISSUE:
default:
break;
;
}
return;
}
Expand All @@ -404,7 +422,7 @@ message_handler(struct coap_context_t *ctx,
coap_tid_t tid;

coap_log(LOG_DEBUG, "** process incoming %d.%02d response:\n",
(received->code >> 5), received->code & 0x1F);
COAP_RESPONSE_CLASS(received->code), received->code & 0x1F);
if (coap_get_log_level() < LOG_DEBUG)
coap_show_pdu(LOG_INFO, received);

Expand Down Expand Up @@ -480,11 +498,22 @@ message_handler(struct coap_context_t *ctx,
coap_log(LOG_DEBUG, "query block %d\n",
(coap_opt_block_num(block_opt) + 1));
coap_add_option(pdu,
blktype,
blktype, /* 23 or 27 */
coap_encode_var_safe(buf, sizeof(buf),
((coap_opt_block_num(block_opt) + 1) << 4) |
COAP_OPT_BLOCK_SZX(block_opt)), buf);

for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_PROXY_URI : /* 35 */
case COAP_OPTION_PROXY_SCHEME : /* 39 */
coap_add_option(pdu, option->number, option->length,
option->data);
break;
default:
; /* skip other options */
}
}
tid = coap_send(session, pdu);

if (tid == COAP_INVALID_TID) {
Expand Down Expand Up @@ -567,7 +596,7 @@ message_handler(struct coap_context_t *ctx,
option->data);
break;
default:
; /* skip other options */
; /* skip other options */
}
}

Expand All @@ -578,12 +607,24 @@ message_handler(struct coap_context_t *ctx,

coap_log(LOG_DEBUG, "send block %d\n", block.num);
coap_add_option(pdu,
COAP_OPTION_BLOCK1,
COAP_OPTION_BLOCK1, /* 27 */
coap_encode_var_safe(buf, sizeof(buf),
(block.num << 4) | (block.m << 3) | block.szx), buf);

for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_PROXY_URI : /* 35 */
case COAP_OPTION_PROXY_SCHEME : /* 39 */
coap_add_option(pdu, option->number, option->length,
option->data);
break;
default:
; /* skip other options */
}
}

coap_add_option(pdu,
COAP_OPTION_SIZE1,
COAP_OPTION_SIZE1, /* 60 */
coap_encode_var_safe8(buf, sizeof(buf), payload.length),
buf);

Expand Down Expand Up @@ -650,7 +691,7 @@ usage( const char *program, const char *version) {
"Usage: %s [-a addr] [-b [num,]size] [-e text] [-f file] [-l loss]\n"
"\t\t[-m method] [-o file] [-p port] [-r] [-s duration] [-t type]\n"
"\t\t[-v num] [-A type] [-B seconds] [-H hoplimit] [-K interval] [-N]\n"
"\t\t[-O num,text] [-P addr[:port]] [-T token] [-U]\n"
"\t\t[-O num,text] [-P scheme://address[:port]] [-T token] [-U]\n"
"\t\t[[-h match_hint_file] [-k key] [-u user]]\n"
"\t\t[[-c certfile] [-j keyfile] [-C cafile] [-J pkcs11_pin]\n"
"\t\t[-M raw_pk] [-R root_cafile] [-S match_pki_sni_file]] URI\n"
Expand Down Expand Up @@ -685,13 +726,15 @@ usage( const char *program, const char *version) {
"\t-H hoplimit\tSet the Hop Limit count to hoplimit for proxies. Must\n"
"\t \t\thave a value between 1 and 255 inclusive.\n"
"\t \t\tDefault is '16'\n"
"\t-K interval\tsend a ping after interval seconds of inactivity\n"
"\t-K interval\tSend a ping after interval seconds of inactivity\n"
"\t-N \t\tSend NON-confirmable message\n"
"\t-O num,text\tAdd option num with contents text to request. If the\n"
"\t \t\ttext begins with 0x, then the hex text is converted to\n"
"\t \t\tbinary data\n"
"\t-P addr[:port]\tUse proxy (automatically adds Proxy-Uri option to\n"
"\t \t\trequest)\n"
"\t-P scheme://address[:port]\tScheme, address and optional port to\n"
"\t \t\tdefine how to connect to a CoAP proxy (automatically adds\n"
"\t \t\tProxy-Uri option to request) to forward the request to.\n"
"\t \t\tScheme is one of coap, coaps, coap+tcp and coaps+tcp\n"
"\t-T token\tInclude specified token\n"
"\t-U \t\tNever include Uri-Host or Uri-Port options\n"
,program, version, coap_string_tls_version(buffer, sizeof(buffer))
Expand Down Expand Up @@ -844,16 +887,12 @@ cmdline_uri(char *arg, int create_uri_opts) {
size_t buflen;
int res;

if (proxy.length) { /* create Proxy-Uri from argument */
if (!proxy_scheme_option && proxy.host.length) {
/* create Proxy-Uri from argument */
size_t len = strlen(arg);
while (len > 270) {
coap_insert_optlist(&optlist,
coap_new_optlist(COAP_OPTION_PROXY_URI,
270,
(unsigned char *)arg));

len -= 270;
arg += 270;
if (len > 1034) {
coap_log(LOG_ERR, "Absolute URI length must be <= 1034 bytes for a proxy\n");
return -1;
}

coap_insert_optlist(&optlist,
Expand Down Expand Up @@ -986,34 +1025,11 @@ cmdline_subscribe(char *arg) {

static int
cmdline_proxy(char *arg) {
char *proxy_port_str = strrchr((const char *)arg, ':'); /* explicit port ? */
if (proxy_port_str) {
char *ipv6_delimiter = strrchr((const char *)arg, ']');
if (!ipv6_delimiter) {
if (proxy_port_str == strchr((const char *)arg, ':')) {
/* host:port format - host not in ipv6 hexadecimal string format */
*proxy_port_str++ = '\0'; /* split */
proxy_port = atoi(proxy_port_str);
}
} else {
arg = strchr((const char *)arg, '[');
if (!arg) return 0;
arg++;
*ipv6_delimiter = '\0'; /* split */
if (ipv6_delimiter + 1 == proxy_port_str++) {
/* [ipv6 address]:port */
proxy_port = atoi(proxy_port_str);
}
}
}

proxy.length = strlen(arg);
if ( (proxy.s = coap_malloc(proxy.length + 1)) == NULL) {
proxy.length = 0;
return 0;
if (coap_split_uri((unsigned char *)arg, strlen(arg), &proxy) < 0 ||
proxy.path.length != 0 || proxy.query.length != 0) {
coap_log(LOG_ERR, "invalid CoAP Proxy definition\n");
return -1;
}

memcpy(proxy.s, arg, proxy.length+1);
return 1;
}

Expand Down Expand Up @@ -1092,6 +1108,31 @@ cmdline_option(char *arg) {
coap_insert_optlist(&optlist,
coap_new_optlist(num, strlen(arg), (unsigned char *)arg));
}
if (num == COAP_OPTION_PROXY_SCHEME) {
proxy_scheme_option = 1;
if (strcasecmp(arg, "coaps+tcp") == 0) {
proxy.scheme = COAP_URI_SCHEME_COAPS_TCP;
proxy.port = COAPS_DEFAULT_PORT;
}
else if (strcasecmp(arg, "coap+tcp") == 0) {
proxy.scheme = COAP_URI_SCHEME_COAP_TCP;
proxy.port = COAP_DEFAULT_PORT;
}
else if (strcasecmp(arg, "coaps") == 0) {
proxy.scheme = COAP_URI_SCHEME_COAPS;
proxy.port = COAPS_DEFAULT_PORT;
}
else if (strcasecmp(arg, "coap") == 0) {
proxy.scheme = COAP_URI_SCHEME_COAP;
proxy.port = COAP_DEFAULT_PORT;
}
else {
coap_log(LOG_WARNING, "%s is not a supported CoAP Proxy-Scheme\n", arg);
}
}
if (num == COAP_OPTION_URI_HOST) {
uri_host_option = 1;
}
}

/**
Expand Down Expand Up @@ -1613,6 +1654,7 @@ main(int argc, char **argv) {
ssize_t user_length = -1, key_length = 0;
int create_uri_opts = 1;
size_t i;
coap_uri_scheme_t scheme;
#ifndef _WIN32
struct sigaction sa;
#endif
Expand Down Expand Up @@ -1759,13 +1801,15 @@ main(int argc, char **argv) {
goto finish;
}

if (proxy.length) {
server.length = proxy.length;
server.s = proxy.s;
port = proxy_port;
if (proxy.host.length) {
server.length = proxy.host.length;
server.s = proxy.host.s;
port = proxy.port;
scheme = proxy.scheme;
} else {
server = uri.host;
port = uri.port;
port = proxy_scheme_option ? proxy.port : uri.port;
scheme = proxy_scheme_option ? proxy.scheme : uri.scheme;
}

/* resolve destination address where server should be sent */
Expand All @@ -1790,11 +1834,11 @@ main(int argc, char **argv) {
session = get_session(
ctx,
node_str[0] ? node_str : NULL, port_str,
uri.scheme==COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP :
uri.scheme==COAP_URI_SCHEME_COAPS_TCP ? COAP_PROTO_TLS :
scheme==COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP :
scheme==COAP_URI_SCHEME_COAPS_TCP ? COAP_PROTO_TLS :
(reliable ?
uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_TLS : COAP_PROTO_TCP
: uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_UDP),
scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_TLS : COAP_PROTO_TCP
: scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_UDP),
&dst,
user_length >= 0 ? user : NULL,
user_length >= 0 ? user_length : 0,
Expand Down Expand Up @@ -1828,11 +1872,11 @@ main(int argc, char **argv) {

/* construct CoAP message */

if (!proxy.length && addrptr
if (!uri_host_option && (!proxy.host.length && addrptr
&& (inet_ntop(dst.addr.sa.sa_family, addrptr, addr, sizeof(addr)) != 0)
&& (strlen(addr) != uri.host.length
|| memcmp(addr, uri.host.s, uri.host.length) != 0)
&& create_uri_opts) {
&& create_uri_opts)) {
/* add Uri-Host */

coap_insert_optlist(&optlist,
Expand Down

0 comments on commit e4b585c

Please sign in to comment.