/
Manager.go
477 lines (438 loc) · 12 KB
/
Manager.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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
package DBus
import (
"os"
"path/filepath"
"sync"
com "github.com/ArisAachen/deepin-network-proxy/com"
"github.com/linuxdeepin/go-lib/log"
config "github.com/ArisAachen/deepin-network-proxy/config"
define "github.com/ArisAachen/deepin-network-proxy/define"
route "github.com/ArisAachen/deepin-network-proxy/ip_route"
newCGroups "github.com/ArisAachen/deepin-network-proxy/new_cgroups"
newIptables "github.com/ArisAachen/deepin-network-proxy/new_iptables"
"github.com/linuxdeepin/go-lib/dbusutil"
)
// manage all proxy handler
type Manager struct {
// dbus
// procsService netlink.Procs
sesService *dbusutil.Service
sysService *dbusutil.Service
// sigLoop *dbusutil.SignalLoop
// proxy handler
handler []BaseProxy
// cgroup manager
mainController *newCGroups.Controller
controllerMgr *newCGroups.Manager
// config
config *config.ProxyConfig
// iptables manager
mainChain *newIptables.Chain // main attach chain
iptablesMgr *newIptables.Manager
// route manager
mainRoute *route.Route
routeMgr *route.Manager
// if current listening
runOnce *sync.Once
}
// make manager
func NewManager() *Manager {
manager := &Manager{}
return manager
}
// inti manager
func (m *Manager) Init() error {
// init session dbus service to export service
sysService, err := dbusutil.NewSystemService()
if err != nil {
logger.Warningf("init dbus session service failed, err: %v", err)
return err
}
// store service
m.sysService = sysService
// attach dbus objects
// m.procsService = netlink.NewProcs(sysService.Conn())
// m.sigLoop = dbusutil.NewSignalLoop(sysService.Conn(), 10)
return nil
}
// load config
func (m *Manager) LoadConfig() error {
// get effective user config dir
path, err := com.GetConfigDir()
if err != nil {
logger.Warningf("failed to get user home dir, user:%v, err: %v", os.Geteuid(), err)
return err
}
path = filepath.Join(path, define.ConfigName)
// config
m.config = config.NewProxyCfg()
err = m.config.LoadPxyCfg(path)
if err != nil {
logger.Warningf("load config failed, path: %s, err: %v", path, err)
return err
}
return nil
}
// write config
func (m *Manager) WriteConfig() error {
// get config path
path, err := com.GetConfigDir()
if err != nil {
logger.Warningf("[manager] get user home dir failed, user:%v, err: %v", os.Geteuid(), err)
return err
}
path = filepath.Join(path, define.ConfigName)
err = m.config.WritePxyCfg(path)
if err != nil {
logger.Warningf("[manager] write config file failed, err: %v", err)
return err
}
return nil
}
// create handler and export service
func (m *Manager) Export() error {
// app
appProxy := newProxy(define.App)
// save manager
appProxy.saveManager(m)
// load config
appProxy.loadConfig()
// export
err := appProxy.export(m.sysService)
if err != nil {
logger.Warningf("create app proxy controller failed, err: %v", err)
return err
}
m.handler = append(m.handler, appProxy)
//// global
//globalProxy := newProxy(define.Global)
//// save manager
//globalProxy.saveManager(m)
//// load config
//globalProxy.loadConfig()
//// export
//err = globalProxy.export(m.sysService)
//if err != nil {
// logger.Warningf("export app proxy failed, err: %v", err)
// return err
//}
// m.handler = append(m.handler, globalProxy)
// request dbus service
err = m.sysService.RequestName(BusServiceName)
if err != nil {
logger.Warningf("request service name failed, err: %v", err)
return err
}
return nil
}
func (m *Manager) Wait() {
m.sysService.Wait()
}
// only run once method
func (m *Manager) Start() {
// if need reset once
if m.runOnce == nil {
m.runOnce = new(sync.Once)
}
m.runOnce.Do(func() {
// run first clean script
_ = m.firstClean()
// init cgroups
_ = m.initCGroups()
// iptables init
_ = m.initIptables()
// init route
_ = m.initRoute()
})
}
// init iptables
func (m *Manager) initIptables() error {
var err error
m.iptablesMgr = newIptables.NewManager()
m.iptablesMgr.Init()
// get mangle output chain
outputChain := m.iptablesMgr.GetChain("mangle", "OUTPUT")
// create main chain to manager all children chain
// sudo iptables -t mangle -N Main
// sudo iptables -t mangle -A OUTPUT -j Main
m.mainChain, err = outputChain.CreateChild(define.Main.String(), 0, &newIptables.CompleteRule{Action: define.Main.String()})
if err != nil {
logger.Warningf("init iptables failed, err: %v", err)
return err
}
// dont proxy local lo
// sudo iptables -t mangle -A Main 1 -o lo -j RETURN
base := newIptables.BaseRule{
// -o
Match: "o",
// "lo"
Param: "lo",
}
cpl := &newIptables.CompleteRule{
Action: newIptables.RETURN,
BaseSl: []newIptables.BaseRule{base},
ExtendsSl: nil,
}
// append rule
err = m.mainChain.AppendRule(cpl)
if err != nil {
logger.Warningf("init iptables failed, err: %v", err)
return err
}
// mainChain add default rule
// iptables -t mangle -A Main -m cgroup --path main.slice -j RETURN
extends := newIptables.ExtendsRule{
// -m
Match: "m",
// cgroup --path main.slice
Elem: newIptables.ExtendsElem{
// cgroup
Match: "cgroup",
// --path main.slice
Base: newIptables.BaseRule{
Match: "path", Param: define.Main.String() + ".slice",
},
},
}
// one complete rule
cpl = &newIptables.CompleteRule{
// -j RETURN
Action: newIptables.RETURN,
BaseSl: nil,
// -m cgroup --path main.slice -j RETURN
ExtendsSl: []newIptables.ExtendsRule{extends},
}
// append rule
err = m.mainChain.AppendRule(cpl)
if err != nil {
logger.Warningf("init iptables failed, err: %v", err)
return err
}
logger.Debug("init iptables success")
return err
}
// init cgroups
func (m *Manager) initCGroups() error {
m.controllerMgr = newCGroups.NewManager()
// create controller
var err error
m.mainController, err = m.controllerMgr.CreatePriorityController(define.Main, 0, 0, define.MainPriority)
if err != nil {
logger.Warningf("init cgroup failed, err: %v", err)
return err
}
logger.Debug("init cgroup success")
return nil
}
// init route
func (m *Manager) initRoute() error {
var err error
m.routeMgr = route.NewManager()
node := route.RouteNodeSpec{
Type: "local",
Prefix: "default",
}
info := route.RouteInfoSpec{
Dev: "lo",
}
m.mainRoute, err = m.routeMgr.CreateRoute("100", node, info)
if err != nil {
logger.Warningf("init route failed, err: %v", err)
return err
}
logger.Debug("init route success")
return nil
}
// format current procs
func (m *Manager) GetAllProcs() (map[string]newCGroups.ControlProcSl, error) {
// check service
//if m.procsService == nil {
// logger.Warning("[manager] get procs failed, service not init")
// return nil, errors.New("service not init")
//}
// get procs message
// map[pid]{pid exec cgroups}
//procs, err := m.procsService.Procs().Get(0)
//if err != nil {
// logger.Warningf("[%s] get procs failed, err: %v", "manager", err)
// return nil, err
//}
// map[exec][pid exec cgroups]
//ctrlProcMap := make(map[string]newCGroups.ControlProcSl)
//for _, proc := range procs {
// execPath := proc.ExecPath
// ctrlProcSl, ok := ctrlProcMap[execPath]
// // if not exist, add one
// if !ok {
// ctrlProcSl = newCGroups.ControlProcSl{}
// // ctrlProcMap[execPath] = ctrlProcSl
// }
// // append
// var temp netlink.ProcMessage = proc
// ctrlProcSl = append(ctrlProcSl, &temp)
// ctrlProcMap[execPath] = ctrlProcSl
//}
return nil, nil
}
// start listen
func (m *Manager) Listen() error {
//m.sigLoop.Start()
//m.procsService.InitSignalExt(m.sigLoop, true)
//_, err := m.procsService.ConnectExecProc(func(execPath string, cgroupPath string, pid string, ppid string) {
// proc := &netlink.ProcMessage{
// ExecPath: execPath,
// CGroupPath: cgroupPath,
// Pid: pid,
// PPid: ppid,
// }
// logger.Debugf("listen exec proc %v", proc)
// // check if is child proc
// controller := m.controllerMgr.GetControllerByCtrlByPPid(ppid)
// if controller != nil {
// // cover proc
// parent := controller.CheckCtrlPid(ppid)
// proc.ExecPath = parent.ExecPath
// proc.CGroupPath = parent.CGroupPath
// // add to
// err := controller.AddCtrlProc(proc)
// if err != nil {
// logger.Warningf("[%s] add exec %s to cgroups failed, err: %v", controller.Name, execPath, err)
// }
// return
// }
//
// // search controller according to exe path, get highest priority one
// controller = m.controllerMgr.GetControllerByCtlPath(execPath)
// if controller == nil {
// return
// }
// logger.Infof("start proc %s need add to proxy", execPath)
// // add to cgroups.procs and save
// err := controller.AddCtrlProc(proc)
// if err != nil {
// logger.Warningf("[%s] add exec %s to cgroups failed, err: %v", controller.Name, execPath, err)
// }
//
//})
//if err != nil {
// logger.Warningf("connect exec proc failed, err: %v")
// return err
//}
//_, err = m.procsService.ConnectExitProc(func(execPath string, cgroupPath string, pid string, ppid string) {
// // search controller according to exe path
// logger.Debugf("listen exit proc %v", execPath)
// controller := m.controllerMgr.GetControllerByCtlPath(execPath)
// if controller == nil {
// return
// }
// proc := &netlink.ProcMessage{
// ExecPath: execPath,
// CGroupPath: cgroupPath,
// Pid: pid,
// PPid: ppid,
// }
// logger.Infof("start proc %s need remove from proxy", execPath)
// // del from save
// err := controller.DelCtlProc(proc)
// if err != nil {
// logger.Warningf("[%s] del exec %s from cgroups failed, err: %v", controller.Name, execPath, err)
// }
//
//})
return nil
}
// release all source
func (m *Manager) release() error {
// check if all app and global proxy has stopped
if m.mainChain.GetChildrenCount() != 0 {
return nil
}
// remove all handler
// m.procsService.RemoveAllHandlers()
// stop loop
// m.sigLoop.Stop()
// remove chain
err := m.mainChain.Remove()
if err != nil {
logger.Warningf("[manager] remove main chain failed, err: %v", err)
return err
}
m.iptablesMgr = nil
//// release all control procs
//err = m.mainController.ReleaseAll()
//if err != nil {
// logger.Warning("[manager] release all control procs failed, err:", err)
// return err
//}
//m.controllerMgr = nil
// remove all route
err = m.mainRoute.Remove()
if err != nil {
logger.Warning("[manager] remove all route failed, err:", err)
return err
}
m.routeMgr = nil
// reset once
m.runOnce = nil
return nil
}
// run first clean script
func (m *Manager) firstClean() error {
// get config path
path, err := com.GetConfigDir()
if err != nil {
logger.Warningf("[%s] run first clean failed, config err: %v", "manager", err)
return err
}
// get script file path
path = filepath.Join(path, define.ScriptName)
// run script
buf, err := com.RunScript(path, []string{"clear_Main"})
if err != nil {
logger.Debugf("[%s] run first clean script failed, out: %s, err: %v", "manager", string(buf), err)
return err
}
logger.Debugf("[%s] run first clean script success", "manager")
return nil
}
// first adjust cgroups
func (m *Manager) firstAdjustCGroups() error {
// get all procs message
procsMap, err := m.GetAllProcs()
if err != nil {
return err
}
// add map
for path, procSl := range procsMap {
// check if exist
if !com.MegaExist(mainProxy, path) {
logger.Debugf("[%s] dont need add %s at first", "manager", path)
continue
}
// check if already exist
controller := m.controllerMgr.GetControllerByCtlPath(path)
if controller == nil {
// add path
m.mainController.AddCtlAppPath(path)
err := m.mainController.MoveIn(path, procSl)
if err != nil {
logger.Warning("[%s] add procs %s at first failed, err: %v", "manager", path, err)
continue
}
logger.Debugf("[%s] add procs %s at first success", "manager", path)
} else {
err = m.mainController.UpdateFromManager(path)
if err != nil {
logger.Warning("[%s] add proc %s from %s at first failed, err: %v", "manager", path, controller.Name, err)
} else {
logger.Debugf("[%s] add proc %s from %s at first failed", "manager", path, controller.Name)
}
m.mainController.AddCtlAppPath(path)
}
}
return nil
}
func init() {
logger = log.NewLogger("daemon/iptables")
logger.SetLogLevel(log.LevelDebug)
}