-
Notifications
You must be signed in to change notification settings - Fork 19
/
main.go
105 lines (93 loc) · 2.08 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
package main
import (
"flag"
"fmt"
"log"
"net"
"time"
nats "github.com/nats-io/go-nats"
"github.com/songgao/water"
"github.com/songgao/water/waterutil"
)
var (
natsURL = flag.String("n", nats.DefaultURL, "the NATS URL to connect to")
vlanID = flag.Uint("v", 0, "a VLAN ID (default 0)")
)
func main() {
// parse command-line args
flag.Parse()
// connect to nats
nc, err := nats.Connect(*natsURL, nats.Timeout(5*time.Second))
if err != nil {
log.Fatal(err)
}
defer nc.Close()
// create a TAP interface
config := water.Config{
DeviceType: water.TAP,
}
config.Name = fmt.Sprintf("vnats%d", *vlanID)
ifce, err := water.New(config)
if err != nil {
log.Fatal(err)
}
// get ethernet address of the interface we just created
var ownEth net.HardwareAddr
nifces, err := net.Interfaces()
if err != nil {
log.Fatal(err)
}
for _, nifce := range nifces {
if nifce.Name == config.Name {
ownEth = nifce.HardwareAddr
break
}
}
if len(ownEth) == 0 {
log.Fatal("failed to get own ethernet address")
}
// sub to our frame address
subTopic := fmt.Sprintf("vlan.%d.%x", *vlanID, ownEth)
sub, err := nc.Subscribe(subTopic, func(m *nats.Msg) {
if _, err := ifce.Write(m.Data); err != nil {
log.Print(err)
}
})
if err != nil {
log.Fatal(err)
}
defer sub.Unsubscribe()
// sub to broadcasts
broadcastTopic := fmt.Sprintf("vlan.%d", *vlanID)
bsub, err := nc.Subscribe(broadcastTopic, func(m *nats.Msg) {
if _, err := ifce.Write(m.Data); err != nil {
log.Print(err)
}
})
if err != nil {
log.Fatal(err)
}
defer bsub.Unsubscribe()
// read each frame and publish it to appropriate topic
var frame [1500]byte
for {
// read frame from interface
n, err := ifce.Read(frame[:])
if err != nil {
log.Fatal(err)
}
frame2 := frame[:n]
// the topic to publish to
dst := waterutil.MACDestination(frame2)
var pubTopic string
if waterutil.IsBroadcast(dst) {
pubTopic = broadcastTopic
} else {
pubTopic = fmt.Sprintf("vlan.%d.%x", *vlanID, dst)
}
// publish
if err := nc.Publish(pubTopic, frame2); err != nil {
log.Fatal(err)
}
}
}