1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <test_progs.h>
4 #include "cgroup_helpers.h"
5 #include "network_helpers.h"
6 
7 static int verify_ports(int family, int fd,
8 			__u16 expected_local, __u16 expected_peer)
9 {
10 	struct sockaddr_storage addr;
11 	socklen_t len = sizeof(addr);
12 	__u16 port;
13 
14 	if (getsockname(fd, (struct sockaddr *)&addr, &len)) {
15 		log_err("Failed to get server addr");
16 		return -1;
17 	}
18 
19 	if (family == AF_INET)
20 		port = ((struct sockaddr_in *)&addr)->sin_port;
21 	else
22 		port = ((struct sockaddr_in6 *)&addr)->sin6_port;
23 
24 	if (ntohs(port) != expected_local) {
25 		log_err("Unexpected local port %d, expected %d", ntohs(port),
26 			expected_local);
27 		return -1;
28 	}
29 
30 	if (getpeername(fd, (struct sockaddr *)&addr, &len)) {
31 		log_err("Failed to get peer addr");
32 		return -1;
33 	}
34 
35 	if (family == AF_INET)
36 		port = ((struct sockaddr_in *)&addr)->sin_port;
37 	else
38 		port = ((struct sockaddr_in6 *)&addr)->sin6_port;
39 
40 	if (ntohs(port) != expected_peer) {
41 		log_err("Unexpected peer port %d, expected %d", ntohs(port),
42 			expected_peer);
43 		return -1;
44 	}
45 
46 	return 0;
47 }
48 
49 static int run_test(int cgroup_fd, int server_fd, int family, int type)
50 {
51 	bool v4 = family == AF_INET;
52 	__u16 expected_local_port = v4 ? 22222 : 22223;
53 	__u16 expected_peer_port = 60000;
54 	struct bpf_program *prog;
55 	struct bpf_object *obj;
56 	const char *obj_file = v4 ? "connect_force_port4.bpf.o" : "connect_force_port6.bpf.o";
57 	int fd, err;
58 	__u32 duration = 0;
59 
60 	obj = bpf_object__open_file(obj_file, NULL);
61 	if (!ASSERT_OK_PTR(obj, "bpf_obj_open"))
62 		return -1;
63 
64 	err = bpf_object__load(obj);
65 	if (!ASSERT_OK(err, "bpf_obj_load")) {
66 		err = -EIO;
67 		goto close_bpf_object;
68 	}
69 
70 	prog = bpf_object__find_program_by_name(obj, v4 ?
71 						"connect4" :
72 						"connect6");
73 	if (CHECK(!prog, "find_prog", "connect prog not found\n")) {
74 		err = -EIO;
75 		goto close_bpf_object;
76 	}
77 
78 	err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
79 			      BPF_CGROUP_INET4_CONNECT :
80 			      BPF_CGROUP_INET6_CONNECT, 0);
81 	if (err) {
82 		log_err("Failed to attach BPF program");
83 		goto close_bpf_object;
84 	}
85 
86 	prog = bpf_object__find_program_by_name(obj, v4 ?
87 						"getpeername4" :
88 						"getpeername6");
89 	if (CHECK(!prog, "find_prog", "getpeername prog not found\n")) {
90 		err = -EIO;
91 		goto close_bpf_object;
92 	}
93 
94 	err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
95 			      BPF_CGROUP_INET4_GETPEERNAME :
96 			      BPF_CGROUP_INET6_GETPEERNAME, 0);
97 	if (err) {
98 		log_err("Failed to attach BPF program");
99 		goto close_bpf_object;
100 	}
101 
102 	prog = bpf_object__find_program_by_name(obj, v4 ?
103 						"getsockname4" :
104 						"getsockname6");
105 	if (CHECK(!prog, "find_prog", "getsockname prog not found\n")) {
106 		err = -EIO;
107 		goto close_bpf_object;
108 	}
109 
110 	err = bpf_prog_attach(bpf_program__fd(prog), cgroup_fd, v4 ?
111 			      BPF_CGROUP_INET4_GETSOCKNAME :
112 			      BPF_CGROUP_INET6_GETSOCKNAME, 0);
113 	if (err) {
114 		log_err("Failed to attach BPF program");
115 		goto close_bpf_object;
116 	}
117 
118 	fd = connect_to_fd(server_fd, 0);
119 	if (fd < 0) {
120 		err = -1;
121 		goto close_bpf_object;
122 	}
123 
124 	err = verify_ports(family, fd, expected_local_port,
125 			   expected_peer_port);
126 	close(fd);
127 
128 close_bpf_object:
129 	bpf_object__close(obj);
130 	return err;
131 }
132 
133 void test_connect_force_port(void)
134 {
135 	int server_fd, cgroup_fd;
136 
137 	cgroup_fd = test__join_cgroup("/connect_force_port");
138 	if (CHECK_FAIL(cgroup_fd < 0))
139 		return;
140 
141 	server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 60123, 0);
142 	if (CHECK_FAIL(server_fd < 0))
143 		goto close_cgroup_fd;
144 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_STREAM));
145 	close(server_fd);
146 
147 	server_fd = start_server(AF_INET6, SOCK_STREAM, NULL, 60124, 0);
148 	if (CHECK_FAIL(server_fd < 0))
149 		goto close_cgroup_fd;
150 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_STREAM));
151 	close(server_fd);
152 
153 	server_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 60123, 0);
154 	if (CHECK_FAIL(server_fd < 0))
155 		goto close_cgroup_fd;
156 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET, SOCK_DGRAM));
157 	close(server_fd);
158 
159 	server_fd = start_server(AF_INET6, SOCK_DGRAM, NULL, 60124, 0);
160 	if (CHECK_FAIL(server_fd < 0))
161 		goto close_cgroup_fd;
162 	CHECK_FAIL(run_test(cgroup_fd, server_fd, AF_INET6, SOCK_DGRAM));
163 	close(server_fd);
164 
165 close_cgroup_fd:
166 	close(cgroup_fd);
167 }
168