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

On linux if this is not the first connect() call for a udp socket, connect(AF_UNSPEC) first #20

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

daurnimator
Copy link

@daurnimator daurnimator commented Mar 9, 2017

Related to #19

@daurnimator
Copy link
Author

Actually this might not be the total fix. The 'resolve' interface doesn't move on in the case of the ECONNREFUSED:

$ cat /etc/resolv.conf
nameserver 127.0.0.2
nameserver 8.8.8.8
$ strace ./dns resolve-stub google.com
execve("./dns", ["./dns", "resolve-stub", "google.com"], [/* 56 vars */]) = 0
brk(NULL)                               = 0x10ce000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=215350, ...}) = 0
mmap(NULL, 215350, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f62fb0e5000
close(3)                                = 0
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\3\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1951744, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f62fb0e3000
mmap(NULL, 3791152, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f62fab5a000
mprotect(0x7f62facef000, 2093056, PROT_NONE) = 0
mmap(0x7f62faeee000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x194000) = 0x7f62faeee000
mmap(0x7f62faef4000, 14640, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f62faef4000
close(3)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f62fb0e4480) = 0
mprotect(0x7f62faeee000, 16384, PROT_READ) = 0
mprotect(0x61b000, 4096, PROT_READ)     = 0
mprotect(0x7f62fb11a000, 4096, PROT_READ) = 0
munmap(0x7f62fb0e5000, 215350)          = 0
brk(NULL)                               = 0x10ce000
brk(0x10ef000)                          = 0x10ef000
uname({sysname="Linux", nodename="daurn-m73", ...}) = 0
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=40, ...}) = 0
lseek(3, 0, SEEK_SET)                   = 0
read(3, "nameserver 127.0.0.2\nnameserver "..., 4096) = 40
read(3, "", 4096)                       = 0
close(3)                                = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=312, ...}) = 0
read(3, "# Begin /etc/nsswitch.conf\n\npass"..., 4096) = 312
read(3, "", 4096)                       = 0
read(3, "", 4096)                       = 0
read(3, "", 4096)                       = 0
close(3)                                = 0
open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=195, ...}) = 0
lseek(3, 0, SEEK_SET)                   = 0
read(3, "#\n# /etc/hosts: static lookup ta"..., 4096) = 195
read(3, "", 4096)                       = 0
close(3)                                = 0
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(10218), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.2")}, 16) = 0
sendto(3, "\317/\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\1\0\1", 32, 0, NULL, 0) = 32
recvfrom(3, 0x10d08ec, 768, 0, NULL, NULL) = -1 ECONNREFUSED (Connection refused)
write(2, "dns: ", 5dns: )                    = 5
write(2, "(resolve_query:9532) dns_res_che"..., 60(resolve_query:9532) dns_res_check: Connection refused (111)) = 60
write(2, "\n", 1
)                       = 1
exit_group(1)                           = ?
+++ exited with 1 +++

@daurnimator
Copy link
Author

With that change the behaviour becomes the IMO more sensible:

