xref: /aosp_15_r20/external/bcc/tools/bindsnoop.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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