-
Notifications
You must be signed in to change notification settings - Fork 4
/
main.go
85 lines (80 loc) · 2.47 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
// `rstlss` is an example of an unprivileged Linux process using a BPF filter
// to block certain TCP packets coming to the socket.
//
// Inspired by awesome blog post "eBPF, Sockets, Hop Distance and manually
// writing eBPF assembly" by Marek Majkowski:
// https://blog.cloudflare.com/epbf_sockets_hop_distance/
//
// CC0, No Rights Reserved. -- Leonid Evdokimov <[email protected]>
package main
import (
"golang.org/x/net/bpf"
"golang.org/x/sys/unix"
"io"
"net"
"net/http"
"os"
"syscall"
"time"
"unsafe"
)
// DNS resolve workaround for android in pure go
// this only work before any Lookup call and net.dnsReadConfig() failed
//go:linkname defaultNS net.defaultNS
var defaultNS []string
func main() {
if _, err := os.Stat("/etc/resolv.conf"); os.IsNotExist(err) {
// Ugly hack for Android, good enough for proof-of-concept.
dns := os.Getenv("RSTLSS_DNS")
if dns != "" {
defaultNS = []string{dns}
}
}
// https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure
// IP headers are also reachable at some magic offset
// https://github.com/torvalds/linux/blob/ead751507de86d90fa250431e9990a8b881f713c/include/uapi/linux/filter.h#L84
filter, err := bpf.Assemble([]bpf.Instruction{
bpf.LoadAbsolute{Off: 13, Size: 1}, // load flags[RST]
bpf.JumpIf{Cond: bpf.JumpBitsSet, Val: 0x04, SkipTrue: 1}, // check RST
bpf.RetConstant{Val: 65535}, // ACCEPT
bpf.RetConstant{Val: 0}, // DROP
})
if err != nil {
panic(err)
}
prog := unix.SockFprog{
Len: uint16(len(filter)),
Filter: (*unix.SockFilter)(unsafe.Pointer(&filter[0])),
}
dialer := &net.Dialer{
Control: func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
if os.Getenv("RSTLSS") == "" {
return
}
err := unix.SetsockoptSockFprog(int(fd), unix.SOL_SOCKET, unix.SO_ATTACH_FILTER, &prog)
if err != nil {
panic(err)
}
})
},
}
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: dialer.DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://rutracker.org/robots.txt")
if err != nil {
panic(err)
}
defer resp.Body.Close()
_, err = io.Copy(os.Stdout, resp.Body)
if err != nil {
panic(err)
}
}