-
Notifications
You must be signed in to change notification settings - Fork 9
/
main.go
175 lines (168 loc) · 4.79 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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright (c) 2021 Wireleap
package main
import (
"io/ioutil"
"log"
"net"
"os"
"os/signal"
"path"
"runtime"
"strconv"
"syscall"
"github.com/fsnotify/fsnotify"
"github.com/vishvananda/netlink"
"github.com/wireleap/client/wireleap_tun/tun"
"net/http"
_ "net/http/pprof"
)
func main() {
if err := syscall.Seteuid(0); err != nil {
log.Fatal("could not gain privileges; check if setuid flag is set?")
}
sh := os.Getenv("WIRELEAP_HOME")
h2caddr := os.Getenv("WIRELEAP_ADDR_H2C")
tunaddr := os.Getenv("WIRELEAP_ADDR_TUN")
if sh == "" || h2caddr == "" || tunaddr == "" {
log.Fatal("Running wireleap_tun separately from wireleap is not supported. Please use `sudo wireleap tun start`.")
}
t, err := tun.New()
if err != nil {
log.Fatalf("could not create tun device: %s", err)
}
rlim := syscall.Rlimit{Cur: 65535, Max: 65535}
if err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil {
log.Fatalf("could not set RLIMIT_NOFILE to %+v", rlim)
}
routes, err := getroutes(sh)
if err != nil {
log.Fatalf("could not get routes: %s", err)
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatalf("could not set up file watcher: %s", err)
}
defer watcher.Close()
err = watcher.Add(path.Join(sh, "bypass.json"))
if err != nil {
log.Fatalf("could not add bypass.json to file watcher: %s", err)
}
link, err := netlink.LinkByName(t.Name())
if err != nil {
log.Fatalf("could not get link for %s: %s", t.Name(), err)
}
err = netlink.LinkSetTxQLen(link, 1000)
if err != nil {
log.Fatalf("could not set link txqueue length for %s to %d: %s", t.Name(), 1000, err)
}
err = netlink.LinkSetUp(link)
if err != nil {
log.Fatalf("could not set %s up: %s", link, err)
}
tunhost, _, err := net.SplitHostPort(tunaddr)
if err != nil {
log.Fatalf("could not parse WIRELEAP_ADDR_TUN `%s`: %s", tunaddr, err)
}
addr, err := netlink.ParseAddr(tunhost + "/31")
if err != nil {
log.Fatalf("could not parse address of %s: %s", tunaddr, err)
}
err = netlink.AddrAdd(link, addr)
if err != nil {
log.Fatalf("could not set address of %s to %s: %s", link, addr, err)
}
// avoid clobbering the default route by being just a _little_ bit more specific
for _, r := range append([]netlink.Route{{
// lower half of all v4 addresses
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{IP: net.IPv4(0, 0, 0, 0), Mask: net.CIDRMask(1, net.IPv4len*8)},
}, {
// upper half of all v4 addresses
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{IP: net.IPv4(128, 0, 0, 0), Mask: net.CIDRMask(1, net.IPv4len*8)},
}, {
// v6 global-adressable range
LinkIndex: link.Attrs().Index,
Dst: &net.IPNet{IP: net.ParseIP("2000::"), Mask: net.CIDRMask(3, net.IPv6len*8)},
}}, routes...) {
log.Printf("adding route: %+v", r)
err = netlink.RouteReplace(&r)
if err != nil {
log.Fatalf("could not add route to %s: %s", r.Dst, err)
}
}
pidfile := path.Join(sh, "wireleap_tun.pid")
finalize := func() {
// don't need to delete catch-all routes via tun dev as they will be
// removed when the device is down
for _, r := range routes {
netlink.RouteDel(&r)
}
os.Remove(pidfile)
}
defer finalize()
sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
os.Remove(pidfile)
pidtext := []byte(strconv.Itoa(os.Getpid()))
err = ioutil.WriteFile(pidfile, pidtext, 0644)
if err != nil {
finalize()
log.Fatalf("could not write pidfile %s: %s", pidfile, err)
}
defer os.Remove(pidfile)
// setup debugging & profiling
if os.Getenv("WIRELEAP_TUN_DEBUG") != "" {
DEBUG = true
}
if os.Getenv("WIRELEAP_TUN_PPROF") != "" {
go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()
}
if bpr := os.Getenv("WIRELEAP_TUN_BLOCK_PROFILE_RATE"); bpr != "" {
n, err := strconv.Atoi(bpr)
if err != nil {
log.Fatalf("invalid WIRELEAP_TUN_BLOCK_PROFILE_RATE value: %s", bpr)
}
runtime.SetBlockProfileRate(n)
}
if mpf := os.Getenv("WIRELEAP_TUN_MUTEX_PROFILE_FRACTION"); mpf != "" {
n, err := strconv.Atoi(mpf)
if err != nil {
log.Fatalf("invalid WIRELEAP_TUN_MUTEX_PROFILE_FRACTION value: %s", mpf)
}
runtime.SetMutexProfileFraction(n)
}
if err = tunsplice(t, h2caddr, tunaddr); err != nil {
log.Fatal("tunsplice returned error:", err)
}
for {
select {
case s := <-sig:
finalize()
log.Fatalf("terminating on signal %s", s)
case _, ok := <-watcher.Events:
if !ok {
return
}
routes2, err := getroutes(sh)
if err != nil {
log.Fatal(err)
}
for _, r := range routes {
netlink.RouteDel(&r)
}
for _, r := range routes2 {
err = netlink.RouteReplace(&r)
if err != nil {
log.Fatalf("could not remove route %s: %s", r, err)
}
}
routes = routes2
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("error while watching files:", err)
}
}
}