Skip to content

Instantly share code, notes, and snippets.

@optman
Last active July 27, 2020 09:21
Show Gist options
  • Save optman/8055431d42d3b530dcbf to your computer and use it in GitHub Desktop.
Save optman/8055431d42d3b530dcbf to your computer and use it in GitHub Desktop.
package main
import (
"errors"
"net"
"strconv"
"syscall"
"unsafe"
"os"
)
type sockaddr struct {
family uint16
data [14]byte
}
const SO_ORIGINAL_DST = 80
func getTCPConnFd(conn *net.Conn)(*os.File, error){
tcpConn, ok := (*conn).(*net.TCPConn)
if !ok {
return nil, errors.New("not a TCPConn")
}
file, err := tcpConn.File()
if err != nil {
return nil, err
}
// To avoid potential problems from making the socket non-blocking.
/*
tcpConn.Close()
*conn, err = net.FileConn(file)
if err != nil {
return nil, err
}*/
return file, nil
}
func getUDPConnFd(conn *net.Conn)(*os.File, error){
udpConn, ok := (*conn).(*net.UDPConn)
if !ok {
return nil, errors.New("not a UDPConn")
}
return udpConn.File()
}
func realTcpAddress(tcpConn *net.TCPConn) (string, error) {
var conn net.Conn
conn = tcpConn
file, err := getTCPConnFd(&conn)
if err != nil{
return "", err
}
defer file.Close()
fd := file.Fd()
var addr sockaddr
size := uint32(unsafe.Sizeof(addr))
err = getsockopt(int(fd), syscall.SOL_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&addr)), &size)
if err != nil {
return "", err
}
var ip net.IP
switch addr.family {
case syscall.AF_INET:
ip = addr.data[2:6]
default:
return "", errors.New("unrecognized address family")
}
port := int(addr.data[0])<<8 + int(addr.data[1])
return net.JoinHostPort(ip.String(), strconv.Itoa(port)), nil
}
func setRecvOrigDstAddr(udpConn *net.UDPConn)error{
var conn net.Conn
conn = udpConn
file, err := getUDPConnFd(&conn)
if err != nil{
return err
}
defer file.Close()
fd := file.Fd()
opt := uint32(1)
size := uint32(4)
err = setsockopt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, uintptr(unsafe.Pointer(&opt)), size)
err = setsockopt(int(fd), syscall.SOL_IP, syscall.IP_RECVORIGDSTADDR, uintptr(unsafe.Pointer(&opt)), size)
if err != nil {
return err
}
return nil
}
func getsockopt(s int, level int, name int, val uintptr, vallen *uint32) (err error) {
_, _, e1 := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = e1
}
return
}
func setsockopt(s int, level int, name int, val uintptr, vallen uint32) (err error) {
_, _, e1 := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
if e1 != 0 {
err = e1
}
return
}
func listenudp() {
udpAddr, _ := net.ResolveUDPAddr("udp", CONN_HOST+":"+CONN_PORT)
udpConn, err := net.ListenUDP("udp", udpAddr)
if err != nil {
fmt.Println("Error listening udp:", err.Error())
os.Exit(1)
}
err = setRecvOrigDstAddr(udpConn)
if err != nil{
fmt.Println(err)
os.Exit(1)
}
defer udpConn.Close()
fmt.Println("udp listening on " + CONN_HOST + ":" + CONN_PORT)
for {
data := make([]byte, 1600)
oob := make([]byte, 1600)
n, oobn, flags, srcAddr, err := udpConn.ReadMsgUDP(data, oob)
if err != nil{
fmt.Println("ReadMSGUDP fail!", err)
os.Exit(1)
}
log.Println("read udp data from", srcAddr, "data", n,
"oob", oobn, "flags", flags)
cmsgs, err := syscall.ParseSocketControlMessage(oob[:oobn])
if err == nil{
for _, cmsg := range cmsgs{
if cmsg.Header.Level == syscall.SOL_IP &&
cmsg.Header.Type == syscall.IP_ORIGDSTADDR{
//log.Println(cmsg.Data)
var ip net.IP
ip = cmsg.Data[4:8]
port := int(cmsg.Data[2])<<8 + int(cmsg.Data[3])
fmt.Printf("original dst: %s:%d\n", ip, port)
}
}
}
//log.Println(oob[:oobn], cmsg)
}
}
func listentcp() {
l, err := net.Listen("tcp", CONN_HOST+":"+CONN_PORT)
if err != nil {
fmt.Println("Error listening tcp:", err.Error())
os.Exit(1)
}
defer l.Close()
fmt.Println("tcp listening on " + CONN_HOST + ":" + CONN_PORT)
for {
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
os.Exit(1)
}
tcpConn, _ := conn.(*net.TCPConn)
go handleTcpRequest(tcpConn)
}
}
@optman
Copy link
Author

optman commented Oct 23, 2015

@optman
Copy link
Author

optman commented Oct 23, 2015

tcp intercept can use REDIRECT instead of TPROXY.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment