diff --git a/README.md b/README.md index 6bcd8bd..858fcbb 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ mProxy is used to proxy requests to a backend server. For the example setup, we - mProxy server for `HTTP protocol without TLS` on port `8086` with prefix path `/messages` - mProxy server for `HTTP protocol with TLS` on port `8087` with prefix path `/messages` - mProxy server for `HTTP protocol with mTLS` on port `8088` with prefix path `/messages` - - mProxy server for `COAP protocol without DTLS` on port `5682` + - mProxy server for `COAP protocol without DTLS` on port `5682` - mProxy server for `COAP protocol with DTLS` on port `5684` ### Example testing of mProxy @@ -193,6 +193,23 @@ Bash scripts available in `examples/client/http` directory help to test the mPro examples/client/http/with_mtls.sh ``` +### Test mProxy server for CoAP protocols + +Bash scripts available in `example/client/coap` directory help to test the mProxy servers running for CoAP protocols. +This scripts can be used after changing the `MPROXY_COAP_WITHOUT_DTLS_TARGET` and `MPROXY_COAP_WITH_DTLS_TARGET` to a public coap server such as `coap://coap.me:5683` + +- Script to test mProxy server running at 5682 for CoAP without DTLS + + ```bash + examples/client/coap/without_dtls.sh + ``` + +- Script to test mProxy server running at 5684 for CoAP with DTLS + + ```bash + examples/client/coap/without_dtls.sh + ``` + ## Configuration The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values. @@ -248,6 +265,14 @@ The service is configured using the environment variables presented in the follo | MPROXY_HTTP_WITH_MTLS_CLIENT_CA_FILE | HTTP with mTLS client CA file path | ssl/certs/ca.crt | | MPROXY_HTTP_WITH_MTLS_CERT_VERIFICATION_METHODS | HTTP with mTLS certificate verification methods, if no value or unset then mProxy server will not do client validation | ocsp | | MPROXY_HTTP_WITH_MTLS_OCSP_RESPONDER_URL | HTTP with mTLS OCSP responder URL, it is used if OCSP responder URL is not available in client certificate AIA | | +| MPROXY_COAP_WITHOUT_DTLS_ADDRESS | CoAP without DTLS inbound (IN) connection listening address | localhost:5682 | +| MPROXY_COAP_WITH_DTLS_TARGET | CoAP without DTLS outbound (OUT) connection | localhost:5683 | +| MPROXY_COAP_WITH_DTLS_ADDRESS | CoAP with DTLS inbound (IN) connection listening address | localhost:5684 | +| MPROXY_COAP_WITH_DTLS_TARGET | CoAP with DTLS outbound (OUT) connection | localhost:5683 | +| MPROXY_COAP_WITH_DTLS_CERT_FILE | CoAP with DTLS certificate file | ssl/certs/server.crt | +| MPROXY_COAP_WITH_DTLS_KEY_FILE | CoAP with DTLS key file | ssl/certs/server.key | +| MPROXY_COAP_WITH_DTLS_SERVER_CA_FILE | CoAP with DTLS server CA file | ssl/certs/ca.crt | +| MPROXY_COAP_WITH_DTLS_CLIENT_CA_FILE | CoAP with DTLS client CA file | ssl/certs/ca.crt | ## mProxy Configuration Environment Variables diff --git a/examples/client/coap/with_dtls.sh b/examples/client/coap/with_dtls.sh new file mode 100755 index 0000000..3e6cbee --- /dev/null +++ b/examples/client/coap/with_dtls.sh @@ -0,0 +1,25 @@ +#!/bin/bash +protocol=coaps +host=localhost +port=5684 +path="test" +content=0x32 +message="{\"message\": \"Hello mProxy\"}" +auth="TOKEN" +cafile=ssl/certs/ca.crt +certfile=ssl/certs/client.crt +keyfile=ssl/certs/client.key + +echo "Posting message to ${protocol}://${host}:${port}/${path} with dtls ..." +coap-client -m post coap://${host}:${port}/${path} -e "${message}" -O 12,${content} -O 15,auth=${auth} \ + -c $certfile -k $keyfile -C $cafile + +echo "Getting message from ${protocol}://${host}:${port}/${path} with dtls ..." +coap-client -m get coap://${host}:${port}/${path} -O 6,0x00 -O 15,auth=${auth} -c $certfile -k $keyfile -C $cafile + +echo "Posting message to ${protocol}://${host}:${port}/${path} with dtls and invalid client certificate..." +coap-client -m post coap://${host}:${port}/${path} -e "${message}" -O 12,${content} -O 15,auth=${auth} \ + -c ssl/certs/client_unknown.crt -k ssl/certs/client_unknown.key -C $cafile + +echo "Getting message from ${protocol}://${host}:${port}/${path} with dtls and invalid client certificate..." +coap-client -m get coap://${host}:${port}/${path} -O 6,0x00 -O 15,auth=${auth} -c ssl/certs/client_unknown.crt -k ssl/certs/client_unknown.key -C $cafile diff --git a/examples/client/coap/without_dtls.sh b/examples/client/coap/without_dtls.sh new file mode 100755 index 0000000..add609a --- /dev/null +++ b/examples/client/coap/without_dtls.sh @@ -0,0 +1,14 @@ +#!/bin/bash +protocol=coap +host=localhost +port=5682 +path="test" +content=0x32 +message="{\"message\": \"Hello mProxy\"}" +auth="TOKEN" + +echo "Posting message to ${protocol}://${host}:${port}/${path} without tls ..." +coap-client -m post coap://${host}:${port}/${path} -e "${message}" -O 12,${content} -O 15,auth=${auth} + +echo "Getting message from ${protocol}://${host}:${port}/${path} without tls ..." +coap-client -m get coap://${host}:${port}/${path} -O 6,0x00 -O 15,auth=${auth} - diff --git a/pkg/coap/coap.go b/pkg/coap/coap.go index 88c7159..7964900 100644 --- a/pkg/coap/coap.go +++ b/pkg/coap/coap.go @@ -22,6 +22,11 @@ import ( "github.com/plgd-dev/go-coap/v3/udp" ) +var ( + errUnsupportedConfig = errors.New("unsupported CoAP configuration") + errUnsupportedMethod = errors.New("unsupported CoAP method") +) + type Proxy struct { config mproxy.Config session session.Handler @@ -47,15 +52,19 @@ func sendErrorMessage(cc mux.Conn, token []byte, err error, code codes.Code) err } func (p *Proxy) postUpstream(cc mux.Conn, req *mux.Message, token []byte) error { - format, err := req.ContentFormat() - if err != nil { - return err - } path, err := req.Options().Path() if err != nil { return err } + format := message.TextPlain + if req.HasOption(message.ContentFormat) { + format, err = req.ContentFormat() + if err != nil { + return err + } + } + targetConn, err := udp.Dial(p.config.Target) if err != nil { return err @@ -92,7 +101,7 @@ func (p *Proxy) observeUpstream(ctx context.Context, cc mux.Conn, opts []message targetConn, err := udp.Dial(p.config.Target) if err != nil { if err := sendErrorMessage(cc, token, err, codes.BadGateway); err != nil { - p.logger.Error("cannot send error response: %v", err) + p.logger.Error(fmt.Sprintf("cannot send error response: %v", err)) } } defer targetConn.Close() @@ -112,14 +121,14 @@ func (p *Proxy) observeUpstream(ctx context.Context, cc mux.Conn, opts []message }, opts...) if err != nil { if err := sendErrorMessage(cc, token, err, codes.BadGateway); err != nil { - p.logger.Error("cannot send error response: %v", err) + p.logger.Error(fmt.Sprintf("cannot send error response: %v", err)) } } select { case <-doneObserving: if err := obs.Cancel(ctx); err != nil { - p.logger.Error("failed to cancel observation: %v", err) + p.logger.Error(fmt.Sprintf("failed to cancel observation:%v", err)) } case <-ctx.Done(): return @@ -168,6 +177,10 @@ func (p *Proxy) handler(w mux.ResponseWriter, r *mux.Message) { return } p.handlePost(ctx, w.Conn(), body, r.Token(), path, r) + default: + if err := sendErrorMessage(w.Conn(), r.Token(), errUnsupportedMethod, codes.MethodNotAllowed); err != nil { + p.logger.Error(err.Error()) + } } } @@ -273,6 +286,6 @@ func (p *Proxy) Listen(ctx context.Context) error { } return nil default: - return errors.New("unsupported CoAP configuration") + return errUnsupportedConfig } }