add tcp debug cmd
parent
9b123d8bb9
commit
44678fa0ff
@ -0,0 +1,35 @@
|
||||
//go:build darwin
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func SetTcpInfo(conn *net.TCPConn, usingKeepAlive bool, keepAliveIdel, keepAlivePeriod, keepAliveCount, userTimeout int) error {
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usingKeepAlive {
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, keepAliveIdel)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, 0x101, keepAlivePeriod)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
} else {
|
||||
err = conn.SetKeepAlive(false)
|
||||
}
|
||||
if userTimeout > 0 {
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, 0x12, userTimeout)
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
//go:build !(windows && darwin)
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func SetTcpInfo(conn *net.TCPConn, usingKeepAlive bool, keepAliveIdel, keepAlivePeriod, keepAliveCount, userTimeout int) error {
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usingKeepAlive {
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, keepAliveIdel)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, keepAlivePeriod)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, keepAliveCount)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
} else {
|
||||
err = conn.SetKeepAlive(false)
|
||||
}
|
||||
if userTimeout > 0 {
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, 0x12, userTimeout)
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
//go:build windows
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func SetTcpInfo(conn *net.TCPConn, usingKeepAlive bool, keepAliveIdel, keepAlivePeriod, keepAliveCount, userTimeout int) error {
|
||||
if usingKeepAlive {
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
ka := syscall.TCPKeepalive{
|
||||
OnOff: 1,
|
||||
Time: uint32(keepAliveIdel),
|
||||
Interval: uint32(keepAlivePeriod),
|
||||
}
|
||||
ret := uint32(0)
|
||||
size := uint32(unsafe.Sizeof(ka))
|
||||
err = syscall.WSAIoctl(syscall.Handle(fd), syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
|
||||
runtime.KeepAlive(fd)
|
||||
})
|
||||
return os.NewSyscallError("wsaioctl", err)
|
||||
}
|
||||
return conn.SetKeepAlive(false)
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"b612.me/starcrypto"
|
||||
"b612.me/starlog"
|
||||
"b612.me/starnet"
|
||||
"crypto/elliptic"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
listenAddr string
|
||||
keyFile string
|
||||
KeyPasswd string
|
||||
outpath string
|
||||
curlUrl string
|
||||
curlArg []string
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmdSSHJar.Flags().StringVarP(&listenAddr, "listen", "l", "0.0.0.0:22", "监听地址")
|
||||
cmdSSHJar.Flags().StringVarP(&keyFile, "key", "k", "", "私钥文件")
|
||||
cmdSSHJar.Flags().StringVarP(&KeyPasswd, "passwd", "p", "", "私钥密码")
|
||||
cmdSSHJar.Flags().StringVarP(&outpath, "output", "o", "", "输出文件")
|
||||
}
|
||||
|
||||
var cmdSSHJar = &cobra.Command{
|
||||
Use: "sshjar",
|
||||
Short: "SSH蜜罐",
|
||||
Long: "SSH蜜罐",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath)
|
||||
},
|
||||
}
|
||||
|
||||
func runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath string) {
|
||||
var f *os.File
|
||||
var err error
|
||||
if outpath != "" {
|
||||
f, err = os.OpenFile(outpath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to open file %s (%s)", outpath, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
defer f.Close()
|
||||
config := &ssh.ServerConfig{
|
||||
// 密码验证回调函数
|
||||
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
|
||||
starlog.Infof("Login attempt from %s with %s %s\n", c.RemoteAddr(), c.User(), string(pass))
|
||||
data := []string{c.RemoteAddr().String(), c.User(), string(pass)}
|
||||
bts, _ := json.Marshal(data)
|
||||
if f != nil {
|
||||
f.Write(bts)
|
||||
f.Write([]byte("\n"))
|
||||
}
|
||||
if curlUrl != "" {
|
||||
go func() {
|
||||
data := map[string]string{
|
||||
"ip": c.RemoteAddr().String(),
|
||||
"user": c.User(),
|
||||
"passwd": string(pass),
|
||||
}
|
||||
if curlArg != nil && len(curlArg) > 0 {
|
||||
for _, v := range curlArg {
|
||||
args := strings.SplitN(v, ":", 2)
|
||||
if len(args) == 2 {
|
||||
data[args[0]] = args[1]
|
||||
}
|
||||
}
|
||||
starnet.Curl(starnet.NewRequests(curlUrl, []byte(starnet.BuildQuery(data)), "POST"))
|
||||
}
|
||||
}()
|
||||
}
|
||||
return nil, fmt.Errorf("password rejected for %q", c.User())
|
||||
},
|
||||
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
|
||||
return nil, fmt.Errorf("public key rejected for %q", conn.User())
|
||||
},
|
||||
}
|
||||
if keyFile == "" {
|
||||
secKey, _, err := starcrypto.GenerateEcdsaKey(elliptic.P256())
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to generate ECDSA key (%s)", err)
|
||||
return
|
||||
}
|
||||
key, err := ssh.NewSignerFromKey(secKey)
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to generate signer from key (%s)", err)
|
||||
return
|
||||
}
|
||||
config.AddHostKey(key)
|
||||
} else {
|
||||
keyByte, err := os.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to read private key from %s (%s)", keyFile, err)
|
||||
return
|
||||
}
|
||||
var key ssh.Signer
|
||||
if KeyPasswd != "" {
|
||||
key, err = ssh.ParsePrivateKeyWithPassphrase(keyByte, []byte(KeyPasswd))
|
||||
} else {
|
||||
key, err = ssh.ParsePrivateKey(keyByte)
|
||||
}
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to load private key from %s (%s)", keyFile, err)
|
||||
return
|
||||
}
|
||||
config.AddHostKey(key)
|
||||
}
|
||||
listener, err := net.Listen("tcp", listenAddr)
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to listen on %s (%s)", listenAddr, err)
|
||||
return
|
||||
}
|
||||
starlog.Noticeln("SSH HoneyJar is listening on", listenAddr)
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, os.Interrupt, os.Kill)
|
||||
for {
|
||||
select {
|
||||
case <-sig:
|
||||
starlog.Noticef("SSH HoneyJar is shutting down")
|
||||
listener.Close()
|
||||
return
|
||||
default:
|
||||
}
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
starlog.Infof("New connection from %s\n", conn.RemoteAddr())
|
||||
go func(conn net.Conn) {
|
||||
ssh.NewServerConn(conn, config)
|
||||
conn.Close()
|
||||
}(conn)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package net
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestSSHJar(t *testing.T) {
|
||||
//runSSHHoneyJar("0.0.0.0:22")
|
||||
}
|
@ -0,0 +1,246 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"b612.me/stario"
|
||||
"b612.me/starlog"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TcpClient struct {
|
||||
LocalAddr string
|
||||
RemoteAddr string
|
||||
UsingKeepAlive bool
|
||||
KeepAlivePeriod int
|
||||
KeepAliveIdel int
|
||||
KeepAliveCount int
|
||||
Interactive bool
|
||||
UserTimeout int
|
||||
ShowRecv bool
|
||||
ShowAsHex bool
|
||||
SaveToFolder string
|
||||
Rmt *TcpConn
|
||||
LogPath string
|
||||
stopCtx context.Context
|
||||
stopFn context.CancelFunc
|
||||
}
|
||||
|
||||
func (s *TcpClient) Close() error {
|
||||
return s.Rmt.Close()
|
||||
}
|
||||
|
||||
func (s *TcpClient) handleInteractive() {
|
||||
var currentCmd string
|
||||
notifyMap := make(map[string]chan struct{})
|
||||
if !s.Interactive {
|
||||
return
|
||||
}
|
||||
starlog.Infoln("Interactive mode enabled")
|
||||
for {
|
||||
select {
|
||||
case <-s.stopCtx.Done():
|
||||
starlog.Infoln("Interactive mode stopped due to context done")
|
||||
return
|
||||
default:
|
||||
}
|
||||
cmd := stario.MessageBox("", "").MustString()
|
||||
if cmd == "" {
|
||||
continue
|
||||
}
|
||||
cmdf := strings.Fields(cmd)
|
||||
switch cmdf[0] {
|
||||
case "hex":
|
||||
currentCmd = "hex"
|
||||
starlog.Infoln("Switch to hex mode,send hex to remote client")
|
||||
case "text":
|
||||
currentCmd = "text"
|
||||
starlog.Infoln("Switch to text mode,send text to remote client")
|
||||
case "close":
|
||||
if s.Rmt.TCPConn == nil {
|
||||
starlog.Errorln("No client selected")
|
||||
continue
|
||||
}
|
||||
s.Rmt.TCPConn.Close()
|
||||
starlog.Infof("Client %s closed\n", s.Rmt.RemoteAddr().String())
|
||||
s.Rmt = nil
|
||||
currentCmd = ""
|
||||
case "startauto":
|
||||
if s.Rmt == nil {
|
||||
starlog.Errorln("No client selected")
|
||||
continue
|
||||
}
|
||||
notifyMap[s.Rmt.RemoteAddr().String()] = make(chan struct{})
|
||||
go func(conn *TcpConn) {
|
||||
for {
|
||||
select {
|
||||
case <-notifyMap[conn.RemoteAddr().String()]:
|
||||
starlog.Infoln("Auto send stopped")
|
||||
return
|
||||
default:
|
||||
}
|
||||
_, err := conn.Write([]byte(strings.Repeat("B612", 256)))
|
||||
if err != nil {
|
||||
starlog.Errorln("Write error:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}(s.Rmt)
|
||||
starlog.Infoln("Auto send started")
|
||||
case "closeauto":
|
||||
if s.Rmt == nil {
|
||||
starlog.Errorln("No client selected")
|
||||
continue
|
||||
}
|
||||
close(notifyMap[s.Rmt.RemoteAddr().String()])
|
||||
case "send":
|
||||
if s.Rmt == nil {
|
||||
starlog.Errorln("No client selected")
|
||||
continue
|
||||
}
|
||||
if currentCmd == "hex" {
|
||||
data, err := hex.DecodeString(strings.TrimSpace(strings.TrimPrefix(cmd, "send")))
|
||||
if err != nil {
|
||||
starlog.Errorln("Hex decode error:", err)
|
||||
continue
|
||||
}
|
||||
_, err = s.Rmt.Write(data)
|
||||
if err != nil {
|
||||
starlog.Errorln("Write error:", err)
|
||||
} else {
|
||||
if s.Rmt.f != nil {
|
||||
s.Rmt.f.Write([]byte(time.Now().String() + " send\n"))
|
||||
s.Rmt.f.Write(data)
|
||||
s.Rmt.f.Write([]byte("\n"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_, err := s.Rmt.Write([]byte(strings.TrimSpace(strings.TrimPrefix(cmd, "send"))))
|
||||
if err != nil {
|
||||
starlog.Errorln("Write error:", err)
|
||||
} else {
|
||||
if s.Rmt.f != nil {
|
||||
s.Rmt.f.Write([]byte(time.Now().String() + " send\n"))
|
||||
s.Rmt.f.Write([]byte(cmdf[1]))
|
||||
s.Rmt.f.Write([]byte("\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
starlog.Infof("Send to %s success\n", s.Rmt.RemoteAddr().String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TcpClient) Run() error {
|
||||
var err error
|
||||
s.stopCtx, s.stopFn = context.WithCancel(context.Background())
|
||||
if s.LogPath != "" {
|
||||
err := starlog.SetLogFile(s.LogPath, starlog.Std, true)
|
||||
if err != nil {
|
||||
starlog.Errorln("SetLogFile error:", err)
|
||||
return fmt.Errorf("SetLogFile error: %w", err)
|
||||
}
|
||||
}
|
||||
var localAddr *net.TCPAddr
|
||||
if s.LocalAddr != "" {
|
||||
localAddr, err = net.ResolveTCPAddr("tcp", s.LocalAddr)
|
||||
if err != nil {
|
||||
starlog.Errorln("ResolveTCPAddr error:", err)
|
||||
return fmt.Errorf("ResolveTCPAddr error: %w", err)
|
||||
}
|
||||
}
|
||||
remoteAddr, err := net.ResolveTCPAddr("tcp", s.RemoteAddr)
|
||||
if err != nil {
|
||||
starlog.Errorln("ResolveTCPAddr error:", err)
|
||||
return fmt.Errorf("ResolveTCPAddr error: %w", err)
|
||||
}
|
||||
|
||||
conn, err := net.DialTCP("tcp", localAddr, remoteAddr)
|
||||
if err != nil {
|
||||
starlog.Errorln("Dial TCP error:", err)
|
||||
return fmt.Errorf("Dial TCP error: %w", err)
|
||||
}
|
||||
starlog.Infof("Connected to %s LocalAddr: %s\n", conn.RemoteAddr().String(), conn.LocalAddr().String())
|
||||
if s.Interactive {
|
||||
go s.handleInteractive()
|
||||
}
|
||||
s.Rmt = s.getTcpConn(conn)
|
||||
|
||||
s.handleConn(s.Rmt)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TcpClient) getTcpConn(conn *net.TCPConn) *TcpConn {
|
||||
var err error
|
||||
var f *os.File
|
||||
if s.SaveToFolder != "" {
|
||||
f, err = os.Create(filepath.Join(s.SaveToFolder, strings.ReplaceAll(conn.RemoteAddr().String(), ":", "_")))
|
||||
if err != nil {
|
||||
starlog.Errorf("Create file error for %s: %v\n", conn.RemoteAddr().String(), err)
|
||||
}
|
||||
}
|
||||
return &TcpConn{
|
||||
TCPConn: conn,
|
||||
f: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TcpClient) handleConn(conn *TcpConn) {
|
||||
var err error
|
||||
log := starlog.Std.NewFlag()
|
||||
err = SetTcpInfo(conn.TCPConn, s.UsingKeepAlive, s.KeepAliveIdel, s.KeepAlivePeriod, s.KeepAliveCount, s.UserTimeout)
|
||||
if err != nil {
|
||||
log.Errorf("SetTcpInfo error for %s: %v\n", conn.RemoteAddr().String(), err)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
log.Infof("SetKeepAlive success for %s\n", conn.RemoteAddr().String())
|
||||
log.Infof("KeepAlivePeriod: %d, KeepAliveIdel: %d, KeepAliveCount: %d, UserTimeout: %d\n", s.KeepAlivePeriod, s.KeepAliveIdel, s.KeepAliveCount, s.UserTimeout)
|
||||
if runtime.GOOS != "linux" {
|
||||
log.Warningln("keepAliveCount and userTimeout only work on linux")
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.stopCtx.Done():
|
||||
log.Infof("Connection from %s closed due to context done\n", conn.RemoteAddr().String())
|
||||
conn.Close()
|
||||
return
|
||||
default:
|
||||
}
|
||||
buf := make([]byte, 8192)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.Errorf("Read error for %s: %v\n", conn.RemoteAddr().String(), err)
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
if s.ShowRecv {
|
||||
if s.ShowAsHex {
|
||||
log.Printf("Recv from %s: %x\n", conn.RemoteAddr().String(), buf[:n])
|
||||
} else {
|
||||
log.Printf("Recv from %s: %s\n", conn.RemoteAddr().String(), string(buf[:n]))
|
||||
}
|
||||
}
|
||||
if conn.f != nil {
|
||||
conn.f.Write([]byte(time.Now().String() + " recv\n"))
|
||||
conn.f.Write(buf[:n])
|
||||
conn.f.Write([]byte("\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TcpClient) Stop() {
|
||||
s.stopFn()
|
||||
if s.Rmt != nil {
|
||||
s.Rmt.Close()
|
||||
}
|
||||
}
|
@ -0,0 +1,285 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"b612.me/stario"
|
||||
"b612.me/starlog"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TcpConn struct {
|
||||
*net.TCPConn
|
||||
f *os.File
|
||||
}
|
||||
|
||||
type TcpServer struct {
|
||||
LocalAddr string
|
||||
UsingKeepAlive bool
|
||||
KeepAlivePeriod int
|
||||
KeepAliveIdel int
|
||||
KeepAliveCount int
|
||||
sync.Mutex
|
||||
Clients map[string]*TcpConn
|
||||
Interactive bool
|
||||
UserTimeout int
|
||||
ShowRecv bool
|
||||
ShowAsHex bool
|
||||
SaveToFolder string
|
||||
Listen *net.TCPListener
|
||||
LogPath string
|
||||
stopCtx context.Context
|
||||
stopFn context.CancelFunc
|
||||
}
|
||||
|
||||
func (s *TcpServer) Close() error {
|
||||
return s.Listen.Close()
|
||||
}
|
||||
|
||||
func (s *TcpServer) handleInteractive() {
|
||||
var conn *TcpConn
|
||||
var currentCmd string
|
||||
notifyMap := make(map[string]chan struct{})
|
||||
if !s.Interactive {
|
||||
return
|
||||
}
|
||||
starlog.Infoln("Interactive mode enabled")
|
||||
for {
|
||||
select {
|
||||
case <-s.stopCtx.Done():
|
||||
starlog.Infoln("Interactive mode stopped due to context done")
|
||||
return
|
||||
default:
|
||||
}
|
||||
cmd := stario.MessageBox("", "").MustString()
|
||||
if cmd == "" {
|
||||
continue
|
||||
}
|
||||
cmdf := strings.Fields(cmd)
|
||||
switch cmdf[0] {
|
||||
case "list":
|
||||
s.Lock()
|
||||
for k, v := range s.Clients {
|
||||
starlog.Green("Client %s: %s\n", k, v.RemoteAddr().String())
|
||||
}
|
||||
s.Unlock()
|
||||
case "use":
|
||||
if len(cmdf) < 2 {
|
||||
starlog.Errorln("use command need a client address")
|
||||
continue
|
||||
}
|
||||
conn = s.Clients[cmdf[1]]
|
||||
if conn == nil {
|
||||
starlog.Errorln("Client not found")
|
||||
continue
|
||||
}
|
||||
starlog.Infof("Using client %s\n", conn.RemoteAddr().String())
|
||||
case "hex":
|
||||
currentCmd = "hex"
|
||||
starlog.Infoln("Switch to hex mode,send hex to remote client")
|
||||
case "text":
|
||||
currentCmd = "text"
|
||||
starlog.Infoln("Switch to text mode,send text to remote client")
|
||||
case "close":
|
||||
if conn.TCPConn == nil {
|
||||
starlog.Errorln("No client selected")
|
||||
continue
|
||||
}
|
||||
conn.TCPConn.Close()
|
||||
starlog.Infof("Client %s closed\n", conn.RemoteAddr().String())
|
||||
conn = nil
|
||||
currentCmd = ""
|
||||
case "startauto":
|
||||
if conn == nil {
|
||||
starlog.Errorln("No client selected")
|
||||
continue
|
||||
}
|
||||
notifyMap[conn.RemoteAddr().String()] = make(chan struct{})
|
||||
go func(conn *TcpConn) {
|
||||
for {
|
||||
select {
|
||||
case <-notifyMap[conn.RemoteAddr().String()]:
|
||||
starlog.Infoln("Auto send stopped")
|
||||
return
|
||||
default:
|
||||
}
|
||||
_, err := conn.Write([]byte(strings.Repeat("B612", 256)))
|
||||
if err != nil {
|
||||
starlog.Errorln("Write error:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}(conn)
|
||||
starlog.Infoln("Auto send started")
|
||||
case "closeauto":
|
||||
if conn == nil {
|
||||
starlog.Errorln("No client selected")
|
||||
continue
|
||||
}
|
||||
close(notifyMap[conn.RemoteAddr().String()])
|
||||
case "send":
|
||||
if conn == nil {
|
||||
starlog.Errorln("No client selected")
|
||||
continue
|
||||
}
|
||||
if currentCmd == "hex" {
|
||||
data, err := hex.DecodeString(strings.TrimSpace(strings.TrimPrefix(cmd, "send")))
|
||||
if err != nil {
|
||||
starlog.Errorln("Hex decode error:", err)
|
||||
continue
|
||||
}
|
||||
_, err = conn.Write(data)
|
||||
if err != nil {
|
||||
starlog.Errorln("Write error:", err)
|
||||
} else {
|
||||
if conn.f != nil {
|
||||
conn.f.Write([]byte(time.Now().String() + " send\n"))
|
||||
conn.f.Write(data)
|
||||
conn.f.Write([]byte("\n"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_, err := conn.Write([]byte(strings.TrimSpace(strings.TrimPrefix(cmd, "send"))))
|
||||
if err != nil {
|
||||
starlog.Errorln("Write error:", err)
|
||||
} else {
|
||||
if conn.f != nil {
|
||||
conn.f.Write([]byte(time.Now().String() + " send\n"))
|
||||
conn.f.Write([]byte(cmdf[1]))
|
||||
conn.f.Write([]byte("\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
starlog.Infof("Send to %s success\n", conn.RemoteAddr().String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TcpServer) Run() error {
|
||||
s.stopCtx, s.stopFn = context.WithCancel(context.Background())
|
||||
if s.LogPath != "" {
|
||||
err := starlog.SetLogFile(s.LogPath, starlog.Std, true)
|
||||
if err != nil {
|
||||
starlog.Errorln("SetLogFile error:", err)
|
||||
return fmt.Errorf("SetLogFile error: %w", err)
|
||||
}
|
||||
}
|
||||
s.Clients = make(map[string]*TcpConn)
|
||||
tcpAddr, err := net.ResolveTCPAddr("tcp", s.LocalAddr)
|
||||
if err != nil {
|
||||
starlog.Errorln("ResolveTCPAddr error:", err)
|
||||
return fmt.Errorf("ResolveTCPAddr error: %w", err)
|
||||
}
|
||||
s.Listen, err = net.ListenTCP("tcp", tcpAddr)
|
||||
if err != nil {
|
||||
starlog.Errorln("ListenTCP error:", err)
|
||||
return fmt.Errorf("ListenTCP error: %w", err)
|
||||
}
|
||||
starlog.Infof("TcpServer listen on %s\n", s.LocalAddr)
|
||||
if s.Interactive {
|
||||
go s.handleInteractive()
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-s.stopCtx.Done():
|
||||
starlog.Infoln("TcpServer stopped due to context done")
|
||||
return s.Listen.Close()
|
||||
default:
|
||||
}
|
||||
conn, err := s.Listen.AcceptTCP()
|
||||
if err != nil {
|
||||
starlog.Errorln("AcceptTCP error:", err)
|
||||
continue
|
||||
}
|
||||
starlog.Infof("Accept new connection from %s", conn.RemoteAddr().String())
|
||||
s.Lock()
|
||||
s.Clients[conn.RemoteAddr().String()] = s.getTcpConn(conn)
|
||||
s.Unlock()
|
||||
go s.handleConn(s.Clients[conn.RemoteAddr().String()])
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TcpServer) getTcpConn(conn *net.TCPConn) *TcpConn {
|
||||
var err error
|
||||
var f *os.File
|
||||
if s.SaveToFolder != "" {
|
||||
f, err = os.Create(filepath.Join(s.SaveToFolder, strings.ReplaceAll(conn.RemoteAddr().String(), ":", "_")))
|
||||
if err != nil {
|
||||
starlog.Errorf("Create file error for %s: %v\n", conn.RemoteAddr().String(), err)
|
||||
}
|
||||
}
|
||||
return &TcpConn{
|
||||
TCPConn: conn,
|
||||
f: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TcpServer) handleConn(conn *TcpConn) {
|
||||
var err error
|
||||
log := starlog.Std.NewFlag()
|
||||
err = SetTcpInfo(conn.TCPConn, s.UsingKeepAlive, s.KeepAliveIdel, s.KeepAlivePeriod, s.KeepAliveCount, s.UserTimeout)
|
||||
if err != nil {
|
||||
log.Errorf("SetTcpInfo error for %s: %v\n", conn.RemoteAddr().String(), err)
|
||||
s.Lock()
|
||||
delete(s.Clients, conn.RemoteAddr().String())
|
||||
s.Unlock()
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
log.Infof("SetKeepAlive success for %s\n", conn.RemoteAddr().String())
|
||||
log.Infof("KeepAlivePeriod: %d, KeepAliveIdel: %d, KeepAliveCount: %d, UserTimeout: %d\n", s.KeepAlivePeriod, s.KeepAliveIdel, s.KeepAliveCount, s.UserTimeout)
|
||||
if runtime.GOOS != "linux" {
|
||||
log.Warningln("keepAliveCount and userTimeout only work on linux")
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.stopCtx.Done():
|
||||
log.Infof("Connection from %s closed due to context done\n", conn.RemoteAddr().String())
|
||||
s.Lock()
|
||||
delete(s.Clients, conn.RemoteAddr().String())
|
||||
s.Unlock()
|
||||
conn.Close()
|
||||
return
|
||||
default:
|
||||
}
|
||||
buf := make([]byte, 8192)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
log.Errorf("Read error for %s: %v\n", conn.RemoteAddr().String(), err)
|
||||
s.Lock()
|
||||
delete(s.Clients, conn.RemoteAddr().String())
|
||||
s.Unlock()
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
if s.ShowRecv {
|
||||
if s.ShowAsHex {
|
||||
log.Printf("Recv from %s: %x\n", conn.RemoteAddr().String(), buf[:n])
|
||||
} else {
|
||||
log.Printf("Recv from %s: %s\n", conn.RemoteAddr().String(), string(buf[:n]))
|
||||
}
|
||||
}
|
||||
if conn.f != nil {
|
||||
conn.f.Write([]byte(time.Now().String() + " recv\n"))
|
||||
conn.f.Write(buf[:n])
|
||||
conn.f.Write([]byte("\n"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TcpServer) Stop() {
|
||||
s.stopFn()
|
||||
if s.Listen != nil {
|
||||
s.Close()
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
//go:build darwin
|
||||
|
||||
package netforward
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func SetTcpInfo(conn *net.TCPConn, usingKeepAlive bool, keepAliveIdel, keepAlivePeriod, keepAliveCount, userTimeout int) error {
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usingKeepAlive {
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, keepAliveIdel)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, 0x101, keepAlivePeriod)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
} else {
|
||||
err = conn.SetKeepAlive(false)
|
||||
}
|
||||
if userTimeout > 0 {
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, 0x12, userTimeout)
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
//go:build !(windows && darwin)
|
||||
|
||||
package netforward
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func SetTcpInfo(conn *net.TCPConn, usingKeepAlive bool, keepAliveIdel, keepAlivePeriod, keepAliveCount, userTimeout int) error {
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if usingKeepAlive {
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, keepAliveIdel)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, keepAlivePeriod)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, keepAliveCount)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
})
|
||||
} else {
|
||||
err = conn.SetKeepAlive(false)
|
||||
}
|
||||
if userTimeout > 0 {
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, 0x12, userTimeout)
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
//go:build windows
|
||||
|
||||
package netforward
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func SetTcpInfo(conn *net.TCPConn, usingKeepAlive bool, keepAliveIdel, keepAlivePeriod, keepAliveCount, userTimeout int) error {
|
||||
if usingKeepAlive {
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
ka := syscall.TCPKeepalive{
|
||||
OnOff: 1,
|
||||
Time: uint32(keepAliveIdel),
|
||||
Interval: uint32(keepAlivePeriod),
|
||||
}
|
||||
ret := uint32(0)
|
||||
size := uint32(unsafe.Sizeof(ka))
|
||||
err = syscall.WSAIoctl(syscall.Handle(fd), syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
|
||||
runtime.KeepAlive(fd)
|
||||
})
|
||||
return os.NewSyscallError("wsaioctl", err)
|
||||
}
|
||||
return conn.SetKeepAlive(false)
|
||||
}
|
Loading…
Reference in New Issue