specializing the data path - hooking into the linux network stack
TRANSCRIPT
●○
●○
●○
●
struct sockaddr_ll { unsigned short sll_family; unsigned short sll_protocol; int sll_ifindex; unsigned short sll_hatype; unsigned char sll_pkttype; unsigned char sll_halen; unsigned char sll_addr[8];};
●○ setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, …)
●
# sudo tcpdump -d arp(000) ldh [12](001) jeq #0x806 jt 2 jf 3(002) ret #262144(003) ret #0
# sudo tcpdump -dd arp{ 0x28, 0, 0, 0x0000000c },{ 0x15, 0, 1, 0x00000806 },{ 0x6, 0, 0, 0x00040000 },{ 0x6, 0, 0, 0x00000000 },
int nf_register_net_hook(struct net *net, const struct nf_hook_ops *ops);
int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg, unsigned int n);
int nf_register_hook(struct nf_hook_ops *reg);
int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n);
static struct nf_hook_ops ipv4_synproxy_ops[] = { { .hook = ipv4_synproxy_hook, .pf = NFPROTO_IPV4, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1, .priv = NULL, }, { .hook = ipv4_synproxy_hook, .pf = NFPROTO_IPV4, .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP_PRI_CONNTRACK_CONFIRM - 1, .priv = NULL, },};
static unsigned int ipv4_synproxy_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *nhs)
{ do_stuff();
if (...) return NF_ACCEPT;
do_more_stuff();
if (...) return NF_DROP;
return NF_ACCEPT;}
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 \ u32 match ip src 4.3.2.1/32 match ip sport 80 0xffff \ flowid 1:3
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 \ u32 match u16 0x0000 0xffc0 at 2 flowid 1:4
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 \ handle 1 fw classid 1:10
# tc filter add dev eth0 parent 1: \ basic match 'meta(priority eq 6)' classid 1:10
# tc filter add dev eth0 parent 1:0 \ bpf obj bpf.o sec mycls flowid 1:1
# tc qdisc add dev eth0 ingress# tc filter add dev eth0 parent ffff: protocol all prio 1 \ u32 match u32 0 0 \ action mirred egress redirect dev eth1
# tc filter add dev eth0 parent ffff: protocol ip prio 6 \ u32 match ip src 10.0.0.9/32 action drop
# tc filter add dev eth0 parent ffff: pref 11 protocol ip \ u32 match ip protocol 1 0xff flowid 1:1 \ u32 match ip src 10.0.0.2 flowid 1:1 \ action vlan push id 123
# tc filter replace dev eth0 parent ffff: \ basic \ action bpf obj bpf.o sec my-action
static inline void set_tcp_dest_port(struct __sk_buff *skb, __u16 new_port)
{
__u16 old_port = htons(load_half(skb, TCP_DPORT_OFF));
bpf_skb_store_bytes(skb, TCP_DPORT_OFF, &new_port, sizeof(new_port), 0);
bpf_l4_csum_replace(skb, TCP_CSUM_OFF, old_port, new_port, sizeof(new_port));
}
__attribute__((section("redirect_xmit"), used))
int _redirect_xmit(struct __sk_buff *skb)
{
__u8 proto = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol));
if (proto == IPPROTO_TCP)
set_tcp_dest_port(skb, 5001);
return bpf_redirect(skb->ifindex + 1, 0);
}
struct bpf_map_def __attribute__((section("maps"), used)) my_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(long),
.max_entries = 256,
};
__attribute__((section("socket1"), used))
int bpf_prog1(struct __sk_buff *skb)
{
int index = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol));
long *value;
if (skb->pkt_type != PACKET_OUTGOING)
return 0;
value = bpf_map_lookup_elem(&my_map, &index);
if (value)
__sync_fetch_and_add(value, skb->len);
return 0;
}