eBPF & XDP ở quy mô lớn: Giảm thiểu DDoS 10 triệu gói/giây & Lọc cấp độ driver

Mục lục bài viết(8 mục)
Các cuộc tấn công DDoS ở tầng mạng, đặc biệt là SYN floods và UDP amplification, vẫn là một mối đe dọa dai dẳng. Mặc dù việc lọc ở không gian kernel truyền thống có hiệu quả, nhưng nó gây ra độ trễ và chi phí CPU do cấp phát sk_buff, duyệt toàn bộ ngăn xếp mạng và chuyển đổi ngữ cảnh. Ở tốc độ đường truyền vượt quá 10 triệu gói tin mỗi giây (Mpps) trên một lõi, những chi phí này trở nên quá lớn. Hướng dẫn này trình bày chi tiết việc triển khai giảm thiểu DDoS hiệu suất cao bằng cách sử dụng eBPF và XDP (eXpress Data Path), tận dụng xử lý gói tin ở cấp độ driver để đạt được khả năng lọc ở tốc độ đường truyền.
Các nguyên tắc cơ bản của XDP để lọc hiệu suất cao
XDP hoạt động ở điểm sớm nhất có thể trong ngăn xếp mạng: trực tiếp trong vòng nhận (RX) của driver card giao diện mạng (NIC). Ngữ cảnh thực thi trước kernel, trước cấp phát sk_buff này rất quan trọng đối với hiệu suất. Một gói tin được xử lý bởi chương trình XDP sẽ không bao giờ đến được ngăn xếp mạng đầy đủ của kernel nếu bị loại bỏ hoặc chuyển hướng. Điều này loại bỏ việc cấp phát bộ nhớ, lỗi bộ nhớ cache và chu kỳ CPU liên quan đến việc tạo sk_buff và xử lý tiếp theo.
Chương trình XDP nhận một cấu trúc xdp_md thô, cung cấp các con trỏ đến điểm bắt đầu và kết thúc của dữ liệu gói tin. Giá trị trả về của chương trình quyết định hành động được thực hiện:
XDP_DROP: Gói tin bị loại bỏ ngay lập tức. Đây là hành động chính để giảm thiểu DDoS.XDP_PASS: Gói tin được phép tiếp tục đến ngăn xếp mạng của kernel.XDP_TX: Gói tin được chuyển hướng trở lại cùng cổng NIC. Hữu ích cho việc cân bằng tải hoặc phản xạ.XDP_REDIRECT: Gói tin được chuyển hướng đến một cổng NIC khác hoặc một bản đồ CPU BPF để giao tiếp giữa các CPU.
Ngữ cảnh thực thi chương trình XDP
Một chương trình XDP thực thi trong môi trường eBPF bị hạn chế. Nó không thể thực hiện các lệnh gọi hệ thống tùy ý, truy cập bộ nhớ kernel tùy ý hoặc lặp vô hạn. Điều này đảm bảo sự ổn định và ngăn chặn các chương trình độc hại hoặc có lỗi làm tổn hại đến kernel. Các ràng buộc chính bao gồm:
- Vòng lặp có giới hạn: Các vòng lặp phải có giới hạn trên đã biết, hữu hạn.
- Truy cập bộ nhớ: Chỉ có thể truy cập dữ liệu gói tin và bộ nhớ bản đồ BPF.
- Các hàm trợ giúp: Một tập hợp giới hạn các hàm trợ giúp BPF có sẵn cho các tác vụ như tra cứu bản đồ, tính toán tổng kiểm tra và thao tác gói tin.
Kiến trúc giảm thiểu DDoS
Kiến trúc giảm thiểu của chúng tôi bao gồm:
- Chương trình XDP (C): Được triển khai trực tiếp đến NIC. Chương trình này thực hiện phân tích cú pháp và lọc gói tin ban đầu dựa trên địa chỉ IP, giao thức và số cổng. Nó tận dụng các bản đồ BPF để đưa vào danh sách đen động và bộ đếm.
- Bản đồ BPF:
BPF_MAP_TYPE_LPM_TRIE: Để đưa vào danh sách đen IP khớp tiền tố dài nhất (LPM) hiệu quả. Điều này cho phép chặn toàn bộ mạng con hoặc các IP riêng lẻ.BPF_MAP_TYPE_ARRAY: Đối với bộ đếm gói tin trên mỗi CPU, cung cấp khả năng hiển thị thời gian thực về lưu lượng truy cập bị loại bỏ.
- Agent không gian người dùng (Go/Python/Rust):
- Tải chương trình XDP và gắn nó vào giao diện mạng mục tiêu.
- Quản lý bản đồ
LPM_TRIE, thêm/xóa các IP bị đưa vào danh sách đen dựa trên thông tin tình báo mối đe dọa bên ngoài hoặc phát hiện bất thường cục bộ. - Đọc và tổng hợp các bộ đếm từ bản đồ
ARRAY, hiển thị chúng qua Prometheus.
LPM Trie để đưa vào danh sách đen IP động
Một bản đồ LPM_TRIE lý tưởng để đưa vào danh sách đen IP do khả năng khớp tiền tố hiệu quả của nó. Điều này cho phép chặn 192.168.1.0/24 bằng một mục nhập duy nhất, thay vì liệt kê tất cả 256 IP.
// bpf_ddos_mitigator.c
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
// Define a structure for LPM trie keys
// This structure is critical for the LPM trie map.
// The 'prefixlen' field determines how many bits of the 'data' field are used for matching.
// For IPv4, prefixlen can be 32 for a host match, or less for a subnet.
// For IPv6, prefixlen can be 128 for a host match.
struct bpf_lpm_trie_key {
__u32 prefixlen; // Must be the first field
__u32 ip_addr; // IPv4 address in network byte order
};
// Map for blacklisted IPs (LPM Trie)
// Key: bpf_lpm_trie_key (prefixlen + IP)
// Value: __u8 (e.g., 1 to indicate blacklisted)
struct {
__uint(type, BPF_MAP_TYPE_LPM_TRIE);
__uint(max_entries, 10240); // Max 10k blacklist entries
__uint(key_size, sizeof(struct bpf_lpm_trie_key));
__uint(value_size, sizeof(__u8));
__uint(map_flags, BPF_F_NO_PREALLOC); // Don't preallocate all memory
} blacklist_ips SEC(".maps");
// Map for packet counters (per-CPU array)
// Key: __u32 (index for counter type, e.g., 0 for dropped, 1 for passed)
// Value: __u64 (counter)
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 2); // 0: dropped_packets, 1: passed_packets
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u64));
} xdp_stats_map SEC(".maps");
// Helper macro to increment a counter in the xdp_stats_map
static __always_inline void increment_counter(__u32 index) {
__u64 *counter = bpf_map_lookup_elem(&xdp_stats_map, &index);
if (counter) {
__sync_fetch_and_add(counter, 1);
}
}
SEC("xdp")
int xdp_ddos_mitigator(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if (eth + 1 > data_end) {
return XDP_PASS; // Malformed Ethernet header
}
// Only process IPv4 for this example
if (bpf_ntohs(eth->h_proto) != ETH_P_IP) {
return XDP_PASS;
}
struct iphdr *iph = data + sizeof(*eth);
if (iph + 1 > data_end) {
return XDP_PASS; // Malformed IP header
}
// Check if source IP is blacklisted
struct bpf_lpm_trie_key key = {
.prefixlen = 32, // Exact match for source IP
.ip_addr = iph->saddr // Source IP in network byte order
};
__u8 *blacklisted = bpf_map_lookup_elem(&blacklist_ips, &key);
if (blacklisted) {
// IP is blacklisted, drop the packet
increment_counter(0); // Increment dropped_packets counter
return XDP_DROP;
}
// Basic SYN flood mitigation (TCP SYN packets without ACK)
if (iph->protocol == IPPROTO_TCP) {
struct tcphdr *tcph = (void *)iph + (iph->ihl * 4);
if (tcph + 1 > data_end) {
return XDP_PASS; // Malformed TCP header
}
// Check for SYN flag set and ACK flag not set
if (tcph->syn && !tcph->ack) {
// Potentially a SYN flood packet.
// For production, this would be more sophisticated,
// e.g., rate limiting, SYN cookie implementation, or state tracking.
// For now, we'll just drop it if it's a simple SYN.
// This is a very aggressive rule and might drop legitimate SYNs.
// A real-world solution would involve more context.
// For demonstration, we'll drop if source IP is not whitelisted.
// (No whitelist implemented here, so it's a direct drop for SYN)
// increment_counter(0); // Increment dropped_packets counter
// return XDP_DROP;
}
}
// Basic UDP amplification mitigation (e.g., DNS, NTP, SSDP)
// This is a simplified example. Real mitigation involves
// checking payload size, specific protocol headers, and known amplification vectors.
if (iph->protocol == IPPROTO_UDP) {
struct udphdr *udph = (void *)iph + (iph->ihl * 4);
if (udph + 1 > data_end) {
return XDP_PASS; // Malformed UDP header
}
// Example: Drop UDP packets to common amplification ports if source is not trusted
// This is a placeholder. A real system would check for specific
// query types, response sizes, or use a dynamic trust list.
__u16 dest_port = bpf_ntohs(udph->dest);
if (dest_port == 53 || dest_port == 123 || dest_port == 1900) { // DNS, NTP, SSDP
// For demonstration, we'll drop these if source is not whitelisted.
// A real system would have more sophisticated logic.
// increment_counter(0); // Increment dropped_packets counter
// return XDP_DROP;
}
}
// If not dropped by any rule, pass to the kernel
increment_counter(1); // Increment passed_packets counter
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
Để biên dịch chương trình eBPF này, bạn sẽ cần clang và llvm với hỗ trợ backend BPF, cùng với các tiêu đề libbpf.
# Install necessary packages on Debian/Ubuntu
sudo apt update
sudo apt install clang llvm libelf-dev libbpf-dev build-essential
# Compile the BPF program
clang -O2 -target bpf -g -c bpf_ddos_mitigator.c -o bpf_ddos_mitigator.o
Mặt phẳng điều khiển không gian người dùng (Ví dụ Go)
Một agent không gian người dùng chịu trách nhiệm tải chương trình eBPF, quản lý bản đồ và hiển thị các số liệu.
// main.go
package main
import (
"fmt"
"log"
"net"
"os"
"os/signal"
"syscall"
"time"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/link"
"github.com/cilium/ebpf/rlimit"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc clang -cflags "-O2 -g -Wall" bpf bpf_ddos_mitigator.c -- -I./headers
// bpf_lpm_trie_key matches the C struct
type bpfLpmTrieKey struct {
Prefixlen uint32
IPAddr uint32 // Network byte order
}
var (
droppedPackets = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "xdp_dropped_packets_total",
Help: "Total number of packets dropped by XDP DDoS mitigator.",
},
)
passedPackets = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "xdp_passed_packets_total",
Help: "Total number of packets passed by XDP DDoS mitigator.",
},
)
)
func init() {
prometheus.MustRegister(droppedPackets)
prometheus.MustRegister(passedPackets)
}
func main() {
if len(os.Args) < 2 {
log.Fatalf("Usage: %s <interface>", os.Args[0])
}
ifaceName := os.Args[1]
// Allow the current process to lock memory for eBPF maps.
if err := rlimit.RemoveMemlock(); err != nil {
log.Fatalf("Failed to remove memlock rlimit: %v", err)
}
// Load pre-compiled programs and maps into the kernel.
objs := bpfObjects{}
if err := loadBpfObjects(&objs, nil); err != nil {
log.Fatalf("Loading eBPF objects: %v", err)
}
defer objs.Close()
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
log.Fatalf("Getting interface %s: %v", ifaceName, err)
}
// Attach the XDP program to the network interface.
// Use XDP_FLAGS_DRV_MODE for best performance if driver supports it.
// Fallback to XDP_FLAGS_SKB_MODE if driver mode fails.
l, err := link.AttachXDP(link.XDPOptions{
Program: objs.XdpDdosMitigator,
Interface: iface,
Flags: uint32(link.XDPDriverMode),
})
if err != nil {
log.Printf("Failed to attach XDP in driver mode, trying SKB mode: %v", err)
l, err = link.AttachXDP(link.XDPOptions{
Program: objs.XdpDdosMitigator,
Interface: iface,
Flags: uint32(link.XDPSkbMode),
})
if err != nil {
log.Fatalf("Failed to attach XDP in SKB mode: %v", err)
}
}
defer l.Close()
log.Printf("Successfully attached XDP program to interface %q (ID: %d)", ifaceName, objs.XdpDdosMitigator.ID())
// Example: Add a blacklisted IP (e.g., 192.0.2.1)
// This would typically come from a dynamic threat feed or detection system.
blacklistIP := net.ParseIP("192.0.2.1").To4()
if blacklistIP == nil {
log.Fatalf("Invalid IP address")
}
key := bpfLpmTrieKey{
Prefixlen: 32, // Exact match
IPAddr: uint32(blacklistIP[0])<<24 | uint32(blacklistIP[1])<<16 | uint32(blacklistIP[2])<<8 | uint32(blacklistIP[3]),
}
value := uint8(1) // Value doesn't matter, just its presence
if err := objs.BlacklistIps.Put(key, value); err != nil {
log.Fatalf("Failed to add IP to blacklist: %v", err)
}
log.Printf("Added %s to blacklist.", blacklistIP.String())
// Start Prometheus metrics server
go func() {
http.Handle("/metrics", promhttp.Handler())
log.Fatal(http.ListenAndServe(":9090", nil))
}()
log.Println("Prometheus metrics exposed on :9090/metrics")
// Periodically read and update Prometheus counters
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
var prevDropped, prevPassed uint64
for {
select {
case <-ticker.C:
var currentDropped, currentPassed uint64
var zero uint32 = 0
var one uint32 = 1
if err := objs.XdpStatsMap.Lookup(zero, ¤tDropped); err != nil {
log.Printf("Failed to lookup dropped_packets counter: %v", err)
}
if err := objs.XdpStatsMap.Lookup(one, ¤tPassed); err != nil {
log.Printf("Failed to lookup passed_packets counter: %v", err)
}
// Update Prometheus counters with delta
droppedPackets.Add(float64(currentDropped - prevDropped))
passedPackets.Add(float64(currentPassed - prevPassed))
prevDropped = currentDropped
prevPassed = currentPassed
log.Printf("Dropped: %d, Passed: %d", currentDropped, currentPassed)
case <-stop:
log.Println("Detaching XDP program...")
return
}
}
}
Để tạo các ràng buộc Go cho chương trình eBPF, hãy chạy:
go generate ./...
Sau đó, biên dịch và chạy chương trình Go:
go build -o xdp-mitigator main.go
sudo ./xdp-mitigator eth0 # Replace eth0 with your network interface
Đánh giá hiệu suất & Đánh đổi
| Tính năng | XDP (Chế độ Driver) | Không gian Kernel (Netfilter/iptables) |
|---|---|---|
| Điểm thực thi | Vòng RX của NIC, trước sk_buff | Sau khi cấp phát sk_buff, trong ngăn xếp kernel |
| Hiệu suất | 10-100 Mpps/lõi (tốc độ đường truyền trên NIC hiện đại) | 1-5 Mpps/lõi (phụ thuộc nhiều vào độ phức tạp của quy tắc) |
| Chi phí CPU | Tối thiểu, không có sk_buff hoặc chuyển đổi ngữ cảnh | Đáng kể, cấp phát sk_buff, duyệt ngăn xếp |
| Sử dụng bộ nhớ | Tối thiểu, không có sk_buff trên mỗi gói tin | Cao, sk_buff trên mỗi gói tin |
| Tính linh hoạt | Các hàm trợ giúp BPF hạn chế, ngôn ngữ giống C | API kernel đầy đủ, bộ quy tắc phức tạp |
| Tính trạng thái | Không trạng thái hoặc trạng thái hạn chế qua bản đồ BPF | Có trạng thái (ví dụ: theo dõi kết nối) |
| Triển khai | Yêu cầu libbpf, kernel 4.8+ (XDP), 5.x+ (đầy đủ) | Tính năng kernel tiêu chuẩn, có sẵn rộng rãi |
| Trường hợp sử dụng | DDoS khối lượng lớn, cân bằng tải, đường dẫn nhanh | Tường lửa chung, NAT, thực thi chính sách phức tạp |
Đánh đổi:
- Độ phức tạp: Các chương trình XDP được viết bằng C và yêu cầu hiểu sâu hơn về các giao thức mạng và nội bộ eBPF. Gỡ lỗi có thể khó khăn.
- Hỗ trợ Driver: Hiệu suất XDP tối ưu (
XDP_DRV_MODE) phụ thuộc vào hỗ trợ driver NIC. Nếu không có nó,XDP_SKB_MODEmang lại một số lợi ích nhưng vẫn liên quan đến cấp phátsk_buff. - Ngữ cảnh hạn chế: Các chương trình XDP có một cái nhìn hạn chế về hệ thống. Chúng không thể dễ dàng truy cập thông tin tiến trình hoặc trạng thái kernel phức tạp.
Những vấn đề và cách khắc phục trong sản xuất
-
XDP_DRV_MODEso vớiXDP_SKB_MODE:- Vấn đề: Cố gắng tải một chương trình XDP trong
XDP_DRV_MODEtrên một driver NIC không hỗ trợ nó sẽ thất bại hoặc âm thầm quay trở lạiXDP_SKB_MODEnếuXDP_FLAGS_UPDATE_IF_NOEXISTđược sử dụng. Hiệu suất sẽ bị suy giảm đáng kể. - Cách khắc phục: Luôn kiểm tra
ethtool -i <interface>chodrivervàfirmware-version. Tham khảoip link show dev <interface>cho các cờxdp. Ưu tiênXDP_DRV_MODEvà quay trở lạiXDP_SKB_MODEmột cách duyên dáng nếu cần, nhưng hãy lưu ý đến các tác động về hiệu suất. Đối với sản xuất, hãy đảm bảo NIC của bạn (ví dụ: Intel ixgbe, i40e, mlx5) có hỗ trợ driver phù hợp.
- Vấn đề: Cố gắng tải một chương trình XDP trong
-
Lỗi trình xác minh eBPF:
- Vấn đề: Các chương trình eBPF phức tạp, đặc biệt là những chương trình có vòng lặp hoặc truy cập bộ nhớ rộng rãi, có thể bị trình xác minh eBPF của kernel từ chối. Các lỗi phổ biến bao gồm "chương trình quá lớn," "vòng lặp không có giới hạn," hoặc "truy cập bộ nhớ không hợp lệ."
- Cách khắc phục: Đơn giản hóa logic eBPF của bạn. Chia nhỏ các tác vụ phức tạp thành các hàm nhỏ hơn, có thể xác minh được. Đảm bảo tất cả các vòng lặp có giới hạn rõ ràng. Sử dụng
bpf_printkđể gỡ lỗi (có thể xem quasudo cat /sys/kernel/debug/tracing/trace_pipe). Lệnhbpftool prog loadvớilog_level=2cung cấp đầu ra trình xác minh chi tiết.
-
Ghim và duy trì bản đồ:
- Vấn đề: Nếu agent không gian người dùng của bạn gặp sự cố hoặc khởi động lại, chương trình eBPF và các bản đồ của nó có thể bị dỡ bỏ, dẫn đến gián đoạn dịch vụ.
- Cách khắc phục: Sử dụng ghim bản đồ BPF (
bpf_obj_pin) để duy trì bản đồ trong hệ thống tệp BPF (/sys/fs/bpf). Chương trình XDP sau đó có thể được tải và gắn, tham chiếu các bản đồ đã ghim. Điều này cho phép quản lý vòng đời độc lập của chương trình và trạng thái của nó.
-
Sắp xếp lại/Mất gói tin với
XDP_REDIRECT:- Vấn đề: Nếu sử dụng
XDP_REDIRECTđể gửi gói tin đến một giao diện hoặc CPU khác, hãy đảm bảo đầu nhận có thể xử lý lưu lượng truy cập. Chuyển hướng không chính xác có thể dẫn đến mất gói tin hoặc phân phối không theo thứ tự, đặc biệt là trên các hàng đợi hoặc CPU khác nhau mà không có sự đồng bộ hóa thích hợp. - Cách khắc phục: Thiết kế cẩn thận logic chuyển hướng của bạn. Đối với giao tiếp giữa các CPU, sử dụng
BPF_MAP_TYPE_CPUMAP. Đối với chuyển hướng đến các giao diện khác, đảm bảo giao diện đích được cấu hình chính xác và có đủ dung lượng.
- Vấn đề: Nếu sử dụng
-
Giới hạn tài nguyên (
memlock):- Vấn đề: Tải các chương trình hoặc bản đồ eBPF lớn có thể đạt đến giới hạn tài nguyên
memlock, khiếnbpf_load_programhoặcbpf_create_mapthất bại với "Operation not permitted" hoặc "Cannot allocate memory." - Cách khắc phục: Tăng giới hạn
memlockcho tiến trình không gian người dùng. Đối với các dịch vụ systemd, sử dụngLimitMEMLOCK=infinity. Đối với thực thi thủ công, sử dụngulimit -l unlimitedtrước khi chạy chương trình. Trợ giúprlimit.RemoveMemlock()của Go giải quyết vấn đề này.
- Vấn đề: Tải các chương trình hoặc bản đồ eBPF lớn có thể đạt đến giới hạn tài nguyên
Các câu hỏi thường gặp
-
Phiên bản kernel nào được yêu cầu cho XDP? XDP được giới thiệu trong kernel Linux 4.8. Để có XDP ổn định và giàu tính năng, nên dùng kernel 4.18+.
BPF_MAP_TYPE_LPM_TRIEcó sẵn từ 4.11. -
Các chương trình XDP có thể kiểm tra tải trọng gói tin ngoài các tiêu đề không? Có, các chương trình XDP có thể kiểm tra toàn bộ tải trọng gói tin, miễn là chúng nằm trong các con trỏ
datavàdata_end. Tuy nhiên, việc phân tích cú pháp các giao thức lớp ứng dụng phức tạp trực tiếp trong eBPF có thể khó khăn do các hạn chế của trình xác minh (ví dụ: vòng lặp có giới hạn, kích thước ngăn xếp). Đối với kiểm tra gói tin sâu, XDP thường hoạt động như một bộ lọc đường dẫn nhanh, chuyển các gói tin thú vị đến một tiến trình không gian người dùng để phân tích thêm. -
XDP so sánh với DPDK như thế nào? DPDK (Data Plane Development Kit) là một framework không gian người dùng bỏ qua hoàn toàn kernel bằng cách thăm dò trực tiếp các NIC. Nó cung cấp khả năng kiểm soát và hiệu suất tối ưu nhưng yêu cầu phần cứng chuyên dụng và thường liên quan đến những thay đổi đáng kể ở cấp ứng dụng. Ngược lại, XDP được tích hợp kernel, tận dụng các driver hiện có và mô hình bảo mật của kernel. XDP thường dễ triển khai và tích hợp vào các hệ thống Linux hiện có hơn, cung cấp hiệu suất gần như DPDK cho nhiều trường hợp sử dụng mà không có chi phí bỏ qua kernel hoàn toàn.
-
Có thể triển khai lọc trạng thái với XDP không? Lọc trạng thái trực tiếp như theo dõi kết nối TCP truyền thống rất khó trong XDP do mô hình thực thi không trạng thái và các ràng buộc của trình xác minh. Tuy nhiên, bạn có thể đạt được trạng thái hạn chế bằng cách sử dụng bản đồ BPF. Ví dụ, một bản đồ
BPF_MAP_TYPE_LRU_HASHcó thể lưu trữ các bộ kết nối (IP nguồn, IP đích, cổng nguồn, cổng đích) và trạng thái của chúng (ví dụ: SYN_SENT, ESTABLISHED) trong một thời gian ngắn. Điều này yêu cầu quản lý cẩn thận các mục bản đồ (ví dụ: thời gian chờ, thu gom rác) từ không gian người dùng hoặc thông qua các bộ đệm vòng BPF để thông báo sự kiện. -
Làm cách nào để kiểm tra chương trình XDP của tôi mà không ảnh hưởng đến lưu lượng truy cập sản xuất? Kiểm tra các chương trình XDP một cách an toàn là rất quan trọng.
- Máy ảo/Container: Sử dụng môi trường ảo (ví dụ: KVM, Docker với các cặp
veth) để mô phỏng lưu lượng mạng và kiểm tra các chương trình XDP mà không ảnh hưởng đến phần cứng vật lý. XDP_SKB_MODE: Mặc dù chậm hơn,XDP_SKB_MODEthường mạnh mẽ hơn trên các driver khác nhau và có thể là một môi trường thử nghiệm ban đầu an toàn hơn.ip link set dev <interface> xdp obj <program.o> section xdp verbose: Lệnh này cho phép tải các chương trình XDP. Sử dụngverboseđể nhận thông báo lỗi chi tiết.bpftool: Tiện íchbpftoolrất có giá trị để kiểm tra các chương trình, bản đồ đã tải và trạng thái của chúng.bpftool prog showvàbpftool map showlà rất cần thiết.- Bộ tạo lưu lượng: Sử dụng các công cụ như
pktgen,hping3hoặcscapyđể tạo các mẫu lưu lượng cụ thể (ví dụ: SYN floods) để kiểm tra logic giảm thiểu của bạn.
- Máy ảo/Container: Sử dụng môi trường ảo (ví dụ: KVM, Docker với các cặp
Free In-Browser Developer Tools
Clean AI CLI logs, build cron expressions, decode JWTs, and calculate chmod permissions offline.
Related Articles

VPN và Proxy: Khác biệt, Fingerprinting, Rò rỉ và Kiểm tra quyền riêng tư
Tôi đã dành nhiều tháng để kiểm tra VPN và proxy trên Linux, phát hiện rò rỉ IPv6 trong thiết lập của riêng mình, làm hỏng dấu vân tay trình duyệt với quá nhiều tiện ích mở rộng và tìm hiểu những gì thực sự hiệu quả cho quyền riêng tư.
Read more
Cách tăng cường bảo mật Firefox trên Linux (Hướng dẫn cho người mới bắt đầu)
Tôi đã dành một buổi chiều để khóa chặt cài đặt Firefox của mình và giảm đáng kể mức độ bị theo dõi. Đây là những gì thực sự hiệu quả, những gì không, và những sai lầm tôi đã mắc phải.
Read more
Triển khai kiến trúc Zero Trust vào năm 2026
Hướng dẫn thực tế để triển khai Kiến trúc Zero Trust (ZTA) vào năm 2026: bảo mật ưu tiên danh tính, SPIFFE/SPIRE, phân đoạn vi mô eBPF và mTLS.
Read more