$ strace ./dns resolve-stub google.com
execve("./dns", ["./dns", "resolve-stub", "google.com"], [/* 56 vars */]) = 0
brk(NULL)                               = 0x2422000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=215350, ...}) = 0
mmap(NULL, 215350, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7fc4c22bb000
close(4)                                = 0
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 4
read(4, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\3\2\0\0\0\0\0"..., 832) = 832
fstat(4, {st_mode=S_IFREG|0755, st_size=1951744, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fc4c22b9000
mmap(NULL, 3791152, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7fc4c1d30000
mprotect(0x7fc4c1ec5000, 2093056, PROT_NONE) = 0
mmap(0x7fc4c20c4000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x194000) = 0x7fc4c20c4000
mmap(0x7fc4c20ca000, 14640, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fc4c20ca000
close(4)                                = 0
arch_prctl(ARCH_SET_FS, 0x7fc4c22ba480) = 0
mprotect(0x7fc4c20c4000, 16384, PROT_READ) = 0
mprotect(0x61b000, 4096, PROT_READ)     = 0
mprotect(0x7fc4c22f0000, 4096, PROT_READ) = 0
munmap(0x7fc4c22bb000, 215350)          = 0
brk(NULL)                               = 0x2422000
brk(0x2443000)                          = 0x2443000
uname({sysname="Linux", nodename="daurn-m73", ...}) = 0
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=40, ...}) = 0
lseek(4, 0, SEEK_SET)                   = 0
read(4, "nameserver 127.0.0.2\nnameserver "..., 4096) = 40
read(4, "", 4096)                       = 0
close(4)                                = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=312, ...}) = 0
read(4, "# Begin /etc/nsswitch.conf\n\npass"..., 4096) = 312
read(4, "", 4096)                       = 0
read(4, "", 4096)                       = 0
read(4, "", 4096)                       = 0
close(4)                                = 0
open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=195, ...}) = 0
lseek(4, 0, SEEK_SET)                   = 0
read(4, "#\n# /etc/hosts: static lookup ta"..., 4096) = 195
read(4, "", 4096)                       = 0
close(4)                                = 0
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 4
bind(4, {sa_family=AF_INET, sin_port=htons(10218), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.2")}, 16) = 0
sendto(4, "\317/\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\1\0\1", 32, 0, NULL, 0) = 32
recvfrom(4, 0x24248ec, 768, 0, NULL, NULL) = -1 ECONNREFUSED (Connection refused)
connect(4, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(4, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.2")}, 16) = 0
sendto(4, "\317/\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\1\0\1", 32, 0, NULL, 0) = 32
recvfrom(4, 0x24248ec, 768, 0, NULL, NULL) = -1 ECONNREFUSED (Connection refused)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 8), ...}) = 0
write(1, ";; [HEADER]\n", 12;; [HEADER]
)           = 12
write(1, ";;    qid : 0\n", 14;;    qid : 0
)         = 14
write(1, ";;     qr : RESPONSE(1)\n", 24;;     qr : RESPONSE(1)
) = 24
write(1, ";; opcode : QUERY(0)\n", 21;; opcode : QUERY(0)
)  = 21
write(1, ";;     aa : NON-AUTHORITATIVE(0)"..., 33;;     aa : NON-AUTHORITATIVE(0)
) = 33
write(1, ";;     tc : NOT-TRUNCATED(0)\n", 29;;     tc : NOT-TRUNCATED(0)
) = 29
write(1, ";;     rd : RECURSION-NOT-DESIRE"..., 37;;     rd : RECURSION-NOT-DESIRED(0)
) = 37
write(1, ";;     ra : RECURSION-NOT-ALLOWE"..., 37;;     ra : RECURSION-NOT-ALLOWED(0)
) = 37
write(1, ";;  rcode : SERVFAIL(2)\n", 24;;  rcode : SERVFAIL(2)
) = 24
write(1, "\n", 1
)                       = 1
write(1, ";; [QUESTION:1]\n", 16;; [QUESTION:1]
)       = 16
write(1, ";www.google.com. IN A\n", 22;www.google.com. IN A
) = 22
write(1, "\n", 1
)                       = 1
write(1, ";; queries:  2\n", 15;; queries:  2
)        = 15
write(1, ";; udp sent: 2 in 64 bytes\n", 27;; udp sent: 2 in 64 bytes
) = 27
write(1, ";; udp rcvd: 0 in 0 bytes\n", 26;; udp rcvd: 0 in 0 bytes
) = 26
write(1, ";; tcp sent: 0 in 0 bytes\n", 26;; tcp sent: 0 in 0 bytes
) = 26
write(1, ";; tcp rcvd: 0 in 0 bytes\n", 26;; tcp rcvd: 0 in 0 bytes
) = 26
close(4)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

@daurnimator
Copy link
Author

Eek, that wasn't the result I thought it was: the second time around recv() returns ECONNREFUSED as well.
This PR doesn't work.

@daurnimator daurnimator closed this Mar 9, 2017
@daurnimator daurnimator reopened this Mar 9, 2017
@daurnimator daurnimator closed this Mar 9, 2017
@daurnimator
Copy link
Author

Oops, I jumped to that conclusion too fast: my code didn't iterate the nameserver and hence it just tried the same one again. strace excerpt showing that AF_UNSPEC does work:

socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 5
connect(5, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.2")}, 16) = 0
sendto(5, "test", 4, 0, NULL, 0)        = 4
recvfrom(5, 0x7ffdf8fcaca0, 200, 0, NULL, NULL) = -1 ECONNREFUSED (Connection refused)
connect(5, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(5, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, 16) = 0
sendto(5, "test", 4, 0, NULL, 0)        = 4
recvfrom(5, 0x7ffdf8fcaca0, 200, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
exit_group(0)                           = ?

@daurnimator daurnimator reopened this Mar 9, 2017
@daurnimator
Copy link
Author

I've updated this PR with fixed code. strace output:

$ strace ./dns resolve-stub google.com
execve("./dns", ["./dns", "resolve-stub", "google.com"], [/* 56 vars */]) = 0
brk(NULL)                               = 0x2038000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 5
fstat(5, {st_mode=S_IFREG|0644, st_size=215350, ...}) = 0
mmap(NULL, 215350, PROT_READ, MAP_PRIVATE, 5, 0) = 0x7f66a2706000
close(5)                                = 0
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 5
read(5, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\3\2\0\0\0\0\0"..., 832) = 832
fstat(5, {st_mode=S_IFREG|0755, st_size=1951744, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f66a2704000
mmap(NULL, 3791152, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 5, 0) = 0x7f66a217b000
mprotect(0x7f66a2310000, 2093056, PROT_NONE) = 0
mmap(0x7f66a250f000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 5, 0x194000) = 0x7f66a250f000
mmap(0x7f66a2515000, 14640, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f66a2515000
close(5)                                = 0
arch_prctl(ARCH_SET_FS, 0x7f66a2705480) = 0
mprotect(0x7f66a250f000, 16384, PROT_READ) = 0
mprotect(0x61b000, 4096, PROT_READ)     = 0
mprotect(0x7f66a273b000, 4096, PROT_READ) = 0
munmap(0x7f66a2706000, 215350)          = 0
brk(NULL)                               = 0x2038000
brk(0x2059000)                          = 0x2059000
uname({sysname="Linux", nodename="daurn-m73", ...}) = 0
open("/etc/resolv.conf", O_RDONLY|O_CLOEXEC) = 5
fstat(5, {st_mode=S_IFREG|0644, st_size=40, ...}) = 0
lseek(5, 0, SEEK_SET)                   = 0
read(5, "nameserver 127.0.0.2\nnameserver "..., 4096) = 40
read(5, "", 4096)                       = 0
close(5)                                = 0
open("/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 5
fstat(5, {st_mode=S_IFREG|0644, st_size=312, ...}) = 0
read(5, "# Begin /etc/nsswitch.conf\n\npass"..., 4096) = 312
read(5, "", 4096)                       = 0
read(5, "", 4096)                       = 0
read(5, "", 4096)                       = 0
close(5)                                = 0
open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 5
fstat(5, {st_mode=S_IFREG|0644, st_size=195, ...}) = 0
lseek(5, 0, SEEK_SET)                   = 0
read(5, "#\n# /etc/hosts: static lookup ta"..., 4096) = 195
read(5, "", 4096)                       = 0
close(5)                                = 0
socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 5
bind(5, {sa_family=AF_INET, sin_port=htons(10218), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
connect(5, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("127.0.0.2")}, 16) = 0
sendto(5, "\317/\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\1\0\1", 32, 0, NULL, 0) = 32
recvfrom(5, 0x203a8ec, 768, 0, NULL, NULL) = -1 ECONNREFUSED (Connection refused)
connect(5, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, 16) = 0
connect(5, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, 16) = 0
sendto(5, "\317/\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\1\0\1", 32, 0, NULL, 0) = 32
recvfrom(5, 0x203a8ec, 768, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
select(6, [5], [], NULL, {tv_sec=1, tv_usec=0}) = 1 (in [5], left {tv_sec=0, tv_usec=987061})
recvfrom(5, "\317/\201\200\0\1\0\1\0\0\0\0\3www\6google\3com\0\0\1\0\1"..., 768, 0, NULL, NULL) = 48
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 8), ...}) = 0
write(1, ";; [HEADER]\n", 12;; [HEADER]
)           = 12
write(1, ";;    qid : 53039\n", 18;;    qid : 53039
)     = 18
write(1, ";;     qr : RESPONSE(1)\n", 24;;     qr : RESPONSE(1)
) = 24
write(1, ";; opcode : QUERY(0)\n", 21;; opcode : QUERY(0)
)  = 21
write(1, ";;     aa : NON-AUTHORITATIVE(0)"..., 33;;     aa : NON-AUTHORITATIVE(0)
) = 33
write(1, ";;     tc : NOT-TRUNCATED(0)\n", 29;;     tc : NOT-TRUNCATED(0)
) = 29
write(1, ";;     rd : RECURSION-DESIRED(1)"..., 33;;     rd : RECURSION-DESIRED(1)
) = 33
write(1, ";;     ra : RECURSION-ALLOWED(1)"..., 33;;     ra : RECURSION-ALLOWED(1)
) = 33
write(1, ";;  rcode : NOERROR(0)\n", 23;;  rcode : NOERROR(0)
) = 23
write(1, "\n", 1
)                       = 1
write(1, ";; [QUESTION:1]\n", 16;; [QUESTION:1]
)       = 16
write(1, ";www.google.com. IN A\n", 22;www.google.com. IN A
) = 22
write(1, "\n", 1
)                       = 1
write(1, ";; [ANSWER:1]\n", 14;; [ANSWER:1]
)         = 14
write(1, "www.google.com. 159 IN A 216.58."..., 40www.google.com. 159 IN A 216.58.200.100
) = 40
write(1, "\n", 1
)                       = 1
write(1, ";; queries:  2\n", 15;; queries:  2
)        = 15
write(1, ";; udp sent: 2 in 64 bytes\n", 27;; udp sent: 2 in 64 bytes
) = 27
write(1, ";; udp rcvd: 1 in 48 bytes\n", 27;; udp rcvd: 1 in 48 bytes
) = 27
write(1, ";; tcp sent: 0 in 0 bytes\n", 26;; tcp sent: 0 in 0 bytes
) = 26
write(1, ";; tcp rcvd: 0 in 0 bytes\n", 26;; tcp rcvd: 0 in 0 bytes
) = 26
close(5)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

@anr2me
Copy link

anr2me commented Aug 26, 2023

This fix matches the description at https://man7.org/linux/man-pages/man2/connect.2.html

Some protocol sockets (e.g., datagram sockets in the UNIX and
Internet domains) may use connect() multiple times to change
their association.

Some protocol sockets (e.g., TCP sockets as well as datagram
sockets in the UNIX and Internet domains) may dissolve the
association by connecting to an address with the sa_family member
of sockaddr set to AF_UNSPEC; thereafter, the socket can be
connected to another address. (AF_UNSPEC is supported since
Linux 2.2.)

By connecting using AF_UNSPEC will dissolve the association from previous connect (which probably lingers when there are no service running at remote side), thus allowing to connect to a different address just like a first time.

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

Successfully merging this pull request may close these issues.

3 participants