Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gcoap: add coaps forward proxy #20454

Merged
merged 5 commits into from
May 6, 2024

Conversation

mariemC
Copy link
Contributor

@mariemC mariemC commented Mar 11, 2024

Contribution description

  • This mainly touches the forward proxy c file, the idea is to have coap-coaps proxy because on some nodes with small MCU flash, we don't want to handle the DTLS stack but also communicate securely with a remote server, therefore coap-coaps proxy would be a huge plus.

Testing procedure

  • In order to test the changes, I have used gcoap_dtls with enabling coap-cops proxy module on the client so it sends coaps requests and on the server I have set the gcoap dtls, enabled the coap-coaps proxy and added the module gcoap-forward-proxy.
    I tested on native, so I created two taps: tap0 for the client which sets the remote proxy and tap1: for the proxy server which sets the route to the remote server.
  • client:
2024-03-11 12:28:14,334 # main(): This is RIOT! (Version: 2024.04-devel-371-g00ed3-mariem/coap-coaps-forward-proxy)
2024-03-11 12:28:14,334 # gcoap example app
2024-03-11 12:28:14,335 # All up, running the shell now
> coaproxy set [fe80::fccc:bff:fe49:2dfa]:5683e
2024-03-11 12:28:28,400 # coap proxy set [fe80::fccc:bff:fe49:2dfa]:5683
> coaget "[fdea:dbee:f::1]" /.well-known/core83
2024-03-11 12:28:41,857 # coap get "[fdea:dbee:f::1]" /.well-known/core
2024-03-11 12:28:41,858 # gcoap_cli: sending msg ID 47696, 55 bytes
> 2024-03-11 12:28:41,868 # gcoap: response Success, code 2.05, 105 bytes
2024-03-11 12:28:41,870 # </>;title="General Info";ct=0,</time>;if="clock";rt="ticks";title="Internal Clock";ct=0;obs,</async>;ct=0
  • proxy-server:
2024-03-11 12:28:27,585 # main(): This is RIOT! (Version: 2024.04-devel-371-g00ed3-mariem/coap-coaps-forward-proxy)
2024-03-11 12:28:27,585 # gcoap example app
2024-03-11 12:28:27,585 # All up, running the shell now
nib route add 8 :: fe80::58da:6eff:fe50:5b94
2024-03-11 12:28:39,628 # nib route add 8 :: fe80::58da:6eff:fe50:5b94
  • remote server running on ubuntu:

coap-server-gnutls -A fdea:dbee:f::1 -k secretPSK -h Client_identity -v20

I have added fdea:dbee:f::1 to dev lo

Wireshark:
image

Issues/PRs references

I think this PR, could be helpful here: #18107 ( I didn't test coaps-coaps)
Mainly the issue is that gcoap thread gets stuck in the DTLS handshake therefore the handshake should happen into a different thread ( proxy thread)

@github-actions github-actions bot added Area: network Area: Networking Area: CoAP Area: Constrained Application Protocol implementations Area: sys Area: System Area: examples Area: Example Applications labels Mar 11, 2024
@benpicco benpicco requested a review from chrysn March 11, 2024 13:17
@mariemC mariemC force-pushed the mariem/coap-coaps-forward-proxy branch from 3b88481 to 9bb0a63 Compare March 11, 2024 13:55
@kfessel kfessel added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Mar 11, 2024
@kfessel kfessel changed the title Mariem/coap coaps forward proxy gcoap: add coaps forward proxy Mar 11, 2024
@riot-ci
Copy link

riot-ci commented Mar 11, 2024

Murdock results

✔️ PASSED

768ce5e sys/net/application_layer/gcoap/include: add internal proxy header

Success Failures Total Runtime
10066 0 10066 20m:32s

Artifacts

@fabian18
Copy link
Contributor

It is a really cool feature!
I had some trouble to set up the test environment but I just saw that it works basically.
I want to explain it more in detail how to set up a POC example.

We need two native instances call them n0 and n1.
For n0 we flash the gcoap example as this will be the CoAP client.

Preparation

Before flashing I did some changes to the Makefiles of examples/gcoap and examples/gcoap_dtls.
I give the tap interfaces a known LL address because I have to set some routing rules later to ping between n0 and n1.
There is a script to configure the tap interfaces and start radvd on them to advertise a subnet.
Also what needs to be changed is the size of CONFIG_GCOAP_PDU_BUF_SIZE, because sock_dtls_recv failed with -ENOMEM.

        ssize_t res = sock_dtls_recv(sock, &socket.ctx_dtls_session, _listen_buf,
                                    sizeof(_listen_buf), 0);
        if (res <= 0) {
            DEBUG("gcoap: DTLS recv failure: %" PRIdSIZE "\n", res);
            return;
        }

examples/gcoap:

diff --git a/examples/gcoap/Makefile b/examples/gcoap/Makefile
index 93bfc25e1b..c5573e5f8f 100644
--- a/examples/gcoap/Makefile
+++ b/examples/gcoap/Makefile
@@ -73,6 +73,15 @@ ifeq (1,$(USE_ZEP))
   USEMODULE += socket_zep
 endif
 
+# Uncomment the following 2 lines to specify static link lokal IPv6 address
+# this might be useful for testing, in cases where you cannot or do not want to
+# run a shell with ifconfig to get the real link lokal address.
+IPV6_STATIC_LLADDR ?= '"fe80::cafe:cafe:cafe:1"'
+CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_LLADDR=$(IPV6_STATIC_LLADDR)
+# uncomment to not increment the last digit by the inderface number
+CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_LLADDR_IS_FIXED=1
+CFLAGS += -DCONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF=4
+
 include $(RIOTBASE)/Makefile.include
 
 # For now this goes after the inclusion of Makefile.include so Kconfig symbols

examples/gcoap_dtls:

diff --git a/examples/gcoap_dtls/Makefile b/examples/gcoap_dtls/Makefile
index 0776185964..75d86c2be7 100644
--- a/examples/gcoap_dtls/Makefile
+++ b/examples/gcoap_dtls/Makefile
@@ -78,6 +78,7 @@ endif
 COAP_COAPS_PROXY_ENABLE ?= 0
 ifeq (1,$(COAP_COAPS_PROXY_ENABLE))
   USEMODULE += coap_coaps_proxy
