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

Does not use bind to local address for outgoing connections #6476

Open
kroeckx opened this issue Jul 26, 2015 · 12 comments
Open

Does not use bind to local address for outgoing connections #6476

kroeckx opened this issue Jul 26, 2015 · 12 comments

Comments

@kroeckx
Copy link

kroeckx commented Jul 26, 2015

I have several IPv4 / IPv6 addresses on a host and I wish to use a specific one. So I set up the bind so it would use that. It seems to be using that for the bind() in the listen socket but not for the outgoing connections.

I've tried settings externalip. That only seems to change the "localaddresses" returned by getnetworkinfo. I'm guessing that's mostly useful for NAT.

@laanwj
Copy link
Member

laanwj commented Jul 27, 2015

Right, there is no option to specify binding for outgoing connections.
I'd be OK with a per-network (IPv4/IPv6) setting that specifies this.
Be aware that enforcing this at application level is, in practice, impossible to make watertight - e.g. impossible for DNS lookups. So if this is for security or privacy reasons I'd strongly recommend to do this at the OS level (eg by giving a certain user only access to certain network interface).

@kroeckx
Copy link
Author

kroeckx commented Jul 31, 2015

I don't care about things like DNS, I would just like the bitcoin traffic itself to go over the addresses I select.

@sipa
Copy link
Member

sipa commented Jul 31, 2015 via email

@phatkiller
Copy link

Has this been implemented ? If not is there a timeframe for it ?

@jonasschnelli
Copy link
Contributor

@phatkiller: The issue is still open that's a sign that nobody has implemented it right now. We don't have a timeframe for features. Bitcoin-Core is an open source project, it will only be implemented if someone invests time to implement a such feature (which mostly is a sign that someone requires that feature).

@laanwj
Copy link
Member

laanwj commented May 4, 2016

If you need this, you need to make sure it gets implemented yourself. This is not a place to get free (as in beer) development resources.

@mrobinton
Copy link

What is required is to bind the socket to the -bind address prior to connecting to the remote site, not the usual way this would be done. I've looked at the code in net.cpp and netbase.cpp and boost appears to be in use and the location of the -bind ip constant is not obvious to me. I'm not skilled with c++. Here's a rough outline of what needs to be done but I don't have the skill to do it in the cpp environment. Perhaps someone else will pick up this thread.

Found this doing research on the issue.
No error checking.

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
// Bind to a specific network interface (and optionally a specific local port)
struct sockaddr_in localaddr;
localaddr.sin_family = AF_INET;
localaddr.sin_addr.s_addr = inet_addr("192.168.1.100");
localaddr.sin_port = 0; // Any local port will do
bind(sockfd, (struct sockaddr *)&localaddr, sizeof(localaddr));

@ryanofsky
Copy link
Contributor

This seems like an unusual request. Do you need bitcoin to use different outgoing IP address than other applications on the system? Or to connect from a different IP address than it it listens on? If not, it seems like you could be better off just fixing the routing table: https://serverfault.com/questions/182550/specifing-ip-address-for-outbound-connections-on-a-multi-ip-host

@infernix
Copy link

infernix commented Oct 4, 2019

This can't be fixed through a routing table because it's not about return packets for incoming connections but for packets that are for connections initiated by the process itself, which if not bindable to a specific IP (as per this request) will just use the hosts' default IP (which may not be the IP where incoming packets arrive). So not that unusual of a request, I had to dockerize and apply some iptables magic to make this work right on a node with multiple IPs within the same subnet.

@Nyanraltotlapun
Copy link

This seems like an unusual request. Do you need bitcoin to use different outgoing IP address than other applications on the system?

I feel that this is needed for avoiding mess up with IPv6 privacy randomized addresses.

@vasild
Copy link
Contributor

vasild commented Aug 5, 2023

This request looks reasonable. Is there still interest in it?

Something like this should do it (and pass the proper argument to ConnectSocketDirectly() untested):

-bool ConnectSocketDirectly(const CService &addrConnect, const Sock& sock, int nTimeout, bool manual_connection)
+bool ConnectSocketDirectly(const std::optional<CNetAddr>& addr_from, const CService &addrConnect, const Sock& sock, int nTimeout, bool manual_connection)
 {
     // Create a sockaddr from the specified service.
     struct sockaddr_storage sockaddr;
     socklen_t len = sizeof(sockaddr);
     if (sock.Get() == INVALID_SOCKET) {
         LogPrintf("Cannot connect to %s: invalid socket\n", addrConnect.ToStringAddrPort());
         return false;
     }
     if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
         LogPrintf("Cannot connect to %s: unsupported network\n", addrConnect.ToStringAddrPort());
         return false;
     }
 
+    if (addr_from.has_value()) {
+        struct sockaddr_storage storage;
+        struct sockaddr* saddr_from = reinterpret_cast<struct sockaddr*>(&storage);
+        socklen_t saddr_from_len = sizeof(storage);
+        if (!CService{addr_from.value(), /*port=*/0}.GetSockAddr(saddr_from, &saddr_from_len)) {
+            LogPrintLevel(
+                BCLog::NET,
+                BCLog::Level::Error,
+                "Cannot connect to %s: unsupported network of the specified outbound address %s\n",
+                addrConnect.ToStringAddrPort(),
+                addr_from->ToStringAddr());
+            return false;
+        }
+        if (sock.Bind(saddr_from, saddr_from_len) == SOCKET_ERROR) {
+            LogPrintLevel(
+                BCLog::NET,
+                BCLog::Level::Error,
+                "Cannot connect to %s: unable to bind to the specified outbound address %s: %s\n",
+                addrConnect.ToStringAddrPort(),
+                addr_from->ToStringAddr(),
+                NetworkErrorString(WSAGetLastError()));
+            return false;
+        }
+    }
+
     // Connect to the addrConnect service on the hSocket socket.
     if (sock.Connect(reinterpret_cast<struct sockaddr*>(&sockaddr), len) == SOCKET_ERROR) {

@Nyanraltotlapun
Copy link

Well, I still interested in it. It is a logical thing to do in general.
I think people uses some workarounds for this when they need this, but have native behavior is right thing to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

11 participants