Coverage Report

Created: 2025-07-11 06:24

/src/libcoap/src/coap_proxy.c
Line
Count
Source (jump to first uncovered line)
1
/* coap_proxy.c -- helper functions for proxy handling
2
 *
3
 * Copyright (C) 2024-2025 Jon Shallow <supjps-libcoap@jpshallow.com>
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 *
7
 * This file is part of the CoAP library libcoap. Please see
8
 * README for terms of use.
9
 */
10
11
/**
12
 * @file coap_proxy.c
13
 * @brief Proxy handling functions
14
 */
15
16
#include "coap3/coap_libcoap_build.h"
17
18
#if COAP_PROXY_SUPPORT
19
#include <stdio.h>
20
#ifndef INET6_ADDRSTRLEN
21
#define INET6_ADDRSTRLEN 46
22
#endif
23
24
#if COAP_CLIENT_SUPPORT == 0
25
#error For Proxy support, COAP_CLIENT_SUPPORT must be set
26
#endif
27
#if COAP_SERVER_SUPPORT == 0
28
#error For Proxy support, COAP_SERVER_SUPPORT must be set
29
#endif
30
31
#ifdef _WIN32
32
#define strcasecmp _stricmp
33
#define strncasecmp _strnicmp
34
#endif
35
36
int
37
0
coap_proxy_is_supported(void) {
38
0
  return 1;
39
0
}
40
41
static void
42
coap_proxy_log_entry(coap_session_t *incoming, const coap_pdu_t *pdu,
43
0
                     coap_bin_const_t *upstream_token, const char *type) {
44
0
  if (coap_get_log_level() >= COAP_LOG_DEBUG) {
45
0
    coap_string_t *url;
46
47
0
    url = coap_get_uri_path(pdu);
48
0
    if (url) {
49
0
      coap_opt_iterator_t opt_iter;
50
0
      uint8_t addr[INET6_ADDRSTRLEN + 8];
51
0
      char scratch_d[24];
52
0
      char scratch_u[24];
53
0
      size_t size;
54
0
      size_t i;
55
56
0
      scratch_d[0] = '\000';
57
0
      for (i = 0; i < pdu->actual_token.length; i++) {
58
0
        size = strlen(scratch_d);
59
0
        snprintf(&scratch_d[size], sizeof(scratch_d)-size,
60
0
                 "%02x", pdu->actual_token.s[i]);
61
0
      }
62
0
      scratch_u[0] = '\000';
63
0
      if (upstream_token) {
64
0
        for (i = 0; i < upstream_token->length; i++) {
65
0
          size = strlen(scratch_u);
66
0
          snprintf(&scratch_u[size], sizeof(scratch_u)-size,
67
0
                   "%02x", upstream_token->s[i]);
68
0
        }
69
0
      }
70
0
      coap_print_addr(coap_session_get_addr_remote(incoming), addr, sizeof(addr));
71
0
      coap_log_debug("   proxy %-4s %s {%s}-{%s} \"%s\"%s\n", type, addr, scratch_u, scratch_d,
72
0
                     url->s, coap_check_option(pdu, COAP_OPTION_OBSERVE, &opt_iter) ? " Observe" : "");
73
0
      coap_delete_string(url);
74
0
    }
75
0
  }
76
0
}
77
78
void
79
0
coap_proxy_del_req(coap_proxy_list_t *proxy_entry, coap_proxy_req_t *proxy_req) {
80
0
  coap_proxy_log_entry(proxy_req->incoming, proxy_req->pdu,  proxy_req->token_used, "del");
81
82
0
  coap_delete_pdu_lkd(proxy_req->pdu);
83
0
  coap_delete_bin_const(proxy_req->token_used);
84
0
  coap_delete_cache_key(proxy_req->cache_key);
85
0
  if (proxy_req->proxy_cache) {
86
0
    if (coap_get_log_level() >= COAP_LOG_DEBUG) {
87
0
      coap_string_t *url;
88
89
0
      url = coap_get_uri_path(proxy_req->proxy_cache->req_pdu);
90
0
      coap_log_debug("***%s: Removing Proxy Cache \"%s\" (Active %d)\n",
91
0
                     coap_session_str(proxy_req->incoming),
92
0
                     url ? (char *)url->s : "???",
93
0
                     proxy_req->proxy_cache->ref);
94
0
      coap_delete_string(url);
95
0
    }
96
0
    assert(proxy_req->proxy_cache->ref);
97
0
    proxy_req->proxy_cache->ref--;
98
0
    if (proxy_req->proxy_cache->ref == 0) {
99
0
      PROXY_CACHE_DELETE(proxy_entry->rsp_cache, proxy_req->proxy_cache);
100
0
      coap_delete_pdu_lkd(proxy_req->proxy_cache->req_pdu);
101
0
      coap_delete_pdu_lkd(proxy_req->proxy_cache->rsp_pdu);
102
0
      coap_free_type(COAP_STRING, proxy_req->proxy_cache);
103
0
      proxy_req->proxy_cache = NULL;
104
0
    }
105
0
    if (proxy_req->doing_observe) {
106
0
      assert(proxy_req->incoming->ref_proxy_subs);
107
0
      proxy_req->incoming->ref_proxy_subs--;
108
0
      proxy_req->doing_observe = 0;
109
0
    }
110
0
  }
111
  /* To prevent potential loops */
112
0
  proxy_req->incoming = NULL;
113
114
0
  LL_DELETE(proxy_entry->proxy_req, proxy_req);
115
0
  coap_free_type(COAP_STRING, proxy_req);
116
0
}
117
118
static void
119
0
coap_proxy_cleanup_entry(coap_proxy_list_t *proxy_entry, int send_failure) {
120
0
  coap_proxy_req_t *proxy_req, *treq;
121
122
0
  LL_FOREACH_SAFE(proxy_entry->proxy_req, proxy_req, treq) {
123
0
    if (send_failure) {
124
0
      coap_pdu_t *response;
125
0
      coap_bin_const_t l_token;
126
127
      /* Need to send back a gateway failure */
128
0
      response = coap_pdu_init(proxy_req->pdu->type,
129
0
                               COAP_RESPONSE_CODE(502),
130
0
                               coap_new_message_id_lkd(proxy_entry->incoming),
131
0
                               coap_session_max_pdu_size_lkd(proxy_entry->incoming));
132
0
      if (!response) {
133
0
        coap_log_info("PDU creation issue\n");
134
0
        goto cleanup;
135
0
      }
136
137
0
      l_token = coap_pdu_get_token(proxy_req->pdu);
138
0
      if (!coap_add_token(response, l_token.length,
139
0
                          l_token.s)) {
140
0
        coap_log_debug("Cannot add token to incoming proxy response PDU\n");
141
0
      }
142
143
0
      if (coap_send_lkd(proxy_entry->incoming, response) == COAP_INVALID_MID) {
144
0
        coap_log_info("Failed to send PDU with 5.02 gateway issue\n");
145
0
      }
146
0
    }
147
0
cleanup:
148
0
    coap_proxy_del_req(proxy_entry, proxy_req);
149
0
  }
150
0
  coap_free_type(COAP_STRING, proxy_entry->uri_host_keep);
151
0
}
152
153
void
154
0
coap_proxy_cleanup(coap_context_t *context) {
155
0
  size_t i;
156
157
0
  for (i = 0; i < context->proxy_list_count; i++) {
158
    /* All sessions have now been closed down */
159
0
    coap_log_debug("proxy_entry %p cleaned up\n",
160
0
                   (void *)&context->proxy_list[i]);
161
0
    coap_proxy_cleanup_entry(&context->proxy_list[i], 0);
162
0
  }
163
0
  coap_free_type(COAP_STRING, context->proxy_list);
164
0
}
165
166
static int
167
0
coap_proxy_check_observe(coap_proxy_list_t *proxy_entry) {
168
0
  if (proxy_entry && proxy_entry->ongoing) {
169
    /* Need to see if there are any Observes active */
170
0
    coap_lg_crcv_t *lg_crcv;
171
172
0
    LL_FOREACH(proxy_entry->ongoing->lg_crcv, lg_crcv) {
173
0
      if (lg_crcv->observe_set) {
174
0
        return 1;
175
0
      }
176
0
    }
177
0
  }
178
0
  return 0;
179
0
}
180
181
/*
182
 * Return 1 if there is a future expire time, else 0.
183
 * Update tim_rem with remaining value if return is 1.
184
 */
