Commit b263926f authored by Qasim Sarfraz's avatar Qasim Sarfraz

Merge branch 'master' into patch-1

parents f712dca2 a67ef8aa
...@@ -3,3 +3,4 @@ install(PROGRAMS ${EXAMPLE_PROGRAMS} DESTINATION share/bcc/examples) ...@@ -3,3 +3,4 @@ install(PROGRAMS ${EXAMPLE_PROGRAMS} DESTINATION share/bcc/examples)
add_subdirectory(networking) add_subdirectory(networking)
add_subdirectory(tracing) add_subdirectory(tracing)
add_subdirectory(lua)
\ No newline at end of file
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)
\ No newline at end of file
...@@ -6,3 +6,5 @@ install(PROGRAMS ${EXAMPLE_PROGRAMS} DESTINATION share/bcc/examples/networking) ...@@ -6,3 +6,5 @@ install(PROGRAMS ${EXAMPLE_PROGRAMS} DESTINATION share/bcc/examples/networking)
add_subdirectory(distributed_bridge) add_subdirectory(distributed_bridge)
add_subdirectory(neighbor_sharing) add_subdirectory(neighbor_sharing)
add_subdirectory(vlan_learning) add_subdirectory(vlan_learning)
add_subdirectory(tunnel_monitor)
add_subdirectory(http_filter)
\ No newline at end of file
/*
* 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;
}
#!/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://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()
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)
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)
\ No newline at end of file
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <luajit-2.0/lauxlib.h> #include "lauxlib.h"
#include <luajit-2.0/lua.h> #include "lua.h"
#include <luajit-2.0/lualib.h> #include "lualib.h"
static lua_State *globalL = NULL; static lua_State *globalL = NULL;
static const char *progname = NULL; static const char *progname = NULL;
......
#!/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://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
#!/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://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>
BPF_STACK_TRACE(stack_traces, 128)
void trace_stack(struct pt_regs *ctx) {
FILTER
int stack_id = stack_traces.get_stackid(ctx, BPF_F_REUSE_STACKID);
if (stack_id >= 0)
bpf_trace_printk("stack_id=%d\n", stack_id);
}
]]
return function(BPF, utils)
local parser = utils.argparse("stacksnoop",
"Trace and print kernel stack traces for a kernel function")
parser:flag("-s --offset")
parser:flag("-v --verbose")
parser:option("-p --pid"):convert(tonumber)
parser:argument("function", "kernel function name"):target("fn")
local args = parser:parse()
local ksym = BPF.SymbolCache()
local filter = ""
if args.pid then
filter = [[
u32 pid;
pid = bpf_get_current_pid_tgid();
if (pid != %d) { return; }
]] % args.pid
end
local text = program:gsub("FILTER", filter)
local bpf = BPF:new{text=text}
bpf:attach_kprobe{event=args.fn, fn_name="trace_stack"}
if BPF.num_open_kprobes() == 0 then
print("Function \"%s\" not found. Exiting." % args.fn)
return
end
if args.verbose then
print("%-18s %-12s %-6s %-3s %s" %
{"TIME(s)", "COMM", "PID", "CPU", "SYSCALL"})
else
print("%-18s %s" % {"TIME(s)", "SYSCALL"})
end
local stack_traces = bpf:get_table("stack_traces")
local pipe = bpf:pipe()
while true do
local task, pid, cpu, flags, ts, msg = pipe:trace_fields()
local stack_id = string.match(msg, "stack_id=(%d+)")
if stack_id then
if args.verbose then
print("%-18.9f %-12.12s %-6d %-3d %s" % {ts, task, pid, cpu, args.fn})
else
print("%-18.9f %s" % {ts, args.fn})
end
for addr in stack_traces:walk(tonumber(stack_id)) do
local sym, offset = ksym:resolve(addr)
if args.offset then
print("\t%-16p %s+0x%x" % {addr, sym, tonumber(offset)})
else
print("\t%-16p %s" % {addr, sym})
end
end
end
print()
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment