specializing the data path - hooking into the linux network stack

49

Upload: kernel-tlv

Post on 14-Jan-2017

553 views

Category:

Software


2 download

TRANSCRIPT

●●●●●

●○○○

●○

●●●●

packet_socket = socket(AF_PACKET, int socket_type, int protocol);

●○

●○

●○

●○

●●

●○ htons(ETH_P_EAPOL), htons(ETH_P_IP)

●○○○

… …

●○

●○

●○

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;

}

●●

○○○○

●●●

●●●●

●●●●●●●●