mirror of
				https://github.com/xjasonlyu/tun2socks.git
				synced 2025-10-31 20:12:41 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			122 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package core
 | |
| 
 | |
| /*
 | |
| #cgo CFLAGS: -I./c/include
 | |
| #include "lwip/tcp.h"
 | |
| #include "lwip/udp.h"
 | |
| #include "lwip/timeouts.h"
 | |
| */
 | |
| import "C"
 | |
| import (
 | |
| 	"sync"
 | |
| 	"time"
 | |
| 	"unsafe"
 | |
| )
 | |
| 
 | |
| const CHECK_TIMEOUTS_INTERVAL = 250 // in millisecond
 | |
| const TCP_POLL_INTERVAL = 8         // poll every 4 seconds
 | |
| 
 | |
| type LWIPStack interface {
 | |
| 	Write([]byte) (int, error)
 | |
| 	Close() error
 | |
| 	RestartTimeouts()
 | |
| }
 | |
| 
 | |
| // lwIP runs in a single thread, locking is needed in Go runtime.
 | |
| var lwipMutex = &sync.Mutex{}
 | |
| 
 | |
| type lwipStack struct {
 | |
| 	tpcb *C.struct_tcp_pcb
 | |
| 	upcb *C.struct_udp_pcb
 | |
| }
 | |
| 
 | |
| // NewLWIPStack listens for any incoming connections/packets and registers
 | |
| // corresponding accept/recv callback functions.
 | |
| func NewLWIPStack() LWIPStack {
 | |
| 	tcpPCB := C.tcp_new()
 | |
| 	if tcpPCB == nil {
 | |
| 		panic("tcp_new return nil")
 | |
| 	}
 | |
| 
 | |
| 	err := C.tcp_bind(tcpPCB, C.IP_ADDR_ANY, 0)
 | |
| 	switch err {
 | |
| 	case C.ERR_OK:
 | |
| 		break
 | |
| 	case C.ERR_VAL:
 | |
| 		panic("invalid PCB state")
 | |
| 	case C.ERR_USE:
 | |
| 		panic("port in use")
 | |
| 	default:
 | |
| 		C.memp_free(C.MEMP_TCP_PCB, unsafe.Pointer(tcpPCB))
 | |
| 		panic("unknown tcp_bind return value")
 | |
| 	}
 | |
| 
 | |
| 	tcpPCB = C.tcp_listen_with_backlog(tcpPCB, C.TCP_DEFAULT_LISTEN_BACKLOG)
 | |
| 	if tcpPCB == nil {
 | |
| 		panic("can not allocate tcp pcb")
 | |
| 	}
 | |
| 
 | |
| 	setTCPAcceptCallback(tcpPCB)
 | |
| 
 | |
| 	udpPCB := C.udp_new()
 | |
| 	if udpPCB == nil {
 | |
| 		panic("could not allocate udp pcb")
 | |
| 	}
 | |
| 
 | |
| 	err = C.udp_bind(udpPCB, C.IP_ADDR_ANY, 0)
 | |
| 	if err != C.ERR_OK {
 | |
| 		panic("address already in use")
 | |
| 	}
 | |
| 
 | |
| 	setUDPRecvCallback(udpPCB, nil)
 | |
| 
 | |
| 	go func() {
 | |
| 		for {
 | |
| 			select {
 | |
| 			case <-time.After(CHECK_TIMEOUTS_INTERVAL * time.Millisecond):
 | |
| 				lwipMutex.Lock()
 | |
| 				C.sys_check_timeouts()
 | |
| 				lwipMutex.Unlock()
 | |
| 			}
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	return &lwipStack{
 | |
| 		tpcb: tcpPCB,
 | |
| 		upcb: udpPCB,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (s *lwipStack) Write(data []byte) (int, error) {
 | |
| 	return Input(data)
 | |
| }
 | |
| 
 | |
| func (s *lwipStack) RestartTimeouts() {
 | |
| 	C.sys_restart_timeouts()
 | |
| }
 | |
| 
 | |
| func (s *lwipStack) Close() error {
 | |
| 	tcpConns.Range(func(_, c interface{}) bool {
 | |
| 		c.(*tcpConn).Abort()
 | |
| 		return true
 | |
| 	})
 | |
| 	udpConns.Range(func(_, c interface{}) bool {
 | |
| 		c.(*udpConn).Close()
 | |
| 		return true
 | |
| 	})
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func init() {
 | |
| 	// Initialize lwIP.
 | |
| 	//
 | |
| 	// There is a little trick here, a loop interface (127.0.0.1)
 | |
| 	// is created in the initialization stage due to the option
 | |
| 	// `#define LWIP_HAVE_LOOPIF 1` in `lwipopts.h`, so we need
 | |
| 	// not create our own interface.
 | |
| 	//
 | |
| 	// Now the loop interface is just the first element in
 | |
| 	// `C.netif_list`, i.e. `*C.netif_list`.
 | |
| 	lwipInit()
 | |
| }
 | 
