1 /*
2 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
3 * Copyright (c) 2017-2018 The strace developers.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "tests.h"
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <sys/socket.h>
34 #include <arpa/inet.h>
35 #include <net/if.h>
36 #include <netinet/tcp.h>
37 #include "test_nlattr.h"
38 #include <linux/inet_diag.h>
39 #include <linux/rtnetlink.h>
40 #include <linux/sock_diag.h>
41
42 static const char address[] = "10.11.12.13";
43 static const unsigned int hdrlen = sizeof(struct inet_diag_req_v2);
44 static void *nlh0;
45 static char pattern[4096];
46
47 static void
init_inet_diag_req_v2(struct nlmsghdr * const nlh,const unsigned int msg_len)48 init_inet_diag_req_v2(struct nlmsghdr *const nlh, const unsigned int msg_len)
49 {
50 SET_STRUCT(struct nlmsghdr, nlh,
51 .nlmsg_len = msg_len,
52 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
53 .nlmsg_flags = NLM_F_REQUEST
54 );
55
56 struct inet_diag_req_v2 *const req = NLMSG_DATA(nlh);
57 SET_STRUCT(struct inet_diag_req_v2, req,
58 .sdiag_family = AF_INET,
59 .idiag_ext = 1 << (INET_DIAG_CONG - 1),
60 .sdiag_protocol = IPPROTO_TCP,
61 .idiag_states = 1 << TCP_CLOSE,
62 .id.idiag_if = ifindex_lo()
63 );
64
65 if (!inet_pton(AF_INET, address, req->id.idiag_src) ||
66 !inet_pton(AF_INET, address, req->id.idiag_dst))
67 perror_msg_and_skip("inet_pton");
68 }
69
70 static void
print_inet_diag_req_v2(const unsigned int msg_len)71 print_inet_diag_req_v2(const unsigned int msg_len)
72 {
73 printf("{len=%u, type=SOCK_DIAG_BY_FAMILY"
74 ", flags=NLM_F_REQUEST, seq=0, pid=0}"
75 ", {sdiag_family=AF_INET, sdiag_protocol=IPPROTO_TCP"
76 ", idiag_ext=1<<(INET_DIAG_CONG-1)"
77 ", idiag_states=1<<TCP_CLOSE"
78 ", id={idiag_sport=htons(0), idiag_dport=htons(0)"
79 ", idiag_src=inet_addr(\"%s\")"
80 ", idiag_dst=inet_addr(\"%s\")"
81 ", idiag_if=" IFINDEX_LO_STR
82 ", idiag_cookie=[0, 0]}}",
83 msg_len, address, address);
84 }
85
86 static void
test_inet_diag_bc_op(const int fd)87 test_inet_diag_bc_op(const int fd)
88 {
89 static const struct inet_diag_bc_op op = {
90 .code = INET_DIAG_BC_S_COND,
91 .yes = 0xaf,
92 .no = 0xafcd
93 };
94 TEST_NLATTR_OBJECT(fd, nlh0, hdrlen,
95 init_inet_diag_req_v2, print_inet_diag_req_v2,
96 INET_DIAG_REQ_BYTECODE, pattern, op,
97 printf("{code=INET_DIAG_BC_S_COND");
98 PRINT_FIELD_U(", ", op, yes);
99 PRINT_FIELD_U(", ", op, no);
100 printf("}"));
101 }
102
103 static void
print_inet_diag_bc_op(const char * const code)104 print_inet_diag_bc_op(const char *const code)
105 {
106 printf("{{code=%s, yes=0, no=0}, ", code);
107 }
108
109 static void
test_inet_diag_bc_s_cond(const int fd)110 test_inet_diag_bc_s_cond(const int fd)
111 {
112 static const struct inet_diag_bc_op op = {
113 .code = INET_DIAG_BC_S_COND,
114 };
115 static const struct inet_diag_hostcond cond = {
116 .family = AF_UNSPEC,
117 .prefix_len = 0xad,
118 .port = 0xadfa
119 };
120 char buf[sizeof(op) + sizeof(cond)];
121 memcpy(buf, &op, sizeof(op));
122
123 const unsigned int plen = sizeof(cond) - 1 > DEFAULT_STRLEN ?
124 sizeof(op) + DEFAULT_STRLEN : sizeof(buf) - 1;
125 memcpy(buf + sizeof(op), &pattern, sizeof(cond));
126 TEST_NLATTR(fd, nlh0, hdrlen,
127 init_inet_diag_req_v2, print_inet_diag_req_v2,
128 INET_DIAG_REQ_BYTECODE,
129 plen, buf, plen,
130 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
131 print_quoted_hex(buf + sizeof(op), plen - sizeof(op));
132 printf("}"));
133
134 TEST_NLATTR(fd, nlh0, hdrlen,
135 init_inet_diag_req_v2, print_inet_diag_req_v2,
136 INET_DIAG_REQ_BYTECODE,
137 sizeof(buf), buf, sizeof(buf) - 1,
138 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
139 printf("%p}", RTA_DATA(TEST_NLATTR_nla) + sizeof(op)));
140
141 memcpy(buf + sizeof(op), &cond, sizeof(cond));
142 TEST_NLATTR(fd, nlh0, hdrlen,
143 init_inet_diag_req_v2, print_inet_diag_req_v2,
144 INET_DIAG_REQ_BYTECODE,
145 sizeof(buf), buf, sizeof(buf),
146 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
147 printf("{family=AF_UNSPEC");
148 PRINT_FIELD_U(", ", cond, prefix_len);
149 PRINT_FIELD_U(", ", cond, port);
150 printf("}}"));
151 }
152
153 static void
print_inet_diag_hostcond(const char * const family)154 print_inet_diag_hostcond(const char *const family)
155 {
156 printf("{family=%s, prefix_len=0, port=0, ", family);
157 }
158
159 static void
test_in_addr(const int fd)160 test_in_addr(const int fd)
161 {
162 static const struct inet_diag_bc_op op = {
163 .code = INET_DIAG_BC_S_COND,
164 };
165 static const struct inet_diag_hostcond cond = {
166 .family = AF_INET,
167 };
168 struct in_addr addr;
169 if (!inet_pton(AF_INET, address, &addr))
170 perror_msg_and_skip("inet_pton");
171
172 char buf[sizeof(op) + sizeof(cond) + sizeof(addr)];
173 memcpy(buf, &op, sizeof(op));
174 memcpy(buf + sizeof(op), &cond, sizeof(cond));
175
176 const unsigned int plen = sizeof(addr) - 1 > DEFAULT_STRLEN ?
177 sizeof(cond) + sizeof(cond) + DEFAULT_STRLEN : sizeof(buf) - 1;
178 memcpy(buf + sizeof(op) + sizeof(cond), &pattern, sizeof(addr));
179 TEST_NLATTR(fd, nlh0, hdrlen,
180 init_inet_diag_req_v2, print_inet_diag_req_v2,
181 INET_DIAG_REQ_BYTECODE,
182 plen, buf, plen,
183 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
184 print_inet_diag_hostcond("AF_INET");
185 printf("addr=");
186 print_quoted_hex(pattern, plen - sizeof(op) - sizeof(cond));
187 printf("}}"));
188
189 TEST_NLATTR(fd, nlh0, hdrlen,
190 init_inet_diag_req_v2, print_inet_diag_req_v2,
191 INET_DIAG_REQ_BYTECODE,
192 sizeof(buf), buf, sizeof(buf) - 1,
193 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
194 print_inet_diag_hostcond("AF_INET");
195 printf("addr=%p}}",
196 RTA_DATA(TEST_NLATTR_nla)
197 + sizeof(op) + sizeof(cond)));
198
199 memcpy(buf + sizeof(op) + sizeof(cond), &addr, sizeof(addr));
200 TEST_NLATTR(fd, nlh0, hdrlen,
201 init_inet_diag_req_v2, print_inet_diag_req_v2,
202 INET_DIAG_REQ_BYTECODE,
203 sizeof(buf), buf, sizeof(buf),
204 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
205 print_inet_diag_hostcond("AF_INET");
206 printf("addr=inet_addr(\"%s\")}}", address));
207 }
208
209 static void
test_in6_addr(const int fd)210 test_in6_addr(const int fd)
211 {
212 const char address6[] = "12:34:56:78:90:ab:cd:ef";
213 static const struct inet_diag_bc_op op = {
214 .code = INET_DIAG_BC_S_COND,
215 };
216 static const struct inet_diag_hostcond cond = {
217 .family = AF_INET6,
218 };
219 struct in6_addr addr;
220 if (!inet_pton(AF_INET6, address6, &addr))
221 perror_msg_and_skip("inet_pton");
222
223 char buf[sizeof(op) + sizeof(cond) + sizeof(addr)];
224 memcpy(buf, &op, sizeof(op));
225 memcpy(buf + sizeof(op), &cond, sizeof(cond));
226
227 const unsigned int plen = sizeof(addr) - 1 > DEFAULT_STRLEN ?
228 sizeof(cond) + sizeof(cond) + DEFAULT_STRLEN : sizeof(buf) - 1;
229 memcpy(buf + sizeof(op) + sizeof(cond), &pattern, sizeof(addr));
230 TEST_NLATTR(fd, nlh0, hdrlen,
231 init_inet_diag_req_v2, print_inet_diag_req_v2,
232 INET_DIAG_REQ_BYTECODE,
233 plen, buf, plen,
234 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
235 print_inet_diag_hostcond("AF_INET6");
236 printf("addr=");
237 print_quoted_hex(pattern, plen - sizeof(op) - sizeof(cond));
238 printf("}}"));
239
240 TEST_NLATTR(fd, nlh0, hdrlen,
241 init_inet_diag_req_v2, print_inet_diag_req_v2,
242 INET_DIAG_REQ_BYTECODE,
243 sizeof(buf), buf, sizeof(buf) - 1,
244 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
245 print_inet_diag_hostcond("AF_INET6");
246 printf("addr=%p}}",
247 RTA_DATA(TEST_NLATTR_nla)
248 + sizeof(op) + sizeof(cond)));
249
250 memcpy(buf + sizeof(op) + sizeof(cond), &addr, sizeof(addr));
251 TEST_NLATTR(fd, nlh0, hdrlen,
252 init_inet_diag_req_v2, print_inet_diag_req_v2,
253 INET_DIAG_REQ_BYTECODE,
254 sizeof(buf), buf, sizeof(buf),
255 print_inet_diag_bc_op("INET_DIAG_BC_S_COND");
256 print_inet_diag_hostcond("AF_INET6");
257 printf("inet_pton(AF_INET6, \"%s\", &addr)}}", address6));
258 }
259
260 static void
test_inet_diag_bc_dev_cond(const int fd)261 test_inet_diag_bc_dev_cond(const int fd)
262 {
263 static const struct inet_diag_bc_op op = {
264 .code = INET_DIAG_BC_DEV_COND,
265 };
266 const uint32_t ifindex = ifindex_lo();
267 char buf[sizeof(op) + sizeof(ifindex)];
268 memcpy(buf, &op, sizeof(op));
269 memcpy(buf + sizeof(op), pattern, sizeof(ifindex));
270
271 TEST_NLATTR(fd, nlh0, hdrlen,
272 init_inet_diag_req_v2, print_inet_diag_req_v2,
273 INET_DIAG_REQ_BYTECODE,
274 sizeof(buf) - 1, buf, sizeof(buf) - 1,
275 print_inet_diag_bc_op("INET_DIAG_BC_DEV_COND");
276 print_quoted_hex(pattern, sizeof(ifindex) - 1);
277 printf("}"));
278
279 TEST_NLATTR(fd, nlh0, hdrlen,
280 init_inet_diag_req_v2, print_inet_diag_req_v2,
281 INET_DIAG_REQ_BYTECODE,
282 sizeof(buf), buf, sizeof(buf) - 1,
283 print_inet_diag_bc_op("INET_DIAG_BC_DEV_COND");
284 printf("%p}", RTA_DATA(TEST_NLATTR_nla) + sizeof(op)));
285
286 memcpy(buf + sizeof(op), &ifindex, sizeof(ifindex));
287 TEST_NLATTR(fd, nlh0, hdrlen,
288 init_inet_diag_req_v2, print_inet_diag_req_v2,
289 INET_DIAG_REQ_BYTECODE,
290 sizeof(buf), buf, sizeof(buf),
291 print_inet_diag_bc_op("INET_DIAG_BC_DEV_COND");
292 printf(IFINDEX_LO_STR "}"));
293 }
294
295 static void
test_inet_diag_bc_s_le(const int fd)296 test_inet_diag_bc_s_le(const int fd)
297 {
298 static const struct inet_diag_bc_op op[] = {
299 {
300 .code = INET_DIAG_BC_S_LE,
301 },
302 {
303 .code = INET_DIAG_BC_DEV_COND,
304 .yes = 0xaf,
305 .no = 0xafcd
306 }
307 };
308
309 char buf[sizeof(op)];
310 memcpy(buf, op, sizeof(op[0]));
311 memcpy(buf + sizeof(op[0]), pattern, sizeof(op[1]));
312
313 const unsigned int plen = sizeof(op[1]) - 1 > DEFAULT_STRLEN ?
314 sizeof(op[0]) + DEFAULT_STRLEN : sizeof(buf) - 1;
315 TEST_NLATTR(fd, nlh0, hdrlen,
316 init_inet_diag_req_v2, print_inet_diag_req_v2,
317 INET_DIAG_REQ_BYTECODE,
318 plen, buf, plen,
319 print_inet_diag_bc_op("INET_DIAG_BC_S_LE");
320 print_quoted_hex(buf + sizeof(op[0]), plen - sizeof(op[0]));
321 printf("}"));
322
323 TEST_NLATTR(fd, nlh0, hdrlen,
324 init_inet_diag_req_v2, print_inet_diag_req_v2,
325 INET_DIAG_REQ_BYTECODE,
326 sizeof(buf), buf, sizeof(buf) - 1,
327 print_inet_diag_bc_op("INET_DIAG_BC_S_LE");
328 printf("%p}", RTA_DATA(TEST_NLATTR_nla) + sizeof(op[0])));
329
330 memcpy(buf + sizeof(op[0]), &op[1], sizeof(op[1]));
331 TEST_NLATTR(fd, nlh0, hdrlen,
332 init_inet_diag_req_v2, print_inet_diag_req_v2,
333 INET_DIAG_REQ_BYTECODE,
334 sizeof(buf), buf, sizeof(buf),
335 print_inet_diag_bc_op("INET_DIAG_BC_S_LE");
336 printf("{code=INET_DIAG_BC_DEV_COND");
337 PRINT_FIELD_U(", ", op[1], yes);
338 PRINT_FIELD_U(", ", op[1], no);
339 printf("}}"));
340 };
341
342 static void
test_inet_diag_bc_mark_cond(const int fd)343 test_inet_diag_bc_mark_cond(const int fd)
344 {
345 static const struct inet_diag_bc_op op = {
346 .code = INET_DIAG_BC_MARK_COND,
347 };
348 static const struct inet_diag_markcond markcond = {
349 .mark = 0xafbcafcd,
350 .mask = 0xbafaacda
351 };
352 char buf[sizeof(op) + sizeof(markcond)];
353 memcpy(buf, &op, sizeof(op));
354 memcpy(buf + sizeof(op), pattern, sizeof(markcond));
355
356 const unsigned int plen = sizeof(markcond) - 1 > DEFAULT_STRLEN ?
357 sizeof(markcond) + DEFAULT_STRLEN : sizeof(buf) - 1;
358 TEST_NLATTR(fd, nlh0, hdrlen,
359 init_inet_diag_req_v2, print_inet_diag_req_v2,
360 INET_DIAG_REQ_BYTECODE,
361 plen, buf, plen,
362 print_inet_diag_bc_op("INET_DIAG_BC_MARK_COND");
363 print_quoted_hex(buf + sizeof(op), plen - sizeof(op));
364 printf("}"));
365
366 TEST_NLATTR(fd, nlh0, hdrlen,
367 init_inet_diag_req_v2, print_inet_diag_req_v2,
368 INET_DIAG_REQ_BYTECODE,
369 sizeof(buf), buf, sizeof(buf) - 1,
370 print_inet_diag_bc_op("INET_DIAG_BC_MARK_COND");
371 printf("%p}", RTA_DATA(TEST_NLATTR_nla) + sizeof(op)));
372
373 memcpy(buf + sizeof(op), &markcond, sizeof(markcond));
374 TEST_NLATTR(fd, nlh0, hdrlen,
375 init_inet_diag_req_v2, print_inet_diag_req_v2,
376 INET_DIAG_REQ_BYTECODE,
377 sizeof(buf), buf, sizeof(buf),
378 print_inet_diag_bc_op("INET_DIAG_BC_MARK_COND");
379 PRINT_FIELD_U("{", markcond, mark);
380 PRINT_FIELD_U(", ", markcond, mask);
381 printf("}}"));
382 }
383
384 static void
test_inet_diag_bc_nop(const int fd)385 test_inet_diag_bc_nop(const int fd)
386 {
387 static const struct inet_diag_bc_op op = {
388 .code = INET_DIAG_BC_AUTO,
389 };
390 char buf[sizeof(op) + 4];
391 memcpy(buf, &op, sizeof(op));
392 memcpy(buf + sizeof(op), pattern, 4);
393
394 TEST_NLATTR(fd, nlh0, hdrlen,
395 init_inet_diag_req_v2, print_inet_diag_req_v2,
396 INET_DIAG_REQ_BYTECODE,
397 sizeof(buf), buf, sizeof(buf),
398 print_inet_diag_bc_op("INET_DIAG_BC_AUTO");
399 print_quoted_hex(buf + sizeof(op),
400 sizeof(buf) - sizeof(op));
401 printf("}"));
402 }
403
404 int
main(void)405 main(void)
406 {
407 skip_if_unavailable("/proc/self/fd/");
408
409 int fd = create_nl_socket(NETLINK_SOCK_DIAG);
410 nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), NLA_HDRLEN +
411 sizeof(struct inet_diag_bc_op) +
412 sizeof(struct inet_diag_hostcond) +
413 sizeof(struct in6_addr) + DEFAULT_STRLEN);
414 fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
415
416 test_inet_diag_bc_op(fd);
417 test_inet_diag_bc_s_cond(fd);
418 test_in_addr(fd);
419 test_in6_addr(fd);
420 test_inet_diag_bc_dev_cond(fd);
421 test_inet_diag_bc_s_le(fd);
422 test_inet_diag_bc_mark_cond(fd);
423 test_inet_diag_bc_nop(fd);
424
425 printf("+++ exited with 0 +++\n");
426 return 0;
427 }
428