+  USEMODULE += gcoap_forward_proxy
 endif
 
 # Instead of simulating an Ethernet connection, we can also simulate
@@ -90,6 +91,15 @@ ifeq (1,$(USE_ZEP))
   USEMODULE += socket_zep
 endif
 
+# Uncomment the following 2 lines to specify static link lokal IPv6 address
+# this might be useful for testing, in cases where you cannot or do not want to
+# run a shell with ifconfig to get the real link lokal address.
+IPV6_STATIC_LLADDR ?= '"fe80::cafe:cafe:cafe:1"'
+CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_LLADDR=$(IPV6_STATIC_LLADDR)
+# uncomment to not increment the last digit by the inderface number
+CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_LLADDR_IS_FIXED=1
+CFLAGS += -DCONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF=4
+
 include $(RIOTBASE)/Makefile.include
 
 # For now this goes after the inclusion of Makefile.include so Kconfig symbols

gcoap.h

diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h
index 8c63709491..77cf88224d 100644
--- a/sys/include/net/gcoap.h
+++ b/sys/include/net/gcoap.h
@@ -460,7 +460,7 @@ extern "C" {
  * @brief   Size of the buffer used to build a CoAP request or response
  */
 #ifndef CONFIG_GCOAP_PDU_BUF_SIZE
-#define CONFIG_GCOAP_PDU_BUF_SIZE      (128)
+#define CONFIG_GCOAP_PDU_BUF_SIZE      (256)
 #endif
 
 /**

Flash the CoAP Client

sudo COAP_COAPS_PROXY_ENABLE=0 GCOAP_ENABLE_DTLS=0 make flash debug PORT=tap0

main(): This is RIOT! (Version: 2024.04-devel-371-g9bb0a-mariem/coap-coaps-forward-proxy)
gcoap example app
All up, running the shell now
> ifconfig
ifconfig
Iface  6  HWaddr: 42:56:96:F1:92:1C 
          L2-PDU:1500  MTU:1500  HL:64  Source address length: 6
          Link type: wired
          inet6 addr: fe80::cafe:cafe:cafe:1  scope: link  VAL
          inet6 addr: fe80::4056:96ff:fef1:921c  scope: link  VAL
          inet6 group: ff02::1
          inet6 group: ff02::1:fffe:1
          inet6 group: ff02::1:fff1:921c

Flash the CoAP Proxy

The coap-coaps proxy will be n1. It must be flashed with the gcoap_dtls example.

sudo COAP_COAPS_PROXY_ENABLE=1 GCOAP_ENABLE_DTLS=1 make flash debug PORT=tap1

main(): This is RIOT! (Version: 2024.04-devel-371-g9bb0a-mariem/coap-coaps-forward-proxy)
gcoap example app
All up, running the shell now
> ifconfig
ifconfig
Iface  8  HWaddr: FE:E7:B7:C6:1F:0E 
          L2-PDU:1500  MTU:1500  HL:64  Source address length: 6
          Link type: wired
          inet6 addr: fe80::cafe:cafe:cafe:1  scope: link  VAL
          inet6 addr: fe80::fce7:b7ff:fec6:1f0e  scope: link  VAL
          inet6 group: ff02::1
          inet6 group: ff02::1:fffe:1
          inet6 group: ff02::1:ffc6:1f0e

Network

I put this script in cpu/native/dist/netdev_tap_setup.sh

#!/bin/sh

set -x

TAPNUM=${TAPNUM:-"0"}
TAPID=$(printf "%02d" ${TAPNUM})
TAPNAME=${TAPNAME:-"tap${TAPNUM}"}
TAPPREFIX=${TAPPREFIX:-"fd${TAPID}::/16"}
TAPSUBNET=${TAPSUBNET:-"fd${TAPID}::/64"}
TAPNEXTHOP=${TAPNEXTHOP:-"fe80::cafe:cafe:cafe:1"}
TAPADDRESS=${TAPADDRESS:-"fd${TAPID}::1/16"}

CURRENT_DIR="$(dirname $(readlink -f $0))"
RADVD_PIDFILE="/tmp/radvd-${TAPNAME}.pid"

tap_exists() {
    ip link show ${TAPNAME} 2> /dev/null
}

tap_up() {
    ip link set ${TAPNAME} up
}

tap_down() {
    ip link set ${TAPNAME} down
}

tap_add_address() {
    ip address add ${TAPADDRESS} dev ${TAPNAME}
}

tap_del_address() {
    ip address del ${TAPADDRESS} dev ${TAPNAME}
}

tap_add_routes() {
    ip route add ${TAPPREFIX} dev ${TAPNAME}
    ip route add ${TAPSUBNET} via ${TAPNEXTHOP} dev ${TAPNAME}
}

tap_del_routes() {
    ip route del ${TAPPREFIX} dev ${TAPNAME}
    ip route del ${TAPSUBNET} dev ${TAPNAME}
}

tap_start_radvd() {
    export TAP=${TAPNAME}
    export PREFIX=${TAPSUBNET}
    cat ${CURRENT_DIR}/radvd.conf | envsubst | radvd -C /dev/stdin -u ${SUDO_USER} -p ${RADVD_PIDFILE}

    if [ $? -ne 0 ]; then
        echo "radvd failed to start on ${TAPNAME} with prefix ${TAPSUBNET}"
        exit 1
    else
        echo "radvd running on ${TAP}"
    fi
}

tap_stop_radvd() {
    if [ -f "${RADVD_PIDFILE}" ]; then
        PID=$(cat ${RADVD_PIDFILE})
    fi
    if [ -n "${PID}" ]; then
        kill ${PID}
        rm ${RADVD_PIDFILE}
        echo "radvd stopped"
    fi
}

enable_forwarding () {
    sysctl -w net.ipv6.conf.all.forwarding=1
}

if [ "$1" = "up" ]; then
    enable_forwarding
    if [ tap_exists ]; then
        tap_up
        tap_add_address
        tap_add_routes
        tap_start_radvd
    fi
elif [ "$1" = "down" ]; then
    if [ tap_exists ]; then
        tap_stop_radvd
        tap_del_routes
        tap_del_address
        tap_down
    fi
else
    echo "Usage: $0 [up|down]"
    exit 1
fi

And I copied dist/tools/radvd/radvd.conf next to it.

Use the script to configure n0.

sudo TAPNUM=0 ./netdev_tap_setup.sh up

> ifconfig
ifconfig
Iface  6  HWaddr: 42:56:96:F1:92:1C 
          L2-PDU:1500  MTU:1500  HL:64  Source address length: 6
          Link type: wired
          inet6 addr: fe80::cafe:cafe:cafe:1  scope: link  VAL
          inet6 addr: fe80::4056:96ff:fef1:921c  scope: link  VAL
          inet6 addr: fd00::4056:96ff:fef1:921c  scope: global  VAL
          inet6 group: ff02::1
          inet6 group: ff02::1:fffe:1
          inet6 group: ff02::1:fff1:921c

Use the script to configure n1.

> ifconfig
ifconfig
Iface  8  HWaddr: FE:E7:B7:C6:1F:0E 
          L2-PDU:1500  MTU:1500  HL:64  Source address length: 6
          Link type: wired
          inet6 addr: fe80::cafe:cafe:cafe:1  scope: link  VAL
          inet6 addr: fe80::fce7:b7ff:fec6:1f0e  scope: link  VAL
          inet6 addr: fd01::fce7:b7ff:fec6:1f0e  scope: global  VAL
          inet6 group: ff02::1
          inet6 group: ff02::1:fffe:1
          inet6 group: ff02::1:ffc6:1f0e

Meanwhile on Linux ip looks like this:

31: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether 06:d3:11:35:6a:42 brd ff:ff:ff:ff:ff:ff
    inet6 fd00::1/16 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::4d3:11ff:fe35:6a42/64 scope link 
       valid_lft forever preferred_lft forever
32: tap1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether a2:ae:a2:2f:af:15 brd ff:ff:ff:ff:ff:ff
    inet6 fd01::1/16 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::a0ae:a2ff:fe2f:af15/64 scope link 
       valid_lft forever preferred_lft forever

Test Reachability

Try to ping n1 from n0.

> ping fd01::fce7:b7ff:fec6:1f0e
ping fd01::fce7:b7ff:fec6:1f0e
12 bytes from fd01::fce7:b7ff:fec6:1f0e: icmp_seq=0 ttl=63 time=1.226 ms
12 bytes from fd01::fce7:b7ff:fec6:1f0e: icmp_seq=1 ttl=63 time=0.366 ms
12 bytes from fd01::fce7:b7ff:fec6:1f0e: icmp_seq=2 ttl=63 time=0.661 ms

--- fd01::fce7:b7ff:fec6:1f0e PING statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.366/0.751/1.226 ms

Set a Proxy server for the Client

In the terminal of n0 enter the address of n1 as a proxy.
Note that the value of this PR is that n0 is not runnnig DTLS and thus the usual coap 5683 port must be used.

> coap proxy set [fd01::fce7:b7ff:fec6:1f0e]:5683
coap proxy set [fd01::fce7:b7ff:fec6:1f0e]:5683
> coap info
coap info
CoAP server is listening on port 5683
 CLI requests sent: 0
CoAP open requests: 0
Configured Proxy: [fd01::fce7:b7ff:fec6:1f0e]:5683

Start a coaps server

I use the latest libcoap coap-server-openssl.

It is bound to the address of tap1.

coap-server-openssl -A fd01::1 -k secretPSK -h Client_identity -v20

Test the coap-coaps proxy

Now n0 can send a coaps proxy request to n1 and n1 does the DTLS handshake with the server.
After that n0 receives the reply from n1.

> coap get -c [fd01::1]:5684 /.well-known/core
coap get -c [fd01::1]:5684 /.well-known/core
gcoap_cli: sending msg ID 52911, 47 bytes
> gcoap: response Success, code 2.05, 151 bytes
</>;title="General Info";ct=0,</time>;if="clock";rt="ticks";title="Internal Clock";ct=0;obs,</async>;ct=0,</example_data>;title="Example Data";ct=0;obs
gcoap: empty ACK matches no known CON, ignoring

@fabian18
Copy link
Contributor

There is an issue when no response is coming from the coaps server to the proxy, or when any error occurs before _forward_resp_handler is called, because the client context is not freed.
During testing I noticed the a 5.00 is returned to the client because the client slots fill up quickly.

@mariemC
Copy link
Contributor Author

mariemC commented Apr 2, 2024

It is a really cool feature! I had some trouble to set up the test environment but I just saw that it works basically. I want to explain it more in detail how to set up a POC example.

We need two native instances call them n0 and n1. For n0 we flash the gcoap example as this will be the CoAP client.

Preparation

Before flashing I did some changes to the Makefiles of examples/gcoap and examples/gcoap_dtls. I give the tap interfaces a known LL address because I have to set some routing rules later to ping between n0 and n1. There is a script to configure the tap interfaces and start radvd on them to advertise a subnet. Also what needs to be changed is the size of CONFIG_GCOAP_PDU_BUF_SIZE, because sock_dtls_recv failed with -ENOMEM.

        ssize_t res = sock_dtls_recv(sock, &socket.ctx_dtls_session, _listen_buf,
                                    sizeof(_listen_buf), 0);
        if (res <= 0) {
            DEBUG("gcoap: DTLS recv failure: %" PRIdSIZE "\n", res);
            return;
        }

examples/gcoap:

diff --git a/examples/gcoap/Makefile b/examples/gcoap/Makefile
index 93bfc25e1b..c5573e5f8f 100644
--- a/examples/gcoap/Makefile
+++ b/examples/gcoap/Makefile
@@ -73,6 +73,15 @@ ifeq (1,$(USE_ZEP))
   USEMODULE += socket_zep
 endif
 
+# Uncomment the following 2 lines to specify static link lokal IPv6 address
+# this might be useful for testing, in cases where you cannot or do not want to
+# run a shell with ifconfig to get the real link lokal address.
+IPV6_STATIC_LLADDR ?= '"fe80::cafe:cafe:cafe:1"'
+CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_LLADDR=$(IPV6_STATIC_LLADDR)
+# uncomment to not increment the last digit by the inderface number
+CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_LLADDR_IS_FIXED=1
+CFLAGS += -DCONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF=4
+
 include $(RIOTBASE)/Makefile.include
 
 # For now this goes after the inclusion of Makefile.include so Kconfig symbols

examples/gcoap_dtls:

diff --git a/examples/gcoap_dtls/Makefile b/examples/gcoap_dtls/Makefile
index 0776185964..75d86c2be7 100644
--- a/examples/gcoap_dtls/Makefile
+++ b/examples/gcoap_dtls/Makefile
@@ -78,6 +78,7 @@ endif
 COAP_COAPS_PROXY_ENABLE ?= 0
 ifeq (1,$(COAP_COAPS_PROXY_ENABLE))
   USEMODULE += coap_coaps_proxy
+  USEMODULE += gcoap_forward_proxy
 endif
 
 # Instead of simulating an Ethernet connection, we can also simulate
@@ -90,6 +91,15 @@ ifeq (1,$(USE_ZEP))
   USEMODULE += socket_zep
 endif
 
+# Uncomment the following 2 lines to specify static link lokal IPv6 address
+# this might be useful for testing, in cases where you cannot or do not want to
+# run a shell with ifconfig to get the real link lokal address.
+IPV6_STATIC_LLADDR ?= '"fe80::cafe:cafe:cafe:1"'
+CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_LLADDR=$(IPV6_STATIC_LLADDR)
+# uncomment to not increment the last digit by the inderface number
+CFLAGS += -DCONFIG_GNRC_IPV6_STATIC_LLADDR_IS_FIXED=1
+CFLAGS += -DCONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF=4
+
 include $(RIOTBASE)/Makefile.include
 
 # For now this goes after the inclusion of Makefile.include so Kconfig symbols

gcoap.h

diff --git a/sys/include/net/gcoap.h b/sys/include/net/gcoap.h
index 8c63709491..77cf88224d 100644
--- a/sys/include/net/gcoap.h
+++ b/sys/include/net/gcoap.h
@@ -460,7 +460,7 @@ extern "C" {
  * @brief   Size of the buffer used to build a CoAP request or response
  */
 #ifndef CONFIG_GCOAP_PDU_BUF_SIZE
-#define CONFIG_GCOAP_PDU_BUF_SIZE      (128)
+#define CONFIG_GCOAP_PDU_BUF_SIZE      (256)
 #endif
 
 /**

Flash the CoAP Client

sudo COAP_COAPS_PROXY_ENABLE=0 GCOAP_ENABLE_DTLS=0 make flash debug PORT=tap0

main(): This is RIOT! (Version: 2024.04-devel-371-g9bb0a-mariem/coap-coaps-forward-proxy)
gcoap example app
All up, running the shell now
> ifconfig
ifconfig
Iface  6  HWaddr: 42:56:96:F1:92:1C 
          L2-PDU:1500  MTU:1500  HL:64  Source address length: 6
          Link type: wired
          inet6 addr: fe80::cafe:cafe:cafe:1  scope: link  VAL
          inet6 addr: fe80::4056:96ff:fef1:921c  scope: link  VAL
          inet6 group: ff02::1
          inet6 group: ff02::1:fffe:1
          inet6 group: ff02::1:fff1:921c

Flash the CoAP Proxy

The coap-coaps proxy will be n1. It must be flashed with the gcoap_dtls example.

sudo COAP_COAPS_PROXY_ENABLE=1 GCOAP_ENABLE_DTLS=1 make flash debug PORT=tap1

main(): This is RIOT! (Version: 2024.04-devel-371-g9bb0a-mariem/coap-coaps-forward-proxy)
gcoap example app
All up, running the shell now
> ifconfig
ifconfig
Iface  8  HWaddr: FE:E7:B7:C6:1F:0E 
          L2-PDU:1500  MTU:1500  HL:64  Source address length: 6
          Link type: wired
          inet6 addr: fe80::cafe:cafe:cafe:1  scope: link  VAL
          inet6 addr: fe80::fce7:b7ff:fec6:1f0e  scope: link  VAL
          inet6 group: ff02::1
          inet6 group: ff02::1:fffe:1
          inet6 group: ff02::1:ffc6:1f0e

Network

I put this script in cpu/native/dist/netdev_tap_setup.sh

#!/bin/sh

set -x

TAPNUM=${TAPNUM:-"0"}
TAPID=$(printf "%02d" ${TAPNUM})
TAPNAME=${TAPNAME:-"tap${TAPNUM}"}
TAPPREFIX=${TAPPREFIX:-"fd${TAPID}::/16"}
TAPSUBNET=${TAPSUBNET:-"fd${TAPID}::/64"}
TAPNEXTHOP=${TAPNEXTHOP:-"fe80::cafe:cafe:cafe:1"}
TAPADDRESS=${TAPADDRESS:-"fd${TAPID}::1/16"}

CURRENT_DIR="$(dirname $(readlink -f $0))"
RADVD_PIDFILE="/tmp/radvd-${TAPNAME}.pid"

tap_exists() {
    ip link show ${TAPNAME} 2> /dev/null
}

tap_up() {
    ip link set ${TAPNAME} up
}

tap_down() {
    ip link set ${TAPNAME} down
}

tap_add_address() {
    ip address add ${TAPADDRESS} dev ${TAPNAME}
}

tap_del_address() {
    ip address del ${TAPADDRESS} dev ${TAPNAME}
}

tap_add_routes() {
    ip route add ${TAPPREFIX} dev ${TAPNAME}
    ip route add ${TAPSUBNET} via ${TAPNEXTHOP} dev ${TAPNAME}
}

tap_del_routes() {
    ip route del ${TAPPREFIX} dev ${TAPNAME}
    ip route del ${TAPSUBNET} dev ${TAPNAME}
}

tap_start_radvd() {
    export TAP=${TAPNAME}
    export PREFIX=${TAPSUBNET}
    cat ${CURRENT_DIR}/radvd.conf | envsubst | radvd -C /dev/stdin -u ${SUDO_USER} -p ${RADVD_PIDFILE}

    if [ $? -ne 0 ]; then
        echo "radvd failed to start on ${TAPNAME} with prefix ${TAPSUBNET}"
        exit 1
    else
        echo "radvd running on ${TAP}"
    fi
}

tap_stop_radvd() {
    if [ -f "${RADVD_PIDFILE}" ]; then
        PID=$(cat ${RADVD_PIDFILE})
    fi
    if [ -n "${PID}" ]; then
        kill ${PID}
        rm ${RADVD_PIDFILE}
        echo "radvd stopped"
    fi
}

enable_forwarding () {
    sysctl -w net.ipv6.conf.all.forwarding=1
}

if [ "$1" = "up" ]; then
    enable_forwarding
    if [ tap_exists ]; then
        tap_up
        tap_add_address
        tap_add_routes
        tap_start_radvd
    fi
elif [ "$1" = "down" ]; then
    if [ tap_exists ]; then
        tap_stop_radvd
        tap_del_routes
        tap_del_address
        tap_down
    fi
else
    echo "Usage: $0 [up|down]"
    exit 1
fi

And I copied dist/tools/radvd/radvd.conf next to it.

Use the script to configure n0.

sudo TAPNUM=0 ./netdev_tap_setup.sh up

> ifconfig
ifconfig
Iface  6  HWaddr: 42:56:96:F1:92:1C 
          L2-PDU:1500  MTU:1500  HL:64  Source address length: 6
          Link type: wired
          inet6 addr: fe80::cafe:cafe:cafe:1  scope: link  VAL
          inet6 addr: fe80::4056:96ff:fef1:921c  scope: link  VAL
          inet6 addr: fd00::4056:96ff:fef1:921c  scope: global  VAL
          inet6 group: ff02::1
          inet6 group: ff02::1:fffe:1
          inet6 group: ff02::1:fff1:921c

Use the script to configure n1.

> ifconfig
ifconfig
Iface  8  HWaddr: FE:E7:B7:C6:1F:0E 
          L2-PDU:1500  MTU:1500  HL:64  Source address length: 6
          Link type: wired
          inet6 addr: fe80::cafe:cafe:cafe:1  scope: link  VAL
          inet6 addr: fe80::fce7:b7ff:fec6:1f0e  scope: link  VAL
          inet6 addr: fd01::fce7:b7ff:fec6:1f0e  scope: global  VAL
          inet6 group: ff02::1
          inet6 group: ff02::1:fffe:1
          inet6 group: ff02::1:ffc6:1f0e

Meanwhile on Linux ip looks like this:

31: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether 06:d3:11:35:6a:42 brd ff:ff:ff:ff:ff:ff
    inet6 fd00::1/16 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::4d3:11ff:fe35:6a42/64 scope link 
       valid_lft forever preferred_lft forever
32: tap1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether a2:ae:a2:2f:af:15 brd ff:ff:ff:ff:ff:ff
    inet6 fd01::1/16 scope global 
       valid_lft forever preferred_lft forever
    inet6 fe80::a0ae:a2ff:fe2f:af15/64 scope link 
       valid_lft forever preferred_lft forever

Test Reachability

Try to ping n1 from n0.

> ping fd01::fce7:b7ff:fec6:1f0e
ping fd01::fce7:b7ff:fec6:1f0e
12 bytes from fd01::fce7:b7ff:fec6:1f0e: icmp_seq=0 ttl=63 time=1.226 ms
12 bytes from fd01::fce7:b7ff:fec6:1f0e: icmp_seq=1 ttl=63 time=0.366 ms
12 bytes from fd01::fce7:b7ff:fec6:1f0e: icmp_seq=2 ttl=63 time=0.661 ms

--- fd01::fce7:b7ff:fec6:1f0e PING statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.366/0.751/1.226 ms

Set a Proxy server for the Client

In the terminal of n0 enter the address of n1 as a proxy. Note that the value of this PR is that n0 is not runnnig DTLS and thus the usual coap 5683 port must be used.

> coap proxy set [fd01::fce7:b7ff:fec6:1f0e]:5683
coap proxy set [fd01::fce7:b7ff:fec6:1f0e]:5683
> coap info
coap info
CoAP server is listening on port 5683
 CLI requests sent: 0
CoAP open requests: 0
Configured Proxy: [fd01::fce7:b7ff:fec6:1f0e]:5683

Start a coaps server

I use the latest libcoap coap-server-openssl.

It is bound to the address of tap1.

coap-server-openssl -A fd01::1 -k secretPSK -h Client_identity -v20

Test the coap-coaps proxy

Now n0 can send a coaps proxy request to n1 and n1 does the DTLS handshake with the server. After that n0 receives the reply from n1.

> coap get -c [fd01::1]:5684 /.well-known/core
coap get -c [fd01::1]:5684 /.well-known/core
gcoap_cli: sending msg ID 52911, 47 bytes
> gcoap: response Success, code 2.05, 151 bytes
</>;title="General Info";ct=0,</time>;if="clock";rt="ticks";title="Internal Clock";ct=0;obs,</async>;ct=0,</example_data>;title="Example Data";ct=0;obs
gcoap: empty ACK matches no known CON, ignoring

Yes the GCOAP_PDU _BUF_SIZE needs to be increased, I added that as a CFLAGS in the Makefile of examples/gcoap_dtls when I tested, I don't see it as a RIOT header change.

Copy link
Contributor

@fabian18 fabian18 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need the coap_coaps_proxy module.
The port selection should not be done by any module constellation, because even if DTLS is used a user still may want to use unsecured coap.
Rather it should be selected by an input URI scheme.
For that, the client must be changed to not take <host>[:port] <path> but accept a full URI instead.

The communication to the proxy should also be determined by <scheme>://<proxy host>[:proxy port].

I would want split this out in another PR which you can rebase on.

There are also a couple of _free_client_ep() missing in the code.
I would want to fix it as well in another PR.
When no reponse is received and the client context has already been passed to the proxy thread it will never get deallocated. Thats why I would add a timestamp to the allocated client and when a new client needs to be allocated, old ones get deleted. This avoids race conditions between the coap and the proxy thread because only the coap thread needs to operate in the client context.

static client_ep_t *_allocate_client_ep(const sock_udp_ep_t *ep)
{
    ztimer_now_t now = ztimer_now(ZTIMER_MSEC);
    client_ep_t *cep;
    for (cep = _client_eps;
         cep < (_client_eps + CONFIG_GCOAP_REQ_WAITING_MAX);
         cep++) {
        if (_cep_in_use(cep) &&
            (now - cep->t_allocated_ms) > CONFIG_GCOAP_FORWARD_PROXY_CLIENT_LIFETIME_MS) {
            _free_client_ep(cep);
        }
        if (!_cep_in_use(cep)) {
            DEBUG("gcoap_forward_proxy: allocating client context %p\n", (void *)cep);
            _cep_set_req_etag_len(cep, 0);
            memcpy(&cep->ep, ep, sizeof(*ep));
            _cep_set_in_use(cep, now);
            return cep;
        }
    }
    return NULL;
}

sys/net/application_layer/gcoap/forward_proxy.c Outdated Show resolved Hide resolved
sys/net/application_layer/gcoap/forward_proxy.c Outdated Show resolved Hide resolved
@fabian18
Copy link
Contributor

fabian18 commented Apr 8, 2024

In _parse_endpoint there it must be:

    if (urip->port != 0) {
        remote->port = urip->port;
    }
    else if (!strncmp(urip->scheme, "coaps", 5)) {
        remote->port = COAPS_PORT;
    }
    else {
        remote->port = COAP_PORT;
    }

miri64
miri64 previously requested changes Apr 15, 2024
Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to have at least a cursory look before this gets merged, but only came back from vacation today. Please give me some time to do this (you may dismiss this change request if I did not comment until 2024-04-22).

@miri64
Copy link
Member

miri64 commented Apr 15, 2024

I think this PR, could be helpful here: #18107 ( I didn't test coaps-coaps)

Why is this PR then needed? #18107 should also support coap to coaps, coaps to coap and everything else (just communicate with the respective endpoint with the respective Proxy-Uri option). Sure, there is a structural bug in gcoap at the moment, that makes the coaps to coaps operation needed, but I am a bit confused, why this PR is introducing a completely separate module for just a certain use case of coap/coaps combination.

@miri64
Copy link
Member

miri64 commented Apr 15, 2024

(just communicate with the respective endpoint with the respective Proxy-Uri option)

This all given that for CoAPS communication the proper credentials are in place, of course.

@mariemC
Copy link
Contributor Author

mariemC commented Apr 15, 2024

Why is this PR then needed? #18107 should also support, coaps to coap and everything else (just communicate with the respective endpoint with the respective Proxy-Uri option). Sure, there is a structural bug in gcoap at the moment, that makes the coaps to coaps operation needed, but I am a bit confused, why this PR is introducing a completely separate module for just a certain use case of coap/coaps combination.

I believe maybe the current approach for integrating a new module to handle CoAP/CoAPs may not be optimal. Instead, I could implement a configurable flag which offers a more straightforward solution ( I am open to suggestions as well). Mainly I had this PR to circumvent the issue of the gcoap blocked thread, by introducing a forward proxy thread.

Furthermore, it's important to note that PR #18107 may encounter difficulties without addressing the gcoap blocked thread. and I think this could solve the issue. (regardless of coaps/coaps or coap/coaps, the new proxy thread is needed)

I could only introduce the proxy thread as well

@miri64
Copy link
Member

miri64 commented Apr 15, 2024

I could only introduce the proxy thread as well

As a workaround, that might be the more viable option, however, in the interest of keeping within resource constraints, an an asynchronous handling of the DTLS handshake, as also proposed by @benpicco in #18107, might be the more solid option. sock_dtls already uses sock_async and it is mostly used by gcoap already. I think _tl_authenticate just needs to be tweaked to not have a busy wait, but rather to delegate the SOCK_ASYNC_CONN_RECV event to the event loop. This of course also causes gcoap_req_send_tl() to be more asynchronous, but this might not be a bad thing either [edit] as pointed out in #18107 (comment):

Maybe an asynchronous version of gcoap_send_req_tl will help here...

@mariemC
Copy link
Contributor Author

mariemC commented Apr 16, 2024

I could only introduce the proxy thread as well

As a workaround, that might be the more viable option, however, in the interest of keeping within resource constraints, an an asynchronous handling of the DTLS handshake, as also proposed by @benpicco in #18107, might be the more solid option. sock_dtls already uses sock_async and it is mostly used by gcoap already. I think _tl_authenticate just needs to be tweaked to not have a busy wait, but rather to delegate the SOCK_ASYNC_CONN_RECV event to the event loop. This of course also causes gcoap_req_send_tl() to be more asynchronous, but this might not be a bad thing either [edit] as pointed out in #18107 (comment):

Maybe an asynchronous version of gcoap_send_req_tl will help here...

Do you suggest then having the workaround with the proxy thread or rather going with async approach?

@miri64
Copy link
Member

miri64 commented Apr 16, 2024

Do you suggest then having the workaround with the proxy thread or rather going with async approach?

If you have the capacity, I would prefer the async approach, but if you are short on time, I am fine with the workaround.

@mariemC
Copy link
Contributor Author

mariemC commented Apr 16, 2024

Do you suggest then having the workaround with the proxy thread or rather going with async approach?

If you have the capacity, I would prefer the async approach, but if you are short on time, I am fine with the workaround.

Time-wise currently is tight, I could for now provide the proxy thread and then have a follow-up with the Async

@miri64 miri64 dismissed their stale review April 16, 2024 11:48

I am fine with the change and will rebase #18107 on top of this, once it is adapted for the proxy thread-only approach.

@mariemC mariemC force-pushed the mariem/coap-coaps-forward-proxy branch from 9bb0a63 to a3ddaf2 Compare April 22, 2024 14:23
@github-actions github-actions bot removed the Area: examples Area: Example Applications label Apr 22, 2024
Comment on lines 50 to 51
static char _forward_proxy_thread[PROXY_STACK_SIZE];
static kernel_pid_t _forward_proxy_pid;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, this should be in an optional sub-module (e.g. forward_proxy_thread.c). For an unencrypted proxy the extra thread is not needed, so this memory usage should not be pulled in.

miri64
miri64 previously requested changes Apr 22, 2024
Comment on lines 473 to 478
/* DTLS communication is blocking the gcoap thread,
* therefore the communication should be handled in the proxy thread */

msg_t msg = { .type = FORWARD_PROXY_MSG_SEND,
.content.ptr = client_ep };
msg_try_send(&msg, _forward_proxy_pid);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can then use

Suggested change
/* DTLS communication is blocking the gcoap thread,
* therefore the communication should be handled in the proxy thread */
msg_t msg = { .type = FORWARD_PROXY_MSG_SEND,
.content.ptr = client_ep };
msg_try_send(&msg, _forward_proxy_pid);
if (IS_USED(MODULE_GCOAP_FORWARD_PROXY_THREAD)) {
/* WORKAROUND: DTLS communication is blocking the gcoap thread,
* therefore the communication should be handled in the proxy thread */
msg_t msg = { .type = FORWARD_PROXY_MSG_SEND,
.content.ptr = client_ep };
msg_try_send(&msg, _forward_proxy_pid);
}
else {
len = gcoap_req_send((uint8_t *)pkt.hdr, len,
&origin_server_ep,
_forward_resp_handler, (void *)client_ep,
GCOAP_SOCKET_TYPE_UNDEF);
}

What worries me a bit is that this changes the semantic of len, but this is a workaround after all and is already the case in your current code.

Comment on lines 116 to 119
_forward_proxy_pid = thread_create(_forward_proxy_thread, sizeof(_forward_proxy_thread),
THREAD_PRIORITY_MAIN - 1,
THREAD_CREATE_STACKTEST, _forward_proxy_thread_start,
NULL, "proxy");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And

Suggested change
_forward_proxy_pid = thread_create(_forward_proxy_thread, sizeof(_forward_proxy_thread),
THREAD_PRIORITY_MAIN - 1,
THREAD_CREATE_STACKTEST, _forward_proxy_thread_start,
NULL, "proxy");
if IS_USED(MODULE_GCOAP_FORWARD_PROXY_THREAD) {
_forward_proxy_pid = thread_create(_forward_proxy_thread, sizeof(_forward_proxy_thread),
THREAD_PRIORITY_MAIN - 1,
THREAD_CREATE_STACKTEST, _forward_proxy_thread_start,
NULL, "proxy");
}

(probably needs to be adapted for the fact that _forward_proxy_thread_start will become at least an extern)

sys/include/net/gcoap/forward_proxy.h Outdated Show resolved Hide resolved
sys/include/net/gcoap/forward_proxy.h Outdated Show resolved Hide resolved
sys/net/application_layer/gcoap/forward_proxy.c Outdated Show resolved Hide resolved
sys/net/application_layer/gcoap/forward_proxy.c Outdated Show resolved Hide resolved
@mariemC mariemC force-pushed the mariem/coap-coaps-forward-proxy branch from a3ddaf2 to 4700081 Compare April 24, 2024 14:03
@github-actions github-actions bot added the Area: build system Area: Build system label Apr 24, 2024
@mariemC mariemC force-pushed the mariem/coap-coaps-forward-proxy branch from 4700081 to 4d8c173 Compare April 24, 2024 14:32
Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO it's better to wrap around gcoap_req_send() with a client_ep_t pointer as parameter instead of exposing the response handler. But iff you insist, it should have a more unique name.

#include "debug.h"

static char _forward_proxy_thread[GCOAP_PROXY_STACK_SIZE];
kernel_pid_t _forward_proxy_pid;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
kernel_pid_t _forward_proxy_pid;
static kernel_pid_t _forward_proxy_pid;

@@ -250,7 +244,7 @@ static void _set_response_type(coap_pkt_t *pdu, uint8_t resp_type)
}
}

