Allow to customise http.Transport for RPC client #1310

Open
opened 2025-12-28 17:15:58 +00:00 by sami · 2 comments
Owner

Originally created by @fyfyrchik on GitHub (May 29, 2024).

The support for providing custom http.Client was removed in nspcc-dev/neo-go@315aabde56. However, there is a number of ways one could want to customize it:

  1. Providing client TLS certificate. Use case: using mTLS on the RPC interface in private networks. Currently, RPC server has no support for this, but it can easily be added in a fork, updating client dependencies is much more difficult.
  2. A related, but separate use case is authenticating server certificate (e.g. make sure it is signed with an NSPCC CA in some private albeit distributed NSPCC deployment).
  3. Policy-based routing. Imagine I have the following routing table and need to provide source address to pick a proper interface. What I need to do here is to set net.Dialer.LocalAddr (== provide custom DialContext). There are multiple lower-level solutions (bond), but they have their own problems, so I have no control over this part.
service@slovo:~$ ip route
...
192.168.201.0/24 dev internal0 proto kernel scope link src 192.168.201.20
192.168.201.0/24 dev internal1 proto kernel scope link src 192.168.201.120
  1. Simplify tests. We could fuzz everything we receive (as it is just a string), or we could rewrite rpcclient/rpc_test.go without using httptest.Server. If RPC response is an untrusted input in my threat model (e.g. I don't use mTLS), it could be necessary (i.e. following the letter of law) to fuzz my service as a blackbox.

Describe the solution you'd like

  1. Deprecate Cert, Key and CACert in rpcclient.Options
  2. Add func(h *http.Client) as option. Lots of ways to do this part actually, mine is an example of what will work.

Describe alternatives you've considered

  1. Adding custom options for each use case. More work, less flexible.
  2. Forking or vendoring rpcclient code. Quickly becomes unmaintainable.
Originally created by @fyfyrchik on GitHub (May 29, 2024). ## Is your feature request related to a problem? Please describe. The support for providing custom http.Client was removed in https://github.com/nspcc-dev/neo-go/commit/315aabde564fd8429b3f262cff83080535e9084b. However, there is a number of ways one could want to customize it: 1. Providing client TLS certificate. Use case: using mTLS on the RPC interface in private networks. Currently, RPC server has no support for this, but it can easily be added in a fork, updating client dependencies is much more difficult. 2. A related, but separate use case is authenticating server certificate (e.g. make sure it is signed with an NSPCC CA in some private albeit distributed NSPCC deployment). 3. Policy-based routing. Imagine I have the following routing table and need to provide source address to pick a proper interface. What I need to do here is to set `net.Dialer.LocalAddr` (== provide custom `DialContext`). There are multiple lower-level solutions (bond), but they have their own problems, so I have no control over this part. ``` service@slovo:~$ ip route ... 192.168.201.0/24 dev internal0 proto kernel scope link src 192.168.201.20 192.168.201.0/24 dev internal1 proto kernel scope link src 192.168.201.120 ``` 4. Simplify tests. We could fuzz everything we receive (as it is just a string), or we could rewrite `rpcclient/rpc_test.go` without using `httptest.Server`. If RPC response is an untrusted input in my threat model (e.g. I don't use mTLS), it could be _necessary_ (i.e. following the letter of law) to fuzz my service as a blackbox. ## Describe the solution you'd like 1. Deprecate `Cert`, `Key` and `CACert` in `rpcclient.Options` 2. Add `func(h *http.Client)` as option. Lots of ways to do this part actually, mine is an example of what will work. ## Describe alternatives you've considered 1. Adding custom options for each use case. More work, less flexible. 2. Forking or vendoring `rpcclient` code. Quickly becomes unmaintainable.
Author
Owner

@roman-khimov commented on GitHub (May 29, 2024):

Providing client TLS certificate.

It was meant to be supported by the client natively (see Options), but never was implemented. Same thing with server authentication. But you know that and other cases like routing really can require something more fancy. We'll think about it.

@roman-khimov commented on GitHub (May 29, 2024): > Providing client TLS certificate. It was meant to be supported by the client natively (see `Options`), but never was implemented. Same thing with server authentication. But you know that and other cases like routing really can require something more fancy. We'll think about it.
Author
Owner

@fyfyrchik commented on GitHub (Jun 11, 2024):

Turns out func(h *http.Client) is not that flexible. For Websocket clients we need to explicitly provide some options in NewWS because it connects differently nspcc-dev/neo-go@b66cea5ccc/pkg/rpcclient/wsclient.go (L456)

Explicit *tls.Config option solves mTLS issues, but again other points in the OP require custom options.

@fyfyrchik commented on GitHub (Jun 11, 2024): Turns out `func(h *http.Client)` is not _that_ flexible. For Websocket clients we need to explicitly provide some options in `NewWS` because it connects differently https://github.com/nspcc-dev/neo-go/blob/b66cea5cccbcc8446312b012e29aaf2d1837430a/pkg/rpcclient/wsclient.go#L456 Explicit `*tls.Config` option solves mTLS issues, but again other points in the OP require custom options.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nspcc-dev/neo-go#1310
No description provided.