Skip to content

Instantly share code, notes, and snippets.

@SpComb
Last active March 12, 2018 14:20
Show Gist options
  • Save SpComb/c509bd064bc75151e6b41e8bc949d13f to your computer and use it in GitHub Desktop.
Save SpComb/c509bd064bc75151e6b41e8bc949d13f to your computer and use it in GitHub Desktop.
RFC 3484 Section 6 Rule 9 is broken for "round-robin" DNS in container networks

The behavior of getaddrinfo result sorting is inconsistent for the case of multiple randomly allocated server addresses within the client's source address subnet: it depends on the exact layout of the bits in the client source address vs the server addresses. For some randomly allocated set of server addresses the client may randomly connect to each address, and for other randomly allocated sets of server addresses the client may always connect to the same address.

Assuming that IP subnets are flat with randomly allocated addresses, it does not make any sense to assign any kind of topological significance in terms of preference-sorting by comparing addresses within the same subnet.

Related Issues

Broken specs

$ ip -4 addr show ethwe
107: ethwe@if108: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1376 qdisc noqueue state UP group default  link-netnsid 0
    inet 10.81.128.91/16 scope global ethwe
       valid_lft forever preferred_lft forever
$ getent hosts whoami.whoami.demo-3.kontena.local
10.81.128.30    whoami.whoami.demo-3.kontena.local
10.81.128.41    whoami.whoami.demo-3.kontena.local
10.81.128.14    whoami.whoami.demo-3.kontena.local
# Address:   10.81.128.91         00001010.01010001. 10000000.01011011
# Address:   10.81.128.41         00001010.01010001. 10000000.00101001
# Address:   10.81.128.14         00001010.01010001. 10000000.00001110
# Address:   10.81.128.30         00001010.01010001. 10000000.00011110

The common prefix length it the same for each of the addresses is the same (25 bits), so all of the results are returned in the original randomized order.

>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.30
10.81.128.14
10.81.128.41
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.41
10.81.128.14
10.81.128.30
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.14
10.81.128.30
10.81.128.41
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.14
10.81.128.30
10.81.128.41
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.41
10.81.128.14
10.81.128.30
$ ip -4 addr show ethwe
107: ethwe@if108: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1376 qdisc noqueue state UP group default  link-netnsid 0
    inet 10.81.128.91/16 scope global ethwe
       valid_lft forever preferred_lft forever
$ getent hosts whoami.whoami.demo-3.kontena.local
10.81.128.103   whoami.whoami.demo-3.kontena.local
10.81.128.22    whoami.whoami.demo-3.kontena.local
10.81.128.76    whoami.whoami.demo-3.kontena.local
# Address:   10.81.128.91         00001010.01010001. 10000000.01011011
# Address:   10.81.128.76         00001010.01010001. 10000000.01001100
# Address:   10.81.128.103        00001010.01010001. 10000000.01100111
# Address:   10.81.128.22         00001010.01010001. 10000000.00010110

The common prefix length is different for each of the addresses, so the results are always returned in the same order.

>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
>>> for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo('whoami.whoami.demo-3.kontena.local', 8000, socket.AF_INET, socket.SOCK_STREAM): print(sockaddr[0])
... 
10.81.128.76
10.81.128.103
10.81.128.22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment