|
@@ -0,0 +1,143 @@
|
|
|
+package default_builtins
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "git.swzry.com/ProjectNagae/saki-v0/engine"
|
|
|
+ "github.com/dop251/goja"
|
|
|
+ "github.com/vishvananda/netlink"
|
|
|
+ "net"
|
|
|
+ "runtime"
|
|
|
+)
|
|
|
+
|
|
|
+type NetlinkUtil struct {
|
|
|
+ mctx *engine.ModuleContext
|
|
|
+}
|
|
|
+
|
|
|
+func (g *NetlinkUtil) Enable(mctx *engine.ModuleContext) engine.RegisterFunc {
|
|
|
+ g.mctx = mctx
|
|
|
+ return g.register
|
|
|
+}
|
|
|
+
|
|
|
+func (g *NetlinkUtil) register(s engine.ModuleSetFunc) {
|
|
|
+ s("setAddr", g.fSetAddr)
|
|
|
+ s("setLink", g.fSetLink)
|
|
|
+ s("addRoute", g.fAddRoute)
|
|
|
+}
|
|
|
+
|
|
|
+func (g *NetlinkUtil) iCheckOs() {
|
|
|
+ if runtime.GOOS != "linux" {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("not supported os '%s'. only linux is supported", runtime.GOOS)))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (g *NetlinkUtil) fSetAddr(call goja.FunctionCall) goja.Value {
|
|
|
+ g.iCheckOs()
|
|
|
+ if len(call.Arguments) != 2 {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: invalid arguments")))
|
|
|
+ }
|
|
|
+ devRaw, ok := call.Arguments[0].Export().(string)
|
|
|
+ if !ok {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: argument[0] (dev) is not string")))
|
|
|
+ }
|
|
|
+ ipRaw, ok := call.Arguments[1].Export().(string)
|
|
|
+ if !ok {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: argument[1] (addr) is not string")))
|
|
|
+ }
|
|
|
+ link, err := netlink.LinkByName(devRaw)
|
|
|
+ if err != nil {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: failed to get link device '%s': %w", devRaw, err)))
|
|
|
+ }
|
|
|
+ addr, err := netlink.ParseAddr(ipRaw)
|
|
|
+ if err != nil {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: failed to parse address '%s': %w", ipRaw, err)))
|
|
|
+ }
|
|
|
+ err = netlink.AddrAdd(link, addr)
|
|
|
+ if err != nil {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: failed to set address: %w", err)))
|
|
|
+ }
|
|
|
+ return goja.Undefined()
|
|
|
+}
|
|
|
+
|
|
|
+func (g *NetlinkUtil) fSetLink(call goja.FunctionCall) goja.Value {
|
|
|
+ g.iCheckOs()
|
|
|
+ if len(call.Arguments) != 2 {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: invalid arguments")))
|
|
|
+ }
|
|
|
+ devRaw, ok := call.Arguments[0].Export().(string)
|
|
|
+ if !ok {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: argument[0] (dev) is not string")))
|
|
|
+ }
|
|
|
+ linkState, ok := call.Arguments[1].Export().(bool)
|
|
|
+ if !ok {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: argument[1] (state) is not bool")))
|
|
|
+ }
|
|
|
+ link, err := netlink.LinkByName(devRaw)
|
|
|
+ if err != nil {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: failed to get link device '%s': %w", devRaw, err)))
|
|
|
+ }
|
|
|
+ if linkState {
|
|
|
+ err = netlink.LinkSetUp(link)
|
|
|
+ } else {
|
|
|
+ err = netlink.LinkSetDown(link)
|
|
|
+ }
|
|
|
+ if err != nil {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: failed to set link state: %w", err)))
|
|
|
+ }
|
|
|
+ return goja.Undefined()
|
|
|
+}
|
|
|
+
|
|
|
+func (g *NetlinkUtil) fAddRoute(call goja.FunctionCall) goja.Value {
|
|
|
+ g.iCheckOs()
|
|
|
+ var ok bool
|
|
|
+ l := len(call.Arguments)
|
|
|
+ if l < 2 {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: invalid arguments: need at least 2 arguments")))
|
|
|
+ }
|
|
|
+ if l > 4 {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: invalid arguments: need at most 4 arguments")))
|
|
|
+ }
|
|
|
+ dstRaw, ok := call.Arguments[0].Export().(string)
|
|
|
+ if !ok {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: argument[0] (dst) is not string")))
|
|
|
+ }
|
|
|
+ devRaw, ok := call.Arguments[1].Export().(string)
|
|
|
+ if !ok {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: argument[1] (dev) is not string")))
|
|
|
+ }
|
|
|
+ var gwRaw string
|
|
|
+ if l > 2 {
|
|
|
+ gwRaw, ok = call.Arguments[2].Export().(string)
|
|
|
+ if !ok {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: argument[2] (gw) is not string")))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var srcRaw string
|
|
|
+ if l > 3 {
|
|
|
+ srcRaw, ok = call.Arguments[3].Export().(string)
|
|
|
+ if !ok {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: argument[3] (src) is not string")))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ link, err := netlink.LinkByName(devRaw)
|
|
|
+ if err != nil {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: failed to get link device '%s': %w", devRaw, err)))
|
|
|
+ }
|
|
|
+ route := netlink.Route{LinkIndex: link.Attrs().Index}
|
|
|
+ if dstRaw != "default" {
|
|
|
+ dstAddr, _ := netlink.ParseAddr(dstRaw)
|
|
|
+ route.Dst = dstAddr.IPNet
|
|
|
+ }
|
|
|
+ if srcRaw != "" {
|
|
|
+ srcIP := net.ParseIP(srcRaw)
|
|
|
+ route.Src = srcIP
|
|
|
+ }
|
|
|
+ if gwRaw != "" {
|
|
|
+ gatewayIP := net.ParseIP(gwRaw)
|
|
|
+ route.Gw = gatewayIP
|
|
|
+ }
|
|
|
+ err = netlink.RouteAdd(&route)
|
|
|
+ if err != nil {
|
|
|
+ panic(g.mctx.NewValue(fmt.Errorf("setAddr: failed to add route: %w", err)))
|
|
|
+ }
|
|
|
+ return goja.Undefined()
|
|
|
+}
|