-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmain.go
160 lines (144 loc) · 4.14 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Description: Main file for the ebpfmon tool
// Author: research@redcanary.com
//
// This tool is used to visualize the bpf programs and maps that are loaded
// on a system. It uses the bpftool binary to get the information about the
// programs and maps and then displays them in a tui using the tview library.
// The user can select a program and then see the maps that are used by that
// program. The user can also see the disassembly of a program by selecting
// the program using the enter key
package main
import (
"ebpfmon/ui"
"ebpfmon/utils"
"encoding/json"
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
log "github.com/sirupsen/logrus"
)
// The global path to the bpftool binary
var BpftoolPath string
// A struct for storing the output of `bpftool version -j`
type BpftoolVersionInfo struct {
Version string `json:"version"`
LibbpfVersion string `json:"libbpf_version"`
Features struct {
Libbfd bool `json:"libbfd"`
Llvm bool `json:"llvm"`
Skeletons bool `json:"skeletons"`
Bootstrap bool `json:"bootstrap"`
} `json:"features"`
}
// A simple struct for storing the config for the app
type Config struct {
// The version of bpftool that is being used
Version BpftoolVersionInfo
// The path to the bpftool binary
BpftoolPath string
// Logging verbosity
Verbose bool
}
func main() {
// Parse the command line arguments
var err error
help := flag.Bool("help", false, "Display help")
verbose := flag.Bool("verbose", false, "Verbose output")
version := flag.Bool("version", false, "Display version information")
logFileArg := flag.String("logfile", "", "Path to log file. Defaults to log.txt")
bpftool_path := flag.String("bpftool", "", "Path to bpftool binary. Defaults to the bpftool located in PATH")
flag.Parse()
if *help {
fmt.Println("ebpfmon is a tool for monitoring bpf programs")
flag.Usage()
return
}
if *version {
fmt.Println("ebpfmon version 0.1")
return
}
var logFile *os.File
var logpath string
if *logFileArg == "" {
logpath, err = filepath.Abs("./log.txt")
if err != nil {
fmt.Println("Failed to find log file")
os.Exit(1)
}
} else {
logpath, err = filepath.Abs(*logFileArg)
if err != nil {
fmt.Println("Failed to find log file")
os.Exit(1)
}
}
logFile, err = os.OpenFile(logpath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("Failed to open log file %s\n%v", logpath, err)
os.Exit(1)
}
defer logFile.Close()
log.SetFormatter(&log.JSONFormatter{})
log.SetOutput(logFile)
if *verbose {
log.SetLevel(log.DebugLevel)
} else {
log.SetLevel(log.InfoLevel)
}
// Set the global bpftool path variable. It can be set by the command line
// argument or by the BPFTOOL_PATH environment variable. It defaults to
// the bpftool binary in the PATH
bpftoolEnvPath, exists := os.LookupEnv("BPFTOOL_PATH")
if *bpftool_path != "" {
_, err := os.Stat(*bpftool_path)
if err != nil {
fmt.Printf("Failed to find bpftool binary at %s\n", *bpftool_path)
os.Exit(1)
}
BpftoolPath = *bpftool_path
} else if exists {
_, err := os.Stat(bpftoolEnvPath)
if err != nil {
fmt.Printf("Failed to find bpftool binary specified by BPFTOOL_PATH at %s\n", bpftoolEnvPath)
os.Exit(1)
}
BpftoolPath = bpftoolEnvPath
} else {
BpftoolPath, err = exec.LookPath("bpftool")
if err != nil {
fmt.Println("Failed to find compiled version of bpftool")
os.Exit(1)
} else {
BpftoolPath, err = filepath.Abs(BpftoolPath)
if err != nil {
fmt.Println("Failed to find compiled version of bpftool")
os.Exit(1)
}
}
}
versionInfo := BpftoolVersionInfo{}
stdout, stderr, err := utils.RunCmd(BpftoolPath, "version", "-j")
if err != nil {
fmt.Printf("Failed to run `%s version -j`\n%s\n", BpftoolPath, string(stderr))
os.Exit(1)
}
err = json.Unmarshal(stdout, &versionInfo)
if err != nil {
fmt.Println("Failed to parse bpftool version output")
os.Exit(1)
}
config := Config{
Version: versionInfo,
BpftoolPath: BpftoolPath,
Verbose: *verbose,
}
utils.BpftoolPath = config.BpftoolPath
app := ui.NewTui(config.BpftoolPath)
log.Info("Starting ebpfmon")
// Run the app
if err := app.App.Run(); err != nil {
panic(err)
}
}