-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
145 lines (123 loc) · 3.71 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
package main
import (
"context"
"fmt"
"io"
"log"
"net"
"os"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcapgo"
"github.com/jessevdk/go-flags"
"google.golang.org/grpc"
pb "github.com/haccht/vplsbh/pkg/grpc"
)
const (
snapshotLen = 65536
)
type cmdOption struct {
Address string `short:"a" long:"addr" description:"gRPC address to connect to" value-name:"<addr>" default:"127.0.0.1:50005"`
BPFFilter string `short:"e" long:"bpf" description:"filter packets by BPF primitive" value-name:"<expression>"`
RemoteFilter string `short:"r" long:"remote" description:"filter packets by Remote-Router name" value-name:"<remote>"`
DomainFilter string `short:"d" long:"domain" description:"filter packets by Bridge-Domain name" value-name:"<bdname>"`
PacketCount uint `short:"c" long:"count" description:"exit after reading specified number of packets" value-name:"<count>"`
Duration uint `short:"t" long:"duration" description:"exit after specified seconds have elapsed" value-name:"<seconds>"`
WriteFile string `short:"w" long:"write" description:"write packets to the pcap file" value-name:"<filepath>"`
}
func NewCmdOption(args []string) (*cmdOption, error) {
var opt cmdOption
_, err := flags.ParseArgs(&opt, args)
if err != nil {
return nil, err
}
return &opt, nil
}
func main() {
opt, err := NewCmdOption(os.Args)
if err != nil {
if fe, ok := err.(*flags.Error); ok && fe.Type == flags.ErrHelp {
os.Exit(0)
}
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
var w *pcapgo.Writer
if opt.WriteFile != "" {
f, err := os.Create(opt.WriteFile)
if err != nil {
log.Fatalf("failed to open file: %v", err)
}
defer f.Close()
w = pcapgo.NewWriter(f)
w.WriteFileHeader(snapshotLen, layers.LinkTypeIPv4)
}
conn, err := grpc.Dial(opt.Address, grpc.WithInsecure())
if err != nil {
log.Fatalf("failed to connect with server: %v", err)
}
defer conn.Close()
req := &pb.Request{Filter: opt.BPFFilter, Remote: opt.RemoteFilter, Domain: opt.DomainFilter}
ctx, cancel := context.WithCancel(context.Background())
if opt.Duration != 0 {
ctx, cancel = context.WithTimeout(ctx, time.Second*time.Duration(opt.Duration))
}
defer cancel()
client := pb.NewBumSniffServiceClient(conn)
stream, err := client.Sniff(ctx, req)
if err != nil {
log.Fatalf("failed to open stream: %v", err)
}
var np uint
for {
recv, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
if ctx.Err() == context.DeadlineExceeded {
break
}
log.Fatalf("stop receiving packets: %v", err)
}
ip := &layers.IPv4{
Version: 4,
IHL: 5,
TTL: 64,
Protocol: layers.IPProtocolEtherIP,
SrcIP: net.ParseIP(recv.Peerid),
DstIP: net.ParseIP("0.0.0.0"),
}
etherip := &layers.EtherIP{
Version: 3,
}
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{}
var bytes []byte
if bytes, err = buf.PrependBytes(len(recv.Data)); err != nil {
break
}
copy(bytes, recv.Data)
if bytes, err = buf.PrependBytes(2); err != nil {
break
}
bytes[0] = (etherip.Version << 4)
if err := ip.SerializeTo(buf, opts); err != nil {
break
}
packet := gopacket.NewPacket(buf.Bytes(), layers.LayerTypeIPv4, gopacket.Lazy)
md := packet.Metadata()
ci := gopacket.CaptureInfo{Timestamp: recv.Timestamp.AsTime(), CaptureLength: len(packet.Data()), Length: len(packet.Data())}
md.CaptureInfo = ci
fmt.Printf("DOMAIN: %s, REMOTE: %s, LABEL: %d\n", recv.Domain, recv.Remote, recv.Label)
fmt.Println(packet)
if w != nil {
w.WritePacket(packet.Metadata().CaptureInfo, packet.Data())
}
np++
if opt.PacketCount != 0 && opt.PacketCount <= np {
break
}
}
}