mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-08-07 05:38:30 +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:
69
src/mod/netutils/netutils.go
Normal file
69
src/mod/netutils/netutils.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"imuslab.com/zoraxy/mod/utils"
|
||||
)
|
||||
|
||||
/*
|
||||
This script handles basic network utilities like
|
||||
- traceroute
|
||||
- ping
|
||||
*/
|
||||
|
||||
func HandleTraceRoute(w http.ResponseWriter, r *http.Request) {
|
||||
targetIpOrDomain, err := utils.GetPara(r, "target")
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, "invalid target (domain or ip) address given")
|
||||
return
|
||||
}
|
||||
|
||||
maxhopsString, err := utils.GetPara(r, "maxhops")
|
||||
if err != nil {
|
||||
maxhopsString = "64"
|
||||
}
|
||||
|
||||
maxHops, err := strconv.Atoi(maxhopsString)
|
||||
if err != nil {
|
||||
maxHops = 64
|
||||
}
|
||||
|
||||
results, err := TraceRoute(targetIpOrDomain, maxHops)
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
js, _ := json.Marshal(results)
|
||||
utils.SendJSONResponse(w, string(js))
|
||||
}
|
||||
|
||||
func TraceRoute(targetIpOrDomain string, maxHops int) ([]string, error) {
|
||||
return traceroute(targetIpOrDomain, maxHops)
|
||||
}
|
||||
|
||||
func HandlePing(w http.ResponseWriter, r *http.Request) {
|
||||
targetIpOrDomain, err := utils.GetPara(r, "target")
|
||||
if err != nil {
|
||||
utils.SendErrorResponse(w, "invalid target (domain or ip) address given")
|
||||
return
|
||||
}
|
||||
|
||||
results := []string{}
|
||||
for i := 0; i < 4; i++ {
|
||||
realIP, pingTime, ttl, err := PingIP(targetIpOrDomain)
|
||||
if err != nil {
|
||||
results = append(results, "Reply from "+realIP+": "+err.Error())
|
||||
} else {
|
||||
results = append(results, fmt.Sprintf("Reply from %s: Time=%dms TTL=%d", realIP, pingTime.Milliseconds(), ttl))
|
||||
}
|
||||
}
|
||||
|
||||
js, _ := json.Marshal(results)
|
||||
utils.SendJSONResponse(w, string(js))
|
||||
|
||||
}
|
28
src/mod/netutils/netutils_test.go
Normal file
28
src/mod/netutils/netutils_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package netutils_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"imuslab.com/zoraxy/mod/netutils"
|
||||
)
|
||||
|
||||
func TestHandleTraceRoute(t *testing.T) {
|
||||
results, err := netutils.TraceRoute("imuslab.com", 64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Log(results)
|
||||
}
|
||||
|
||||
func TestHandlePing(t *testing.T) {
|
||||
ipOrDomain := "example.com"
|
||||
|
||||
realIP, pingTime, ttl, err := netutils.PingIP(ipOrDomain)
|
||||
if err != nil {
|
||||
t.Fatal("Error:", err)
|
||||
return
|
||||
}
|
||||
|
||||
t.Log(realIP, pingTime, ttl)
|
||||
}
|
48
src/mod/netutils/pingip.go
Normal file
48
src/mod/netutils/pingip.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func PingIP(ipOrDomain string) (string, time.Duration, int, error) {
|
||||
ipAddr, err := net.ResolveIPAddr("ip", ipOrDomain)
|
||||
if err != nil {
|
||||
return "", 0, 0, fmt.Errorf("failed to resolve IP address: %v", err)
|
||||
}
|
||||
|
||||
ip := ipAddr.IP.String()
|
||||
|
||||
start := time.Now()
|
||||
|
||||
conn, err := net.Dial("ip:icmp", ip)
|
||||
if err != nil {
|
||||
return ip, 0, 0, fmt.Errorf("failed to establish ICMP connection: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
icmpMsg := []byte{8, 0, 0, 0, 0, 1, 0, 0}
|
||||
_, err = conn.Write(icmpMsg)
|
||||
if err != nil {
|
||||
return ip, 0, 0, fmt.Errorf("failed to send ICMP message: %v", err)
|
||||
}
|
||||
|
||||
reply := make([]byte, 1500)
|
||||
err = conn.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||
if err != nil {
|
||||
return ip, 0, 0, fmt.Errorf("failed to set read deadline: %v", err)
|
||||
}
|
||||
|
||||
_, err = conn.Read(reply)
|
||||
if err != nil {
|
||||
return ip, 0, 0, fmt.Errorf("failed to read ICMP reply: %v", err)
|
||||
}
|
||||
|
||||
elapsed := time.Since(start)
|
||||
pingTime := elapsed.Round(time.Millisecond)
|
||||
|
||||
ttl := int(reply[8])
|
||||
|
||||
return ip, pingTime, ttl, nil
|
||||
}
|
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