add tcp debug cmd

master
兔子 8 months ago
parent 9b123d8bb9
commit 44678fa0ff

@ -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")
} }

@ -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,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()
},
}

@ -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

@ -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)
}

@ -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 {

@ -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)

@ -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…
Cancel
Save