1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef NET_FIREWALL_SKB_UTILS_H
16 #define NET_FIREWALL_SKB_UTILS_H
17
18 #include <stdint.h>
19 #include <sys/socket.h>
20 #include <bpf/bpf_endian.h>
21 #include <linux/bpf.h>
22 #include <linux/icmp.h>
23 #include <linux/icmpv6.h>
24 #include <linux/if_ether.h>
25 #include <linux/if_packet.h>
26 #include <linux/if_vlan.h>
27 #include <linux/if_tunnel.h>
28 #include <linux/in.h>
29 #include <linux/in6.h>
30 #include <linux/ip.h>
31 #include <linux/ipv6.h>
32 #include <linux/tc_act/tc_bpf.h>
33 #include <linux/tcp.h>
34 #include <linux/udp.h>
35 #include <stdbool.h>
36
37 #define TCP_FLAGS_OFFSET 12
38 #define TCP_FLAGS_SIZE 2
39
40 #define L3_NHOFF 0
41 #define L4_NHOFF(ipv4) (L3_NHOFF + ((ipv4) ? sizeof(struct iphdr) : sizeof(struct ipv6hdr)))
42
43 union tcp_flags {
44 struct {
45 __u8 upper_bits;
46 __u8 lower_bits;
47 __u16 pad;
48 };
49 __u32 value;
50 };
51
52 /**
53 * @brief judget given skb is a layler 4 protocol or not
54 *
55 * @param skb struct __sk_buff
56 * @param l3_nhoff layer 3 network header offset
57 * @param protocol layer 4 protocol number
58 * @return true if match, otherwise false
59 */
is_l4_protocol(struct __sk_buff * skb,__u32 l3_nhoff,__u8 protocol)60 static __always_inline bool is_l4_protocol(struct __sk_buff *skb, __u32 l3_nhoff, __u8 protocol)
61 {
62 if (skb->family == AF_INET) {
63 struct iphdr iph = { 0 };
64 bpf_skb_load_bytes(skb, l3_nhoff, &iph, sizeof(struct iphdr));
65
66 return iph.protocol == protocol;
67 }
68 if (skb->family == AF_INET6) {
69 struct ipv6hdr ip6h = { 0 };
70 bpf_skb_load_bytes(skb, l3_nhoff, &ip6h, sizeof(struct ipv6hdr));
71
72 return ip6h.nexthdr == protocol;
73 }
74
75 return false;
76 }
77
78 /**
79 * Get the layer 3 network header offset
80 * offset
81 *
82 * @param skb struct __sk_buff
83 * @return layer 3 network header offset
84 */
get_l3_nhoff(struct __sk_buff * skb)85 static __always_inline __u32 get_l3_nhoff(struct __sk_buff *skb)
86 {
87 return L3_NHOFF;
88 }
89
90 /**
91 * Get the layer 4 network header offset
92 * offset
93 *
94 * @param skb struct __sk_buff
95 * @return layer 4 network header offset
96 */
get_l4_nhoff(struct __sk_buff * skb)97 static __always_inline __u32 get_l4_nhoff(struct __sk_buff *skb)
98 {
99 return L4_NHOFF(skb->family == AF_INET);
100 }
101
102 /**
103 * @brief load tcp flags from given skb
104 *
105 * @param skb struct __sk_buff
106 * @param l4_nhoff layer 4 network header offset
107 * @param flags union tcp_flags
108 * @return __always_inline
109 */
load_tcp_flags(struct __sk_buff * skb,__u32 l4_nhoff,union tcp_flags * flags)110 static __always_inline int load_tcp_flags(struct __sk_buff *skb, __u32 l4_nhoff, union tcp_flags *flags)
111 {
112 return bpf_skb_load_bytes(skb, l4_nhoff + TCP_FLAGS_OFFSET, flags, TCP_FLAGS_SIZE);
113 }
114
115 /**
116 * @brief load layer 4 protocol from given skb
117 *
118 * @param skb struct __sk_buff
119 * @param l3_nhoff layer 3 network header offset
120 * @param protocol out layer 4 protocol
121 * @return true if success or false if an error occurred
122 */
load_l4_protocol(const struct __sk_buff * skb,__u32 l3_nhoff,__u8 * protocol)123 static __always_inline bool load_l4_protocol(const struct __sk_buff *skb, __u32 l3_nhoff, __u8 *protocol)
124 {
125 if (skb->family == AF_INET) {
126 struct iphdr iph = { 0 };
127 bpf_skb_load_bytes(skb, l3_nhoff, &iph, sizeof(struct iphdr));
128
129 *protocol = iph.protocol;
130 return true;
131 } else if (skb->family == AF_INET6) {
132 struct ipv6hdr ip6h = { 0 };
133 bpf_skb_load_bytes(skb, l3_nhoff, &ip6h, sizeof(struct ipv6hdr));
134
135 *protocol = ip6h.nexthdr;
136 return true;
137 }
138
139 return false;
140 }
141
142 /**
143 * @brief load layer 3 ipv4 addrs from given skb
144 *
145 * @param skb struct __sk_buff
146 * @param l3_nhoff layer 3 network header offset
147 * @param saddr out saddr
148 * @param daddr out daddr
149 * @return true if success or false if an error occurred
150 */
load_l3_v4_addrs(const struct __sk_buff * skb,__u32 l3_nhoff,__be32 * saddr,__be32 * daddr)151 static __always_inline bool load_l3_v4_addrs(const struct __sk_buff *skb, __u32 l3_nhoff, __be32 *saddr, __be32 *daddr)
152 {
153 if (skb->family != AF_INET) {
154 return false;
155 }
156
157 struct iphdr iph = { 0 };
158 bpf_skb_load_bytes(skb, l3_nhoff, &iph, sizeof(struct iphdr));
159
160 *saddr = iph.saddr;
161 *daddr = iph.daddr;
162
163 return true;
164 }
165
166 /**
167 * @brief load layer 3 ipv6 addrs from given skb
168 *
169 * @param skb struct __sk_buff
170 * @param l3_nhoff layer 3 network header offset
171 * @param saddr out saddr
172 * @param daddr out daddr
173 * @return true if success or false if an error occurred
174 */
load_l3_v6_addrs(const struct __sk_buff * skb,__u32 l3_nhoff,struct in6_addr * saddr,struct in6_addr * daddr)175 static __always_inline bool load_l3_v6_addrs(const struct __sk_buff *skb, __u32 l3_nhoff, struct in6_addr *saddr,
176 struct in6_addr *daddr)
177 {
178 if (skb->family != AF_INET6) {
179 return false;
180 }
181
182 struct ipv6hdr ip6h = { 0 };
183 bpf_skb_load_bytes(skb, l3_nhoff, &ip6h, sizeof(struct ipv6hdr));
184
185 *saddr = ip6h.saddr;
186 *daddr = ip6h.daddr;
187
188 return true;
189 }
190
191 /**
192 * @brief load layer 4 icmp info from given skb
193 *
194 * @param skb struct __sk_buff
195 * @param l4_nhoff layer 4 network header offset
196 * @param protocol IPPROTO_ICMP or IPPROTO_ICMPV6
197 * @param type out icmp type
198 * @param code out icmp code
199 * @return true if success or false if an error occurred
200 */
load_icmp_info(const struct __sk_buff * skb,__u32 l4_nhoff,__u8 protocol,__u8 * type,__u8 * code)201 static __always_inline bool load_icmp_info(const struct __sk_buff *skb, __u32 l4_nhoff, __u8 protocol, __u8 *type,
202 __u8 *code)
203 {
204 bool res = true;
205 switch (protocol) {
206 case IPPROTO_ICMP: {
207 struct icmphdr icmph = { 0 };
208 bpf_skb_load_bytes(skb, l4_nhoff, &icmph, sizeof(struct icmphdr));
209
210 *type = icmph.type;
211 *code = icmph.code;
212 } break;
213 case IPPROTO_ICMPV6: {
214 struct icmp6hdr icmph = { 0 };
215 bpf_skb_load_bytes(skb, l4_nhoff, &icmph, sizeof(struct icmp6hdr));
216
217 *type = icmph.icmp6_type;
218 *code = icmph.icmp6_code;
219 } break;
220 default:
221 res = false;
222 break;
223 }
224
225 return res;
226 }
227
228 /**
229 * @brief load layer 4 ports from given skb
230 *
231 * @param skb struct __sk_buff
232 * @param l4_nhoff layer 4 network header offset
233 * @param protocol IPPROTO_TCP or IPPROTO_UDP
234 * @param sport out sport
235 * @param dport out dport
236 * @return true if success or false if an error occurred
237 */
load_l4_ports(const struct __sk_buff * skb,__u32 l4_nhoff,__u8 protocol,__be16 * sport,__be16 * dport)238 static __always_inline bool load_l4_ports(const struct __sk_buff *skb, __u32 l4_nhoff, __u8 protocol, __be16 *sport,
239 __be16 *dport)
240 {
241 bool res = true;
242 switch (protocol) {
243 case IPPROTO_TCP: {
244 struct tcphdr tcph = { 0 };
245 bpf_skb_load_bytes(skb, l4_nhoff, &tcph, sizeof(struct tcphdr));
246 *sport = tcph.source;
247 *dport = tcph.dest;
248 } break;
249 case IPPROTO_UDP: {
250 struct udphdr udph = { 0 };
251 bpf_skb_load_bytes(skb, l4_nhoff, &udph, sizeof(struct udphdr));
252 *sport = udph.source;
253 *dport = udph.dest;
254 } break;
255 default:
256 res = false;
257 break;
258 }
259
260 return res;
261 }
262
263 /**
264 * @brief load layer 4 rst from given skb
265 *
266 * @param skb struct __sk_buff
267 * @param l4_nhoff layer 4 network header offset
268 * @param rst out rst packet
269 * @return true if success or false if an error occurred
270 */
load_l4_header_flags(const struct __sk_buff * skb,__u32 l4_nhoff,__u16 * rst)271 static __always_inline bool load_l4_header_flags(const struct __sk_buff *skb, __u32 l4_nhoff, __u16 *rst)
272 {
273 struct tcphdr tcph = { 0 };
274 bpf_skb_load_bytes(skb, l4_nhoff, &tcph, sizeof(struct tcphdr));
275 *rst = tcph.rst;
276 return true;
277 }
278
279 #endif // NET_FIREWALL_SKB_UTILS_H