@@ -35,12 +35,15 @@ struct sock_test {
3535 /* Endpoint to bind() to */
3636 const char * ip ;
3737 unsigned short port ;
38+ unsigned short port_retry ;
3839 /* Expected test result */
3940 enum {
4041 LOAD_REJECT ,
4142 ATTACH_REJECT ,
4243 BIND_REJECT ,
4344 SUCCESS ,
45+ RETRY_SUCCESS ,
46+ RETRY_REJECT
4447 } result ;
4548};
4649
@@ -60,6 +63,7 @@ static struct sock_test tests[] = {
6063 0 ,
6164 NULL ,
6265 0 ,
66+ 0 ,
6367 LOAD_REJECT ,
6468 },
6569 {
@@ -77,6 +81,7 @@ static struct sock_test tests[] = {
7781 0 ,
7882 NULL ,
7983 0 ,
84+ 0 ,
8085 LOAD_REJECT ,
8186 },
8287 {
@@ -94,6 +99,7 @@ static struct sock_test tests[] = {
9499 0 ,
95100 NULL ,
96101 0 ,
102+ 0 ,
97103 LOAD_REJECT ,
98104 },
99105 {
@@ -111,6 +117,7 @@ static struct sock_test tests[] = {
111117 0 ,
112118 NULL ,
113119 0 ,
120+ 0 ,
114121 LOAD_REJECT ,
115122 },
116123 {
@@ -125,6 +132,7 @@ static struct sock_test tests[] = {
125132 SOCK_STREAM ,
126133 "127.0.0.1" ,
127134 8097 ,
135+ 0 ,
128136 SUCCESS ,
129137 },
130138 {
@@ -139,6 +147,7 @@ static struct sock_test tests[] = {
139147 SOCK_STREAM ,
140148 "127.0.0.1" ,
141149 8097 ,
150+ 0 ,
142151 SUCCESS ,
143152 },
144153 {
@@ -153,6 +162,7 @@ static struct sock_test tests[] = {
153162 0 ,
154163 NULL ,
155164 0 ,
165+ 0 ,
156166 ATTACH_REJECT ,
157167 },
158168 {
@@ -167,6 +177,7 @@ static struct sock_test tests[] = {
167177 0 ,
168178 NULL ,
169179 0 ,
180+ 0 ,
170181 ATTACH_REJECT ,
171182 },
172183 {
@@ -181,6 +192,7 @@ static struct sock_test tests[] = {
181192 0 ,
182193 NULL ,
183194 0 ,
195+ 0 ,
184196 ATTACH_REJECT ,
185197 },
186198 {
@@ -195,6 +207,7 @@ static struct sock_test tests[] = {
195207 0 ,
196208 NULL ,
197209 0 ,
210+ 0 ,
198211 ATTACH_REJECT ,
199212 },
200213 {
@@ -209,6 +222,7 @@ static struct sock_test tests[] = {
209222 SOCK_STREAM ,
210223 "0.0.0.0" ,
211224 0 ,
225+ 0 ,
212226 BIND_REJECT ,
213227 },
214228 {
@@ -223,6 +237,7 @@ static struct sock_test tests[] = {
223237 SOCK_STREAM ,
224238 "::" ,
225239 0 ,
240+ 0 ,
226241 BIND_REJECT ,
227242 },
228243 {
@@ -253,6 +268,7 @@ static struct sock_test tests[] = {
253268 SOCK_STREAM ,
254269 "::1" ,
255270 8193 ,
271+ 0 ,
256272 BIND_REJECT ,
257273 },
258274 {
@@ -283,8 +299,102 @@ static struct sock_test tests[] = {
283299 SOCK_STREAM ,
284300 "127.0.0.1" ,
285301 4098 ,
302+ 0 ,
286303 SUCCESS ,
287304 },
305+ {
306+ "bind4 deny specific IP & port of TCP, and retry" ,
307+ .insns = {
308+ BPF_MOV64_REG (BPF_REG_6 , BPF_REG_1 ),
309+
310+ /* if (ip == expected && port == expected) */
311+ BPF_LDX_MEM (BPF_W , BPF_REG_7 , BPF_REG_6 ,
312+ offsetof(struct bpf_sock , src_ip4 )),
313+ BPF_JMP_IMM (BPF_JNE , BPF_REG_7 ,
314+ __bpf_constant_ntohl (0x7F000001 ), 4 ),
315+ BPF_LDX_MEM (BPF_W , BPF_REG_7 , BPF_REG_6 ,
316+ offsetof(struct bpf_sock , src_port )),
317+ BPF_JMP_IMM (BPF_JNE , BPF_REG_7 , 0x1002 , 2 ),
318+
319+ /* return DENY; */
320+ BPF_MOV64_IMM (BPF_REG_0 , 0 ),
321+ BPF_JMP_A (1 ),
322+
323+ /* else return ALLOW; */
324+ BPF_MOV64_IMM (BPF_REG_0 , 1 ),
325+ BPF_EXIT_INSN (),
326+ },
327+ BPF_CGROUP_INET4_POST_BIND ,
328+ BPF_CGROUP_INET4_POST_BIND ,
329+ AF_INET ,
330+ SOCK_STREAM ,
331+ "127.0.0.1" ,
332+ 4098 ,
333+ 5000 ,
334+ RETRY_SUCCESS ,
335+ },
336+ {
337+ "bind4 deny specific IP & port of UDP, and retry" ,
338+ .insns = {
339+ BPF_MOV64_REG (BPF_REG_6 , BPF_REG_1 ),
340+
341+ /* if (ip == expected && port == expected) */
342+ BPF_LDX_MEM (BPF_W , BPF_REG_7 , BPF_REG_6 ,
343+ offsetof(struct bpf_sock , src_ip4 )),
344+ BPF_JMP_IMM (BPF_JNE , BPF_REG_7 ,
345+ __bpf_constant_ntohl (0x7F000001 ), 4 ),
346+ BPF_LDX_MEM (BPF_W , BPF_REG_7 , BPF_REG_6 ,
347+ offsetof(struct bpf_sock , src_port )),
348+ BPF_JMP_IMM (BPF_JNE , BPF_REG_7 , 0x1002 , 2 ),
349+
350+ /* return DENY; */
351+ BPF_MOV64_IMM (BPF_REG_0 , 0 ),
352+ BPF_JMP_A (1 ),
353+
354+ /* else return ALLOW; */
355+ BPF_MOV64_IMM (BPF_REG_0 , 1 ),
356+ BPF_EXIT_INSN (),
357+ },
358+ BPF_CGROUP_INET4_POST_BIND ,
359+ BPF_CGROUP_INET4_POST_BIND ,
360+ AF_INET ,
361+ SOCK_DGRAM ,
362+ "127.0.0.1" ,
363+ 4098 ,
364+ 5000 ,
365+ RETRY_SUCCESS ,
366+ },
367+ {
368+ "bind6 deny specific IP & port, and retry" ,
369+ .insns = {
370+ BPF_MOV64_REG (BPF_REG_6 , BPF_REG_1 ),
371+
372+ /* if (ip == expected && port == expected) */
373+ BPF_LDX_MEM (BPF_W , BPF_REG_7 , BPF_REG_6 ,
374+ offsetof(struct bpf_sock , src_ip6 [3 ])),
375+ BPF_JMP_IMM (BPF_JNE , BPF_REG_7 ,
376+ __bpf_constant_ntohl (0x00000001 ), 4 ),
377+ BPF_LDX_MEM (BPF_W , BPF_REG_7 , BPF_REG_6 ,
378+ offsetof(struct bpf_sock , src_port )),
379+ BPF_JMP_IMM (BPF_JNE , BPF_REG_7 , 0x2001 , 2 ),
380+
381+ /* return DENY; */
382+ BPF_MOV64_IMM (BPF_REG_0 , 0 ),
383+ BPF_JMP_A (1 ),
384+
385+ /* else return ALLOW; */
386+ BPF_MOV64_IMM (BPF_REG_0 , 1 ),
387+ BPF_EXIT_INSN (),
388+ },
389+ BPF_CGROUP_INET6_POST_BIND ,
390+ BPF_CGROUP_INET6_POST_BIND ,
391+ AF_INET6 ,
392+ SOCK_STREAM ,
393+ "::1" ,
394+ 8193 ,
395+ 9000 ,
396+ RETRY_SUCCESS ,
397+ },
288398 {
289399 "bind4 allow all" ,
290400 .insns = {
@@ -297,6 +407,7 @@ static struct sock_test tests[] = {
297407 SOCK_STREAM ,
298408 "0.0.0.0" ,
299409 0 ,
410+ 0 ,
300411 SUCCESS ,
301412 },
302413 {
@@ -311,6 +422,7 @@ static struct sock_test tests[] = {
311422 SOCK_STREAM ,
312423 "::" ,
313424 0 ,
425+ 0 ,
314426 SUCCESS ,
315427 },
316428};
@@ -351,14 +463,15 @@ static int attach_sock_prog(int cgfd, int progfd,
351463 return bpf_prog_attach (progfd , cgfd , attach_type , BPF_F_ALLOW_OVERRIDE );
352464}
353465
354- static int bind_sock (int domain , int type , const char * ip , unsigned short port )
466+ static int bind_sock (int domain , int type , const char * ip ,
467+ unsigned short port , unsigned short port_retry )
355468{
356469 struct sockaddr_storage addr ;
357470 struct sockaddr_in6 * addr6 ;
358471 struct sockaddr_in * addr4 ;
359472 int sockfd = -1 ;
360473 socklen_t len ;
361- int err = 0 ;
474+ int res = SUCCESS ;
362475
363476 sockfd = socket (domain , type , 0 );
364477 if (sockfd < 0 )
@@ -384,21 +497,44 @@ static int bind_sock(int domain, int type, const char *ip, unsigned short port)
384497 goto err ;
385498 }
386499
387- if (bind (sockfd , (const struct sockaddr * )& addr , len ) == -1 )
388- goto err ;
500+ if (bind (sockfd , (const struct sockaddr * )& addr , len ) == -1 ) {
501+ /* sys_bind() may fail for different reasons, errno has to be
502+ * checked to confirm that BPF program rejected it.
503+ */
504+ if (errno != EPERM )
505+ goto err ;
506+ if (port_retry )
507+ goto retry ;
508+ res = BIND_REJECT ;
509+ goto out ;
510+ }
389511
512+ goto out ;
513+ retry :
514+ if (domain == AF_INET )
515+ addr4 -> sin_port = htons (port_retry );
516+ else
517+ addr6 -> sin6_port = htons (port_retry );
518+ if (bind (sockfd , (const struct sockaddr * )& addr , len ) == -1 ) {
519+ if (errno != EPERM )
520+ goto err ;
521+ res = RETRY_REJECT ;
522+ } else {
523+ res = RETRY_SUCCESS ;
524+ }
390525 goto out ;
391526err :
392- err = -1 ;
527+ res = -1 ;
393528out :
394529 close (sockfd );
395- return err ;
530+ return res ;
396531}
397532
398533static int run_test_case (int cgfd , const struct sock_test * test )
399534{
400535 int progfd = -1 ;
401536 int err = 0 ;
537+ int res ;
402538
403539 printf ("Test case: %s .. " , test -> descr );
404540 progfd = load_sock_prog (test -> insns , test -> expected_attach_type );
@@ -416,21 +552,11 @@ static int run_test_case(int cgfd, const struct sock_test *test)
416552 goto err ;
417553 }
418554
419- if (bind_sock (test -> domain , test -> type , test -> ip , test -> port ) == -1 ) {
420- /* sys_bind() may fail for different reasons, errno has to be
421- * checked to confirm that BPF program rejected it.
422- */
423- if (test -> result == BIND_REJECT && errno == EPERM )
424- goto out ;
425- else
426- goto err ;
427- }
428-
555+ res = bind_sock (test -> domain , test -> type , test -> ip , test -> port ,
556+ test -> port_retry );
557+ if (res > 0 && test -> result == res )
558+ goto out ;
429559
430- if (test -> result != SUCCESS )
431- goto err ;
432-
433- goto out ;
434560err :
435561 err = -1 ;
436562out :
0 commit comments