add tcp debug cmd
This commit is contained in:
parent
9b123d8bb9
commit
44678fa0ff
2
main.go
2
main.go
@ -41,7 +41,7 @@ import (
|
|||||||
|
|
||||||
var cmdRoot = &cobra.Command{
|
var cmdRoot = &cobra.Command{
|
||||||
Use: "b612",
|
Use: "b612",
|
||||||
Version: "2.1.0.beta.4",
|
Version: "2.1.0.beta.6",
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -52,7 +52,7 @@ func init() {
|
|||||||
CmdNetTrace.Flags().BoolVarP(&disableIpInfo, "disable-ipinfo", "D", false, "禁用ip信息查询")
|
CmdNetTrace.Flags().BoolVarP(&disableIpInfo, "disable-ipinfo", "D", false, "禁用ip信息查询")
|
||||||
CmdNetTrace.Flags().StringVarP(&bindAddr, "bind", "b", "0.0.0.0", "绑定地址")
|
CmdNetTrace.Flags().StringVarP(&bindAddr, "bind", "b", "0.0.0.0", "绑定地址")
|
||||||
CmdNetTrace.Flags().BoolVarP(&hideIncorrect, "hide-incorrect", "H", false, "隐藏错误节点")
|
CmdNetTrace.Flags().BoolVarP(&hideIncorrect, "hide-incorrect", "H", false, "隐藏错误节点")
|
||||||
Cmd.AddCommand(CmdNetTrace)
|
Cmd.AddCommand(CmdNetTrace, cmdSSHJar)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,5 +25,5 @@ func TestNat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTrace(t *testing.T) {
|
func TestTrace(t *testing.T) {
|
||||||
Traceroute("b612.me", "", 32, time.Millisecond*800, "https://ip.b612.me/{ip}/detail")
|
//Traceroute("b612.me", "", 32, time.Millisecond*800, "https://ip.b612.me/{ip}/detail")
|
||||||
}
|
}
|
||||||
|
35
net/setcpinfo_darwin.go
Normal file
35
net/setcpinfo_darwin.go
Normal file
@ -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
|
||||||
|
}
|
39
net/setcpinfo_linux.go
Normal file
39
net/setcpinfo_linux.go
Normal file
@ -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
|
||||||
|
}
|
33
net/setcpinfo_windows.go
Normal file
33
net/setcpinfo_windows.go
Normal file
@ -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)
|
||||||
|
}
|
145
net/sshjar.go
Normal file
145
net/sshjar.go
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
7
net/sshjar_test.go
Normal file
7
net/sshjar_test.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSSHJar(t *testing.T) {
|
||||||
|
//runSSHHoneyJar("0.0.0.0:22")
|
||||||
|
}
|
246
net/tcpclient.go
Normal file
246
net/tcpclient.go
Normal file
@ -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()
|
||||||
|
}
|
||||||
|
}
|
80
net/tcpcmd.go
Normal file
80
net/tcpcmd.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package net
|
||||||
|
|
||||||
|
import (
|
||||||
|
"b612.me/starlog"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
tcps TcpServer
|
||||||
|
tcpc TcpClient
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
CmdTcps.Flags().StringVarP(&tcps.LocalAddr, "local", "l", "0.0.0.0:29127", "本地地址")
|
||||||
|
CmdTcps.Flags().BoolVarP(&tcps.UsingKeepAlive, "keepalive", "k", true, "启用KeepAlive")
|
||||||
|
CmdTcps.Flags().IntVarP(&tcps.KeepAlivePeriod, "keepalive-period", "p", 10, "KeepAlive重试周期(秒)")
|
||||||
|
CmdTcps.Flags().IntVarP(&tcps.KeepAliveIdel, "keepalive-idel", "i", 15, "KeepAlive空闲时间(秒)")
|
||||||
|
CmdTcps.Flags().IntVarP(&tcps.KeepAliveCount, "keepalive-count", "c", 3, "KeepAlive次数)")
|
||||||
|
CmdTcps.Flags().BoolVarP(&tcps.Interactive, "interactive", "I", false, "交互模式")
|
||||||
|
CmdTcps.Flags().IntVarP(&tcps.UserTimeout, "user-timeout", "u", 0, "用户超时时间(毫秒)")
|
||||||
|
CmdTcps.Flags().BoolVarP(&tcps.ShowRecv, "show-recv", "r", true, "显示接收数据")
|
||||||
|
CmdTcps.Flags().BoolVarP(&tcps.ShowAsHex, "show-hex", "H", false, "显示十六进制")
|
||||||
|
CmdTcps.Flags().StringVarP(&tcps.SaveToFolder, "save", "s", "", "保存到文件夹")
|
||||||
|
CmdTcps.Flags().StringVarP(&tcps.LogPath, "log", "L", "", "日志文件路径")
|
||||||
|
Cmd.AddCommand(CmdTcps)
|
||||||
|
|
||||||
|
CmdTcpc.Flags().StringVarP(&tcpc.LocalAddr, "local", "l", "", "本地地址")
|
||||||
|
CmdTcpc.Flags().BoolVarP(&tcpc.UsingKeepAlive, "keepalive", "k", true, "启用KeepAlive")
|
||||||
|
CmdTcpc.Flags().IntVarP(&tcpc.KeepAlivePeriod, "keepalive-period", "p", 1, "KeepAlive重试周期(秒)")
|
||||||
|
CmdTcpc.Flags().IntVarP(&tcpc.KeepAliveIdel, "keepalive-idel", "i", 15, "KeepAlive空闲时间(秒)")
|
||||||
|
CmdTcpc.Flags().IntVarP(&tcpc.KeepAliveCount, "keepalive-count", "c", 3, "KeepAlive次数")
|
||||||
|
CmdTcpc.Flags().BoolVarP(&tcpc.Interactive, "interactive", "I", false, "交互模式")
|
||||||
|
CmdTcpc.Flags().IntVarP(&tcpc.UserTimeout, "user-timeout", "u", 0, "用户超时时间(毫秒)")
|
||||||
|
CmdTcpc.Flags().BoolVarP(&tcpc.ShowRecv, "show-recv", "r", true, "显示接收数据")
|
||||||
|
CmdTcpc.Flags().BoolVarP(&tcpc.ShowAsHex, "show-hex", "H", false, "显示十六进制")
|
||||||
|
CmdTcpc.Flags().StringVarP(&tcpc.SaveToFolder, "save", "s", "", "保存到文件夹")
|
||||||
|
CmdTcpc.Flags().StringVarP(&tcpc.LogPath, "log", "L", "", "日志文件路径")
|
||||||
|
|
||||||
|
Cmd.AddCommand(CmdTcpc)
|
||||||
|
}
|
||||||
|
|
||||||
|
var CmdTcps = &cobra.Command{
|
||||||
|
Use: "tcps",
|
||||||
|
Short: "TCP服务端",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
go func() {
|
||||||
|
s := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(s, os.Interrupt, os.Kill)
|
||||||
|
<-s
|
||||||
|
tcps.Stop()
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
tcps.Run()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var CmdTcpc = &cobra.Command{
|
||||||
|
Use: "tcpc",
|
||||||
|
Short: "TCP客户端",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
starlog.Errorln("请指定目标地址")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tcpc.RemoteAddr = args[0]
|
||||||
|
go func() {
|
||||||
|
s := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(s, os.Interrupt, os.Kill)
|
||||||
|
<-s
|
||||||
|
tcpc.Stop()
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
os.Exit(0)
|
||||||
|
}()
|
||||||
|
tcpc.Run()
|
||||||
|
},
|
||||||
|
}
|
285
net/tcpserver.go
Normal file
285
net/tcpserver.go
Normal file
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,12 @@ func init() {
|
|||||||
CmdNetforward.Flags().BoolVarP(&f.EnableUDP, "enable-udp-forward", "u", true, "enable udp forward mode")
|
CmdNetforward.Flags().BoolVarP(&f.EnableUDP, "enable-udp-forward", "u", true, "enable udp forward mode")
|
||||||
CmdNetforward.Flags().Int64VarP(&dialTimeout, "dial-timeout", "d", 10000, "dial timeout milliseconds")
|
CmdNetforward.Flags().Int64VarP(&dialTimeout, "dial-timeout", "d", 10000, "dial timeout milliseconds")
|
||||||
CmdNetforward.Flags().Int64VarP(&udpTimeout, "udp-timeout", "D", 60000, "udp connection timeout milliseconds")
|
CmdNetforward.Flags().Int64VarP(&udpTimeout, "udp-timeout", "D", 60000, "udp connection timeout milliseconds")
|
||||||
|
CmdNetforward.Flags().BoolVarP(&f.UsingKeepAlive, "keepalive", "k", true, "enable keepalive")
|
||||||
|
CmdNetforward.Flags().IntVarP(&f.KeepAlivePeriod, "keepalive-period", "P", 10, "keepalive retry period (seconds)")
|
||||||
|
CmdNetforward.Flags().IntVarP(&f.KeepAliveIdel, "keepalive-idel", "I", 15, "keepalive idel time (seconds)")
|
||||||
|
CmdNetforward.Flags().IntVarP(&f.KeepAliveCount, "keepalive-count", "C", 3, "keepalive count")
|
||||||
|
CmdNetforward.Flags().IntVarP(&f.UserTimeout, "user-timeout", "U", 0, "user timeout (milliseconds)")
|
||||||
|
CmdNetforward.Flags().BoolVarP(&f.IgnoreEof, "ignore-eof", "E", false, "ignore eof")
|
||||||
}
|
}
|
||||||
|
|
||||||
var CmdNetforward = &cobra.Command{
|
var CmdNetforward = &cobra.Command{
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -23,11 +24,18 @@ type NetForward struct {
|
|||||||
DelayMilSec int
|
DelayMilSec int
|
||||||
DelayToward int
|
DelayToward int
|
||||||
StdinMode bool
|
StdinMode bool
|
||||||
|
IgnoreEof bool
|
||||||
DialTimeout time.Duration
|
DialTimeout time.Duration
|
||||||
UDPTimeout time.Duration
|
UDPTimeout time.Duration
|
||||||
stopCtx context.Context
|
stopCtx context.Context
|
||||||
stopFn context.CancelFunc
|
stopFn context.CancelFunc
|
||||||
running int32
|
running int32
|
||||||
|
|
||||||
|
KeepAlivePeriod int
|
||||||
|
KeepAliveIdel int
|
||||||
|
KeepAliveCount int
|
||||||
|
UserTimeout int
|
||||||
|
UsingKeepAlive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NetForward) Close() {
|
func (n *NetForward) Close() {
|
||||||
@ -145,6 +153,12 @@ func (n *NetForward) runTCP() error {
|
|||||||
log.Infof("Delay %d ms\n", n.DelayMilSec)
|
log.Infof("Delay %d ms\n", n.DelayMilSec)
|
||||||
time.Sleep(time.Millisecond * time.Duration(n.DelayMilSec))
|
time.Sleep(time.Millisecond * time.Duration(n.DelayMilSec))
|
||||||
}
|
}
|
||||||
|
err = SetTcpInfo(conn.(*net.TCPConn), n.UsingKeepAlive, n.KeepAliveIdel, n.KeepAlivePeriod, n.KeepAliveCount, n.UserTimeout)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("SetTcpInfo error for %s: %v\n", conn.RemoteAddr().String(), err)
|
||||||
|
conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
go func(conn net.Conn) {
|
go func(conn net.Conn) {
|
||||||
rmt, err := net.DialTimeout("tcp", n.RemoteURI, n.DialTimeout)
|
rmt, err := net.DialTimeout("tcp", n.RemoteURI, n.DialTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -152,9 +166,17 @@ func (n *NetForward) runTCP() error {
|
|||||||
conn.Close()
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
err = SetTcpInfo(rmt.(*net.TCPConn), n.UsingKeepAlive, n.KeepAliveIdel, n.KeepAlivePeriod, n.KeepAliveCount, n.UserTimeout)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("SetTcpInfo error for %s: %v\n", conn.RemoteAddr().String(), err)
|
||||||
|
rmt.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
log.Infof("TCP Connect %s <==> %s\n", conn.RemoteAddr().String(), rmt.RemoteAddr().String())
|
log.Infof("TCP Connect %s <==> %s\n", conn.RemoteAddr().String(), rmt.RemoteAddr().String())
|
||||||
n.copy(rmt, conn)
|
n.copy(rmt, conn)
|
||||||
log.Noticef("TCP Connection Closed %s <==> %s\n", conn.RemoteAddr().String(), n.RemoteURI)
|
log.Noticef("TCP Connection Closed %s <==> %s\n", conn.RemoteAddr().String(), n.RemoteURI)
|
||||||
|
conn.Close()
|
||||||
|
rmt.Close()
|
||||||
}(conn)
|
}(conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,6 +311,9 @@ func (n *NetForward) copy(dst, src net.Conn) {
|
|||||||
for {
|
for {
|
||||||
count, err := src.Read(bufsize)
|
count, err := src.Read(bufsize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if n.IgnoreEof && err == io.EOF {
|
||||||
|
continue
|
||||||
|
}
|
||||||
dst.Close()
|
dst.Close()
|
||||||
src.Close()
|
src.Close()
|
||||||
return
|
return
|
||||||
@ -310,6 +335,9 @@ func (n *NetForward) copy(dst, src net.Conn) {
|
|||||||
for {
|
for {
|
||||||
count, err := dst.Read(bufsize)
|
count, err := dst.Read(bufsize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if n.IgnoreEof && err == io.EOF {
|
||||||
|
continue
|
||||||
|
}
|
||||||
src.Close()
|
src.Close()
|
||||||
dst.Close()
|
dst.Close()
|
||||||
return
|
return
|
||||||
|
35
netforward/setcpinfo_darwin.go
Normal file
35
netforward/setcpinfo_darwin.go
Normal file
@ -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
|
||||||
|
}
|
39
netforward/setcpinfo_linux.go
Normal file
39
netforward/setcpinfo_linux.go
Normal file
@ -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
|
||||||
|
}
|
33
netforward/setcpinfo_windows.go
Normal file
33
netforward/setcpinfo_windows.go
Normal file
@ -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)
|
||||||
|
}
|
@ -28,6 +28,8 @@ var useHTML bool
|
|||||||
var user, pwd, server string
|
var user, pwd, server string
|
||||||
var skipInsecure, usingFile bool
|
var skipInsecure, usingFile bool
|
||||||
var useTLS int
|
var useTLS int
|
||||||
|
var hostname string
|
||||||
|
var autoHostname bool
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Cmd.Flags().BoolVarP(&usingFile, "file", "F", false, "using file")
|
Cmd.Flags().BoolVarP(&usingFile, "file", "F", false, "using file")
|
||||||
@ -45,6 +47,8 @@ func init() {
|
|||||||
Cmd.Flags().StringVarP(&server, "server", "S", "127.0.0.1:25", "server")
|
Cmd.Flags().StringVarP(&server, "server", "S", "127.0.0.1:25", "server")
|
||||||
Cmd.Flags().IntVarP(&useTLS, "tls", "l", 0, "use tls,1 means use tls,2 means use starttls,other means not use tls")
|
Cmd.Flags().IntVarP(&useTLS, "tls", "l", 0, "use tls,1 means use tls,2 means use starttls,other means not use tls")
|
||||||
Cmd.Flags().BoolVarP(&skipInsecure, "skip-insecure", "i", false, "skip insecure")
|
Cmd.Flags().BoolVarP(&skipInsecure, "skip-insecure", "i", false, "skip insecure")
|
||||||
|
Cmd.Flags().StringVarP(&hostname, "hostname", "n", "", "hostname")
|
||||||
|
Cmd.Flags().BoolVarP(&autoHostname, "auto-hostname", "N", false, "auto hostname")
|
||||||
}
|
}
|
||||||
|
|
||||||
func run() {
|
func run() {
|
||||||
@ -112,16 +116,28 @@ func run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if autoHostname && hostname == "" {
|
||||||
|
hostname = strings.Split(server, ":")[0]
|
||||||
|
}
|
||||||
var auth smtp.Auth
|
var auth smtp.Auth
|
||||||
if user != "" && pwd != "" {
|
if user != "" && pwd != "" {
|
||||||
auth = smtp.PlainAuth("", user, pwd, server)
|
auth = smtp.PlainAuth("", user, pwd, hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch useTLS {
|
switch useTLS {
|
||||||
case 1:
|
case 1:
|
||||||
err = mail.SendWithTLS(server, auth, &tls.Config{InsecureSkipVerify: skipInsecure})
|
starlog.Noticef("Mail send method:TLS InsecureSkipVerify:%v ServerName:%v\n", skipInsecure, hostname)
|
||||||
|
err = mail.SendWithTLS(server, auth, &tls.Config{
|
||||||
|
InsecureSkipVerify: skipInsecure,
|
||||||
|
ServerName: hostname,
|
||||||
|
})
|
||||||
case 2:
|
case 2:
|
||||||
err = mail.SendWithStartTLS(server, auth, &tls.Config{InsecureSkipVerify: skipInsecure})
|
starlog.Noticef("Mail send method:StartTLS InsecureSkipVerify:%v ServerName:%v\n", skipInsecure, hostname)
|
||||||
|
err = mail.SendWithStartTLS(server, auth, &tls.Config{InsecureSkipVerify: skipInsecure,
|
||||||
|
ServerName: hostname})
|
||||||
default:
|
default:
|
||||||
|
starlog.Noticef("Mail send method:Normal\n")
|
||||||
err = mail.Send(server, auth)
|
err = mail.Send(server, auth)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
188
tls/cert.go
188
tls/cert.go
@ -9,18 +9,33 @@ import (
|
|||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/net/idna"
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var hideDetail bool
|
var hideDetail bool
|
||||||
var dump string
|
var dump string
|
||||||
|
var reqRawIP int
|
||||||
|
var timeoutMillSec int
|
||||||
|
var socks5 string
|
||||||
|
var socks5Auth string
|
||||||
|
var showCA bool
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Cmd.Flags().BoolVarP(&hideDetail, "hide-detail", "H", false, "隐藏证书详细信息")
|
Cmd.Flags().BoolVarP(&hideDetail, "hide-detail", "H", false, "隐藏证书详细信息")
|
||||||
Cmd.Flags().StringVarP(&dump, "dump", "d", "", "将证书保存到文件")
|
Cmd.Flags().StringVarP(&dump, "dump", "d", "", "将证书保存到文件")
|
||||||
|
Cmd.Flags().IntVarP(&reqRawIP, "resolve-ip", "r", 0, "使用解析到的IP地址进行连接,输入数字表示使用解析到的第几个IP地址")
|
||||||
|
Cmd.Flags().IntVarP(&timeoutMillSec, "timeout", "t", 5000, "连接超时时间(毫秒)")
|
||||||
|
Cmd.Flags().StringVarP(&socks5, "socks5", "p", "", "socks5代理,示例:127.0.0.1:1080")
|
||||||
|
Cmd.Flags().StringVarP(&socks5Auth, "socks5-auth", "A", "", "socks5代理认证,示例:username:password")
|
||||||
|
Cmd.Flags().BoolVarP(&showCA, "show-ca", "c", false, "显示CA证书")
|
||||||
}
|
}
|
||||||
|
|
||||||
var Cmd = &cobra.Command{
|
var Cmd = &cobra.Command{
|
||||||
@ -29,25 +44,155 @@ var Cmd = &cobra.Command{
|
|||||||
Long: "查看TLS证书信息",
|
Long: "查看TLS证书信息",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
for _, target := range args {
|
for _, target := range args {
|
||||||
showTls(target, !hideDetail, dump)
|
showTls(target, !hideDetail, showCA, reqRawIP, dump, time.Duration(timeoutMillSec)*time.Millisecond)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func showTls(target string, showDetail bool, dumpPath string) {
|
func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath string, timeout time.Duration) {
|
||||||
if !strings.Contains(target, ":") {
|
var err error
|
||||||
target += ":443"
|
{
|
||||||
|
sp := strings.Split(target, ":")
|
||||||
|
if len(sp) < 2 {
|
||||||
|
target = target + ":443"
|
||||||
|
} else {
|
||||||
|
if _, err := strconv.Atoi(sp[len(sp)-1]); err != nil {
|
||||||
|
target = target + ":443"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if timeout == 0 {
|
||||||
|
timeout = 5 * time.Second
|
||||||
|
}
|
||||||
|
hostname := strings.Split(target, ":")[0]
|
||||||
|
if strings.Count(target, ":") == 2 {
|
||||||
|
strs := strings.Split(target, ":")
|
||||||
|
if len(strs) != 3 {
|
||||||
|
starlog.Errorln("invalid target format")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
target = strs[0] + ":" + strs[2]
|
||||||
|
hostname = strs[1]
|
||||||
|
}
|
||||||
|
if reqRawIP > 0 {
|
||||||
|
domain := strings.Split(target, ":")[0]
|
||||||
|
ips, err := net.LookupIP(domain)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("failed to resolve domain: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(ips) == 0 {
|
||||||
|
starlog.Errorln("no ip found for domain")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, v := range ips {
|
||||||
|
starlog.Infof("解析到的IP地址为: %s\n", v.String())
|
||||||
|
}
|
||||||
|
if reqRawIP > len(ips) {
|
||||||
|
reqRawIP = len(ips)
|
||||||
|
}
|
||||||
|
target = ips[reqRawIP-1].String() + ":443"
|
||||||
|
hostname = ips[reqRawIP-1].String()
|
||||||
|
starlog.Noticeln("使用解析到的IP地址进行连接:", target)
|
||||||
|
}
|
||||||
|
starlog.Noticef("将使用如下地址连接:%s ; ServerName: %s\n", target, hostname)
|
||||||
|
punyCode, err := idna.ToASCII(hostname)
|
||||||
|
if err == nil {
|
||||||
|
if punyCode != hostname {
|
||||||
|
starlog.Infoln("检测到域名中含有非ASCII字符,PunyCode转换后为:", punyCode)
|
||||||
|
hostname = punyCode
|
||||||
|
}
|
||||||
}
|
}
|
||||||
starlog.Infof("正在连接服务器: %s\n", target)
|
starlog.Infof("正在连接服务器: %s\n", target)
|
||||||
conn, err := tls.Dial("tcp", target, &tls.Config{
|
var netDialer = &net.Dialer{
|
||||||
InsecureSkipVerify: true,
|
Timeout: timeout,
|
||||||
})
|
}
|
||||||
if err != nil {
|
var socksDialer *proxy.Dialer
|
||||||
starlog.Errorln("failed to connect: " + err.Error())
|
if socks5 != "" {
|
||||||
return
|
var auth *proxy.Auth
|
||||||
|
if socks5Auth != "" {
|
||||||
|
up := strings.SplitN(socks5Auth, ":", 2)
|
||||||
|
if len(up) == 2 {
|
||||||
|
auth = &proxy.Auth{
|
||||||
|
User: up[0],
|
||||||
|
Password: up[1],
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
starlog.Errorln("socks5认证格式错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s5Dial, err := proxy.SOCKS5("tcp", socks5, auth, proxy.Direct)
|
||||||
|
if err == nil {
|
||||||
|
socksDialer = &s5Dial
|
||||||
|
} else {
|
||||||
|
starlog.Errorln("socks5代理错误:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var verifyErr error
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
var conn *tls.Conn
|
||||||
|
if socksDialer == nil {
|
||||||
|
conn, verifyErr = tls.DialWithDialer(netDialer, "tcp", target, &tls.Config{
|
||||||
|
InsecureSkipVerify: false,
|
||||||
|
ServerName: hostname,
|
||||||
|
MinVersion: tls.VersionSSL30,
|
||||||
|
})
|
||||||
|
if verifyErr == nil {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
con, err := (*socksDialer).Dial("tcp", target)
|
||||||
|
if err != nil {
|
||||||
|
verifyErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn = tls.Client(con, &tls.Config{
|
||||||
|
InsecureSkipVerify: false,
|
||||||
|
ServerName: hostname,
|
||||||
|
MinVersion: tls.VersionSSL30,
|
||||||
|
})
|
||||||
|
verifyErr = conn.Handshake()
|
||||||
|
con.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var conn *tls.Conn
|
||||||
|
|
||||||
|
if socksDialer == nil {
|
||||||
|
conn, err = tls.DialWithDialer(netDialer, "tcp", target, &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: hostname,
|
||||||
|
MinVersion: tls.VersionSSL30,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("failed to connect: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
con, err := (*socksDialer).Dial("tcp", target)
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("failed to connect: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer con.Close()
|
||||||
|
conn = tls.Client(con, &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: hostname,
|
||||||
|
MinVersion: tls.VersionSSL30,
|
||||||
|
})
|
||||||
|
err = conn.Handshake()
|
||||||
|
if err != nil {
|
||||||
|
starlog.Errorln("failed to handshake: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
starlog.Infoln("连接成功,正在获取证书信息")
|
starlog.Infof("连接成功,对方IP:%s,正在获取证书信息\n", conn.RemoteAddr().String())
|
||||||
certs := conn.ConnectionState().PeerCertificates
|
certs := conn.ConnectionState().PeerCertificates
|
||||||
if len(certs) == 0 {
|
if len(certs) == 0 {
|
||||||
starlog.Errorln("no certificate found")
|
starlog.Errorln("no certificate found")
|
||||||
@ -58,11 +203,11 @@ func showTls(target string, showDetail bool, dumpPath string) {
|
|||||||
|
|
||||||
switch state.Version {
|
switch state.Version {
|
||||||
case tls.VersionSSL30:
|
case tls.VersionSSL30:
|
||||||
starlog.Infoln("当前TLS版本: SSL 3.0")
|
starlog.Warningln("当前TLS版本: SSL 3.0")
|
||||||
case tls.VersionTLS10:
|
case tls.VersionTLS10:
|
||||||
starlog.Infoln("当前TLS版本: TLS 1.0")
|
starlog.Warningln("当前TLS版本: TLS 1.0")
|
||||||
case tls.VersionTLS11:
|
case tls.VersionTLS11:
|
||||||
starlog.Infoln("当前TLS版本: TLS 1.1")
|
starlog.Warningln("当前TLS版本: TLS 1.1")
|
||||||
case tls.VersionTLS12:
|
case tls.VersionTLS12:
|
||||||
starlog.Infoln("当前TLS版本: TLS 1.2")
|
starlog.Infoln("当前TLS版本: TLS 1.2")
|
||||||
case tls.VersionTLS13:
|
case tls.VersionTLS13:
|
||||||
@ -123,13 +268,22 @@ func showTls(target string, showDetail bool, dumpPath string) {
|
|||||||
starlog.Infoln("当前加密套件:", state.CipherSuite)
|
starlog.Infoln("当前加密套件:", state.CipherSuite)
|
||||||
}
|
}
|
||||||
starlog.Infoln("服务器名称:", state.ServerName)
|
starlog.Infoln("服务器名称:", state.ServerName)
|
||||||
|
wg.Wait()
|
||||||
|
if verifyErr != nil {
|
||||||
|
starlog.Red("证书验证失败: " + verifyErr.Error())
|
||||||
|
} else {
|
||||||
|
starlog.Green("证书验证成功")
|
||||||
|
}
|
||||||
if showDetail {
|
if showDetail {
|
||||||
for _, c := range certs {
|
for _, c := range certs {
|
||||||
if c.IsCA {
|
if c.IsCA && !showCA {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fmt.Printf("----------\n证书基础信息: %+v\n", c.Subject)
|
fmt.Printf("----------\n")
|
||||||
|
if c.IsCA {
|
||||||
|
fmt.Println("!这是一个CA证书!")
|
||||||
|
}
|
||||||
|
fmt.Printf("证书基础信息: %+v\n", c.Subject)
|
||||||
fmt.Printf("证书颁发者: %+v\n", c.Issuer)
|
fmt.Printf("证书颁发者: %+v\n", c.Issuer)
|
||||||
fmt.Printf("证书生效时间: %+v 距今:%.1f天\n", c.NotBefore.In(time.Local), time.Since(c.NotBefore).Hours()/24)
|
fmt.Printf("证书生效时间: %+v 距今:%.1f天\n", c.NotBefore.In(time.Local), time.Since(c.NotBefore).Hours()/24)
|
||||||
fmt.Printf("证书过期时间: %+v 剩余:%.1f天\n", c.NotAfter.In(time.Local), c.NotAfter.Sub(time.Now()).Hours()/24)
|
fmt.Printf("证书过期时间: %+v 剩余:%.1f天\n", c.NotAfter.In(time.Local), c.NotAfter.Sub(time.Now()).Hours()/24)
|
||||||
|
33
whois/cmd.go
33
whois/cmd.go
@ -1,19 +1,28 @@
|
|||||||
package whois
|
package whois
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"b612.me/starlog"
|
||||||
"b612.me/staros"
|
"b612.me/staros"
|
||||||
"github.com/likexian/whois"
|
"github.com/likexian/whois"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var timeout int
|
var timeout int
|
||||||
var output string
|
var output string
|
||||||
|
var whoisServer []string
|
||||||
|
var socks5 string
|
||||||
|
var socks5Auth string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Cmd.Flags().IntVarP(&timeout, "timeout", "t", 20, "超时时间")
|
Cmd.Flags().IntVarP(&timeout, "timeout", "t", 20, "超时时间")
|
||||||
Cmd.Flags().StringVarP(&output, "output", "o", "", "输出文件夹")
|
Cmd.Flags().StringVarP(&output, "output", "o", "", "输出文件夹")
|
||||||
|
Cmd.Flags().StringSliceVarP(&whoisServer, "server", "s", nil, "whois服务器")
|
||||||
|
Cmd.Flags().StringVarP(&socks5, "socks5", "p", "", "socks5代理,示例:127.0.0.1:1080")
|
||||||
|
Cmd.Flags().StringVarP(&socks5Auth, "socks5-auth", "A", "", "socks5代理认证,示例:username:password")
|
||||||
}
|
}
|
||||||
|
|
||||||
var Cmd = &cobra.Command{
|
var Cmd = &cobra.Command{
|
||||||
@ -30,9 +39,31 @@ var Cmd = &cobra.Command{
|
|||||||
output = ""
|
output = ""
|
||||||
}
|
}
|
||||||
c := whois.NewClient()
|
c := whois.NewClient()
|
||||||
|
if socks5 != "" {
|
||||||
|
var auth *proxy.Auth
|
||||||
|
if socks5Auth != "" {
|
||||||
|
up := strings.SplitN(socks5Auth, ":", 2)
|
||||||
|
if len(up) == 2 {
|
||||||
|
auth = &proxy.Auth{
|
||||||
|
User: up[0],
|
||||||
|
Password: up[1],
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
starlog.Errorln("socks5认证格式错误")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s5Dial, err := proxy.SOCKS5("tcp", socks5, auth, proxy.Direct)
|
||||||
|
if err == nil {
|
||||||
|
c.SetDialer(s5Dial)
|
||||||
|
} else {
|
||||||
|
starlog.Errorln("socks5代理错误:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
c.SetTimeout(time.Second * time.Duration(timeout))
|
c.SetTimeout(time.Second * time.Duration(timeout))
|
||||||
for _, v := range args {
|
for _, v := range args {
|
||||||
data, err := c.Whois(v)
|
data, err := c.Whois(v, whoisServer...)
|
||||||
cmd.Println("Query:", v)
|
cmd.Println("Query:", v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cmd.Println("查询失败:", err)
|
cmd.Println("查询失败:", err)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user