8

My python test code:

import socket

s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('192.168.1.1', 80)) 
s1.listen(5)

s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.bind(('0.0.0.0', 80)) 
s2.listen(5)

I got this error:

fpemud-workstation test # ./test.py
Traceback (most recent call last):
  File "./test.py", line 11, in <module>
    s2.bind(('0.0.0.0', 80)) 
  File "/usr/lib64/python2.7/socket.py", line 224, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in use

192.168.1.1 is the ip address of my eth0 interface.
I think 0.0.0.0:80 and 192.168.1.1:80 should be able to co-exist.
Packets with dst-addr 192.168.1.1 goes to socket s1, packets with other dst-addr goes to socket s2.

Useless
  • 64,155
  • 6
  • 88
  • 132
fpemud
  • 363
  • 3
  • 10
  • because in the network you are running this, this pc ip is 192.168.1.1, that it same as 0.0.0.0 and 127.0.0.1, in fact, it doesn't matter about the ip address, the port number is issue –  Jun 25 '13 at 21:30
  • 1
    Notwithstanding the answer that was already posted, try binding the wildcard socket *first*, then bind the other one – Celada Jun 26 '13 at 02:09

3 Answers3

15

You cannot bind to both 0.0.0.0:80 and any other IP on port 80, because 0.0.0.0 covers every IP that exists on the machine, including your 192.168.1.1 address. It doesn't mean 'any other destination address', it means 'all interfaces on this box'.

Ben
  • 6,687
  • 2
  • 33
  • 46
  • You mean it's a spec. Why the OS (linux) use this spec? Does the co-existance of server-socket 0.0.0.0:80 and 192.168.0.1:80 raise any problem? – fpemud Jun 26 '13 at 01:52
  • I want to run 2 samba servers, server A is for inteface br0, server B is for all other interfaces (including interfaces dynamically created). Now I can't do it because of the limitation of this spec. – fpemud Jun 26 '13 at 01:57
  • 2
    @fpemud If `0.0.0.0` meant "all addresses unbound at this port`, that would be nondeterministic. If I say `0.0.0.0`, I expect *every* address this computer responds to to reach me at that port. What happens in your example if the `192.168.0.1` process goes down? Should the `0.0.0.0` process take over that binding? I'm not expecting that in code, and C code should never do something on its own like that. But if it doesn't, the binding to `0.0.0.0` is useless because it's not really every port, or every available port, it's every port that happened to be open at the time of that system call. – Kevin Jun 26 '13 at 02:33
  • 1
    @fpemud there's no way around it I'm afraid - that is how networking works. Any TCP stack that behaves differently is fundamentally broken, so you won't find any implementation that does what you want. Sorry! – Ben Jun 26 '13 at 06:40
  • @Ben It's quite possible to get this to work and I have done so on multiple operating systems. See [my answer](http://stackoverflow.com/a/17330779/2334192) for an explanation of how you can do this on Linux (3.9 or later). – James Holderness Jun 29 '13 at 19:37
  • @JamesHolderness I stand corrected! This link is quite interesting: https://lwn.net/Articles/542629/ – Ben Jun 29 '13 at 19:45
  • @Kevin I have just tested the scenario you described and `0.0.0.0` does actually mean all unbound addresses. If the `192.168.0.1` process goes down, the `0.0.0.0` process takes over the binding. If the `192.168.0.1` process is started up again, the `0.0.0.0` process loses that binding. For this to work on Linux, though, both processes must share the same uid. – James Holderness Jun 29 '13 at 20:24
1

Because it's a contradiction in terms. 0.0.0.0 means 'accept connections from any local IP address'. 192.168.1.1 means 'accept connections only that are addressed to 192.168.1.1'. What exactly do you expect to happen if someone connects to 192.168.1.1?

user207421
  • 305,947
  • 44
  • 307
  • 483
1

Despite what other answers have said, this should be possible - it's just that the way bind works is implementation dependent.

On Windows, for example, your code will probably work fine as is. On some *nix operating systems I believe you can get it to work by setting the SO_REUSEADDR socket option. On Linux, I've been able to get it to work using the SO_REUSEPORT socket option, but only on kernel version 3.9 or later.

Unfortunately the SO_REUSEPORT property isn't directly supported in current versions of python, so we have to define it manually.

Basically your code should look like this:

# This adds support for the SO_REUSEPORT constant if not already defined.
if not hasattr(socket, 'SO_REUSEPORT'):
  socket.SO_REUSEPORT = 15

s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s1.bind(('192.168.1.1', 80)) 
s1.listen(5)

s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s2.bind(('0.0.0.0', 80)) 
s2.listen(5)
James Holderness
  • 22,721
  • 2
  • 40
  • 52
  • SO_REUSEADDR is for TIME_WAIT only. The sequence switch has no effect. I also don't think Windows has a different behavior. – fpemud Jun 27 '13 at 12:21
  • Have a look at [this StackOverflow answer](http://stackoverflow.com/a/14388707/2334192) for more information on the different implementations of `SO_REUSEADDR`. I tested your original code on Windows (Windows Vista at least) so I know for a fact that that works. I have just now had a chance to test on Linux and I couldn't get it to work, but that may be version dependent. I don't have time to look into it more now, but will update later if I find out anything else. – James Holderness Jun 27 '13 at 14:34
  • @fpemud I've had a chance to do some more research, and have been able to get it to work using SO_REUSEPORT, but only on kernel version 3.9 or later. Updated code in my answer. – James Holderness Jun 29 '13 at 19:30