1/*
2 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
3 * Copyright (c) 2017 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
42static const char address[] = "10.11.12.13";
43static const unsigned int hdrlen = sizeof(struct inet_diag_req_v2);
44static void *nlh0;
45static char pattern[4096];
46
47static void
48init_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
70static void
71print_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
86static void
87test_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
103static void
104print_inet_diag_bc_op(const char *const code)
105{
106	printf("{{code=%s, yes=0, no=0}, ", code);
107}
108
109static void
110test_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
153static void
154print_inet_diag_hostcond(const char *const family)
155{
156	printf("{family=%s, prefix_len=0, port=0, ", family);
157}
158
159static void
160test_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
209static void
210test_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
260static void
261test_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
295static void
296test_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
342static void
343test_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
384static void
385test_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
404int
405main(void)
406{
407	skip_if_unavailable("/proc/self/fd/");
408
409	int fd = create_nl_socket(NETLINK_SOCK_DIAG);
410	nlh0 = tail_alloc(NLMSG_SPACE(hdrlen));
411	fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
412
413	test_inet_diag_bc_op(fd);
414	test_inet_diag_bc_s_cond(fd);
415	test_in_addr(fd);
416	test_in6_addr(fd);
417	test_inet_diag_bc_dev_cond(fd);
418	test_inet_diag_bc_s_le(fd);
419	test_inet_diag_bc_mark_cond(fd);
420	test_inet_diag_bc_nop(fd);
421
422	printf("+++ exited with 0 +++\n");
423	return 0;
424}
425