xref: /third_party/ltp/lib/safe_net.c (revision f08c3bdf)
1/*
2 * Copyright (c) 2015 Fujitsu Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19#include <errno.h>
20#include "test.h"
21#include "safe_macros_fn.h"
22#include "safe_net_fn.h"
23
24char *tst_sock_addr(const struct sockaddr *sa, socklen_t salen, char *res,
25		    size_t len)
26{
27	char portstr[8];
28
29	switch (sa->sa_family) {
30
31	case AF_INET: {
32		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
33
34		if (!inet_ntop(AF_INET, &sin->sin_addr, res, len))
35			return NULL;
36
37		if (ntohs(sin->sin_port) != 0) {
38			snprintf(portstr, sizeof(portstr), ":%d",
39				 ntohs(sin->sin_port));
40			strcat(res, portstr);
41		}
42
43		return res;
44	}
45
46	case AF_INET6: {
47		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
48
49		res[0] = '[';
50		if (!inet_ntop(AF_INET6, &sin6->sin6_addr, res + 1, len - 1))
51			return NULL;
52
53		if (ntohs(sin6->sin6_port) != 0) {
54			snprintf(portstr, sizeof(portstr), "]:%d",
55				 ntohs(sin6->sin6_port));
56			strcat(res, portstr);
57			return res;
58		}
59
60		return res + 1;
61	}
62
63	case AF_UNIX: {
64		struct sockaddr_un *unp = (struct sockaddr_un *)sa;
65
66		if (unp->sun_path[0] == '\0')
67			strcpy(res, "(no pathname bound)");
68		else
69			snprintf(res, len, "%s", unp->sun_path);
70
71		return res;
72	}
73
74	default: {
75		snprintf(res, len,
76			 "sock_ntop: unknown AF_xxx: %d, len: %d",
77			 sa->sa_family, salen);
78
79		return res;
80	}
81
82	}
83}
84
85int tst_getsockport(const char *file, const int lineno, int sockfd)
86{
87	struct sockaddr_storage ss;
88	socklen_t addrlen = sizeof(ss);
89	struct sockaddr *sa = (struct sockaddr *)&ss;
90
91	safe_getsockname(file, lineno, NULL, sockfd, sa, &addrlen);
92
93	switch (sa->sa_family) {
94	case AF_INET: {
95		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
96
97		return ntohs(sin->sin_port);
98	}
99	case AF_INET6: {
100		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
101
102		return ntohs(sin6->sin6_port);
103	} }
104
105	return -1;
106}
107
108int safe_socket(const char *file, const int lineno, void (cleanup_fn)(void),
109		int domain, int type, int protocol)
110{
111	int rval, ttype;
112
113	rval = socket(domain, type, protocol);
114
115	if (rval == -1) {
116		switch (errno) {
117		case EPROTONOSUPPORT:
118		case ESOCKTNOSUPPORT:
119		case EOPNOTSUPP:
120		case EPFNOSUPPORT:
121		case EAFNOSUPPORT:
122			ttype = TCONF;
123			break;
124		default:
125			ttype = TBROK;
126		}
127
128		tst_brkm_(file, lineno, ttype | TERRNO, cleanup_fn,
129			"socket(%d, %d, %d) failed", domain, type, protocol);
130	} else if (rval < 0) {
131		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
132			"Invalid socket(%d, %d, %d) return value %d", domain,
133			type, protocol, rval);
134	}
135
136	return rval;
137}
138
139int safe_socketpair(const char *file, const int lineno, int domain, int type,
140		    int protocol, int sv[])
141{
142	int rval, ttype;
143
144	rval = socketpair(domain, type, protocol, sv);
145
146	if (rval == -1) {
147		switch (errno) {
148		case EPROTONOSUPPORT:
149		case EOPNOTSUPP:
150		case EAFNOSUPPORT:
151			ttype = TCONF;
152			break;
153		default:
154			ttype = TBROK;
155		}
156
157		tst_brkm_(file, lineno, ttype | TERRNO, NULL,
158			"socketpair(%d, %d, %d, %p) failed", domain, type,
159			protocol, sv);
160	} else if (rval) {
161		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
162			"Invalid socketpair(%d, %d, %d, %p) return value %d",
163			domain, type, protocol, sv, rval);
164	}
165
166	return rval;
167}
168
169int safe_getsockopt(const char *file, const int lineno, int sockfd, int level,
170		    int optname, void *optval, socklen_t *optlen)
171{
172	int rval = getsockopt(sockfd, level, optname, optval, optlen);
173
174	if (rval == -1) {
175		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
176			"getsockopt(%d, %d, %d, %p, %p) failed",
177			sockfd, level, optname, optval, optlen);
178	} else if (rval) {
179		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
180			"Invalid getsockopt(%d, %d, %d, %p, %p) return value %d",
181			sockfd, level, optname, optval, optlen, rval);
182	}
183
184	return rval;
185}
186
187int safe_setsockopt(const char *file, const int lineno, int sockfd, int level,
188		    int optname, const void *optval, socklen_t optlen)
189{
190	int rval;
191
192	rval = setsockopt(sockfd, level, optname, optval, optlen);
193
194	if (rval == -1) {
195		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
196			"setsockopt(%d, %d, %d, %p, %d) failed",
197			sockfd, level, optname, optval, optlen);
198	} else if (rval) {
199		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
200			"Invalid setsockopt(%d, %d, %d, %p, %d) return value %d",
201			sockfd, level, optname, optval, optlen, rval);
202	}
203
204	return rval;
205}
206
207ssize_t safe_send(const char *file, const int lineno, char len_strict,
208		  int sockfd, const void *buf, size_t len, int flags)
209{
210	ssize_t rval;
211
212	rval = send(sockfd, buf, len, flags);
213
214	if (rval == -1 || (len_strict && (size_t)rval != len)) {
215		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
216			"send(%d, %p, %zu, %d) failed", sockfd, buf, len,
217			flags);
218	} else if (rval < 0) {
219		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
220			"Invalid send(%d, %p, %zu, %d) return value %zd",
221			sockfd, buf, len, flags, rval);
222	}
223
224	return rval;
225}
226
227ssize_t safe_sendto(const char *file, const int lineno, char len_strict,
228		    int sockfd, const void *buf, size_t len, int flags,
229		    const struct sockaddr *dest_addr, socklen_t addrlen)
230{
231	ssize_t rval;
232	char res[128];
233
234	rval = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
235
236	if (rval == -1 || (len_strict && (size_t)rval != len)) {
237		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
238			"sendto(%d, %p, %zu, %d, %s, %d) failed",
239			sockfd, buf, len, flags,
240			tst_sock_addr(dest_addr, addrlen, res, sizeof(res)),
241			addrlen);
242	} else if (rval < 0) {
243		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
244			"Invalid sendto(%d, %p, %zu, %d, %s, %d) return value %zd",
245			sockfd, buf, len, flags,
246			tst_sock_addr(dest_addr, addrlen, res, sizeof(res)),
247			addrlen, rval);
248	}
249
250	return rval;
251}
252
253ssize_t safe_sendmsg(const char *file, const int lineno, size_t len,
254		     int sockfd, const struct msghdr *msg, int flags)
255{
256	ssize_t rval;
257
258	rval = sendmsg(sockfd, msg, flags);
259
260	if (rval == -1) {
261		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
262			"sendmsg(%d, %p, %d) failed", sockfd, msg, flags);
263	} else if (rval < 0) {
264		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
265			"Invalid sendmsg(%d, %p, %d) return value %zd",
266			sockfd, msg, flags, rval);
267	} else if (len && (size_t)rval != len) {
268		tst_brkm_(file, lineno, TBROK, NULL,
269			 "sendmsg(%d, %p, %d) ret(%zd) != len(%zu)",
270			 sockfd, msg, flags, rval, len);
271	}
272
273	return rval;
274}
275
276ssize_t safe_recv(const char *file, const int lineno, size_t len,
277	int sockfd, void *buf, size_t size, int flags)
278{
279	ssize_t rval;
280
281	rval = recv(sockfd, buf, size, flags);
282
283	if (rval == -1) {
284		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
285			"recv(%d, %p, %zu, %d) failed", sockfd, buf, size,
286			flags);
287	} else if (rval < 0) {
288		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
289			"Invalid recv(%d, %p, %zu, %d) return value %zd",
290			sockfd, buf, size, flags, rval);
291	} else if (len && (size_t)rval != len) {
292		tst_brkm_(file, lineno, TBROK, NULL,
293			"recv(%d, %p, %zu, %d) ret(%zd) != len(%zu)",
294			sockfd, buf, size, flags, rval, len);
295	}
296
297	return rval;
298
299}
300
301ssize_t safe_recvmsg(const char *file, const int lineno, size_t len,
302		     int sockfd, struct msghdr *msg, int flags)
303{
304	ssize_t rval;
305
306	rval = recvmsg(sockfd, msg, flags);
307
308	if (rval == -1) {
309		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
310			"recvmsg(%d, %p, %d) failed", sockfd, msg, flags);
311	} else if (rval < 0) {
312		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
313			"Invalid recvmsg(%d, %p, %d) return value %zd",
314			sockfd, msg, flags, rval);
315	} else if (len && (size_t)rval != len) {
316		tst_brkm_(file, lineno, TBROK, NULL,
317			"recvmsg(%d, %p, %d) ret(%zd) != len(%zu)",
318			sockfd, msg, flags, rval, len);
319	}
320
321	return rval;
322
323}
324
325int safe_bind(const char *file, const int lineno, void (cleanup_fn)(void),
326	      int socket, const struct sockaddr *address,
327	      socklen_t address_len)
328{
329	int i, ret;
330	char buf[128];
331
332	for (i = 0; i < 120; i++) {
333		ret = bind(socket, address, address_len);
334
335		if (!ret)
336			return 0;
337
338		if (ret != -1) {
339			tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
340				"Invalid bind(%d, %s, %d) return value %d",
341				socket, tst_sock_addr(address, address_len,
342				buf, sizeof(buf)), address_len, ret);
343			return ret;
344		} else if (errno != EADDRINUSE) {
345			tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
346				"bind(%d, %s, %d) failed", socket,
347				tst_sock_addr(address, address_len, buf,
348				sizeof(buf)), address_len);
349			return ret;
350		}
351
352		if ((i + 1) % 10 == 0) {
353			tst_resm_(file, lineno, TINFO,
354				"address is in use, waited %3i sec", i + 1);
355		}
356
357		sleep(1);
358	}
359
360	tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
361		"Failed to bind(%d, %s, %d) after 120 retries", socket,
362		tst_sock_addr(address, address_len, buf, sizeof(buf)),
363		address_len);
364	return -1;
365}
366
367int safe_listen(const char *file, const int lineno, void (cleanup_fn)(void),
368		int socket, int backlog)
369{
370	int rval;
371	int res = TBROK;
372
373	rval = listen(socket, backlog);
374
375	if (rval == -1) {
376		if (errno == ENOSYS)
377			res = TCONF;
378		tst_brkm_(file, lineno, res | TERRNO, cleanup_fn,
379			"listen(%d, %d) failed", socket, backlog);
380	} else if (rval) {
381		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
382			"Invalid listen(%d, %d) return value %d", socket,
383			backlog, rval);
384	}
385
386	return rval;
387}
388
389int safe_accept(const char *file, const int lineno, void (cleanup_fn)(void),
390		int sockfd, struct sockaddr *addr, socklen_t *addrlen)
391{
392	int rval;
393
394	rval = accept(sockfd, addr, addrlen);
395
396	if (rval == -1) {
397		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
398			"accept(%d, %p, %d) failed", sockfd, addr, *addrlen);
399	} else if (rval < 0) {
400		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
401			"Invalid accept(%d, %p, %d) return value %d", sockfd,
402			addr, *addrlen, rval);
403	}
404
405	return rval;
406}
407
408int safe_connect(const char *file, const int lineno, void (cleanup_fn)(void),
409		 int sockfd, const struct sockaddr *addr, socklen_t addrlen)
410{
411	int rval;
412	char buf[128];
413
414	rval = connect(sockfd, addr, addrlen);
415
416	if (rval == -1) {
417		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
418			"connect(%d, %s, %d) failed", sockfd,
419			tst_sock_addr(addr, addrlen, buf, sizeof(buf)),
420			addrlen);
421	} else if (rval) {
422		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
423			"Invalid connect(%d, %s, %d) return value %d", sockfd,
424			tst_sock_addr(addr, addrlen, buf, sizeof(buf)),
425			addrlen, rval);
426	}
427
428	return rval;
429}
430
431int safe_getsockname(const char *file, const int lineno,
432		     void (cleanup_fn)(void), int sockfd, struct sockaddr *addr,
433		     socklen_t *addrlen)
434{
435	int rval;
436	char buf[128];
437
438	rval = getsockname(sockfd, addr, addrlen);
439
440	if (rval == -1) {
441		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
442			"getsockname(%d, %s, %d) failed", sockfd,
443			tst_sock_addr(addr, *addrlen, buf, sizeof(buf)),
444			*addrlen);
445	} else if (rval) {
446		tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn,
447			"Invalid getsockname(%d, %s, %d) return value %d",
448			sockfd, tst_sock_addr(addr, *addrlen, buf,
449			sizeof(buf)), *addrlen, rval);
450	}
451
452	return rval;
453}
454
455int safe_gethostname(const char *file, const int lineno,
456		     char *name, size_t size)
457{
458	int rval = gethostname(name, size);
459
460	if (rval == -1) {
461		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
462			"gethostname(%p, %zu) failed", name, size);
463	} else if (rval) {
464		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
465			"Invalid gethostname(%p, %zu) return value %d", name,
466			size, rval);
467	}
468
469	return rval;
470}
471
472int safe_sethostname(const char *file, const int lineno,
473		     const char *name, size_t size)
474{
475	int rval = sethostname(name, size);
476
477	if (rval == -1) {
478		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
479			"sethostname(%p, %zu) failed", name, size);
480	} else if (rval) {
481		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
482			"Invalid sethostname(%p, %zu) return value %d", name,
483			size, rval);
484	}
485
486	return rval;
487}
488
489/*
490 * @return port in network byte order.
491 */
492unsigned short tst_get_unused_port(const char *file, const int lineno,
493	      void (cleanup_fn)(void), unsigned short family, int type)
494{
495	int sock, ret;
496	socklen_t slen;
497	struct sockaddr_storage _addr;
498	struct sockaddr *addr = (struct sockaddr *)&_addr;
499	struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
500	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
501
502	switch (family) {
503	case AF_INET:
504		addr4->sin_family = AF_INET;
505		addr4->sin_port = 0;
506		addr4->sin_addr.s_addr = INADDR_ANY;
507		slen = sizeof(*addr4);
508		break;
509
510	case AF_INET6:
511		addr6->sin6_family = AF_INET6;
512		addr6->sin6_port = 0;
513		addr6->sin6_addr = in6addr_any;
514		slen = sizeof(*addr6);
515		break;
516
517	default:
518		tst_brkm_(file, lineno, TBROK, cleanup_fn,
519			"%s(): Unsupported socket family %d", __func__,
520			family);
521		return -1;
522	}
523
524	sock = safe_socket(file, lineno, cleanup_fn, addr->sa_family, type, 0);
525
526	if (sock < 0)
527		return sock;
528
529	ret = safe_bind(file, lineno, cleanup_fn, sock, addr, slen);
530
531	if (ret)
532		return ret;
533
534	ret = safe_getsockname(file, lineno, cleanup_fn, sock, addr, &slen);
535
536	if (ret)
537		return ret;
538
539	ret = safe_close(file, lineno, cleanup_fn, sock);
540
541	if (ret)
542		return ret;
543
544	switch (family) {
545	case AF_INET:
546		return addr4->sin_port;
547	case AF_INET6:
548		return addr6->sin6_port;
549	default:
550		return -1;
551	}
552}
553