From 3c4432e0f2fb8ddf54a2e441063d584b99572a4e Mon Sep 17 00:00:00 2001 From: Mikhail Osipov Date: Thu, 26 Mar 2020 00:29:12 +0300 Subject: add tun socket --- pkg/server/socket/tun.go | 133 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 pkg/server/socket/tun.go (limited to 'pkg/server/socket/tun.go') diff --git a/pkg/server/socket/tun.go b/pkg/server/socket/tun.go new file mode 100644 index 0000000..78bdfd4 --- /dev/null +++ b/pkg/server/socket/tun.go @@ -0,0 +1,133 @@ +package socket + +import ( + "errors" + "fmt" + "golang.org/x/sys/unix" + "log" + "os" + "strings" + "sync" + "tunnel/pkg/pack" + "tunnel/pkg/server/env" + "tunnel/pkg/server/queue" + "unsafe" +) + +const maxTunBufSize = 65535 + +var errPartialWrite = errors.New("partial write") + +type ifReq struct { + name [unix.IFNAMSIZ]uint8 + flags uint16 +} + +type tunSocket struct { + name string +} + +type tunChannel struct { + name string + s *tunSocket + fp *os.File + once sync.Once +} + +func ioctl(fd int, req uintptr, ptr unsafe.Pointer) error { + _, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), req, uintptr(ptr)) + if errno != 0 { + return errno + } + + return nil +} + +func newTunSocket(name string) (S, error) { + return &tunSocket{name: name}, nil + +} + +func (s *tunSocket) String() string { + return fmt.Sprintf("tun/%s", s.name) +} + +func (s *tunSocket) Open(env.Env) (Channel, error) { + fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0) + if err != nil { + return nil, err + } + + ifr := &ifReq{} + copy(ifr.name[:], s.name) + ifr.flags = unix.IFF_TUN | unix.IFF_NO_PI + + if err := ioctl(fd, unix.TUNSETIFF, unsafe.Pointer(ifr)); err != nil { + unix.Close(fd) + return nil, fmt.Errorf("ioctl TUNSETIFF %s: %w", s.name, err) + } + + if err := unix.SetNonblock(fd, true); err != nil { + unix.Close(fd) + return nil, fmt.Errorf("set nonblock %s: %w", s.name, err) + } + + c := &tunChannel{ + name: strings.Trim(string(ifr.name[:]), "\x00"), + fp: os.NewFile(uintptr(fd), "tun"), + } + + return c, nil +} + +func (s *tunSocket) Close() { +} + +func (c *tunChannel) Send(wq queue.Q) error { + buf := make([]byte, maxTunBufSize) + enc := pack.NewEncoder(wq.Writer()) + + for { + n, err := c.fp.Read(buf) + if err != nil { + return err + } + + enc.Lps(buf[0:n]) + } +} + +func (c *tunChannel) Recv(rq queue.Q) error { + dec := pack.NewDecoder(rq.Reader()) + + for { + b, err := dec.Lps() + if err != nil { + return err + } + + n, err := c.fp.Write(b) + if err != nil { + return err + } + + if n != len(b) { + return errPartialWrite + } + } +} + +func (c *tunChannel) String() string { + return "tun/" + c.name +} + +func (c *tunChannel) Close() error { + err := ErrAlreadyClosed + + c.once.Do(func() { + log.Println("close", c) + err = c.fp.Close() + }) + + return err +} -- cgit v1.2.3-70-g09d2