package tun import ( "fmt" "github.com/pkg/taptun" "io" "log" "mpbl3p/proxy" "net" "os" "strings" "sync" "time" ) type SourceSink struct { tun *taptun.Tun bufferSize int up bool upMu sync.Mutex } func NewTun(namingScheme string, bufferSize int) (ss *SourceSink, err error) { ss = &SourceSink{} ss.tun, err = taptun.NewTun(namingScheme) if err != nil { return } ss.bufferSize = bufferSize ss.upMu.Lock() go func() { defer ss.upMu.Unlock() for { iface, err := net.InterfaceByName(ss.tun.String()) if err != nil { panic(err) } if strings.Contains(iface.Flags.String(), "up") { log.Println("tun is up") ss.up = true return } time.Sleep(100 * time.Millisecond) } }() return } func (t *SourceSink) Source() (proxy.Packet, error) { if !t.up { t.upMu.Lock() t.upMu.Unlock() } buf := make([]byte, t.bufferSize) read, err := t.tun.Read(buf) if err != nil { return proxy.Packet{}, err } if read == 0 { return proxy.Packet{}, io.EOF } return proxy.NewPacket(buf[:read]), nil } var good, bad float64 func (t *SourceSink) Sink(packet proxy.Packet) error { if !t.up { t.upMu.Lock() t.upMu.Unlock() } _, err := t.tun.Write(packet.Raw()) if err != nil { switch err.(type) { case *os.PathError: bad += 1 fmt.Printf("packet loss: %f%%\n", bad*100/(good+bad)) return nil default: return err } } good += 1 return nil }