1
2#include <string.h>
3#include <linux/tcp.h>
4#include <linux/bpf.h>
5#include <netinet/in.h>
6#include <bpf/bpf_helpers.h>
7
8char _license[] SEC("license") = "GPL";
9
10int page_size = 0;
11
12#ifndef SOL_TCP
13#define SOL_TCP IPPROTO_TCP
14#endif
15
16#define SOL_CUSTOM 0xdeadbeef
17
18struct sockopt_sk {
19 __u8 val;
20};
21
22struct {
23 __uint(type, BPF_MAP_TYPE_SK_STORAGE);
24 __uint(map_flags, BPF_F_NO_PREALLOC);
25 __type(key, int);
26 __type(value, struct sockopt_sk);
27} socket_storage_map SEC(".maps");
28
29SEC("cgroup/getsockopt")
30int _getsockopt(struct bpf_sockopt *ctx)
31{
32 __u8 *optval_end = ctx->optval_end;
33 __u8 *optval = ctx->optval;
34 struct sockopt_sk *storage;
35
36 if (ctx->level == SOL_IP && ctx->optname == IP_TOS) {
37
38
39
40
41 ctx->optlen = 0;
42 return 1;
43 }
44
45 if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) {
46
47
48
49
50 return 1;
51 }
52
53 if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) {
54
55
56
57
58 return 1;
59 }
60
61 if (ctx->level == SOL_TCP && ctx->optname == TCP_ZEROCOPY_RECEIVE) {
62
63
64
65
66
67 if (optval + sizeof(struct tcp_zerocopy_receive) > optval_end)
68 return 0;
69
70 if (((struct tcp_zerocopy_receive *)optval)->address != 0)
71 return 0;
72
73 return 1;
74 }
75
76 if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) {
77 if (optval + 1 > optval_end)
78 return 0;
79
80 ctx->retval = 0;
81
82
83 optval[0] = 0x55;
84 ctx->optlen = 1;
85
86
87
88
89
90 if (optval_end - optval != page_size)
91 return 0;
92
93 return 1;
94 }
95
96 if (ctx->level != SOL_CUSTOM)
97 return 0;
98
99 if (optval + 1 > optval_end)
100 return 0;
101
102 storage = bpf_sk_storage_get(&socket_storage_map, ctx->sk, 0,
103 BPF_SK_STORAGE_GET_F_CREATE);
104 if (!storage)
105 return 0;
106
107 if (!ctx->retval)
108 return 0;
109
110
111 ctx->retval = 0;
112
113 optval[0] = storage->val;
114 ctx->optlen = 1;
115
116 return 1;
117}
118
119SEC("cgroup/setsockopt")
120int _setsockopt(struct bpf_sockopt *ctx)
121{
122 __u8 *optval_end = ctx->optval_end;
123 __u8 *optval = ctx->optval;
124 struct sockopt_sk *storage;
125
126 if (ctx->level == SOL_IP && ctx->optname == IP_TOS) {
127
128
129
130
131 ctx->optlen = 0;
132 return 1;
133 }
134
135 if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) {
136
137
138 if (optval + sizeof(__u32) > optval_end)
139 return 0;
140
141 *(__u32 *)optval = 0x55AA;
142 ctx->optlen = 4;
143
144 return 1;
145 }
146
147 if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) {
148
149
150 if (optval + 5 > optval_end)
151 return 0;
152
153 memcpy(optval, "cubic", 5);
154 ctx->optlen = 5;
155
156 return 1;
157 }
158
159 if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) {
160
161 if (ctx->optlen != page_size * 2)
162 return 0;
163
164 if (optval + 1 > optval_end)
165 return 0;
166
167
168 optval[0] = 0;
169 ctx->optlen = 1;
170
171
172
173
174
175 if (optval_end - optval != page_size)
176 return 0;
177
178 return 1;
179 }
180
181 if (ctx->level != SOL_CUSTOM)
182 return 0;
183
184 if (optval + 1 > optval_end)
185 return 0;
186
187 storage = bpf_sk_storage_get(&socket_storage_map, ctx->sk, 0,
188 BPF_SK_STORAGE_GET_F_CREATE);
189 if (!storage)
190 return 0;
191
192 storage->val = optval[0];
193 ctx->optlen = -1;
194
195
196
197 return 1;
198}
199