#include <stddef.h> #include "bpf.h" #include <linux/netfilter_ipv4.h> #include <linux/in.h>
#include "bpf-builtin.h" #include "bpf-utils.h"
#define MAX_CONNECTIONS 20000
struct Config { __u16 proxy_port; __u64 pipy_pid; };
struct Socket { __u32 src_addr; __u16 src_port; __u32 dst_addr; __u16 dst_port; };
struct { int (*type)[BPF_MAP_TYPE_HASH]; int (*max_entries)[1]; __u32 *key; struct Config *value; } map_config SEC(".maps");
struct { int (*type)[BPF_MAP_TYPE_HASH]; int (*max_entries)[MAX_CONNECTIONS]; __u64 *key; struct Socket *value; } map_socks SEC(".maps");
struct { int (*type)[BPF_MAP_TYPE_HASH]; int (*max_entries)[MAX_CONNECTIONS]; __u16 *key; __u64 *value; } map_ports SEC(".maps");
int cg_connect4(struct bpf_sock_addr *ctx) { if (ctx->user_family != 2) return 1; if (ctx->protocol != IPPROTO_TCP) return 1;
__u32 i = 0; struct Config *conf = bpf_map_lookup_elem(&map_config, &i); if (!conf) return 1; if ((bpf_get_current_pi
It looks like your code snippet was cut off. However, I can provide some insights and suggestions based on the provided code.
The code appears to be an eBPF program designed to handle network connections, specifically for TCP connections in an IPv4 context. The program uses several eBPF maps to store configuration, socket information, and port mappings. Here's a breakdown of the key components and some suggestions for completing the function cg_connect4
:
Configuration Map (map_config
):
pipy_pid
).Socket Map (map_socks
):
Port Map (map_ports
):
cg_connect4
FunctionThis function is a BPF program that is triggered on a connect syscall for IPv4 TCP connections. The function performs the following steps:
Check the Address Family and Protocol:
user_family == 2
) and TCP (protocol == IPPROTO_TCP
).Lookup Configuration:
map_config
.Check Process ID:
To complete the cg_connect4
function, you need to handle the connection logic based on the configuration and possibly update the socket and port maps. Here is a possible continuation and completion of the function:
int cg_connect4(struct bpf_sock_addr *ctx) {
if (ctx->user_family != AF_INET) return 1;
if (ctx->protocol != IPPROTO_TCP) return 1;
__u32 i = 0;
struct Config *conf = bpf_map_lookup_elem(&map_config, &i);
if (!conf) return 1;
// Check if the current process ID matches the configured pipy_pid
if (bpf_get_current_pid_tgid() >> 32 != conf->pipy_pid) return 1;
// Create a unique key for the connection
__u64 key = ((__u64)ctx->user_ip4 << 32) | ctx->user_port;
// Lookup the socket information in the map_socks
struct Socket sock = {
.src_addr = ctx->user_ip4,
.src_port = ctx->user_port,
.dst_addr = ctx->msg_src_ip4,
.dst_port = ctx->msg_src_port
};
// Update the socket map with the new connection
bpf_map_update_elem(&map_socks, &key, &sock, BPF_ANY);
// Update the port map with the new connection
bpf_map_update_elem(&map_ports, &ctx->user_port, &key, BPF_ANY);
// Redirect the connection to the proxy port if necessary
if (ctx->user_port == conf->proxy_port) {
ctx->user_ip4 = bpf_htonl(INADDR_LOOPBACK);
ctx->user_port = bpf_htons(conf->proxy_port);
}
return 0;
}
Check Process ID:
pipy_pid
. If not, it returns 1 to allow the connection to proceed normally.Create a Unique Key:
Update Socket Map:
map_socks
map using the unique key.Update Port Map:
Redirect Connection:
This is a basic implementation and may need adjustments based on your specific requirements and environment. Make sure to test thoroughly in a