mirror of
https://github.com/xjasonlyu/tun2socks.git
synced 2025-10-30 11:36:22 +08:00
add go-tun2socks code
This commit is contained in:
127
core/input.go
Normal file
127
core/input.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package core
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I./c/include
|
||||
#include "lwip/pbuf.h"
|
||||
#include "lwip/tcp.h"
|
||||
|
||||
err_t
|
||||
input(struct pbuf *p)
|
||||
{
|
||||
return (*netif_list).input(p, netif_list);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type ipver byte
|
||||
|
||||
const (
|
||||
ipv4 = 4
|
||||
ipv6 = 6
|
||||
)
|
||||
|
||||
type proto byte
|
||||
|
||||
const (
|
||||
proto_icmp = 1
|
||||
proto_tcp = 6
|
||||
proto_udp = 17
|
||||
)
|
||||
|
||||
func peekIPVer(p []byte) (ipver, error) {
|
||||
if len(p) < 1 {
|
||||
return 0, errors.New("short IP packet")
|
||||
}
|
||||
return ipver((p[0] & 0xf0) >> 4), nil
|
||||
}
|
||||
|
||||
func moreFrags(ipv ipver, p []byte) bool {
|
||||
switch ipv {
|
||||
case ipv4:
|
||||
if (p[6] & 0x20) > 0 /* has MF (More Fragments) bit set */ {
|
||||
return true
|
||||
}
|
||||
case ipv6:
|
||||
// FIXME Just too lazy to implement this for IPv6, for now
|
||||
// returning true simply indicate do the copy anyway.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fragOffset(ipv ipver, p []byte) uint16 {
|
||||
switch ipv {
|
||||
case ipv4:
|
||||
return binary.BigEndian.Uint16(p[6:8]) & 0x1fff
|
||||
case ipv6:
|
||||
// FIXME Just too lazy to implement this for IPv6, for now
|
||||
// returning a value greater than 0 simply indicate do the
|
||||
// copy anyway.
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func peekNextProto(ipv ipver, p []byte) (proto, error) {
|
||||
switch ipv {
|
||||
case ipv4:
|
||||
if len(p) < 9 {
|
||||
return 0, errors.New("short IPv4 packet")
|
||||
}
|
||||
return proto(p[9]), nil
|
||||
case ipv6:
|
||||
if len(p) < 6 {
|
||||
return 0, errors.New("short IPv6 packet")
|
||||
}
|
||||
return proto(p[6]), nil
|
||||
default:
|
||||
return 0, errors.New("unknown IP version")
|
||||
}
|
||||
}
|
||||
|
||||
func Input(pkt []byte) (int, error) {
|
||||
if len(pkt) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
ipv, err := peekIPVer(pkt)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
nextProto, err := peekNextProto(ipv, pkt)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
lwipMutex.Lock()
|
||||
defer lwipMutex.Unlock()
|
||||
|
||||
var buf *C.struct_pbuf
|
||||
|
||||
if nextProto == proto_udp && (!moreFrags(ipv, pkt) || fragOffset(ipv, pkt) > 0) {
|
||||
// Copying data is not necessary for unfragmented UDP packets, and we would like to
|
||||
// have all data in one pbuf.
|
||||
buf = C.pbuf_alloc_reference(unsafe.Pointer(&pkt[0]), C.u16_t(len(pkt)), C.PBUF_REF)
|
||||
} else {
|
||||
// TODO Copy the data only when lwip need to keep it, e.g. in
|
||||
// case we are returning ERR_CONN in tcpRecvFn.
|
||||
//
|
||||
// Allocating from PBUF_POOL results in a pbuf chain that may
|
||||
// contain multiple pbufs.
|
||||
buf = C.pbuf_alloc(C.PBUF_RAW, C.u16_t(len(pkt)), C.PBUF_POOL)
|
||||
C.pbuf_take(buf, unsafe.Pointer(&pkt[0]), C.u16_t(len(pkt)))
|
||||
}
|
||||
|
||||
ierr := C.input(buf)
|
||||
if ierr != C.ERR_OK {
|
||||
C.pbuf_free(buf)
|
||||
return 0, errors.New("packet not handled")
|
||||
}
|
||||
return len(pkt), nil
|
||||
}
|
||||
Reference in New Issue
Block a user