Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leolovenet/bfbaefd370e3c2318db9af69292dcf70 to your computer and use it in GitHub Desktop.
Save leolovenet/bfbaefd370e3c2318db9af69292dcf70 to your computer and use it in GitHub Desktop.
SetsockoptInt IP_TRANSPARENT for net.Listener in golang
package main
import (
"fmt"
"net"
"os"
"os/signal"
"reflect"
"syscall"
)
func rFieldByNames(i interface{}, fields...string) (field reflect.Value) {
v := reflect.Indirect(reflect.ValueOf(i))
for _, n := range fields {
field = reflect.Indirect(v.FieldByName(n))
v = field
}
return
}
func main() {
l, err := net.Listen("tcp", ":40404")
if err != nil {
panic(err)
}
/*
Method 1:
from https://github.com/naoina/kuune.org/blob/master/content/text/get-fd-from-net-tcplistener-of-golang.md
May not be compatible, but there will be no problems.
*/
fd := int(rFieldByNames(l, "fd", "pfd", "Sysfd").Int())
if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
syscall.Close(fd)
fmt.Printf("syscall.SetsockoptInt err: %s", err)
return
}
/*
Method 2 (Not recommended):
from https://github.com/LiamHaworth/go-tproxy/blob/master/tproxy_tcp.go
There is a problem here, that is, the program will hung when it exits,
because the program is blocked by the Accept function.
*/
//lt := l.(*net.TCPListener)
//fh, err := lt.File()
//if err != nil {
// fmt.Printf("get TCPListener file err: %s", err)
// return
//}
//fd := int(fh.Fd())
//if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
// syscall.Close(fd)
// fmt.Printf("syscall.SetsockoptInt err: %s", err)
// return
//}
//fh.Close()
go func() {
for {
c, err := l.Accept()
if err == nil {
c.Write([]byte("accept & close"))
c.Close()
} else {
fmt.Println(err)
break
}
}
}()
sigs := make(chan os.Signal, 1)
done := make(chan bool)
signal.Notify(sigs, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func() {
for range sigs {
fmt.Println("stopping...")
l.Close()
done <- true
}
}()
<-done
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment