gitee.com/aurawing/surguard-go@v0.3.1-0.20240409071558-96509a61ecf3/device/postconfig_linux.go (about) 1 package device 2 3 import ( 4 "bufio" 5 "fmt" 6 "os" 7 "os/exec" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/coreos/go-iptables/iptables" 13 "github.com/jviney/go-filelock" 14 sysctl "github.com/lorenzosaino/go-sysctl" 15 ) 16 17 const ( 18 ENV_SG_FWMARK = "SG_FWMARK" 19 ENV_SG_RT_ID = "SG_RT_ID" 20 ENV_SG_TUNNEL_FWMARK = "SG_TUNNEL_FWMARK" 21 ) 22 23 var fwmark = 1024 24 var tunnelFwmark = 65535 25 26 var ip4t *iptables.IPTables 27 var deviceName string 28 var lock filelock.FileLock 29 30 func init() { 31 lockfile := "/var/lock/surguard.lock" 32 if _, err := os.Stat(lockfile); err != nil { 33 if os.IsNotExist(err) { 34 var file, err = os.Create(lockfile) 35 if err != nil { 36 panic(err) 37 } 38 file.Close() 39 } else { 40 panic(err) 41 } 42 } 43 lock = filelock.FileLock{Path: lockfile, Timeout: time.Second * 5} 44 } 45 46 func GetDeviceIndex() int { 47 return 0 48 } 49 50 func (device *Device) configTunDevice() error { 51 ifBindInterface = false 52 var err error 53 //find tun device name 54 deviceName, err = device.tun.device.Name() 55 if err != nil { 56 device.log.Errorf("configTunDevice: failed to find tun device name: %s", err) 57 return err 58 } 59 60 //bring up tun device 61 device.runCmd(false, "ip", "link", "set", "dev", deviceName, "up") 62 for { 63 if deviceState(device.state.state.Load()) == deviceStateUp { 64 break 65 } else { 66 time.Sleep(500 * time.Millisecond) 67 } 68 } 69 device.log.Verbosef("configTunDevice: device %s is up\n", deviceName) 70 71 //close rp_filter of tun device 72 rp_filter_all, err := sysctl.Get("net.ipv4.conf.all.rp_filter") 73 if err != nil { 74 device.log.Errorf("configTunDevice: failed to get net.ipv4.conf.all.rp_filter: %s", err) 75 return err 76 } 77 if rp_filter_all != "0" { 78 err = sysctl.Set("net.ipv4.conf.all.rp_filter", "0") 79 if err != nil { 80 device.log.Errorf("configTunDevice: failed to disable net.ipv4.conf.all.rp_filter: %s", err) 81 return err 82 } 83 device.log.Verbosef("configTunDevice: set net.ipv4.conf.all.rp_filter to 0\n") 84 } 85 rp_filter_sg, err := sysctl.Get(fmt.Sprintf("net.ipv4.conf.%s.rp_filter", deviceName)) 86 if err != nil { 87 device.log.Errorf("configTunDevice: failed to get net.ipv4.conf.%s.rp_filter: %s", deviceName, err) 88 return err 89 } 90 if rp_filter_sg != "0" { 91 err = sysctl.Set(fmt.Sprintf("net.ipv4.conf.%s.rp_filter", deviceName), "0") 92 if err != nil { 93 device.log.Errorf("configTunDevice: failed to disable net.ipv4.conf.%s.rp_filter: %s", deviceName, err) 94 return err 95 } 96 device.log.Verbosef("configTunDevice: set net.ipv4.conf.%s.rp_filter to 0\n", deviceName) 97 } 98 99 //get fwmark and route table id 100 rtid := 256 101 fwmarkStr := os.Getenv(ENV_SG_FWMARK) 102 tunnelFwmarkStr := os.Getenv(ENV_SG_TUNNEL_FWMARK) 103 104 if fwmarkStr != "" { 105 fwmark, err = strconv.Atoi(fwmarkStr) 106 if err != nil { 107 device.log.Errorf("configTunDevice: failed to parse fwmark %s: %s", fwmarkStr, err) 108 } 109 } 110 if tunnelFwmarkStr != "" { 111 tunnelFwmark, err = strconv.Atoi(tunnelFwmarkStr) 112 if err != nil { 113 device.log.Errorf("configTunDevice: failed to parse tunnel fwmark %s: %s", fwmarkStr, err) 114 } 115 } 116 rtidStr := os.Getenv(ENV_SG_RT_ID) 117 if rtidStr != "" { 118 rtid, err = strconv.Atoi(rtidStr) 119 if err != nil { 120 device.log.Errorf("configTunDevice: failed to parse route table ID %s: %s", rtidStr, err) 121 } 122 } 123 124 //modify route table 125 err = device.modifyRtTables("/etc/iproute2/rt_tables", rtid) 126 if err != nil { 127 device.log.Errorf("configTunDevice: failed to modify route table ID %d: %s", rtid, err) 128 return err 129 } 130 131 // set route policy 132 device.runCmd(false, "ip", "route", "flush", "table", groupName) 133 device.runCmd(false, "ip", "route", "add", "default", "dev", deviceName, "table", groupName) 134 device.runCmd(true, "ip", "rule", "delete", "from", "all", "fwmark", strconv.Itoa(fwmark), "lookup", groupName) 135 device.runCmd(false, "ip", "rule", "add", "from", "all", "fwmark", strconv.Itoa(fwmark), "lookup", groupName) 136 device.log.Verbosef("configTunDevice: set route policy table %d %s for %s\n", rtid, groupName, deviceName) 137 138 // //set up iptables 139 // ip4t, err = iptables.NewWithProtocol(iptables.ProtocolIPv4) 140 // if err != nil { 141 // device.log.Errorf("PostConfig: failed to create new iptables instance: %s", err) 142 // return err 143 // } 144 // exists, err := ip4t.ChainExists("mangle", groupName) 145 // if err != nil { 146 // device.log.Errorf("PostConfig: check chain %s failed: %s", groupName, err) 147 // return err 148 // } 149 // if !exists { 150 // err = ip4t.NewChain("mangle", groupName) 151 // if err != nil { 152 // device.log.Errorf("PostConfig: create chain %s failed: %s", groupName, err) 153 // return err 154 // } 155 // } 156 // err = ip4t.ClearChain("mangle", groupName) 157 // if err != nil { 158 // device.log.Errorf("PostConfig: clean chain %s failed: %s", groupName, err) 159 // return err 160 // } 161 // err = ip4t.AppendUnique("mangle", "OUTPUT", "-j", groupName) 162 // if err != nil { 163 // device.log.Errorf("PostConfig: append chain to %s failed: %s", groupName, err) 164 // return err 165 // } 166 return nil 167 } 168 169 func (device *Device) initRules() error { 170 // //find tun device name 171 // deviceName, err := device.tun.device.Name() 172 // if err != nil { 173 // device.log.Errorf("initRules: failed to find tun device name: %s", err) 174 // return err 175 // } 176 //set up iptables 177 err := lock.Lock() 178 if err != nil { 179 device.log.Errorf("initRules: accquire global lock failed: %s", err) 180 return err 181 } 182 defer lock.Unlock() 183 ip4t, err = iptables.NewWithProtocol(iptables.ProtocolIPv4) 184 if err != nil { 185 device.log.Errorf("initRules: failed to create new iptables instance: %s", err) 186 return err 187 } 188 //initialize IN-SURGUARD chain 189 exists, err := ip4t.ChainExists("mangle", "IN-SURGUARD") 190 if err != nil { 191 device.log.Errorf("initRules: check chain IN-SURGUARD failed: %s", err) 192 return err 193 } 194 if !exists { 195 err = ip4t.NewChain("mangle", "IN-SURGUARD") 196 if err != nil { 197 device.log.Errorf("initRules: create chain IN-SURGUARD failed: %s", err) 198 return err 199 } 200 } 201 exists, err = ip4t.Exists("mangle", "PREROUTING", "-j", "IN-SURGUARD") 202 if err != nil { 203 device.log.Errorf("initRules: check if rule IN-SURGUARD in chain PREROUTING failed: %s", err) 204 return err 205 } 206 if !exists { 207 err = ip4t.AppendUnique("mangle", "PREROUTING", "-j", "IN-SURGUARD") 208 if err != nil { 209 device.log.Errorf("initRules: add chain reference IN-SURGUARD to chain PREROUTING failed: %s", err) 210 return err 211 } 212 } 213 // exists, err = ip4t.ChainExists("mangle", fmt.Sprintf("IN-%s", groupName)) 214 // if err != nil { 215 // device.log.Errorf("initRules: check chain %s failed: %s", fmt.Sprintf("IN-%s", groupName), err) 216 // return err 217 // } 218 // if !exists { 219 // err = ip4t.NewChain("mangle", fmt.Sprintf("IN-%s", groupName)) 220 // if err != nil { 221 // device.log.Errorf("initRules: create chain %s failed: %s", fmt.Sprintf("IN-%s", groupName), err) 222 // return err 223 // } 224 // } 225 // err = ip4t.ClearChain("mangle", fmt.Sprintf("IN-%s", groupName)) 226 // if err != nil { 227 // device.log.Errorf("initRules: clean chain %s failed: %s", fmt.Sprintf("IN-%s", groupName), err) 228 // return err 229 // } 230 exists, err = ip4t.Exists("mangle", "IN-SURGUARD", "-i", deviceName, "-j", "CONNMARK", "--set-mark", strconv.Itoa(fwmark)) 231 if err != nil { 232 device.log.Errorf("initRules: checking if connmark setting rule in chain IN-SURGUARD failed: %s", err) 233 return err 234 } 235 if !exists { 236 err = ip4t.AppendUnique("mangle", "IN-SURGUARD", "-i", deviceName, "-j", "CONNMARK", "--set-mark", strconv.Itoa(fwmark)) 237 if err != nil { 238 device.log.Errorf("initRules: create connmark setting rule in chain IN-SURGUARD failed: %s", err) 239 return err 240 } 241 } 242 // err = ip4t.AppendUnique("mangle", fmt.Sprintf("IN-%s", groupName), "-i", deviceName, "-j", "CONNMARK", "--set-mark", strconv.Itoa(fwmark)) 243 // if err != nil { 244 // device.log.Errorf("initRules: create connmark setting rule in chain %s failed: %s", fmt.Sprintf("IN-%s", groupName), err) 245 // return err 246 // } 247 // err = ip4t.AppendUnique("mangle", fmt.Sprintf("IN-%s", groupName), "-m", "connmark", "!", "--mark", "0", "-j", "RETURN") 248 // if err != nil { 249 // device.log.Errorf("initRules: create connmark checking rule in chain %s failed: %s", fmt.Sprintf("IN-%s", groupName), err) 250 // return err 251 // } 252 // err = ip4t.AppendUnique("mangle", fmt.Sprintf("IN-%s", groupName), "-p", "udp", "--dport", strconv.Itoa(int(device.net.port)), "-j", "CONNMARK", "--set-mark", strconv.Itoa(tunnelFwmark)) 253 // if err != nil { 254 // device.log.Errorf("initRules: create connmark setting rule in chain %s failed: %s", fmt.Sprintf("IN-%s", groupName), err) 255 // return err 256 // } 257 // err = ip4t.Append("mangle", fmt.Sprintf("IN-%s", groupName), "-m", "connmark", "!", "--mark", "0", "-j", "RETURN") 258 // if err != nil { 259 // device.log.Errorf("initRules: create connmark checking rule in chain %s failed: %s", fmt.Sprintf("IN-%s", groupName), err) 260 // return err 261 // } 262 //initialize PRE-SURGUARD chain 263 exists, err = ip4t.ChainExists("mangle", "PRE-SURGUARD") 264 if err != nil { 265 device.log.Errorf("initRules: check chain PRE-SURGUARD failed: %s", err) 266 return err 267 } 268 if !exists { 269 err = ip4t.NewChain("mangle", "PRE-SURGUARD") 270 if err != nil { 271 device.log.Errorf("initRules: create chain PRE-SURGUARD failed: %s", err) 272 return err 273 } 274 } 275 exists, err = ip4t.Exists("mangle", "OUTPUT", "-j", "PRE-SURGUARD") 276 if err != nil { 277 device.log.Errorf("initRules: check if rule PRE-SURGUARD in chain OUTPUT failed: %s", err) 278 return err 279 } 280 if !exists { 281 err = ip4t.AppendUnique("mangle", "OUTPUT", "-j", "PRE-SURGUARD") 282 if err != nil { 283 device.log.Errorf("initRules: add chain reference PRE-SURGUARD to chain OUTPUT failed: %s", err) 284 return err 285 } 286 } 287 // exists, err = ip4t.Exists("mangle", "FORWARD", "-j", "PRE-SURGUARD") 288 // if err != nil { 289 // device.log.Errorf("initRules: check if rule PRE-SURGUARD in chain FORWARD failed: %s", err) 290 // return err 291 // } 292 // if !exists { 293 // err = ip4t.AppendUnique("mangle", "FORWARD", "-j", "PRE-SURGUARD") 294 // if err != nil { 295 // device.log.Errorf("initRules: add chain reference PRE-SURGUARD to chain FORWARD failed: %s", err) 296 // return err 297 // } 298 // } 299 exists, err = ip4t.Exists("mangle", "PRE-SURGUARD", "-j", "CONNMARK", "--restore-mark") 300 if err != nil { 301 device.log.Errorf("initRules: check if rule restore mark in chain PRE-SURGUARD failed: %s", err) 302 return err 303 } 304 if !exists { 305 err = ip4t.AppendUnique("mangle", "PRE-SURGUARD", "-j", "CONNMARK", "--restore-mark") 306 if err != nil { 307 device.log.Errorf("initRules: add rule restore mark in chain PRE-SURGUARD failed: %s", err) 308 return err 309 } 310 } 311 exists, err = ip4t.Exists("mangle", "PRE-SURGUARD", "-m", "mark", "!", "--mark", "0", "-j", "ACCEPT") 312 if err != nil { 313 device.log.Errorf("initRules: check if mark checking rule in chain PRE-SURGUARD failed: %s", err) 314 return err 315 } 316 if !exists { 317 err = ip4t.AppendUnique("mangle", "PRE-SURGUARD", "-m", "mark", "!", "--mark", "0", "-j", "ACCEPT") 318 if err != nil { 319 device.log.Errorf("initRules: create mark checking rule in chain PRE-SURGUARD failed: %s", err) 320 return err 321 } 322 } 323 exists, err = ip4t.Exists("mangle", "PRE-SURGUARD", "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT") 324 if err != nil { 325 device.log.Errorf("initRules: check if releated connection passing rule in chain PRE-SURGUARD failed: %s", err) 326 return err 327 } 328 if !exists { 329 err = ip4t.AppendUnique("mangle", "PRE-SURGUARD", "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT") 330 if err != nil { 331 device.log.Errorf("initRules: create releated connection passing rule in chain PRE-SURGUARD failed: %s", err) 332 return err 333 } 334 } 335 //initialize OUT-SURGUARD chain 336 exists, err = ip4t.ChainExists("mangle", "OUT-SURGUARD") 337 if err != nil { 338 device.log.Errorf("initRules: check chain OUT-SURGUARD failed: %s", err) 339 return err 340 } 341 if !exists { 342 err = ip4t.NewChain("mangle", "OUT-SURGUARD") 343 if err != nil { 344 device.log.Errorf("initRules: create chain OUT-SURGUARD failed: %s", err) 345 return err 346 } 347 } 348 exists, err = ip4t.Exists("mangle", "OUTPUT", "-j", "OUT-SURGUARD") 349 if err != nil { 350 device.log.Errorf("initRules: check if rule OUT-SURGUARD in chain OUTPUT failed: %s", err) 351 return err 352 } 353 if !exists { 354 err = ip4t.AppendUnique("mangle", "OUTPUT", "-j", "OUT-SURGUARD") 355 if err != nil { 356 device.log.Errorf("initRules: add chain reference OUT-SURGUARD to chain OUTPUT failed: %s", err) 357 return err 358 } 359 } 360 // exists, err = ip4t.Exists("mangle", "FORWARD", "-j", "OUT-SURGUARD") 361 // if err != nil { 362 // device.log.Errorf("initRules: check if rule OUT-SURGUARD in chain FORWARD failed: %s", err) 363 // return err 364 // } 365 // if !exists { 366 // err = ip4t.AppendUnique("mangle", "FORWARD", "-j", "OUT-SURGUARD") 367 // if err != nil { 368 // device.log.Errorf("initRules: add chain reference OUT-SURGUARD to chain FORWARD failed: %s", err) 369 // return err 370 // } 371 // } 372 exists, err = ip4t.ChainExists("mangle", fmt.Sprintf("OUT-%s", groupName)) 373 if err != nil { 374 device.log.Errorf("initRules: check chain %s failed: %s", fmt.Sprintf("OUT-%s", groupName), err) 375 return err 376 } 377 if !exists { 378 err = ip4t.NewChain("mangle", fmt.Sprintf("OUT-%s", groupName)) 379 if err != nil { 380 device.log.Errorf("initRules: create chain %s failed: %s", fmt.Sprintf("OUT-%s", groupName), err) 381 return err 382 } 383 } 384 err = ip4t.ClearChain("mangle", fmt.Sprintf("OUT-%s", groupName)) 385 if err != nil { 386 device.log.Errorf("initRules: clean chain %s failed: %s", fmt.Sprintf("OUT-%s", groupName), err) 387 return err 388 } 389 exists, err = ip4t.Exists("mangle", "OUT-SURGUARD", "-j", fmt.Sprintf("OUT-%s", groupName)) 390 if err != nil { 391 device.log.Errorf("initRules: check if rule %s in chain OUT-SURGUARD failed: %s", fmt.Sprintf("OUT-%s", groupName), err) 392 return err 393 } 394 if !exists { 395 err = ip4t.AppendUnique("mangle", "OUT-SURGUARD", "-j", fmt.Sprintf("OUT-%s", groupName)) 396 if err != nil { 397 device.log.Errorf("initRules: add chain reference %s to chain OUT-SURGUARD failed: %s", fmt.Sprintf("OUT-%s", groupName), err) 398 return err 399 } 400 } 401 return nil 402 } 403 404 func (device *Device) zkChangedCallback(addedMap, deletedMap map[string]string) { 405 for _, dels := range deletedMap { 406 flag := true 407 for _, del := range strings.Split(dels, ",") { 408 strs := strings.Split(del, ":") 409 ip4t.Delete("mangle", fmt.Sprintf("OUT-%s", groupName), "-d", strs[0], "-j", "MARK", "--set-mark", strconv.Itoa(fwmark)) 410 if flag { 411 ip4t.Delete("mangle", fmt.Sprintf("OUT-%s", groupName), "-p", "udp", "-d", strs[0], "--dport", strs[1], "-j", "MARK", "--set-mark", strconv.Itoa(tunnelFwmark)) 412 flag = false 413 } 414 ip4t.Delete("mangle", fmt.Sprintf("OUT-%s", groupName), "-d", strs[0], "-m", "mark", "!", "--mark", "0", "-j", "RETURN") 415 } 416 } 417 for _, adds := range addedMap { 418 flag := true 419 for _, add := range strings.Split(adds, ",") { 420 strs := strings.Split(add, ":") 421 ip4t.AppendUnique("mangle", fmt.Sprintf("OUT-%s", groupName), "-d", strs[0], "-j", "MARK", "--set-mark", strconv.Itoa(fwmark)) 422 if flag { 423 ip4t.AppendUnique("mangle", fmt.Sprintf("OUT-%s", groupName), "-p", "udp", "-d", strs[0], "--dport", strs[1], "-j", "MARK", "--set-mark", strconv.Itoa(tunnelFwmark)) 424 flag = false 425 } 426 ip4t.AppendUnique("mangle", fmt.Sprintf("OUT-%s", groupName), "-d", strs[0], "-m", "mark", "!", "--mark", "0", "-j", "RETURN") 427 } 428 } 429 } 430 431 func (device *Device) clearConfigOSSpecific() error { 432 err := lock.Lock() 433 if err != nil { 434 device.log.Errorf("clearConfigOSSpecific: accquire global lock failed: %s", err) 435 return err 436 } 437 defer lock.Unlock() 438 device.runCmd(false, "ip", "route", "flush", "table", groupName) 439 device.runCmd(true, "ip", "rule", "delete", "from", "all", "fwmark", strconv.Itoa(fwmark), "lookup", groupName) 440 // err := ip4t.ClearChain("mangle", fmt.Sprintf("IN-%s", groupName)) 441 // if err != nil { 442 // device.log.Errorf("PostConfig: clean chain %s failed: %s", fmt.Sprintf("IN-%s", groupName), err) 443 // return err 444 // } 445 446 err = ip4t.Delete("mangle", "IN-SURGUARD", "-i", deviceName, "-j", "CONNMARK", "--set-mark", strconv.Itoa(fwmark)) 447 if err != nil { 448 device.log.Errorf("clearConfigOSSpecific: delete connmark setting rule in chain IN-SURGUARD failed: %s", err) 449 return err 450 } 451 // err = ip4t.DeleteChain("mangle", fmt.Sprintf("IN-%s", groupName)) 452 // if err != nil { 453 // device.log.Errorf("PostConfig: delete chain %s failed: %s", fmt.Sprintf("IN-%s", groupName), err) 454 // return err 455 // } 456 err = ip4t.ClearChain("mangle", fmt.Sprintf("OUT-%s", groupName)) 457 if err != nil { 458 device.log.Errorf("clearConfigOSSpecific: clean chain %s failed: %s", fmt.Sprintf("OUT-%s", groupName), err) 459 return err 460 } 461 err = ip4t.Delete("mangle", "OUT-SURGUARD", "-j", fmt.Sprintf("OUT-%s", groupName)) 462 if err != nil { 463 device.log.Errorf("clearConfigOSSpecific: delete chain reference %s in OUT-SURGUARD chain failed: %s", fmt.Sprintf("OUT-%s", groupName), err) 464 return err 465 } 466 err = ip4t.DeleteChain("mangle", fmt.Sprintf("OUT-%s", groupName)) 467 if err != nil { 468 device.log.Errorf("clearConfigOSSpecific: delete chain %s failed: %s", fmt.Sprintf("OUT-%s", groupName), err) 469 return err 470 } 471 return nil 472 } 473 474 func (device *Device) modifyRtTables(filename string, rtid int) error { 475 //lock := filelock.FileLock{Path: filename, Timeout: time.Second * 5} 476 err := lock.Lock() 477 if err != nil { 478 device.log.Errorf("modifyRtTables: accquire global lock failed: %s", err) 479 return err 480 } 481 defer lock.Unlock() 482 output := make([]string, 0) 483 484 fileData, err := os.ReadFile(filename) 485 if err != nil { 486 device.log.Errorf("modifyRtTables: can not read file %s", filename) 487 return err 488 } 489 490 scanner := bufio.NewScanner(strings.NewReader(string(fileData))) 491 for scanner.Scan() { 492 line := scanner.Text() 493 if strings.Contains(line, fmt.Sprintf("%d\t%s", rtid, groupName)) { 494 return nil 495 } else if !strings.Contains(line, groupName) { 496 output = append(output, line) 497 } 498 } 499 500 output = append(output, fmt.Sprintf("%d\t%s", rtid, groupName)) 501 502 err = os.WriteFile(filename, []byte(strings.Join(output, "\n")), 0644) 503 if err != nil { 504 device.log.Errorf("modifyRtTables: can not write back file %s", filename) 505 return err 506 } 507 508 return nil 509 } 510 511 func (device *Device) runCmd(ignoreErr bool, args ...string) { 512 cmd := exec.Command(args[0], args[1:]...) 513 cmd.Stderr = os.Stderr 514 cmd.Stdout = os.Stdout 515 cmd.Stdin = os.Stdin 516 err := cmd.Run() 517 if nil != err { 518 if !ignoreErr { 519 device.log.Errorf("Error running %s: %s\n", args[0], err) 520 } else { 521 device.log.Verbosef("Warning: %s\n", err.Error()) 522 } 523 } 524 }