add support for tap device
This commit is contained in:
parent
355847faa4
commit
bde4217ca9
@ -396,6 +396,8 @@ func (r *route) GenRouters() ([]router, error) {
|
|||||||
ln, err = gost.ObfsHTTPListener(node.Addr)
|
ln, err = gost.ObfsHTTPListener(node.Addr)
|
||||||
case "tun":
|
case "tun":
|
||||||
ln, err = gost.TunListener(node.Addr)
|
ln, err = gost.TunListener(node.Addr)
|
||||||
|
case "tap":
|
||||||
|
ln, err = gost.TapListener(node.Addr)
|
||||||
default:
|
default:
|
||||||
ln, err = gost.TCPListener(node.Addr)
|
ln, err = gost.TCPListener(node.Addr)
|
||||||
}
|
}
|
||||||
@ -441,6 +443,14 @@ func (r *route) GenRouters() ([]router, error) {
|
|||||||
Routes: strings.Split(node.Get("route"), ","),
|
Routes: strings.Split(node.Get("route"), ","),
|
||||||
}
|
}
|
||||||
handler = gost.TunHandler(node.Remote, gost.TunConfigHandlerOption(cfg))
|
handler = gost.TunHandler(node.Remote, gost.TunConfigHandlerOption(cfg))
|
||||||
|
case "tap":
|
||||||
|
cfg := gost.TapConfig{
|
||||||
|
Name: node.Get("name"),
|
||||||
|
Addr: node.Get("net"),
|
||||||
|
MTU: node.GetInt("mtu"),
|
||||||
|
Routes: strings.Split(node.Get("route"), ","),
|
||||||
|
}
|
||||||
|
handler = gost.TapHandler(node.Remote, gost.TapConfigHandlerOption(cfg))
|
||||||
default:
|
default:
|
||||||
// start from 2.5, if remote is not empty, then we assume that it is a forward tunnel.
|
// start from 2.5, if remote is not empty, then we assume that it is a forward tunnel.
|
||||||
if node.Remote != "" {
|
if node.Remote != "" {
|
||||||
|
@ -41,6 +41,7 @@ type HandlerOptions struct {
|
|||||||
Host string
|
Host string
|
||||||
IPs []string
|
IPs []string
|
||||||
TunConfig TunConfig
|
TunConfig TunConfig
|
||||||
|
TapConfig TapConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandlerOption allows a common way to set handler options.
|
// HandlerOption allows a common way to set handler options.
|
||||||
@ -203,6 +204,13 @@ func TunConfigHandlerOption(cfg TunConfig) HandlerOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TapConfigHandlerOption sets the config for tap device.
|
||||||
|
func TapConfigHandlerOption(cfg TapConfig) HandlerOption {
|
||||||
|
return func(opts *HandlerOptions) {
|
||||||
|
opts.TapConfig = cfg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type autoHandler struct {
|
type autoHandler struct {
|
||||||
options *HandlerOptions
|
options *HandlerOptions
|
||||||
}
|
}
|
||||||
|
4
node.go
4
node.go
@ -82,7 +82,7 @@ func ParseNode(s string) (node Node, err error) {
|
|||||||
case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding
|
case "tcp", "udp": // started from v2.1, tcp and udp are for local port forwarding
|
||||||
case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding
|
case "rtcp", "rudp": // rtcp and rudp are for remote port forwarding
|
||||||
case "ohttp": // obfs-http
|
case "ohttp": // obfs-http
|
||||||
case "tun": //tun device
|
case "tun", "tap": // tun/tap device
|
||||||
default:
|
default:
|
||||||
node.Transport = "tcp"
|
node.Transport = "tcp"
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ func ParseNode(s string) (node Node, err error) {
|
|||||||
case "tcp", "udp", "rtcp", "rudp": // port forwarding
|
case "tcp", "udp", "rtcp", "rudp": // port forwarding
|
||||||
case "direct", "remote", "forward": // forwarding
|
case "direct", "remote", "forward": // forwarding
|
||||||
case "redirect": // TCP transparent proxy
|
case "redirect": // TCP transparent proxy
|
||||||
case "tun": // tun device
|
case "tun", "tap": // tun/tap device
|
||||||
default:
|
default:
|
||||||
node.Protocol = ""
|
node.Protocol = ""
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/go-log/log"
|
"github.com/go-log/log"
|
||||||
"github.com/shadowsocks/go-shadowsocks2/core"
|
"github.com/shadowsocks/go-shadowsocks2/core"
|
||||||
"github.com/songgao/water"
|
"github.com/songgao/water"
|
||||||
|
"github.com/songgao/water/waterutil"
|
||||||
"golang.org/x/net/ipv4"
|
"golang.org/x/net/ipv4"
|
||||||
"golang.org/x/net/ipv6"
|
"golang.org/x/net/ipv6"
|
||||||
)
|
)
|
||||||
@ -227,43 +228,6 @@ func (h *tunHandler) transportTun(tun net.Conn, conn net.PacketConn, raddr net.A
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
type tunConn struct {
|
|
||||||
ifce *water.Interface
|
|
||||||
addr net.Addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tunConn) Read(b []byte) (n int, err error) {
|
|
||||||
return c.ifce.Read(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tunConn) Write(b []byte) (n int, err error) {
|
|
||||||
return c.ifce.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tunConn) Close() (err error) {
|
|
||||||
return c.ifce.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tunConn) LocalAddr() net.Addr {
|
|
||||||
return c.addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tunConn) RemoteAddr() net.Addr {
|
|
||||||
return &net.IPAddr{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tunConn) SetDeadline(t time.Time) error {
|
|
||||||
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tunConn) SetReadDeadline(t time.Time) error {
|
|
||||||
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *tunConn) SetWriteDeadline(t time.Time) error {
|
|
||||||
return &net.OpError{Op: "set", Net: "tun", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
|
||||||
}
|
|
||||||
|
|
||||||
type tunListener struct {
|
type tunListener struct {
|
||||||
addr net.Addr
|
addr net.Addr
|
||||||
conns chan net.Conn
|
conns chan net.Conn
|
||||||
@ -318,3 +282,272 @@ func (l *tunListener) Close() error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TapConfig struct {
|
||||||
|
Name string
|
||||||
|
Addr string
|
||||||
|
MTU int
|
||||||
|
Routes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type tapHandler struct {
|
||||||
|
raddr string
|
||||||
|
options *HandlerOptions
|
||||||
|
ipNet *net.IPNet
|
||||||
|
routes sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
// TapHandler creates a handler for tap tunnel.
|
||||||
|
func TapHandler(raddr string, opts ...HandlerOption) Handler {
|
||||||
|
h := &tapHandler{
|
||||||
|
raddr: raddr,
|
||||||
|
options: &HandlerOptions{},
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(h.options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tapHandler) Init(options ...HandlerOption) {
|
||||||
|
if h.options == nil {
|
||||||
|
h.options = &HandlerOptions{}
|
||||||
|
}
|
||||||
|
for _, opt := range options {
|
||||||
|
opt(h.options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tapHandler) Handle(conn net.Conn) {
|
||||||
|
defer os.Exit(0)
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
uc, ok := conn.(net.PacketConn)
|
||||||
|
if !ok {
|
||||||
|
log.Log("[tap] wrong connection type, must be PacketConn")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tc, err := h.createTap()
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[tap] %s create tap: %v", conn.LocalAddr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer tc.Close()
|
||||||
|
|
||||||
|
log.Logf("[tap] %s - %s: tap creation successful", tc.LocalAddr(), conn.LocalAddr())
|
||||||
|
|
||||||
|
var raddr net.Addr
|
||||||
|
if h.raddr != "" {
|
||||||
|
raddr, err = net.ResolveUDPAddr("udp", h.raddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[tap] %s - %s remote addr: %v", tc.LocalAddr(), conn.LocalAddr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(h.options.Users) > 0 && h.options.Users[0] != nil {
|
||||||
|
passwd, _ := h.options.Users[0].Password()
|
||||||
|
cipher, err := core.PickCipher(h.options.Users[0].Username(), nil, passwd)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[tap] %s - %s cipher: %v", tc.LocalAddr(), conn.LocalAddr(), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uc = cipher.PacketConn(uc)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.transportTap(tc, uc, raddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tapHandler) createTap() (conn net.Conn, err error) {
|
||||||
|
conn, h.ipNet, err = createTap(h.options.TapConfig)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *tapHandler) transportTap(tap net.Conn, conn net.PacketConn, raddr net.Addr) error {
|
||||||
|
errc := make(chan error, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
err := func() error {
|
||||||
|
b := sPool.Get().([]byte)
|
||||||
|
defer sPool.Put(b)
|
||||||
|
|
||||||
|
n, err := tap.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
macSrc := waterutil.MACSource(b[:n])
|
||||||
|
macDst := waterutil.MACDestination(b[:n])
|
||||||
|
|
||||||
|
addr := raddr
|
||||||
|
if v, ok := h.routes.Load(macDst.String()); ok {
|
||||||
|
addr = v.(net.Addr)
|
||||||
|
}
|
||||||
|
if addr == nil {
|
||||||
|
log.Logf("[tap] %s: no route for %s -> %s %d %d",
|
||||||
|
tap.LocalAddr(), macSrc, macDst, n, waterutil.MACEthertype(b[:n]))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
log.Logf("[tap] %s >>> %s: %s -> %s %d %d",
|
||||||
|
tap.LocalAddr(), addr, macSrc, macDst, n, waterutil.MACEthertype(b[:n]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := conn.WriteTo(b[:n], addr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errc <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
err := func() error {
|
||||||
|
b := sPool.Get().([]byte)
|
||||||
|
defer mPool.Put(b)
|
||||||
|
|
||||||
|
n, addr, err := conn.ReadFrom(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
macSrc := waterutil.MACSource(b[:n])
|
||||||
|
macDst := waterutil.MACDestination(b[:n])
|
||||||
|
|
||||||
|
if Debug {
|
||||||
|
log.Logf("[tap] %s <<< %s: %s -> %s %d %d",
|
||||||
|
tap.LocalAddr(), addr, macSrc, macDst, n, waterutil.MACEthertype(b[:n]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if actual, loaded := h.routes.LoadOrStore(macSrc.String(), addr); loaded {
|
||||||
|
if actual.(net.Addr).String() != addr.String() {
|
||||||
|
log.Logf("[tap] %s <- %s: update route: %s -> %s (old %s)",
|
||||||
|
tap.LocalAddr(), addr, macSrc, addr, actual.(net.Addr))
|
||||||
|
h.routes.Store(macSrc.String(), addr)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Logf("[tap] %s: new route: %s -> %s", tap.LocalAddr(), macSrc, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := tap.Write(b[:n]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
errc <- err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err := <-errc
|
||||||
|
if err != nil && err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
log.Logf("[tap] %s - %s: %v", tap.LocalAddr(), conn.LocalAddr(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type tapListener struct {
|
||||||
|
addr net.Addr
|
||||||
|
conns chan net.Conn
|
||||||
|
closed chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TapListener creates a listener for tap tunnel.
|
||||||
|
func TapListener(addr string) (Listener, error) {
|
||||||
|
laddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
threads := 1
|
||||||
|
ln := &tapListener{
|
||||||
|
addr: laddr,
|
||||||
|
conns: make(chan net.Conn, threads),
|
||||||
|
closed: make(chan struct{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < threads; i++ {
|
||||||
|
conn, err := net.ListenUDP("udp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ln.conns <- conn
|
||||||
|
}
|
||||||
|
|
||||||
|
return ln, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tapListener) Accept() (net.Conn, error) {
|
||||||
|
select {
|
||||||
|
case conn := <-l.conns:
|
||||||
|
return conn, nil
|
||||||
|
case <-l.closed:
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("accept on closed listener")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tapListener) Addr() net.Addr {
|
||||||
|
return l.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tapListener) Close() error {
|
||||||
|
select {
|
||||||
|
case <-l.closed:
|
||||||
|
return errors.New("listener has been closed")
|
||||||
|
default:
|
||||||
|
close(l.closed)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type tunTapConn struct {
|
||||||
|
ifce *water.Interface
|
||||||
|
addr net.Addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunTapConn) Read(b []byte) (n int, err error) {
|
||||||
|
return c.ifce.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunTapConn) Write(b []byte) (n int, err error) {
|
||||||
|
return c.ifce.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunTapConn) Close() (err error) {
|
||||||
|
return c.ifce.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunTapConn) LocalAddr() net.Addr {
|
||||||
|
return c.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunTapConn) RemoteAddr() net.Addr {
|
||||||
|
return &net.IPAddr{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunTapConn) SetDeadline(t time.Time) error {
|
||||||
|
return &net.OpError{Op: "set", Net: "tuntap", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunTapConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return &net.OpError{Op: "set", Net: "tuntap", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *tunTapConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return &net.OpError{Op: "set", Net: "tuntap", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
// +build !linux,!windows
|
|
||||||
|
|
||||||
package gost
|
package gost
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -42,13 +41,18 @@ func createTun(cfg TunConfig) (conn net.Conn, ipNet *net.IPNet, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = &tunConn{
|
conn = &tunTapConn{
|
||||||
ifce: ifce,
|
ifce: ifce,
|
||||||
addr: &net.IPAddr{IP: ip},
|
addr: &net.IPAddr{IP: ip},
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createTap(cfg TapConfig) (conn net.Conn, ipNet *net.IPNet, err error) {
|
||||||
|
err = errors.New("tap is not supported on darwin")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func addRoutes(ifName string, routes ...string) error {
|
func addRoutes(ifName string, routes ...string) error {
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
if route == "" {
|
if route == "" {
|
@ -57,24 +57,82 @@ func createTun(cfg TunConfig) (conn net.Conn, ipNet *net.IPNet, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = addRoutes(ifce.Name(), cfg.Routes...); err != nil {
|
if err = addRoutes("tun", ifce.Name(), cfg.Routes...); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = &tunConn{
|
conn = &tunTapConn{
|
||||||
ifce: ifce,
|
ifce: ifce,
|
||||||
addr: &net.IPAddr{IP: ip},
|
addr: &net.IPAddr{IP: ip},
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRoutes(ifName string, routes ...string) error {
|
func createTap(cfg TapConfig) (conn net.Conn, ipNet *net.IPNet, err error) {
|
||||||
|
ip, ipNet, err := net.ParseCIDR(cfg.Addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ifce, err := water.New(water.Config{
|
||||||
|
DeviceType: water.TAP,
|
||||||
|
PlatformSpecificParams: water.PlatformSpecificParams{
|
||||||
|
Name: cfg.Name,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
link, err := tenus.NewLinkFrom(ifce.Name())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mtu := cfg.MTU
|
||||||
|
if mtu <= 0 {
|
||||||
|
mtu = DefaultMTU
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := fmt.Sprintf("ip link set dev %s mtu %d", ifce.Name(), mtu)
|
||||||
|
log.Log("[tap]", cmd)
|
||||||
|
if er := link.SetLinkMTU(mtu); er != nil {
|
||||||
|
err = fmt.Errorf("%s: %v", cmd, er)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = fmt.Sprintf("ip address add %s dev %s", cfg.Addr, ifce.Name())
|
||||||
|
log.Log("[tap]", cmd)
|
||||||
|
if er := link.SetLinkIp(ip, ipNet); er != nil {
|
||||||
|
err = fmt.Errorf("%s: %v", cmd, er)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = fmt.Sprintf("ip link set dev %s up", ifce.Name())
|
||||||
|
log.Log("[tap]", cmd)
|
||||||
|
if er := link.SetLinkUp(); er != nil {
|
||||||
|
err = fmt.Errorf("%s: %v", cmd, er)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = addRoutes("tap", ifce.Name(), cfg.Routes...); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn = &tunTapConn{
|
||||||
|
ifce: ifce,
|
||||||
|
addr: &net.IPAddr{IP: ip},
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRoutes(ifType, ifName string, routes ...string) error {
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
if route == "" {
|
if route == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cmd := fmt.Sprintf("ip route add %s dev %s", route, ifName)
|
cmd := fmt.Sprintf("ip route add %s dev %s", route, ifName)
|
||||||
log.Log("[tun]", cmd)
|
log.Logf("[%s] %s", ifType, cmd)
|
||||||
if err := netlink.AddRoute(route, "", "", ifName); err != nil {
|
if err := netlink.AddRoute(route, "", "", ifName); err != nil {
|
||||||
return fmt.Errorf("%s: %v", cmd, err)
|
return fmt.Errorf("%s: %v", cmd, err)
|
||||||
}
|
}
|
102
tuntap_unix.go
Normal file
102
tuntap_unix.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// +build !linux,!windows,!darwin
|
||||||
|
|
||||||
|
package gost
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-log/log"
|
||||||
|
"github.com/songgao/water"
|
||||||
|
)
|
||||||
|
|
||||||
|
func createTun(cfg TunConfig) (conn net.Conn, ipNet *net.IPNet, err error) {
|
||||||
|
ip, ipNet, err := net.ParseCIDR(cfg.Addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ifce, err := water.New(water.Config{
|
||||||
|
DeviceType: water.TUN,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mtu := cfg.MTU
|
||||||
|
if mtu <= 0 {
|
||||||
|
mtu = DefaultMTU
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := fmt.Sprintf("ifconfig %s inet %s mtu %d up", ifce.Name(), cfg.Addr, mtu)
|
||||||
|
log.Log("[tun]", cmd)
|
||||||
|
args := strings.Split(cmd, " ")
|
||||||
|
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||||
|
err = fmt.Errorf("%s: %v", cmd, er)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = addRoutes("tun", ifce.Name(), cfg.Routes...); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn = &tunTapConn{
|
||||||
|
ifce: ifce,
|
||||||
|
addr: &net.IPAddr{IP: ip},
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTap(cfg TapConfig) (conn net.Conn, ipNet *net.IPNet, err error) {
|
||||||
|
ip, ipNet, err := net.ParseCIDR(cfg.Addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ifce, err := water.New(water.Config{
|
||||||
|
DeviceType: water.TAP,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mtu := cfg.MTU
|
||||||
|
if mtu <= 0 {
|
||||||
|
mtu = DefaultMTU
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := fmt.Sprintf("ifconfig %s inet %s mtu %d up", ifce.Name(), cfg.Addr, mtu)
|
||||||
|
log.Log("[tap]", cmd)
|
||||||
|
args := strings.Split(cmd, " ")
|
||||||
|
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||||
|
err = fmt.Errorf("%s: %v", cmd, er)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = addRoutes("tap", ifce.Name(), cfg.Routes...); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn = &tunTapConn{
|
||||||
|
ifce: ifce,
|
||||||
|
addr: &net.IPAddr{IP: ip},
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRoutes(ifType, ifName string, routes ...string) error {
|
||||||
|
for _, route := range routes {
|
||||||
|
if route == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmd := fmt.Sprintf("route add -net %s -interface %s", route, ifName)
|
||||||
|
log.Logf("[%s] %s", ifType, 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
|
||||||
|
}
|
@ -38,18 +38,57 @@ func createTun(cfg TunConfig) (conn net.Conn, ipNet *net.IPNet, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = addRoutes(ifce.Name(), cfg.Routes...); err != nil {
|
if err = addRoutes("tun", ifce.Name(), cfg.Routes...); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conn = &tunConn{
|
conn = &tunTapConn{
|
||||||
ifce: ifce,
|
ifce: ifce,
|
||||||
addr: &net.IPAddr{IP: ip},
|
addr: &net.IPAddr{IP: ip},
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRoutes(ifName string, routes ...string) error {
|
func createTap(cfg TapConfig) (conn net.Conn, ipNet *net.IPNet, err error) {
|
||||||
|
ip, ipNet, err := net.ParseCIDR(cfg.Addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ifce, err := water.New(water.Config{
|
||||||
|
DeviceType: water.TAP,
|
||||||
|
PlatformSpecificParams: water.PlatformSpecificParams{
|
||||||
|
ComponentID: "tap0901",
|
||||||
|
InterfaceName: cfg.Name,
|
||||||
|
Network: cfg.Addr,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := fmt.Sprintf("netsh interface ip set address name=%s "+
|
||||||
|
"source=static addr=%s mask=%s gateway=none",
|
||||||
|
ifce.Name(), ip.String(), ipMask(ipNet.Mask))
|
||||||
|
log.Log("[tap]", cmd)
|
||||||
|
args := strings.Split(cmd, " ")
|
||||||
|
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||||
|
err = fmt.Errorf("%s: %v", cmd, er)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = addRoutes("tap", ifce.Name(), cfg.Routes...); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn = &tunTapConn{
|
||||||
|
ifce: ifce,
|
||||||
|
addr: &net.IPAddr{IP: ip},
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRoutes(ifType, ifName string, routes ...string) error {
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
if route == "" {
|
if route == "" {
|
||||||
continue
|
continue
|
||||||
@ -59,7 +98,7 @@ func addRoutes(ifName string, routes ...string) error {
|
|||||||
|
|
||||||
cmd := fmt.Sprintf("netsh interface ip add route prefix=%s interface=%s store=active",
|
cmd := fmt.Sprintf("netsh interface ip add route prefix=%s interface=%s store=active",
|
||||||
route, ifName)
|
route, ifName)
|
||||||
log.Log("[tun]", cmd)
|
log.Logf("[%s] %s", ifType, cmd)
|
||||||
args := strings.Split(cmd, " ")
|
args := strings.Split(cmd, " ")
|
||||||
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
if er := exec.Command(args[0], args[1:]...).Run(); er != nil {
|
||||||
return fmt.Errorf("%s: %v", cmd, er)
|
return fmt.Errorf("%s: %v", cmd, er)
|
Loading…
Reference in New Issue
Block a user