add vtun listener and handler
This commit is contained in:
@@ -27,7 +27,7 @@ type tunListener struct {
|
||||
addr net.Addr
|
||||
cqueue chan net.Conn
|
||||
closed chan struct{}
|
||||
logger logger.Logger
|
||||
log logger.Logger
|
||||
md metadata
|
||||
options listener.Options
|
||||
routes []*router.Route
|
||||
@@ -39,7 +39,7 @@ func NewListener(opts ...listener.Option) listener.Listener {
|
||||
opt(&options)
|
||||
}
|
||||
return &tunListener{
|
||||
logger: options.Logger,
|
||||
log: options.Logger,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ func (l *tunListener) listenLoop() {
|
||||
}
|
||||
|
||||
addrs, _ := itf.Addrs()
|
||||
l.logger.Infof("name: %s, net: %s, mtu: %d, addrs: %s",
|
||||
l.log.Infof("name: %s, net: %s, mtu: %d, addrs: %s",
|
||||
itf.Name, ip, itf.MTU, addrs)
|
||||
|
||||
var c net.Conn
|
||||
@@ -112,7 +112,7 @@ func (l *tunListener) listenLoop() {
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
l.logger.Error(err)
|
||||
l.log.Error(err)
|
||||
cancel()
|
||||
}
|
||||
|
||||
|
||||
+43
-35
@@ -7,53 +7,51 @@ import (
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
|
||||
const (
|
||||
tunOffsetBytes = 16
|
||||
MaxMessageSize = math.MaxUint16
|
||||
)
|
||||
|
||||
type tunDevice struct {
|
||||
dev tun.Device
|
||||
elems [][MaxMessageSize]byte
|
||||
rbufs [][]byte
|
||||
wbuf [tunOffsetBytes + MaxMessageSize]byte
|
||||
dev tun.Device
|
||||
packets int
|
||||
sizes []int
|
||||
rbufs [][]byte
|
||||
wbufs [][]byte
|
||||
wbuf []byte
|
||||
}
|
||||
|
||||
func (d *tunDevice) Read(p []byte) (n int, err error) {
|
||||
if len(d.rbufs) > 0 {
|
||||
n = copy(p, d.rbufs[0])
|
||||
d.rbufs = d.rbufs[1:]
|
||||
return
|
||||
}
|
||||
if d.packets > 0 {
|
||||
for i, size := range d.sizes {
|
||||
if size > 0 {
|
||||
n = copy(p, d.rbufs[i][:size])
|
||||
|
||||
sizes := make([]int, len(d.elems))
|
||||
bufs := make([][]byte, len(d.elems))
|
||||
for i := range d.elems {
|
||||
bufs[i] = d.elems[i][:]
|
||||
}
|
||||
|
||||
nn, err := d.dev.Read(bufs, sizes, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < nn; i++ {
|
||||
if sizes[i] <= 0 {
|
||||
continue
|
||||
d.sizes[i] = 0
|
||||
d.packets--
|
||||
return
|
||||
}
|
||||
}
|
||||
d.rbufs = append(d.rbufs, bufs[i][:sizes[i]])
|
||||
}
|
||||
|
||||
n = copy(p, d.rbufs[0])
|
||||
d.rbufs = d.rbufs[1:]
|
||||
d.rbufs[0] = p
|
||||
packets, err := d.dev.Read(d.rbufs, d.sizes, readOffset)
|
||||
if err != nil && err != tun.ErrTooManySegments {
|
||||
return
|
||||
}
|
||||
n = d.sizes[0]
|
||||
|
||||
d.sizes[0] = 0
|
||||
d.packets = packets - 1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (d *tunDevice) Write(p []byte) (n int, err error) {
|
||||
buf := d.wbuf[:]
|
||||
n = copy(buf[tunOffsetBytes:], p)
|
||||
_, err = d.dev.Write([][]byte{buf[:tunOffsetBytes+n]}, tunOffsetBytes)
|
||||
if writeOffset > 0 {
|
||||
copy(d.wbuf[writeOffset:], p)
|
||||
d.wbufs[0] = d.wbuf[:writeOffset+len(p)]
|
||||
} else {
|
||||
d.wbufs[0] = p
|
||||
}
|
||||
|
||||
_, err = d.dev.Write(d.wbufs, writeOffset)
|
||||
n = len(p)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -67,9 +65,19 @@ func (l *tunListener) createTunDevice() (dev io.ReadWriteCloser, name string, er
|
||||
return
|
||||
}
|
||||
|
||||
batchSize := 16
|
||||
|
||||
rbufs := make([][]byte, batchSize)
|
||||
for i := 1; i < len(rbufs); i++ {
|
||||
rbufs[i] = make([]byte, math.MaxUint16)
|
||||
}
|
||||
|
||||
dev = &tunDevice{
|
||||
dev: ifce,
|
||||
elems: make([][MaxMessageSize]byte, ifce.BatchSize()),
|
||||
sizes: make([]int, batchSize),
|
||||
rbufs: rbufs,
|
||||
wbufs: make([][]byte, 1),
|
||||
wbuf: make([]byte, math.MaxUint16+writeOffset),
|
||||
}
|
||||
name, err = ifce.Name()
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
|
||||
const (
|
||||
defaultTunName = "utun"
|
||||
readOffset = 4
|
||||
writeOffset = 4
|
||||
)
|
||||
|
||||
func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.IP, err error) {
|
||||
|
||||
@@ -10,6 +10,11 @@ import (
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
const (
|
||||
readOffset = 0
|
||||
writeOffset = 16
|
||||
)
|
||||
|
||||
func (l *tunListener) createTun() (dev io.ReadWriteCloser, name string, ip net.IP, err error) {
|
||||
dev, name, err = l.createTunDevice()
|
||||
if err != nil {
|
||||
@@ -30,7 +35,7 @@ func (l *tunListener) createTun() (dev io.ReadWriteCloser, name string, ip net.I
|
||||
if err = netlink.AddrAdd(link, &netlink.Addr{
|
||||
IPNet: &net,
|
||||
}); err != nil {
|
||||
l.logger.Error(err)
|
||||
l.log.Error(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -52,7 +57,7 @@ func (l *tunListener) createTun() (dev io.ReadWriteCloser, name string, ip net.I
|
||||
}
|
||||
if len(dnsServers) > 0 {
|
||||
cmd := fmt.Sprintf("resolvectl dns %s %s", name, strings.Join(dnsServers, " "))
|
||||
l.logger.Debug(cmd)
|
||||
l.log.Debug(cmd)
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
const (
|
||||
defaultTunName = "tun0"
|
||||
readOffset = 4
|
||||
writeOffset = 4
|
||||
)
|
||||
|
||||
func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.IP, err error) {
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
|
||||
const (
|
||||
defaultTunName = "wintun"
|
||||
readOffset = 0
|
||||
writeOffset = 0
|
||||
)
|
||||
|
||||
func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.IP, err error) {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type conn struct {
|
||||
ifce io.ReadWriteCloser
|
||||
laddr net.Addr
|
||||
raddr net.Addr
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (c *conn) Read(b []byte) (n int, err error) {
|
||||
return c.ifce.Read(b)
|
||||
}
|
||||
|
||||
func (c *conn) Write(b []byte) (n int, err error) {
|
||||
return c.ifce.Write(b)
|
||||
}
|
||||
|
||||
func (c *conn) LocalAddr() net.Addr {
|
||||
return c.laddr
|
||||
}
|
||||
|
||||
func (c *conn) RemoteAddr() net.Addr {
|
||||
return c.raddr
|
||||
}
|
||||
|
||||
func (c *conn) SetDeadline(t time.Time) error {
|
||||
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||
}
|
||||
|
||||
func (c *conn) SetReadDeadline(t time.Time) error {
|
||||
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||
}
|
||||
|
||||
func (c *conn) SetWriteDeadline(t time.Time) error {
|
||||
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||
}
|
||||
|
||||
func (c *conn) Close() (err error) {
|
||||
if c.cancel != nil {
|
||||
c.cancel()
|
||||
}
|
||||
return c.ifce.Close()
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/go-gost/core/limiter"
|
||||
"github.com/go-gost/core/listener"
|
||||
"github.com/go-gost/core/logger"
|
||||
mdata "github.com/go-gost/core/metadata"
|
||||
"github.com/go-gost/core/router"
|
||||
traffic_limiter "github.com/go-gost/x/limiter/traffic"
|
||||
limiter_wrapper "github.com/go-gost/x/limiter/traffic/wrapper"
|
||||
metrics "github.com/go-gost/x/metrics/wrapper"
|
||||
stats "github.com/go-gost/x/observer/stats/wrapper"
|
||||
"github.com/go-gost/x/registry"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registry.ListenerRegistry().Register("vtun", NewListener)
|
||||
}
|
||||
|
||||
type tunListener struct {
|
||||
addr net.Addr
|
||||
cqueue chan net.Conn
|
||||
closed chan struct{}
|
||||
log logger.Logger
|
||||
md metadata
|
||||
options listener.Options
|
||||
routes []*router.Route
|
||||
}
|
||||
|
||||
func NewListener(opts ...listener.Option) listener.Listener {
|
||||
options := listener.Options{}
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
return &tunListener{
|
||||
log: options.Logger,
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *tunListener) Init(md mdata.Metadata) (err error) {
|
||||
if err = l.parseMetadata(md); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
l.addr = &Addr{Name: l.options.Addr}
|
||||
|
||||
l.cqueue = make(chan net.Conn)
|
||||
l.closed = make(chan struct{})
|
||||
|
||||
go l.listenLoop()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (l *tunListener) listenLoop() {
|
||||
for {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
err := func() error {
|
||||
ifce, name, ip, err := l.createTun()
|
||||
if err != nil {
|
||||
if ifce != nil {
|
||||
ifce.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
itf, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addrs, _ := itf.Addrs()
|
||||
l.log.Infof("name: %s, net: %s, mtu: %d, addrs: %s",
|
||||
itf.Name, ip, itf.MTU, addrs)
|
||||
|
||||
var c net.Conn
|
||||
c = &conn{
|
||||
ifce: ifce,
|
||||
laddr: l.addr,
|
||||
raddr: &net.IPAddr{IP: ip},
|
||||
cancel: cancel,
|
||||
}
|
||||
c = metrics.WrapConn(l.options.Service, c)
|
||||
c = stats.WrapConn(c, l.options.Stats)
|
||||
c = limiter_wrapper.WrapConn(
|
||||
c,
|
||||
l.options.TrafficLimiter,
|
||||
traffic_limiter.ServiceLimitKey,
|
||||
limiter.ScopeOption(limiter.ScopeService),
|
||||
limiter.ServiceOption(l.options.Service),
|
||||
limiter.NetworkOption(c.LocalAddr().Network()),
|
||||
)
|
||||
l.cqueue <- c
|
||||
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
l.log.Error(err)
|
||||
cancel()
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-l.closed:
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *tunListener) Accept() (net.Conn, error) {
|
||||
select {
|
||||
case conn := <-l.cqueue:
|
||||
return conn, nil
|
||||
case <-l.closed:
|
||||
}
|
||||
|
||||
return nil, listener.ErrClosed
|
||||
}
|
||||
|
||||
func (l *tunListener) Addr() net.Addr {
|
||||
return l.addr
|
||||
}
|
||||
|
||||
func (l *tunListener) Close() error {
|
||||
select {
|
||||
case <-l.closed:
|
||||
return net.ErrClosed
|
||||
default:
|
||||
close(l.closed)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Addr struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (a *Addr) Network() string {
|
||||
return "tun"
|
||||
}
|
||||
|
||||
func (a *Addr) String() string {
|
||||
return a.Name
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
mdata "github.com/go-gost/core/metadata"
|
||||
"github.com/go-gost/core/router"
|
||||
tun_util "github.com/go-gost/x/internal/util/tun"
|
||||
mdutil "github.com/go-gost/x/metadata/util"
|
||||
xrouter "github.com/go-gost/x/router"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMTU = 1420
|
||||
)
|
||||
|
||||
type metadata struct {
|
||||
config *tun_util.Config
|
||||
}
|
||||
|
||||
func (l *tunListener) parseMetadata(md mdata.Metadata) (err error) {
|
||||
config := &tun_util.Config{
|
||||
Name: mdutil.GetString(md, "name", "tun.name"),
|
||||
Peer: mdutil.GetString(md, "peer", "tun.peer"),
|
||||
MTU: mdutil.GetInt(md, "mtu", "tun.mtu"),
|
||||
}
|
||||
if config.MTU <= 0 {
|
||||
config.MTU = defaultMTU
|
||||
}
|
||||
if gw := mdutil.GetString(md, "gw", "tun.gw"); gw != "" {
|
||||
config.Gateway = net.ParseIP(gw)
|
||||
}
|
||||
|
||||
for _, s := range strings.Split(mdutil.GetString(md, "net", "tun.net"), ",") {
|
||||
if s = strings.TrimSpace(s); s == "" {
|
||||
continue
|
||||
}
|
||||
ip, ipNet, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
config.Net = append(config.Net, net.IPNet{
|
||||
IP: ip,
|
||||
Mask: ipNet.Mask,
|
||||
})
|
||||
}
|
||||
|
||||
for _, s := range strings.Split(mdutil.GetString(md, "route", "tun.route"), ",") {
|
||||
gw := ""
|
||||
if config.Gateway != nil {
|
||||
gw = config.Gateway.String()
|
||||
}
|
||||
if route := xrouter.ParseRoute(strings.TrimSpace(s), gw); route != nil {
|
||||
l.routes = append(l.routes, route)
|
||||
}
|
||||
}
|
||||
|
||||
for _, s := range mdutil.GetStrings(md, "routes", "tun.routes") {
|
||||
ss := strings.SplitN(s, " ", 2)
|
||||
if len(ss) == 2 {
|
||||
_, ipNet, _ := net.ParseCIDR(strings.TrimSpace(ss[0]))
|
||||
if ipNet == nil {
|
||||
continue
|
||||
}
|
||||
gw := net.ParseIP(ss[1])
|
||||
if gw == nil {
|
||||
gw = config.Gateway
|
||||
}
|
||||
|
||||
gateway := ""
|
||||
if gw != nil {
|
||||
gateway = gw.String()
|
||||
}
|
||||
|
||||
l.routes = append(l.routes, &router.Route{
|
||||
Net: ipNet,
|
||||
Dst: ipNet.String(),
|
||||
Gateway: gateway,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range strings.Split(mdutil.GetString(md, "dns", "tun.dns"), ",") {
|
||||
if ip := net.ParseIP(strings.TrimSpace(v)); ip != nil {
|
||||
config.DNS = append(config.DNS, ip)
|
||||
}
|
||||
}
|
||||
|
||||
l.md.config = config
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"github.com/go-gost/core/logger"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
|
||||
type tunDevice struct {
|
||||
dev tun.Device
|
||||
|
||||
packets int
|
||||
sizes []int
|
||||
rbufs [][]byte
|
||||
wbufs [][]byte
|
||||
wbuf []byte
|
||||
|
||||
log logger.Logger
|
||||
}
|
||||
|
||||
func (d *tunDevice) Read(p []byte) (n int, err error) {
|
||||
if d.packets > 0 {
|
||||
for i, size := range d.sizes {
|
||||
if size > 0 {
|
||||
n = copy(p, d.rbufs[i][:size])
|
||||
|
||||
d.sizes[i] = 0
|
||||
d.packets--
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d.rbufs[0] = p
|
||||
packets, err := d.dev.Read(d.rbufs, d.sizes, readOffset)
|
||||
if err != nil && err != tun.ErrTooManySegments {
|
||||
return
|
||||
}
|
||||
n = d.sizes[0]
|
||||
|
||||
d.sizes[0] = 0
|
||||
d.packets = packets - 1
|
||||
|
||||
// d.log.Debugf("read tun: (%d), % x", n, p[:n])
|
||||
return
|
||||
}
|
||||
|
||||
func (d *tunDevice) Write(p []byte) (n int, err error) {
|
||||
if writeOffset > 0 {
|
||||
copy(d.wbuf[writeOffset:], p)
|
||||
d.wbufs[0] = d.wbuf[:writeOffset+len(p)]
|
||||
} else {
|
||||
d.wbufs[0] = p
|
||||
}
|
||||
|
||||
_, err = d.dev.Write(d.wbufs, writeOffset)
|
||||
n = len(p)
|
||||
return
|
||||
}
|
||||
|
||||
func (d *tunDevice) Close() error {
|
||||
return d.dev.Close()
|
||||
}
|
||||
|
||||
func (l *tunListener) createTunDevice() (dev io.ReadWriteCloser, name string, err error) {
|
||||
ifce, err := tun.CreateTUN(l.md.config.Name, l.md.config.MTU)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
batchSize := 16
|
||||
|
||||
rbufs := make([][]byte, batchSize)
|
||||
for i := 1; i < len(rbufs); i++ {
|
||||
rbufs[i] = make([]byte, math.MaxUint16)
|
||||
}
|
||||
|
||||
dev = &tunDevice{
|
||||
dev: ifce,
|
||||
sizes: make([]int, batchSize),
|
||||
rbufs: rbufs,
|
||||
wbufs: make([][]byte, 1),
|
||||
wbuf: make([]byte, math.MaxUint16+writeOffset),
|
||||
log: l.log,
|
||||
}
|
||||
name, err = ifce.Name()
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTunName = "utun"
|
||||
readOffset = 4
|
||||
writeOffset = 4
|
||||
)
|
||||
|
||||
func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.IP, err error) {
|
||||
if l.md.config.Name == "" {
|
||||
l.md.config.Name = defaultTunName
|
||||
}
|
||||
ifce, name, err = l.createTunDevice()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
peer := l.md.config.Peer
|
||||
if peer == "" {
|
||||
peer = ip.String()
|
||||
}
|
||||
if len(l.md.config.Net) > 0 {
|
||||
cmd := fmt.Sprintf("ifconfig %s inet %s %s mtu %d up",
|
||||
name, l.md.config.Net[0].String(), l.md.config.Peer, l.md.config.MTU)
|
||||
l.logger.Debug(cmd)
|
||||
args := strings.Split(cmd, " ")
|
||||
if err = exec.Command(args[0], args[1:]...).Run(); err != nil {
|
||||
return
|
||||
}
|
||||
ip = l.md.config.Net[0].IP
|
||||
}
|
||||
|
||||
if err = l.addRoutes(name); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (l *tunListener) addRoutes(ifName string) error {
|
||||
for _, route := range l.routes {
|
||||
cmd := fmt.Sprintf("route add -net %s -interface %s", route.Net.String(), ifName)
|
||||
l.logger.Debug(cmd)
|
||||
args := strings.Split(cmd, " ")
|
||||
if err := exec.Command(args[0], args[1:]...).Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
const (
|
||||
readOffset = 0
|
||||
writeOffset = 16
|
||||
)
|
||||
|
||||
func (l *tunListener) createTun() (dev io.ReadWriteCloser, name string, ip net.IP, err error) {
|
||||
dev, name, err = l.createTunDevice()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ifce, err := net.InterfaceByName(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
link, err := netlink.LinkByName(name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, net := range l.md.config.Net {
|
||||
if err = netlink.AddrAdd(link, &netlink.Addr{
|
||||
IPNet: &net,
|
||||
}); err != nil {
|
||||
l.log.Error(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(l.md.config.Net) > 0 {
|
||||
ip = l.md.config.Net[0].IP
|
||||
}
|
||||
|
||||
if err = netlink.LinkSetUp(link); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = l.addRoutes(ifce); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var dnsServers []string
|
||||
for _, dns := range l.md.config.DNS {
|
||||
dnsServers = append(dnsServers, dns.String())
|
||||
}
|
||||
if len(dnsServers) > 0 {
|
||||
cmd := fmt.Sprintf("resolvectl dns %s %s", name, strings.Join(dnsServers, " "))
|
||||
l.log.Debug(cmd)
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (l *tunListener) addRoutes(ifce *net.Interface) error {
|
||||
for _, route := range l.routes {
|
||||
if route.Net == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
r := netlink.Route{
|
||||
Dst: route.Net,
|
||||
Gw: net.ParseIP(route.Gateway),
|
||||
}
|
||||
if r.Gw == nil {
|
||||
r.LinkIndex = ifce.Index
|
||||
}
|
||||
if err := netlink.RouteReplace(&r); err != nil {
|
||||
return fmt.Errorf("add route %v %v: %v", r.Dst, r.Gw, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//go:build !linux && !windows && !darwin
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTunName = "tun0"
|
||||
readOffset = 4
|
||||
writeOffset = 4
|
||||
)
|
||||
|
||||
func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.IP, err error) {
|
||||
if l.md.config.Name == "" {
|
||||
l.md.config.Name = defaultTunName
|
||||
}
|
||||
ifce, name, err = l.createTunDevice()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(l.md.config.Net) > 0 {
|
||||
cmd := fmt.Sprintf("ifconfig %s inet %s mtu %d up",
|
||||
name, l.md.config.Net[0].String(), l.md.config.MTU)
|
||||
l.logger.Debug(cmd)
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
ip = l.md.config.Net[0].IP
|
||||
}
|
||||
|
||||
if err = l.addRoutes(name); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (l *tunListener) addRoutes(ifName string) error {
|
||||
for _, route := range l.routes {
|
||||
cmd := fmt.Sprintf("route add -net %s -interface %s", route.Net.String(), ifName)
|
||||
l.logger.Debug(cmd)
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
return fmt.Errorf("%s: %v", cmd, er)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package tun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTunName = "wintun"
|
||||
readOffset = 0
|
||||
writeOffset = 0
|
||||
)
|
||||
|
||||
func (l *tunListener) createTun() (ifce io.ReadWriteCloser, name string, ip net.IP, err error) {
|
||||
if l.md.config.Name == "" {
|
||||
l.md.config.Name = defaultTunName
|
||||
}
|
||||
ifce, name, err = l.createTunDevice()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(l.md.config.Net) > 0 {
|
||||
ipNet := l.md.config.Net[0]
|
||||
cmd := fmt.Sprintf("netsh interface ip set address name=%s "+
|
||||
"source=static addr=%s mask=%s gateway=none",
|
||||
name, ipNet.IP.String(), ipMask(ipNet.Mask))
|
||||
l.logger.Debug(cmd)
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
ip = ipNet.IP
|
||||
}
|
||||
|
||||
if err = l.addRoutes(name, l.md.config.Gateway); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, dns := range l.md.config.DNS {
|
||||
cmd := fmt.Sprintf("netsh interface ip add dnsservers name=%s address=%s validate=no", name, dns.String())
|
||||
l.logger.Debug(cmd)
|
||||
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
err = fmt.Errorf("%s: %v", cmd, er)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (l *tunListener) addRoutes(ifName string, gw net.IP) error {
|
||||
for _, route := range l.routes {
|
||||
l.deleteRoute(ifName, route.Net.String())
|
||||
|
||||
cmd := fmt.Sprintf("netsh interface ip add route prefix=%s interface=%s store=active",
|
||||
route.Net.String(), ifName)
|
||||
if gw != nil {
|
||||
cmd += " nexthop=" + gw.String()
|
||||
}
|
||||
l.logger.Debug(cmd)
|
||||
args := strings.Split(cmd, " ")
|
||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||
return fmt.Errorf("%s: %v", cmd, er)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *tunListener) deleteRoute(ifName string, route string) error {
|
||||
cmd := fmt.Sprintf("netsh interface ip delete route prefix=%s interface=%s store=active",
|
||||
route, ifName)
|
||||
l.logger.Debug(cmd)
|
||||
args := strings.Split(cmd, " ")
|
||||
return exec.Command(args[0], args[1:]...).Run()
|
||||
}
|
||||
|
||||
func ipMask(mask net.IPMask) string {
|
||||
return fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3])
|
||||
}
|
||||
Reference in New Issue
Block a user