You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
1.`tokio` is the async library we're using, which provides our [Ctrl-C handler](https://docs.rs/tokio/latest/tokio/signal/fn.ctrl_c.html). It will come in useful later as we expand the functionality of the initial program:
@@ -130,10 +130,10 @@ $ cargo xtask run -- -h
130
130
:
131
131
Finished dev [optimized] target(s) in 0.90s
132
132
Finished dev [unoptimized + debuginfo] target(s) in 0.60s
133
-
myapp
133
+
xdp-hello
134
134
135
135
USAGE:
136
-
myapp [OPTIONS]
136
+
xdp-hello [OPTIONS]
137
137
138
138
OPTIONS:
139
139
-h, --help Print help information
@@ -148,13 +148,12 @@ OPTIONS:
148
148
149
149
```console
150
150
$ RUST_LOG=info cargo xtask run
151
-
17:51:57 [INFO] myapp: [myapp/src/main.rs:48] Waiting for Ctrl-C...
152
-
17:51:57 [INFO] myapp: [src/main.rs:20] received a packet
153
-
17:51:57 [INFO] myapp: [src/main.rs:20] received a packet
154
-
17:51:57 [INFO] myapp: [src/main.rs:20] received a packet
155
-
:
156
-
17:51:58 [INFO] myapp: [src/main.rs:20] received a packet
Copy file name to clipboardExpand all lines: docs/book/start/logging-packets.md
+31-56Lines changed: 31 additions & 56 deletions
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ Let's expand this program to log the traffic that is being permitted in the user
6
6
7
7
!!! example "Source Code"
8
8
9
-
Full code for the example in this chapter is availble [here](https://github.com/aya-rs/book/tree/main/examples/myapp-02)
9
+
Full code for the example in this chapter is available [here](https://github.com/aya-rs/book/tree/main/examples/xdp-log)
10
10
11
11
## Getting Data to User-Space
12
12
@@ -17,8 +17,8 @@ To get data from kernel-space to user-space we use an eBPF map. There are numero
17
17
While we could go all out and extract data all the way up to L7, we'll constrain our firewall to L3, and to make things easier, IPv4 only.
18
18
The data structure that we'll need to send information to user-space will need to hold an IPv4 address and an action for Permit/Deny, we'll encode both as a `u32`.
1. We implement the `aya::Pod` trait for our struct since it is Plain Old Data as can be safely converted to a byte-slice and back.
@@ -87,73 +87,50 @@ The data structure that we'll need to send information to user-space will need t
87
87
88
88
## Writing Data
89
89
90
-
### Generating Bindings To vmlinux.h
90
+
### Using Kernel Network Types
91
91
92
-
To get useful data to add to our maps, we first need some useful data structures to populate with data from the `XdpContext`.
92
+
To get useful data to add to our maps, we first need some useful data structures
93
+
to populate with data from the `XdpContext`.
93
94
We want to log the Source IP Address of incoming traffic, so we'll need to:
94
95
95
96
1. Read the Ethernet Header to determine if this is an IPv4 Packet
96
97
1. Read the Source IP Address from the IPv4 Header
97
98
98
-
The two structs in the kernel for this are `ethhdr` from `uapi/linux/if_ether.h` and `iphdr` from `uapi/linux/ip.h`.
99
-
If I were to use bindgen to generate Rust bindings for those headers, I'd be tied to the kernel version of the system that I'm developing on.
100
-
This is where `aya-tool` comes in to play. It can easily generate bindings for using the BTF information in `/sys/kernel/btf/vmlinux`.
99
+
The two structs in the kernel for this are `ethhdr` from `uapi/linux/if_ether.h`
100
+
and `iphdr` from `uapi/linux/ip.h`. Rust equivalents of those structures (`EthHdr`
101
+
and `Ipv4Hdr`) are provided by the [network-types crate](https://crates.io/crates/network-types).
101
102
102
-
First, we must make sure that `bindgen` is installed.
103
-
```sh
104
-
cargo install bindgen-cli
105
-
```
106
-
107
-
Once the bindings are generated and checked in to our repository they shouldn't need to be regenerated again unless we need to add a new struct.
108
-
109
-
Lets use `xtask` to automate this so we can easily reproduce this file in future.
110
-
111
-
We'll add the following code
112
-
113
-
=== "xtask/src/codegen.rs"
114
-
115
-
```rust linenums="1"
116
-
--8<-- "examples/myapp-02/xtask/src/codegen.rs"
117
-
```
103
+
Let's add it to our eBPF crate by adding a dependency on `network-types` in our
104
+
`xdp-log-ebpf/Cargo.toml`:
118
105
119
-
=== "xtask/Cargo.toml"
106
+
=== "xdp-log-ebpf/Cargo.toml"
120
107
121
108
```toml linenums="1"
122
-
--8<-- "examples/myapp-02/xtask/Cargo.toml"
109
+
--8<-- "examples/xdp-log/xdp-log-ebpf/Cargo.toml"
123
110
```
124
111
125
-
=== "xtask/src/main.rs"
126
-
127
-
```rust linenums="1"
128
-
--8<-- "examples/myapp-02/xtask/src/main.rs"
129
-
```
130
-
131
-
Once we've generated our file using `cargo xtask codegen` from the root of the project.
132
-
We can access these by including `mod bindings` from our eBPF code.
133
-
134
112
### Getting Packet Data From The Context And Into the Map
135
113
136
114
The `XdpContext` contains two fields, `data` and `data_end`.
137
-
`data` is a pointer to the start of the data in kernel memory and `data_end`, a pointer to the end of the data in kernel memory. In order to access this data and ensure that the eBPF verifier is happy, we'll introduce a helper function called `ptr_at`. This function will ensure that before we access any data, we check that it's contained between `data` and `data_end`. It is marked as `unsafe` because when calling the function, you must ensure that there is a valid `T` at that location or there will be undefined behaviour.
115
+
`data` is a pointer to the start of the data in kernel memory and `data_end`, a
116
+
pointer to the end of the data in kernel memory. In order to access this data
117
+
and ensure that the eBPF verifier is happy, we'll introduce a helper function
118
+
called `ptr_at`. This function will ensure that before we access any data, we
119
+
check that it's contained between `data` and `data_end`. It is marked as `unsafe`
120
+
because when calling the function, you must ensure that there is a valid `T` at
121
+
that location or there will be undefined behaviour.
138
122
139
123
With our helper function in place, we can:
140
124
141
125
1. Read the Ethertype field to check if we have an IPv4 packet.
142
126
1. Read the IPv4 Source Address from the IP header
143
127
144
-
To do this efficiently we'll add a dependency on `memoffset = "0.6"` in our `myapp-ebpf/Cargo.toml`
145
-
146
-
!!! tip "Reading Fields Using `offset_of!`"
147
-
148
-
As there is limited stack space, it's more memory efficient to use the `offset_of!` macro to read
149
-
a single field from a struct, rather than reading the whole struct and accessing the field by name.
150
-
151
128
Once we have our IPv4 source address, we can create a `PacketLog` struct and output this to our `PerfEventArray`
@@ -168,16 +145,16 @@ Don't forget to rebuild your eBPF program!
168
145
In order to read from the `AsyncPerfEventArray`, we have to call `AsyncPerfEventArray::open()` for each online CPU, then we have to poll the file descriptor for events.
169
146
While this is do-able using `PerfEventArray` and `mio` or `epoll`, the code is much less easy to follow. Instead, we'll use `tokio`, which was added to our template for us.
170
147
171
-
We'll need to add a dependency on `bytes = "1"` to `myapp/Cargo.toml` since this will make it easier
148
+
We'll need to add a dependency on `bytes = "1"` to `xdp-log/Cargo.toml` since this will make it easier
172
149
to deal with the chunks of bytes yielded by the `AsyncPerfEventArray`.
173
150
174
151
Here's the code:
175
152
176
-
```rust linenums="1" title="myapp/src/main.rs"
177
-
--8<--"examples/myapp-02/myapp/src/main.rs"
153
+
```rust linenums="1" title="xdp-log/src/main.rs"
154
+
--8<--"examples/xdp-log/xdp-log/src/main.rs"
178
155
```
179
156
180
-
1. Name was not defined in `myapp-ebpf/src/main.rs`, so use `xdp` instead of `myapp`
157
+
1. Name was not defined in `xdp-log-ebpf/src/main.rs`, so use `xdp`
181
158
2. Define our map
182
159
3. Call `open()` for each online CPU
183
160
4. Spawn a `tokio::task`
@@ -192,11 +169,9 @@ As before, the interface can be overwritten by providing the interface name as a
192
169
193
170
```console
194
171
$ RUST_LOG=info cargo xtask run
195
-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 192.168.1.205, ACTION 2
196
-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 192.168.1.21, ACTION 2
197
-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 192.168.1.21, ACTION 2
198
-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 18.168.253.132, ACTION 2
199
-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 18.168.253.132, ACTION 2
200
-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 18.168.253.132, ACTION 2
201
-
[2022-10-04T12:46:05Z INFO myapp] LOG: SRC 140.82.121.6, ACTION 2
172
+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 172.52.22.104, SRC PORT: 443
173
+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 172.52.22.104, SRC PORT: 443
174
+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 172.52.22.104, SRC PORT: 443
175
+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 172.52.22.104, SRC PORT: 443
176
+
[2022-12-22T11:32:21Z INFO xdp_log] SRC IP: 234.130.159.162, SRC PORT: 443
0 commit comments