Hello, is there a configuration option to bind to a specific local IP address for the routines that are sending data to ports 5775 and 7777?
It looks like with standard config these are using host IP address, which might be undesirable in some setups.
Well, did you try to specify desired_IP:port
instead of 0:port
or :port
? As 127.0.0.1:port
vs 0:port
works as expected for debug port, I see no reason why it should be different for 7777
All the addresses I have specified as IP:port, but I do not see a way to define it for these data reports going to some google service. Because of this these reports are taking a different route than the rest of the storagenode.
The source port also looks to be random, so the definition would have to be an IP address only I think and I do not see such option in the config.
# lsof -i | grep 192.168.1.130
storageno 188688 storj 7u IPv4 3593951118 0t0 UDP 192.168.1.130:41927->120.40.184.35.bc.googleusercontent.com:5775
# config.yaml
console.address: 192.168.1.131:14002
debug.addr: 192.168.1.131:9651
server.address: 192.168.1.131:28967
server.private-address: 192.168.1.131:7778
It looks like only the destination can be specified for these routines, such as:
# address for jaeger agent
# tracing.agent-addr: agent.tracing.datasci.storj.io:5775
Because they don’t listen on ports, they pass data, so it’s not the services that connect to your node, but your node that establishes a connection to the tracing service.
It should be configured on your device in the routing table, not in the node’s config.
I understand, I’m doing that on the router, but that is based on the source IP address.
It looks like with IP tables you can do source NAT per process owner and change source IP that way, or I guess I can mark with DSCP on host and match and route based on that on the router, but that would mean creating multiple users on the host, messing with IP tables, creating additional rules on the router, and I like things simple.
So I think a better approach would be to be able to specify which local IP address to use for this outbound service traffic in the storagenode config, so here I’m hinting at code changes and I’m not familiar with Go .
it’s hard to implement, it’s the OS level, not application level. Yes of course you may try to re-implement the routing table, but we do not have free engineering resources to partially re-implent the system network stack.
It must be done by OS, not the storage application, because it’s an outgoing traffic initiated by the application. This is an exact job for the routing table to route this request properly.
This is the same as asking the browsers developers to implement the routing table in the browser to send requests from different IP.
The IP address is already present on the system, so in a way it should be as easy as tell the socket to use this IP address, something similar to telling the storagenode to listen on this IP:port, as for example 192.168.1.100:14002. In such case the web interface is only available on this IP address, even if there are multiple configured on the system.
Gen AI came up with something like below.
It looks to be http specific, but maybe something similar exists even for raw TCP/UDP sockets and in such case it would be adding one more parameter to the socket and creating a config file entry for it.
package main
import (
"context"
"fmt"
"io"
"log"
"net"
"net/http"
"time"
)
func main() {
// Replace with your desired local IP address
localIP := "192.168.1.100"
// Replace with the target URL
targetURL := "https://www.example.com"
// Create a custom dialer
dialer := &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
LocalAddr: &net.TCPAddr{IP: net.ParseIP(localIP)},
}
// Create a custom transport with the dialer
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: dialer.DialContext,
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
// Create an HTTP client with the custom transport
client := &http.Client{
Timeout: time.Second * 10,
Transport: transport,
}
// Perform the request
resp, err := client.Get(targetURL)
if err != nil {
log.Fatalf("Error fetching URL: %v", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
fmt.Println("Response from:", resp.Request.URL.String())
}
Then you can implement this hack for your own storagenode, if you believe that it’s simpler than properly configure the routing table.