mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-08-14 08:59:19 +02:00
Updates 2.6.4
+ Added force TLS v1.2 above toggle + Added trace route + Added ICMP ping + Added special routing rules module for up-coming acme integration + Fixed IPv6 check bug in black/whitelist + Optimized UI for TCP Proxy +
This commit is contained in:
212
src/mod/netutils/traceroute.go
Normal file
212
src/mod/netutils/traceroute.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv4"
|
||||
)
|
||||
|
||||
const (
|
||||
protocolICMP = 1
|
||||
)
|
||||
|
||||
// liveTraceRoute return realtime tracing information to live response handler
|
||||
func liveTraceRoute(dst string, maxHops int, liveRespHandler func(string)) error {
|
||||
timeout := time.Second * 3
|
||||
// resolve the host name to an IP address
|
||||
ipAddr, err := net.ResolveIPAddr("ip4", dst)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to resolve IP address for %s: %v", dst, err)
|
||||
}
|
||||
// create a socket to listen for incoming ICMP packets
|
||||
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create ICMP listener: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
id := os.Getpid() & 0xffff
|
||||
seq := 0
|
||||
loop_ttl:
|
||||
for ttl := 1; ttl <= maxHops; ttl++ {
|
||||
// set the TTL on the socket
|
||||
if err := conn.IPv4PacketConn().SetTTL(ttl); err != nil {
|
||||
return fmt.Errorf("failed to set TTL: %v", err)
|
||||
}
|
||||
seq++
|
||||
// create an ICMP message
|
||||
msg := icmp.Message{
|
||||
Type: ipv4.ICMPTypeEcho,
|
||||
Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: id,
|
||||
Seq: seq,
|
||||
Data: []byte("zoraxy_trace"),
|
||||
},
|
||||
}
|
||||
// serialize the ICMP message
|
||||
msgBytes, err := msg.Marshal(nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to serialize ICMP message: %v", err)
|
||||
}
|
||||
// send the ICMP message
|
||||
start := time.Now()
|
||||
if _, err := conn.WriteTo(msgBytes, ipAddr); err != nil {
|
||||
//log.Printf("%d: %v", ttl, err)
|
||||
liveRespHandler(fmt.Sprintf("%d: %v", ttl, err))
|
||||
continue loop_ttl
|
||||
}
|
||||
// listen for the reply
|
||||
replyBytes := make([]byte, 1500)
|
||||
if err := conn.SetReadDeadline(time.Now().Add(timeout)); err != nil {
|
||||
return fmt.Errorf("failed to set read deadline: %v", err)
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
n, peer, err := conn.ReadFrom(replyBytes)
|
||||
if err != nil {
|
||||
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
|
||||
//fmt.Printf("%d: *\n", ttl)
|
||||
liveRespHandler(fmt.Sprintf("%d: *\n", ttl))
|
||||
continue loop_ttl
|
||||
} else {
|
||||
liveRespHandler(fmt.Sprintf("%d: Failed to parse ICMP message: %v", ttl, err))
|
||||
}
|
||||
continue
|
||||
}
|
||||
// parse the ICMP message
|
||||
replyMsg, err := icmp.ParseMessage(protocolICMP, replyBytes[:n])
|
||||
if err != nil {
|
||||
liveRespHandler(fmt.Sprintf("%d: Failed to parse ICMP message: %v", ttl, err))
|
||||
continue
|
||||
}
|
||||
// check if the reply is an echo reply
|
||||
if replyMsg.Type == ipv4.ICMPTypeEchoReply {
|
||||
echoReply, ok := msg.Body.(*icmp.Echo)
|
||||
if !ok || echoReply.ID != id || echoReply.Seq != seq {
|
||||
continue
|
||||
}
|
||||
liveRespHandler(fmt.Sprintf("%d: %v %v\n", ttl, peer, time.Since(start)))
|
||||
break loop_ttl
|
||||
}
|
||||
if replyMsg.Type == ipv4.ICMPTypeTimeExceeded {
|
||||
echoReply, ok := msg.Body.(*icmp.Echo)
|
||||
if !ok || echoReply.ID != id || echoReply.Seq != seq {
|
||||
continue
|
||||
}
|
||||
var raddr = peer.String()
|
||||
names, _ := net.LookupAddr(raddr)
|
||||
if len(names) > 0 {
|
||||
raddr = names[0] + " (" + raddr + ")"
|
||||
} else {
|
||||
raddr = raddr + " (" + raddr + ")"
|
||||
}
|
||||
liveRespHandler(fmt.Sprintf("%d: %v %v\n", ttl, raddr, time.Since(start)))
|
||||
continue loop_ttl
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Standard traceroute, return results after complete
|
||||
func traceroute(dst string, maxHops int) ([]string, error) {
|
||||
results := []string{}
|
||||
timeout := time.Second * 3
|
||||
// resolve the host name to an IP address
|
||||
ipAddr, err := net.ResolveIPAddr("ip4", dst)
|
||||
if err != nil {
|
||||
return results, fmt.Errorf("failed to resolve IP address for %s: %v", dst, err)
|
||||
}
|
||||
// create a socket to listen for incoming ICMP packets
|
||||
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
|
||||
if err != nil {
|
||||
return results, fmt.Errorf("failed to create ICMP listener: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
id := os.Getpid() & 0xffff
|
||||
seq := 0
|
||||
loop_ttl:
|
||||
for ttl := 1; ttl <= maxHops; ttl++ {
|
||||
// set the TTL on the socket
|
||||
if err := conn.IPv4PacketConn().SetTTL(ttl); err != nil {
|
||||
return results, fmt.Errorf("failed to set TTL: %v", err)
|
||||
}
|
||||
seq++
|
||||
// create an ICMP message
|
||||
msg := icmp.Message{
|
||||
Type: ipv4.ICMPTypeEcho,
|
||||
Code: 0,
|
||||
Body: &icmp.Echo{
|
||||
ID: id,
|
||||
Seq: seq,
|
||||
Data: []byte("zoraxy_trace"),
|
||||
},
|
||||
}
|
||||
// serialize the ICMP message
|
||||
msgBytes, err := msg.Marshal(nil)
|
||||
if err != nil {
|
||||
return results, fmt.Errorf("failed to serialize ICMP message: %v", err)
|
||||
}
|
||||
// send the ICMP message
|
||||
start := time.Now()
|
||||
if _, err := conn.WriteTo(msgBytes, ipAddr); err != nil {
|
||||
//log.Printf("%d: %v", ttl, err)
|
||||
results = append(results, fmt.Sprintf("%d: %v", ttl, err))
|
||||
continue loop_ttl
|
||||
}
|
||||
// listen for the reply
|
||||
replyBytes := make([]byte, 1500)
|
||||
if err := conn.SetReadDeadline(time.Now().Add(timeout)); err != nil {
|
||||
return results, fmt.Errorf("failed to set read deadline: %v", err)
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
n, peer, err := conn.ReadFrom(replyBytes)
|
||||
if err != nil {
|
||||
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
|
||||
//fmt.Printf("%d: *\n", ttl)
|
||||
results = append(results, fmt.Sprintf("%d: *", ttl))
|
||||
continue loop_ttl
|
||||
} else {
|
||||
results = append(results, fmt.Sprintf("%d: Failed to parse ICMP message: %v", ttl, err))
|
||||
}
|
||||
continue
|
||||
}
|
||||
// parse the ICMP message
|
||||
replyMsg, err := icmp.ParseMessage(protocolICMP, replyBytes[:n])
|
||||
if err != nil {
|
||||
results = append(results, fmt.Sprintf("%d: Failed to parse ICMP message: %v", ttl, err))
|
||||
continue
|
||||
}
|
||||
// check if the reply is an echo reply
|
||||
if replyMsg.Type == ipv4.ICMPTypeEchoReply {
|
||||
echoReply, ok := msg.Body.(*icmp.Echo)
|
||||
if !ok || echoReply.ID != id || echoReply.Seq != seq {
|
||||
continue
|
||||
}
|
||||
results = append(results, fmt.Sprintf("%d: %v %v", ttl, peer, time.Since(start)))
|
||||
break loop_ttl
|
||||
}
|
||||
if replyMsg.Type == ipv4.ICMPTypeTimeExceeded {
|
||||
echoReply, ok := msg.Body.(*icmp.Echo)
|
||||
if !ok || echoReply.ID != id || echoReply.Seq != seq {
|
||||
continue
|
||||
}
|
||||
var raddr = peer.String()
|
||||
names, _ := net.LookupAddr(raddr)
|
||||
if len(names) > 0 {
|
||||
raddr = names[0] + " (" + raddr + ")"
|
||||
} else {
|
||||
raddr = raddr + " (" + raddr + ")"
|
||||
}
|
||||
results = append(results, fmt.Sprintf("%d: %v %v", ttl, raddr, time.Since(start)))
|
||||
continue loop_ttl
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return results, nil
|
||||
}
|
Reference in New Issue
Block a user