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  }