mirror of
https://github.com/ipfs/kubo.git
synced 2026-03-10 02:40:11 +08:00
Merge pull request #10019 from djdv/uds-client
fix(rpc): cross-platform support for /unix/ socket maddrs in Addresses.API
This commit is contained in:
commit
c5b0428860
@ -5,6 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -98,11 +99,29 @@ func ApiAddr(ipfspath string) (ma.Multiaddr, error) {
|
||||
|
||||
// NewApi constructs HttpApi with specified endpoint.
|
||||
func NewApi(a ma.Multiaddr) (*HttpApi, error) {
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DisableKeepAlives: true,
|
||||
}
|
||||
|
||||
network, address, err := manet.DialArgs(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if network == "unix" {
|
||||
transport.DialContext = func(_ context.Context, _, _ string) (net.Conn, error) {
|
||||
return net.Dial("unix", address)
|
||||
}
|
||||
c := &http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
// This will create an API client which
|
||||
// makes requests to `http://unix`.
|
||||
return NewURLApiWithClient(network, c)
|
||||
}
|
||||
|
||||
c := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
DisableKeepAlives: true,
|
||||
},
|
||||
Transport: transport,
|
||||
}
|
||||
|
||||
return NewApiWithClient(a, c)
|
||||
|
||||
@ -113,6 +113,11 @@ control your node remotely. If you need to control the node remotely,
|
||||
make sure to protect the port as you would other services or database
|
||||
(firewall, authenticated proxy, etc), or at least set API.Authorizations.
|
||||
|
||||
If you do not want to open any ports for RPC, and only want to use
|
||||
kubo CLI client, it is possible to expose the RPC over Unix socket:
|
||||
|
||||
ipfs config Addresses.API /unix/var/run/kubo.socket
|
||||
|
||||
HTTP Headers
|
||||
|
||||
Kubo supports passing arbitrary headers to the RPC API and Gateway. You can
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
- [AutoNAT V2 Service Introduced Alongside V1](#autonat-v2-service-introduced-alongside-v1)
|
||||
- [Automated `ipfs version check`](#automated-ipfs-version-check)
|
||||
- [Version Suffix Configuration](#version-suffix-configuration)
|
||||
- [`/unix/` socket support in `Addresses.API`](#unix-socket-support-in-addressesapi)
|
||||
- [Cleaned Up `ipfs daemon` Startup Log](#cleaned-up-ipfs-daemon-startup-log)
|
||||
- [📝 Changelog](#-changelog)
|
||||
- [👨👩👧👦 Contributors](#-contributors)
|
||||
@ -49,7 +50,24 @@ Defining the optional agent version suffix is now simpler. The [`Version.AgentSu
|
||||
|
||||
> [!NOTE]
|
||||
> Setting a custom version suffix helps with ecosystem analysis, such as Amino DHT reports published at https://stats.ipfs.network
|
||||
>
|
||||
|
||||
#### `/unix/` socket support in `Addresses.API`
|
||||
|
||||
This release fixes a bug which blocked users from using Unix domain sockets for [Kubo's RPC](https://docs.ipfs.tech/reference/kubo/rpc/) (instead of a local HTTP port).
|
||||
|
||||
```console
|
||||
$ ipfs config Addresses.API "/unix/tmp/kubo.socket"
|
||||
$ ipfs daemon # start with rpc socket
|
||||
...
|
||||
RPC API server listening on /unix/tmp/kubo.socket
|
||||
|
||||
$ # cli client, in different terminal can find socket via /api file
|
||||
$ cat $IPFS_PATH/api
|
||||
/unix/tmp/kubo.socket
|
||||
|
||||
$ # or have it pased via --api
|
||||
$ ipfs --api=/unix/tmp/kubo.socket id
|
||||
```
|
||||
|
||||
#### Cleaned Up `ipfs daemon` Startup Log
|
||||
|
||||
|
||||
@ -350,6 +350,17 @@ func (n *Node) checkAPI(authorization string) bool {
|
||||
log.Debugf("node %d API addr not available yet: %s", n.ID, err.Error())
|
||||
return false
|
||||
}
|
||||
|
||||
if unixAddr, err := apiAddr.ValueForProtocol(multiaddr.P_UNIX); err == nil {
|
||||
parts := strings.SplitN(unixAddr, "/", 2)
|
||||
if len(parts) < 1 {
|
||||
panic("malformed unix socket address")
|
||||
}
|
||||
fileName := "/" + parts[1]
|
||||
_, err := os.Stat(fileName)
|
||||
return !errors.Is(err, fs.ErrNotExist)
|
||||
}
|
||||
|
||||
ip, err := apiAddr.ValueForProtocol(multiaddr.P_IP4)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
51
test/cli/rpc_unixsocket_test.go
Normal file
51
test/cli/rpc_unixsocket_test.go
Normal file
@ -0,0 +1,51 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
rpcapi "github.com/ipfs/kubo/client/rpc"
|
||||
"github.com/ipfs/kubo/config"
|
||||
"github.com/ipfs/kubo/test/cli/harness"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRPCUnixSocket(t *testing.T) {
|
||||
node := harness.NewT(t).NewNode().Init()
|
||||
|
||||
sockDir := node.Dir
|
||||
sockAddr := path.Join("/unix", sockDir, "sock")
|
||||
|
||||
node.UpdateConfig(func(cfg *config.Config) {
|
||||
//cfg.Addresses.API = append(cfg.Addresses.API, sockPath)
|
||||
cfg.Addresses.API = []string{sockAddr}
|
||||
})
|
||||
t.Log("Starting daemon with unix socket:", sockAddr)
|
||||
node.StartDaemon()
|
||||
|
||||
unixMaddr, err := multiaddr.NewMultiaddr(sockAddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
apiClient, err := rpcapi.NewApi(unixMaddr)
|
||||
require.NoError(t, err)
|
||||
|
||||
var ver struct {
|
||||
Version string
|
||||
}
|
||||
err = apiClient.Request("version").Exec(context.Background(), &ver)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, ver)
|
||||
t.Log("Got version:", ver.Version)
|
||||
|
||||
var res struct {
|
||||
ID string
|
||||
}
|
||||
err = apiClient.Request("id").Exec(context.Background(), &res)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, res)
|
||||
t.Log("Got ID:", res.ID)
|
||||
|
||||
node.StopDaemon()
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user