forked from iovisor/bcc
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
455 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
file(GLOB C_FILES *.c) | ||
file(GLOB LUA_FILES *.lua) | ||
install(FILES ${C_FILES} DESTINATION share/bcc/examples/lua) | ||
install(PROGRAMS ${LUA_FILES} DESTINATION share/bcc/examples/lua) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* | ||
* dns_matching.c Drop DNS packets requesting DNS name contained in hash map | ||
* For Linux, uses BCC, eBPF. See .py file. | ||
* | ||
* Copyright (c) 2016 Rudi Floren. | ||
* 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. | ||
* | ||
* 11-May-2016 Rudi Floren Created this. | ||
*/ | ||
|
||
#include <uapi/linux/bpf.h> | ||
#include <uapi/linux/if_ether.h> | ||
#include <uapi/linux/if_packet.h> | ||
#include <uapi/linux/ip.h> | ||
#include <uapi/linux/in.h> | ||
#include <uapi/linux/udp.h> | ||
#include <bcc/proto.h> | ||
|
||
#define ETH_LEN 14 | ||
|
||
struct dns_hdr_t | ||
{ | ||
uint16_t id; | ||
uint16_t flags; | ||
uint16_t qdcount; | ||
uint16_t ancount; | ||
uint16_t nscount; | ||
uint16_t arcount; | ||
} BPF_PACKET_HEADER; | ||
|
||
|
||
struct dns_query_flags_t | ||
{ | ||
uint16_t qtype; | ||
uint16_t qclass; | ||
} BPF_PACKET_HEADER; | ||
|
||
struct dns_char_t | ||
{ | ||
char c; | ||
} BPF_PACKET_HEADER; | ||
|
||
struct Key { | ||
unsigned char p[32]; | ||
}; | ||
|
||
struct Leaf { | ||
// Not really needed in this example | ||
unsigned char p[4]; | ||
}; | ||
|
||
BPF_TABLE("hash", struct Key, struct Leaf, cache, 128); | ||
|
||
int dns_matching(struct __sk_buff *skb) | ||
{ | ||
u8 *cursor = 0; | ||
struct Key key = {}; | ||
// Check of ethernet/IP frame. | ||
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet)); | ||
if(ethernet->type == ETH_P_IP) { | ||
|
||
// Check for UDP. | ||
struct ip_t *ip = cursor_advance(cursor, sizeof(*ip)); | ||
u16 hlen_bytes = ip->hlen << 2; | ||
if(ip->nextp == IPPROTO_UDP) { | ||
|
||
// Check for Port 53, DNS packet. | ||
struct udp_t *udp = cursor_advance(cursor, sizeof(*udp)); | ||
if(udp->dport == 53){ | ||
|
||
// Our Cursor + the length of our udp packet - size of the udp header | ||
// - the two 16bit values for QTYPE and QCLASS. | ||
u8 *sentinel = cursor + udp->length - sizeof(*udp) - 4; | ||
|
||
struct dns_hdr_t *dns_hdr = cursor_advance(cursor, sizeof(*dns_hdr)); | ||
|
||
// Do nothing if packet is not a request. | ||
if((dns_hdr->flags >>15) != 0) { | ||
// Exit if this packet is not a request. | ||
return -1; | ||
} | ||
|
||
u16 i = 0; | ||
struct dns_char_t *c; | ||
// This unroll worked not in latest BCC version. | ||
for(u8 j = 0; i<255;i++){ | ||
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c; | ||
} | ||
end: | ||
{} | ||
|
||
struct Leaf * lookup_leaf = cache.lookup(&key); | ||
|
||
// If DNS name is contained in our map, drop packet. | ||
if(lookup_leaf) { | ||
return 0; | ||
} | ||
} | ||
} | ||
} | ||
|
||
return -1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#!/usr/bin/python | ||
|
||
from __future__ import print_function | ||
from bcc import BPF | ||
from ctypes import * | ||
|
||
import sys | ||
import socket | ||
import os | ||
import struct | ||
|
||
|
||
def encode_dns(name): | ||
size = 32 | ||
if len(name) > 253: | ||
raise Exception("DNS Name too long.") | ||
b = bytearray(size) | ||
i = 0; | ||
elements = name.split(".") | ||
for element in elements: | ||
b[i] = struct.pack("!B", len(element)) | ||
i += 1 | ||
for j in range(0, len(element)): | ||
b[i] = element[j] | ||
i += 1 | ||
|
||
|
||
return (c_ubyte * size).from_buffer(b) | ||
|
||
|
||
|
||
# initialize BPF - load source code from http-parse-simple.c | ||
bpf = BPF(src_file = "dns_matching.c", debug=0) | ||
# print(bpf.dump_func("dns_test")) | ||
|
||
#load eBPF program http_filter of type SOCKET_FILTER into the kernel eBPF vm | ||
#more info about eBPF program types | ||
#http:https://man7.org/linux/man-pages/man2/bpf.2.html | ||
function_dns_matching = bpf.load_func("dns_matching", BPF.SOCKET_FILTER) | ||
|
||
|
||
#create raw socket, bind it to eth0 | ||
#attach bpf program to socket created | ||
BPF.attach_raw_socket(function_dns_matching, "eth1") | ||
|
||
# Get the table. | ||
cache = bpf.get_table("cache") | ||
|
||
# Create first entry for foo.bar | ||
key = cache.Key() | ||
key.p = encode_dns("foo.bar") | ||
|
||
leaf = cache.Leaf() | ||
leaf.p = (c_ubyte * 4).from_buffer(bytearray(4)) | ||
cache[key] = leaf | ||
|
||
bpf.trace_print() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
set(FILES http-parse-complete.c http-parse-simple.c README.md) | ||
set(PROGRAMS http-parse-complete.py http-parse-simple.py) | ||
install(FILES ${FILES} DESTINATION share/bcc/examples/networking/http_filter) | ||
install(PROGRAMS ${PROGRAMS} DESTINATION share/bcc/examples/networking/http_filter) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
set(FILES README.md chord.png monitor.c simulation.py vxlan.jpg) | ||
set(PROGRAMS main.py monitor.py setup.sh traffic.sh) | ||
install(FILES ${FILES} DESTINATION share/bcc/examples/networking/tunnel_monitor) | ||
install(PROGRAMS ${PROGRAMS} DESTINATION share/bcc/examples/networking/tunnel_monitor) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
#!/usr/bin/env bcc-lua | ||
--[[ | ||
Copyright 2016 GitHub, Inc | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http:https://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
--]] | ||
|
||
local program = [[ | ||
#include <uapi/linux/ptrace.h> | ||
#include <linux/blkdev.h> | ||
struct val_t { | ||
u32 pid; | ||
char name[TASK_COMM_LEN]; | ||
}; | ||
struct data_t { | ||
u32 pid; | ||
u64 rwflag; | ||
u64 delta; | ||
u64 sector; | ||
u64 len; | ||
u64 ts; | ||
char disk_name[DISK_NAME_LEN]; | ||
char name[TASK_COMM_LEN]; | ||
}; | ||
BPF_HASH(start, struct request *); | ||
BPF_HASH(infobyreq, struct request *, struct val_t); | ||
BPF_PERF_OUTPUT(events); | ||
// cache PID and comm by-req | ||
int trace_pid_start(struct pt_regs *ctx, struct request *req) | ||
{ | ||
struct val_t val = {}; | ||
if (bpf_get_current_comm(&val.name, sizeof(val.name)) == 0) { | ||
val.pid = bpf_get_current_pid_tgid(); | ||
infobyreq.update(&req, &val); | ||
} | ||
return 0; | ||
} | ||
// time block I/O | ||
int trace_req_start(struct pt_regs *ctx, struct request *req) | ||
{ | ||
u64 ts; | ||
ts = bpf_ktime_get_ns(); | ||
start.update(&req, &ts); | ||
return 0; | ||
} | ||
// output | ||
int trace_req_completion(struct pt_regs *ctx, struct request *req) | ||
{ | ||
u64 *tsp, delta; | ||
u32 *pidp = 0; | ||
struct val_t *valp; | ||
struct data_t data ={}; | ||
u64 ts; | ||
// fetch timestamp and calculate delta | ||
tsp = start.lookup(&req); | ||
if (tsp == 0) { | ||
// missed tracing issue | ||
return 0; | ||
} | ||
ts = bpf_ktime_get_ns(); | ||
data.delta = ts - *tsp; | ||
data.ts = ts / 1000; | ||
valp = infobyreq.lookup(&req); | ||
if (valp == 0) { | ||
data.len = req->__data_len; | ||
strcpy(data.name,"?"); | ||
} else { | ||
data.pid = valp->pid; | ||
data.len = req->__data_len; | ||
data.sector = req->__sector; | ||
bpf_probe_read(&data.name, sizeof(data.name), valp->name); | ||
bpf_probe_read(&data.disk_name, sizeof(data.disk_name), | ||
req->rq_disk->disk_name); | ||
} | ||
if (req->cmd_flags & REQ_WRITE) { | ||
data.rwflag=1; | ||
} else { | ||
data.rwflag=0; | ||
} | ||
events.perf_submit(ctx,&data,sizeof(data)); | ||
start.delete(&req); | ||
infobyreq.delete(&req); | ||
return 0; | ||
} | ||
]] | ||
|
||
local ffi = require("ffi") | ||
|
||
return function(BPF, utils) | ||
local bpf = BPF:new{text=program} | ||
|
||
bpf:attach_kprobe{event="blk_account_io_start", fn_name="trace_pid_start"} | ||
bpf:attach_kprobe{event="blk_start_request", fn_name="trace_req_start"} | ||
bpf:attach_kprobe{event="blk_mq_start_request", fn_name="trace_req_start"} | ||
bpf:attach_kprobe{event="blk_account_io_completion", | ||
fn_name="trace_req_completion"} | ||
|
||
print("%-14s %-14s %-6s %-7s %-2s %-9s %-7s %7s" % {"TIME(s)", "COMM", "PID", | ||
"DISK", "T", "SECTOR", "BYTES", "LAT(ms)"}) | ||
|
||
local rwflg = "" | ||
local start_ts = 0 | ||
local prev_ts = 0 | ||
local delta = 0 | ||
|
||
local function print_event(cpu, event) | ||
local val = -1 | ||
local event_pid = event.pid | ||
local event_delta = tonumber(event.delta) | ||
local event_sector = tonumber(event.sector) | ||
local event_len = tonumber(event.len) | ||
local event_ts = tonumber(event.ts) | ||
local event_disk_name = ffi.string(event.disk_name) | ||
local event_name = ffi.string(event.name) | ||
|
||
if event.rwflag == 1 then | ||
rwflg = "W" | ||
end | ||
|
||
if event.rwflag == 0 then | ||
rwflg = "R" | ||
end | ||
|
||
if not event_name:match("%?") then | ||
val = event_sector | ||
end | ||
|
||
if start_ts == 0 then | ||
prev_ts = start_ts | ||
end | ||
|
||
if start_ts == 1 then | ||
delta = delta + (event_ts - prev_ts) | ||
end | ||
|
||
print("%-14.9f %-14.14s %-6s %-7s %-2s %-9s %-7s %7.2f" % { | ||
delta / 1000000, event_name, event_pid, event_disk_name, rwflg, val, | ||
event_len, event_delta / 1000000}) | ||
|
||
prev_ts = event_ts | ||
start_ts = 1 | ||
end | ||
|
||
local TASK_COMM_LEN = 16 -- linux/sched.h | ||
local DISK_NAME_LEN = 32 -- linux/genhd.h | ||
|
||
bpf:get_table("events"):open_perf_buffer(print_event, [[ | ||
struct { | ||
uint32_t pid; | ||
uint64_t rwflag; | ||
uint64_t delta; | ||
uint64_t sector; | ||
uint64_t len; | ||
uint64_t ts; | ||
char disk_name[%d]; | ||
char name[%d]; | ||
} | ||
]] % {DISK_NAME_LEN, TASK_COMM_LEN}) | ||
bpf:kprobe_poll_loop() | ||
end |
Oops, something went wrong.