vnet

package module
v0.0.0-...-26fa1e3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 26, 2022 License: MIT Imports: 6 Imported by: 1

README

vnet

virtual net interface

中文

golang provides net.Listener and net.Conn interfaces to wrap the network. A lot of interesting tcp codes are built on these two interfaces. So as long as these two interfaces are met, these codes can be used outside of tcp, this is what vnet does.

PipeListener

The ListenPipe function returns a PipeListener. PipeListener implements the net.Listener interface in memory. Use PipeListener.Dial or PipeListener.DialContext to dial.

One of the most typical applications is to use PipeListener to provide grpc and grpc-gateway services in the program. The grpc and grpc-gateway use memory copy communication instead of socket communication.

package main

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"runtime"

	"github.com/powerpuffpenguin/vnet"
)

func main() {
	var (
		// listen pipe
		p = vnet.ListenPipe()

		l net.Listener = p
		d vnet.Dialer  = p
	)

	// run client
	go runClient(&http.Client{
		Transport: &http.Transport{
			// http client by vnet.Dialer
			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
				return d.DialContext(ctx, network, addr)
			},
		},
	})

	// run server
	runServer(l)
}

func runClient(client *http.Client) {
	// get /info
	resp, e := client.Get(`http://pipe/info`)
	if e != nil {
		log.Fatalln(e)
	}
	b, e := ioutil.ReadAll(resp.Body)
	if e != nil {
		log.Fatalln(e)
	}
	fmt.Printf("/info resp: %s\n", b)

	// get /exit
	resp, e = client.Get(`http://pipe/exit`)
	if e != nil {
		log.Fatalln(e)
	}
	b, e = ioutil.ReadAll(resp.Body)
	if e != nil {
		log.Fatalln(e)
	}
	fmt.Printf("/exit resp: %s\n", b)
}

func runServer(l net.Listener) {
	mux := http.NewServeMux()

	mux.HandleFunc(`/info`, func(rw http.ResponseWriter, r *http.Request) {
		rw.Write([]byte(`pipe listener`))
	})
	mux.HandleFunc(`/exit`, func(rw http.ResponseWriter, r *http.Request) {
		rw.Write([]byte(`success`))
		runtime.Gosched()
		l.Close()
	})

	e := http.Serve(l, mux)
	if e != nil && !errors.Is(e, vnet.ErrListenerClosed) {
		log.Fatalln(e)
	}
}

reverse.Dialer reverse.Listener

reverse.Dialer reverse.Listener used to reverse the server client. This allows socket.connect to work in the server role and socket.accept to work in the client role.

The most typical use is that the server role works on the internal network, and the client role works on the external network. For example, reverse Trojan horses or programs that need to break through the intranet to provide services. Imagine how easy it is to write a reverse Trojan using grpc.

package main

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/powerpuffpenguin/vnet"
	"github.com/powerpuffpenguin/vnet/reverse"
)

func main() {
	l, e := net.Listen(`tcp`, `127.0.0.1:9000`)
	if e != nil {
		log.Fatalln(e)
	}

	var (
		dialer *reverse.Dialer = reverse.NewDialer(l)
		d      vnet.Dialer     = dialer
	)
	go dialer.Serve()
	l = reverse.Listen(l.Addr())

	// run client
	go runClient(&http.Client{
		Transport: &http.Transport{
			// http client by vnet.Dialer
			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
				fmt.Println(network, addr)
				return d.DialContext(ctx, network, addr)
			},
		},
	})

	// run server
	runServer(l)
}

func runClient(client *http.Client) {
	// get /info
	resp, e := client.Get(`http://reverse/info`)
	if e != nil {
		log.Fatalln(e)
	}
	b, e := ioutil.ReadAll(resp.Body)
	if e != nil {
		log.Fatalln(e)
	}
	fmt.Printf("/info resp: %s\n", b)

	// get /exit
	resp, e = client.Get(`http://reverse/exit`)
	if e != nil {
		log.Fatalln(e)
	}
	b, e = ioutil.ReadAll(resp.Body)
	if e != nil {
		log.Fatalln(e)
	}
	fmt.Printf("/exit resp: %s\n", b)
}

func runServer(l net.Listener) {
	mux := http.NewServeMux()

	mux.HandleFunc(`/info`, func(rw http.ResponseWriter, r *http.Request) {
		rw.Write([]byte(`reverse listener`))
	})
	mux.HandleFunc(`/exit`, func(rw http.ResponseWriter, r *http.Request) {
		rw.Write([]byte(`success`))
		go func() {
			time.Sleep(time.Millisecond * 100)
			l.Close()
		}()
	})

	e := http.Serve(l, mux)
	if e != nil && !errors.Is(e, vnet.ErrListenerClosed) {
		log.Fatalln(e)
	}
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrClosed = errors.New(`already closed`)
View Source
var ErrDialerClosed = errs.WrapError(ErrClosed, `dialer already closed`)
View Source
var ErrListenerClosed = errs.WrapError(ErrClosed, `listener already closed`)

Functions

This section is empty.

Types

type Dialer

type Dialer interface {
	Dial(network, addr string) (net.Conn, error)
	DialContext(ctx context.Context, network, addr string) (conn net.Conn, e error)
}

type PipeListener

type PipeListener struct {
	// contains filtered or unexported fields
}

func ListenPipe

func ListenPipe() *PipeListener

func (*PipeListener) Accept

func (l *PipeListener) Accept() (c net.Conn, e error)

Accept waits for and returns the next connection to the listener.

func (*PipeListener) Addr

func (l *PipeListener) Addr() net.Addr

Addr returns the listener's network address.

func (*PipeListener) Close

func (l *PipeListener) Close() (e error)

Close closes the listener. Any blocked Accept operations will be unblocked and return errors.

func (*PipeListener) Dial

func (l *PipeListener) Dial(network, addr string) (net.Conn, error)

func (*PipeListener) DialContext

func (l *PipeListener) DialContext(ctx context.Context, network, addr string) (conn net.Conn, e error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL