V3 release

This commit is contained in:
Eliezer Croitoru 2026-09-09 16:09:08 +03:00
parent 4d67f8be82
commit db9f887958
4 changed files with 33 additions and 17 deletions

View File

@ -6,12 +6,9 @@ COPY src/ .
RUN go mod init ngtech.co.il/network/livtrace/v2 && go mod tidy
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build -ldflags="-s -w" -o /out/livetrace-linux-amd64 .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o /out/livetrace-linux-amd64 .
RUN CGO_ENABLED=0 GOOS=windows GOARCH=amd64 \
go build -ldflags="-s -w" -o /out/livetrace-windows-amd64.exe .
RUN CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o /out/livetrace-windows-amd64.exe .
# Stage 2: Export target
FROM scratch AS bin
COPY --from=builder /out/ /

Binary file not shown.

Binary file not shown.

View File

@ -295,12 +295,16 @@ func NewTracer(
func (t *Tracer) Done() <-chan struct{} { return t.stopCh }
func (t *Tracer) Start() error {
var err error
if t.proto == "winapi" {
// Windows ICMP API manages its own sockets per probe.
// No raw socket, no receive loop, no cleanup loop needed.
go t.probeLoop()
return nil
}
// ICMP socket — always required (receiving ICMP errors, and sending in ICMP mode).
var err error
t.icmpConn, err = icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err != nil {
// Fallback: unprivileged ICMP dgram (Linux ≥5.x with ping_group_range).
t.icmpConn, err = icmp.ListenPacket("udp4", "0.0.0.0:0")
if err != nil {
hint := "try: sudo ./livetrace"
@ -312,7 +316,6 @@ func (t *Tracer) Start() error {
}
t.icmpPC = t.icmpConn.IPv4PacketConn()
// UDP sending socket — only needed in UDP mode.
if t.proto == "udp" {
t.udpSend, err = net.ListenPacket("udp4", ":0")
if err != nil {
@ -334,7 +337,9 @@ func (t *Tracer) Stop() {
default:
close(t.stopCh)
}
_ = t.icmpConn.Close()
if t.icmpConn != nil {
_ = t.icmpConn.Close()
}
if t.udpSend != nil {
_ = t.udpSend.Close()
}
@ -386,9 +391,12 @@ func (t *Tracer) makeUDPBytes() []byte {
// ─── Sending ──────────────────────────────────────────────────────────────────
func (t *Tracer) sendProbe(ttl int) {
if t.proto == "udp" {
switch t.proto {
case "udp":
t.sendProbeUDP(ttl)
} else {
case "winapi":
t.sendProbeWinAPI(ttl)
default:
t.sendProbeICMP(ttl)
}
}
@ -449,6 +457,12 @@ func (t *Tracer) sendProbeUDP(ttl int) {
}
}
func winAPIProbe(_ net.IP, _ int, _ time.Duration, _ []byte) (float64, string, uint32, error) {
return 0, "", 0, fmt.Errorf("winapi probe not supported on this platform")
}
func (t *Tracer) sendProbeWinAPI(_ int) {}
// ─── Probe loop ───────────────────────────────────────────────────────────────
func (t *Tracer) probeLoop() {
@ -898,7 +912,7 @@ func main() {
maxHops := flag.Int("m", 30, "maximum hops")
intervalMS := flag.Int("i", 1000, "probe interval in milliseconds")
timeoutMS := flag.Int("t", 3000, "probe timeout in milliseconds")
proto := flag.String("proto", "icmp", "probe protocol: icmp or udp")
proto := flag.String("proto", "icmp", "probe protocol: icmp, udp, or winapi (Windows ICMP API, Windows only)")
port := flag.Int("port", 33434, "base destination port (UDP mode only)")
size := flag.Int("size", defPktSize, "total IP packet size in bytes (min 28); use 1500 for MTU test")
noDNS := flag.Bool("n", false, "disable reverse DNS (show numeric IPs only)")
@ -930,10 +944,15 @@ Examples:
}
p := strings.ToLower(*proto)
if p != "icmp" && p != "udp" {
fmt.Fprintln(os.Stderr, "Error: -proto must be icmp or udp")
os.Exit(1)
}
if p != "icmp" && p != "udp" && p != "winapi" {
fmt.Fprintln(os.Stderr, "Error: -proto must be icmp, udp, or winapi")
os.Exit(1)
}
if p == "winapi" && runtime.GOOS != "windows" {
fmt.Fprintln(os.Stderr, "Error: -proto winapi is only available on Windows")
os.Exit(1)
}
tracer, err := NewTracer(
flag.Arg(0),