1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 #include <sched.h>
5 
6 #include <stddef.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 
10 #include <sys/socket.h>
11 #include <sys/un.h>
12 
13 #include "../../kselftest_harness.h"
14 
15 FIXTURE(unix_connect)
16 {
17 	int server, client;
18 	int family;
19 };
20 
21 FIXTURE_VARIANT(unix_connect)
22 {
23 	int type;
24 	char sun_path[8];
25 	int len;
26 	int flags;
27 	int err;
28 };
29 
30 FIXTURE_VARIANT_ADD(unix_connect, stream_pathname)
31 {
32 	.type = SOCK_STREAM,
33 	.sun_path = "test",
34 	.len = 4 + 1,
35 	.flags = 0,
36 	.err = 0,
37 };
38 
39 FIXTURE_VARIANT_ADD(unix_connect, stream_abstract)
40 {
41 	.type = SOCK_STREAM,
42 	.sun_path = "\0test",
43 	.len = 5,
44 	.flags = 0,
45 	.err = 0,
46 };
47 
48 FIXTURE_VARIANT_ADD(unix_connect, stream_pathname_netns)
49 {
50 	.type = SOCK_STREAM,
51 	.sun_path = "test",
52 	.len = 4 + 1,
53 	.flags = CLONE_NEWNET,
54 	.err = 0,
55 };
56 
57 FIXTURE_VARIANT_ADD(unix_connect, stream_abstract_netns)
58 {
59 	.type = SOCK_STREAM,
60 	.sun_path = "\0test",
61 	.len = 5,
62 	.flags = CLONE_NEWNET,
63 	.err = ECONNREFUSED,
64 };
65 
66 FIXTURE_VARIANT_ADD(unix_connect, dgram_pathname)
67 {
68 	.type = SOCK_DGRAM,
69 	.sun_path = "test",
70 	.len = 4 + 1,
71 	.flags = 0,
72 	.err = 0,
73 };
74 
75 FIXTURE_VARIANT_ADD(unix_connect, dgram_abstract)
76 {
77 	.type = SOCK_DGRAM,
78 	.sun_path = "\0test",
79 	.len = 5,
80 	.flags = 0,
81 	.err = 0,
82 };
83 
84 FIXTURE_VARIANT_ADD(unix_connect, dgram_pathname_netns)
85 {
86 	.type = SOCK_DGRAM,
87 	.sun_path = "test",
88 	.len = 4 + 1,
89 	.flags = CLONE_NEWNET,
90 	.err = 0,
91 };
92 
93 FIXTURE_VARIANT_ADD(unix_connect, dgram_abstract_netns)
94 {
95 	.type = SOCK_DGRAM,
96 	.sun_path = "\0test",
97 	.len = 5,
98 	.flags = CLONE_NEWNET,
99 	.err = ECONNREFUSED,
100 };
101 
102 FIXTURE_SETUP(unix_connect)
103 {
104 	self->family = AF_UNIX;
105 }
106 
107 FIXTURE_TEARDOWN(unix_connect)
108 {
109 	close(self->server);
110 	close(self->client);
111 
112 	if (variant->sun_path[0])
113 		remove("test");
114 }
115 
116 TEST_F(unix_connect, test)
117 {
118 	socklen_t addrlen;
119 	struct sockaddr_un addr = {
120 		.sun_family = self->family,
121 	};
122 	int err;
123 
124 	self->server = socket(self->family, variant->type, 0);
125 	ASSERT_NE(-1, self->server);
126 
127 	addrlen = offsetof(struct sockaddr_un, sun_path) + variant->len;
128 	memcpy(&addr.sun_path, variant->sun_path, variant->len);
129 
130 	err = bind(self->server, (struct sockaddr *)&addr, addrlen);
131 	ASSERT_EQ(0, err);
132 
133 	if (variant->type == SOCK_STREAM) {
134 		err = listen(self->server, 32);
135 		ASSERT_EQ(0, err);
136 	}
137 
138 	err = unshare(variant->flags);
139 	ASSERT_EQ(0, err);
140 
141 	self->client = socket(self->family, variant->type, 0);
142 	ASSERT_LT(0, self->client);
143 
144 	err = connect(self->client, (struct sockaddr *)&addr, addrlen);
145 	ASSERT_EQ(variant->err, err == -1 ? errno : 0);
146 }
147 
148 TEST_HARNESS_MAIN
149