-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathmain.go
130 lines (112 loc) · 3.31 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
// roflcoptor is a Tor Control Port filter daemon which does bidirectional
// filtering.
//
// It is not only limited to the use case "I want to run Tor Browser on my desktop with a
// system tor service and have 'about:tor' and 'New Identity' work while
// disallowing scary control port commands", but could also be used to trick a program
// into thinking that it gathered the "real" data from the tor control port when instead
// our proxy feed it a bunch of lies, such as:
//
// "server-replacement-prefixes": {
// "250-address=":"250-address=127.0.0.1"
// },
//
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"syscall"
"unsafe"
"github.com/op/go-logging"
"github.com/subgraph/roflcoptor/common"
"github.com/subgraph/roflcoptor/proxy"
)
var log = logging.MustGetLogger("roflcoptor")
var logFormat = logging.MustStringFormatter(
"%{level:.4s} %{id:03x} %{message}",
)
var ttyFormat = logging.MustStringFormatter(
"%{color}%{time:15:04:05} ▶ %{level:.4s} %{id:03x}%{color:reset} %{message}",
)
const ioctlReadTermios = 0x5401
func isTerminal(fd int) bool {
var termios syscall.Termios
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return err == 0
}
func stringToLogLevel(level string) (logging.Level, error) {
switch level {
case "DEBUG":
return logging.DEBUG, nil
case "INFO":
return logging.INFO, nil
case "NOTICE":
return logging.NOTICE, nil
case "WARNING":
return logging.WARNING, nil
case "ERROR":
return logging.ERROR, nil
case "CRITICAL":
return logging.CRITICAL, nil
}
return -1, fmt.Errorf("invalid logging level %s", level)
}
func setupLoggerBackend(level logging.Level) logging.LeveledBackend {
format := logFormat
if isTerminal(int(os.Stderr.Fd())) {
format = ttyFormat
}
backend := logging.NewLogBackend(os.Stderr, "", 0)
formatter := logging.NewBackendFormatter(backend, format)
leveler := logging.AddModuleLevel(formatter)
leveler.SetLevel(level, "roflcoptor")
return leveler
}
func main() {
var configFilePath string
var watchMode bool
var logLevel string
var config *common.RoflcoptorConfig
var level logging.Level
var err error
flag.StringVar(&configFilePath, "config", "", "configuration file")
flag.BoolVar(&watchMode, "watch", false, "watch-mode of operation will default to unfiltered-allow policy")
flag.StringVar(&logLevel, "log_level", "INFO", "logging level could be set to: DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL")
flag.Parse()
if configFilePath == "" {
log.Error("you must specify a configuration file")
flag.Usage()
os.Exit(1)
}
// Load configuration file
config, err = loadConfiguration(configFilePath)
if err != nil {
panic(err)
}
level, err = stringToLogLevel(logLevel)
if err != nil {
log.Critical("Invalid logging-level specified.")
os.Exit(1)
}
logBackend := setupLoggerBackend(level)
log.SetBackend(logBackend)
if os.Geteuid() == 0 {
log.Error("Must be run as a non-root user!")
os.Exit(1)
}
sigKillChan := make(chan os.Signal, 1)
signal.Notify(sigKillChan, os.Interrupt, os.Kill)
log.Notice("roflcoptor startup!")
proxyListener := proxy.NewProxyListener(config, watchMode)
proxyListener.StartListeners()
defer proxyListener.StopListeners()
for {
select {
case <-sigKillChan:
log.Notice("roflcoptor shutdown!")
return
}
}
}