bind("tcp://*:6001") meaning in python - python

I came across a zeromq example code
subscriber = ctx.socket(zmq.XSUB)
subscriber.connect("tcp://localhost:6000")
publisher = ctx.socket(zmq.XPUB)
publisher.bind("tcp://*:6001")
The subscriber (client) is connecting to local host port 6000. But the publisher (the server) is binding to *:6001
What does this mean?

It means "all interfaces, port 6001" - a given computer can have more than one network interface (a trivial example would be that the average computer's LAN IP and it's localhost address are two different interfaces. The * means to accept connections from any of them.

What does it mean to .bind() at port 6000 while .connect() aims at port 6001?
Simply put, these two peers will not meet at this attempt to setup a link to communicate.
While wildcard does work for all <localhost> interfaces, it does not for port#-s.
A .bind() side can open it's receiving policy to accept a connection from any interface "behind" the * wild card, but the port#-s must match.
No exceptions, no excuse.

Related

why socket binding in server needs its ip address >

For a connection is to be made, a bounded socket should be listening for clients. Client needs to know both ip address and port. For bounding a socket why we need an ip address of the server itself when the program(which listens for clients) itself is running on the server?
Simply because a server has multiple addresses, at least the loopback one at 127.0.0.1 (IP v4) and one per physical network interfaces. For example a corporate proxy has commonly two interfaces, one on the internal network and one on the public one. Most have a third one for the DMZ. Being member of different networks, those interfaces must have different addresses. And it make sense to open some services on only one interface.
But you also can use the ANY address (0.0.0.0 in IPv4) that means to accept connections on any interface.

What is the purpose and result of using INADDR_ANY?

In Python when we want to make a script that listens for multicast traffic we set the IP_ADD_MEMBERSHIP option of the socket with a value that consists of the multicast group address and the address of a local interface on which it will listen for the group's traffic.
Many examples on the Internet pass to IP_ADD_MEMBERSHIP the INADDR_ANY wildcard address as the local interface, and some of them state that this will make the socket to listen on all interfaces for multicast packets. However the Linux ip(7) man page states that when using INADDR_ANY
"an appropriate interface is chosen by the system"
and the freebsd man page says that it will choose the "default interface".
So either some answers online are wrong, or there's something that I'm missing here. I believe there's a confusion with INADDR_ANY when used as a parameter in IP_ADD_MEMBERSHIP, and INADDR_ANY when used as a parameter in bind() (represented by an empty string) but I'm not really sure. Can someone please clarify what is happening with INADDR_ANY or 0.0.0.0 when used in IP_ADD_MEMBERSHIP (i.e. it chooses the default interface or all interfaces) and if it behaves differently when used with bind?
When INADDR_ANY is given as the address in a bind call, this causes the socket to listen on the given port for any network interface.
After calling bind in this way, you'll see an entry like this in the output of the netstat command:
udp 0 0 0.0.0.0:46162 0.0.0.0:*
This is a UDP socket that was bound to INADDR_ANY with port 46162.
When used as the interface address when setting the IP_ADD_MEMBERSHIP option, INADDR_ANY indicates that the OS will chose an interface to join the given multicast group on, i.e. the "default" network interface.
It does not mean that it will join the group on all interfaces. To do that, you would need to itereate over all network interfaces and set the IP_ADD_MEMBERSHIP option on each one.
I've worked with Linux, Solaris, FreeBSD, and Windows, and none of them joins a multicast group on all interfaces when using INADDR_ANY.

How to send a message in a specific port with python sockets ? No random ports

I have to test a broadcast with acknowledgement on localhost. So I have some text files that represent the nodes and inside there is a list of neighbors.
I use localhost as the IP and the port is the number of the node.
The problem is when I receive a message (that I sent) from a node like 7000, python replaces it with a random number for example 65724. So now my father is 65724 instead of 7000, so I cannot remove 7000 from the list of neighbors.
I cannot complete my algorithm and that is very frustrating.
I can send a message with the port number that I want, but it's not very elegant.
Could someone tell me how to not allow python to randomize the port?
rmunn saved me, the answer I was looking far is the bind before connect method. Befor sending a message you bind your own port and you connect to the other one.
This is not a Python problem, per se. You are confused about how ports work.
Each TCP communication (sending or receiving) has two IP addresses and two ports: the host IP and host port, and the destination IP and destination port.
If you're communicating with a computer "out there" on the network, your host and destination IPs will be different. In your test case, your host and destination IPs will both be 127.0.0.1 (localhost). But I'm going to go with the "different IPs" case for my example, because it makes it easier to see.
So your IP address is, say 10.1.2.3, and you're talking to a computer at 10.1.2.99. You tell the system that you want to talk to 10.1.2.99 at port 7000, and it opens up a connection. When that happens, it will randomly pick a source port that's not in use. So now there's a two-way communication channel open:
10.1.2.3:65274 <-> 10.1.2.99:7000
Note that you did not pick that host port. EDIT: I originally said "In fact, the system will not allow you to pick the host port; it will be assigned to you" here, but that is wrong. If s is a socket object, you can call s.bind() to set its source port, then call s.connect() to connect to a destination port.
Now, when you're listening for a message, then you pick the port you're listening on, and the computer that's connecting to you will have a random port. So if you were listening for a message on port 8912, the incoming connection (once established) will look like:
10.1.2.3:8912 <-> 10.1.2.99:38290
Note that 38290 was chosen at random by the operating system of the computer at the 10.1.2.99 IP address.
Now for the bit of Python. You mention sockets in your question title, so I'll assume you're using the socket module from Python's standard library. Once you've created a socket object s, use s.getpeername() to find out the address (host and port) that you've connected to, and s.getsockname() to find out the address (host and port) that you've connected from.
Since you talk about expecting the number 7000 and getting a random number, I think you're using the host socket when you should be using the destination socket.

Python - Twisted - Simple UDP forwarder. Preserve source IP?

I have this basic UDP forward script in Python 3.
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
class Forward(DatagramProtocol):
def __init__(self, targetTuples):
print ('in init, targetTuples are ', targetTuples)
self._targetTuples = targetTuples
def datagramReceived(self, data, hostAndPort):
print ('self._targetTuples is ', self._targetTuples)
for (targetHost, targetPort) in self._targetTuples:
self.transport.write(data, (targetHost, targetPort))
reactor.listenUDP(5005, Forward([('10.35.203.24', 5000), ('10.35.200.251', 5005)]))
reactor.run()
So I'm listening on port 5005 UDP, and forwarding those packets to the two IP addresses and different ports.
My question is this -
How do I preserve the original IP address that twisted gets while listening on port 5005?
Source IP (10.1.1.1) --> Twisted (10.30.1.1) --> Multiple Destinations
How can I get Multiple Destinations to see the packet source preserved from the Source IP of (10.1.1.1) ?
When sending UDP datagrams using the BSD socket API (around which, as a first approximation, Twisted is a wrapper), the source address is set to the address the socket is bound to. You can specify the IP of the bind address for a UDP socket in Twisted by passing a value for the interface argument to reactor.listenTCP. However, you are typically restricted in what addresses you are allowed to bind to. Typically the only values allowed are addresses which are assigned to a local network interface. If you are forwarding traffic for 10.1.1.1 but you are on host 10.30.1.1 then you probably cannot set the source address of the UDP packets you send to 10.1.1.1 because that address isn't assigned to a network interface on the host doing the forwarding. If you assigned it to one, routing on your network would probably break in weird ways because then two different hosts would have the same IP address.
This doesn't mean it's not possible to do what you want - but it does mean you probably cannot do it using Twisted's basic UDP support. There are a number of other approaches you could take. For example, you can rewrite source addresses using iptables on Linux. Or you can operate on the IP level and parse and generate full UDP datagrams yourself letting you specify any source address you want (you can do this with Twisted on Linux, too, using twisted.pair.tuntap). There are probably a number of other ways. The best solution for you may depend on which platforms you're targeting and the particular reasons you want to do this kind of forwarding.

Capture destination IP in TCP Python SocketServer

I have a Python script that is running on a Linux server that has a dozen IP addresses associated with it. I implemented a TCPSServer from Python's socketserver library and had it listen on all network interfaces.
Several devices will be connecting to this server, and we need to be able to somehow capture the ip address of the destination (not the IP address of the client, but the IP address of the server that the client thinks it is connecting to). Right now, I can receive client connections, I can see the client IP, but I cannot figure out a method for obtaining the destination IP.
Does anyone know a method for capturing the destination IP on the socketserver class? It would seem if I can listen to multiple interfaces, there would be a way to tell which interface was hit.
This will be installed on several servers eventually, each with an unknown number of network interfaces. However, we do know that this will only exist on Linux bases systems. So if there was an OS specific way to do this, I would be fine with that as well.
If you have a socket object, you can use socket.getsockname() to obtain the IP address it's bound to. So something along the lines of:
# IPv4
client = listening_socket.accept()
(ipv4,port) = client.getsockname()
# IPv6
client = listening_socket.accept()
(address, port, flow_info, scope_id) = client.getsockname()
Never tested it on a multihomed server with a socket bound to all interfaces though - might return IPv4 0.0.0.0 or the IPv6 equivalent, for all I know, which wouldn't be all that useful.

Categories