]> git.pld-linux.org Git - packages/exim.git/blob - exim-ipv6.patch
710e0cf5bde75677b6f1c9e378da1e603538d39f
[packages/exim.git] / exim-ipv6.patch
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
6      }\r
7  \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
19 +\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
23 +\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
27 +\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
30 +\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
33 +    above.\r
34 +\r
35 +  . I heard a report that the USAGI IPv6 stack for Linux has implemented\r
36 +    IPV6_V6ONLY.\r
37 +\r
38 +  So, what we do is as follows:\r
39 +\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
42 +   address.\r
43 +\r
44 +   (2) Later, when we create the IPv6 socket, we set IPV6_V6ONLY if that option\r
45 +   is defined.\r
46 +\r
47 +   (3) We listen on the v6 socket first. If that fails, there is a serious\r
48 +   error.\r
49 +\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
53  \r
54    else\r
55      {\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
60  \r
61      #if HAVE_IPV6\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
71 +\r
72 +    #else\r
73 +    addresses->next = NULL;\r
74 +    addresses->address[0] = 0;\r
75 +    listen_socket_count = 1;\r
76      #endif  /* HAVE_IPV6 */\r
77      }\r
78  \r
79 @@ -726,10 +762,12 @@\r
80    #endif\r
81  \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
86 -  IPv6 world. */\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
93  \r
94    for (ipa = addresses, sk = 0; sk < listen_socket_count; ipa = ipa->next, sk++)\r
95      {\r
96 @@ -738,8 +776,37 @@\r
97  \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
102 +      {\r
103 +      /* Just log failure for an IPv6 wildcard socket */\r
104 +\r
105 +      if (af == AF_INET6 && local_interfaces == NULL)\r
106 +        {\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
109 +\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
114 +        }\r
115 +\r
116 +      /* Not a failure to create an IPv6 socket for wildcard listening */\r
117 +\r
118 +      else\r
119 +        log_write(0, LOG_PANIC_DIE, "IPv%c socket creation failed: %s",\r
120 +          (af == AF_INET6)? '6' : '4', strerror(errno));\r
121 +      }\r
122 +\r
123 +    /* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is\r
124 +    available. */\r
125 +\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
129 +          sizeof(on)) < 0)\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
133  \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
137      }\r
138  \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
145  \r
146    for (sk = 0; sk < listen_socket_count; sk++)\r
147 -    listen(listen_sockets[sk], smtp_connect_backlog);\r
148 +    {\r
149 +    if (listen(listen_sockets[sk], smtp_connect_backlog) < 0)\r
150 +      {\r
151 +      if (errno == EADDRINUSE && local_interfaces == NULL && sk > 0)\r
152 +        {\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
158 +        }\r
159 +      else\r
160 +        {\r
161 +        int skf;\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
166 +          ipa->address,\r
167 +          strerror(errno));\r
168 +        }\r
169 +      }\r
170 +    }\r
171    }\r
172  \r
173  /* Set up the handler for SIGHUP, which causes a restart of the daemon. */\r
This page took 0.643346 seconds and 2 git commands to generate.