/* Copyright (c) 2016 Thomas Graf <tgraf@tgraf.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include "vmlinux.h"
#include "net_shared.h"
#include <bpf/bpf_helpers.h>
#include <string.h>
# define printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof (____fmt), \
## __VA_ARGS__); \
})
#define CB_MAGIC 1234
/* Test: Pass all packets through */
SEC("nop" )
int do_nop(struct __sk_buff *skb)
{
return BPF_OK;
}
/* Test: Verify context information can be accessed */
SEC("test_ctx" )
int do_test_ctx(struct __sk_buff *skb)
{
skb->cb[0 ] = CB_MAGIC;
printk("len %d hash %d protocol %d" , skb->len, skb->hash,
skb->protocol);
printk("cb %d ingress_ifindex %d ifindex %d" , skb->cb[0 ],
skb->ingress_ifindex, skb->ifindex);
return BPF_OK;
}
/* Test: Ensure skb->cb[] buffer is cleared */
SEC("test_cb" )
int do_test_cb(struct __sk_buff *skb)
{
printk("cb0: %x cb1: %x cb2: %x" , skb->cb[0 ], skb->cb[1 ],
skb->cb[2 ]);
printk("cb3: %x cb4: %x" , skb->cb[3 ], skb->cb[4 ]);
return BPF_OK;
}
/* Test: Verify skb data can be read */
SEC("test_data" )
int do_test_data(struct __sk_buff *skb)
{
void *data = (void *)(long )skb->data;
void *data_end = (void *)(long )skb->data_end;
struct iphdr *iph = data;
if (data + sizeof (*iph) > data_end) {
printk("packet truncated" );
return BPF_DROP;
}
printk("src: %x dst: %x" , iph->saddr, iph->daddr);
return BPF_OK;
}
#define IP_CSUM_OFF offsetof(struct iphdr, check)
#define IP_DST_OFF offsetof(struct iphdr, daddr)
#define IP_SRC_OFF offsetof(struct iphdr, saddr)
#define IP_PROTO_OFF offsetof(struct iphdr, protocol)
#define TCP_CSUM_OFF offsetof(struct tcphdr, check)
#define UDP_CSUM_OFF offsetof(struct udphdr, check)
#define IS_PSEUDO 0 x10
static inline int rewrite(struct __sk_buff *skb, uint32_t old_ip,
uint32_t new_ip, int rw_daddr)
{
int ret, off = 0 , flags = IS_PSEUDO;
uint8_t proto;
ret = bpf_skb_load_bytes(skb, IP_PROTO_OFF, &proto, 1 );
if (ret < 0 ) {
printk("bpf_l4_csum_replace failed: %d" , ret);
return BPF_DROP;
}
switch (proto) {
case IPPROTO_TCP:
off = TCP_CSUM_OFF;
break ;
case IPPROTO_UDP:
off = UDP_CSUM_OFF;
flags |= BPF_F_MARK_MANGLED_0;
break ;
case IPPROTO_ICMPV6:
off = offsetof(struct icmp6hdr, icmp6_cksum);
break ;
}
if (off) {
ret = bpf_l4_csum_replace(skb, off, old_ip, new_ip,
flags | sizeof (new_ip));
if (ret < 0 ) {
printk("bpf_l4_csum_replace failed: %d" );
return BPF_DROP;
}
}
ret = bpf_l3_csum_replace(skb, IP_CSUM_OFF, old_ip, new_ip, sizeof (new_ip));
if (ret < 0 ) {
printk("bpf_l3_csum_replace failed: %d" , ret);
return BPF_DROP;
}
if (rw_daddr)
ret = bpf_skb_store_bytes(skb, IP_DST_OFF, &new_ip, sizeof (new_ip), 0 );
else
ret = bpf_skb_store_bytes(skb, IP_SRC_OFF, &new_ip, sizeof (new_ip), 0 );
if (ret < 0 ) {
printk("bpf_skb_store_bytes() failed: %d" , ret);
return BPF_DROP;
}
return BPF_OK;
}
/* Test: Verify skb data can be modified */
SEC("test_rewrite" )
int do_test_rewrite(struct __sk_buff *skb)
{
uint32_t old_ip, new_ip = 0 x3fea8c0;
int ret;
ret = bpf_skb_load_bytes(skb, IP_DST_OFF, &old_ip, 4 );
if (ret < 0 ) {
printk("bpf_skb_load_bytes failed: %d" , ret);
return BPF_DROP;
}
if (old_ip == 0 x2fea8c0) {
printk("out: rewriting from %x to %x" , old_ip, new_ip);
return rewrite(skb, old_ip, new_ip, 1 );
}
return BPF_OK;
}
static inline int __do_push_ll_and_redirect(struct __sk_buff *skb)
{
uint64_t smac = SRC_MAC, dmac = DST_MAC;
int ret, ifindex = DST_IFINDEX;
struct ethhdr ehdr;
ret = bpf_skb_change_head(skb, 14 , 0 );
if (ret < 0 ) {
printk("skb_change_head() failed: %d" , ret);
}
ehdr.h_proto = bpf_htons(ETH_P_IP);
memcpy(&ehdr.h_source, &smac, 6 );
memcpy(&ehdr.h_dest, &dmac, 6 );
ret = bpf_skb_store_bytes(skb, 0 , &ehdr, sizeof (ehdr), 0 );
if (ret < 0 ) {
printk("skb_store_bytes() failed: %d" , ret);
return BPF_DROP;
}
return bpf_redirect(ifindex, 0 );
}
SEC("push_ll_and_redirect_silent" )
int do_push_ll_and_redirect_silent(struct __sk_buff *skb)
{
return __do_push_ll_and_redirect(skb);
}
SEC("push_ll_and_redirect" )
int do_push_ll_and_redirect(struct __sk_buff *skb)
{
int ret, ifindex = DST_IFINDEX;
ret = __do_push_ll_and_redirect(skb);
if (ret >= 0 )
printk("redirected to %d" , ifindex);
return ret;
}
static inline void __fill_garbage(struct __sk_buff *skb)
{
uint64_t f = 0 xFFFFFFFFFFFFFFFF;
bpf_skb_store_bytes(skb, 0 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 8 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 16 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 24 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 32 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 40 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 48 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 56 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 64 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 72 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 80 , &f, sizeof (f), 0 );
bpf_skb_store_bytes(skb, 88 , &f, sizeof (f), 0 );
}
SEC("fill_garbage" )
int do_fill_garbage(struct __sk_buff *skb)
{
__fill_garbage(skb);
printk("Set initial 96 bytes of header to FF" );
return BPF_OK;
}
SEC("fill_garbage_and_redirect" )
int do_fill_garbage_and_redirect(struct __sk_buff *skb)
{
int ifindex = DST_IFINDEX;
__fill_garbage(skb);
printk("redirected to %d" , ifindex);
return bpf_redirect(ifindex, 0 );
}
/* Drop all packets */
SEC("drop_all" )
int do_drop_all(struct __sk_buff *skb)
{
printk("dropping with: %d" , BPF_DROP);
return BPF_DROP;
}
char _license[] SEC("license" ) = "GPL" ;
Messung V0.5 in Prozent C=96 H=94 G=94
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-07)
¤
*© Formatika GbR, Deutschland