static void _forward_resp_handler(const gcoap_request_memo_t *memo,
void _forward_resp_handler(const gcoap_request_memo_t *memo,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
void _forward_resp_handler(const gcoap_request_memo_t *memo,
void _gcoap_forward_resp_handler(const gcoap_request_memo_t *memo,

Just to be on the save side naming-wise. ;-)

static char _forward_proxy_thread[GCOAP_PROXY_STACK_SIZE];
kernel_pid_t _forward_proxy_pid;

extern void _forward_resp_handler(const gcoap_request_memo_t *memo,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
extern void _forward_resp_handler(const gcoap_request_memo_t *memo,
extern void _gcoap_forward_resp_handler(const gcoap_request_memo_t *memo,

}
else {
len = gcoap_req_send((uint8_t *)client_ep->pdu.hdr, coap_get_total_len(&client_ep->pdu),
&client_ep->server_ep, _forward_resp_handler, client_ep,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
&client_ep->server_ep, _forward_resp_handler, client_ep,
&client_ep->server_ep, _gcoap_forward_resp_handler, client_ep,

switch (msg.type) {
case GCOAP_FORWARD_PROXY_MSG_SEND: {
if (gcoap_req_send((uint8_t *)cep->pdu.hdr, coap_get_total_len(&cep->pdu),
&cep->server_ep, _forward_resp_handler, cep,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
&cep->server_ep, _forward_resp_handler, cep,
&cep->server_ep, _gcoap_forward_resp_handler, cep,

Comment on lines 45 to 49
if (gcoap_req_send((uint8_t *)cep->pdu.hdr, coap_get_total_len(&cep->pdu),
&cep->server_ep, _forward_resp_handler, cep,
GCOAP_SOCKET_TYPE_UNDEF) < 0) {
DEBUG_PUTS("_forward_proxy_thread_start: gcoap_req_send failed\n");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This somewhat looks like a duplication of https://github.com/RIOT-OS/RIOT/pull/20454/files#diff-29f9b7660bbd785a3db5ce4ed3ebd3f5f396b1bd51193576e232a526b6808b85R445 now. Wouldn't it be better to expose a function that uses the client_ep_t pointer as an input instead of exposing the response handler?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes either create a wrapping API for example gcoap_forward_proxy_req_send() or create an internal header file.

@mariemC mariemC force-pushed the mariem/coap-coaps-forward-proxy branch from d0c6ef5 to f2d4cd5 Compare April 25, 2024 11:30
@mariemC mariemC force-pushed the mariem/coap-coaps-forward-proxy branch from f2d4cd5 to 768ce5e Compare April 25, 2024 11:36
@mariemC
Copy link
Contributor Author

mariemC commented Apr 29, 2024

For testing the client should provide a coaps URI with GCOAPS port ( for that I tweaked the gcoap example) but I think this could be used from Fabian. #20554

@miri64 miri64 dismissed their stale review April 29, 2024 10:13

I leave the rest to @fabian18

@fabian18
Copy link
Contributor

For testing the client should provide a coaps URI with GCOAPS port ( for that I tweaked the gcoap example) but I think this could be used from Fabian. #20554

The changes here look good for me. There is just the thing that @mariemC hard coded whether to use either coap or coaps to talk to the proxy. You can say that it is decided by ports 5683 or 5684 but also a non standard port could be used and that motivated me to create the liked PR. So I wanted to get that in first actually. If that is not feasible, then we would need to add the "port maps schema" assumption here.

@miri64
Copy link
Member

miri64 commented Apr 29, 2024

There is just the thing that @mariemC hard coded whether to use either coap or coaps to talk to the proxy. You can say that it is decided by ports 5683 or 5684 but also a non standard port could be used and that motivated me to create the liked PR. So I wanted to get that in first actually. If that is not feasible, then we would need to add the "port maps schema" assumption here.

I think any notion of proxying was actually removed in this PR. #18107 uses the URI (and hopefully at some point CRI) schema to identify the protocol. If the port is different, that should also be encoded in the URI (and covered in #18107), so I am not sure what the problem is. All I need to do is rebase #18107 and make the module introduced here a dependency, once this PR is merged.

@miri64
Copy link
Member

miri64 commented Apr 29, 2024

Or is the problem that the gcoap example currently does not accept URIs as input for its commands (which, as far as I understand it is fixed by #20554; thanks for that btw!)

@fabian18
Copy link
Contributor

fabian18 commented Apr 30, 2024

Or is the problem that the gcoap example currently does not accept URIs as input for its commands (which, as far as I understand it is fixed by #20554; thanks for that btw!)

Yes, Exactly.

When you run the PR as is, the protocol towards the proxy is chosen implicitly here.:

bytes_sent = gcoap_req_send(buf, len, remote, _resp_handler, NULL,
                                                      GCOAP_SOCKET_TYPE_UNDEF);

followed by

static int _tl_init_coap_socket(gcoap_socket_t *sock, gcoap_socket_type_t type)
{
    switch (type) {
#if !IS_USED(MODULE_GCOAP_DTLS)
        case GCOAP_SOCKET_TYPE_UNDEF:
#endif
        case GCOAP_SOCKET_TYPE_UDP:
            sock->type = GCOAP_SOCKET_TYPE_UDP;
            sock->socket.udp = &_sock_udp;
            break;
#if IS_USED(MODULE_GCOAP_DTLS)
        case GCOAP_SOCKET_TYPE_UNDEF:
        case GCOAP_SOCKET_TYPE_DTLS:
            sock->type = GCOAP_SOCKET_TYPE_DTLS;
            sock->socket.dtls = &_sock_dtls;
            break;
#else
        default:
            return -1;
#endif
    }
    return 0;
}

where the socket is selected based on used modules.
But for example if the client has a DTLS stack, maybe you still want to talk plain coap to a proxy.
#20554 fixes this because there you need to specify a scheme for a proxy.

The second place is here:

        if (_proxied) {
#ifdef SOCK_HAS_IPV6
            char addrstr[IPV6_ADDR_MAX_STR_LEN];
#else
            char addrstr[IPV4_ADDR_MAX_STR_LEN];
#endif
            inet_ntop(remote.family, &remote.addr, addrstr, sizeof(addrstr));

            if (remote.family == AF_INET6) {
                uri_len = snprintf(proxy_uri, sizeof(proxy_uri), "coap://[%s]:%d%s",
                                   addrstr, remote.port, uri);
            }
            else {
                uri_len = snprintf(proxy_uri, sizeof(proxy_uri), "coap://%s:%d%s",
                                   addrstr, remote.port, uri);
            }

            uri = proxy_uri;
        }

@mariemC has a hard coded "coaps://[%s]:%d%s" here (not pushed).
The obvious fix in #20554 is that the URI has to be specified for a request.

@miri64
Copy link
Member

miri64 commented Apr 30, 2024

bytes_sent = gcoap_req_send(buf, len, remote, _resp_handler, NULL,
                                                      GCOAP_SOCKET_TYPE_UNDEF);
    

(for future reference: can you please use code links, please? If you use an absolute SHA reference (which you can generate by hitting “y” in the GitHub code view) the code from the current repo will be shown; makes it easier to follow which code you are talking about)


Yes this needs to be replaced by the corresponding SOCKET_TYPE from the schema, of course!

@miri64
Copy link
Member

miri64 commented Apr 30, 2024

        if (_proxied) {
#ifdef SOCK_HAS_IPV6
            char addrstr[IPV6_ADDR_MAX_STR_LEN];
#else
            char addrstr[IPV4_ADDR_MAX_STR_LEN];
#endif
            inet_ntop(remote.family, &remote.addr, addrstr, sizeof(addrstr));

            if (remote.family == AF_INET6) {
                uri_len = snprintf(proxy_uri, sizeof(proxy_uri), "coap://[%s]:%d%s",
                                   addrstr, remote.port, uri);
            }
            else {
                uri_len = snprintf(proxy_uri, sizeof(proxy_uri), "coap://%s:%d%s",
                                   addrstr, remote.port, uri);
            }

            uri = proxy_uri;
        }

IMHO, the proxy should be configured as a URI outright. I thought this was already the case, but apparently it isn't:

else if (strcmp(argv[1], "proxy") == 0) {
if ((argc == 4) && (strcmp(argv[2], "set") == 0)) {
if (sock_udp_name2ep(&_proxy_remote, argv[3]) != 0) {
puts("Could not set proxy");
return 1;
}
if (_proxy_remote.port == 0) {
if (IS_USED(MODULE_GCOAP_DTLS)) {
_proxy_remote.port = CONFIG_GCOAPS_PORT;
}
else {
_proxy_remote.port = CONFIG_GCOAP_PORT;
}
}
_proxied = true;
return 0;
}
if ((argc == 3) && (strcmp(argv[2], "unset") == 0)) {
memset(&_proxy_remote, 0, sizeof(_proxy_remote));
_proxied = false;
return 0;
}
printf("usage: %s proxy set <host>[:port]\n", argv[0]);
printf(" %s proxy unset\n", argv[0]);
return 1;
}

Must have been my own app I was thinking of ^^"

@miri64 miri64 added this pull request to the merge queue May 6, 2024
Merged via the queue into RIOT-OS:master with commit a5996e2 May 6, 2024
27 checks passed
@mguetschow mguetschow added this to the Release 2024.07 milestone Jul 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: build system Area: Build system Area: CoAP Area: Constrained Application Protocol implementations Area: network Area: Networking Area: sys Area: System CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants