github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/gadgets/snapshot/socket/tracer/bpf/socket.bpf.c (about) 1 // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note 2 3 /* Copyright (c) 2021 The Inspektor Gadget authors */ 4 5 /* 6 * Inspired by the BPF selftests in the Linux tree: 7 * https://github.com/torvalds/linux/blob/v5.13/tools/testing/selftests/bpf/progs/bpf_iter_tcp4.c 8 */ 9 10 /* 11 * This BPF program uses the GPL-restricted function bpf_seq_printf(). 12 */ 13 14 #include <vmlinux.h> 15 16 #include <bpf/bpf_helpers.h> 17 #include <bpf/bpf_endian.h> 18 19 #define AF_INET 2 20 #define AF_INET6 10 21 22 #define IPV6_LEN 16 23 24 #define sk_v6_daddr __sk_common.skc_v6_daddr 25 #define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr 26 27 #define inet_daddr sk.__sk_common.skc_daddr 28 #define inet_rcv_saddr sk.__sk_common.skc_rcv_saddr 29 #define inet_dport sk.__sk_common.skc_dport 30 31 #define ir_loc_addr req.__req_common.skc_rcv_saddr 32 #define ir_num req.__req_common.skc_num 33 #define ir_rmt_addr req.__req_common.skc_daddr 34 #define ir_rmt_port req.__req_common.skc_dport 35 #define ir_v6_loc_addr req.__req_common.skc_v6_rcv_saddr 36 #define ir_v6_rmt_addr req.__req_common.skc_v6_daddr 37 #define ireq_family req.__req_common.skc_family 38 39 #define sk_family __sk_common.skc_family 40 #define sk_state __sk_common.skc_state 41 #define sk_proto __sk_common.sk_protocol 42 43 #define tw_daddr __tw_common.skc_daddr 44 #define tw_rcv_saddr __tw_common.skc_rcv_saddr 45 #define tw_dport __tw_common.skc_dport 46 #define tw_v6_daddr __tw_common.skc_v6_daddr 47 #define tw_v6_rcv_saddr __tw_common.skc_v6_rcv_saddr 48 #define tw_family __tw_common.skc_family 49 50 struct entry { 51 __u8 daddr[IPV6_LEN]; 52 __u8 saddr[IPV6_LEN]; 53 __u16 dport; 54 __u16 sport; 55 __u16 proto; // IP protocol 56 __u16 family; 57 __u8 state; 58 __u64 inode; 59 }; 60 61 // we need this to make sure the compiler doesn't remove our struct 62 const struct entry *unused __attribute__((unused)); 63 64 /** 65 * sock_i_ino - Returns the inode identifier associated to a socket. 66 * @sk: The socket whom inode identifier will be returned. 67 * 68 * Returns the inode identifier corresponding to the given as parameter socket. 69 * 70 * Returns: 71 * * The inode identifier associated to the socket. 72 */ 73 static unsigned long sock_i_ino(const struct sock *sk) 74 { 75 const struct socket *sk_socket = sk->sk_socket; 76 const struct inode *inode; 77 unsigned long ino; 78 79 if (!sk_socket) 80 return 0; 81 82 inode = &container_of(sk_socket, struct socket_alloc, socket)->vfs_inode; 83 bpf_probe_read_kernel(&ino, sizeof(ino), &inode->i_ino); 84 return ino; 85 } 86 87 /* 88 * This function receives arguments as they are stored 89 * in the different socket structure, i.e. network-byte order. 90 */ 91 static __always_inline void 92 socket_bpf_seq_write(struct seq_file *seq, __u16 family, __u16 proto, 93 __be32 src_v4, struct in6_addr *src_v6, __u16 srcp, 94 __be32 dest_v4, struct in6_addr *dest_v6, __u16 destp, 95 __u8 state, __u64 ino) 96 { 97 struct entry entry = {}; 98 99 switch (family) { 100 case AF_INET: 101 *((__u32 *)entry.saddr) = src_v4; 102 *((__u32 *)entry.daddr) = dest_v4; 103 104 break; 105 case AF_INET6: 106 bpf_probe_read_kernel(&entry.daddr, sizeof(entry.daddr), 107 dest_v6); 108 bpf_probe_read_kernel(&entry.saddr, sizeof(entry.saddr), 109 src_v6); 110 111 break; 112 default: 113 return; 114 } 115 116 entry.dport = bpf_ntohs(destp); 117 entry.sport = bpf_ntohs(srcp); 118 entry.proto = proto; 119 entry.family = family; 120 entry.state = state; 121 entry.inode = ino; 122 123 bpf_seq_write(seq, &entry, sizeof(entry)); 124 } 125 126 char _license[] SEC("license") = "GPL"; 127 128 static int dump_tcp_sock(struct seq_file *seq, struct tcp_sock *tp) 129 { 130 struct inet_connection_sock *icsk = &tp->inet_conn; 131 struct inet_sock *inet = &icsk->icsk_inet; 132 struct sock *sp = &inet->sk; 133 134 socket_bpf_seq_write(seq, sp->sk_family, IPPROTO_TCP, 135 inet->inet_rcv_saddr, &sp->sk_v6_rcv_saddr, 136 inet->inet_sport, inet->inet_daddr, 137 &sp->sk_v6_daddr, inet->inet_dport, sp->sk_state, 138 sock_i_ino(sp)); 139 140 return 0; 141 } 142 143 static int dump_tw_sock(struct seq_file *seq, struct tcp_timewait_sock *ttw) 144 { 145 struct inet_timewait_sock *tw = &ttw->tw_sk; 146 147 /* 148 * tcp_timewait_sock represents socket in TIME_WAIT state. 149 * Socket is this particular state are not associated with a 150 * struct sock: 151 * https://elixir.bootlin.com/linux/v5.15.12/source/include/linux/tcp.h#L442 152 * https://elixir.bootlin.com/linux/v5.15.12/source/include/net/inet_timewait_sock.h#L33 153 * Hence, they do not have an underlying file and, as a 154 * consequence, no inode. 155 * 156 * Like /proc/net/tcp, we print 0 as inode number for TIME_WAIT 157 * (state 6) socket: 158 * https://elixir.bootlin.com/linux/v5.15.12/source/include/net/tcp_states.h#L18 159 */ 160 161 socket_bpf_seq_write(seq, tw->tw_family, IPPROTO_TCP, tw->tw_rcv_saddr, 162 &tw->tw_v6_rcv_saddr, tw->tw_sport, tw->tw_daddr, 163 &tw->tw_v6_daddr, tw->tw_dport, tw->tw_substate, 164 0); 165 166 return 0; 167 } 168 169 static int dump_req_sock(struct seq_file *seq, struct tcp_request_sock *treq) 170 { 171 struct inet_request_sock *irsk = &treq->req; 172 173 socket_bpf_seq_write(seq, irsk->ireq_family, IPPROTO_TCP, 174 irsk->ir_loc_addr, &irsk->ir_v6_loc_addr, 175 irsk->ir_num, irsk->ir_rmt_addr, 176 &irsk->ir_v6_rmt_addr, irsk->ir_rmt_port, 177 TCP_SYN_RECV, sock_i_ino(treq->req.req.sk)); 178 179 return 0; 180 } 181 182 SEC("iter/tcp") 183 int ig_snap_tcp(struct bpf_iter__tcp *ctx) 184 { 185 struct sock_common *sk_common = ctx->sk_common; 186 struct seq_file *seq = ctx->meta->seq; 187 struct tcp_timewait_sock *tw; 188 struct tcp_request_sock *req; 189 struct tcp_sock *tp; 190 191 if (sk_common == (void *)0) 192 return 0; 193 194 tp = bpf_skc_to_tcp_sock(sk_common); 195 if (tp) 196 return dump_tcp_sock(seq, tp); 197 198 tw = bpf_skc_to_tcp_timewait_sock(sk_common); 199 if (tw) 200 return dump_tw_sock(seq, tw); 201 202 req = bpf_skc_to_tcp_request_sock(sk_common); 203 if (req) 204 return dump_req_sock(seq, req); 205 206 return 0; 207 } 208 209 SEC("iter/udp") 210 int ig_snap_udp(struct bpf_iter__udp *ctx) 211 { 212 struct seq_file *seq = ctx->meta->seq; 213 struct udp_sock *udp_sk = ctx->udp_sk; 214 struct inet_sock *inet; 215 struct sock *sp; 216 217 if (udp_sk == (void *)0) 218 return 0; 219 220 inet = &udp_sk->inet; 221 sp = &inet->sk; 222 223 socket_bpf_seq_write(seq, sp->sk_family, IPPROTO_UDP, 224 inet->inet_rcv_saddr, &sp->sk_v6_rcv_saddr, 225 inet->inet_sport, inet->inet_daddr, 226 &sp->sk_v6_daddr, inet->inet_dport, sp->sk_state, 227 sock_i_ino(sp)); 228 229 return 0; 230 }