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  }