185
int
186
coap_proxy_check_timeouts(coap_context_t *context, coap_tick_t now,
187
0
                          coap_tick_t *tim_rem) {
188
0
  size_t i;
189
0
  int ret = 0;
190
191
0
  *tim_rem = COAP_MAX_DELAY_TICKS;
192
0
  for (i = 0; i < context->proxy_list_count; i++) {
193
0
    coap_proxy_list_t *proxy_entry = &context->proxy_list[i];
194
195
0
    if (coap_proxy_check_observe(proxy_entry))
196
0
      continue;
197
198
0
    if (proxy_entry->ongoing && proxy_entry->idle_timeout_ticks) {
199
0
      if (proxy_entry->last_used + proxy_entry->idle_timeout_ticks <= now) {
200
        /* Drop session to upstream server (which may remove proxy entry) */
201
0
        if (coap_proxy_remove_association(proxy_entry->ongoing, 0))
202
0
          i--;
203
0
      } else {
204
0
        if (*tim_rem > proxy_entry->last_used + proxy_entry->idle_timeout_ticks - now) {
205
0
          *tim_rem = proxy_entry->last_used + proxy_entry->idle_timeout_ticks - now;
206
0
          ret = 1;
207
0
        }
208
0
      }
209
0
    }
210
0
  }
211
0
  return ret;
212
0
}
213
214
static int
215
coap_get_uri_proxy_scheme_info(const coap_pdu_t *request,
216
                               coap_opt_t *opt,
217
0
                               coap_uri_t *uri) {
218
0
  const char *opt_val = (const char *)coap_opt_value(opt);
219
0
  int opt_len = coap_opt_length(opt);
220
0
  coap_opt_iterator_t opt_iter;
221
222
0
  if (opt_len == 9 &&
223
0
      strncasecmp(opt_val, "coaps+tcp", 9) == 0) {
224
0
    uri->scheme = COAP_URI_SCHEME_COAPS_TCP;
225
0
    uri->port = COAPS_DEFAULT_PORT;
226
0
  } else if (opt_len == 8 &&
227
0
             strncasecmp(opt_val, "coap+tcp", 8) == 0) {
228
0
    uri->scheme = COAP_URI_SCHEME_COAP_TCP;
229
0
    uri->port = COAP_DEFAULT_PORT;
230
0
  } else if (opt_len == 5 &&
231
0
             strncasecmp(opt_val, "coaps", 5) == 0) {
232
0
    uri->scheme = COAP_URI_SCHEME_COAPS;
233
0
    uri->port = COAPS_DEFAULT_PORT;
234
0
  } else if (opt_len == 4 &&
235
0
             strncasecmp(opt_val, "coap", 4) == 0) {
236
0
    uri->scheme = COAP_URI_SCHEME_COAP;
237
0
    uri->port = COAP_DEFAULT_PORT;
238
0
  } else if (opt_len == 7 &&
239
0
             strncasecmp(opt_val, "coap+ws", 7) == 0) {
240
0
    uri->scheme = COAP_URI_SCHEME_COAP_WS;
241
0
    uri->port = 80;
242
0
  } else if (opt_len == 8 &&
243
0
             strncasecmp(opt_val, "coaps+ws", 8) == 0) {
244
0
    uri->scheme = COAP_URI_SCHEME_COAPS_WS;
245
0
    uri->port = 443;
246
0
  } else {
247
0
    coap_log_warn("Unsupported Proxy Scheme '%*.*s'\n",
248
0
                  opt_len, opt_len, opt_val);
249
0
    return 0;
250
0
  }
251
252
0
  opt = coap_check_option(request, COAP_OPTION_URI_HOST, &opt_iter);
253
0
  if (opt) {
254
0
    uri->host.length = coap_opt_length(opt);
255
0
    uri->host.s = coap_opt_value(opt);
256
0
  } else {
257
0
    uri->host.s = NULL;
258
0
    uri->host.length = 0;
259
0
    coap_log_warn("Proxy Scheme requires Uri-Host\n");
260
0
    return 0;
261
0
  }
262
0
  opt = coap_check_option(request, COAP_OPTION_URI_PORT, &opt_iter);
263
0
  if (opt) {
264
0
    uri->port =
265
0
        coap_decode_var_bytes(coap_opt_value(opt),
266
0
                              coap_opt_length(opt));
267
0
  }
268
0
  return 1;
269
0
}
270
271
int
272
0
coap_verify_proxy_scheme_supported(coap_uri_scheme_t scheme) {
273
274
  /* Sanity check that the connection can be forwarded on */
275
0
  switch (scheme) {
276
0
  case COAP_URI_SCHEME_HTTP:
277
0
  case COAP_URI_SCHEME_HTTPS:
278
0
    coap_log_warn("Proxy URI http or https not supported\n");
279
0
    return 0;
280
0
  case COAP_URI_SCHEME_COAP:
281
0
    break;
282
0
  case COAP_URI_SCHEME_COAPS:
283
0
    if (!coap_dtls_is_supported()) {
284
0
      coap_log_warn("coaps URI scheme not supported for proxy\n");
285
0
      return 0;
286
0
    }
287
0
    break;
288
0
  case COAP_URI_SCHEME_COAP_TCP:
289
0
    if (!coap_tcp_is_supported()) {
290
0
      coap_log_warn("coap+tcp URI scheme not supported for proxy\n");
291
0
      return 0;
292
0
    }
293
0
    break;
294
0
  case COAP_URI_SCHEME_COAPS_TCP:
295
0
    if (!coap_tls_is_supported()) {
296
0
      coap_log_warn("coaps+tcp URI scheme not supported for proxy\n");
297
0
      return 0;
298
0
    }
299
0
    break;
300
0
  case COAP_URI_SCHEME_COAP_WS:
301
0
    if (!coap_ws_is_supported()) {
302
0
      coap_log_warn("coap+ws URI scheme not supported for proxy\n");
303
0
      return 0;
304
0
    }
305
0
    break;
306
0
  case COAP_URI_SCHEME_COAPS_WS:
307
0
    if (!coap_wss_is_supported()) {
308
0
      coap_log_warn("coaps+ws URI scheme not supported for proxy\n");
309
0
      return 0;
310
0
    }
311
0
    break;
312
0
  case COAP_URI_SCHEME_LAST:
313
0
  default:
314
0
    coap_log_warn("%d URI scheme not supported\n", scheme);
315
0
    return 0;
316
0
  }
317
0
  return 1;
318
0
}
319
320
static coap_proxy_list_t *
321
coap_proxy_get_session(coap_session_t *session, const coap_pdu_t *request,
322
                       coap_pdu_t *response,
323
                       coap_proxy_server_list_t *server_list,
324
0
                       coap_proxy_server_t *server_use, int *proxy_entry_created) {
325
0
  size_t i;
326
0
  coap_proxy_list_t *new_proxy_list;
327
0
  coap_proxy_list_t *proxy_list = session->context->proxy_list;
328
0
  size_t proxy_list_count = session->context->proxy_list_count;
329
0
  coap_opt_iterator_t opt_iter;
330
0
  coap_opt_t *proxy_scheme;
331
0
  coap_opt_t *proxy_uri;
332
333
0
  *proxy_entry_created = 0;
334
335
  /*
336
   * Maintain server stickability. server_use not needed as there is
337
   * ongoing session in place.
338
   */
339
0
  if (session->proxy_entry) {
340
0
    for (i = 0; i < proxy_list_count; i++) {
341
0
      if (&proxy_list[i] == session->proxy_entry) {
342
0
        if (session->proxy_entry->ongoing) {
343
0
          memset(server_use, 0, sizeof(*server_use));
344
0
          return session->proxy_entry;
345
0
        }
346
0
      }
347
0
    }
348
0
  }
349
350
  /* Round robin the defined next server list (which usually is just one */
351
0
  server_list->next_entry++;
352
0
  if (server_list->next_entry >= server_list->entry_count)
353
0
    server_list->next_entry = 0;
354
355
0
  if (server_list->entry_count) {
356
0
    memcpy(server_use, &server_list->entry[server_list->next_entry], sizeof(*server_use));
357
0
  } else {
358
0
    memset(server_use, 0, sizeof(*server_use));
359
0
  }
360
361
0
  switch (server_list->type) {
362
0
  case COAP_PROXY_REVERSE:
363
0
  case COAP_PROXY_REVERSE_STRIP:
364
0
  case COAP_PROXY_FORWARD_STATIC:
365
0
  case COAP_PROXY_FORWARD_STATIC_STRIP:
366
    /* Nothing else needs to be done here */
367
0
    break;
368
0
  case COAP_PROXY_FORWARD_DYNAMIC:
369
0
  case COAP_PROXY_FORWARD_DYNAMIC_STRIP:
370
    /* Need to get actual server from CoAP Proxy-Uri or Proxy-Scheme options */
371
    /*
372
     * See if Proxy-Scheme
373
     */
374
0
    proxy_scheme = coap_check_option(request, COAP_OPTION_PROXY_SCHEME, &opt_iter);
375
0
    if (proxy_scheme) {
376
0
      if (!coap_get_uri_proxy_scheme_info(request, proxy_scheme, &server_use->uri)) {
377
0
        response->code = COAP_RESPONSE_CODE(505);
378
0
        return NULL;
379
0
      }
380
0
    }
381
    /*
382
     * See if Proxy-Uri
383
     */
384
0
    proxy_uri = coap_check_option(request, COAP_OPTION_PROXY_URI, &opt_iter);
385
0
    if (proxy_uri) {
386
0
      coap_log_info("Proxy URI '%.*s'\n",
387
0
                    (int)coap_opt_length(proxy_uri),
388
0
                    (const char *)coap_opt_value(proxy_uri));
389
0
      if (coap_split_proxy_uri(coap_opt_value(proxy_uri),
390
0
                               coap_opt_length(proxy_uri),
391
0
                               &server_use->uri) < 0) {
392
        /* Need to return a 5.05 RFC7252 Section 5.7.2 */
393
0
        coap_log_warn("Proxy URI not decodable\n");
394
0
        response->code = COAP_RESPONSE_CODE(505);
395
0
        return NULL;
396
0
      }
397
0
    }
398
399
0
    if (!(proxy_scheme || proxy_uri)) {
400
0
      response->code = COAP_RESPONSE_CODE(404);
401
0
      return NULL;
402
0
    }
403
0
    break;
404
0
  default:
405
0
    assert(0);
406
0
    return NULL;
407
0
  }
408
409
0
  if (server_use->uri.host.length == 0) {
410
    /* Ongoing connection not well formed */
411
0
    response->code = COAP_RESPONSE_CODE(505);
412
0
    return NULL;
413
0
  }
414
415
0
  if (!coap_verify_proxy_scheme_supported(server_use->uri.scheme)) {
416
0
    response->code = COAP_RESPONSE_CODE(505);
417
0
    return NULL;
418
0
  }
419
420
  /* See if we are already connected to the Server */
421
0
  for (i = 0; i < proxy_list_count; i++) {
422
0
    if (coap_string_equal(&proxy_list[i].uri.host, &server_use->uri.host) &&
423
0
        proxy_list[i].uri.port == server_use->uri.port &&
424
0
        proxy_list[i].uri.scheme == server_use->uri.scheme) {
425
0
      if (!server_list->track_client_session && session->context->proxy_response_handler) {
426
0
        coap_ticks(&proxy_list[i].last_used);
427
0
        return &proxy_list[i];
428
0
      } else {
429
0
        if (proxy_list[i].incoming == session) {
430
0
          coap_ticks(&proxy_list[i].last_used);
431
0
          return &proxy_list[i];
432
0
        }
433
0
      }
434
0
    }
435
0
  }
436
437
  /* Need to create a new forwarding mapping */
438
0
  new_proxy_list = coap_realloc_type(COAP_STRING, proxy_list, (i+1)*sizeof(proxy_list[0]));
439
440
0
  if (new_proxy_list == NULL) {
441
0
    response->code = COAP_RESPONSE_CODE(500);
442
0
    return NULL;
443
0
  }
444
0
  session->context->proxy_list = proxy_list = new_proxy_list;
445
0
  memset(&proxy_list[i], 0, sizeof(proxy_list[i]));
446
447
  /* Keep a copy of the host as server_use->uri pointed to will be going away */
448
0
  proxy_list[i].uri = server_use->uri;
449
0
  proxy_list[i].uri_host_keep = coap_malloc_type(COAP_STRING,
450
0
                                                 server_use->uri.host.length);
451
0
  if (!proxy_list[i].uri_host_keep) {
452
0
    response->code = COAP_RESPONSE_CODE(500);
453
0
    return NULL;
454
0
  }
455
0
  memcpy(proxy_list[i].uri_host_keep, server_use->uri.host.s,
456
0
         server_use->uri.host.length);
457
0
  proxy_list[i].uri.host.s = proxy_list[i].uri_host_keep;
458
  /* Unset uri parts which point to going away information */
459
0
  proxy_list[i].uri.path.s = NULL;
460
0
  proxy_list[i].uri.path.length = 0;
461
0
  proxy_list[i].uri.query.s = NULL;
462
0
  proxy_list[i].uri.query.length = 0;
463
464
0
  if (server_list->track_client_session) {
465
0
    proxy_list[i].incoming = session;
466
0
  }
467
0
  *proxy_entry_created = 1;
468
0
  session->context->proxy_list_count++;
469
0
  proxy_list[i].idle_timeout_ticks = server_list->idle_timeout_secs * COAP_TICKS_PER_SECOND;
470
0
  coap_ticks(&proxy_list[i].last_used);
471
0
  session->proxy_entry = &proxy_list[i];
472
0
  return &proxy_list[i];
473
0
}
474
475
int
476
0
coap_proxy_remove_association(coap_session_t *session, int send_failure) {
477
478
0
  size_t i;
479
0
  coap_proxy_list_t *proxy_list = session->context->proxy_list;
480
0
  size_t proxy_list_count = session->context->proxy_list_count;
481
482
0
  for (i = 0; i < proxy_list_count; i++) {
483
0
    coap_proxy_list_t *proxy_entry = &proxy_list[i];
484
0
    coap_proxy_req_t *proxy_req;
485
486
    /* Check for incoming match */
487
0
retry:
488
0
    LL_FOREACH(proxy_entry->proxy_req, proxy_req) {
489
0
      if (proxy_req->incoming == session) {
490
0
        coap_proxy_del_req(proxy_entry, proxy_req);
491
0
        goto retry;
492
0
      }
493
0
    }
494
0
    if (proxy_entry->incoming == session) {
495
      /* Only if there is a one-to-one tracking */
496
0
      coap_session_t *ongoing = proxy_entry->ongoing;
497
498
0
      proxy_entry->ongoing = NULL;
499
0
      coap_session_release_lkd(ongoing);
500
0
      return 0;
501
0
    }
502
503
    /* Check for outgoing match */
504
0
    if (proxy_entry->ongoing == session) {
505
0
      coap_session_t *ongoing;
506
507
0
      coap_proxy_cleanup_entry(proxy_entry, send_failure);
508
0
      ongoing = proxy_entry->ongoing;
509
0
      coap_log_debug("*  %s: proxy_entry %p released (rem count = %zd)\n",
510
0
                     coap_session_str(ongoing),
511
0
                     (void *)proxy_entry,
512
0
                     session->context->proxy_list_count - 1);
513
0
      if (proxy_list_count-i > 1) {
514
0
        memmove(&proxy_list[i],
515
0
                &proxy_list[i+1],
516
0
                (proxy_list_count-i-1) * sizeof(proxy_list[0]));
517
0
      }
518
0
      session->context->proxy_list_count--;
519
0
      coap_session_release_lkd(ongoing);
520
0
      return 1;
521
0
    }
522
0
  }
523
0
  return 0;
524
0
}
525
526
static coap_proxy_list_t *
527
coap_proxy_get_ongoing_session(coap_session_t *session,
528
                               const coap_pdu_t *request,
529
                               coap_pdu_t *response,
530
0
                               coap_proxy_server_list_t *server_list) {
531
532
0
  coap_address_t dst;
533
0
  coap_proto_t proto;
534
0
  coap_addr_info_t *info_list = NULL;
535
0
  coap_proxy_list_t *proxy_entry;
536
0
  coap_context_t *context = session->context;
537
0
  static char client_sni[256];
538
0
  coap_proxy_server_t server_use;
539
0
  int proxy_entry_created;
540
541
0
  proxy_entry = coap_proxy_get_session(session, request, response, server_list,
542
0
                                       &server_use, &proxy_entry_created);
543
0
  if (!proxy_entry) {
544
    /* Error response code already set */
545
0
    return NULL;
546
0
  }
547
548
0
  if (!proxy_entry->ongoing) {
549
    /* Need to create a new session */
550
0
    coap_address_t *local_addr = NULL;
551
552
    /* resolve destination address where data should be sent */
553
0
    info_list = coap_resolve_address_info(&server_use.uri.host,
554
0
                                          server_use.uri.port,
555
0
                                          server_use.uri.port,
556
0
                                          server_use.uri.port,
557
0
                                          server_use.uri.port,
558
0
                                          0,
559
0
                                          1 << server_use.uri.scheme,
560
0
                                          COAP_RESOLVE_TYPE_REMOTE);
561
562
0
    if (info_list == NULL) {
563
0
      response->code = COAP_RESPONSE_CODE(502);
564
0
      coap_proxy_remove_association(session, 0);
565
0
      return NULL;
566
0
    }
567
0
    proto = info_list->proto;
568
0
    memcpy(&dst, &info_list->addr, sizeof(dst));
569
0
    coap_free_address_info(info_list);
570
571
0
#if COAP_AF_UNIX_SUPPORT
572
0
    coap_address_t bind_addr;
573
0
    if (coap_is_af_unix(&dst)) {
574
0
      char buf[COAP_UNIX_PATH_MAX];
575
0
      coap_tick_t now;
576
577
      /* Need a unique 'client' address */
578
0
      coap_ticks(&now);
579
0
      snprintf(buf, COAP_UNIX_PATH_MAX,
580
0
               "/tmp/coap-pr-cl-%" PRIu64, (uint64_t)now);
581
0
      if (!coap_address_set_unix_domain(&bind_addr, (const uint8_t *)buf,
582
0
                                        strlen(buf))) {
583
0
        fprintf(stderr, "coap_address_set_unix_domain: %s: failed\n",
584
0
                buf);
585
0
        remove(buf);
586
0
        return NULL;
587
0
      }
588
0
      (void)remove(buf);
589
0
      local_addr = &bind_addr;
590
0
    }
591
0
#endif /* COAP_AF_UNIX_SUPPORT */
592
593
0
    snprintf(client_sni, sizeof(client_sni), "%*.*s", (int)server_use.uri.host.length,
594
0
             (int)server_use.uri.host.length, server_use.uri.host.s);
595
596
0
    switch (server_use.uri.scheme) {
597
0
    case COAP_URI_SCHEME_COAP:
598
0
    case COAP_URI_SCHEME_COAP_TCP:
599
0
    case COAP_URI_SCHEME_COAP_WS:
600
0
#if COAP_OSCORE_SUPPORT
601
0
      if (server_use.oscore_conf) {
602
0
        proxy_entry->ongoing =
603
0
            coap_new_client_session_oscore_lkd(context, local_addr, &dst,
604
0
                                               proto, server_use.oscore_conf);
605
0
      } else {
606
0
#endif /* COAP_OSCORE_SUPPORT */
607
0
        proxy_entry->ongoing =
608
0
            coap_new_client_session_lkd(context, local_addr, &dst, proto);
609
0
#if COAP_OSCORE_SUPPORT
610
0
      }
611
0
#endif /* COAP_OSCORE_SUPPORT */
612
0
      break;
613
0
    case COAP_URI_SCHEME_COAPS:
614
0
    case COAP_URI_SCHEME_COAPS_TCP:
615
0
    case COAP_URI_SCHEME_COAPS_WS:
616
0
#if COAP_OSCORE_SUPPORT
617
0
      if (server_use.oscore_conf) {
618
0
        if (server_use.dtls_pki) {
619
0
          server_use.dtls_pki->client_sni = client_sni;
620
0
          proxy_entry->ongoing =
621
0
              coap_new_client_session_oscore_pki_lkd(context, local_addr, &dst,
622
0
                                                     proto, server_use.dtls_pki, server_use.oscore_conf);
623
0
        } else if (server_use.dtls_cpsk) {
624
0
          server_use.dtls_cpsk->client_sni = client_sni;
625
0
          proxy_entry->ongoing =
626
0
              coap_new_client_session_oscore_psk_lkd(context, local_addr, &dst,
627
0
                                                     proto, server_use.dtls_cpsk, server_use.oscore_conf);
628
0
        } else {
629
0
          coap_log_warn("Proxy: (D)TLS not configured for secure session\n");
630
0
        }
631
0
      } else {
632
0
#endif /* COAP_OSCORE_SUPPORT */
633
        /* Not doing OSCORE */
634
0
        if (server_use.dtls_pki) {
635
0
          server_use.dtls_pki->client_sni = client_sni;
636
0
          proxy_entry->ongoing =
637
0
              coap_new_client_session_pki_lkd(context, local_addr, &dst,
638
0
                                              proto, server_use.dtls_pki);
639
0
        } else if (server_use.dtls_cpsk) {
640
0
          server_use.dtls_cpsk->client_sni = client_sni;
641
0
          proxy_entry->ongoing =
642
0
              coap_new_client_session_psk2_lkd(context, local_addr, &dst,
643
0
                                               proto, server_use.dtls_cpsk);
644
0
        } else {
645
          /* Using client anonymous PKI */
646
0
          proxy_entry->ongoing =
647
0
              coap_new_client_session_lkd(context, local_addr, &dst, proto);
648
0
        }
649
0
#if COAP_OSCORE_SUPPORT
650
0
      }
651
0
#endif /* COAP_OSCORE_SUPPORT */
652
0
      break;
653
0
    case COAP_URI_SCHEME_HTTP:
654
0
    case COAP_URI_SCHEME_HTTPS:
655
0
    case COAP_URI_SCHEME_LAST:
656
0
    default:
657
0
      assert(0);
658
0
      break;
659
0
    }
660
0
    if (proxy_entry->ongoing == NULL) {
661
0
      response->code = COAP_RESPONSE_CODE(505);
662
0
      coap_proxy_remove_association(session, 0);
663
0
      return NULL;
664
0
    }
665
0
    if (proxy_entry_created) {
666
0
      coap_log_debug("*  %s: proxy_entry %p created (tot count = %zd)\n",
667
0
                     coap_session_str(proxy_entry->ongoing),
668
0
                     (void *)proxy_entry,
669
0
                     session->context->proxy_list_count);
670
0
    }
671
0
  } else if (proxy_entry->ongoing->session_failed) {
672
0
    if (!coap_session_reconnect(proxy_entry->ongoing)) {
673
      /* Server is not yet back up */
674
0
      return NULL;
675
0
    }
676
0
  }
677
678
0
  return proxy_entry;
679
0
}
680
681
static void
682
coap_proxy_release_body_data(coap_session_t *session COAP_UNUSED,
683
0
                             void *app_ptr) {
684
0
  coap_delete_binary(app_ptr);
685
0
}
686
687
static coap_proxy_req_t *
688
coap_proxy_get_req(coap_proxy_list_t *proxy_entry, coap_proxy_cache_t *proxy_cache,
689
0
                   coap_session_t *session) {
690
0
  coap_proxy_req_t *proxy_req;
691
692
0
  LL_FOREACH(proxy_entry->proxy_req, proxy_req) {
693
0
    if (proxy_req->incoming == session && proxy_req->proxy_cache == proxy_cache) {
694
0
      return proxy_req;
695
0
    }
696
0
  }
697
0
  return NULL;
698
0
}
699
700
static void
701
0
coap_proxy_free_response_data(coap_session_t *session COAP_UNUSED, void *app_ptr) {
702
0
  coap_delete_bin_const(app_ptr);
703
0
}
704
705
static coap_response_t
706
coap_proxy_call_response_handler(coap_session_t *session, const coap_pdu_t *sent,
707
                                 coap_pdu_t *rcvd, coap_bin_const_t *token,
708
                                 coap_proxy_req_t *proxy_req, int replace_mid,
709
0
                                 int remove_observe) {
710
0
  coap_response_t ret = COAP_RESPONSE_FAIL;
711
0
  coap_pdu_t *resp_pdu;
712
0
  coap_pdu_t *fwd_pdu = NULL;
713
0
  size_t size;
714
0
  size_t offset;
715
0
  size_t total;
716
0
  const uint8_t *data;
717
0
  coap_string_t *l_query = NULL;
718
719
0
  if (remove_observe) {
720
0
    coap_opt_filter_t drop_options;
721
722
0
    memset(&drop_options, 0, sizeof(coap_opt_filter_t));
723
0
    coap_option_filter_set(&drop_options, COAP_OPTION_OBSERVE);
724
    /* Correct the token */
725
0
    resp_pdu = coap_pdu_duplicate_lkd(rcvd, session, token->length, token->s,
726
0
                                      &drop_options);
727
0
  } else {
728
    /* Correct the token */
729
0
    resp_pdu = coap_pdu_duplicate_lkd(rcvd, session, token->length, token->s,
730
0
                                      NULL);
731
0
  }
732
0
  if (!resp_pdu)
733
0
    return COAP_RESPONSE_FAIL;
734
735
0
  if (COAP_PROTO_NOT_RELIABLE(session->proto))
736
0
    resp_pdu->max_size = coap_session_max_pdu_size_lkd(session);
737
738
0
  if (replace_mid)
739
0
    resp_pdu->mid = sent->mid;
740
741
0
  proxy_req->mid =  resp_pdu->mid;
742
743
0
  if (coap_get_data_large(rcvd, &size, &data, &offset, &total)) {
744
0
    uint16_t media_type = 0;
745
0
    int maxage = -1;
746
0
    uint64_t etag = 0;
747
0
    coap_opt_t *option;
748
0
    coap_opt_iterator_t opt_iter;
749
0
    coap_bin_const_t *body;
750
751
    /* COAP_BLOCK_SINGLE_BODY is set, so single body should be given */
752
0
    assert(size == total);
753
754
0
    body = coap_new_bin_const(data, size);
755
0
    if (!body) {
756
0
      coap_log_debug("coap_proxy_call_response_handler: copy data error\n");
757
0
      goto failed;
758
0
    }
759
0
    option = coap_check_option(rcvd, COAP_OPTION_CONTENT_FORMAT, &opt_iter);
760
0
    if (option) {
761
0
      media_type = coap_decode_var_bytes(coap_opt_value(option),
762
0
                                         coap_opt_length(option));
763
0
    }
764
0
    option = coap_check_option(rcvd, COAP_OPTION_MAXAGE, &opt_iter);
765
0
    if (option) {
766
0
      maxage = coap_decode_var_bytes(coap_opt_value(option),
767
0
                                     coap_opt_length(option));
768
0
    }
769
0
    option = coap_check_option(rcvd, COAP_OPTION_ETAG, &opt_iter);
770
0
    if (option) {
771
0
      etag = coap_decode_var_bytes8(coap_opt_value(option),
772
0
                                    coap_opt_length(option));
773
0
    }
774
0
    if (sent)
775
0
      l_query = coap_get_query(sent);
776
0
    if (!coap_add_data_large_response_lkd(proxy_req->resource, session, sent,
777
0
                                          resp_pdu,
778
0
                                          l_query,
779
0
                                          media_type, maxage, etag, body->length,
780
0
                                          body->s,
781
0
                                          coap_proxy_free_response_data,
782
0
                                          body)) {
783
0
      coap_log_debug("coap_proxy_call_response_handler: add data error\n");
784
0
      goto failed;
785
0
    }
786
0
  }
787
0
  coap_lock_callback_ret_release(fwd_pdu,
788
0
                                 session->context->proxy_response_handler(session,
789
0
                                     sent,
790
0
                                     resp_pdu,
791
0
                                     proxy_req->cache_key),
792
                                 /* context is being freed off */
793
0
                                 goto failed);
794
0
  if (fwd_pdu) {
795
0
    ret = COAP_RESPONSE_OK;
796
0
    if (coap_send_lkd(session, fwd_pdu) == COAP_INVALID_MID) {
797
0
      ret = COAP_RESPONSE_FAIL;
798
0
    }
799
0
    if (fwd_pdu != resp_pdu) {
800
      /* Application created a new PDU */
801
0
      coap_delete_pdu_lkd(resp_pdu);
802
0
    }
803
0
  } else {
804
0
failed:
805
0
    ret = COAP_RESPONSE_FAIL;
806
0
    coap_delete_pdu_lkd(resp_pdu);
807
0
  }
808
0
  coap_delete_string(l_query);
809
0
  return ret;
810
0
}
811
812
int COAP_API
813
coap_proxy_forward_request(coap_session_t *session,
814
                           const coap_pdu_t *request,
815
                           coap_pdu_t *response,
816
                           coap_resource_t *resource,
817
                           coap_cache_key_t *cache_key,
818
0
                           coap_proxy_server_list_t *server_list) {
819
0
  int ret;
820
821
0
  coap_lock_lock(return 0);
822
0
  ret = coap_proxy_forward_request_lkd(session,
823
0
                                       request,
824
0
                                       response,
825
0
                                       resource,
826
0
                                       cache_key,
827
0
                                       server_list);
828
0
  coap_lock_unlock();
829
0
  return ret;
830
0
}
831
832
/* https://rfc-editor.org/rfc/rfc7641#section-3.6 */
833
static const uint16_t coap_proxy_ignore_options[] = { COAP_OPTION_ETAG,
834
                                                      COAP_OPTION_RTAG,
835
                                                      COAP_OPTION_BLOCK2,
836
                                                      COAP_OPTION_Q_BLOCK2,
837
                                                      COAP_OPTION_OSCORE
838
                                                    };
