1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python 2*387f9dfdSAndroid Build Coastguard Worker# 3*387f9dfdSAndroid Build Coastguard Worker# bindsnoop Trace IPv4 and IPv6 binds()s. 4*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF. Embedded C. 5*387f9dfdSAndroid Build Coastguard Worker# 6*387f9dfdSAndroid Build Coastguard Worker# based on tcpconnect utility from Brendan Gregg's suite. 7*387f9dfdSAndroid Build Coastguard Worker# 8*387f9dfdSAndroid Build Coastguard Worker# USAGE: bindsnoop [-h] [-t] [-E] [-p PID] [-P PORT[,PORT ...]] [-w] 9*387f9dfdSAndroid Build Coastguard Worker# [--count] [--cgroupmap mappath] [--mntnsmap mappath] 10*387f9dfdSAndroid Build Coastguard Worker# 11*387f9dfdSAndroid Build Coastguard Worker# bindsnoop reports socket options set before the bind call 12*387f9dfdSAndroid Build Coastguard Worker# that would impact this system call behavior: 13*387f9dfdSAndroid Build Coastguard Worker# SOL_IP IP_FREEBIND F.... 14*387f9dfdSAndroid Build Coastguard Worker# SOL_IP IP_TRANSPARENT .T... 15*387f9dfdSAndroid Build Coastguard Worker# SOL_IP IP_BIND_ADDRESS_NO_PORT ..N.. 16*387f9dfdSAndroid Build Coastguard Worker# SOL_SOCKET SO_REUSEADDR ...R. 17*387f9dfdSAndroid Build Coastguard Worker# SOL_SOCKET SO_REUSEPORT ....r 18*387f9dfdSAndroid Build Coastguard Worker# 19*387f9dfdSAndroid Build Coastguard Worker# SO_BINDTODEVICE interface is reported as "BOUND_IF" index 20*387f9dfdSAndroid Build Coastguard Worker# 21*387f9dfdSAndroid Build Coastguard Worker# This uses dynamic tracing of kernel functions, and will need to be updated 22*387f9dfdSAndroid Build Coastguard Worker# to match kernel changes. 23*387f9dfdSAndroid Build Coastguard Worker# 24*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2020-present Facebook. 25*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 26*387f9dfdSAndroid Build Coastguard Worker# 27*387f9dfdSAndroid Build Coastguard Worker# 14-Feb-2020 Pavel Dubovitsky Created this. 28*387f9dfdSAndroid Build Coastguard Worker 29*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function, absolute_import, unicode_literals 30*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 31*387f9dfdSAndroid Build Coastguard Workerfrom bcc.containers import filter_by_containers 32*387f9dfdSAndroid Build Coastguard Workerfrom bcc.utils import printb 33*387f9dfdSAndroid Build Coastguard Workerimport argparse 34*387f9dfdSAndroid Build Coastguard Workerimport re 35*387f9dfdSAndroid Build Coastguard Workerfrom os import strerror 36*387f9dfdSAndroid Build Coastguard Workerfrom socket import ( 37*387f9dfdSAndroid Build Coastguard Worker inet_ntop, AF_INET, AF_INET6, __all__ as socket_all, __dict__ as socket_dct 38*387f9dfdSAndroid Build Coastguard Worker) 39*387f9dfdSAndroid Build Coastguard Workerfrom struct import pack 40*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep 41*387f9dfdSAndroid Build Coastguard Worker 42*387f9dfdSAndroid Build Coastguard Worker# arguments 43*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 44*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop # trace all TCP bind()s 45*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop -t # include timestamps 46*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop -w # wider columns (fit IPv6) 47*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop -p 181 # only trace PID 181 48*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop -P 80 # only trace port 80 49*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop -P 80,81 # only trace port 80 and 81 50*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop -U # include UID 51*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop -u 1000 # only trace UID 1000 52*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop -E # report bind errors 53*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop --count # count bind per src ip 54*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop --cgroupmap mappath # only trace cgroups in this BPF map 55*387f9dfdSAndroid Build Coastguard Worker ./bindsnoop --mntnsmap mappath # only trace mount namespaces in the map 56*387f9dfdSAndroid Build Coastguard Worker 57*387f9dfdSAndroid Build Coastguard Workerit is reporting socket options set before the bins call 58*387f9dfdSAndroid Build Coastguard Workerimpacting system call behavior: 59*387f9dfdSAndroid Build Coastguard Worker SOL_IP IP_FREEBIND F.... 60*387f9dfdSAndroid Build Coastguard Worker SOL_IP IP_TRANSPARENT .T... 61*387f9dfdSAndroid Build Coastguard Worker SOL_IP IP_BIND_ADDRESS_NO_PORT ..N.. 62*387f9dfdSAndroid Build Coastguard Worker SOL_SOCKET SO_REUSEADDR ...R. 63*387f9dfdSAndroid Build Coastguard Worker SOL_SOCKET SO_REUSEPORT ....r 64*387f9dfdSAndroid Build Coastguard Worker 65*387f9dfdSAndroid Build Coastguard Worker SO_BINDTODEVICE interface is reported as "IF" index 66*387f9dfdSAndroid Build Coastguard Worker""" 67*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 68*387f9dfdSAndroid Build Coastguard Worker description="Trace TCP binds", 69*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 70*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 71*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-t", "--timestamp", action="store_true", 72*387f9dfdSAndroid Build Coastguard Worker help="include timestamp on output") 73*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-w", "--wide", action="store_true", 74*387f9dfdSAndroid Build Coastguard Worker help="wide column output (fits IPv6 addresses)") 75*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", 76*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 77*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-P", "--port", 78*387f9dfdSAndroid Build Coastguard Worker help="comma-separated list of ports to trace.") 79*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-E", "--errors", action="store_true", 80*387f9dfdSAndroid Build Coastguard Worker help="include errors in the output.") 81*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-U", "--print-uid", action="store_true", 82*387f9dfdSAndroid Build Coastguard Worker help="include UID on output") 83*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-u", "--uid", 84*387f9dfdSAndroid Build Coastguard Worker help="trace this UID only") 85*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--count", action="store_true", 86*387f9dfdSAndroid Build Coastguard Worker help="count binds per src ip and port") 87*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--cgroupmap", 88*387f9dfdSAndroid Build Coastguard Worker help="trace cgroups in this BPF map only") 89*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--mntnsmap", 90*387f9dfdSAndroid Build Coastguard Worker help="trace mount namespaces in this BPF map only") 91*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true", 92*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 93*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--debug-source", action="store_true", 94*387f9dfdSAndroid Build Coastguard Worker help=argparse.SUPPRESS) 95*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 96*387f9dfdSAndroid Build Coastguard Worker 97*387f9dfdSAndroid Build Coastguard Worker# define BPF program 98*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 99*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 100*387f9dfdSAndroid Build Coastguard Worker#pragma clang diagnostic push 101*387f9dfdSAndroid Build Coastguard Worker#pragma clang diagnostic ignored "-Wtautological-compare" 102*387f9dfdSAndroid Build Coastguard Worker#include <net/sock.h> 103*387f9dfdSAndroid Build Coastguard Worker#pragma clang diagnostic pop 104*387f9dfdSAndroid Build Coastguard Worker#include <net/inet_sock.h> 105*387f9dfdSAndroid Build Coastguard Worker#include <net/net_namespace.h> 106*387f9dfdSAndroid Build Coastguard Worker#include <bcc/proto.h> 107*387f9dfdSAndroid Build Coastguard Worker 108*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(currsock, u32, struct socket *); 109*387f9dfdSAndroid Build Coastguard Worker 110*387f9dfdSAndroid Build Coastguard Worker// separate data structs for ipv4 and ipv6 111*387f9dfdSAndroid Build Coastguard Workerstruct ipv4_bind_data_t { 112*387f9dfdSAndroid Build Coastguard Worker u64 ts_us; 113*387f9dfdSAndroid Build Coastguard Worker u32 pid; 114*387f9dfdSAndroid Build Coastguard Worker u32 uid; 115*387f9dfdSAndroid Build Coastguard Worker u64 ip; 116*387f9dfdSAndroid Build Coastguard Worker u32 saddr; 117*387f9dfdSAndroid Build Coastguard Worker u32 bound_dev_if; 118*387f9dfdSAndroid Build Coastguard Worker int return_code; 119*387f9dfdSAndroid Build Coastguard Worker u16 sport; 120*387f9dfdSAndroid Build Coastguard Worker u8 socket_options; 121*387f9dfdSAndroid Build Coastguard Worker u8 protocol; 122*387f9dfdSAndroid Build Coastguard Worker char task[TASK_COMM_LEN]; 123*387f9dfdSAndroid Build Coastguard Worker}; 124*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv4_bind_events); 125*387f9dfdSAndroid Build Coastguard Worker 126*387f9dfdSAndroid Build Coastguard Workerstruct ipv6_bind_data_t { 127*387f9dfdSAndroid Build Coastguard Worker // int128 would be aligned on 16 bytes boundary, better to go first 128*387f9dfdSAndroid Build Coastguard Worker unsigned __int128 saddr; 129*387f9dfdSAndroid Build Coastguard Worker u64 ts_us; 130*387f9dfdSAndroid Build Coastguard Worker u32 pid; 131*387f9dfdSAndroid Build Coastguard Worker u32 uid; 132*387f9dfdSAndroid Build Coastguard Worker u64 ip; 133*387f9dfdSAndroid Build Coastguard Worker u32 bound_dev_if; 134*387f9dfdSAndroid Build Coastguard Worker int return_code; 135*387f9dfdSAndroid Build Coastguard Worker u16 sport; 136*387f9dfdSAndroid Build Coastguard Worker u8 socket_options; 137*387f9dfdSAndroid Build Coastguard Worker u8 protocol; 138*387f9dfdSAndroid Build Coastguard Worker char task[TASK_COMM_LEN]; 139*387f9dfdSAndroid Build Coastguard Worker}; 140*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(ipv6_bind_events); 141*387f9dfdSAndroid Build Coastguard Worker 142*387f9dfdSAndroid Build Coastguard Worker// separate flow keys per address family 143*387f9dfdSAndroid Build Coastguard Workerstruct ipv4_flow_key_t { 144*387f9dfdSAndroid Build Coastguard Worker u32 saddr; 145*387f9dfdSAndroid Build Coastguard Worker u16 sport; 146*387f9dfdSAndroid Build Coastguard Worker}; 147*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(ipv4_count, struct ipv4_flow_key_t); 148*387f9dfdSAndroid Build Coastguard Worker 149*387f9dfdSAndroid Build Coastguard Workerstruct ipv6_flow_key_t { 150*387f9dfdSAndroid Build Coastguard Worker unsigned __int128 saddr; 151*387f9dfdSAndroid Build Coastguard Worker u16 sport; 152*387f9dfdSAndroid Build Coastguard Worker}; 153*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(ipv6_count, struct ipv6_flow_key_t); 154*387f9dfdSAndroid Build Coastguard Worker 155*387f9dfdSAndroid Build Coastguard Worker// bind options for event reporting 156*387f9dfdSAndroid Build Coastguard Workerunion bind_options { 157*387f9dfdSAndroid Build Coastguard Worker u8 data; 158*387f9dfdSAndroid Build Coastguard Worker struct { 159*387f9dfdSAndroid Build Coastguard Worker u8 freebind:1; 160*387f9dfdSAndroid Build Coastguard Worker u8 transparent:1; 161*387f9dfdSAndroid Build Coastguard Worker u8 bind_address_no_port:1; 162*387f9dfdSAndroid Build Coastguard Worker u8 reuseaddress:1; 163*387f9dfdSAndroid Build Coastguard Worker u8 reuseport:1; 164*387f9dfdSAndroid Build Coastguard Worker } fields; 165*387f9dfdSAndroid Build Coastguard Worker}; 166*387f9dfdSAndroid Build Coastguard Worker 167*387f9dfdSAndroid Build Coastguard Worker// TODO: add reporting for the original bind arguments 168*387f9dfdSAndroid Build Coastguard Workerint bindsnoop_entry(struct pt_regs *ctx, struct socket *socket) 169*387f9dfdSAndroid Build Coastguard Worker{ 170*387f9dfdSAndroid Build Coastguard Worker u64 pid_tgid = bpf_get_current_pid_tgid(); 171*387f9dfdSAndroid Build Coastguard Worker u32 pid = pid_tgid >> 32; 172*387f9dfdSAndroid Build Coastguard Worker u32 tid = pid_tgid; 173*387f9dfdSAndroid Build Coastguard Worker FILTER_PID 174*387f9dfdSAndroid Build Coastguard Worker 175*387f9dfdSAndroid Build Coastguard Worker u32 uid = bpf_get_current_uid_gid(); 176*387f9dfdSAndroid Build Coastguard Worker 177*387f9dfdSAndroid Build Coastguard Worker FILTER_UID 178*387f9dfdSAndroid Build Coastguard Worker 179*387f9dfdSAndroid Build Coastguard Worker if (container_should_be_filtered()) { 180*387f9dfdSAndroid Build Coastguard Worker return 0; 181*387f9dfdSAndroid Build Coastguard Worker } 182*387f9dfdSAndroid Build Coastguard Worker 183*387f9dfdSAndroid Build Coastguard Worker // stash the sock ptr for lookup on return 184*387f9dfdSAndroid Build Coastguard Worker currsock.update(&tid, &socket); 185*387f9dfdSAndroid Build Coastguard Worker 186*387f9dfdSAndroid Build Coastguard Worker return 0; 187*387f9dfdSAndroid Build Coastguard Worker}; 188*387f9dfdSAndroid Build Coastguard Worker 189*387f9dfdSAndroid Build Coastguard Worker 190*387f9dfdSAndroid Build Coastguard Workerstatic int bindsnoop_return(struct pt_regs *ctx, short ipver) 191*387f9dfdSAndroid Build Coastguard Worker{ 192*387f9dfdSAndroid Build Coastguard Worker int ret = PT_REGS_RC(ctx); 193*387f9dfdSAndroid Build Coastguard Worker u64 pid_tgid = bpf_get_current_pid_tgid(); 194*387f9dfdSAndroid Build Coastguard Worker u32 pid = pid_tgid >> 32; 195*387f9dfdSAndroid Build Coastguard Worker u32 tid = pid_tgid; 196*387f9dfdSAndroid Build Coastguard Worker 197*387f9dfdSAndroid Build Coastguard Worker struct socket **skpp; 198*387f9dfdSAndroid Build Coastguard Worker skpp = currsock.lookup(&tid); 199*387f9dfdSAndroid Build Coastguard Worker if (skpp == 0) { 200*387f9dfdSAndroid Build Coastguard Worker return 0; // missed entry 201*387f9dfdSAndroid Build Coastguard Worker } 202*387f9dfdSAndroid Build Coastguard Worker 203*387f9dfdSAndroid Build Coastguard Worker int ignore_errors = 1; 204*387f9dfdSAndroid Build Coastguard Worker FILTER_ERRORS 205*387f9dfdSAndroid Build Coastguard Worker if (ret != 0 && ignore_errors) { 206*387f9dfdSAndroid Build Coastguard Worker // failed to bind 207*387f9dfdSAndroid Build Coastguard Worker currsock.delete(&tid); 208*387f9dfdSAndroid Build Coastguard Worker return 0; 209*387f9dfdSAndroid Build Coastguard Worker } 210*387f9dfdSAndroid Build Coastguard Worker 211*387f9dfdSAndroid Build Coastguard Worker // pull in details 212*387f9dfdSAndroid Build Coastguard Worker struct socket *skp_ = *skpp; 213*387f9dfdSAndroid Build Coastguard Worker struct sock *skp = skp_->sk; 214*387f9dfdSAndroid Build Coastguard Worker 215*387f9dfdSAndroid Build Coastguard Worker struct inet_sock *sockp = (struct inet_sock *)skp; 216*387f9dfdSAndroid Build Coastguard Worker 217*387f9dfdSAndroid Build Coastguard Worker u16 sport = 0; 218*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&sport, sizeof(sport), &sockp->inet_sport); 219*387f9dfdSAndroid Build Coastguard Worker sport = ntohs(sport); 220*387f9dfdSAndroid Build Coastguard Worker 221*387f9dfdSAndroid Build Coastguard Worker FILTER_PORT 222*387f9dfdSAndroid Build Coastguard Worker 223*387f9dfdSAndroid Build Coastguard Worker union bind_options opts = {0}; 224*387f9dfdSAndroid Build Coastguard Worker u8 bitfield; 225*387f9dfdSAndroid Build Coastguard Worker // fetching freebind, transparent, and bind_address_no_port bitfields 226*387f9dfdSAndroid Build Coastguard Worker // via the next struct member, rcv_tos 227*387f9dfdSAndroid Build Coastguard Worker bitfield = (u8) *(&sockp->rcv_tos - 2) & 0xFF; 228*387f9dfdSAndroid Build Coastguard Worker // IP_FREEBIND (sockp->freebind) 229*387f9dfdSAndroid Build Coastguard Worker opts.fields.freebind = bitfield >> 2 & 0x01; 230*387f9dfdSAndroid Build Coastguard Worker // IP_TRANSPARENT (sockp->transparent) 231*387f9dfdSAndroid Build Coastguard Worker opts.fields.transparent = bitfield >> 5 & 0x01; 232*387f9dfdSAndroid Build Coastguard Worker // IP_BIND_ADDRESS_NO_PORT (sockp->bind_address_no_port) 233*387f9dfdSAndroid Build Coastguard Worker opts.fields.bind_address_no_port = *(&sockp->rcv_tos - 1) & 0x01; 234*387f9dfdSAndroid Build Coastguard Worker 235*387f9dfdSAndroid Build Coastguard Worker // SO_REUSEADDR and SO_REUSEPORT are bitfields that 236*387f9dfdSAndroid Build Coastguard Worker // cannot be accessed directly, fetched via the next struct member, 237*387f9dfdSAndroid Build Coastguard Worker // __sk_common.skc_bound_dev_if 238*387f9dfdSAndroid Build Coastguard Worker bitfield = *((u8*)&skp->__sk_common.skc_bound_dev_if - 1); 239*387f9dfdSAndroid Build Coastguard Worker // SO_REUSEADDR (skp->reuse) 240*387f9dfdSAndroid Build Coastguard Worker // it is 4 bit, but we are interested in the lowest one 241*387f9dfdSAndroid Build Coastguard Worker opts.fields.reuseaddress = bitfield & 0x0F; 242*387f9dfdSAndroid Build Coastguard Worker // SO_REUSEPORT (skp->reuseport) 243*387f9dfdSAndroid Build Coastguard Worker opts.fields.reuseport = bitfield >> 4 & 0x01; 244*387f9dfdSAndroid Build Coastguard Worker 245*387f9dfdSAndroid Build Coastguard Worker // workaround for reading the sk_protocol bitfield (from tcpaccept.py): 246*387f9dfdSAndroid Build Coastguard Worker u16 protocol; 247*387f9dfdSAndroid Build Coastguard Worker int gso_max_segs_offset = offsetof(struct sock, sk_gso_max_segs); 248*387f9dfdSAndroid Build Coastguard Worker int sk_lingertime_offset = offsetof(struct sock, sk_lingertime); 249*387f9dfdSAndroid Build Coastguard Worker 250*387f9dfdSAndroid Build Coastguard Worker // Since kernel v5.6 sk_protocol has its own u16 field 251*387f9dfdSAndroid Build Coastguard Worker if (sk_lingertime_offset - gso_max_segs_offset == 2) 252*387f9dfdSAndroid Build Coastguard Worker protocol = skp->sk_protocol; 253*387f9dfdSAndroid Build Coastguard Worker else if (sk_lingertime_offset - gso_max_segs_offset == 4) 254*387f9dfdSAndroid Build Coastguard Worker // 4.10+ with little endian 255*387f9dfdSAndroid Build Coastguard Worker#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 256*387f9dfdSAndroid Build Coastguard Worker protocol = *(u8 *)((u64)&skp->sk_gso_max_segs - 3); 257*387f9dfdSAndroid Build Coastguard Worker else 258*387f9dfdSAndroid Build Coastguard Worker // pre-4.10 with little endian 259*387f9dfdSAndroid Build Coastguard Worker protocol = *(u8 *)((u64)&skp->sk_wmem_queued - 3); 260*387f9dfdSAndroid Build Coastguard Worker#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 261*387f9dfdSAndroid Build Coastguard Worker // 4.10+ with big endian 262*387f9dfdSAndroid Build Coastguard Worker protocol = *(u8 *)((u64)&skp->sk_gso_max_segs - 1); 263*387f9dfdSAndroid Build Coastguard Worker else 264*387f9dfdSAndroid Build Coastguard Worker // pre-4.10 with big endian 265*387f9dfdSAndroid Build Coastguard Worker protocol = *(u8 *)((u64)&skp->sk_wmem_queued - 1); 266*387f9dfdSAndroid Build Coastguard Worker#else 267*387f9dfdSAndroid Build Coastguard Worker# error "Fix your compiler's __BYTE_ORDER__?!" 268*387f9dfdSAndroid Build Coastguard Worker#endif 269*387f9dfdSAndroid Build Coastguard Worker 270*387f9dfdSAndroid Build Coastguard Worker if (ipver == 4) { 271*387f9dfdSAndroid Build Coastguard Worker IPV4_CODE 272*387f9dfdSAndroid Build Coastguard Worker } else /* 6 */ { 273*387f9dfdSAndroid Build Coastguard Worker IPV6_CODE 274*387f9dfdSAndroid Build Coastguard Worker } 275*387f9dfdSAndroid Build Coastguard Worker 276*387f9dfdSAndroid Build Coastguard Worker currsock.delete(&tid); 277*387f9dfdSAndroid Build Coastguard Worker 278*387f9dfdSAndroid Build Coastguard Worker return 0; 279*387f9dfdSAndroid Build Coastguard Worker} 280*387f9dfdSAndroid Build Coastguard Worker 281*387f9dfdSAndroid Build Coastguard Workerint bindsnoop_v4_return(struct pt_regs *ctx) 282*387f9dfdSAndroid Build Coastguard Worker{ 283*387f9dfdSAndroid Build Coastguard Worker return bindsnoop_return(ctx, 4); 284*387f9dfdSAndroid Build Coastguard Worker} 285*387f9dfdSAndroid Build Coastguard Worker 286*387f9dfdSAndroid Build Coastguard Workerint bindsnoop_v6_return(struct pt_regs *ctx) 287*387f9dfdSAndroid Build Coastguard Worker{ 288*387f9dfdSAndroid Build Coastguard Worker return bindsnoop_return(ctx, 6); 289*387f9dfdSAndroid Build Coastguard Worker} 290*387f9dfdSAndroid Build Coastguard Worker""" 291*387f9dfdSAndroid Build Coastguard Worker 292*387f9dfdSAndroid Build Coastguard Workerstruct_init = { 293*387f9dfdSAndroid Build Coastguard Worker 'ipv4': { 294*387f9dfdSAndroid Build Coastguard Worker 'count': """ 295*387f9dfdSAndroid Build Coastguard Worker struct ipv4_flow_key_t flow_key = {}; 296*387f9dfdSAndroid Build Coastguard Worker flow_key.saddr = skp->__sk_common.skc_rcv_saddr; 297*387f9dfdSAndroid Build Coastguard Worker flow_key.sport = sport; 298*387f9dfdSAndroid Build Coastguard Worker ipv4_count.increment(flow_key);""", 299*387f9dfdSAndroid Build Coastguard Worker 'trace': """ 300*387f9dfdSAndroid Build Coastguard Worker struct ipv4_bind_data_t data4 = {.pid = pid, .ip = ipver}; 301*387f9dfdSAndroid Build Coastguard Worker data4.uid = bpf_get_current_uid_gid(); 302*387f9dfdSAndroid Build Coastguard Worker data4.ts_us = bpf_ktime_get_ns() / 1000; 303*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel( 304*387f9dfdSAndroid Build Coastguard Worker &data4.saddr, sizeof(data4.saddr), &sockp->inet_saddr); 305*387f9dfdSAndroid Build Coastguard Worker data4.return_code = ret; 306*387f9dfdSAndroid Build Coastguard Worker data4.sport = sport; 307*387f9dfdSAndroid Build Coastguard Worker data4.bound_dev_if = skp->__sk_common.skc_bound_dev_if; 308*387f9dfdSAndroid Build Coastguard Worker data4.socket_options = opts.data; 309*387f9dfdSAndroid Build Coastguard Worker data4.protocol = protocol; 310*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data4.task, sizeof(data4.task)); 311*387f9dfdSAndroid Build Coastguard Worker ipv4_bind_events.perf_submit(ctx, &data4, sizeof(data4));""" 312*387f9dfdSAndroid Build Coastguard Worker }, 313*387f9dfdSAndroid Build Coastguard Worker 'ipv6': { 314*387f9dfdSAndroid Build Coastguard Worker 'count': """ 315*387f9dfdSAndroid Build Coastguard Worker struct ipv6_flow_key_t flow_key = {}; 316*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&flow_key.saddr, sizeof(flow_key.saddr), 317*387f9dfdSAndroid Build Coastguard Worker skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); 318*387f9dfdSAndroid Build Coastguard Worker flow_key.sport = sport; 319*387f9dfdSAndroid Build Coastguard Worker ipv6_count.increment(flow_key);""", 320*387f9dfdSAndroid Build Coastguard Worker 'trace': """ 321*387f9dfdSAndroid Build Coastguard Worker struct ipv6_bind_data_t data6 = {.pid = pid, .ip = ipver}; 322*387f9dfdSAndroid Build Coastguard Worker data6.uid = bpf_get_current_uid_gid(); 323*387f9dfdSAndroid Build Coastguard Worker data6.ts_us = bpf_ktime_get_ns() / 1000; 324*387f9dfdSAndroid Build Coastguard Worker bpf_probe_read_kernel(&data6.saddr, sizeof(data6.saddr), 325*387f9dfdSAndroid Build Coastguard Worker skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); 326*387f9dfdSAndroid Build Coastguard Worker data6.return_code = ret; 327*387f9dfdSAndroid Build Coastguard Worker data6.sport = sport; 328*387f9dfdSAndroid Build Coastguard Worker data6.bound_dev_if = skp->__sk_common.skc_bound_dev_if; 329*387f9dfdSAndroid Build Coastguard Worker data6.socket_options = opts.data; 330*387f9dfdSAndroid Build Coastguard Worker data6.protocol = protocol; 331*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data6.task, sizeof(data6.task)); 332*387f9dfdSAndroid Build Coastguard Worker ipv6_bind_events.perf_submit(ctx, &data6, sizeof(data6));""" 333*387f9dfdSAndroid Build Coastguard Worker }, 334*387f9dfdSAndroid Build Coastguard Worker} 335*387f9dfdSAndroid Build Coastguard Worker 336*387f9dfdSAndroid Build Coastguard Worker# code substitutions 337*387f9dfdSAndroid Build Coastguard Workerif args.count: 338*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace("IPV4_CODE", struct_init['ipv4']['count']) 339*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace("IPV6_CODE", struct_init['ipv6']['count']) 340*387f9dfdSAndroid Build Coastguard Workerelse: 341*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace("IPV4_CODE", struct_init['ipv4']['trace']) 342*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace("IPV6_CODE", struct_init['ipv6']['trace']) 343*387f9dfdSAndroid Build Coastguard Worker 344*387f9dfdSAndroid Build Coastguard Workerif args.pid: 345*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_PID', 346*387f9dfdSAndroid Build Coastguard Worker 'if (pid != %s) { return 0; }' % args.pid) 347*387f9dfdSAndroid Build Coastguard Workerif args.port: 348*387f9dfdSAndroid Build Coastguard Worker sports = [int(sport) for sport in args.port.split(',')] 349*387f9dfdSAndroid Build Coastguard Worker sports_if = ' && '.join(['sport != %d' % sport for sport in sports]) 350*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_PORT', 351*387f9dfdSAndroid Build Coastguard Worker 'if (%s) { currsock.delete(&tid); return 0; }' % sports_if) 352*387f9dfdSAndroid Build Coastguard Workerif args.uid: 353*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_UID', 354*387f9dfdSAndroid Build Coastguard Worker 'if (uid != %s) { return 0; }' % args.uid) 355*387f9dfdSAndroid Build Coastguard Workerif args.errors: 356*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER_ERRORS', 'ignore_errors = 0;') 357*387f9dfdSAndroid Build Coastguard Workerbpf_text = filter_by_containers(args) + bpf_text 358*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_PID', '') 359*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_PORT', '') 360*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_UID', '') 361*387f9dfdSAndroid Build Coastguard Workerbpf_text = bpf_text.replace('FILTER_ERRORS', '') 362*387f9dfdSAndroid Build Coastguard Worker 363*387f9dfdSAndroid Build Coastguard Worker# selecting output format - 80 characters or wide, fitting IPv6 addresses 364*387f9dfdSAndroid Build Coastguard Workerheader_fmt = "%8s %-12.12s %-4s %-15s %-5s %5s %2s" 365*387f9dfdSAndroid Build Coastguard Workeroutput_fmt = b"%8d %-12.12s %-4.4s %-15.15s %5d %-5s %2d" 366*387f9dfdSAndroid Build Coastguard Workererror_header_fmt = "%3s " 367*387f9dfdSAndroid Build Coastguard Workererror_output_fmt = b"%3s " 368*387f9dfdSAndroid Build Coastguard Workererror_value_fmt = str 369*387f9dfdSAndroid Build Coastguard Workerif args.wide: 370*387f9dfdSAndroid Build Coastguard Worker header_fmt = "%10s %-12.12s %-4s %-39s %-5s %5s %2s" 371*387f9dfdSAndroid Build Coastguard Worker output_fmt = b"%10d %-12.12s %-4s %-39s %5d %-5s %2d" 372*387f9dfdSAndroid Build Coastguard Worker error_header_fmt = "%-25s " 373*387f9dfdSAndroid Build Coastguard Worker error_output_fmt = b"%-25s " 374*387f9dfdSAndroid Build Coastguard Worker error_value_fmt = strerror 375*387f9dfdSAndroid Build Coastguard Worker 376*387f9dfdSAndroid Build Coastguard Workerif args.ebpf: 377*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 378*387f9dfdSAndroid Build Coastguard Worker exit() 379*387f9dfdSAndroid Build Coastguard Worker 380*387f9dfdSAndroid Build Coastguard Worker# L4 protocol resolver 381*387f9dfdSAndroid Build Coastguard Workerclass L4Proto: 382*387f9dfdSAndroid Build Coastguard Worker def __init__(self): 383*387f9dfdSAndroid Build Coastguard Worker self.num2str = {} 384*387f9dfdSAndroid Build Coastguard Worker proto_re = re.compile("IPPROTO_(.*)") 385*387f9dfdSAndroid Build Coastguard Worker for attr in socket_all: 386*387f9dfdSAndroid Build Coastguard Worker proto_match = proto_re.match(attr) 387*387f9dfdSAndroid Build Coastguard Worker if proto_match: 388*387f9dfdSAndroid Build Coastguard Worker self.num2str[socket_dct[attr]] = proto_match.group(1) 389*387f9dfdSAndroid Build Coastguard Worker 390*387f9dfdSAndroid Build Coastguard Worker def proto2str(self, proto): 391*387f9dfdSAndroid Build Coastguard Worker return self.num2str.get(proto, "UNKNOWN") 392*387f9dfdSAndroid Build Coastguard Worker 393*387f9dfdSAndroid Build Coastguard Workerl4 = L4Proto() 394*387f9dfdSAndroid Build Coastguard Worker 395*387f9dfdSAndroid Build Coastguard Worker# bind options: 396*387f9dfdSAndroid Build Coastguard Worker# SOL_IP IP_FREEBIND F.... 397*387f9dfdSAndroid Build Coastguard Worker# SOL_IP IP_TRANSPARENT .T... 398*387f9dfdSAndroid Build Coastguard Worker# SOL_IP IP_BIND_ADDRESS_NO_PORT ..N.. 399*387f9dfdSAndroid Build Coastguard Worker# SOL_SOCKET SO_REUSEADDR ...R. 400*387f9dfdSAndroid Build Coastguard Worker# SOL_SOCKET SO_REUSEPORT ....r 401*387f9dfdSAndroid Build Coastguard Workerdef opts2str(bitfield): 402*387f9dfdSAndroid Build Coastguard Worker str_options = "" 403*387f9dfdSAndroid Build Coastguard Worker bit = 1 404*387f9dfdSAndroid Build Coastguard Worker for opt in "FTNRr": 405*387f9dfdSAndroid Build Coastguard Worker str_options += opt if bitfield & bit else "." 406*387f9dfdSAndroid Build Coastguard Worker bit *= 2 407*387f9dfdSAndroid Build Coastguard Worker return str_options.encode() 408*387f9dfdSAndroid Build Coastguard Worker 409*387f9dfdSAndroid Build Coastguard Worker 410*387f9dfdSAndroid Build Coastguard Worker# process events 411*387f9dfdSAndroid Build Coastguard Workerdef print_ipv4_bind_event(cpu, data, size): 412*387f9dfdSAndroid Build Coastguard Worker event = b["ipv4_bind_events"].event(data) 413*387f9dfdSAndroid Build Coastguard Worker global start_ts 414*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 415*387f9dfdSAndroid Build Coastguard Worker if start_ts == 0: 416*387f9dfdSAndroid Build Coastguard Worker start_ts = event.ts_us 417*387f9dfdSAndroid Build Coastguard Worker printb(b"%-9.6f " % ((float(event.ts_us) - start_ts) / 1000000), nl="") 418*387f9dfdSAndroid Build Coastguard Worker if args.print_uid: 419*387f9dfdSAndroid Build Coastguard Worker printb(b"%6d " % event.uid, nl="") 420*387f9dfdSAndroid Build Coastguard Worker if args.errors: 421*387f9dfdSAndroid Build Coastguard Worker printb( 422*387f9dfdSAndroid Build Coastguard Worker error_output_fmt % error_value_fmt(event.return_code).encode(), 423*387f9dfdSAndroid Build Coastguard Worker nl="", 424*387f9dfdSAndroid Build Coastguard Worker ) 425*387f9dfdSAndroid Build Coastguard Worker printb(output_fmt % (event.pid, event.task, 426*387f9dfdSAndroid Build Coastguard Worker l4.proto2str(event.protocol).encode(), 427*387f9dfdSAndroid Build Coastguard Worker inet_ntop(AF_INET, pack("I", event.saddr)).encode(), 428*387f9dfdSAndroid Build Coastguard Worker event.sport, opts2str(event.socket_options), event.bound_dev_if)) 429*387f9dfdSAndroid Build Coastguard Worker 430*387f9dfdSAndroid Build Coastguard Worker 431*387f9dfdSAndroid Build Coastguard Workerdef print_ipv6_bind_event(cpu, data, size): 432*387f9dfdSAndroid Build Coastguard Worker event = b["ipv6_bind_events"].event(data) 433*387f9dfdSAndroid Build Coastguard Worker global start_ts 434*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 435*387f9dfdSAndroid Build Coastguard Worker if start_ts == 0: 436*387f9dfdSAndroid Build Coastguard Worker start_ts = event.ts_us 437*387f9dfdSAndroid Build Coastguard Worker printb(b"%-9.6f " % ((float(event.ts_us) - start_ts) / 1000000), nl="") 438*387f9dfdSAndroid Build Coastguard Worker if args.print_uid: 439*387f9dfdSAndroid Build Coastguard Worker printb(b"%6d " % event.uid, nl="") 440*387f9dfdSAndroid Build Coastguard Worker if args.errors: 441*387f9dfdSAndroid Build Coastguard Worker printb( 442*387f9dfdSAndroid Build Coastguard Worker error_output_fmt % error_value_fmt(event.return_code).encode(), 443*387f9dfdSAndroid Build Coastguard Worker nl="", 444*387f9dfdSAndroid Build Coastguard Worker ) 445*387f9dfdSAndroid Build Coastguard Worker printb(output_fmt % (event.pid, event.task, 446*387f9dfdSAndroid Build Coastguard Worker l4.proto2str(event.protocol).encode(), 447*387f9dfdSAndroid Build Coastguard Worker inet_ntop(AF_INET6, event.saddr).encode(), 448*387f9dfdSAndroid Build Coastguard Worker event.sport, opts2str(event.socket_options), event.bound_dev_if)) 449*387f9dfdSAndroid Build Coastguard Worker 450*387f9dfdSAndroid Build Coastguard Worker 451*387f9dfdSAndroid Build Coastguard Workerdef depict_cnt(counts_tab, l3prot='ipv4'): 452*387f9dfdSAndroid Build Coastguard Worker for k, v in sorted( 453*387f9dfdSAndroid Build Coastguard Worker counts_tab.items(), key=lambda counts: counts[1].value, reverse=True 454*387f9dfdSAndroid Build Coastguard Worker ): 455*387f9dfdSAndroid Build Coastguard Worker depict_key = "" 456*387f9dfdSAndroid Build Coastguard Worker if l3prot == 'ipv4': 457*387f9dfdSAndroid Build Coastguard Worker depict_key = "%-32s %20s" % ( 458*387f9dfdSAndroid Build Coastguard Worker (inet_ntop(AF_INET, pack('I', k.saddr))), k.sport 459*387f9dfdSAndroid Build Coastguard Worker ) 460*387f9dfdSAndroid Build Coastguard Worker else: 461*387f9dfdSAndroid Build Coastguard Worker depict_key = "%-32s %20s" % ( 462*387f9dfdSAndroid Build Coastguard Worker (inet_ntop(AF_INET6, k.saddr)), k.sport 463*387f9dfdSAndroid Build Coastguard Worker ) 464*387f9dfdSAndroid Build Coastguard Worker print("%s %-10d" % (depict_key, v.value)) 465*387f9dfdSAndroid Build Coastguard Worker 466*387f9dfdSAndroid Build Coastguard Worker 467*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 468*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 469*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="inet_bind", fn_name="bindsnoop_entry") 470*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="inet6_bind", fn_name="bindsnoop_entry") 471*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="inet_bind", fn_name="bindsnoop_v4_return") 472*387f9dfdSAndroid Build Coastguard Workerb.attach_kretprobe(event="inet6_bind", fn_name="bindsnoop_v6_return") 473*387f9dfdSAndroid Build Coastguard Worker 474*387f9dfdSAndroid Build Coastguard Workerprint("Tracing binds ... Hit Ctrl-C to end") 475*387f9dfdSAndroid Build Coastguard Workerif args.count: 476*387f9dfdSAndroid Build Coastguard Worker try: 477*387f9dfdSAndroid Build Coastguard Worker while 1: 478*387f9dfdSAndroid Build Coastguard Worker sleep(99999999) 479*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 480*387f9dfdSAndroid Build Coastguard Worker pass 481*387f9dfdSAndroid Build Coastguard Worker 482*387f9dfdSAndroid Build Coastguard Worker # header 483*387f9dfdSAndroid Build Coastguard Worker print("\n%-32s %20s %-10s" % ( 484*387f9dfdSAndroid Build Coastguard Worker "LADDR", "LPORT", "BINDS")) 485*387f9dfdSAndroid Build Coastguard Worker depict_cnt(b["ipv4_count"]) 486*387f9dfdSAndroid Build Coastguard Worker depict_cnt(b["ipv6_count"], l3prot='ipv6') 487*387f9dfdSAndroid Build Coastguard Worker# read events 488*387f9dfdSAndroid Build Coastguard Workerelse: 489*387f9dfdSAndroid Build Coastguard Worker # header 490*387f9dfdSAndroid Build Coastguard Worker if args.timestamp: 491*387f9dfdSAndroid Build Coastguard Worker print("%-9s " % ("TIME(s)"), end="") 492*387f9dfdSAndroid Build Coastguard Worker if args.print_uid: 493*387f9dfdSAndroid Build Coastguard Worker print("%6s " % ("UID"), end="") 494*387f9dfdSAndroid Build Coastguard Worker if args.errors: 495*387f9dfdSAndroid Build Coastguard Worker print(error_header_fmt % ("RC"), end="") 496*387f9dfdSAndroid Build Coastguard Worker print(header_fmt % ("PID", "COMM", "PROT", "ADDR", "PORT", "OPTS", "IF")) 497*387f9dfdSAndroid Build Coastguard Worker 498*387f9dfdSAndroid Build Coastguard Worker start_ts = 0 499*387f9dfdSAndroid Build Coastguard Worker 500*387f9dfdSAndroid Build Coastguard Worker # read events 501*387f9dfdSAndroid Build Coastguard Worker b["ipv4_bind_events"].open_perf_buffer(print_ipv4_bind_event) 502*387f9dfdSAndroid Build Coastguard Worker b["ipv6_bind_events"].open_perf_buffer(print_ipv6_bind_event) 503*387f9dfdSAndroid Build Coastguard Worker while 1: 504*387f9dfdSAndroid Build Coastguard Worker try: 505*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 506*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 507*387f9dfdSAndroid Build Coastguard Worker exit() 508