1 diff -urN exim-3.32.org/src/daemon.c exim-3.32/src/daemon.c
\r
2 --- exim-3.32.org/src/daemon.c Mon Aug 13 20:01:02 2001
\r
3 +++ exim-3.32/src/daemon.c Mon Aug 13 20:01:27 2001
\r
4 @@ -689,26 +689,62 @@
\r
5 listen_socket_count++;
\r
8 - /* Otherwise set up one address item with a null address, implying listening
\r
9 - on all interfaces. In an IPv6 world, we set up a second address for listening
\r
10 - on all IPv6 interfaces. Some IPv6 stacks will pick up incoming IPv4 calls on
\r
11 - an IPv6 wildcard socket, but some won't (there are security issues). Using
\r
12 - two sockets should work in all cases. We identify an IPv6 wildcard address by
\r
13 - the string ":". */
\r
14 + /* Otherwise we set up things to listen on all interfaces. In an IPv4 world,
\r
15 + this is just a single, empty address. On systems with IPv6, several different
\r
16 + implementation approaches have been taken. This code is now supposed to work
\r
17 + with all of them. The point of difference is whether an IPv6 socket that is
\r
18 + listening on all interfaces will receive incoming IPv4 calls or not.
\r
20 + . On Solaris, an IPv6 socket will accept IPv4 calls, and give them as mapped
\r
21 + addresses. However, if an IPv4 socket is also listening on all interfaces,
\r
22 + calls are directed to the appropriate socket.
\r
24 + . On (some versions of) Linux, an IPv6 socket will accept IPv4 calls, and
\r
25 + give them as mapped addresses, but an attempt also to listen on an IPv4
\r
26 + socket on all interfaces causes an error.
\r
28 + . On OpenBSD, an IPv6 socket will not accept IPv4 calls. You have to set up
\r
29 + two sockets if you want to accept both kinds of call.
\r
31 + . FreeBSD is like OpenBSD, but it has the IPV6_V6ONLY socket option, which
\r
32 + can be turned off, to make it behave like the versions of Linux described
\r
35 + . I heard a report that the USAGI IPv6 stack for Linux has implemented
\r
38 + So, what we do is as follows:
\r
40 + (1) At this point we set up two addresses, one containing ":" to indicate
\r
41 + an IPv6 wildcard address, and an empty one to indicate an IPv4 wildcard
\r
44 + (2) Later, when we create the IPv6 socket, we set IPV6_V6ONLY if that option
\r
47 + (3) We listen on the v6 socket first. If that fails, there is a serious
\r
50 + (4) We listen on the v4 socket second. If that fails with the error
\r
51 + EADDRINUSE, assume we are in the situation where just a single socket is
\r
52 + permitted, and ignore the error. */
\r
56 addresses = store_get(sizeof(ip_address_item));
\r
57 - addresses->next = NULL;
\r
58 - addresses->address[0] = 0;
\r
59 - listen_socket_count = 1;
\r
62 addresses->next = store_get(sizeof(ip_address_item));
\r
63 + addresses->address[0] = ':';
\r
64 + addresses->address[1] = 0;
\r
65 addresses->next->next = NULL;
\r
66 - addresses->next->address[0] = ':';
\r
67 - addresses->next->address[1] = 0;
\r
68 - listen_socket_count++;
\r
69 + addresses->next->address[0] = 0;
\r
70 + listen_socket_count = 2;
\r
73 + addresses->next = NULL;
\r
74 + addresses->address[0] = 0;
\r
75 + listen_socket_count = 1;
\r
76 #endif /* HAVE_IPV6 */
\r
79 @@ -726,10 +762,12 @@
\r
82 /* For each IP address, create a socket and bind it to the appropriate
\r
83 - port. Some IPv6 stacks can handle IPv4 addresses on IPv6 sockets using
\r
84 - the mapping facilities. However, some don't do this because of security
\r
85 - concerns. Therefore, we use IPv4 sockets for IPv4 addresses even in an
\r
87 + port. See comments above about IPv6 sockets that may or may not accept IPv4
\r
88 + calls when listening on all interfaces. We also have to cope with the case of
\r
89 + a system with IPv6 libraries, but no IPv6 support in the kernel. In this
\r
90 + case, we must ignore failure to create an IPv6 socket for wildcard listening.
\r
91 + The second socket (IPv4) should then get used instead - we have to shuffle
\r
92 + it down into first place. */
\r
94 for (ipa = addresses, sk = 0; sk < listen_socket_count; ipa = ipa->next, sk++)
\r
96 @@ -738,8 +776,37 @@
\r
98 listen_sockets[sk] = socket(af, SOCK_STREAM, 0);
\r
99 if (listen_sockets[sk] < 0)
\r
100 - log_write(0, LOG_PANIC_DIE, "IPv%c socket creation failed: %s",
\r
101 - (af == AF_INET6)? '6' : '4', strerror(errno));
\r
103 + /* Just log failure for an IPv6 wildcard socket */
\r
105 + if (af == AF_INET6 && local_interfaces == NULL)
\r
107 + log_write(0, LOG_MAIN, "Failed to create IPv6 socket for wildcard "
\r
108 + "listening (%s): falling back to IPv4", strerror(errno));
\r
110 + addresses = addresses->next; /* Chop IPv6 off the list */
\r
111 + sk--; /* Back up the count */
\r
112 + listen_socket_count--; /* Reduce the total */
\r
113 + continue; /* With the IPv4 socket */
\r
116 + /* Not a failure to create an IPv6 socket for wildcard listening */
\r
119 + log_write(0, LOG_PANIC_DIE, "IPv%c socket creation failed: %s",
\r
120 + (af == AF_INET6)? '6' : '4', strerror(errno));
\r
123 + /* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is
\r
126 + #ifdef IPV6_V6ONLY
\r
127 + if (local_interfaces == NULL && af == AF_INET6 &&
\r
128 + setsockopt(listen_sockets[sk], SOL_SOCKET, IPV6_V6ONLY, (char *)(&on),
\r
130 + log_write(0, LOG_PANIC_DIE, "setting IPV6_V6ONLY on socket failed: %s",
\r
131 + strerror(errno));
\r
132 + #endif /* IPV6_V6ONLY */
\r
134 /* Set SO_REUSEADDR so that the daemon can be restarted while a connection
\r
135 is being handled. Without this, a connection will prevent reuse of the
\r
136 @@ -853,10 +920,35 @@
\r
139 /* Start listening on the bound sockets, establishing the maximum backlog of
\r
140 - connections that is allowed. */
\r
141 + connections that is allowed. In an IPv6 environment, if listen() fails with
\r
142 + the error EADDRINUSE and we are doing wildcard listening and this is the
\r
143 + second (i.e last) socket, ignore the error on the grounds that we must be
\r
144 + in a system where the IPv6 socket accepts both kinds of call. */
\r
146 for (sk = 0; sk < listen_socket_count; sk++)
\r
147 - listen(listen_sockets[sk], smtp_connect_backlog);
\r
149 + if (listen(listen_sockets[sk], smtp_connect_backlog) < 0)
\r
151 + if (errno == EADDRINUSE && local_interfaces == NULL && sk > 0)
\r
153 + DEBUG(9) debug_printf("wildcard IPv4 listen() failed after IPv6 "
\r
154 + "listen() success; EADDRINUSE ignored\n");
\r
155 + close(listen_sockets[sk]);
\r
156 + listen_socket_count--; /* OK because we know we are in the */
\r
157 + break; /* last iteration of this loop */
\r
162 + for (ipa = addresses, skf = 0; skf < sk; ipa = ipa->next, skf++);
\r
163 + log_write(0, LOG_PANIC_DIE, "listen() failed on interface %s: %s",
\r
164 + (ipa->address[0] == 0)? "(any IPv4)" :
\r
165 + (ipa->address[0] == ':' && ipa->address[1] == ':')? "(any IPv6)" :
\r
167 + strerror(errno));
\r
173 /* Set up the handler for SIGHUP, which causes a restart of the daemon. */
\r