-
Notifications
You must be signed in to change notification settings - Fork 3
/
main.go
129 lines (108 loc) · 2.68 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
package main
import (
"flag"
"fmt"
"log"
"net"
"os"
"os/signal"
"strings"
"time"
tm "github.com/buger/goterm"
"github.com/dropbox/goebpf"
"go.uber.org/zap"
)
type IPAddressList []string
// Implements flag.Value
func (i *IPAddressList) String() string {
return fmt.Sprintf("%+v", *i)
}
// Implements flag.Value
func (i *IPAddressList) Set(value string) error {
if len(*i) == 16 {
return ErrTooManyIPs
}
// Validate that value is correct IPv4 address
if !strings.Contains(value, "/") {
value += "/32"
}
if strings.Contains(value, ":") {
return fmt.Errorf("%s "+ErrInvalidIP.Error(), value)
}
_, _, err := net.ParseCIDR(value)
if err != nil {
return err
}
// Valid, add to the list
*i = append(*i, value)
return nil
}
func main() {
logger, err := zap.NewProduction()
if err != nil {
log.Fatal("unable to initialize logger: ", err)
}
defer logger.Sync()
w := Wall{
lg: logger.Sugar(),
FirewallConfig: FirewallConfig{
Iface: flag.String("iface", "", "Interface to bind XDP program to"),
ELF: flag.String("elf", "ebpf_prog/xdp_fw.elf", "clang/llvm compiled binary file"),
},
bpf: goebpf.NewDefaultEbpfSystem(),
}
flag.Var(&w.IPAddrs, "drop", "IPv4 CIDR to DROP traffic from, repeatable")
flag.Parse()
if *w.Iface == "" {
flag.PrintDefaults()
log.Fatal("-iface is required.")
}
if len(w.IPAddrs) <= 0 {
flag.PrintDefaults()
log.Fatal("at least one IPv4 address to DROP required to the -drop flag.")
}
if err := w.createBPFSystem(); err != nil {
w.lg.Fatal("failed to load elf: ", err)
}
if err = w.getBPFMaps(); err != nil {
w.lg.Fatal("failed to load bpf maps: ", err)
}
if err = w.getProgramByName(); err != nil {
w.lg.Fatalf("failed to load program: ", err)
}
if err = w.populateBlackList(); err != nil {
w.lg.Fatalf("failed to populate blacklist: ", err)
}
if err = w.loadXDP(); err != nil {
w.lg.Fatalf("unable to load XDP program into the kernel: ", err)
}
if err = w.attachXDP(); err != nil {
w.lg.Fatalf("unable to attach XDP program: ", err)
}
defer w.xdp.Detach()
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
ticker := time.NewTicker(time.Second * 1)
for {
select {
case <-ticker.C:
tm.Clear()
tm.MoveCursor(1, 1)
_, _ = tm.Println("Current Time:", time.Now().Format(time.RFC1123))
table := tm.NewTable(0, 10, 5, ' ', 0)
_, _ = fmt.Fprintf(table, "IP\tDROPs\n")
for i := 0; i < len(w.IPAddrs); i++ {
value, err := w.Matches.Lookup(i)
if err != nil {
continue
}
_, _ = fmt.Fprintf(table, "%s\t%d\n", w.IPAddrs[i], value)
}
_, _ = tm.Println(table)
tm.Flush()
case <-interrupt:
w.lg.Info("Detaching and exiting..")
return
}
}
}