1 /*
2 * Check decoding of SIOCGIFCONF command of ioctl syscall.
3 *
4 * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * Copyright (c) 2016-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12
13 #include <stdio.h>
14 #include <string.h>
15
16 #include <arpa/inet.h>
17 #include <net/if.h>
18 #include <sys/ioctl.h>
19 #include <sys/socket.h>
20
21 #define MAX_STRLEN 1
22
23 static void
24 print_ifc_len(const int val)
25 {
26 printf("%d", val);
27 if (val > 0 && val % (int) sizeof(struct ifreq) == 0)
28 printf(" /* %d * sizeof(struct ifreq) */",
29 val / (int) sizeof(struct ifreq));
30 }
31
32 static void
33 print_ifconf(const struct ifconf *const ifc, const int in_len,
34 const char *const in_buf, const long rc)
35 {
36 if (in_buf) {
37 printf("{ifc_len=");
38 print_ifc_len(in_len);
39
40 if (in_len != ifc->ifc_len) {
41 printf(" => ");
42 print_ifc_len(ifc->ifc_len);
43 }
44 } else {
45 printf("{ifc_len=");
46 print_ifc_len(ifc->ifc_len);
47 }
48
49 printf(", ifc_buf=");
50
51 if ((rc < 0) || !in_buf) {
52 if (in_buf)
53 printf("%p", in_buf);
54 else
55 printf("NULL");
56 } else {
57 int i;
58
59 printf("[");
60 for (i = 0; i < (ifc->ifc_len) &&
61 i < (int) (MAX_STRLEN * sizeof(struct ifreq));
62 i += sizeof(struct ifreq)) {
63 struct ifreq *ifr = (struct ifreq *) (ifc->ifc_buf + i);
64 struct sockaddr_in *const sa_in =
65 (struct sockaddr_in *) &(ifr->ifr_addr);
66
67 if (i)
68 printf(", ");
69 printf("{ifr_name=\"%s\", ifr_addr={sa_family=AF_INET, "
70 "sin_port=htons(%u), sin_addr=inet_addr(\"%s\")}"
71 "}", ifr->ifr_name, ntohs(sa_in->sin_port),
72 inet_ntoa(sa_in->sin_addr));
73 }
74
75 if ((size_t) (ifc->ifc_len - i) >= sizeof(struct ifreq))
76 printf(", ...");
77
78 printf("]");
79 }
80
81 printf("}");
82 }
83
84 static void
85 gifconf_ioctl(const int fd, struct ifconf *const ifc, const bool ifc_valid)
86 {
87 const int in_len = ifc_valid ? ifc->ifc_len : 0;
88 const char *const in_buf = ifc_valid ? ifc->ifc_buf : NULL;
89 long rc = ioctl(fd, SIOCGIFCONF, ifc);
90 const char *errstr = sprintrc(rc);
91
92 printf("ioctl(%d, SIOCGIFCONF, ", fd);
93 if (ifc_valid) {
94 print_ifconf(ifc, in_len, in_buf, rc);
95 } else {
96 if (ifc)
97 printf("%p", ifc);
98 else
99 printf("NULL");
100 }
101
102 printf(") = %s\n", errstr);
103 }
104
105 int
106 main(int argc, char *argv[])
107 {
108 struct ifreq *const ifr = tail_alloc(2 * sizeof(*ifr));
109 TAIL_ALLOC_OBJECT_CONST_PTR(struct ifconf, ifc);
110 const int fd = socket(AF_INET, SOCK_STREAM, 0);
111 if (fd < 0)
112 perror_msg_and_skip("socket AF_INET");
113
114 gifconf_ioctl(fd, NULL, false);
115 gifconf_ioctl(fd, ifc + 1, false);
116
117 ifc->ifc_len = 3141592653U;
118 ifc->ifc_buf = NULL;
119 gifconf_ioctl(fd, ifc, true);
120
121 ifc->ifc_len = 0;
122 ifc->ifc_buf = (char *) (ifr + 2);
123 gifconf_ioctl(fd, ifc, true);
124
125 ifc->ifc_len = 1;
126 ifc->ifc_buf = (char *) (ifr + 1);
127 gifconf_ioctl(fd, ifc, true);
128
129 ifc->ifc_len = 1 * sizeof(*ifr);
130 ifc->ifc_buf = (char *) (ifr + 1);
131 gifconf_ioctl(fd, ifc, true);
132
133 ifc->ifc_len = 2 * sizeof(*ifr);
134 ifc->ifc_buf = (char *) (ifr + 1);
135 gifconf_ioctl(fd, ifc, true);
136
137 ifc->ifc_len = 2 * sizeof(*ifr) + 2;
138 ifc->ifc_buf = (char *) ifr;
139 gifconf_ioctl(fd, ifc, true);
140
141 ifc->ifc_len = 3 * sizeof(*ifr) + 4;
142 ifc->ifc_buf = (char *) ifr;
143 gifconf_ioctl(fd, ifc, true);
144
145 puts("+++ exited with 0 +++");
146 return 0;
147 }