Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "bpfilter/cgen/matcher/tcp.h"
7 :
8 : #include <linux/bpf.h>
9 : #include <linux/bpf_common.h>
10 : #include <linux/in.h> // NOLINT
11 : #include <linux/tcp.h>
12 :
13 : #include <endian.h>
14 : #include <errno.h>
15 : #include <stddef.h>
16 : #include <stdint.h>
17 :
18 : #include "bpfilter/cgen/program.h"
19 : #include "core/logger.h"
20 : #include "core/matcher.h"
21 :
22 : #include "external/filter.h"
23 :
24 0 : static int _bf_matcher_generate_tcp_port(struct bf_program *program,
25 : const struct bf_matcher *matcher)
26 : {
27 : uint16_t *port = (uint16_t *)&matcher->payload;
28 0 : size_t offset = matcher->type == BF_MATCHER_TCP_SPORT ?
29 0 : offsetof(struct tcphdr, source) :
30 : offsetof(struct tcphdr, dest);
31 :
32 0 : EMIT(program, BPF_LDX_MEM(BPF_H, BPF_REG_1, BPF_REG_6, offset));
33 :
34 0 : switch (matcher->op) {
35 0 : case BF_MATCHER_EQ:
36 0 : EMIT_FIXUP_JMP_NEXT_RULE(
37 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_1, htobe16(*port), 0));
38 0 : break;
39 0 : case BF_MATCHER_NE:
40 0 : EMIT_FIXUP_JMP_NEXT_RULE(
41 : program, BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, htobe16(*port), 0));
42 0 : break;
43 0 : case BF_MATCHER_RANGE:
44 0 : EMIT_FIXUP_JMP_NEXT_RULE(
45 : program, BPF_JMP_IMM(BPF_JLT, BPF_REG_1, htobe16(port[0]), 0));
46 0 : EMIT_FIXUP_JMP_NEXT_RULE(
47 : program, BPF_JMP_IMM(BPF_JGT, BPF_REG_1, htobe16(port[1]), 0));
48 0 : break;
49 0 : default:
50 0 : return bf_err_r(-EINVAL, "unknown matcher operator '%s' (%d)",
51 : bf_matcher_op_to_str(matcher->op), matcher->op);
52 : }
53 :
54 : return 0;
55 : }
56 :
57 0 : static int _bf_matcher_generate_tcp_flags(struct bf_program *program,
58 : const struct bf_matcher *matcher)
59 : {
60 0 : uint8_t flags = *(uint8_t *)matcher->payload;
61 :
62 0 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6, 13));
63 :
64 0 : switch (matcher->op) {
65 0 : case BF_MATCHER_EQ:
66 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
67 : BPF_JMP_IMM(BPF_JNE, BPF_REG_1, flags, 0));
68 0 : break;
69 0 : case BF_MATCHER_NE:
70 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
71 : BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, flags, 0));
72 0 : break;
73 0 : case BF_MATCHER_ANY:
74 0 : EMIT(program, BPF_ALU32_IMM(BPF_AND, BPF_REG_1, flags));
75 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
76 : BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0, 0));
77 0 : break;
78 0 : case BF_MATCHER_ALL:
79 0 : EMIT(program, BPF_ALU32_IMM(BPF_AND, BPF_REG_1, flags));
80 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
81 : BPF_JMP_IMM(BPF_JNE, BPF_REG_1, flags, 0));
82 0 : break;
83 0 : default:
84 0 : return bf_err_r(-EINVAL, "unsupported matcher for tcp.flags: %s",
85 : bf_matcher_op_to_str(matcher->op));
86 : }
87 :
88 : return 0;
89 : }
90 :
91 0 : int bf_matcher_generate_tcp(struct bf_program *program,
92 : const struct bf_matcher *matcher)
93 : {
94 : int r;
95 :
96 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
97 : BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_TCP, 0));
98 0 : EMIT(program,
99 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
100 :
101 0 : switch (matcher->type) {
102 0 : case BF_MATCHER_TCP_SPORT:
103 : case BF_MATCHER_TCP_DPORT:
104 0 : r = _bf_matcher_generate_tcp_port(program, matcher);
105 0 : break;
106 0 : case BF_MATCHER_TCP_FLAGS:
107 0 : r = _bf_matcher_generate_tcp_flags(program, matcher);
108 0 : break;
109 0 : default:
110 0 : return bf_err_r(-EINVAL, "unknown matcher type %d", matcher->type);
111 : };
112 :
113 : return r;
114 : }
|