diff --git a/dist/rootfs/etc/openlan/access.yaml b/dist/rootfs/etc/openlan/access.yaml new file mode 100644 index 0000000..2e579d5 --- /dev/null +++ b/dist/rootfs/etc/openlan/access.yaml @@ -0,0 +1,18 @@ +protocol: tcp +connection: 2.2.2.1 +interface: + address: 192.168.11.33/24 +username: test@vxlan +password: fvph0ldhdvai +crypt: + secret: 477bb0c55edb +backends: +- server: 192.168.11.10 + match: + - openai.com + - chatgpt.com +- server: 192.168.11.11 + match: + - google.com + - github.com + - facebook.com \ No newline at end of file diff --git a/pkg/access/point_darwin.go b/pkg/access/point_darwin.go index df26c43..9b1c8eb 100755 --- a/pkg/access/point_darwin.go +++ b/pkg/access/point_darwin.go @@ -1,10 +1,11 @@ package access import ( + "strings" + "github.com/luscis/openlan/pkg/config" "github.com/luscis/openlan/pkg/libol" "github.com/luscis/openlan/pkg/models" - "strings" ) type Point struct { @@ -39,16 +40,16 @@ func (p *Point) AddAddr(ipStr string) error { ips := strings.SplitN(ipStr, "/", 2) out, err := libol.IpAddrAdd(p.IfName(), ips[0], ips[0]) if err != nil { - p.out.Warn("Point.AddAddr: %s, %s", err, out) + p.out.Warn("Access.AddAddr: %s, %s", err, out) return err } - p.out.Info("Point.AddAddr: %s", ipStr) + p.out.Info("Access.AddAddr: %s", ipStr) // add directly route. out, err = libol.IpRouteAdd(p.IfName(), ipStr, "") if err != nil { - p.out.Warn("Point.AddAddr: %s, %s", err, out) + p.out.Warn("Access.AddAddr: %s, %s", err, out) } - p.out.Info("Point.AddAddr: route %s via %s", ipStr, p.IfName()) + p.out.Info("Access.AddAddr: route %s via %s", ipStr, p.IfName()) p.addr = ipStr return nil } @@ -57,17 +58,17 @@ func (p *Point) DelAddr(ipStr string) error { // delete directly route. out, err := libol.IpRouteDel(p.IfName(), ipStr, "") if err != nil { - p.out.Warn("Point.DelAddr: %s, %s", err, out) + p.out.Warn("Access.DelAddr: %s, %s", err, out) } - p.out.Info("Point.DelAddr: route %s via %s", ipStr, p.IfName()) + p.out.Info("Access.DelAddr: route %s via %s", ipStr, p.IfName()) // delete point-to-point ip4 := strings.SplitN(ipStr, "/", 2)[0] out, err = libol.IpAddrDel(p.IfName(), ip4) if err != nil { - p.out.Warn("Point.DelAddr: %s, %s", err, out) + p.out.Warn("Access.DelAddr: %s, %s", err, out) return err } - p.out.Info("Point.DelAddr: %s", ip4) + p.out.Info("Access.DelAddr: %s", ip4) p.addr = "" return nil } @@ -79,10 +80,10 @@ func (p *Point) AddRoutes(routes []*models.Route) error { for _, route := range routes { out, err := libol.IpRouteAdd(p.IfName(), route.Prefix, "") if err != nil { - p.out.Warn("Point.AddRoutes: %s %s", route.Prefix, out) + p.out.Warn("Access.AddRoutes: %s %s", route.Prefix, out) continue } - p.out.Info("Point.AddRoutes: route %s via %s", route.Prefix, p.IfName()) + p.out.Info("Access.AddRoutes: route %s via %s", route.Prefix, p.IfName()) } p.routes = routes return nil @@ -92,10 +93,10 @@ func (p *Point) DelRoutes(routes []*models.Route) error { for _, route := range routes { out, err := libol.IpRouteDel(p.IfName(), route.Prefix, "") if err != nil { - p.out.Warn("Point.DelRoutes: %s %s", route.Prefix, out) + p.out.Warn("Access.DelRoutes: %s %s", route.Prefix, out) continue } - p.out.Info("Point.DelRoutes: route %s via %s", route.Prefix, p.IfName()) + p.out.Info("Access.DelRoutes: route %s via %s", route.Prefix, p.IfName()) } p.routes = nil return nil diff --git a/pkg/access/point_linux.go b/pkg/access/point_linux.go index 216f587..261870d 100755 --- a/pkg/access/point_linux.go +++ b/pkg/access/point_linux.go @@ -1,12 +1,13 @@ package access import ( + "net" + "strings" + "github.com/luscis/openlan/pkg/config" "github.com/luscis/openlan/pkg/models" "github.com/luscis/openlan/pkg/network" "github.com/vishvananda/netlink" - "net" - "strings" ) type Point struct { @@ -35,11 +36,15 @@ func NewPoint(config *config.Point) *Point { } func (p *Point) Initialize() { - p.worker.listener.AddAddr = p.AddAddr - p.worker.listener.DelAddr = p.DelAddr - p.worker.listener.AddRoutes = p.AddRoutes - p.worker.listener.DelRoutes = p.DelRoutes - p.worker.listener.OnTap = p.OnTap + w := p.worker + + w.listener.AddAddr = p.AddAddr + w.listener.DelAddr = p.DelAddr + w.listener.AddRoutes = p.AddRoutes + w.listener.DelRoutes = p.DelRoutes + w.listener.OnTap = p.OnTap + w.listener.Forward = p.Forward + p.MixPoint.Initialize() } @@ -49,13 +54,13 @@ func (p *Point) DelAddr(ipStr string) error { } ipAddr, err := netlink.ParseAddr(ipStr) if err != nil { - p.out.Error("Point.AddAddr.ParseCIDR %s: %s", ipStr, err) + p.out.Error("Access.AddAddr.ParseCIDR %s: %s", ipStr, err) return err } if err := netlink.AddrDel(p.link, ipAddr); err != nil { - p.out.Warn("Point.DelAddr.UnsetLinkIp: %s", err) + p.out.Warn("Access.DelAddr.UnsetLinkIp: %s", err) } - p.out.Info("Point.DelAddr: %s", ipStr) + p.out.Info("Access.DelAddr: %s", ipStr) p.addr = "" return nil } @@ -66,14 +71,14 @@ func (p *Point) AddAddr(ipStr string) error { } ipAddr, err := netlink.ParseAddr(ipStr) if err != nil { - p.out.Error("Point.AddAddr.ParseCIDR %s: %s", ipStr, err) + p.out.Error("Access.AddAddr.ParseCIDR %s: %s", ipStr, err) return err } if err := netlink.AddrAdd(p.link, ipAddr); err != nil { - p.out.Warn("Point.AddAddr.SetLinkIp: %s", err) + p.out.Warn("Access.AddAddr.SetLinkIp: %s", err) return err } - p.out.Info("Point.AddAddr: %s", ipStr) + p.out.Info("Access.AddAddr: %s", ipStr) p.addr = ipStr return nil } @@ -85,52 +90,52 @@ func (p *Point) UpBr(name string) *netlink.Bridge { la := netlink.LinkAttrs{TxQLen: -1, Name: name} br := &netlink.Bridge{LinkAttrs: la} if link, err := netlink.LinkByName(name); link == nil { - p.out.Warn("Point.UpBr: %s %s", name, err) + p.out.Warn("Access.UpBr: %s %s", name, err) err := netlink.LinkAdd(br) if err != nil { - p.out.Warn("Point.UpBr.newBr: %s %s", name, err) + p.out.Warn("Access.UpBr.newBr: %s %s", name, err) } } link, err := netlink.LinkByName(name) if link == nil { - p.out.Error("Point.UpBr: %s %s", name, err) + p.out.Error("Access.UpBr: %s %s", name, err) return nil } if err := netlink.LinkSetUp(link); err != nil { - p.out.Error("Point.UpBr.LinkUp: %s", err) + p.out.Error("Access.UpBr.LinkUp: %s", err) } return br } func (p *Point) OnTap(w *TapWorker) error { - p.out.Info("Point.OnTap") + p.out.Info("Access.OnTap") tap := w.device name := tap.Name() if tap.Type() == network.ProviderVir { // virtual device - p.out.Error("Point.OnTap: not support %s", tap.Type()) + p.out.Error("Access.OnTap: not support %s", tap.Type()) return nil } // kernel device link, err := netlink.LinkByName(name) if err != nil { - p.out.Error("Point.OnTap: Get %s: %s", name, err) + p.out.Error("Access.OnTap: Get %s: %s", name, err) return err } if err := netlink.LinkSetMTU(link, p.ipMtu); err != nil { - p.out.Error("Point.OnTap.SetMTU: %s", err) + p.out.Error("Access.OnTap.SetMTU: %s", err) } if br := p.UpBr(p.brName); br != nil { if err := netlink.LinkSetMaster(link, br); err != nil { - p.out.Error("Point.OnTap.AddSlave: Switch dev %s: %s", name, err) + p.out.Error("Access.OnTap.AddSlave: Switch dev %s: %s", name, err) } link, err = netlink.LinkByName(p.brName) if err != nil { - p.out.Error("Point.OnTap: Get %s: %s", p.brName, err) + p.out.Error("Access.OnTap: Get %s: %s", p.brName, err) } if p.config.Interface.Cost > 0 { port := network.NewBrPort(name) if err := port.Cost(p.config.Interface.Cost); err != nil { - p.out.Error("Point.OnTap: Cost %s: %s", p.brName, err) + p.out.Error("Access.OnTap: Cost %s: %s", p.brName, err) } } } @@ -156,7 +161,7 @@ func (p *Point) AddBypass(routes []*models.Route) { addr, dest, _ := net.ParseCIDR(remote + "/32") gws, err := netlink.RouteGet(addr) if err != nil || len(gws) == 0 { - p.out.Error("Point.AddBypass: RouteGet %s: %s", addr, err) + p.out.Error("Access.AddBypass: RouteGet %s: %s", addr, err) return } rt := &netlink.Route{ @@ -165,19 +170,19 @@ func (p *Point) AddBypass(routes []*models.Route) { Gw: gws[0].Gw, Table: 100, } - p.out.Debug("Point.AddBypass: %s") + p.out.Debug("Access.AddBypass: %s") if err := netlink.RouteReplace(rt); err != nil { - p.out.Warn("Point.AddBypass: %s %s", rt.Dst, err) + p.out.Warn("Access.AddBypass: %s %s", rt.Dst, err) return } - p.out.Info("Point.AddBypass: route %s via %s", rt.Dst, rt.Gw) + p.out.Info("Access.AddBypass: route %s via %s", rt.Dst, rt.Gw) ru := netlink.NewRule() ru.Table = 100 ru.Priority = 16383 if err := netlink.RuleAdd(ru); err != nil { - p.out.Warn("Point.AddBypass: %s %s", ru.Dst, err) + p.out.Warn("Access.AddBypass: %s %s", ru.Dst, err) } - p.out.Info("Point.AddBypass: %s", ru) + p.out.Info("Access.AddBypass: %s", ru) p.bypass = rt for _, rt := range routes { if rt.Prefix != "0.0.0.0/0" { @@ -191,11 +196,11 @@ func (p *Point) AddBypass(routes []*models.Route) { Gw: gw, Priority: rt.Metric, } - p.out.Debug("Point.AddBypass: %s", rt0) + p.out.Debug("Access.AddBypass: %s", rt0) if err := netlink.RouteAdd(&rt0); err != nil { - p.out.Warn("Point.AddBypass: %s %s", rt0.Dst, err) + p.out.Warn("Access.AddBypass: %s %s", rt0.Dst, err) } - p.out.Info("Point.AddBypass: route %s via %s", rt0.Dst, rt0.Gw) + p.out.Info("Access.AddBypass: route %s via %s", rt0.Dst, rt0.Gw) _, dst1, _ := net.ParseCIDR("128.0.0.0/1") rt1 := netlink.Route{ LinkIndex: p.link.Attrs().Index, @@ -203,11 +208,24 @@ func (p *Point) AddBypass(routes []*models.Route) { Gw: gw, Priority: rt.Metric, } - p.out.Debug("Point.AddBypass: %s", rt1) + p.out.Debug("Access.AddBypass: %s", rt1) if err := netlink.RouteAdd(&rt1); err != nil { - p.out.Warn("Point.AddBypass: %s %s", rt1.Dst, err) + p.out.Warn("Access.AddBypass: %s %s", rt1.Dst, err) + } + p.out.Info("Access.AddBypass: route %s via %s", rt1.Dst, rt1.Gw) + } +} + +func (p *Point) Forward(prefix, nexthop string) { + _, dst, _ := net.ParseCIDR(prefix) + p.out.Info("Access.Forward: %s via %s", prefix, nexthop) + if err := netlink.RouteAdd(&netlink.Route{ + Dst: dst, + Gw: net.ParseIP(nexthop), + }); err != nil { + if !strings.Contains(err.Error(), "file exists") { + p.out.Warn("Access.Forward: %s %s", prefix, err) } - p.out.Info("Point.AddBypass: route %s via %s", rt1.Dst, rt1.Gw) } } @@ -228,12 +246,12 @@ func (p *Point) AddRoutes(routes []*models.Route) error { Gw: nxt, Priority: rt.Metric, } - p.out.Debug("Point.AddRoute: %s", rte) + p.out.Debug("Access.AddRoute: %s", rte) if err := netlink.RouteAdd(&rte); err != nil { - p.out.Warn("Point.AddRoute: %s %s", rt.Prefix, err) + p.out.Warn("Access.AddRoute: %s %s", rt.Prefix, err) continue } - p.out.Info("Point.AddRoutes: route %s via %s", rt.Prefix, rt.NextHop) + p.out.Info("Access.AddRoutes: route %s via %s", rt.Prefix, rt.NextHop) } p.routes = routes return nil @@ -243,12 +261,12 @@ func (p *Point) DelBypass(routes []*models.Route) { if !p.config.ByPass || p.bypass == nil { return } - p.out.Debug("Point.DelRoute: %s") + p.out.Debug("Access.DelRoute: %s") rt := p.bypass if err := netlink.RouteAdd(rt); err != nil { - p.out.Warn("Point.DelRoute: %s %s", rt.Dst, err) + p.out.Warn("Access.DelRoute: %s %s", rt.Dst, err) } - p.out.Info("Point.DelBypass: route %s via %s", rt.Dst, rt.Gw) + p.out.Info("Access.DelBypass: route %s via %s", rt.Dst, rt.Gw) p.bypass = nil for _, rt := range routes { if rt.Prefix != "0.0.0.0/0" { @@ -262,11 +280,11 @@ func (p *Point) DelBypass(routes []*models.Route) { Gw: gw, Priority: rt.Metric, } - p.out.Debug("Point.DelBypass: %s", rt0) + p.out.Debug("Access.DelBypass: %s", rt0) if err := netlink.RouteDel(&rt0); err != nil { - p.out.Warn("Point.DelBypass: %s %s", rt0.Dst, err) + p.out.Warn("Access.DelBypass: %s %s", rt0.Dst, err) } - p.out.Info("Point.DelBypass: route %s via %s", rt0.Dst, rt0.Gw) + p.out.Info("Access.DelBypass: route %s via %s", rt0.Dst, rt0.Gw) _, dst1, _ := net.ParseCIDR("128.0.0.0/1") rt1 := netlink.Route{ LinkIndex: p.link.Attrs().Index, @@ -274,11 +292,11 @@ func (p *Point) DelBypass(routes []*models.Route) { Gw: gw, Priority: rt.Metric, } - p.out.Debug("Point.DelBypass: %s", rt1) + p.out.Debug("Access.DelBypass: %s", rt1) if err := netlink.RouteDel(&rt1); err != nil { - p.out.Warn("Point.DelBypass: %s %s", rt1.Dst, err) + p.out.Warn("Access.DelBypass: %s %s", rt1.Dst, err) } - p.out.Info("Point.DelBypass: route %s via %s", rt1.Dst, rt1.Gw) + p.out.Info("Access.DelBypass: route %s via %s", rt1.Dst, rt1.Gw) } } @@ -300,10 +318,10 @@ func (p *Point) DelRoutes(routes []*models.Route) error { Priority: rt.Metric, } if err := netlink.RouteDel(&rte); err != nil { - p.out.Warn("Point.DelRoute: %s %s", rt.Prefix, err) + p.out.Warn("Access.DelRoute: %s %s", rt.Prefix, err) continue } - p.out.Info("Point.DelRoutes: route %s via %s", rt.Prefix, rt.NextHop) + p.out.Info("Access.DelRoutes: route %s via %s", rt.Prefix, rt.NextHop) } p.routes = nil return nil diff --git a/pkg/access/point_windows.go b/pkg/access/point_windows.go index 5663c90..1f7bc1b 100755 --- a/pkg/access/point_windows.go +++ b/pkg/access/point_windows.go @@ -1,10 +1,11 @@ package access import ( + "strings" + "github.com/luscis/openlan/pkg/config" "github.com/luscis/openlan/pkg/libol" "github.com/luscis/openlan/pkg/models" - "strings" ) type Point struct { @@ -39,11 +40,11 @@ func (p *Point) OnTap(w *TapWorker) error { if err := libol.UnmarshalLoad(&routes, ".routes.json"); err == nil { for _, route := range routes { _, _ = libol.IpRouteDel(p.IfName(), route.Prefix, route.NextHop) - p.out.Debug("Point.OnTap: clear %s via %s", route.Prefix, route.NextHop) + p.out.Debug("Access.OnTap: clear %s via %s", route.Prefix, route.NextHop) } } if out, err := libol.IpMetricSet(p.IfName(), "235"); err != nil { - p.out.Warn("Point.OnTap: metricSet %s: %s", err, out) + p.out.Warn("Access.OnTap: metricSet %s: %s", err, out) } return nil } @@ -64,10 +65,10 @@ func (p *Point) AddAddr(ipStr string) error { } out, err := libol.IpAddrAdd(p.IfName(), ipStr) if err != nil { - p.out.Warn("Point.AddAddr: %s, %s", err, p.Trim(out)) + p.out.Warn("Access.AddAddr: %s, %s", err, p.Trim(out)) return err } - p.out.Info("Point.AddAddr: %s", ipStr) + p.out.Info("Access.AddAddr: %s", ipStr) p.addr = ipStr return nil } @@ -76,10 +77,10 @@ func (p *Point) DelAddr(ipStr string) error { ipv4 := strings.Split(ipStr, "/")[0] out, err := libol.IpAddrDel(p.IfName(), ipv4) if err != nil { - p.out.Warn("Point.DelAddr: %s, %s", err, p.Trim(out)) + p.out.Warn("Access.DelAddr: %s, %s", err, p.Trim(out)) return err } - p.out.Info("Point.DelAddr: %s", ipv4) + p.out.Info("Access.DelAddr: %s", ipv4) p.addr = "" return nil } @@ -92,10 +93,10 @@ func (p *Point) AddRoutes(routes []*models.Route) error { for _, route := range routes { out, err := libol.IpRouteAdd(p.IfName(), route.Prefix, route.NextHop) if err != nil { - p.out.Warn("Point.AddRoutes: %s %s", route.Prefix, p.Trim(out)) + p.out.Warn("Access.AddRoutes: %s %s", route.Prefix, p.Trim(out)) continue } - p.out.Info("Point.AddRoutes: route %s via %s", route.Prefix, route.NextHop) + p.out.Info("Access.AddRoutes: route %s via %s", route.Prefix, route.NextHop) } p.routes = routes return nil @@ -105,10 +106,10 @@ func (p *Point) DelRoutes(routes []*models.Route) error { for _, route := range routes { out, err := libol.IpRouteDel(p.IfName(), route.Prefix, route.NextHop) if err != nil { - p.out.Warn("Point.DelRoutes: %s %s", route.Prefix, p.Trim(out)) + p.out.Warn("Access.DelRoutes: %s %s", route.Prefix, p.Trim(out)) continue } - p.out.Info("Point.DelRoutes: route %s via %s", route.Prefix, route.NextHop) + p.out.Info("Access.DelRoutes: route %s via %s", route.Prefix, route.NextHop) } p.routes = nil return nil diff --git a/pkg/access/pointer.go b/pkg/access/pointer.go index c29d524..bd32947 100755 --- a/pkg/access/pointer.go +++ b/pkg/access/pointer.go @@ -1,12 +1,13 @@ package access import ( + "runtime" + "github.com/luscis/openlan/pkg/access/http" "github.com/luscis/openlan/pkg/config" "github.com/luscis/openlan/pkg/libol" "github.com/luscis/openlan/pkg/models" "github.com/luscis/openlan/pkg/network" - "runtime" ) type Pointer interface { @@ -44,7 +45,7 @@ func NewMixPoint(config *config.Point) MixPoint { } func (p *MixPoint) Initialize() { - libol.Info("MixPoint.Initialize") + libol.Info("MixAccess.Initialize") p.worker.SetUUID(p.UUID()) p.worker.Initialize() if p.config.Http != nil { @@ -53,7 +54,7 @@ func (p *MixPoint) Initialize() { } func (p *MixPoint) Start() { - p.out.Info("MixPoint.Start %s", runtime.GOOS) + p.out.Info("MixAccess.Start %s", runtime.GOOS) if p.config.PProf != "" { f := libol.PProf{Listen: p.config.PProf} f.Start() @@ -62,7 +63,7 @@ func (p *MixPoint) Start() { } func (p *MixPoint) Stop() { - defer libol.Catch("MixPoint.Stop") + defer libol.Catch("MixAccess.Stop") if p.http != nil { p.http.Shutdown() } diff --git a/pkg/access/worker.go b/pkg/access/worker.go index 0a62485..be13775 100755 --- a/pkg/access/worker.go +++ b/pkg/access/worker.go @@ -72,6 +72,7 @@ type WorkerListener struct { OnTap func(w *TapWorker) error AddRoutes func(routes []*models.Route) error DelRoutes func(routes []*models.Route) error + Forward func(prefix, nexthop string) } type PrefixRule struct { @@ -404,6 +405,14 @@ func (w *Worker) SetUUID(v string) { w.uuid = v } -func (w *Worker) OnDNS(name string, addr net.IP) { - w.out.Info("Worker.OnDSN %s -> %s\n", name, addr.String()) +func (w *Worker) OnDNS(domain string, addr net.IP) { + name := strings.TrimRight(domain, ".") + w.out.Debug("Worker.OnDNS %s -> %s\n", name, addr.String()) + via := w.cfg.Backends.FindBackend(name) + if via != nil { + w.out.Debug("Worker.OnDNS %s via %s", name, via.Server) + if w.listener.Forward != nil { + w.listener.Forward(addr.String()+"/32", via.Server) + } + } } diff --git a/pkg/config/point.go b/pkg/config/point.go index 6b53155..e4d7895 100755 --- a/pkg/config/point.go +++ b/pkg/config/point.go @@ -19,27 +19,28 @@ type Interface struct { } type Point struct { - File string `json:"file,omitempty"` - Alias string `json:"alias,omitempty"` - Connection string `json:"connection"` - Timeout int `json:"timeout,omitempty"` - Username string `json:"username,omitempty"` - Network string `json:"network,omitempty"` - Password string `json:"password,omitempty"` - Protocol string `json:"protocol,omitempty"` - Interface Interface `json:"interface,omitempty"` - Log Log `json:"log,omitempty"` - Http *Http `json:"http,omitempty"` - Crypt *Crypt `json:"crypt,omitempty"` - PProf string `json:"pprof,omitempty"` - RequestAddr bool `json:"requestAddr"` - ByPass bool `json:"bypass,omitempty"` - SaveFile string `json:"-"` - Queue *Queue `json:"queue,omitempty"` - Terminal string `json:"-"` - Cert *Cert `json:"cert,omitempty"` - StatusFile string `json:"status,omitempty"` - PidFile string `json:"pid,omitempty"` + File string `json:"file,omitempty"` + Alias string `json:"alias,omitempty"` + Connection string `json:"connection"` + Timeout int `json:"timeout,omitempty"` + Username string `json:"username,omitempty"` + Network string `json:"network,omitempty"` + Password string `json:"password,omitempty"` + Protocol string `json:"protocol,omitempty"` + Interface Interface `json:"interface,omitempty"` + Log Log `json:"log,omitempty"` + Http *Http `json:"http,omitempty"` + Crypt *Crypt `json:"crypt,omitempty"` + PProf string `json:"pprof,omitempty"` + RequestAddr bool `json:"requestAddr"` + ByPass bool `json:"bypass,omitempty"` + SaveFile string `json:"-"` + Queue *Queue `json:"queue,omitempty"` + Terminal string `json:"-"` + Cert *Cert `json:"cert,omitempty"` + StatusFile string `json:"status,omitempty"` + PidFile string `json:"pid,omitempty"` + Backends HttpBackends `json:"backends,omitempty" yaml:"backends,omitempty"` } func (i *Interface) Correct() {