Skip to content

Commit dccc41b

Browse files
committed
udp mode增加mutex 以避免固定端口时的端口竞争问题
1 parent 9af629b commit dccc41b

File tree

2 files changed

+81
-69
lines changed

2 files changed

+81
-69
lines changed

trace/udp_ipv4.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type UDPTracer struct {
3232

3333
sem *semaphore.Weighted
3434
fetchLock sync.Mutex
35+
udpMutex sync.Mutex
3536
}
3637

3738
func (t *UDPTracer) Execute() (*Result, error) {
@@ -192,6 +193,11 @@ func (t *UDPTracer) send(ttl int) error {
192193
return nil
193194
}
194195

196+
if util.GetenvDefault("NEXTTRACE_RANDOMPORT", "") == "" {
197+
t.udpMutex.Lock()
198+
defer t.udpMutex.Unlock()
199+
}
200+
195201
srcIP, srcPort, udpConn, err := t.getUDPConn(0)
196202
if err != nil {
197203
return err

trace/udp_ipv6.go

Lines changed: 75 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type UDPTracerIPv6 struct {
3232

3333
sem *semaphore.Weighted
3434
fetchLock sync.Mutex
35+
udpMutex sync.Mutex
3536
}
3637

3738
func (t *UDPTracerIPv6) Execute() (*Result, error) {
@@ -118,7 +119,7 @@ func (t *UDPTracerIPv6) listenICMP() {
118119
}
119120

120121
// handleICMPMessage 处理 ICMPv6 消息并提取 UDP 源端口
121-
//
122+
//
122123
// ICMPv6 错误消息格式:
123124
// - ICMPv6 头部 (8 字节)
124125
// - 原始 IPv6 包 (包含 IPv6 头部和 UDP 头部)
@@ -131,74 +132,74 @@ func (t *UDPTracerIPv6) listenICMP() {
131132
// 5. 提取 UDP 源端口
132133
// 6. 发送结果到对应通道
133134
func (t *UDPTracerIPv6) handleICMPMessage(msg ReceivedMessage) {
134-
// ICMPv6 错误消息至少需要包含 IPv6 头部(40字节)和部分 UDP 头部
135-
if len(msg.Msg) < 48 {
136-
return
137-
}
138-
139-
// 尝试解析 ICMPv6 消息中包含的原始数据包
140-
var offset int = 8 // ICMPv6 头部长度
141-
142-
// 检查剩余长度是否足够包含 IPv6 头部
143-
if len(msg.Msg) < offset+40 {
144-
return
145-
}
146-
147-
// 验证 IPv6 版本 (前4位应该是6)
148-
if (msg.Msg[offset] >> 4) != 6 {
149-
return
150-
}
151-
152-
// 获取下一个头部类型
153-
nextHeader := msg.Msg[offset+6]
154-
155-
// 跳过 IPv6 基本头部
156-
offset += 40
157-
158-
// 处理可能的扩展头部
159-
for nextHeader != 17 && offset+2 < len(msg.Msg) { // 17 是 UDP 协议号
160-
switch nextHeader {
161-
case 0: // Hop-by-Hop Options
162-
case 43: // Routing
163-
case 44: // Fragment
164-
case 50: // ESP
165-
case 51: // AH
166-
case 60: // Destination Options
167-
if offset+2 >= len(msg.Msg) {
168-
return // 不够长,无法读取扩展头部长度
169-
}
170-
nextHeader = msg.Msg[offset]
171-
headerLen := int(msg.Msg[offset+1])*8 + 8
172-
offset += headerLen
173-
default:
174-
// 未知或不支持的扩展头部类型
175-
return
176-
}
177-
}
178-
179-
// 确认下一个头部是 UDP (17)
180-
if nextHeader != 17 {
181-
return
182-
}
183-
184-
// 确保有足够的数据来读取 UDP 源端口
185-
if offset+2 > len(msg.Msg) {
186-
return
187-
}
188-
189-
// 从 UDP 头部提取源端口(前2字节)
190-
srcPort := int(uint16(msg.Msg[offset])<<8 | uint16(msg.Msg[offset+1]))
191-
192-
t.inflightRequestLock.Lock()
193-
defer t.inflightRequestLock.Unlock()
194-
ch, ok := t.inflightRequest[srcPort]
195-
if !ok {
196-
return
197-
}
198-
ch <- Hop{
199-
Success: true,
200-
Address: msg.Peer,
201-
}
135+
// ICMPv6 错误消息至少需要包含 IPv6 头部(40字节)和部分 UDP 头部
136+
if len(msg.Msg) < 48 {
137+
return
138+
}
139+
140+
// 尝试解析 ICMPv6 消息中包含的原始数据包
141+
var offset int = 8 // ICMPv6 头部长度
142+
143+
// 检查剩余长度是否足够包含 IPv6 头部
144+
if len(msg.Msg) < offset+40 {
145+
return
146+
}
147+
148+
// 验证 IPv6 版本 (前4位应该是6)
149+
if (msg.Msg[offset] >> 4) != 6 {
150+
return
151+
}
152+
153+
// 获取下一个头部类型
154+
nextHeader := msg.Msg[offset+6]
155+
156+
// 跳过 IPv6 基本头部
157+
offset += 40
158+
159+
// 处理可能的扩展头部
160+
for nextHeader != 17 && offset+2 < len(msg.Msg) { // 17 是 UDP 协议号
161+
switch nextHeader {
162+
case 0: // Hop-by-Hop Options
163+
case 43: // Routing
164+
case 44: // Fragment
165+
case 50: // ESP
166+
case 51: // AH
167+
case 60: // Destination Options
168+
if offset+2 >= len(msg.Msg) {
169+
return // 不够长,无法读取扩展头部长度
170+
}
171+
nextHeader = msg.Msg[offset]
172+
headerLen := int(msg.Msg[offset+1])*8 + 8
173+
offset += headerLen
174+
default:
175+
// 未知或不支持的扩展头部类型
176+
return
177+
}
178+
}
179+
180+
// 确认下一个头部是 UDP (17)
181+
if nextHeader != 17 {
182+
return
183+
}
184+
185+
// 确保有足够的数据来读取 UDP 源端口
186+
if offset+2 > len(msg.Msg) {
187+
return
188+
}
189+
190+
// 从 UDP 头部提取源端口(前2字节)
191+
srcPort := int(uint16(msg.Msg[offset])<<8 | uint16(msg.Msg[offset+1]))
192+
193+
t.inflightRequestLock.Lock()
194+
defer t.inflightRequestLock.Unlock()
195+
ch, ok := t.inflightRequest[srcPort]
196+
if !ok {
197+
return
198+
}
199+
ch <- Hop{
200+
Success: true,
201+
Address: msg.Peer,
202+
}
202203
}
203204

204205
var cachedLocalPortv6 int
@@ -257,6 +258,11 @@ func (t *UDPTracerIPv6) send(ttl int) error {
257258
return nil
258259
}
259260

261+
if util.GetenvDefault("NEXTTRACE_RANDOMPORT", "") == "" {
262+
t.udpMutex.Lock()
263+
defer t.udpMutex.Unlock()
264+
}
265+
260266
srcIP, srcPort, udpConn, err := t.getUDPConn(0)
261267
if err != nil {
262268
return err

0 commit comments

Comments
 (0)