xref: /aosp_15_r20/external/bcc/examples/networking/net_monitor.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1#!/usr/bin/python
2#
3# net_monitor.py Aggregates incoming network traffic
4# outputs source ip, destination ip, the number of their network traffic, and current time
5# how to use : net_monitor.py <net_interface>
6#
7# Copyright (c) 2020 YoungEun Choe
8
9from bcc import BPF
10import time
11from ast import literal_eval
12import sys
13
14def help():
15    print("execute: {0} <net_interface>".format(sys.argv[0]))
16    print("e.g.: {0} eno1\n".format(sys.argv[0]))
17    exit(1)
18
19if len(sys.argv) != 2:
20    help()
21elif len(sys.argv) == 2:
22    INTERFACE = sys.argv[1]
23
24bpf_text = """
25
26#include <uapi/linux/ptrace.h>
27#include <net/sock.h>
28#include <bcc/proto.h>
29#include <linux/bpf.h>
30
31#define IP_TCP 6
32#define IP_UDP 17
33#define IP_ICMP 1
34#define ETH_HLEN 14
35
36BPF_PERF_OUTPUT(skb_events);
37BPF_HASH(packet_cnt, u64, long, 256);
38
39int packet_monitor(struct __sk_buff *skb) {
40    u8 *cursor = 0;
41    u32 saddr, daddr;
42    long* count = 0;
43    long one = 1;
44    u64 pass_value = 0;
45
46    struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
47
48    struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
49    if (ip->nextp != IP_TCP)
50    {
51        if (ip -> nextp != IP_UDP)
52        {
53            if (ip -> nextp != IP_ICMP)
54                return 0;
55        }
56    }
57
58    saddr = ip -> src;
59    daddr = ip -> dst;
60
61    pass_value = saddr;
62    pass_value = pass_value << 32;
63    pass_value = pass_value + daddr;
64
65    count = packet_cnt.lookup(&pass_value);
66    if (count)  // check if this map exists
67        *count += 1;
68    else        // if the map for the key doesn't exist, create one
69        {
70            packet_cnt.update(&pass_value, &one);
71        }
72    return -1;
73}
74
75"""
76
77from ctypes import *
78import ctypes as ct
79import sys
80import socket
81import os
82import struct
83
84OUTPUT_INTERVAL = 1
85
86bpf = BPF(text=bpf_text)
87
88function_skb_matching = bpf.load_func("packet_monitor", BPF.SOCKET_FILTER)
89
90BPF.attach_raw_socket(function_skb_matching, INTERFACE)
91
92    # retrieeve packet_cnt map
93packet_cnt = bpf.get_table('packet_cnt')    # retrieeve packet_cnt map
94
95def decimal_to_human(input_value):
96    input_value = int(input_value)
97    hex_value = hex(input_value)[2:]
98    pt3 = literal_eval((str('0x'+str(hex_value[-2:]))))
99    pt2 = literal_eval((str('0x'+str(hex_value[-4:-2]))))
100    pt1 = literal_eval((str('0x'+str(hex_value[-6:-4]))))
101    pt0 = literal_eval((str('0x'+str(hex_value[-8:-6]))))
102    result = str(pt0)+'.'+str(pt1)+'.'+str(pt2)+'.'+str(pt3)
103    return result
104
105try:
106    while True :
107        time.sleep(OUTPUT_INTERVAL)
108        packet_cnt_output = packet_cnt.items()
109        output_len = len(packet_cnt_output)
110        print('\n')
111        for i in range(0,output_len):
112            if (len(str(packet_cnt_output[i][0]))) != 30:
113                continue
114            temp = int(str(packet_cnt_output[i][0])[8:-2]) # initial output omitted from the kernel space program
115            temp = int(str(bin(temp))[2:]) # raw file
116            src = int(str(temp)[:32],2) # part1
117            dst = int(str(temp)[32:],2)
118            pkt_num = str(packet_cnt_output[i][1])[7:-1]
119
120            monitor_result = 'source address : ' + decimal_to_human(str(src)) + ' ' + 'destination address : ' + \
121            decimal_to_human(str(dst)) + ' ' + pkt_num + ' ' + 'time : ' + str(time.localtime()[0])+\
122            ';'+str(time.localtime()[1]).zfill(2)+';'+str(time.localtime()[2]).zfill(2)+';'+\
123            str(time.localtime()[3]).zfill(2)+';'+str(time.localtime()[4]).zfill(2)+';'+\
124            str(time.localtime()[5]).zfill(2)
125            print(monitor_result)
126
127            # time.time() outputs time elapsed since 00:00 hours, 1st, Jan., 1970.
128        packet_cnt.clear() # delete map entires after printing output. confiremd it deletes values and keys too
129
130except KeyboardInterrupt:
131    sys.stdout.close()
132    pass
133
134