云风的个人空间 : XTunnel

首页 :: 索引 :: 修订历史 :: 你好, 44.220.255.141
你的足迹: » XTunnel
我自己写的一个小程序,介绍见[InterWiki]我的 Blog

xtunnel.go 这个程序运行在本地
package main

import "net"
import "log"
import "container/list"
import "io"
import "os"
import "sync"

const bindAddr = "127.0.0.1:1080"
const serverAddr = "www.yourvps.com:2011"
const bufferSize = 4096
const maxConn = 0x10000
const xor = 0x64

type tunnel struct {
	id int
	* list.Element
	send chan []byte
	reply io.Writer
}

type bundle struct {
	t [maxConn] tunnel
	* list.List
	* xsocket
	sync.Mutex
}

type xsocket struct {
	net.Conn
	* sync.Mutex
}

func (s xsocket) Read(data []byte) (n int, err os.Error) {
	n,err = io.ReadFull(s.Conn, data)
	if n>0 {
		for i:=0;i<n;i++ {
			data[i] = data[i]^xor
		}
	}

	return
}

func (s xsocket) Write(data []byte) (n int, err os.Error) {
	s.Lock()
	defer s.Unlock()
	log.Println("Send",len(data))
	for i:=0;i<len(data);i++ {
		data[i] = data[i]^xor
	}
	x := 0
	all := len(data)

	for all>0 {
		n, err = s.Conn.Write(data)
		if err != nil {
			n += x
			return
		}
		if all != n {
			log.Println("Write only",n,all)
		}
		all -= n
		x += n
		data = data[n:]
	}

	return all,err
}

func (t *tunnel) processBack(c net.Conn) {
	c.SetReadTimeout(1e7)
	var buf [bufferSize]byte
	for {
		n,err := c.Read(buf[4:])
		if n>0 {
			t.sendBack(buf[:4+n])
		}
		e, ok := err.(net.Error);
		if !(ok && e.Timeout()) && err != nil {
			log.Println(n,err)
			return
		}
	}
}

func (t *tunnel) sendClose() {
	buf := [4]byte {
		byte(t.id>>8),
		byte(t.id & 0xff),
		0,
		0,
	}
	t.reply.Write(buf[:])
}

func (t *tunnel) sendBack(buf []byte) {
	buf[0] = byte(t.id>>8)
	buf[1] = byte(t.id & 0xff)
	length := len(buf) - 4
	buf[2] = byte(length >> 8)
	buf[3] = byte(length & 0xff)
	t.reply.Write(buf)
}

func (t *tunnel) process(c net.Conn,b *bundle) {
	go t.processBack(c)
	send := t.send
	
	for {
		buf,ok := <-send 
		if !ok {
			c.Close()
			return
		}
		n,err := c.Write(buf)
		if err != nil {
			b.free(t.id)
		} else if n!=len(buf) {
			log.Println("Write",n,len(buf))
		}
	}
}

func (t *tunnel) open(b *bundle, c net.Conn) {
	t.send = make(chan []byte)
	t.reply = b.xsocket
	go t.process(c,b)
}

func (t *tunnel) close() {
	close(t.send)
}

func newBundle(c net.Conn) *bundle {
	b := new(bundle)
	b.List = list.New()
	for i:=0;i<maxConn;i++ {
		t := &b.t[i]
		t.id = i
		t.Element = b.PushBack(t)
	}
	b.xsocket = & xsocket { c , new (sync.Mutex) }
	return b
}

func (b *bundle) alloc(c net.Conn) *tunnel {
	b.Lock()
	defer b.Unlock()
	f := b.Front()
	if f == nil {
		return nil
	}
	t := b.Remove(f).(*tunnel)
	t.Element = nil
	t.open(b,c)
	return t
}

func (b *bundle) free(id int) {
	b.Lock()
	defer b.Unlock()
	t := &b.t[id]
	if t.Element == nil {
		t.sendClose()
		t.Element = b.PushBack(t)
		t.close()
	}
}

func (b *bundle) get(id int) *tunnel {
	b.Lock()
	defer b.Unlock()
	t := &b.t[id]
	if t.Element != nil {
		return nil
	}
	return t
}

func servSocks(b *bundle) {
	a , err := net.ResolveTCPAddr("tcp",bindAddr)
	if err != nil {
		log.Fatal(err)
	}
	l , err2 := net.ListenTCP("tcp",a)
	if err2 != nil {
		log.Fatal(err2)
	}
	log.Printf("xtunnelc bind %s",a)
	for {
		c , err := l.Accept()
		if err != nil {
			log.Fatal(err)
		}
		log.Println(c.RemoteAddr())
		b.alloc(c)
	}
}

func mainServer(c net.Conn) {
	b := newBundle(c)
	go servSocks(b)
	var header [4]byte
	for {
		_,err := b.Read(header[:])
		if err != nil {
			log.Fatal(err)
		}
		id := int(header[0]) << 8 | int(header[1])
		length := int(header[2]) << 8 | int(header[3])
		log.Println("Recv",id,length)
		if length == 0 {
			b.free(id)			
		} else {
			t := b.get(id)
			buf := make([]byte, length)
			n,err := b.Read(buf)
			if err != nil {
				log.Fatal(err)
			} else if n!=len(buf) {
				log.Println("Read",n,len(buf))					
			}
			if t != nil {
				t.send <- buf
			}
		}
	}
}

