1a999696cSStanislav Fomichev // SPDX-License-Identifier: GPL-2.0
2a999696cSStanislav Fomichev
3a999696cSStanislav Fomichev #include <string.h>
4a999696cSStanislav Fomichev
5a999696cSStanislav Fomichev #include <linux/stddef.h>
6a999696cSStanislav Fomichev #include <linux/bpf.h>
7a999696cSStanislav Fomichev #include <linux/in.h>
8a999696cSStanislav Fomichev #include <linux/in6.h>
9a999696cSStanislav Fomichev #include <linux/if.h>
10a999696cSStanislav Fomichev #include <errno.h>
11a999696cSStanislav Fomichev
12a999696cSStanislav Fomichev #include <bpf/bpf_helpers.h>
13a999696cSStanislav Fomichev #include <bpf/bpf_endian.h>
14a999696cSStanislav Fomichev
15a999696cSStanislav Fomichev #define SERV6_IP_0 0xfaceb00c /* face:b00c:1234:5678::abcd */
16a999696cSStanislav Fomichev #define SERV6_IP_1 0x12345678
17a999696cSStanislav Fomichev #define SERV6_IP_2 0x00000000
18a999696cSStanislav Fomichev #define SERV6_IP_3 0x0000abcd
19a999696cSStanislav Fomichev #define SERV6_PORT 6060
20a999696cSStanislav Fomichev #define SERV6_REWRITE_IP_0 0x00000000
21a999696cSStanislav Fomichev #define SERV6_REWRITE_IP_1 0x00000000
22a999696cSStanislav Fomichev #define SERV6_REWRITE_IP_2 0x00000000
23a999696cSStanislav Fomichev #define SERV6_REWRITE_IP_3 0x00000001
24a999696cSStanislav Fomichev #define SERV6_REWRITE_PORT 6666
25a999696cSStanislav Fomichev
26a540c81aSStanislav Fomichev #ifndef IFNAMSIZ
27a540c81aSStanislav Fomichev #define IFNAMSIZ 16
28a540c81aSStanislav Fomichev #endif
29a540c81aSStanislav Fomichev
bind_to_device(struct bpf_sock_addr * ctx)30a540c81aSStanislav Fomichev static __inline int bind_to_device(struct bpf_sock_addr *ctx)
31a540c81aSStanislav Fomichev {
32a540c81aSStanislav Fomichev char veth1[IFNAMSIZ] = "test_sock_addr1";
33a540c81aSStanislav Fomichev char veth2[IFNAMSIZ] = "test_sock_addr2";
34a540c81aSStanislav Fomichev char missing[IFNAMSIZ] = "nonexistent_dev";
35a540c81aSStanislav Fomichev char del_bind[IFNAMSIZ] = "";
363218231dSDaniel Borkmann int veth1_idx, veth2_idx;
37a540c81aSStanislav Fomichev
38a540c81aSStanislav Fomichev if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
39a540c81aSStanislav Fomichev &veth1, sizeof(veth1)))
40a540c81aSStanislav Fomichev return 1;
413218231dSDaniel Borkmann if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
423218231dSDaniel Borkmann &veth1_idx, sizeof(veth1_idx)) || !veth1_idx)
433218231dSDaniel Borkmann return 1;
44a540c81aSStanislav Fomichev if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
45a540c81aSStanislav Fomichev &veth2, sizeof(veth2)))
46a540c81aSStanislav Fomichev return 1;
473218231dSDaniel Borkmann if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
483218231dSDaniel Borkmann &veth2_idx, sizeof(veth2_idx)) || !veth2_idx ||
493218231dSDaniel Borkmann veth1_idx == veth2_idx)
503218231dSDaniel Borkmann return 1;
51a540c81aSStanislav Fomichev if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
52a540c81aSStanislav Fomichev &missing, sizeof(missing)) != -ENODEV)
53a540c81aSStanislav Fomichev return 1;
543218231dSDaniel Borkmann if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
553218231dSDaniel Borkmann &veth1_idx, sizeof(veth1_idx)))
563218231dSDaniel Borkmann return 1;
57a540c81aSStanislav Fomichev if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
58a540c81aSStanislav Fomichev &del_bind, sizeof(del_bind)))
59a540c81aSStanislav Fomichev return 1;
60a540c81aSStanislav Fomichev
61a540c81aSStanislav Fomichev return 0;
62a540c81aSStanislav Fomichev }
63a540c81aSStanislav Fomichev
bind_reuseport(struct bpf_sock_addr * ctx)64*6503b9f2SManu Bretelle static __inline int bind_reuseport(struct bpf_sock_addr *ctx)
65*6503b9f2SManu Bretelle {
66*6503b9f2SManu Bretelle int val = 1;
67*6503b9f2SManu Bretelle
68*6503b9f2SManu Bretelle if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
69*6503b9f2SManu Bretelle &val, sizeof(val)))
70*6503b9f2SManu Bretelle return 1;
71*6503b9f2SManu Bretelle if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
72*6503b9f2SManu Bretelle &val, sizeof(val)) || !val)
73*6503b9f2SManu Bretelle return 1;
74*6503b9f2SManu Bretelle val = 0;
75*6503b9f2SManu Bretelle if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
76*6503b9f2SManu Bretelle &val, sizeof(val)))
77*6503b9f2SManu Bretelle return 1;
78*6503b9f2SManu Bretelle if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
79*6503b9f2SManu Bretelle &val, sizeof(val)) || val)
80*6503b9f2SManu Bretelle return 1;
81*6503b9f2SManu Bretelle
82*6503b9f2SManu Bretelle return 0;
83*6503b9f2SManu Bretelle }
84*6503b9f2SManu Bretelle
misc_opts(struct bpf_sock_addr * ctx,int opt)853218231dSDaniel Borkmann static __inline int misc_opts(struct bpf_sock_addr *ctx, int opt)
863218231dSDaniel Borkmann {
873218231dSDaniel Borkmann int old, tmp, new = 0xeb9f;
883218231dSDaniel Borkmann
893218231dSDaniel Borkmann /* Socket in test case has guarantee that old never equals to new. */
903218231dSDaniel Borkmann if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)) ||
913218231dSDaniel Borkmann old == new)
923218231dSDaniel Borkmann return 1;
933218231dSDaniel Borkmann if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &new, sizeof(new)))
943218231dSDaniel Borkmann return 1;
953218231dSDaniel Borkmann if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &tmp, sizeof(tmp)) ||
963218231dSDaniel Borkmann tmp != new)
973218231dSDaniel Borkmann return 1;
983218231dSDaniel Borkmann if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)))
993218231dSDaniel Borkmann return 1;
1003218231dSDaniel Borkmann
1013218231dSDaniel Borkmann return 0;
1023218231dSDaniel Borkmann }
1033218231dSDaniel Borkmann
104a999696cSStanislav Fomichev SEC("cgroup/bind6")
bind_v6_prog(struct bpf_sock_addr * ctx)105a999696cSStanislav Fomichev int bind_v6_prog(struct bpf_sock_addr *ctx)
106a999696cSStanislav Fomichev {
107a999696cSStanislav Fomichev struct bpf_sock *sk;
108a999696cSStanislav Fomichev __u32 user_ip6;
109a999696cSStanislav Fomichev __u16 user_port;
110a999696cSStanislav Fomichev int i;
111a999696cSStanislav Fomichev
112a999696cSStanislav Fomichev sk = ctx->sk;
113a999696cSStanislav Fomichev if (!sk)
114a999696cSStanislav Fomichev return 0;
115a999696cSStanislav Fomichev
116a999696cSStanislav Fomichev if (sk->family != AF_INET6)
117a999696cSStanislav Fomichev return 0;
118a999696cSStanislav Fomichev
119a999696cSStanislav Fomichev if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
120a999696cSStanislav Fomichev return 0;
121a999696cSStanislav Fomichev
122a999696cSStanislav Fomichev if (ctx->user_ip6[0] != bpf_htonl(SERV6_IP_0) ||
123a999696cSStanislav Fomichev ctx->user_ip6[1] != bpf_htonl(SERV6_IP_1) ||
124a999696cSStanislav Fomichev ctx->user_ip6[2] != bpf_htonl(SERV6_IP_2) ||
125a999696cSStanislav Fomichev ctx->user_ip6[3] != bpf_htonl(SERV6_IP_3) ||
126a999696cSStanislav Fomichev ctx->user_port != bpf_htons(SERV6_PORT))
127a999696cSStanislav Fomichev return 0;
128a999696cSStanislav Fomichev
129a999696cSStanislav Fomichev // u8 narrow loads:
130a999696cSStanislav Fomichev for (i = 0; i < 4; i++) {
131a999696cSStanislav Fomichev user_ip6 = 0;
132a999696cSStanislav Fomichev user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[0] << 0;
133a999696cSStanislav Fomichev user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[1] << 8;
134a999696cSStanislav Fomichev user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[2] << 16;
135a999696cSStanislav Fomichev user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[3] << 24;
136a999696cSStanislav Fomichev if (ctx->user_ip6[i] != user_ip6)
137a999696cSStanislav Fomichev return 0;
138a999696cSStanislav Fomichev }
139a999696cSStanislav Fomichev
140a999696cSStanislav Fomichev user_port = 0;
141a999696cSStanislav Fomichev user_port |= ((volatile __u8 *)&ctx->user_port)[0] << 0;
142a999696cSStanislav Fomichev user_port |= ((volatile __u8 *)&ctx->user_port)[1] << 8;
143a999696cSStanislav Fomichev if (ctx->user_port != user_port)
144a999696cSStanislav Fomichev return 0;
145a999696cSStanislav Fomichev
146a999696cSStanislav Fomichev // u16 narrow loads:
147a999696cSStanislav Fomichev for (i = 0; i < 4; i++) {
148a999696cSStanislav Fomichev user_ip6 = 0;
149a999696cSStanislav Fomichev user_ip6 |= ((volatile __u16 *)&ctx->user_ip6[i])[0] << 0;
150a999696cSStanislav Fomichev user_ip6 |= ((volatile __u16 *)&ctx->user_ip6[i])[1] << 16;
151a999696cSStanislav Fomichev if (ctx->user_ip6[i] != user_ip6)
152a999696cSStanislav Fomichev return 0;
153a999696cSStanislav Fomichev }
154a999696cSStanislav Fomichev
155a540c81aSStanislav Fomichev /* Bind to device and unbind it. */
156a540c81aSStanislav Fomichev if (bind_to_device(ctx))
157a540c81aSStanislav Fomichev return 0;
158a540c81aSStanislav Fomichev
1593218231dSDaniel Borkmann /* Test for misc socket options. */
1603218231dSDaniel Borkmann if (misc_opts(ctx, SO_MARK) || misc_opts(ctx, SO_PRIORITY))
1613218231dSDaniel Borkmann return 0;
1623218231dSDaniel Borkmann
163*6503b9f2SManu Bretelle /* Set reuseport and unset */
164*6503b9f2SManu Bretelle if (bind_reuseport(ctx))
165*6503b9f2SManu Bretelle return 0;
166*6503b9f2SManu Bretelle
167a999696cSStanislav Fomichev ctx->user_ip6[0] = bpf_htonl(SERV6_REWRITE_IP_0);
168a999696cSStanislav Fomichev ctx->user_ip6[1] = bpf_htonl(SERV6_REWRITE_IP_1);
169a999696cSStanislav Fomichev ctx->user_ip6[2] = bpf_htonl(SERV6_REWRITE_IP_2);
170a999696cSStanislav Fomichev ctx->user_ip6[3] = bpf_htonl(SERV6_REWRITE_IP_3);
171a999696cSStanislav Fomichev ctx->user_port = bpf_htons(SERV6_REWRITE_PORT);
172a999696cSStanislav Fomichev
173a999696cSStanislav Fomichev return 1;
174a999696cSStanislav Fomichev }
175a999696cSStanislav Fomichev
176a999696cSStanislav Fomichev char _license[] SEC("license") = "GPL";
177