1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python 2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports 3*387f9dfdSAndroid Build Coastguard Worker# 4*387f9dfdSAndroid Build Coastguard Worker# Copyright (c) 2021 Chenyue Zhou 5*387f9dfdSAndroid Build Coastguard Worker 6*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 7*387f9dfdSAndroid Build Coastguard Workerimport os 8*387f9dfdSAndroid Build Coastguard Workerimport sys 9*387f9dfdSAndroid Build Coastguard Workerimport time 10*387f9dfdSAndroid Build Coastguard Workerimport atexit 11*387f9dfdSAndroid Build Coastguard Workerimport argparse 12*387f9dfdSAndroid Build Coastguard Worker 13*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, BPFAttachType, lib 14*387f9dfdSAndroid Build Coastguard Worker 15*387f9dfdSAndroid Build Coastguard Worker 16*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 17*387f9dfdSAndroid Build Coastguard Worker ./sockmap.py -c /root/cgroup # attach to /root/cgroup 18*387f9dfdSAndroid Build Coastguard Worker""" 19*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 20*387f9dfdSAndroid Build Coastguard Worker description="pipe data across multiple sockets", 21*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 22*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 23*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-c", "--cgroup", required=True, 24*387f9dfdSAndroid Build Coastguard Worker help="Specify the cgroup address. Note. must be cgroup2") 25*387f9dfdSAndroid Build Coastguard Worker 26*387f9dfdSAndroid Build Coastguard Workerbpf_text = ''' 27*387f9dfdSAndroid Build Coastguard Worker#include <net/sock.h> 28*387f9dfdSAndroid Build Coastguard Worker 29*387f9dfdSAndroid Build Coastguard Worker#define MAX_SOCK_OPS_MAP_ENTRIES 65535 30*387f9dfdSAndroid Build Coastguard Worker 31*387f9dfdSAndroid Build Coastguard Workerstruct sock_key { 32*387f9dfdSAndroid Build Coastguard Worker u32 remote_ip4; 33*387f9dfdSAndroid Build Coastguard Worker u32 local_ip4; 34*387f9dfdSAndroid Build Coastguard Worker u32 remote_port; 35*387f9dfdSAndroid Build Coastguard Worker u32 local_port; 36*387f9dfdSAndroid Build Coastguard Worker u32 family; 37*387f9dfdSAndroid Build Coastguard Worker}; 38*387f9dfdSAndroid Build Coastguard Worker 39*387f9dfdSAndroid Build Coastguard WorkerBPF_SOCKHASH(sock_hash, struct sock_key, MAX_SOCK_OPS_MAP_ENTRIES); 40*387f9dfdSAndroid Build Coastguard Worker 41*387f9dfdSAndroid Build Coastguard Workerstatic __always_inline void bpf_sock_ops_ipv4(struct bpf_sock_ops *skops) { 42*387f9dfdSAndroid Build Coastguard Worker struct sock_key skk = { 43*387f9dfdSAndroid Build Coastguard Worker .remote_ip4 = skops->remote_ip4, 44*387f9dfdSAndroid Build Coastguard Worker .local_ip4 = skops->local_ip4, 45*387f9dfdSAndroid Build Coastguard Worker .local_port = skops->local_port, 46*387f9dfdSAndroid Build Coastguard Worker .remote_port = bpf_ntohl(skops->remote_port), 47*387f9dfdSAndroid Build Coastguard Worker .family = skops->family, 48*387f9dfdSAndroid Build Coastguard Worker }; 49*387f9dfdSAndroid Build Coastguard Worker int ret; 50*387f9dfdSAndroid Build Coastguard Worker 51*387f9dfdSAndroid Build Coastguard Worker bpf_trace_printk("remote-port: %d, local-port: %d\\n", skk.remote_port, 52*387f9dfdSAndroid Build Coastguard Worker skk.local_port); 53*387f9dfdSAndroid Build Coastguard Worker ret = sock_hash.sock_hash_update(skops, &skk, BPF_NOEXIST); 54*387f9dfdSAndroid Build Coastguard Worker if (ret) { 55*387f9dfdSAndroid Build Coastguard Worker bpf_trace_printk("bpf_sock_hash_update() failed. %d\\n", -ret); 56*387f9dfdSAndroid Build Coastguard Worker return; 57*387f9dfdSAndroid Build Coastguard Worker } 58*387f9dfdSAndroid Build Coastguard Worker 59*387f9dfdSAndroid Build Coastguard Worker bpf_trace_printk("Sockhash op: %d, port %d --> %d\\n", skops->op, 60*387f9dfdSAndroid Build Coastguard Worker skk.local_port, skk.remote_port); 61*387f9dfdSAndroid Build Coastguard Worker} 62*387f9dfdSAndroid Build Coastguard Worker 63*387f9dfdSAndroid Build Coastguard Workerint bpf_sockhash(struct bpf_sock_ops *skops) { 64*387f9dfdSAndroid Build Coastguard Worker u32 op = skops->op; 65*387f9dfdSAndroid Build Coastguard Worker 66*387f9dfdSAndroid Build Coastguard Worker /* ipv4 only */ 67*387f9dfdSAndroid Build Coastguard Worker if (skops->family != AF_INET) 68*387f9dfdSAndroid Build Coastguard Worker return 0; 69*387f9dfdSAndroid Build Coastguard Worker 70*387f9dfdSAndroid Build Coastguard Worker switch (op) { 71*387f9dfdSAndroid Build Coastguard Worker case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: 72*387f9dfdSAndroid Build Coastguard Worker case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: 73*387f9dfdSAndroid Build Coastguard Worker bpf_sock_ops_ipv4(skops); 74*387f9dfdSAndroid Build Coastguard Worker break; 75*387f9dfdSAndroid Build Coastguard Worker default: 76*387f9dfdSAndroid Build Coastguard Worker break; 77*387f9dfdSAndroid Build Coastguard Worker } 78*387f9dfdSAndroid Build Coastguard Worker 79*387f9dfdSAndroid Build Coastguard Worker return 0; 80*387f9dfdSAndroid Build Coastguard Worker} 81*387f9dfdSAndroid Build Coastguard Worker 82*387f9dfdSAndroid Build Coastguard Workerint bpf_redir(struct sk_msg_md *msg) { 83*387f9dfdSAndroid Build Coastguard Worker if (msg->family != AF_INET) 84*387f9dfdSAndroid Build Coastguard Worker return SK_PASS; 85*387f9dfdSAndroid Build Coastguard Worker 86*387f9dfdSAndroid Build Coastguard Worker if (msg->remote_ip4 != msg->local_ip4) 87*387f9dfdSAndroid Build Coastguard Worker return SK_PASS; 88*387f9dfdSAndroid Build Coastguard Worker 89*387f9dfdSAndroid Build Coastguard Worker struct sock_key skk = { 90*387f9dfdSAndroid Build Coastguard Worker .remote_ip4 = msg->local_ip4, 91*387f9dfdSAndroid Build Coastguard Worker .local_ip4 = msg->remote_ip4, 92*387f9dfdSAndroid Build Coastguard Worker .local_port = bpf_ntohl(msg->remote_port), 93*387f9dfdSAndroid Build Coastguard Worker .remote_port = msg->local_port, 94*387f9dfdSAndroid Build Coastguard Worker .family = msg->family, 95*387f9dfdSAndroid Build Coastguard Worker }; 96*387f9dfdSAndroid Build Coastguard Worker int ret = 0; 97*387f9dfdSAndroid Build Coastguard Worker 98*387f9dfdSAndroid Build Coastguard Worker ret = sock_hash.msg_redirect_hash(msg, &skk, BPF_F_INGRESS); 99*387f9dfdSAndroid Build Coastguard Worker bpf_trace_printk("try redirect port %d --> %d\\n", msg->local_port, 100*387f9dfdSAndroid Build Coastguard Worker bpf_ntohl(msg->remote_port)); 101*387f9dfdSAndroid Build Coastguard Worker if (ret != SK_PASS) 102*387f9dfdSAndroid Build Coastguard Worker bpf_trace_printk("redirect port %d --> %d failed\\n", msg->local_port, 103*387f9dfdSAndroid Build Coastguard Worker bpf_ntohl(msg->remote_port)); 104*387f9dfdSAndroid Build Coastguard Worker 105*387f9dfdSAndroid Build Coastguard Worker return ret; 106*387f9dfdSAndroid Build Coastguard Worker} 107*387f9dfdSAndroid Build Coastguard Worker''' 108*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 109*387f9dfdSAndroid Build Coastguard Workerbpf = BPF(text=bpf_text) 110*387f9dfdSAndroid Build Coastguard Workerfunc_sock_ops = bpf.load_func("bpf_sockhash", bpf.SOCK_OPS) 111*387f9dfdSAndroid Build Coastguard Workerfunc_sock_redir = bpf.load_func("bpf_redir", bpf.SK_MSG) 112*387f9dfdSAndroid Build Coastguard Worker# raise if error 113*387f9dfdSAndroid Build Coastguard Workerfd = os.open(args.cgroup, os.O_RDONLY) 114*387f9dfdSAndroid Build Coastguard Workermap_fd = lib.bpf_table_fd(bpf.module, b"sock_hash") 115*387f9dfdSAndroid Build Coastguard Workerbpf.attach_func(func_sock_ops, fd, BPFAttachType.CGROUP_SOCK_OPS) 116*387f9dfdSAndroid Build Coastguard Workerbpf.attach_func(func_sock_redir, map_fd, BPFAttachType.SK_MSG_VERDICT) 117*387f9dfdSAndroid Build Coastguard Worker 118*387f9dfdSAndroid Build Coastguard Workerdef detach_all(): 119*387f9dfdSAndroid Build Coastguard Worker bpf.detach_func(func_sock_ops, fd, BPFAttachType.CGROUP_SOCK_OPS) 120*387f9dfdSAndroid Build Coastguard Worker bpf.detach_func(func_sock_redir, map_fd, BPFAttachType.SK_MSG_VERDICT) 121*387f9dfdSAndroid Build Coastguard Worker print("Detaching...") 122*387f9dfdSAndroid Build Coastguard Worker 123*387f9dfdSAndroid Build Coastguard Workeratexit.register(detach_all) 124*387f9dfdSAndroid Build Coastguard Worker 125*387f9dfdSAndroid Build Coastguard Workerwhile True: 126*387f9dfdSAndroid Build Coastguard Worker try: 127*387f9dfdSAndroid Build Coastguard Worker bpf.trace_print() 128*387f9dfdSAndroid Build Coastguard Worker sleep(1) 129*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 130*387f9dfdSAndroid Build Coastguard Worker sys.exit(0) 131