func start(addr string) {
	a , err := net.ResolveTCPAddr("tcp",addr)
	if err != nil {
		log.Fatal(err)
	}
	c,err2 := net.DialTCP("tcp", nil, a)
	if err2 != nil {
		log.Fatal(err2)
	}
	log.Printf("xtunnelc connect %s",a)
	mainServer(c)
}

func main() {
	start(serverAddr)
}


xtunneld.go 这个程序运行在墙外
package main

import "net"
import "log"
import "container/list"
import "io"
import "os"
import "sync"

const socksServer = "127.0.0.1:1080"
const bindAddr = ":2011"
const bufferSize = 4096
const maxConn = 0x10000
const xor = 0x64

var socksAddr * net.TCPAddr

func init() {
	var err os.Error
	socksAddr , err = net.ResolveTCPAddr("tcp",socksServer)
	if err != nil {
		log.Fatal(err)
	}
}

type tunnel struct {
	id int
	* list.Element
	send chan []byte
	reply io.Writer
}

type bundle struct {
	t [maxConn] tunnel
	* list.List
	* xsocket
}

type xsocket struct {
	net.Conn
	* sync.Mutex
}

func (s xsocket) Read(data []byte) (n int, err os.Error) {
	n,err = io.ReadFull(s.Conn, data)
	if n>0 {
		for i:=0;i<n;i++ {
			data[i] = data[i]^xor
		}
	}

	return
}

func (s xsocket) Write(data []byte) (n int, err os.Error) {
	s.Lock()
	defer s.Unlock()
	log.Println("Send",len(data))
	for i:=0;i<len(data);i++ {
		data[i] = data[i]^xor
	}
	x := 0
	all := len(data)

	for all>0 {
		n, err = s.Conn.Write(data)
		if err != nil {
			n += x
			return
		}
		all -= n
		x += n
		data = data[n:]
	}

	return all,err
}

func (t *tunnel) processBack(c net.Conn) {
	c.SetReadTimeout(1e7)
	var buf [bufferSize]byte
	for {
		n,err := c.Read(buf[4:])
		if n>0 {
			t.sendBack(buf[:4+n])
		}
		e, ok := err.(net.Error)
		if !(ok && e.Timeout()) && err != nil {
			log.Println(n,err)
			return
		}
	}
}

func (t *tunnel) sendClose() {
	buf := [4]byte {
		byte(t.id>>8),
		byte(t.id & 0xff),
		0,
		0,
	}
	t.reply.Write(buf[:])
}

func (t *tunnel) sendBack(buf []byte) {
	buf[0] = byte(t.id>>8)
	buf[1] = byte(t.id & 0xff)
	length := len(buf) - 4
	buf[2] = byte(length >> 8)
	buf[3] = byte(length & 0xff)
	t.reply.Write(buf)
}

func connectSocks() net.Conn {
	c,err := net.DialTCP("tcp", nil, socksAddr)
	if err != nil {
		return nil
	}
	log.Println(c.RemoteAddr())
	return c
}

func (t *tunnel) process() {
	c := connectSocks()
	if c==nil {
		t.sendClose()
	} else {
		go t.processBack(c)
	}
	send := t.send
	
	for {
		buf,ok := <-send 
		if !ok {
			if c!=nil {
				c.Close()
			}
			return
		}
		if c!=nil {
			n,err := c.Write(buf)
			if err != nil {
				log.Println("tunnel",n,err)
				t.sendClose()
			}
		}
	}
}

func (t *tunnel) open(reply io.Writer) {
	t.send = make(chan []byte)
	t.reply = reply
	go t.process()
}

func (t *tunnel) close() {
	close(t.send)
}

func newBundle(c net.Conn) *bundle {
	b := new(bundle)
	b.List = list.New()
	for i:=0;i<maxConn;i++ {
		t := &b.t[i]
		t.id = i
		t.Element = b.PushBack(t)
	}
	b.xsocket = & xsocket { c , new(sync.Mutex) }
	return b
}

func (b *bundle) free(id int) {
	t := &b.t[id]
	if t.Element == nil {
		t.Element = b.PushBack(t)
		t.close()
	}
}

func (b *bundle) get(id int) *tunnel {
	t := &b.t[id]
	if t.Element != nil {
		b.Remove(t.Element)
		t.Element = nil
		t.open(b.xsocket)
	}
	return t
}

func servTunnel(c net.Conn) {
	b := newBundle(c)
	var header [4]byte
	for {
		_,err := b.Read(header[:])
		if err != nil {
			log.Fatal(err)
		}
		id := int(header[0]) << 8 | int(header[1])
		length := int(header[2]) << 8 | int(header[3])
		log.Println("Recv",id,length)
		if length == 0 {
			b.free(id)			
		} else {
			t := b.get(id)
			buf := make([]byte, length)
			_,err := b.Read(buf)
			if err != nil {
				log.Fatal(err)
			}
			t.send <- buf
		}
	}
}

func start(addr string) {
	a , err := net.ResolveTCPAddr("tcp",addr)
	if err != nil {
		log.Fatal(err)
	}
	l , err2 := net.ListenTCP("tcp",a)
	if err2 != nil {
		log.Fatal(err2)
	}
	log.Printf("xtunneld bind %s",a)
	c , err3 := l.Accept()
	if err3 != nil {
		log.Fatal(err3)
	}
	l.Close()
	servTunnel(c)
}

func main() {
	start(bindAddr)
}