839
840
int
841
coap_proxy_forward_request_lkd(coap_session_t *session,
842
                               const coap_pdu_t *request,
843
                               coap_pdu_t *response,
844
                               coap_resource_t *resource,
845
                               coap_cache_key_t *cache_key,
846
0
                               coap_proxy_server_list_t *server_list) {
847
0
  coap_proxy_list_t *proxy_entry;
848
0
  size_t size;
849
0
  size_t offset;
850
0
  size_t total;
851
0
  coap_binary_t *body_data = NULL;
852
0
  const uint8_t *data;
853
0
  coap_pdu_t *pdu = NULL;
854
0
  coap_bin_const_t r_token = coap_pdu_get_token(request);
855
0
  uint8_t token[8];
856
0
  size_t token_len;
857
0
  coap_proxy_req_t *proxy_req = NULL;
858
0
  coap_optlist_t *optlist = NULL;
859
0
  coap_opt_t *option;
860
0
  coap_opt_iterator_t opt_iter;
861
0
  coap_uri_t uri;
862
0
  coap_opt_t *obs_opt = coap_check_option(request,
863
0
                                          COAP_OPTION_OBSERVE,
864
0
                                          &opt_iter);
865
0
  coap_proxy_cache_t *proxy_cache = NULL;
866
867
  /* Set up ongoing session (if not already done) */
868
0
  proxy_entry = coap_proxy_get_ongoing_session(session, request, response,
869
0
                                               server_list);
870
0
  if (!proxy_entry) {
871
    /* Error response code already set */
872
0
    return 0;
873
0
  }
874
0
  coap_proxy_log_entry(session, request, NULL, "req");
875
876
  /* Is this a observe cached request? */
877
0
  if (obs_opt && session->context->proxy_response_handler) {
878
0
    coap_cache_key_t *cache_key_l;
879
880
0
    cache_key_l = coap_cache_derive_key_w_ignore(session, request,
881
0
                                                 COAP_CACHE_NOT_SESSION_BASED,
882
0
                                                 coap_proxy_ignore_options,
883
0
                                                 sizeof(coap_proxy_ignore_options)/sizeof(coap_proxy_ignore_options[0]));
884
0
    if (!cache_key_l) {
885
0
      response->code = COAP_RESPONSE_CODE(505);
886
0
      return 0;
887
0
    }
888
0
    PROXY_CACHE_FIND(proxy_entry->rsp_cache, cache_key_l, proxy_cache);
889
0
    coap_delete_cache_key(cache_key_l);
890
0
  }
891
892
0
  if (proxy_cache) {
893
0
    proxy_req = coap_proxy_get_req(proxy_entry, proxy_cache, session);
894
0
    if (proxy_req) {
895
0
      coap_tick_t now;
896
897
0
      if (obs_opt) {
898
0
        int observe_action;
899
900
0
        observe_action = coap_decode_var_bytes(coap_opt_value(obs_opt),
901
0
                                               coap_opt_length(obs_opt));
902
903
0
        if (observe_action == COAP_OBSERVE_CANCEL) {
904
0
          if (proxy_req->doing_observe) {
905
0
            assert(proxy_req->incoming->ref_proxy_subs);
906
0
            proxy_req->incoming->ref_proxy_subs--;
907
0
            proxy_req->doing_observe = 0;
908
0
          }
909
0
          if (proxy_entry->proxy_req && !proxy_entry->proxy_req->next &&
910
0
              proxy_req->token_used) {
911
0
            coap_binary_t tmp;
912
913
0
            coap_log_debug("coap_proxy_forward_request: Using coap_cancel_observe() to do Proxy OBSERVE cancellation\n");
914
            /* Unfortunately need to change the ptr type to be r/w */
915
0
            memcpy(&tmp.s, &proxy_req->token_used->s, sizeof(tmp.s));
916
0
            tmp.length = proxy_req->token_used->length;
917
0
            coap_cancel_observe_lkd(proxy_entry->ongoing, &tmp, COAP_MESSAGE_CON);
918
            /* Let the upstream cancellation be the response */
919
0
            return 1;
920
0
          } else {
921
0
            obs_opt = 0;
922
0
            goto return_cached_info;
923
0
          }
924
0
        } else if (observe_action == COAP_OBSERVE_ESTABLISH) {
925
          /* Client must be re-registering */
926
0
          coap_ticks(&now);
927
0
          if (proxy_cache && (proxy_cache->expire + COAP_TICKS_PER_SECOND) < now) {
928
            /* Need to get an updated rsp_pdu */
929
0
            coap_proxy_del_req(proxy_entry, proxy_req);
930
0
            proxy_req = NULL;
931
0
            proxy_cache = NULL;
932
0
          } else {
933
0
            goto return_cached_info;
934
0
          }
935
0
        }
936
0
      } else {
937
0
        coap_ticks(&now);
938
0
        if (proxy_cache && (proxy_cache->expire + COAP_TICKS_PER_SECOND) < now) {
939
          /* Need to get an updated rsp_pdu */
940
0
          coap_proxy_del_req(proxy_entry, proxy_req);
941
0
          proxy_req = NULL;
942
0
          proxy_cache = NULL;
943
0
        } else {
944
0
          goto return_cached_info;
945
0
        }
946
0
      }
947
0
    }
948
0
  }
949
950
0
  if (!proxy_req) {
951
0
    proxy_req = coap_malloc_type(COAP_STRING, sizeof(coap_proxy_req_t));
952
0
    if (proxy_req == NULL) {
953
0
      goto failed;
954
0
    }
955
0
    memset(proxy_req, 0, sizeof(coap_proxy_req_t));
956
0
    LL_PREPEND(proxy_entry->proxy_req, proxy_req);
957
958
0
    proxy_req->pdu = coap_const_pdu_reference_lkd(request);
959
0
    proxy_req->resource = resource;
960
0
    proxy_req->incoming = session;
961
0
    proxy_req->cache_key = cache_key;
962
0
    proxy_req->proxy_cache = proxy_cache;
963
964
0
    coap_proxy_log_entry(proxy_req->incoming, proxy_req->pdu, proxy_req->token_used,  "add");
965
0
  }
966
967
0
  if (proxy_cache) {
968
0
    coap_bin_const_t j_token;
969
970
0
    if (obs_opt)
971
0
      proxy_cache->ref++;
972
0
    coap_delete_bin_const(proxy_req->token_used);
973
0
    j_token = coap_pdu_get_token(proxy_cache->rsp_pdu);
974
0
    proxy_req->token_used = coap_new_bin_const(j_token.s, j_token.length);
975
0
    if (proxy_req->token_used == NULL) {
976
0
      goto failed;
977
0
    }
978
0
    goto return_cached_info;
979
0
  }
980
981
  /* Get a new token for ongoing session */
982
0
  coap_session_new_token(proxy_entry->ongoing, &token_len, token);
983
0
  coap_delete_bin_const(proxy_req->token_used);
984
0
  proxy_req->token_used = coap_new_bin_const(token, token_len);
985
0
  if (proxy_req->token_used == NULL) {
986
0
    goto failed;
987
0
  }
988
0
  coap_pdu_release_lkd(proxy_req->pdu);
989
0
  proxy_req->pdu = coap_const_pdu_reference_lkd(request);
990
991
  /* Need to create the ongoing request pdu entry */
992
0
  switch (server_list->type) {
993
0
  case COAP_PROXY_REVERSE_STRIP:
994
0
  case COAP_PROXY_FORWARD_STATIC_STRIP:
995
0
  case COAP_PROXY_FORWARD_DYNAMIC_STRIP:
996
    /*
997
     * Need to replace Proxy-Uri with Uri-Host (and Uri-Port)
998
     * and strip out Proxy-Scheme.
999
     */
1000
1001
    /*
1002
     * Build up the ongoing PDU that we are going to send
1003
     */
1004
0
    pdu = coap_pdu_init(request->type, request->code,
1005
0
                        coap_new_message_id_lkd(proxy_entry->ongoing),
1006
0
                        coap_session_max_pdu_size_lkd(proxy_entry->ongoing));
1007
0
    if (!pdu) {
1008
0
      goto failed;
1009
0
    }
1010
1011
0
    if (!coap_add_token(pdu, token_len, token)) {
1012
0
      goto failed;
1013
0
    }
1014
1015
    /* Copy the remaining options across */
1016
0
    coap_option_iterator_init(request, &opt_iter, COAP_OPT_ALL);
1017
0
    while ((option = coap_option_next(&opt_iter))) {
1018
0
      switch (opt_iter.number) {
1019
0
      case COAP_OPTION_PROXY_URI:
1020
0
        if (coap_split_proxy_uri(coap_opt_value(option),
1021
0
                                 coap_opt_length(option),
1022
0
                                 &uri) < 0) {
1023
          /* Need to return a 5.05 RFC7252 Section 5.7.2 */
1024
0
          coap_log_warn("Proxy URI not decodable\n");
1025
0
          coap_delete_pdu_lkd(pdu);
1026
0
          return 0;
1027
0
        }
1028
0
        if (!coap_uri_into_optlist(&uri, NULL, &optlist, 0)) {
1029
0
          coap_log_err("Failed to create options for URI\n");
1030
0
          goto failed;
1031
0
        }
1032
0
        break;
1033
0
      case COAP_OPTION_PROXY_SCHEME:
1034
0
        break;
1035
0
      case COAP_OPTION_BLOCK1:
1036
0
      case COAP_OPTION_BLOCK2:
1037
0
      case COAP_OPTION_Q_BLOCK1:
1038
0
      case COAP_OPTION_Q_BLOCK2:
1039
        /* These are not passed on */
1040
0
        break;
1041
0
      case COAP_OPTION_URI_HOST:
1042
0
      case COAP_OPTION_URI_PORT:
1043
0
        break;
1044
0
      default:
1045
0
        coap_insert_optlist(&optlist,
1046
0
                            coap_new_optlist(opt_iter.number,
1047
0
                                             coap_opt_length(option),
1048
0
                                             coap_opt_value(option)));
1049
0
        break;
1050
0
      }
1051
0
    }
1052
1053
    /* Update pdu with options */
1054
0
    coap_add_optlist_pdu(pdu, &optlist);
1055
0
    coap_delete_optlist(optlist);
1056
0
    break;
1057
0
  case COAP_PROXY_REVERSE:
1058
0
  case COAP_PROXY_FORWARD_STATIC:
1059
0
  case COAP_PROXY_FORWARD_DYNAMIC:
1060
0
  default:
1061
    /*
1062
     * Duplicate request PDU for onward transmission (with new token).
1063
     */
1064
0
    pdu = coap_pdu_duplicate_lkd(request, proxy_entry->ongoing, token_len, token, NULL);
1065
0
    if (!pdu) {
1066
0
      coap_log_debug("proxy: PDU generation error\n");
1067
0
      goto failed;
1068
0
    }
1069
0
    if (COAP_PROTO_NOT_RELIABLE(session->proto))
1070
0
      pdu->max_size = coap_session_max_pdu_size_lkd(proxy_entry->ongoing);
1071
0
    break;
1072
0
  }
1073
1074
0
  if (coap_get_data_large(request, &size, &data, &offset, &total)) {
1075
    /* COAP_BLOCK_SINGLE_BODY is set, so single body should be given */
1076
0
    assert(size == total);
1077
    /*
1078
     * Need to take a copy of the data as request PDU may go away before
1079
     * all data is transmitted.
1080
     */
1081
0
    body_data = coap_new_binary(total);
1082
0
    if (!body_data) {
1083
0
      coap_log_debug("proxy: body build memory error\n");
1084
0
      goto failed;
1085
0
    }
1086
0
    memcpy(body_data->s, data, size);
1087
0
    if (!coap_add_data_large_request_lkd(proxy_entry->ongoing, pdu, total, data,
1088
0
                                         coap_proxy_release_body_data, body_data)) {
1089
0
      coap_log_debug("proxy: add data error\n");
1090
0
      goto failed;
1091
0
    }
1092
0
  }
1093
1094
0
  coap_proxy_log_entry(proxy_req->incoming, proxy_req->pdu, proxy_req->token_used,  "fwd");
1095
0
  if (coap_send_lkd(proxy_entry->ongoing, pdu) == COAP_INVALID_MID) {
1096
0
    pdu = NULL;
1097
0
    coap_log_debug("proxy: upstream PDU send error\n");
1098
0
    goto failed;
1099
0
  }
1100
1101
  /*
1102
   * Do not update the response code (hence empty ACK) as will be sending
1103
   * separate response when response comes back from upstream server
1104
   */
1105
1106
0
  return 1;
1107
1108
0
failed:
1109
0
  response->code = COAP_RESPONSE_CODE(500);
1110
0
  coap_delete_pdu_lkd(pdu);
1111
0
  return 0;
1112
1113
0
return_cached_info:
1114
0
  if (obs_opt && !proxy_req->doing_observe) {
1115
0
    int observe_action;
1116
1117
0
    observe_action = coap_decode_var_bytes(coap_opt_value(obs_opt),
1118
0
                                           coap_opt_length(obs_opt));
1119
1120
0
    if (observe_action == COAP_OBSERVE_ESTABLISH) {
1121
0
      proxy_req->doing_observe = 1;
1122
0
      proxy_req->incoming->ref_proxy_subs++;
1123
0
    }
1124
0
  }
1125
0
  coap_log_debug("*  %s: Using Proxy Cache (Active %d)\n",
1126
0
                 coap_session_str(session),
1127
0
                 proxy_cache->ref);
1128
0
  coap_proxy_log_entry(session, request, &proxy_cache->rsp_pdu->actual_token,  "rspc");
1129
0
  coap_proxy_call_response_handler(session, request, proxy_cache->rsp_pdu,
1130
0
                                   &r_token, proxy_req, 1, obs_opt ? 0 : 1);
1131
0
  if (!obs_opt)
1132
0
    coap_proxy_del_req(proxy_entry, proxy_req);
1133
0
  return 1;
1134
0
}
1135
1136
coap_proxy_req_t *
1137
coap_proxy_map_outgoing_request(coap_session_t *ongoing,
1138
                                const coap_pdu_t *received,
1139
0
                                coap_proxy_list_t **u_proxy_entry) {
1140
0
  coap_proxy_list_t *proxy_list = ongoing->context->proxy_list;
1141
0
  size_t proxy_list_count = ongoing->context->proxy_list_count;
1142
0
  size_t i;
1143
0
  coap_bin_const_t rcv_token = coap_pdu_get_token(received);
1144
0
  coap_proxy_list_t *proxy_entry = NULL;
1145
0
  coap_proxy_req_t *proxy_req;
1146
1147
0
  for (i = 0; i < proxy_list_count; i++) {
1148
0
    proxy_entry = &proxy_list[i];
1149
0
    if (proxy_entry->ongoing == ongoing) {
1150
0
      LL_FOREACH(proxy_entry->proxy_req, proxy_req) {
1151
0
        if (coap_binary_equal(&rcv_token, proxy_req->token_used)) {
1152
0
          coap_ticks(&proxy_entry->last_used);
1153
0
          if (u_proxy_entry)
1154
0
            *u_proxy_entry = proxy_entry;
1155
0
          return proxy_req;
1156
0
        }
1157
0
      }
1158
0
    }
1159
0
  }
1160
0
  if (coap_get_log_level() >= COAP_LOG_DEBUG) {
1161
0
    char scratch[24];
1162
0
    size_t size;
1163
1164
0
    scratch[0] = '\000';
1165
0
    for (i = 0; i < rcv_token.length; i++) {
1166
0
      size = strlen(scratch);
1167
0
      snprintf(&scratch[size], sizeof(scratch)-size,
1168
0
               "%02x", rcv_token.s[i]);
1169
0
    }
1170
0
    coap_log_debug("   proxy token to match {%s}\n", scratch);
1171
0
    for (i = 0; i < proxy_list_count; i++) {
1172
0
      proxy_entry = &proxy_list[i];
1173
0
      LL_FOREACH(proxy_entry->proxy_req, proxy_req) {
1174
0
        coap_proxy_log_entry(proxy_req->incoming, proxy_req->pdu,  proxy_req->token_used, "miss");
1175
0
      }
1176
0
    }
1177
0
  }
1178
0
  return NULL;
1179
0
}
1180
1181
coap_response_t COAP_API
1182
coap_proxy_forward_response(coap_session_t *session,
1183
                            const coap_pdu_t *received,
1184
0
                            coap_cache_key_t **cache_key) {
1185
0
  int ret;
1186
1187
0
  coap_lock_lock(return 0);
1188
0
  ret = coap_proxy_forward_response_lkd(session,
1189
0
                                        received,
1190
0
                                        cache_key);
1191
0
  coap_lock_unlock();
1192
0
  return ret;
1193
0
}
1194
1195
coap_response_t
1196
coap_proxy_forward_response_lkd(coap_session_t *session,
1197
                                const coap_pdu_t *received,
1198
0
                                coap_cache_key_t **cache_key) {
1199
0
  coap_pdu_t *pdu = NULL;
1200
0
  coap_session_t *incoming = NULL;
1201
0
  size_t size;
1202
0
  const uint8_t *data;
1203
0
  coap_optlist_t *optlist = NULL;
1204
0
  coap_opt_t *option;
1205
0
  coap_opt_iterator_t opt_iter;
1206
0
  size_t offset;
1207
0
  size_t total;
1208
0
  coap_proxy_list_t *proxy_entry = NULL;
1209
0
  uint16_t media_type = COAP_MEDIATYPE_TEXT_PLAIN;
1210
0
  int maxage = -1;
1211
0
  uint64_t etag = 0;
1212
0
  coap_pdu_code_t rcv_code = coap_pdu_get_code(received);
1213
0
  coap_bin_const_t req_token;
1214
0
  coap_binary_t *body_data = NULL;
1215
0
  coap_pdu_t *req_pdu;
1216
0
  coap_resource_t *resource;
1217
0
  coap_proxy_req_t *proxy_req = NULL;
1218
1219
0
  proxy_req = coap_proxy_map_outgoing_request(session, received, &proxy_entry);
1220
0
  if (!proxy_req || proxy_req->incoming->server_list) {
1221
0
    coap_log_warn("Unknown proxy ongoing session response received - ignored\n");
1222
0
    return COAP_RESPONSE_OK;
1223
0
  }
1224
1225
0
  req_pdu = proxy_req->pdu;
1226
0
  req_token = coap_pdu_get_token(req_pdu);
1227
0
  resource = proxy_req->resource;
1228
0
  incoming = proxy_req->incoming;
1229
1230
0
  coap_log_debug("** process upstream incoming %d.%02d response:\n",
1231
0
                 COAP_RESPONSE_CLASS(rcv_code), rcv_code & 0x1F);
1232
1233
0
  if (coap_get_data_large(received, &size, &data, &offset, &total)) {
1234
    /* COAP_BLOCK_SINGLE_BODY is set, so single body should be given */
1235
0
    assert(size == total);
1236
0
    body_data = coap_new_binary(total);
1237
0
    if (!body_data) {
1238
0
      coap_log_debug("body build memory error\n");
1239
0
      goto remove_match;
1240
0
    }
1241
0
    memcpy(body_data->s, data, size);
1242
0
    data = body_data->s;
1243
0
  }
1244
1245
  /*
1246
   * Build up the ongoing PDU that we are going to send to proxy originator
1247
   * as separate response
1248
   */
1249
0
  pdu = coap_pdu_init(req_pdu->type, rcv_code,
1250
0
                      coap_new_message_id_lkd(incoming),
1251
0
                      coap_session_max_pdu_size_lkd(incoming));
1252
0
  if (!pdu) {
1253
0
    coap_log_debug("Failed to create ongoing proxy response PDU\n");
1254
0
    goto remove_match;
1255
0
  }
1256
1257
0
  if (!coap_add_token(pdu, req_token.length, req_token.s)) {
1258
0
    coap_log_debug("cannot add token to ongoing proxy response PDU\n");
1259
0
  }
1260
1261
  /*
1262
   * Copy the options across, skipping those needed for
1263
   * coap_add_data_response_large()
1264
   */
1265
0
  coap_option_iterator_init(received, &opt_iter, COAP_OPT_ALL);
1266
0
  while ((option = coap_option_next(&opt_iter))) {
1267
0
    switch (opt_iter.number) {
1268
0
    case COAP_OPTION_CONTENT_FORMAT:
1269
0
      media_type = coap_decode_var_bytes(coap_opt_value(option),
1270
0
                                         coap_opt_length(option));
1271
0
      break;
1272
0
    case COAP_OPTION_MAXAGE:
1273
0
      maxage = coap_decode_var_bytes(coap_opt_value(option),
1274
0
                                     coap_opt_length(option));
1275
0
      break;
1276
0
    case COAP_OPTION_ETAG:
1277
0
      etag = coap_decode_var_bytes8(coap_opt_value(option),
1278
0
                                    coap_opt_length(option));
1279
0
      break;
1280
0
    case COAP_OPTION_BLOCK2:
1281
0
    case COAP_OPTION_Q_BLOCK2:
1282
0
    case COAP_OPTION_SIZE2:
1283
0
      break;
1284
0
    default:
1285
0
      coap_insert_optlist(&optlist,
1286
0
                          coap_new_optlist(opt_iter.number,
1287
0
                                           coap_opt_length(option),
1288
0
                                           coap_opt_value(option)));
1289
0
      break;
1290
0
    }
1291
0
  }
1292
0
  coap_add_optlist_pdu(pdu, &optlist);
1293
0
  coap_delete_optlist(optlist);
1294
1295
0
  if (size > 0) {
1296
0
    coap_string_t *l_query = coap_get_query(req_pdu);
1297
1298
0
    coap_add_data_large_response_lkd(resource, incoming, req_pdu, pdu,
1299
0
                                     l_query,
1300
0
                                     media_type, maxage, etag, size, data,
1301
0
                                     coap_proxy_release_body_data,
1302
0
                                     body_data);
1303
0
    body_data = NULL;
1304
0
    coap_delete_string(l_query);
1305
0
  }
1306
1307
0
  if (cache_key)
1308
0
    *cache_key = proxy_req->cache_key;
1309
1310
0
  coap_send_lkd(incoming, pdu);
1311
1312
0
remove_match:
1313
0
  option = coap_check_option(received, COAP_OPTION_OBSERVE, &opt_iter);
1314
  /* Need to remove matching token entry (apart from an Observe response) */
1315
0
  if (option == NULL) {
1316
0
    if (proxy_entry->proxy_req) {
1317
      /* Do not delete cache key here - caller's responsibility */
1318
0
      proxy_req->cache_key = NULL;
1319
0
      coap_proxy_del_req(proxy_entry, proxy_req);
1320
0
    }
1321
0
  } else if (!proxy_req->doing_observe) {
1322
0
    option = coap_check_option(proxy_req->pdu, COAP_OPTION_OBSERVE, &opt_iter);
1323
0
    if (option &&
1324
0
        coap_decode_var_bytes(coap_opt_value(option),
1325
0
                              coap_opt_length(option)) == COAP_OBSERVE_ESTABLISH) {
1326
0
      proxy_req->doing_observe = 1;
1327
0
      proxy_req->incoming->ref_proxy_subs++;
1328
0
    }
1329
0
  }
1330
0
  coap_delete_binary(body_data);
1331
0
  return COAP_RESPONSE_OK;
1332
0
}
1333
1334
void
1335
coap_proxy_process_incoming(coap_session_t *session,
1336
                            coap_pdu_t *rcvd,
1337
                            void *body_data, coap_proxy_req_t *proxy_req,
1338
0
                            coap_proxy_list_t *proxy_entry) {
1339
0
  coap_opt_t *obs_opt;
1340
0
  coap_opt_t *option;
1341
0
  coap_opt_iterator_t opt_iter;
1342
0
  coap_response_t ret = COAP_RESPONSE_FAIL;
1343
0
  coap_bin_const_t token;
1344
1345
0
  obs_opt = coap_check_option(rcvd, COAP_OPTION_OBSERVE, &opt_iter);
1346
1347
  /* See if we are doing proxy caching */
1348
0
  if (obs_opt) {
1349
0
    coap_proxy_cache_t *proxy_cache;
1350
0
    coap_cache_key_t *cache_key_l;
1351
0
    coap_tick_t now;
1352
0
    uint64_t expire;
1353
1354
    /* Need to cache the response */
1355
0
    if (proxy_req->proxy_cache) {
1356
0
      coap_delete_pdu_lkd(proxy_req->proxy_cache->rsp_pdu);
1357
0
      proxy_cache = proxy_req->proxy_cache;
1358
0
    } else {
1359
0
      proxy_cache = coap_malloc_type(COAP_STRING, sizeof(coap_proxy_cache_t));
1360
0
      if (proxy_cache == NULL) {
1361
0
        goto cache_fail;
1362
0
      }
1363
0
      memset(proxy_cache, 0, sizeof(coap_proxy_cache_t));
1364
0
      cache_key_l = coap_cache_derive_key_w_ignore(session, proxy_req->pdu,
1365
0
                                                   COAP_CACHE_NOT_SESSION_BASED,
1366
0
                                                   coap_proxy_ignore_options,
1367
0
                                                   sizeof(coap_proxy_ignore_options)/sizeof(coap_proxy_ignore_options[0]));
1368
0
      if (!cache_key_l) {
1369
0
        coap_free_type(COAP_STRING, proxy_cache);
1370
0
        goto cache_fail;
1371
0
      }
1372
0
      memcpy(&proxy_cache->cache_req, cache_key_l,
1373
0
             sizeof(proxy_cache->cache_req));
1374
0
      coap_delete_cache_key(cache_key_l);
1375
1376
0
      proxy_cache->req_pdu = coap_pdu_reference_lkd(proxy_req->pdu);
1377
0
      proxy_req->proxy_cache = proxy_cache;
1378
1379
0
      PROXY_CACHE_ADD(proxy_entry->rsp_cache, proxy_cache);
1380
0
      proxy_cache->ref++;
1381
0
    }
1382
0
    proxy_cache->rsp_pdu = coap_pdu_reference_lkd(rcvd);
1383
0
    option = coap_check_option(rcvd, COAP_OPTION_ETAG, &opt_iter);
1384
0
    if (option) {
1385
0
      proxy_cache->etag = coap_decode_var_bytes8(coap_opt_value(option),
1386
0
                                                 coap_opt_length(option));
1387
0
    } else {
1388
0
      proxy_cache->etag = 0;
1389
0
    }
1390
0
    coap_ticks(&now);
1391
0
    option = coap_check_option(rcvd, COAP_OPTION_MAXAGE, &opt_iter);
1392
0
    if (option) {
1393
0
      expire = coap_decode_var_bytes(coap_opt_value(option),
1394
0
                                     coap_opt_length(option));
1395
0
    } else {
1396
      /* Default is 60 seconds */
1397
0
      expire = 60;
1398
0
    }
1399
0
    proxy_cache->expire = now + expire * COAP_TICKS_PER_SECOND;
1400
1401
    /* Update all the cache listeners */
1402
0
    LL_FOREACH(proxy_entry->proxy_req, proxy_req) {
1403
0
      if (proxy_req->proxy_cache == proxy_cache) {
1404
0
        if (!proxy_req->doing_observe) {
1405
0
          coap_opt_t *req_obs;
1406
1407
0
          req_obs = coap_check_option(proxy_req->pdu, COAP_OPTION_OBSERVE, &opt_iter);
1408
0
          if (req_obs &&
1409
0
              coap_decode_var_bytes(coap_opt_value(req_obs),
1410
0
                                    coap_opt_length(req_obs)) == COAP_OBSERVE_ESTABLISH) {
1411
0
            proxy_req->doing_observe = 1;
1412
0
            proxy_req->incoming->ref_proxy_subs++;
1413
0
          }
1414
0
        }
1415
0
        coap_proxy_log_entry(proxy_req->incoming, proxy_req->pdu, proxy_req->token_used,  "rsp");
1416
0
        token = coap_pdu_get_token(proxy_req->pdu);
1417
0
        if (coap_proxy_call_response_handler(proxy_req->incoming, proxy_req->pdu,
1418
0
                                             rcvd, &token,
1419
0
                                             proxy_req, 0, 0) == COAP_RESPONSE_OK) {
1420
          /* At least one success */
1421
0
          ret = COAP_RESPONSE_OK;
1422
0
        }
1423
0
      }
1424
0
    }
1425
0
    goto finish;
1426
0
  }
1427
0
cache_fail:
1428
0
  coap_proxy_log_entry(proxy_req->incoming, proxy_req->pdu, proxy_req->token_used,  "rspn");
1429
0
  token = coap_pdu_get_token(proxy_req->pdu);
1430
0
  ret = coap_proxy_call_response_handler(proxy_req->incoming, proxy_req->pdu,
1431
0
                                         rcvd, &token, proxy_req, 0, 0);
1432
0
  if (!obs_opt)
1433
0
    coap_proxy_del_req(proxy_entry, proxy_req);
1434
1435
0
finish:
1436
0
  if (ret == COAP_RESPONSE_FAIL && rcvd->type != COAP_MESSAGE_ACK) {
1437
0
    coap_send_rst_lkd(session, rcvd);
1438
0
    session->last_con_handler_res = COAP_RESPONSE_FAIL;
1439
0
  } else {
1440
0
    coap_send_ack_lkd(session, rcvd);
1441
0
    session->last_con_handler_res = COAP_RESPONSE_OK;
1442
0
  }
1443
0
  coap_free_type(COAP_STRING, body_data);
1444
0
}
1445
1446
/*
1447
 */
