forked from p1d3er/port_reuse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathport_reuse_linux.go
137 lines (128 loc) · 3.51 KB
/
port_reuse_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package main
import (
"context"
"crypto/md5"
"fmt"
"golang.org/x/sys/unix"
"io"
"net"
"os"
"regexp"
"strconv"
"strings"
"syscall"
"time"
)
var timeout = 1
var lc = net.ListenConfig{
Control: func(network, address string, c syscall.RawConn) error {
var opErr error
if err := c.Control(func(fd uintptr) {
opErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
opErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
}); err != nil {
return err
}
return opErr
},
}
func isIPAddress(ipStr string) bool {
ip := net.ParseIP(ipStr)
return ip != nil
}
func isPort(portStr string) bool {
port, err := strconv.Atoi(portStr)
if err != nil {
return false
}
return port > 0 && port <= 65535
}
func isMD5(input string) bool {
md5Pattern := "^[0-9a-fA-F]{32}$"
regex := regexp.MustCompile(md5Pattern)
return regex.MatchString(input)
}
func main() {
if len(os.Args) <= 5 && len(os.Args) >= 1 {
if os.Args[0] == os.Args[1] {
fmt.Println(os.Args[0] + " [lhost] [reuse prot] [rhost] [rport] [md5(myip)]")
fmt.Println("myip is we link to its md5(IP)")
fmt.Println("Use it carefully and bear the consequences.")
os.Exit(0)
}
fmt.Println("'" + os.Args[0] + "' " + "is not recognized as an internal or external command, operable program or batch file")
os.Exit(0)
}
lhost := os.Args[1]
lprot := os.Args[2]
rhost := os.Args[3]
rport := os.Args[4]
myip := os.Args[5]
if !(isIPAddress(lhost) && isPort(lprot) && isIPAddress(rhost) && isPort(rport) && isMD5(myip)) {
fmt.Println("'" + os.Args[0] + "' " + "is not recognized as an internal or external command, operable program or batch file")
os.Exit(0)
}
if lhost == "0.0.0.0" || lhost == "127.0.0.1" || lhost == rhost {
fmt.Println("lhost cannot be equal to 127.0.0.1,0.0.0.0 and rhost")
os.Exit(0)
} else if lprot == rport && lhost == rhost {
fmt.Println("lprot cannot be equal to 1rport")
os.Exit(0)
} else if myip == lhost || myip == rhost {
fmt.Println("myip cannot be equal to lhost and rhost")
os.Exit(0)
}
laddr := fmt.Sprintf("%s:%s", lhost, lprot)
l, err := lc.Listen(context.Background(), "tcp", laddr)
go func() {
time.Sleep(2 * time.Minute)
l.Close()
if timeout == 1 {
os.Exit(0)
}
}()
if err != nil {
fmt.Println("无法监听端口:", err)
return
}
fmt.Printf("开始监听端口 %s,将转发到 %s:%s\n", lprot, rhost, rport)
for {
clientConn, err := l.Accept()
if err != nil {
continue
}
addr_prot := strings.Split(clientConn.RemoteAddr().String(), ":")
if fmt.Sprintf("%x", md5.Sum([]byte(addr_prot[0]))) == myip {
timeout = 0
go handleClient(clientConn, rhost, rport)
} else {
go handleClient(clientConn, rhost, lprot)
}
}
}
func handleClient(clientConn net.Conn, remoteHost, remotePort string) {
// 连接到目标主机
serverConn, err := net.Dial("tcp", remoteHost+":"+remotePort)
if err != nil {
fmt.Println("连接到目标主机时出错:", err)
clientConn.Close()
return
}
defer serverConn.Close()
// 在 goroutine 中进行双向数据传输
done := make(chan struct{})
go copyData(clientConn, serverConn, done)
go copyData(serverConn, clientConn, done)
// 等待任意一个goroutine完成后关闭另一个连接
<-done
clientConn.Close()
<-done
}
func copyData(dst io.Writer, src io.Reader, done chan<- struct{}) {
buf := make([]byte, 4096) // 使用较大的缓冲区,提高性能
_, err := io.CopyBuffer(dst, src, buf)
if err != nil && err != io.EOF {
fmt.Println("数据传输时出错:", err)
}
done <- struct{}{}
}