-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
186 lines (154 loc) · 4.23 KB
/
main.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package main
import (
"flag"
"fmt"
"log"
"net"
"os"
"os/signal"
"sync"
"time"
)
// Session is the UDP session info
type Session struct {
clientAddr *net.UDPAddr
serverConn *net.UDPConn
timeout time.Time
}
// Forwarder is the info of forwarder
type Forwarder struct {
fromAddr *net.UDPAddr
toAddr *net.UDPAddr
localConn *net.UDPConn
sessions map[string]*Session
mu sync.Mutex
timeout time.Duration
}
func main() {
// Parse command line arguments
fromAddrStr := flag.String("from", "127.0.0.1:8080", "UDP address to forward from")
toAddrStr := flag.String("to", "127.0.0.1:9090", "UDP address to forward to")
timeout := flag.Duration("timeout", 60*time.Second, "Timeout for inactive sessions")
flag.Parse()
fromAddr, err := net.ResolveUDPAddr("udp", *fromAddrStr)
if err != nil {
log.Fatal("Error resolving UDP address:", err)
}
toAddr, err := net.ResolveUDPAddr("udp", *toAddrStr)
if err != nil {
log.Fatal("Error resolving UDP address:", err)
}
// Create and start the UDP forwarder with a timeout
forwarder := NewForwarder(fromAddr, toAddr, *timeout)
go forwarder.Start()
// Wait for a termination signal
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
<-signalChan
// Stop the forwarder on termination signal
forwarder.Stop()
log.Println("UDP forwarder stopped")
}
// NewForwarder creates a new UDP forwarder with a timeout feature
func NewForwarder(fromAddr, toAddr *net.UDPAddr, timeout time.Duration) *Forwarder {
localConn, err := net.ListenUDP("udp", fromAddr)
if err != nil {
log.Fatal("Error listening on UDP address:", err)
}
return &Forwarder{
fromAddr: fromAddr,
toAddr: toAddr,
localConn: localConn,
sessions: make(map[string]*Session),
timeout: timeout,
}
}
// Start starts the UDP forwarder with a timeout feature
func (f *Forwarder) Start() {
log.Printf("UDP forwarder started - From: %v, To: %v, Timeout: %v\n", f.fromAddr, f.toAddr, f.timeout)
buffer := make([]byte, 1500)
// Periodically clean up inactive sessions
go func() {
for range time.Tick(f.timeout / 2) {
f.cleanupInactiveSessions()
}
}()
for {
n, clientAddr, err := f.localConn.ReadFromUDP(buffer)
if err != nil {
log.Println("Error reading from UDP:", err)
continue
}
clientKey := fmt.Sprintf("%s:%d", clientAddr.IP.String(), clientAddr.Port)
f.mu.Lock()
session, ok := f.sessions[clientKey]
if !ok {
serverConn, err := net.DialUDP("udp", nil, f.toAddr)
if err != nil {
log.Println("Error connecting to server:", err)
f.mu.Unlock()
continue
}
session = &Session{
clientAddr: clientAddr,
serverConn: serverConn,
timeout: time.Now().Add(f.timeout),
}
f.sessions[clientKey] = session
// Log new connection
log.Printf("New session established with client: %s\n", clientKey)
go f.handleSession(clientKey, session)
} else {
// Update session timeout for active sessions
session.timeout = time.Now().Add(f.timeout)
}
f.mu.Unlock()
// Forward the UDP packet to the server
_, err = session.serverConn.Write(buffer[:n])
if err != nil {
log.Println("Error forwarding UDP packet:", err)
}
}
}
// cleanupInactiveSessions closes inactive sessions
func (f *Forwarder) cleanupInactiveSessions() {
f.mu.Lock()
defer f.mu.Unlock()
now := time.Now()
for key, session := range f.sessions {
if session.timeout.Before(now) {
log.Printf("Cleaning up inactive session %s\n", key)
session.serverConn.Close()
delete(f.sessions, key)
}
}
}
// handleSession handles a UDP session
func (f *Forwarder) handleSession(clientKey string, session *Session) {
buffer := make([]byte, 1500)
for {
n, _, err := session.serverConn.ReadFromUDP(buffer)
if err != nil {
log.Printf("Session %s closed\n", clientKey)
f.mu.Lock()
delete(f.sessions, clientKey)
f.mu.Unlock()
session.serverConn.Close()
return
}
// Forward the UDP packet back to the client
_, err = f.localConn.WriteToUDP(buffer[:n], session.clientAddr)
if err != nil {
log.Println("Error forwarding UDP packet to client:", err)
}
}
}
// Stop stops the UDP forwarder
func (f *Forwarder) Stop() {
f.mu.Lock()
defer f.mu.Unlock()
for _, session := range f.sessions {
session.serverConn.Close()
}
f.localConn.Close()
}