1448
coap_mid_t
1449
0
coap_proxy_local_write(coap_session_t *session, coap_pdu_t *pdu) {
1450
0
  coap_pdu_t *response = NULL;
1451
0
  coap_resource_t *resource;
1452
0
  coap_mid_t mid = COAP_INVALID_MID;
1453
1454
0
  resource = session->context->unknown_resource ?
1455
0
             session->context->unknown_resource :
1456
0
             session->context->proxy_uri_resource;
1457
0
  if (!resource) {
1458
0
    coap_log_err("coap_proxy_local_write: Unknown or Proxy resource not defined\n");
1459
0
    goto fail;
1460
0
  }
1461
1462
0
  response = coap_pdu_init(pdu->type == COAP_MESSAGE_CON ?
1463
0
                           COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
1464
0
                           0, pdu->mid, coap_session_max_pdu_size_lkd(session));
1465
0
  if (!response) {
1466
0
    coap_log_err("coap_proxy_local_write: Could not create response PDU\n");
1467
0
    goto fail;
1468
0
  }
1469
0
  response->session = session;
1470
1471
0
  if (!coap_add_token(response, pdu->actual_token.length,
1472
0
                      pdu->actual_token.s)) {
1473
0
    goto fail;
1474
0
  }
1475
1476
0
  coap_log_debug("*  %s: internal: sent %4zd bytes\n",
1477
0
                 coap_session_str(session),
1478
0
                 pdu->used_size + coap_pdu_encode_header(pdu, session->proto));
1479
0
  coap_show_pdu(COAP_LOG_DEBUG, pdu);
1480
1481
0
  mid = pdu->mid;
1482
0
  if (!coap_proxy_forward_request_lkd(session, pdu, response, resource,
1483
0
                                      NULL, session->server_list)) {
1484
0
    coap_log_debug("coap_proxy_local_write: Failed to forward PDU\n");
1485
0
    mid = COAP_INVALID_MID;
1486
0
  }
1487
0
fail:
1488
0
  coap_delete_pdu_lkd(response);
1489
0
  coap_delete_pdu_lkd(pdu);
1490
0
  return mid;
1491
0
}
1492
1493
COAP_API coap_session_t *
1494
coap_new_client_session_proxy(coap_context_t *ctx,
1495
0
                              coap_proxy_server_list_t *server_list) {
1496
0
  coap_session_t *session;
1497
1498
0
  coap_lock_lock(return NULL);
1499
0
  session = coap_new_client_session_proxy_lkd(ctx, server_list);
1500
0
  coap_lock_unlock();
1501
0
  return session;
1502
0
}
1503
1504
coap_session_t *
1505
coap_new_client_session_proxy_lkd(coap_context_t *ctx,
1506
0
                                  coap_proxy_server_list_t *server_list) {
1507
0
  coap_session_t *session;
1508
0
  coap_addr_info_t *info_list = NULL;
1509
0
  coap_str_const_t remote;
1510
1511
0
  coap_lock_check_locked();
1512
1513
0
#if COAP_IPV6_SUPPORT
1514
0
  remote.s = (const uint8_t *)"::1";
1515
#elif COAP_IPV4_SUPPORT
1516
  remote.s = (const uint8_t *)"127.0.0.1";
1517
#else /* !COAP_IPV6_SUPPORT && ! COAP_IPV4_SUPPORT */
1518
  coap_log_warn("coap_new_client_session_proxy: No IPv4 or IPv6 support\n");
1519
  return NULL;
1520
#endif /* !COAP_IPV6_SUPPORT && ! COAP_IPV4_SUPPORT */
1521
0
  remote.length = strlen((const char *)remote.s);
1522
  /* resolve internal remote address where proxy session is 'connecting' to */
1523
0
  info_list = coap_resolve_address_info(&remote, 0, 0, 0, 0,
1524
0
                                        0,
1525
0
                                        1 << COAP_URI_SCHEME_COAP,
1526
0
                                        COAP_RESOLVE_TYPE_REMOTE);
1527
0
  if (!info_list) {
1528
0
    coap_log_warn("coap_new_client_session_proxy: Unable to resolve IP address\n");
1529
0
    return NULL;
1530
0
  }
1531
1532
0
  session = coap_new_client_session_lkd(ctx, NULL, &info_list->addr, COAP_PROTO_UDP);
1533
1534
0
  if (session) {
1535
0
    session->server_list = server_list;
1536
0
  }
1537
0
  coap_free_address_info(info_list);
1538
0
  return session;
1539
0
}
1540
1541
void
1542
coap_delete_proxy_subscriber(coap_session_t *session, coap_bin_const_t *token,
1543
0
                             coap_mid_t mid, coap_proxy_subs_delete_t type) {
1544
  /* Need to check is there is a proxy subscription active and delete it */
1545
0
  coap_context_t *context = session->context;
1546
0
  size_t i;
1547
1548
0
  for (i = 0; i < context->proxy_list_count; i++) {
1549
0
    coap_proxy_list_t *proxy_entry = &context->proxy_list[i];
1550
0
    coap_proxy_req_t *proxy_req, *treq;
1551
1552
0
    LL_FOREACH_SAFE(proxy_entry->proxy_req, proxy_req, treq) {
1553
0
      if (proxy_req->incoming == session) {
1554
0
        coap_bin_const_t req_token;
1555
0
        int match = 0;
1556
1557
0
        req_token = coap_pdu_get_token(proxy_req->pdu);
1558
0
        switch (type) {
1559
0
        case COAP_PROXY_SUBS_ALL:
1560
0
          match = 1;
1561
0
          break;
1562
0
        case COAP_PROXY_SUBS_TOKEN:
1563
0
          if (token && coap_binary_equal(token, &req_token))
1564
0
            match = 1;
1565
0
          break;
1566
0
        case COAP_PROXY_SUBS_MID:
1567
0
          if (proxy_req->mid == mid)
1568
0
            match = 1;
1569
0
          break;
1570
0
        default:
1571
0
          break;
1572
0
        }
1573
1574
0
        if (match && proxy_entry->proxy_req && ! proxy_entry->proxy_req->next &&
1575
0
            proxy_req->token_used) {
1576
0
          coap_binary_t tmp;
1577
1578
0
          coap_log_debug("coap_delete_proxy_subscriber: Using coap_cancel_observe() to do Proxy OBSERVE cancellation\n");
1579
          /* Unfortunately need to change the ptr type to be r/w */
1580
0
          memcpy(&tmp.s, &proxy_req->token_used->s, sizeof(tmp.s));
1581
0
          tmp.length = proxy_req->token_used->length;
1582
0
          coap_cancel_observe_lkd(proxy_entry->ongoing, &tmp, COAP_MESSAGE_CON);
1583
0
        }
1584
0
        coap_proxy_del_req(proxy_entry, proxy_req);
1585
0
      }
1586
0
    }
1587
0
  }
1588
0
}
1589
1590
#else /* ! COAP_PROXY_SUPPORT */
1591
1592
int
1593
coap_proxy_is_supported(void) {
1594
  return 0;
1595
}
1596
1597
COAP_API int
1598
coap_proxy_forward_request(coap_session_t *session,
1599
                           const coap_pdu_t *request,
1600
                           coap_pdu_t *response,
1601
                           coap_resource_t *resource,
1602
                           coap_cache_key_t *cache_key,
1603
                           coap_proxy_server_list_t *server_list) {
1604
  (void)session;
1605
  (void)request;
1606
  (void)resource;
1607
  (void)cache_key;
1608
  (void)server_list;
1609
  response->code = COAP_RESPONSE_CODE(500);
1610
  return 0;
1611
}
1612
1613
COAP_API coap_response_t
1614
coap_proxy_forward_response(coap_session_t *session,
1615
                            const coap_pdu_t *received,
1616
                            coap_cache_key_t **cache_key) {
1617
  (void)session;
1618
  (void)received;
1619
  (void)cache_key;
1620
  return COAP_RESPONSE_OK;
1621
}
1622
1623
int
1624
coap_verify_proxy_scheme_supported(coap_uri_scheme_t scheme) {
1625
  (void)scheme;
1626
  return 0;
1627
}
1628
#endif /* ! COAP_PROXY_SUPPORT */