Commit | Line | Data |
---|---|---|
0a49a7a4 | 1 | /* $Cambridge: exim/src/src/ip.c,v 1.8 2009/11/16 19:50:37 nm4 Exp $ */ |
059ec3d9 PH |
2 | |
3 | /************************************************* | |
4 | * Exim - an Internet mail transport agent * | |
5 | *************************************************/ | |
6 | ||
0a49a7a4 | 7 | /* Copyright (c) University of Cambridge 1995 - 2009 */ |
059ec3d9 PH |
8 | /* See the file NOTICE for conditions of use and distribution. */ |
9 | ||
10 | /* Functions for doing things with sockets. With the advent of IPv6 this has | |
11 | got messier, so that it's worth pulling out the code into separate functions | |
12 | that other parts of Exim can call, expecially as there are now several | |
13 | different places in the code where sockets are used. */ | |
14 | ||
15 | ||
16 | #include "exim.h" | |
17 | ||
18 | ||
19 | /************************************************* | |
20 | * Create a socket * | |
21 | *************************************************/ | |
22 | ||
23 | /* Socket creation happens in a number of places so it's packaged here for | |
24 | convenience. | |
25 | ||
26 | Arguments: | |
27 | type SOCK_DGRAM or SOCK_STREAM | |
28 | af AF_INET or AF_INET6 | |
29 | ||
30 | Returns: socket number or -1 on failure | |
31 | */ | |
32 | ||
33 | int | |
34 | ip_socket(int type, int af) | |
35 | { | |
36 | int sock = socket(af, type, 0); | |
37 | if (sock < 0) | |
38 | log_write(0, LOG_MAIN, "IPv%c socket creation failed: %s", | |
39 | (af == AF_INET6)? '6':'4', strerror(errno)); | |
40 | return sock; | |
41 | } | |
42 | ||
43 | ||
44 | ||
45 | ||
46 | #if HAVE_IPV6 | |
47 | /************************************************* | |
48 | * Convert printing address to numeric * | |
49 | *************************************************/ | |
50 | ||
51 | /* This function converts the textual form of an IP address into a numeric form | |
52 | in an appropriate structure in an IPv6 environment. The getaddrinfo() function | |
53 | can (apparently) handle more complicated addresses (e.g. those containing | |
54 | scopes) than inet_pton() in some environments. We use hints to tell it that the | |
55 | input must be a numeric address. | |
56 | ||
57 | However, apparently some operating systems (or libraries) don't support | |
58 | getaddrinfo(), so there is a build-time option to revert to inet_pton() (which | |
59 | does not support scopes). | |
60 | ||
61 | Arguments: | |
62 | address textual form of the address | |
63 | addr where to copy back the answer | |
64 | ||
65 | Returns: nothing - failure provokes a panic-die | |
66 | */ | |
67 | ||
68 | static void | |
69 | ip_addrinfo(uschar *address, struct sockaddr_in6 *saddr) | |
70 | { | |
71 | #ifdef IPV6_USE_INET_PTON | |
72 | ||
73 | if (inet_pton(AF_INET6, CS address, &saddr->sin6_addr) != 1) | |
74 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "unable to parse \"%s\" as an " | |
75 | "IP address", address); | |
76 | saddr->sin6_family = AF_INET6; | |
77 | ||
78 | #else | |
79 | ||
80 | int rc; | |
81 | struct addrinfo hints, *res; | |
82 | memset(&hints, 0, sizeof(hints)); | |
83 | hints.ai_family = AF_INET6; | |
84 | hints.ai_socktype = SOCK_STREAM; | |
85 | hints.ai_flags = AI_NUMERICHOST; | |
86 | if ((rc = getaddrinfo(CS address, NULL, &hints, &res)) != 0 || res == NULL) | |
87 | log_write(0, LOG_MAIN|LOG_PANIC_DIE, "unable to parse \"%s\" as an " | |
88 | "IP address: %s", address, | |
89 | (rc == 0)? "NULL result returned" : gai_strerror(rc)); | |
90 | memcpy(saddr, res->ai_addr, res->ai_addrlen); | |
91 | freeaddrinfo(res); | |
92 | ||
93 | #endif | |
94 | } | |
95 | #endif /* HAVE_IPV6 */ | |
96 | ||
97 | ||
98 | /************************************************* | |
99 | * Bind socket to interface and port * | |
100 | *************************************************/ | |
101 | ||
102 | /* This function binds a socket to a local interface address and port. For a | |
103 | wildcard IPv6 bind, the address is ":". | |
104 | ||
105 | Arguments: | |
106 | sock the socket | |
107 | af AF_INET or AF_INET6 - the socket type | |
108 | address the IP address, in text form | |
109 | port the IP port (host order) | |
110 | ||
111 | Returns: the result of bind() | |
112 | */ | |
113 | ||
114 | int | |
115 | ip_bind(int sock, int af, uschar *address, int port) | |
116 | { | |
117 | int s_len; | |
118 | union sockaddr_46 sin; | |
119 | memset(&sin, 0, sizeof(sin)); | |
120 | ||
121 | /* Setup code when using an IPv6 socket. The wildcard address is ":", to | |
122 | ensure an IPv6 socket is used. */ | |
123 | ||
124 | #if HAVE_IPV6 | |
125 | if (af == AF_INET6) | |
126 | { | |
127 | if (address[0] == ':' && address[1] == 0) | |
128 | { | |
129 | sin.v6.sin6_family = AF_INET6; | |
130 | sin.v6.sin6_addr = in6addr_any; | |
131 | } | |
132 | else | |
133 | { | |
134 | ip_addrinfo(address, &sin.v6); /* Panic-dies on error */ | |
135 | } | |
136 | sin.v6.sin6_port = htons(port); | |
137 | s_len = sizeof(sin.v6); | |
138 | } | |
139 | else | |
140 | #else /* HAVE_IPv6 */ | |
141 | af = af; /* Avoid compiler warning */ | |
142 | #endif /* HAVE_IPV6 */ | |
143 | ||
144 | /* Setup code when using IPv4 socket. The wildcard address is "". */ | |
145 | ||
146 | { | |
147 | sin.v4.sin_family = AF_INET; | |
148 | sin.v4.sin_port = htons(port); | |
149 | s_len = sizeof(sin.v4); | |
150 | if (address[0] == 0) | |
151 | sin.v4.sin_addr.s_addr = (S_ADDR_TYPE)INADDR_ANY; | |
152 | else | |
153 | sin.v4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(CS address); | |
154 | } | |
155 | ||
156 | /* Now we can call the bind() function */ | |
157 | ||
158 | return bind(sock, (struct sockaddr *)&sin, s_len); | |
159 | } | |
160 | ||
161 | ||
162 | ||
163 | /************************************************* | |
164 | * Connect socket to remote host * | |
165 | *************************************************/ | |
166 | ||
167 | /* This function connects a socket to a remote address and port. The socket may | |
d515a917 PH |
168 | or may not have previously been bound to a local interface. The socket is not |
169 | closed, even in cases of error. It is expected that the calling function, which | |
170 | created the socket, will be the one that closes it. | |
059ec3d9 PH |
171 | |
172 | Arguments: | |
173 | sock the socket | |
174 | af AF_INET6 or AF_INET for the socket type | |
175 | address the remote address, in text form | |
176 | port the remote port | |
177 | timeout a timeout | |
178 | ||
179 | Returns: 0 on success; -1 on failure, with errno set | |
180 | */ | |
181 | ||
182 | int | |
183 | ip_connect(int sock, int af, uschar *address, int port, int timeout) | |
184 | { | |
185 | struct sockaddr_in s_in4; | |
186 | struct sockaddr *s_ptr; | |
187 | int s_len, rc, save_errno; | |
188 | ||
189 | /* For an IPv6 address, use an IPv6 sockaddr structure. */ | |
190 | ||
191 | #if HAVE_IPV6 | |
192 | struct sockaddr_in6 s_in6; | |
193 | if (af == AF_INET6) | |
194 | { | |
195 | memset(&s_in6, 0, sizeof(s_in6)); | |
196 | ip_addrinfo(address, &s_in6); /* Panic-dies on error */ | |
197 | s_in6.sin6_port = htons(port); | |
198 | s_ptr = (struct sockaddr *)&s_in6; | |
199 | s_len = sizeof(s_in6); | |
200 | } | |
201 | else | |
202 | #else /* HAVE_IPV6 */ | |
203 | af = af; /* Avoid compiler warning */ | |
204 | #endif /* HAVE_IPV6 */ | |
205 | ||
206 | /* For an IPv4 address, use an IPv4 sockaddr structure, even on a system with | |
207 | IPv6 support. */ | |
208 | ||
209 | { | |
210 | memset(&s_in4, 0, sizeof(s_in4)); | |
211 | s_in4.sin_family = AF_INET; | |
212 | s_in4.sin_port = htons(port); | |
213 | s_in4.sin_addr.s_addr = (S_ADDR_TYPE)inet_addr(CS address); | |
214 | s_ptr = (struct sockaddr *)&s_in4; | |
215 | s_len = sizeof(s_in4); | |
216 | } | |
217 | ||
218 | /* If no connection timeout is set, just call connect() without setting a | |
219 | timer, thereby allowing the inbuilt OS timeout to operate. */ | |
220 | ||
221 | sigalrm_seen = FALSE; | |
222 | if (timeout > 0) alarm(timeout); | |
223 | rc = connect(sock, s_ptr, s_len); | |
224 | save_errno = errno; | |
225 | alarm(0); | |
226 | ||
227 | /* There is a testing facility for simulating a connection timeout, as I | |
228 | can't think of any other way of doing this. It converts a connection refused | |
75e0e026 | 229 | into a timeout if the timeout is set to 999999. */ |
059ec3d9 PH |
230 | |
231 | if (running_in_test_harness) | |
232 | { | |
75e0e026 | 233 | if (save_errno == ECONNREFUSED && timeout == 999999) |
059ec3d9 PH |
234 | { |
235 | rc = -1; | |
236 | save_errno = EINTR; | |
237 | sigalrm_seen = TRUE; | |
238 | } | |
239 | } | |
240 | ||
241 | /* Success */ | |
242 | ||
243 | if (rc >= 0) return 0; | |
244 | ||
245 | /* A failure whose error code is "Interrupted system call" is in fact | |
246 | an externally applied timeout if the signal handler has been run. */ | |
247 | ||
059ec3d9 PH |
248 | errno = (save_errno == EINTR && sigalrm_seen)? ETIMEDOUT : save_errno; |
249 | return -1; | |
250 | } | |
251 | ||
252 | ||
253 | ||
254 | /************************************************* | |
255 | * Set keepalive on a socket * | |
256 | *************************************************/ | |
257 | ||
258 | /* Can be called for both incoming and outgoing sockets. | |
259 | ||
260 | Arguments: | |
261 | sock the socket | |
262 | address the remote host address, for failure logging | |
263 | torf true for outgoing connection, false for incoming | |
264 | ||
265 | Returns: nothing | |
266 | */ | |
267 | ||
268 | void | |
269 | ip_keepalive(int sock, uschar *address, BOOL torf) | |
270 | { | |
271 | int fodder = 1; | |
272 | if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, | |
273 | (uschar *)(&fodder), sizeof(fodder)) != 0) | |
274 | log_write(0, LOG_MAIN, "setsockopt(SO_KEEPALIVE) on connection %s %s " | |
275 | "failed: %s", torf? "to":"from", address, strerror(errno)); | |
276 | } | |
277 | ||
278 | ||
279 | ||
280 | /************************************************* | |
281 | * Receive from a socket with timeout * | |
282 | *************************************************/ | |
283 | ||
284 | /* The timeout is implemented using select(), and we loop to cover select() | |
285 | getting interrupted, and the possibility of select() returning with a positive | |
286 | result but no ready descriptor. Is this in fact possible? | |
287 | ||
288 | Arguments: | |
289 | sock the socket | |
290 | buffer to read into | |
291 | bufsize the buffer size | |
292 | timeout the timeout | |
293 | ||
294 | Returns: > 0 => that much data read | |
295 | <= 0 on error or EOF; errno set - zero for EOF | |
296 | */ | |
297 | ||
298 | int | |
299 | ip_recv(int sock, uschar *buffer, int buffsize, int timeout) | |
300 | { | |
301 | fd_set select_inset; | |
302 | struct timeval tv; | |
303 | int start_recv = time(NULL); | |
304 | int rc; | |
305 | ||
306 | /* Wait until the socket is ready */ | |
307 | ||
308 | for (;;) | |
309 | { | |
310 | FD_ZERO (&select_inset); | |
311 | FD_SET (sock, &select_inset); | |
312 | tv.tv_sec = timeout; | |
313 | tv.tv_usec = 0; | |
314 | ||
315 | DEBUG(D_transport) debug_printf("waiting for data on socket\n"); | |
316 | rc = select(sock + 1, (SELECT_ARG2_TYPE *)&select_inset, NULL, NULL, &tv); | |
317 | ||
318 | /* If some interrupt arrived, just retry. We presume this to be rare, | |
319 | but it can happen (e.g. the SIGUSR1 signal sent by exiwhat causes | |
320 | select() to exit). | |
321 | ||
322 | Aug 2004: Somebody set up a cron job that ran exiwhat every 2 minutes, making | |
323 | the interrupt not at all rare. Since the timeout is typically more than 2 | |
324 | minutes, the effect was to block the timeout completely. To prevent this | |
325 | happening again, we do an explicit time test. */ | |
326 | ||
327 | if (rc < 0 && errno == EINTR) | |
328 | { | |
329 | DEBUG(D_transport) debug_printf("EINTR while waiting for socket data\n"); | |
330 | if (time(NULL) - start_recv < timeout) continue; | |
331 | DEBUG(D_transport) debug_printf("total wait time exceeds timeout\n"); | |
332 | } | |
333 | ||
334 | /* Handle a timeout, and treat any other select error as a timeout, including | |
335 | an EINTR when we have been in this loop for longer than timeout. */ | |
336 | ||
337 | if (rc <= 0) | |
338 | { | |
339 | errno = ETIMEDOUT; | |
340 | return -1; | |
341 | } | |
342 | ||
343 | /* If the socket is ready, break out of the loop. */ | |
344 | ||
345 | if (FD_ISSET(sock, &select_inset)) break; | |
346 | } | |
347 | ||
348 | /* The socket is ready, read from it (via TLS if it's active). On EOF (i.e. | |
349 | close down of the connection), set errno to zero; otherwise leave it alone. */ | |
350 | ||
351 | #ifdef SUPPORT_TLS | |
352 | if (tls_active == sock) | |
353 | rc = tls_read(buffer, buffsize); | |
354 | else | |
355 | #endif | |
356 | rc = recv(sock, buffer, buffsize, 0); | |
357 | ||
358 | if (rc > 0) return rc; | |
359 | if (rc == 0) errno = 0; | |
360 | return -1; | |
361 | } | |
362 | ||
363 | ||
364 | /* End of ip.c */ |