Showing preview only (1,202K chars total). Download the full file or copy to clipboard to get everything.
Repository: nxtrace/NTrace-core
Branch: main
Commit: 1cda0e53bb56
Files: 198
Total size: 1.1 MB
Directory structure:
gitextract_otbi_aku/
├── .cross_compile.sh
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build.yml
│ ├── publishNewFormula.yml
│ ├── test.yml
│ └── triggerDebRepo.yml
├── .gitignore
├── AGENTS.md
├── CLAUDE.md
├── LICENSE
├── README.md
├── README_zh_CN.md
├── _config.yml
├── assets/
│ └── windivert/
│ ├── divert.go
│ ├── x64/
│ │ └── WinDivert64.sys
│ └── x86/
│ └── WinDivert32.sys
├── cmd/
│ ├── cmd.go
│ ├── cmd_test.go
│ ├── deploy_disabled.go
│ ├── deploy_full.go
│ ├── flavor_full.go
│ ├── flavor_ntr.go
│ ├── flavor_tiny.go
│ ├── globalping_disabled.go
│ ├── globalping_full.go
│ ├── listen_info_test.go
│ ├── mtr_mode.go
│ ├── mtr_mode_test.go
│ ├── mtr_ui.go
│ ├── mtu_mode.go
│ └── mtu_mode_test.go
├── config/
│ ├── basic.go
│ └── viper.go
├── dn42/
│ ├── dn42.go
│ ├── geofeed.go
│ ├── geofeed_test.go
│ ├── ptr.go
│ └── ptr_test.go
├── fast_trace/
│ ├── basic.go
│ ├── fast_trace ipv6.go
│ ├── fast_trace.go
│ └── fast_trace_test.go
├── geofeed.example.csv
├── go.mod
├── go.sum
├── internal/
│ └── hoprender/
│ └── group.go
├── ipgeo/
│ ├── chunzhen.go
│ ├── dn42.go
│ ├── dn42_test.go
│ ├── ipapicom.go
│ ├── ipdbone.go
│ ├── ipfilter.go
│ ├── ipfilter_test.go
│ ├── ipgeo.go
│ ├── ipgeo_test.go
│ ├── ipinfo.go
│ ├── ipinfoLocal.go
│ ├── ipinsight.go
│ ├── ipsb.go
│ ├── leo.go
│ ├── tokens.go
│ └── tokens_test.go
├── main.go
├── nt_config.yaml
├── nt_install.sh
├── pow/
│ ├── pow.go
│ └── pow_test.go
├── printer/
│ ├── basic.go
│ ├── classic_printer.go
│ ├── easy.go
│ ├── mtr_raw.go
│ ├── mtr_table.go
│ ├── mtr_table_test.go
│ ├── mtr_tui.go
│ ├── mtr_tui_color.go
│ ├── printer.go
│ ├── printer_test.go
│ ├── realtime_common.go
│ ├── realtime_printer.go
│ ├── realtime_printer_router.go
│ ├── tableprinter.go
│ └── tableprinter_test.go
├── ptr.example.csv
├── reporter/
│ ├── reporter.go
│ └── reporter_test.go
├── server/
│ ├── browser_access.go
│ ├── browser_access_test.go
│ ├── cache_handler.go
│ ├── handlers.go
│ ├── mtr.go
│ ├── server.go
│ ├── trace_handler.go
│ ├── trace_handler_test.go
│ ├── web/
│ │ ├── assets/
│ │ │ ├── app.js
│ │ │ ├── mtr_agg.js
│ │ │ ├── mtr_agg.test.cjs
│ │ │ ├── mtr_truncation.test.cjs
│ │ │ ├── style.css
│ │ │ ├── trace_form.js
│ │ │ └── trace_form.test.cjs
│ │ └── index.html
│ ├── ws_handler.go
│ └── ws_handler_test.go
├── trace/
│ ├── cache.go
│ ├── globalping.go
│ ├── globalping_test.go
│ ├── globalping_types.go
│ ├── icmp_ipv4.go
│ ├── icmp_ipv6.go
│ ├── internal/
│ │ ├── icmp_common.go
│ │ ├── icmp_darwin.go
│ │ ├── icmp_decode.go
│ │ ├── icmp_decode_test.go
│ │ ├── icmp_unix.go
│ │ ├── icmp_windows.go
│ │ ├── icmp_windows_test.go
│ │ ├── packet_listener.go
│ │ ├── tcp_common.go
│ │ ├── tcp_darwin.go
│ │ ├── tcp_probe_decode.go
│ │ ├── tcp_probe_decode_test.go
│ │ ├── tcp_unix.go
│ │ ├── tcp_windows.go
│ │ ├── udp_common.go
│ │ ├── udp_darwin.go
│ │ ├── udp_unix.go
│ │ ├── udp_windows.go
│ │ └── windivert_sniff_windows.go
│ ├── mtr_loop_runtime.go
│ ├── mtr_raw.go
│ ├── mtr_raw_test.go
│ ├── mtr_runner.go
│ ├── mtr_runner_test.go
│ ├── mtr_scheduler.go
│ ├── mtr_scheduler_runtime.go
│ ├── mtr_scheduler_test.go
│ ├── mtr_stats.go
│ ├── mtr_stats_helpers.go
│ ├── mtr_stats_test.go
│ ├── mtu/
│ │ ├── decode.go
│ │ ├── decode_test.go
│ │ ├── metadata.go
│ │ ├── metadata_test.go
│ │ ├── runner.go
│ │ ├── runner_test.go
│ │ ├── socket_prober.go
│ │ ├── socket_prober_read_default.go
│ │ ├── socket_prober_read_windows.go
│ │ ├── socket_prober_test.go
│ │ ├── socketopts_darwin.go
│ │ ├── socketopts_linux.go
│ │ ├── socketopts_stub.go
│ │ ├── socketopts_windows.go
│ │ └── types.go
│ ├── packet_size.go
│ ├── packet_size_test.go
│ ├── quic.go
│ ├── tcp_ipv4.go
│ ├── tcp_ipv6.go
│ ├── tcp_match.go
│ ├── tcp_match_test.go
│ ├── temp_printer.go
│ ├── trace.go
│ ├── trace_runtime_test.go
│ ├── udp_ipv4.go
│ └── udp_ipv6.go
├── tracelog/
│ ├── log.go
│ └── log_test.go
├── tracemap/
│ ├── tracemap.go
│ └── tracemap_test.go
├── util/
│ ├── common.go
│ ├── dns_resolver.go
│ ├── dns_resolver_test.go
│ ├── dot.go
│ ├── env.go
│ ├── env_test.go
│ ├── frag.go
│ ├── http_client_geo.go
│ ├── http_client_geo_test.go
│ ├── latency.go
│ ├── latency_test.go
│ ├── pcap.go
│ ├── privilege_stub.go
│ ├── privilege_windows.go
│ ├── trace.go
│ ├── trace_privilege.go
│ ├── trace_privilege_darwin.go
│ ├── trace_privilege_linux.go
│ ├── trace_privilege_stub.go
│ ├── trace_privilege_windows.go
│ ├── trace_test.go
│ ├── udp.go
│ ├── util.go
│ └── util_test.go
└── wshandle/
├── client.go
└── client_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .cross_compile.sh
================================================
#!/usr/bin/env bash
set -Eeuo pipefail
# -------- Config --------
# Usage: .cross_compile.sh [full|tiny|ntr|all] [debug]
# full — build nexttrace (Full, includes WebUI + Globalping + MTR)
# tiny — build nexttrace-tiny (no WebUI, no Globalping, no MTR)
# ntr — build ntr (MTR-only, default MTR mode)
# all — build all three flavors (default)
# debug — enable debug symbols (can combine: .cross_compile.sh all debug)
FLAVOR_ARG="${1:-all}"
DEBUG_MODE="${2:-}"
# Allow "debug" as first arg for backward compat
if [[ "${FLAVOR_ARG}" == "debug" ]]; then
FLAVOR_ARG="all"
DEBUG_MODE="debug"
fi
# Define flavor specs: "bin_name:build_tags"
declare -a FLAVOR_SPECS
case "${FLAVOR_ARG}" in
full) FLAVOR_SPECS=("nexttrace:") ;;
tiny) FLAVOR_SPECS=("nexttrace-tiny:flavor_tiny") ;;
ntr) FLAVOR_SPECS=("ntr:flavor_ntr") ;;
all) FLAVOR_SPECS=("nexttrace:" "nexttrace-tiny:flavor_tiny" "ntr:flavor_ntr") ;;
*)
echo "Usage: $0 [full|tiny|ntr|all] [debug]" >&2
exit 1
;;
esac
TARGET_DIR="dist"
PLATFORMS="linux/386 linux/amd64 linux/arm64 linux/mips linux/mips64 linux/mipsle linux/mips64le linux/loong64 windows/amd64 windows/arm64 openbsd/amd64 openbsd/arm64 freebsd/amd64 freebsd/arm64"
UPX_BIN="${UPX_BIN:-$(command -v upx 2>/dev/null || true)}"
UPX_FLAGS="${UPX_FLAGS:--9}"
# -------- Build metadata (robust) --------
BUILD_VERSION="$(git describe --tags --always 2>/dev/null || true)"
BUILD_VERSION="${BUILD_VERSION:-dev}"
BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
COMMIT_SHA1="$(git rev-parse --short HEAD 2>/dev/null || true)"
COMMIT_SHA1="${COMMIT_SHA1:-unknown}"
# 通用 ldflags(去掉了内部单引号)
LD_BASE="-X github.com/nxtrace/NTrace-core/config.Version=${BUILD_VERSION} \
-X github.com/nxtrace/NTrace-core/config.BuildDate=${BUILD_DATE} \
-X github.com/nxtrace/NTrace-core/config.CommitID=${COMMIT_SHA1} \
-w -s"
GO_BUILD_FLAGS=(-trimpath)
if [[ "${DEBUG_MODE}" == "debug" ]]; then
GO_BUILD_FLAGS=(-trimpath -gcflags "all=-N -l")
fi
# build_one BIN TAGS GOOS GOARCH [EXTRA_ENV...]
build_one() {
local bin="$1" tags="$2" goos="$3" goarch="$4"
shift 4
local target="${TARGET_DIR}/${bin}_${goos}_${goarch}"
local target_arm=""
# Apply extra env vars (e.g. GOARM=7 suffix)
for ev in "$@"; do
local key="${ev%%=*}" val="${ev#*=}"
if [[ "${key}" == "GOARM" ]]; then
target_arm="${val}"
target="${target}v${val}"
elif [[ "${key}" == "GOMIPS" && "${val}" == "softfloat" ]]; then
target="${target}_softfloat"
fi
done
if [[ "${goos}" == "windows" ]]; then
target="${target}.exe"
fi
local tags_flag=()
if [[ -n "${tags}" ]]; then
tags_flag=(-tags "${tags}")
fi
echo "build => ${target} (tags: ${tags:-none})"
env "$@" go build "${GO_BUILD_FLAGS[@]}" "${tags_flag[@]}" -o "${target}" -ldflags "${LD_BASE}"
compress_with_upx "${target}" "${goos}" "${goarch}" "${target_arm}" "quiet"
}
compress_with_upx() {
local binary="${1:-}"
local target_os="${2:-}"
local target_arch="${3:-}"
local target_arm="${4:-}"
local note="${5:-}"
if [[ "${target_os}" != "linux" ]]; then
return
fi
case "${target_arch}" in
386|amd64|arm64)
;;
arm)
if [[ "${target_arm}" != "7" ]]; then
return
fi
;;
*)
return
;;
esac
if [[ -z "${UPX_BIN}" ]]; then
return
fi
if [[ ! -f "${binary}" ]]; then
return
fi
if [[ "${note}" != "quiet" ]]; then
echo "upx => ${binary}"
fi
if ! "${UPX_BIN}" ${UPX_FLAGS} "${binary}" >/dev/null; then
echo "warn: upx failed for ${binary}, keeping uncompressed" >&2
fi
}
if [[ -z "${UPX_BIN}" ]]; then
echo "info: upx not found; set UPX_BIN or install upx to enable binary compression" >&2
else
echo "info: using upx at ${UPX_BIN} with flags ${UPX_FLAGS}" >&2
fi
echo "info: building flavor(s): ${FLAVOR_ARG}" >&2
# -------- Prepare out dir --------
rm -rf -- "${TARGET_DIR}"
mkdir -p -- "${TARGET_DIR}"
# -------- Pure Go targets (CGO off) --------
for pl in ${PLATFORMS}; do
export CGO_ENABLED=0
GOOS="${pl%%/*}"
GOARCH="${pl#*/}"
export GOOS GOARCH
for SPEC in "${FLAVOR_SPECS[@]}"; do
BIN="${SPEC%%:*}"
TAGS="${SPEC#*:}"
build_one "${BIN}" "${TAGS}" "${GOOS}" "${GOARCH}"
done
# Extra soft-float variants for linux/mips and linux/mipsle
if [[ "${GOOS}" == "linux" && ( "${GOARCH}" == "mips" || "${GOARCH}" == "mipsle" ) ]]; then
for SPEC in "${FLAVOR_SPECS[@]}"; do
BIN="${SPEC%%:*}"
TAGS="${SPEC#*:}"
build_one "${BIN}" "${TAGS}" "${GOOS}" "${GOARCH}" "GOMIPS=softfloat"
done
fi
done
# -------- linux/armv7(CGO off)--------
export CGO_ENABLED=0
export GOOS='linux'
export GOARCH='arm'
export GOARM='7'
for SPEC in "${FLAVOR_SPECS[@]}"; do
BIN="${SPEC%%:*}"
TAGS="${SPEC#*:}"
build_one "${BIN}" "${TAGS}" "${GOOS}" "${GOARCH}" "GOARM=7"
done
# -------- Darwin targets with CGO + SDK libpcap --------
if [[ "$(uname)" == "Darwin" ]]; then
if ! command -v xcrun >/dev/null 2>&1; then
echo "error: xcrun not found. Please install Xcode Command Line Tools: xcode-select --install" >&2
exit 1
fi
SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
for GOARCH in amd64 arm64; do
export CGO_ENABLED=1
export GOOS=darwin
export CC=clang
export CXX=clang++
if [[ "${GOARCH}" == "amd64" ]]; then
ARCH_FLAG="-arch x86_64"
else
ARCH_FLAG="-arch arm64"
fi
# 仅提供 SDK/架构/最低系统版本;-lpcap 交由源码中的 #cgo LDFLAGS 处理,避免重复
export CGO_CFLAGS="-isysroot ${SDKROOT} ${ARCH_FLAG} -mmacosx-version-min=11.0"
export CGO_LDFLAGS="-isysroot ${SDKROOT} ${ARCH_FLAG} -mmacosx-version-min=11.0"
for SPEC in "${FLAVOR_SPECS[@]}"; do
BIN="${SPEC%%:*}"
TAGS="${SPEC#*:}"
build_one "${BIN}" "${TAGS}" "${GOOS}" "${GOARCH}"
done
done
# 合并 Universal 2(存在 lipo 才合并)
if command -v lipo >/dev/null 2>&1; then
for SPEC in "${FLAVOR_SPECS[@]}"; do
BIN="${SPEC%%:*}"
if [[ -f "${TARGET_DIR}/${BIN}_darwin_amd64" && -f "${TARGET_DIR}/${BIN}_darwin_arm64" ]]; then
lipo -create -output "${TARGET_DIR}/${BIN}_darwin_universal" \
"${TARGET_DIR}/${BIN}_darwin_amd64" \
"${TARGET_DIR}/${BIN}_darwin_arm64"
echo "build => ${TARGET_DIR}/${BIN}_darwin_universal"
else
echo "warn: missing one of darwin slices for ${BIN}; skip universal lipo." >&2
fi
done
else
echo "warn: lipo not found; skip universal binary." >&2
fi
fi
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
---
name: nexttrace 程序问题
about: "提交一个 nexttrace 的程序问题报告。"
copyright: [v2fly](https://github.com/v2fly)
---
<!--
除非特殊情况,请完整填写所有问题。不按模板发的 issue 将直接被关闭。
如果你遇到的问题不是 nexttrace 的 bug,比如你不清楚如何配置,请在 https://github.com/nxtrace/NTrace-core/discussions 进行讨论。
-->
## 本项目是基于Linux/macOS的,请确认您遇到的问题是否在Linux或macOS上存在。
<!-- 是/否 -->
<!-- 对于只出现在Windows上的问题,本项目有时无法解决,请知悉 -->
## 你正在使用哪个版本的 nexttrace?
<!-- 比如linux_amd64 macOS_arm64 -->
## 你看到的异常现象是什么?
<!-- 请描述具体现象 -->
## 你期待看到的正常表现是怎样的?
## 请附上你的命令
<!-- 提交 issue 前,请隐去您的隐私信息 -->
## 请附上出错时软件输出的错误信息
<!-- 是/否 -->
## 是否查询过本仓库wiki有没有类似错误
<!-- wiki: https://github.com/nxtrace/NTrace-core/wiki -->
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
================================================
FILE: .github/workflows/build.yml
================================================
name: Build & Release
permissions:
contents: read
defaults:
run:
shell: bash
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
workflow_dispatch:
push:
branches: [ main ]
tags: [ "v*" ]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
jobs:
build:
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.allow_fail || false }}
strategy:
fail-fast: false
matrix:
goos: [windows, freebsd, openbsd, linux, dragonfly]
goarch: [amd64, 386]
exclude:
- goarch: 386
goos: dragonfly
include:
- { goos: linux, goarch: arm, goarm: 7 }
- { goos: linux, goarch: arm, goarm: 6 }
- { goos: linux, goarch: arm, goarm: 5 }
- { goos: android, goarch: arm64 }
- { goos: windows, goarch: arm64 }
# windows/arm 已于 Go 1.26 移除
- { goos: linux, goarch: arm64 }
- { goos: linux, goarch: riscv64 }
- { goos: linux, goarch: loong64 }
- { goos: linux, goarch: mips64 }
- { goos: linux, goarch: mips64le }
- { goos: linux, goarch: mipsle }
- { goos: linux, goarch: mips }
- { goos: linux, goarch: mipsle, gomips: softfloat }
- { goos: linux, goarch: mips, gomips: softfloat }
- { goos: linux, goarch: ppc64 }
- { goos: linux, goarch: ppc64le }
- { goos: freebsd, goarch: arm64 }
- { goos: freebsd, goarch: arm, goarm: 7 }
- { goos: linux, goarch: s390x }
- { goos: openbsd, goarch: arm64 }
- { goos: openbsd, goarch: arm, goarm: 7 }
env:
CGO_ENABLED: ${{ matrix.goos == 'android' && 1 || 0 }}
GOOS: ${{ matrix.goos }}
GOARCH: ${{ matrix.goarch }}
GOARM: ${{ matrix.goarm }}
GOMIPS: ${{ matrix.gomips }}
steps:
- name: Checkout codebase
uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
- name: Set up Go (built-in cache)
uses: actions/setup-go@v6
with:
go-version: '1.26.x'
check-latest: true
cache: true
- name: Show Go toolchain info
run: |
set -Eeuo pipefail
go version && go env && echo "Supported targets (dist list):" && go tool dist list | sort -u
- name: Setup Android NDK
if: matrix.goos == 'android'
id: setup-ndk
uses: nttld/setup-ndk@v1
with:
ndk-version: r26d
add-to-path: false
- name: Resolve build metadata
run: |
set -Eeuo pipefail
BUILD_VERSION="$(git describe --tags --always 2>/dev/null || echo dev)"
BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
COMMIT_SHA1="$(git rev-parse --short HEAD 2>/dev/null || echo unknown)"
ARM_SUFFIX=""
if [ -n "${GOARM:-}" ]; then ARM_SUFFIX="v${GOARM}"; fi
PLATFORM="${GOOS}_${GOARCH}${ARM_SUFFIX}"
EXT=""
if [ "${GOOS}" = "windows" ]; then EXT=".exe"; fi
SOFT=""
if [ "${GOMIPS:-}" = "softfloat" ]; then SOFT="_softfloat"; fi
if [ "$GOOS" = "android" ]; then
ANDROID_API=21
TOOLCHAIN_BIN="${{ steps.setup-ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin"
export CC="$TOOLCHAIN_BIN/aarch64-linux-android${ANDROID_API}-clang"
echo "CC=${CC}" >> "$GITHUB_ENV"
fi
echo "BUILD_VERSION=${BUILD_VERSION}" >> "$GITHUB_ENV"
echo "BUILD_DATE=${BUILD_DATE}" >> "$GITHUB_ENV"
echo "COMMIT_SHA1=${COMMIT_SHA1}" >> "$GITHUB_ENV"
echo "ARM_SUFFIX=${ARM_SUFFIX}" >> "$GITHUB_ENV"
echo "PLATFORM=${PLATFORM}" >> "$GITHUB_ENV"
echo "EXT=${EXT}" >> "$GITHUB_ENV"
echo "SOFT=${SOFT}" >> "$GITHUB_ENV"
- name: Get project dependencies
run: go mod download
- name: Install UPX (selected Linux targets)
if: >
matrix.goos == 'linux' && (
matrix.goarch == 'amd64' ||
matrix.goarch == '386' ||
matrix.goarch == 'arm64' ||
(matrix.goarch == 'arm' && matrix.goarm == '7')
)
run: |
sudo apt-get update
sudo apt-get install -y upx
- name: Build all flavors
run: |
mkdir -p dist
LD_BASE="-X github.com/nxtrace/NTrace-core/config.Version=${BUILD_VERSION} \
-X github.com/nxtrace/NTrace-core/config.BuildDate=${BUILD_DATE} \
-X github.com/nxtrace/NTrace-core/config.CommitID=${COMMIT_SHA1} \
-w -s"
for SPEC in "nexttrace:" "nexttrace-tiny:flavor_tiny" "ntr:flavor_ntr"; do
BIN="${SPEC%%:*}"
TAGS="${SPEC#*:}"
NAME="${BIN}_${PLATFORM}${EXT}${SOFT}"
BUILD_ARGS=(-trimpath)
if [ -n "$TAGS" ]; then BUILD_ARGS+=( -tags "$TAGS" ); fi
BUILD_ARGS+=( -o "dist/${NAME}" -ldflags "$LD_BASE" )
echo "build => dist/${NAME} (tags: ${TAGS:-none})"
go build "${BUILD_ARGS[@]}"
if command -v upx >/dev/null 2>&1; then
case "${GOOS}-${GOARCH}-${GOARM:-}" in
linux-amd64-*|linux-386-*|linux-arm64-*|linux-arm-7) upx -9 "dist/${NAME}" ;;
*) ;;
esac
fi
done
- name: Verify tiny/ntr decoupling
run: |
set -Eeuo pipefail
for BIN in "nexttrace-tiny" "ntr"; do
FNAME="${BIN}_${PLATFORM}${EXT}${SOFT}"
if go version -m "dist/${FNAME}" 2>/dev/null | grep -qE 'github\.com/gin-gonic/gin|github\.com/jsdelivr/globalping-cli'; then
echo "FAIL: ${FNAME} contains gin or globalping-cli dependency"
exit 1
fi
done
echo "Decoupling check passed"
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: build-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goarm && format('-v{0}', matrix.goarm) || '' }}${{ matrix.gomips && format('-{0}', matrix.gomips) || '' }}
path: dist/
if-no-files-found: error
build-darwin:
runs-on: macos-latest
strategy:
fail-fast: false
matrix: { goarch: [ amd64, arm64 ] }
env:
CGO_ENABLED: 1
GOOS: darwin
GOARCH: ${{ matrix.goarch }}
steps:
- name: Checkout codebase
uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
- name: Set up Go (built-in cache)
uses: actions/setup-go@v6
with:
go-version: '1.26.x'
check-latest: true
cache: true
- name: Show Go toolchain info
run: |
set -Eeuo pipefail
go version && go env && echo "Supported targets (dist list):" && go tool dist list | sort -u
- name: Sanity check (Xcode/SDK/lipo/pcap)
run: |
set -Eeuo pipefail
xcode-select -p
SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
echo "$SDKROOT"
clang --version || true
xcrun -f lipo
command -v lipo >/dev/null || (echo "lipo not found"; exit 1)
test -f "$SDKROOT/usr/include/pcap/pcap.h" || (echo "pcap headers not found in SDK"; exit 1)
- name: Resolve build metadata + Darwin CGO flags
run: |
set -Eeuo pipefail
SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
if [ "${GOARCH}" = "amd64" ]; then ARCH_FLAG="-arch x86_64"; else ARCH_FLAG="-arch arm64"; fi
CC="$(xcrun -f clang)"; CXX="$(xcrun -f clang++)"
echo "CC=${CC}" >> "$GITHUB_ENV"
echo "CXX=${CXX}" >> "$GITHUB_ENV"
echo "CGO_CFLAGS=-isysroot ${SDKROOT} ${ARCH_FLAG} -mmacosx-version-min=11.0" >> "$GITHUB_ENV"
echo "CGO_LDFLAGS=-isysroot ${SDKROOT} ${ARCH_FLAG} -mmacosx-version-min=11.0" >> "$GITHUB_ENV"
BUILD_VERSION="$(git describe --tags --always 2>/dev/null || echo dev)"
BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
COMMIT_SHA1="$(git rev-parse --short HEAD 2>/dev/null || echo unknown)"
echo "BUILD_VERSION=${BUILD_VERSION}" >> "$GITHUB_ENV"
echo "BUILD_DATE=${BUILD_DATE}" >> "$GITHUB_ENV"
echo "COMMIT_SHA1=${COMMIT_SHA1}" >> "$GITHUB_ENV"
- name: Get project dependencies
run: go mod download
- name: Build all flavors (Darwin, CGO+libpcap via SDK)
run: |
mkdir -p dist
LD_BASE="-X github.com/nxtrace/NTrace-core/config.Version=${BUILD_VERSION} \
-X github.com/nxtrace/NTrace-core/config.BuildDate=${BUILD_DATE} \
-X github.com/nxtrace/NTrace-core/config.CommitID=${COMMIT_SHA1} \
-w -s"
for SPEC in "nexttrace:" "nexttrace-tiny:flavor_tiny" "ntr:flavor_ntr"; do
BIN="${SPEC%%:*}"
TAGS="${SPEC#*:}"
NAME="${BIN}_${GOOS}_${GOARCH}"
BUILD_ARGS=(-trimpath)
if [ -n "$TAGS" ]; then BUILD_ARGS+=( -tags "$TAGS" ); fi
BUILD_ARGS+=( -o "dist/${NAME}" -ldflags "$LD_BASE" )
echo "build => dist/${NAME} (tags: ${TAGS:-none})"
go build "${BUILD_ARGS[@]}"
done
- name: Verify tiny/ntr decoupling
run: |
set -Eeuo pipefail
for BIN in "nexttrace-tiny" "ntr"; do
FNAME="${BIN}_${GOOS}_${GOARCH}"
if go version -m "dist/${FNAME}" 2>/dev/null | grep -qE 'github\.com/gin-gonic/gin|github\.com/jsdelivr/globalping-cli'; then
echo "FAIL: ${FNAME} contains gin or globalping-cli dependency"
exit 1
fi
done
echo "Decoupling check passed"
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: build-darwin-${{ matrix.goarch }}
path: dist/
if-no-files-found: error
# Build Universal binaries for all flavors
darwin-universal:
runs-on: macos-latest
needs: [ build-darwin ]
steps:
- name: Download darwin slices (flatten)
uses: actions/download-artifact@v8
with:
pattern: build-darwin-*
merge-multiple: true
path: dist
- name: Make macOS Universal (amd64+arm64) for all flavors
run: |
set -Eeuo pipefail
for BIN in nexttrace nexttrace-tiny ntr; do
AMD64="dist/${BIN}_darwin_amd64"
ARM64="dist/${BIN}_darwin_arm64"
if [ -f "$AMD64" ] && [ -f "$ARM64" ]; then
lipo -create -output "dist/${BIN}_darwin_universal" "$AMD64" "$ARM64"
file "dist/${BIN}_darwin_universal" || true
echo "Built: dist/${BIN}_darwin_universal"
else
echo "Missing darwin slices for ${BIN}; cannot build universal." >&2
exit 1
fi
done
ls -l dist
- name: Upload universal artifacts
uses: actions/upload-artifact@v7
with:
name: build-darwin-universal
path: |
dist/nexttrace_darwin_universal
dist/nexttrace-tiny_darwin_universal
dist/ntr_darwin_universal
if-no-files-found: error
# Download all build artifacts and publish to a single release
release:
runs-on: ubuntu-latest
needs: [ build, build-darwin, darwin-universal ]
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Download all artifacts (flatten)
uses: actions/download-artifact@v8
with:
pattern: build-*
merge-multiple: true
path: dist_release
- name: Show downloaded files
run: |
set -Eeuo pipefail
ls -lah dist_release
test -n "$(find dist_release -type f -print -quit)" || { echo "No artifacts found in dist_release"; exit 1; }
- name: Create GitHub Release (draft)
uses: softprops/action-gh-release@v2
with:
draft: true
name: ${{ github.ref_name }}
tag_name: ${{ github.ref_name }}
files: dist_release/*
token: ${{ secrets.GT_TOKEN }}
fail_on_unmatched_files: true
publish-new-formula:
runs-on: ubuntu-latest
needs: [ release ]
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: config git
run: |
git config --global user.email "${{ secrets.GIT_MAIL }}"
git config --global user.name "${{ secrets.GIT_NAME }}"
- name: Clone repo
run: git clone https://github.com/nxtrace/homebrew-nexttrace.git
- name: Exec script
run: |
set -Eeuo pipefail
cd homebrew-nexttrace
bash genFormula.sh
- name: Git Push
run: |
set -Eeuo pipefail
cd homebrew-nexttrace
git add -A
git commit -m 'Publish a new version with Formula' || true
git remote set-url origin https://${{ secrets.GT_TOKEN }}@github.com/nxtrace/homebrew-nexttrace.git
git push
- run: echo "🍏 This job's status is ${{ job.status }}."
================================================
FILE: .github/workflows/publishNewFormula.yml
================================================
name: Publish New Formula
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Controls when the action will run. Workflow runs when manually triggered using the UI
# or API.
on:
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "greet"
publish-new-formula:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Runs a single command using the runners shell
- name: config git
run: |
git config --global user.email "${{ secrets.GIT_MAIL }}"
git config --global user.name "${{ secrets.GIT_NAME }}"
- name: Clone repo
run: |
git clone https://github.com/nxtrace/homebrew-nexttrace.git
- name: Exec script
run: |
set -Eeuo pipefail
cd homebrew-nexttrace
bash genFormula.sh
# - name: setup SSH keys and known_hosts
# run: |
# mkdir -p ~/.ssh
# ssh-keyscan github.com >> ~/.ssh/known_hosts
# ssh-agent -a $SSH_AUTH_SOCK > /dev/null
# ssh-add - <<< "${{ secrets.ID_RSA }}"
# env:
# SSH_AUTH_SOCK: /tmp/ssh_agent.sock
- name: Git Push
run: |
set -Eeuo pipefail
cd homebrew-nexttrace
git add -A
git commit -m 'Publish a new version with Formula' || true
git remote set-url origin https://${{ secrets.GT_TOKEN }}@github.com/nxtrace/homebrew-nexttrace.git
git push
# env:
# SSH_AUTH_SOCK: /tmp/ssh_agent.sock
- run: echo "🍏 This job's status is ${{ job.status }}."
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
- main
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
pull_request:
types: [opened, synchronize, reopened]
paths:
- "**/*.go"
- "go.mod"
- "go.sum"
- ".github/workflows/*.yml"
workflow_dispatch:
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- name: Checkout codebase
uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
- name: Set up Go (built-in cache)
uses: actions/setup-go@v6
with:
go-version: '1.26.x'
check-latest: true
cache: true
- name: Test with unix
if: ${{ matrix.os != 'windows-latest' }}
shell: bash
run: |
sudo go env -w GOTOOLCHAIN=go1.26.0+auto
sudo go test -v -covermode=count -coverprofile='coverage.out' ./...
- name: Test with windows
if: ${{ matrix.os == 'windows-latest' }}
run: |
go env -w GOTOOLCHAIN=go1.26.0+auto
go test -v -covermode=count -coverprofile="coverage.out" ./...
================================================
FILE: .github/workflows/triggerDebRepo.yml
================================================
name: Trigger Deb Repo
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.release.id }}
cancel-in-progress: true
on:
release:
types: [published, prereleased]
jobs:
trigger-deb-repo:
runs-on: ubuntu-latest
steps:
- env:
GITHUB_TOKEN: ${{ secrets.GT_TOKEN }} # 操作 deb 仓库的 PAT
run: |
curl -X POST -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/repos/nxtrace/nexttrace-debs/actions/workflows/build.yaml/dispatches \
-d '{"ref": "main", "inputs": {"tag": "${{ github.event.release.tag_name }}"}}'
================================================
FILE: .gitignore
================================================
### VisualStudioCode template
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Example user template template
### Example user template
# IntelliJ project files
.idea
*.iml
out
gen
### Go template
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Unignore DLLs under assets/windivert
!assets/windivert/**/*.dll
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
### Windows template
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
### macOS template
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# compile target directory
dist/
NTrace-core
.gocache
.gomodcache
.cache
================================================
FILE: AGENTS.md
================================================
# NTrace-core 项目记忆文件(2026-03 快照,rev-3)
# 供 LLM 在后续会话中快速加载上下文,减少重复分析。
## 项目概览
- 名称:NextTrace (NTrace-core)
- 仓库:github.com/nxtrace/NTrace-core
- 模块:`github.com/nxtrace/NTrace-core`
- 语言:Go(`go 1.26.0`)
- 入口:`main.go -> cmd.Execute()`
- 核心能力:ICMP/TCP/UDP traceroute、GeoIP/RDNS、MTR 连续探测、Web/API、多平台构建
## 构建与测试(必须遵守)
- 常用命令:
- 构建:`go build ./...`
- 测试:`go test ./...`
- 交叉编译脚本:`.cross_compile.sh`
- Darwin 下 `trace/internal/icmp_darwin.go` 已不再使用 `//go:linkname`,改为
`syscall.Socket` + `os.NewFile` + 自定义 `icmpPacketConn`(实现 `net.PacketConn` /
`net.Conn` / `syscall.Conn` + `ReadMsgIP` 以满足 `x/net/internal/socket.ipConn`
接口),并在 `ReadFrom` 中调用 `stripIPv4Header` 剥离 macOS DGRAM ICMP socket
返回的外层 IP 头。
## 当前 CLI 语义(重点)
### 常规 traceroute 路径
- `--table`:现在是"最终汇总表"模式(一次探测完成后输出汇总表),不再是旧的异步 table 刷新模式。
- `--route-path`:仍由 `reporter.New(...).Print()` 负责(与 MTR report 无关)。
### 独立 `--mtu` 路径
- `--mtu`:独立 UDP path-MTU / tracepath 风格模式,不复用普通 `trace.Traceroute` / MTR / Web 路径。
- flavor 可用性:仅 `nexttrace` / `nexttrace-tiny` 包含;`ntr` 不注册该 flag。
- 输出:
- `TTY`:当前 TTL 占位后原地更新,边探测边刷行。
- `非 TTY`:TTL 定稿后逐行流式输出,不使用 renderer 自己的 ANSI 控制序列。
- `--json`:输出独立 mtu schema;`hop.geo` 已存在。
- 参数语义:
- 复用 `--data-provider`、`--language`、`--no-rdns`、`--always-rdns`、`--dot-server`。
- `--mtu` 仍只支持 UDP;显式 `--tcp` 冲突报错。
- Geo/RDNS:
- `trace/mtu` 自带独立 metadata helper,不依赖普通 `trace.Hop.fetchIPData`。
- 流式事件会先输出基础 hop,再在同一 TTL 内补一条带 Geo/RDNS 的 update,最后 `ttl_final` 定稿。
- macOS 上曾有 `Warning: macOS --mtu support is experimental.` 提示,现已删除;不要再假设 CLI 会打印这句。
### `--psize` / `--tos` 语义与平台差异
- `--psize` 现在统一对齐 `mtr -s/--psize`:
- 用户输入语义是“含 IP + 当前探测协议头的总字节数”。
- 内部 `trace.Config.PktSize` 仍保存 payload bytes。
- 未显式传入时,不再固定默认 `52`,而是按协议/IP 族自动取最小合法值:
- ICMPv4 / UDPv4 = `28`
- TCPv4 = `44`
- ICMPv6 = `48`
- UDPv6 = `50`
- TCPv6 = `64`
- 负数 `--psize` 表示“每个 probe 独立随机”,CLI 允许 `--psize -84` 这种写法并会在解析前归一化。
- `--tos` / `-Q`:
- 范围固定 `0..255`。
- `--mtu` 与 Globalping 显式传 `--psize` / `--tos` 会直接报不支持。
- 平台发送路径差异(这是后续判断 bug 的关键记忆):
- Linux / 其他 Unix:
- `ICMP/TCP/UDP` 的 IPv4/IPv6 都走原生 socket/raw socket 路径。
- `--tos` 只是在现有路径上设置 `TOS/TrafficClass`,不会切换实现。
- macOS:
- 与 Linux 类似,`ICMP/TCP/UDP` 的 IPv4/IPv6 都走原生发送路径。
- `--tos` 同样只是在现有路径上设置 `TOS/TrafficClass`。
- Windows:
- `TCP/UDP` 的 IPv4/IPv6 一直走 WinDivert raw send。
- `ICMPv4` 一直走 socket path(`SetTOS` / `SetTTL`)。
- `ICMPv6`:
- 默认或 `--tos 0`:继续走原生 socket path,只设置 `HopLimit`,保持与 `v1.5.2` 一致。
- 非零 `--tos`:切到 WinDivert raw send,直接发送完整 `IPv6 + ICMPv6` 报文,因为 Windows 的 `x/net/ipv6.PacketConn` 不能可靠设置 `TrafficClass`。
- 因此,Windows 上只有“`ICMPv6` 且 `--tos != 0`”这个组合会额外依赖 WinDivert 发送能力;README 中英两份都已写明。
### 间隔默认值(分层体系)
- `-z/--send-time`:每包间隔,默认 `defaultPacketIntervalMs = 50` ms。
- `-i/--ttl-time`:
- **常规 traceroute**:TTL 分组间隔,默认 `defaultTracerouteTTLIntervalMs = 300` ms。
- **MTR 模式**:`normalizeMTRTraceConfig()` 始终覆盖为 `defaultMTRInternalTTLIntervalMs = 0` ms(各 TTL 间不间隔)。
- MTR 每跳探测间隔由 `-i` 显式传值 或 默认 1000ms 决定(见下文 `-q/-i` 语义)。`-z/--send-time` 在 MTR 模式下被忽略。
### MTR 相关参数
- `-t/--mtr`:开启 MTR 交互模式(TTY 全屏 TUI)。
- `-r/--report`:MTR 报告模式(非交互),隐式开启 MTR。
- `-w/--wide`:宽报告模式,隐式等价 `--mtr --report --wide`。
- `--raw`:与 MTR 组合时进入 **MTR raw 流式模式**(`runMTRRaw`),不再与 MTR 冲突。
- 有效 MTR 开关:`effectiveMTR = mtr || report || wide`。
- MTR 三路分支(`chooseMTRRunMode`):
1. `effectiveMTRRaw` → `runMTRRaw`(流式行输出,适合管道/脚本)
2. `effectiveReport` → `runMTRReport`(非交互报告表)
3. 默认 → `runMTRTUI`(全屏 TUI)
- MTR 冲突参数(会直接报错退出):`--table` `--classic` `--json` `--output` `--route-path` `--from` `--fast-trace` `--file` `--deploy`。
- **注意**:`--raw` 不再是冲突参数。
### MTR 中 `-q/-i/-y` 的新语义
- `-q/--queries`:
- 在 MTR report 下表示每跳探测次数,默认 10(仅当用户未显式传 `-q`)。
- 在 MTR TUI 下表示每跳最大探测次数,未显式传时默认无限运行。
- `-i/--ttl-time`:
- 在 MTR 下表示每跳探测间隔毫秒,默认 1000ms(仅当用户未显式传 `-i`)。
- 各 TTL 间内部扫描间隔固定 0ms(`normalizeMTRTraceConfig` 覆盖为 `defaultMTRInternalTTLIntervalMs = 0`)。
- `-z/--send-time` 在 MTR 模式下被忽略。
- `-y/--ipinfo <0..4>`:
- TUI 初始 Host 显示模式,默认 0(IP/PTR only)。
- 0=Base(IP/PTR) 1=ASN 2=City 3=Owner 4=Full
- 仅 TUI 模式生效,report/raw 不受影响。
### MTR report wide / non-wide 区别
- **wide 模式**(`-w` 或 `--mtr --report --wide`):
- 查询 GeoIP,显示完整 host 信息(ASN + geo + MPLS)。
- **非 wide 模式**(`-r` 或 `--mtr --report`):
- `normalizeMTRReportConfig` 设 `IPGeoSource=nil`(不查 geo)、`AlwaysWaitRDNS=true`。
- 显示 `formatCompactReportHost`:仅 IP/PTR + ASN,无 geo 列。
## MTR 运行链路(重要文件)
- 入口与调度:`cmd/mtr_mode.go`(~315 行)
- `runMTRTUI(...)` / `runMTRReport(...)` / `runMTRRaw(...)`
- `normalizeMTRTraceConfig(conf)` / `normalizeMTRReportConfig(conf, wide)`
- `buildAPIInfo(...)` / `buildRawAPIInfoLine(...)`
- MTR CLI 现在统一使用 `signal.NotifyContext(...)` 管理 Ctrl-C / SIGTERM;不再保留额外的 `sigCh` + goroutine 等待器。
- 交互控制:`cmd/mtr_ui.go`
- alternate screen + raw mode
- 输入状态机 `mtrInputParser`(字节流,吞掉 CSI/SS3/OSC/鼠标/焦点等序列)
- Enter/Leave 显式关闭输入扩展模式:1000/1002/1003/1006/1015/1004/2004
- Quit 路径会先判空 `cancel`,因此 `newMTRUI(nil, ...)` / 测试注入 nil 不会 panic。
- 核心探测循环:`trace/mtr_runner.go`
- `RunMTR` / `mtrLoop` / `RunMTRRaw`
- 支持暂停、重置、流式预览(`ProgressThrottle` 默认 200ms)
- ICMP 持久引擎 + TCP/UDP fallback
- 统计聚合:`trace/mtr_stats.go`
- `MTRAggregator` / `MTRHopStat`
- unknown 合并策略:单路径时把 unknown 合并到唯一已知路径,避免同 TTL 分裂成 waiting + 真实 IP 两行
- 输出层:
- TUI:`printer/mtr_tui.go`
- table/report:`printer/mtr_table.go`
- raw 行格式化:`printer.FormatMTRRawLine(rec)`
- TUI 颜色:`printer/mtr_tui_color.go`
## MTR 交互行为(当前)
- `q`/`Q`/`Ctrl-C`:退出
- `p`:暂停
- `SPACE`:恢复
- `r`:重置统计
- `y`:切换 Host 显示模式(IP/PTR → ASN → City → Owner → Full → 循环)
- `n`:切换 Host 基名显示(PTR-or-IP / IP-only)
- `e`:切换 MPLS 标签显示(toggle MPLS on/off)
## MTR 显示与统计规则(当前)
- Host 显示支持 5 种模式(`-y/--ipinfo` 设初始值,`y` 键运行时循环):
- `HostModeBase=0`:仅 IP/PTR,无 ASN 前缀
- `HostModeASN=1` / `HostModeCity=2` / `HostModeOwner=3` / `HostModeFull=4`
- `HostNamePTRorIP` / `HostNameIPOnly`
- 默认语言:`cn`(`--language en` 才优先英文字段)
- waiting 判定:`loss >= 99.95 && IP=="" && Host==""`
- 显示为 `(waiting for reply)`
- 指标列(Loss/Snt/Last/Avg/Best/Wrst/StDev)留空
- TUI Host 对齐(重要,已从 tab 改为手动空格):
- `buildTUIHostParts(stat, mode, nameMode, lang, showIPs)` 生成结构化 parts
- `computeTUIASNWidth(stats, ...)` 扫描所有 hop 确定 ASN 列最大宽度
- `formatTUIHost(parts, asnW)` 用 `padRight(asn, asnW)` + 空格拼接(不用 `\t`)
- ASN 为空但 IP 已知时填 `"AS???"` 占位符,保证列对齐(HostModeBase 除外,该模式不显示 ASN)
- waiting hop 不填占位符
- compact report host(非 wide report):
- `formatCompactReportHost(stat, nameMode, lang)` 仅输出 hostname/IP + ASN
- TUI 其他特性:
- 终端宽度自适应 + CJK 宽度计算(go-runewidth)
- 窄屏右锚定指标区
- 动态 hop 前缀宽度(覆盖 3 位/4 位 TTL)
- MPLS 独立续行显示
- 紧凑指标列宽度:Loss=5 Snt=3 RTT=7 RTTMin=5
## MTR 目的地检测与高 TTL 丢弃
- 当 `knownFinalTTL` 已确定后,所有 `TTL > knownFinalTTL` 的调度槽位被标记为 `disabled`。
- disabled TTL 的探测回包(包括在途探测返回的 dst-ip 回复)**一律丢弃**,不折叠、不计入任何统计。
- **MaxPerHop 上限检查**(`states[originTTL].completed + inFlightCount >= MaxPerHop`):
- 调度时使用 `completed + inFlightCount >= MaxPerHop` 防止超发。
- 完成时仍检查 `completed >= MaxPerHop` 丢弃溢出结果。
- `originTTL < curFinal` 时(更低 TTL 先到 dst-ip → 降低 `knownFinalTTL`):
- 保存 `oldFinal`,更新 `knownFinalTTL = originTTL`,disable 所有 `originTTL+1..maxHops`。
- 调用 `agg.ClearHop(oldFinal)`:清除旧 finalTTL 的聚合数据(避免幽灵行),**不合并**到新 finalTTL。
- 新 finalTTL 由独立的 per-hop 调度器自行积累新鲜探测数据,不存在 Snt 膨胀问题。
- 调度状态(`inFlightCount`/`nextAt`/`consecutiveErrs`)更新在 `originTTL`。
- 统计聚合(`completed++`/`agg.Update`/`onProbe`)均使用 `originTTL`(不再有 `accountTTL` 分离)。
## MTR Per-Hop 调度器关键设计(当前)
- **多 in-flight 探测**:每 TTL 允许最多 `MaxInFlightPerHop`(默认 3)个并发探测。
- `mtrHopState.inFlightCount` 是计数器(非 bool)。
- 这解决了高丢包 hop 因超时阻塞导致 Snt 积累速率远低于低丢包 hop 的问题。
- **nextAt 基于发送时间**:`launchProbe` 时设 `nextAt = now + hopInterval`。
- 不再等探测完成才设 nextAt,调度器可在超时探测还在飞行中时为同一 TTL 发射新探测。
- 这保证了所有 TTL 的 Snt 积累速率大致相同,不受丢包率影响。
- **全局并发限制**:`inFlight`(全局计数器)< `parallelism` 仍然有效。
- **`MaxInFlightPerHop` 配置**:`mtrSchedulerConfig.MaxInFlightPerHop`,默认动态计算。
- 动态默认 = `ceil(Timeout / HopInterval) + 1`(至少 1)。
- 例:`Timeout=2s, HopInterval=1s` → 默认 3;`Timeout=2s, HopInterval=200ms` → 默认 11。
- 用户显式设置 > 0 时优先使用用户值。
## MTR 引擎关键机制(易踩坑)
- 目的地提前停止:
- `knownFinalTTL`(持久缓存)用于缩短后续探测的 TTL 上界;高 TTL 标记 disabled 后不再调度。
- seq 16 位回卷处理:
- `seqWillWrap(...)` 触发 `rotateEngine(...)`
- 轮换 echoID 并重建 listener,协议层隔离新旧回包。
- 额外安全网:
- onICMP 中有 RTT 合理性检查(`<=0` 或 `>timeout` 丢弃)。
- 流式预览:
- 仅已发送 TTL 才会参与预览;未发送 TTL 保持 nil 槽位,避免提前计入 Snt/Loss。
## Web Console / WebSocket(server/)
### WS 架构(`server/ws_handler.go`,~451 行)
- **异步写模型**:`wsTraceSession` 使用 `sendCh`(buffered channel,1024)+ `writeLoop` goroutine。
- 调用方通过 `send(envelope)` 非阻塞投递;channel 满时返回 `errWSSlowConsumer`。
- `writeLoop` 从 `sendCh` 取消息,`SetWriteDeadline` + `WriteJSON`。
- **关闭路径**:
- `closeWithCode(code, reason)`:异常关闭(slow consumer / write error),关 `stopCh` + 发 close frame。
- `finish()`:正常结束,`sendMu` 下关 `sendCh`,等 `writerDone`,再关 conn。
- 两者均幂等(`closeOnce` / `finishOnce`)。
- **可测试性**:`wsConn` 接口 + `fakeWSConn` mock(`server/ws_handler_test.go`)。
- **常量**:`wsSendQueueSize=1024`,`wsWriteTimeout=5s`。
### Web MTR 调度模式(重要变更)
- **已从 round-based 迁移到 per-hop 调度**。
- `runMTRTrace()`:
- 优先读 `HopIntervalMs`,fallback `IntervalMs`,再缺省 1000ms。
- `MaxRounds` → `MaxPerHop`(0 = 无限运行直到客户端断开)。
- 不再使用 legacy round-based 的 `Interval` / `RunRound`。
- `executeMTRRaw()` 两路分支:
- `HopInterval > 0`:per-hop 模式,仅在 LeoMoe/FastIP 初始化阶段短暂加锁;长期探测不再依赖 `SrcDev` / `DisableMPLS` 等进程级全局。
- fallback:legacy round-based 模式(保留兼容),`RunRound` 回调内 per-round 锁定。
- `trace/runMTRRawRoundBased()` 也会先做 `normalizeRuntimeConfig(&cfg)`,因此 legacy raw 路径同样能继承 `SourceDevice`;`DisableMPLS` 不再从全局反向覆盖会话配置。
- `traceRequest` 新增 `HopIntervalMs` 字段(`json:"hop_interval_ms"`),与 `IntervalMs` 解耦。
- 前端 MTR 请求现在发送 `hop_interval_ms=1000`,不再把旧的 `interval_ms=2000` 当默认值。
- 前端 raw 聚合键现在按 TTL 折叠,避免同一 hop 的 timeout / success 被拆成两行。
### 前端渲染节流(`server/web/assets/app.js`)
- MTR raw 消息通过 `scheduleMTRRender()` 节流,最小间隔 100ms,优先 `requestAnimationFrame`。
- `cancelScheduledMTRRender()` 在 `clearResult`、socket close/error 路径调用,避免孤儿回调。
- `flushMTRRender()` 立即执行挂起渲染。
### 其他 server 文件
- `server/server.go`:Gin 路由注册
- `server/handlers.go`:REST 接口
- `server/mtr.go`:MTR 专用 handler 逻辑
- `server/trace_handler.go`:traceroute handler
- `server/cache_handler.go`:缓存
## DoT 与 Geo DNS
- `--dot-server` 不仅影响目标域名解析,也影响 GeoIP API / LeoMoe FastIP 的域名解析链路。
- 关键文件:`util/dns_resolver.go`
- `SetGeoDNSResolver(dotServer)`
- `WithGeoDNSResolver(dotServer, fn)`:为 Web/API 请求提供作用域化的 resolver 切换;不同 resolver 串行切换,相同 resolver 允许安全嵌套,避免 `GetSourceWithGeoDNS` + 外层作用域组合时死锁。
- `geoResolverOverride` 的读写现在也走 `geoMu`,避免测试覆盖 resolver 时的数据竞争。
- `LookupHostForGeo(ctx, host)`:IP 字面量短路 -> DoT -> 失败时按配置 fallback 系统 DNS
- `cmd/cmd.go` 在早期阶段(fast-trace / ws 初始化之前)注入 DoT 解析策略,避免早期分支绕过。
- `server/trace_handler.go` 通过 `ipgeo.GetSourceWithGeoDNS(...)` + `WithGeoDNSResolver(...)` 让 Web/API 请求也遵守 `dot_server`,包括 LeoMoe/FastIP 初始化阶段。
- Geo HTTP 请求统一走 `util.NewGeoHTTPClient(...)`(`util/http_client_geo.go`),其 Transport 现在从默认 Transport `Clone()` 而来,保留代理/HTTP2/连接池等标准行为。
## LeoMoe FastIP 与 MTR 首行
- `util/latency.go`:
- `FastIPMetaCache` 缓存节点元数据(IP/Latency/NodeName)
- `SuppressFastIPOutput` 可抑制彩色横幅
- `GetFastIP(...)` 的 DNS 阶段现在显式受 `timeout` 限制;`FastIPMetaCache` 也改为在 fallback/default IP 决定后再写入,避免缓存空 IP。
- MTR 模式在进入 TUI 前会设 `SuppressFastIPOutput=true`,避免污染主终端历史。
- MTR TUI/report 首行 `APIInfo` 由 `cmd/mtr_mode.go` 的 `buildAPIInfo(...)` 生成(仅 LeoMoeAPI 且有元数据时显示)。
- MTR raw 首行由 `buildRawAPIInfoLine(...)` 生成(格式略不同,包含延迟信息)。
## `--source` / `--dev` 现状
- `--dev` 在 `cmd/cmd.go` 先解析网卡并推导 `srcAddr`(已处理非 `*net.IPNet` 地址类型,避免 panic)。
- `trace.Config` 现在显式携带 `SourceDevice` / `DisableMPLS`,Darwin TCP/UDP 抓包与 MPLS 解析优先走会话级配置,不再依赖 Web 侧临时改写全局变量。
- `trace.Config` 也显式携带 `Context`;`TracerouteWithContext(...)` 通过把上游 ctx 传入各 tracer 的 `signal.NotifyContext(...)` 基底,让 TCP/UDP fallback MTR 可以响应取消。
- Windows TCP 目前仍无法把 `SourceDevice` 映射到 WinDivert 接口选择;当前策略是显式报错拒绝,而不是静默忽略该字段。
- MTR 标题显示源信息来自:
- `--source`(最高优先)
- `--dev` 推导
- UDP dial fallback
- 相关函数:`cmd/mtr_mode.go -> resolveSrcIP(...)`
## CI 与工具链(当前)
- `go.mod`: `go 1.26.0`
- GitHub Actions:
- `.github/workflows/build.yml` 使用 `setup-go@v6` + `go-version: 1.26.x`
- `.github/workflows/test.yml` 使用 `setup-go@v6` + `go-version: 1.26.x`
- test workflow 中 `GOTOOLCHAIN=go1.26.0+auto`
- build matrix 已移除 `windows/arm`
- `.cross_compile.sh` 与 workflow 里的 `go build` 现在都用数组构造 `-tags` 参数,避免 shell word-splitting;脚本也会把当前 `GOARM` 传给 `compress_with_upx`,使 linux/armv7 目标能命中对应压缩分支。
- `ipgeo/ipdbone.go` 不再原地修改全局 `defaultClient.httpClient.Timeout`;超时覆盖会通过克隆 client(复用 token cache / token init,同步替换整个 HTTP client)实现,避免 dial timeout 与 client timeout 脱节。
## 关键文件导航
- CLI 主调度:`cmd/cmd.go`(~855 行)
- MTR 参数/流程:`cmd/mtr_mode.go`(~315 行)
- MTR 交互输入:`cmd/mtr_ui.go`
- MTR 引擎:`trace/mtr_runner.go`
- MTR 聚合:`trace/mtr_stats.go`
- MTR TUI:`printer/mtr_tui.go`(~691 行)
- MTR table/report:`printer/mtr_table.go`(~625 行)
- MTR TUI 颜色:`printer/mtr_tui_color.go`
- WS handler:`server/ws_handler.go`(~449 行)
- 前端:`server/web/assets/app.js`
- Geo DoT 解析:`util/dns_resolver.go`
- Geo HTTP 客户端:`util/http_client_geo.go`
- FastIP:`util/latency.go`
## 2026-03 Gocyclo 重构快照
- 第一波低风险重构已落地:
- `ipgeo.Filter` 改为 CIDR 规则表驱动。
- `util.DomainLookUp` 拆成 resolver / lookup / family filter / interactive select 四段。
- `server.prepareTrace`、`normalizeTarget`、`trace.Traceroute`、`trace.Hop.fetchIPData` 已改成薄协调器。
- `GetMTUByIPForDevice`、`GetICMPResponsePayload`、`parseIPDBOneResponse`、`GlobalpingFormatLocation` 已拆 helper。
- 第二波主流程/输出层已部分落地:
- `cmd.Execute` 已拆成 parser 注册 helper、启动模式 helper、运行时调度 helper。
- `fast_trace.FastTest` / `testFile` 已拆成交互选择、源地址推导、文件目标解析、单目标执行。
- `server.mtrAggregator.Update`、`wshandle.messageSendHandler` 已改成薄入口。
- `printer.RealtimePrinter`、`RealtimePrinterWithRouter`、`tracelog.RealtimePrinter` 现在共用 `internal/hoprender` 的 hop attempt 分组逻辑。
- 第三波协议层已开始落地:
- `trace/internal/icmp_common.go`、`tcp_common.go`、`udp_common.go` 已改成“读包循环 + 共享解码 helper + 回调派发”结构。
- 新增 `trace/internal/icmp_decode.go`,集中处理 ICMPv4/v6 解析、echo reply 匹配、内嵌目标 IP 校验、内嵌 ICMP seq 提取。
- 新增 `trace/internal/icmp_decode_test.go`,覆盖 IPv4/IPv6 echo reply、error payload、目标 IP 校验、内嵌 seq 提取。
- `trace/internal/udp_unix.go` 的 `SendUDP` 已拆成 IPv4/IPv6 独立发送 helper;`trace/udp_ipv4.go` 的 `send()` 也已拆成配额检查、构包、超时守护、发送记账四段。
- Windows 协议层新增 `trace/internal/windivert_sniff_windows.go`,把 WinDivert sniff handle 打开、收包、ICMP/TCP 解码下沉为共享 helper;`icmp_windows.go` / `tcp_windows.go` / `udp_windows.go` 的 sniff 入口已变成薄协调器。
- Darwin `trace/internal/icmp_darwin.go:ListenPacket` 已拆成 socket spec、接口绑定、bind sockaddr、finalize packet conn 四段;`trace/internal/tcp_darwin.go:ListenTCP` 也改成设备选择 + BPF + 共享 TCP reply 解码 helper。
- 新增 `trace/internal/tcp_probe_decode.go` 与 `trace/internal/tcp_probe_decode_test.go`,集中处理 TCP probe reply 的 seq 还原、peer IP 提取与 IPv4/IPv6 解析,供 Darwin/Windows TCP sniff 共用。
- 当前已知剩余高复杂度主要集中在:
- `printer/mtr_*` 渲染层
- `cmd/mtr_ui.go` 输入状态机
- `trace/globalping.go` 的主流程函数
- `trace/mtr_runner.go` 中仍未拆薄的 ICMP round handler(`probeRound` / `onICMP`)
- 少量收尾函数:`fast_trace ipv6.go`、`reporter/reporter.go`、`trace/mtr_raw.go`
## 2026-03 Gocyclo 重构快照(追加)
- MTR 核心热点已完成一轮收敛:
- `trace/mtr_scheduler.go:runMTRScheduler` 已改成薄入口,核心状态与分支移动到 `trace/mtr_scheduler_runtime.go`。
- `trace/mtr_stats.go:Update` / `MigrateStats` 已拆成按 hop 分组、累加器合并、裁剪 helper;新增 `trace/mtr_stats_helpers.go`。
- `trace/mtr_runner.go:mtrLoop` 已改成薄入口,取消/重置/暂停/预览/backoff 分支移动到 `trace/mtr_loop_runtime.go`。
- MTR 输出层与输入层热点也已收敛:
- `printer/mtr_tui.go:mtrTUIRenderWithWidth` 已拆成布局扫描、三行头部构建、host part 预构建、MPLS 续行渲染四段。
- `printer/mtr_table.go` 的 host 组装和 `MTRReportPrint` 已改成共享 host-part 拼接 helper + report header/row helper。
- `cmd/mtr_ui.go:(*mtrInputParser).Feed` 已拆成按状态分发的 parser helper。
- 最后一批业务流程热点也已拆薄:
- `trace/globalping.go:GlobalpingTraceroute` 已拆成 client 构建、measurement 请求、结果解码、hop limit 推导、结果组装五段。
- `trace/mtr_runner.go:(*mtrICMPEngine).onICMP` / `probeRound` 已拆成 reply 校验、notify 清理、目的地 TTL 识别、round 准备、发包 sweep、等待回包、结果构建多个 helper。
- `fast_trace/fast_trace ipv6.go:FastTestv6`、`reporter/reporter.go:generateRouteReportNode`、`trace/mtr_raw.go:buildMTRRawRecordFromProbe` 也已分别拆成选择分发、route-node 属性构建、raw record metadata 填充 helper。
- 当前本地复杂度扫描结果:
- `go run /tmp/checkcyclo.go .` 已无 `>15` 函数输出。
- `go test ./...` 通过。
## 仍需记住的残余风险(非阻断)
- `closeWithCode` 中 `closed.Store(true)` 在 `closeOnce.Do` 外部,理论上有微小竞态窗口(实际无害,因 `sendMu` 保护;且无法简单移入 Once 内部,否则第二个调用者无法设置 closed)。
================================================
FILE: CLAUDE.md
================================================
每次执行命令前均需阅读项目根目录下的 ./AGENTS.md 文件
================================================
FILE: LICENSE
================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.
================================================
FILE: README.md
================================================
<div align="center">
<img src="assets/logo.png" height="200px" alt="NextTrace Logo"/>
</div>
<h1 align="center">
<br>NextTrace<br>
</h1>
<h4 align="center">An open source visual routing tool that pursues light weight, developed using Golang.</h4>
---
<h6 align="center">HomePage: www.nxtrace.org</h6>
<p align="center">
<a href="https://github.com/nxtrace/NTrace-dev/actions">
<img src="https://img.shields.io/github/actions/workflow/status/nxtrace/NTrace-dev/build.yml?branch=main&style=flat-square" alt="Github Actions">
</a>
<a href="https://goreportcard.com/report/github.com/nxtrace/NTrace-dev">
<img src="https://goreportcard.com/badge/github.com/nxtrace/NTrace-dev?style=flat-square">
</a>
<a href="https://github.com/nxtrace/NTrace-dev/releases">
<img src="https://img.shields.io/github/release/nxtrace/NTrace-dev/all.svg?style=flat-square">
</a>
</p>
## IAAS Sponsor
<div style="text-align: center;">
<a href="https://dmit.io">
<img src="https://assets.nxtrace.org/dmit.svg" width="170.7" height="62.9">
</a>
<a href="https://misaka.io" >
<img src="https://assets.nxtrace.org/misaka.svg" width="170.7" height="62.9">
</a>
<a href="https://portal.saltyfish.io" >
<img src="https://assets.nxtrace.org/snapstack.svg" width="170.7" height="62.9">
</a>
</div>
We are extremely grateful to [DMIT](https://dmit.io), [Misaka](https://misaka.io) and [SnapStack](https://portal.saltyfish.io) for providing the network infrastructure that powers this project.
## How To Use
Document Language: English | [简体中文](README_zh_CN.md)
⚠️ Please note: We welcome PR submissions from the community, but please submit your PRs to the [NTrace-dev](https://github.com/nxtrace/NTrace-dev) repository instead of [NTrace-core](https://github.com/nxtrace/NTrace-core) repository.<br>
Regarding the NTrace-dev and NTrace-core repositories:<br>
Both will largely remain consistent with each other. All development work is done within the NTrace-dev repository. The NTrace-dev repository releases new versions first. After running stably for an undetermined period, we will synchronize that version to NTrace-core. This means that the NTrace-dev repository serves as a "beta" or "testing" version.<br>
Please note, there are exceptions to this synchronization. If a version of NTrace-dev encounters a serious bug, NTrace-core will skip that flawed version and synchronize directly to the next version that resolves the issue.
### Automated Install
- Linux
- One-click installation script
```shell
curl -sL https://nxtrace.org/nt | bash
```
- Install nxtrace from the APT repository
- Supports AMD64/ARM64 architectures
```shell
curl -fsSL https://github.com/nxtrace/nexttrace-debs/releases/latest/download/nexttrace-archive-keyring.gpg | sudo tee /etc/apt/keyrings/nexttrace.gpg >/dev/null
echo "Types: deb
URIs: https://github.com/nxtrace/nexttrace-debs/releases/latest/download/
Suites: ./
Signed-By: /etc/apt/keyrings/nexttrace.gpg" | sudo tee /etc/apt/sources.list.d/nexttrace.sources >/dev/null
sudo apt update
sudo apt install nexttrace
```
- APT repository maintained by wcbing and nxtrace
- Arch Linux AUR installation command
- Directly download bin package (only supports amd64)
```shell
yay -S nexttrace-bin
```
- Build from source (only supports amd64)
```shell
yay -S nexttrace
```
- The AUR builds are maintained by ouuan, huyz
- Linuxbrew's installation command
Same as the macOS Homebrew's installation method (homebrew-core version only supports amd64)
- deepin installation command
```shell
apt install nexttrace
```
- [x-cmd](https://www.x-cmd.com/pkg/nexttrace) installation command
```shell
x env use nexttrace
```
- Termux installation command
```shell
pkg install root-repo
pkg install nexttrace
```
- ImmortalWrt installation command
```shell
opkg install nexttrace
```
- macOS
- macOS Homebrew's installation command
- Homebrew-core version
```shell
brew install nexttrace
```
- This repository's ACTIONS automatically built version (updates faster)
```shell
brew tap nxtrace/nexttrace && brew install nxtrace/nexttrace/nexttrace
```
- The homebrew-core build is maintained by chenrui333, please note that this version's updates may lag behind the repository Action automatically version
- Windows
- Windows WinGet installation command
- WinGet version
```powershell
winget install nexttrace
```
- WinGet build maintained by Dragon1573
- Windows Scoop installation command
- Scoop-extras version
```powershell
scoop bucket add extras && scoop install extras/nexttrace
```
- Scoop-extra is maintained by soenggam
Please note, the repositories for all of the above installation methods are maintained by open source enthusiasts. Availability and timely updates are not guaranteed. If you encounter problems, please contact the repository maintainer to solve them, or use the binary packages provided by the official build of this project.
### Manual Install
- Download the precompiled executable
For users not covered by the above methods, please go directly to [Release](https://www.nxtrace.org/downloads) to download the compiled binary executable.
- `Release` provides compiled binary executables for many systems and different architectures. If none are available, you can compile it yourself.
- Some essential dependencies of this project are not fully implemented on `Windows` by `Golang`, so currently, `NextTrace` is in an experimental support phase on the `Windows` platform.
### Build Variants
Starting from this release, NextTrace is published in **three flavors** under the same tag. Choose the one that best fits your use case:
| Feature | `nexttrace` (Full) | `nexttrace-tiny` | `ntr` |
| --------------------- | :----------------: | :--------------: | :----------: |
| Normal traceroute | ✅ | ✅ | — |
| Standalone MTU (`--mtu`) | ✅ | ✅ | — |
| MTR TUI | ✅ | — | ✅ (default) |
| MTR report (`-r`) | ✅ | — | ✅ |
| MTR wide (`-w`) | ✅ | — | ✅ |
| MTR raw (`--raw`) | ✅ | — | ✅ |
| Globalping (`--from`) | ✅ | — | — |
| WebUI (`--deploy`) | ✅ | — | — |
| Fast Trace (`-F`) | ✅ | ✅ | — |
| Default mode | traceroute | traceroute | MTR TUI |
| Binary name | `nexttrace` | `nexttrace-tiny` | `ntr` |
> **Note:** Package managers (Homebrew, AUR, Scoop, etc.) currently install the **Full** (`nexttrace`) version only.
### Feature Matrix
- **`nexttrace`** — Full-featured build. Includes everything: traceroute, MTR, Globalping, and WebUI.
- **`nexttrace-tiny`** — Lightweight build. Normal traceroute only, no MTR / Globalping / WebUI. Suitable for embedded or minimal environments.
- **`ntr`** — MTR-focused build. Runs MTR TUI by default. No Globalping / WebUI; no normal traceroute mode and no standalone `--mtu` mode.
### Manual Build
Build from source with Go 1.22+ installed:
```bash
# Full (all features)
go build -trimpath -o dist/nexttrace -ldflags "-w -s" .
# Tiny (no MTR, no Globalping, no WebUI)
go build -tags flavor_tiny -trimpath -o dist/nexttrace-tiny -ldflags "-w -s" .
# NTR (MTR-only)
go build -tags flavor_ntr -trimpath -o dist/ntr -ldflags "-w -s" .
```
Cross-compile example:
```bash
# Linux arm64, Tiny flavor
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 \
go build -tags flavor_tiny -trimpath -o dist/nexttrace-tiny_linux_arm64 -ldflags "-w -s" .
```
The `tiny` and `ntr` flavors use **compile-time build tags** to exclude modules — this is not a runtime switch. You can verify with `go version -m <binary>` that `gin` and `globalping-cli` are absent from `nexttrace-tiny` and `ntr`.
The `.cross_compile.sh` script supports building flavors:
```bash
./.cross_compile.sh all # Build all three flavors for all platforms
./.cross_compile.sh full # Build only nexttrace (Full)
./.cross_compile.sh tiny # Build only nexttrace-tiny
./.cross_compile.sh ntr # Build only ntr
```
### Release Assets Naming
Release binaries follow this naming convention:
```
{binary}_{os}_{arch}[v{arm}][.exe][_softfloat]
```
Examples:
- `nexttrace_linux_amd64`, `nexttrace-tiny_linux_amd64`, `ntr_linux_amd64`
- `nexttrace_darwin_universal`, `nexttrace-tiny_darwin_universal`, `ntr_darwin_universal`
- `nexttrace_windows_amd64.exe`, `ntr_windows_amd64.exe`
### Get Started
`NextTrace` uses the `ICMP` protocol to perform TraceRoute requests by default, which supports both `IPv4` and `IPv6`
```bash
# IPv4 ICMP Trace
nexttrace 1.0.0.1
# URL
nexttrace http://example.com:8080/index.html?q=1
# Table output (report mode): runs trace once and prints a final summary table
nexttrace --table 1.0.0.1
# Machine-readable output: stdout is a single JSON document
nexttrace --raw 1.0.0.1
nexttrace --json 1.0.0.1
# Realtime trace output to a custom file
nexttrace --output ./trace.log 1.0.0.1
# Realtime trace output to the default log file
nexttrace --output-default 1.0.0.1
# IPv4/IPv6 Resolve Only, and automatically select the first IP when there are multiple IPs
nexttrace --ipv4 g.co
nexttrace --ipv6 g.co
# IPv6 ICMP Trace
nexttrace 2606:4700:4700::1111
# Developer mode: set the ENV variable NEXTTRACE_DEVMODE=1 to make fatal errors panic with a stack trace
export NEXTTRACE_DEVMODE=1
# Set TTL-group interval in normal traceroute mode (default: 300ms)
nexttrace -i 300 1.1.1.1
# Disable Path Visualization With the -M parameter
nexttrace koreacentral.blob.core.windows.net
# MapTrace URL: https://api.nxtrace.org/tracemap/html/c14e439e-3250-5310-8965-42a1e3545266.html
# Disable MPLS display using the --disable-mpls / -e parameter or the NEXTTRACE_DISABLEMPLS environment variable
nexttrace --disable-mpls example.com
export NEXTTRACE_DISABLEMPLS=1
```
PS: The route visualization module is an independent component, You can find its source code at [nxtrace/traceMap](https://github.com/nxtrace/traceMap).
The routing visualization function requires the geographical coordinates of each Hop, but third-party APIs generally do not provide this information, so this function is currently only supported when used with LeoMoeAPI.
#### Mandatory Configuration Steps for `Windows` Users
- **For Normal User Mode:**
Only **ICMP mode** can be used, and the firewall must allow `ICMP/ICMPv6` traffic.
```powershell
netsh advfirewall firewall add rule name="All ICMP v4" dir=in action=allow protocol=icmpv4:any,any
netsh advfirewall firewall add rule name="All ICMP v6" dir=in action=allow protocol=icmpv6:any,any
```
- **For Administrator Mode:**
**TCP/UDP mode** requires `WinDivert`.
**ICMP mode** supports `1=Socket` and `2=WinDivert` (`0=Auto`). If running in Socket mode, the firewall must allow `ICMP/ICMPv6`.
On `Windows`, `ICMPv6` without `--tos` (or with `--tos 0`) keeps using the native Socket send path. A non-zero `ICMPv6 --tos` requires `WinDivert` send support in addition to administrator privilege.
`WinDivert` can be automatically configured using the `--init` parameter.
#### `NextTrace` now supports quick testing, and friends who have a one-time backhaul routing test requirement can use it
```bash
# IPv4 ICMP Fast Test (Beijing + Shanghai + Guangzhou + Hangzhou) in China Telecom / Unicom / Mobile / Education Network
nexttrace --fast-trace
# You can also use TCP SYN for testing
nexttrace --fast-trace --tcp
# You can also quickly test through a customized IP/DOMAIN list file
nexttrace --file /path/to/your/iplist.txt
# CUSTOMIZED IP DOMAIN LIST FILE FORMAT
## One IP/DOMAIN per line + space + description information (optional)
## forExample:
## 106.37.67.1 BEIJING-TELECOM
## 240e:928:101:31a::1 BEIJING-TELECOM
## bj.10086.cn BEIJING-MOBILE
## 2409:8080:0:1::1
## 223.5.5.5
```
#### `NextTrace` already supports route tracing for specified Network Devices
```bash
# Use eth0 network interface
nexttrace --dev eth0 2606:4700:4700::1111
# Use eth0 network interface's IP
# When using the network interface's IP for route tracing, note that the IP type to be traced should be the same as network interface's IP type (e.g. both IPv4)
nexttrace --source 204.98.134.56 9.9.9.9
```
#### `NextTrace` can also use `TCP` and `UDP` protocols to perform `Traceroute` requests
```bash
# TCP SYN Trace
nexttrace --tcp www.bing.com
# You can specify the port by yourself [here is 443], the default port is 80
nexttrace --tcp --port 443 2001:4860:4860::8888
# UDP Trace
nexttrace --udp 1.0.0.1
# You can specify the target port yourself [here it is 5353], the default is port 33494
nexttrace --udp --port 5353 1.0.0.1
# For TCP/UDP Trace, you can specify the source port; by default, a fixed random port is used
# (If you need to use a different random source port for each packet, please set the ENV variable NEXTTRACE_RANDOMPORT, or set the source port to -1)
nexttrace --tcp --source-port 14514 www.bing.com
```
#### `NextTrace` also supports standalone path-MTU discovery mode
```bash
# Tracepath-style UDP PMTU discovery with live hop output
nexttrace --mtu 1.1.1.1
# Reuse the normal GeoIP / RDNS knobs in mtu mode
nexttrace --mtu --data-provider IPInfo --language en 1.1.1.1
# JSON output keeps the standalone mtu schema and now includes hop.geo
nexttrace --mtu --json 1.1.1.1
```
- `--mtu` is an independent UDP-only mode. It does not reuse the normal traceroute engine.
- TTY output updates the current hop in place and adds color for hop state / PMTU highlights; redirected / piped output falls back to finalized line-by-line streaming without ANSI.
- `--mtu --json` prints only the standalone MTU JSON document on stdout.
- GeoIP, RDNS, `--data-provider`, `--language`, `--no-rdns`, `--always-rdns`, and `--dot-server` all apply to this mode.
#### `NextTrace` also supports some advanced functions, such as ttl control, concurrent probe packet count control, mode switching, etc.
```bash
# Display 2 latency samples per hop
nexttrace --queries 2 www.hkix.net
# Allow up to 10 probe packets per hop to collect those samples
# (NextTrace stops earlier if it has already got the replies requested by --queries)
nexttrace --max-attempts 10 www.hkix.net
# or use the ENV variable NEXTTRACE_MAXATTEMPTS to persist across runs
export NEXTTRACE_MAXATTEMPTS=10
# No concurrent probe packets, only one probe packet is sent at a time
nexttrace --parallel-requests 1 www.hkix.net
# Start Trace with TTL of 5, end at TTL of 10
nexttrace --first 5 --max-hops 10 www.decix.net
# In addition, an ENV is provided to set whether to mask the destination IP and omit its hostname
export NEXTTRACE_ENABLEHIDDENDSTIP=1
# Turn off the IP reverse parsing function
nexttrace --no-rdns www.bbix.net
# Set the probe packet size to 1024 bytes (inclusive IP + probe headers)
nexttrace --psize 1024 example.com
# Randomize each probe packet size up to 1500 bytes
nexttrace --psize -1500 example.com
# Set the TOS / traffic class field
nexttrace -Q 46 example.com
# Feature: print Route-Path diagram
# Route-Path diagram example:
# AS6453 Tata Communication「Singapore『Singapore』」
# ╭╯
# ╰AS9299 Philippine Long Distance Telephone Co.「Philippines『Metro Manila』」
# ╭╯
# ╰AS36776 Five9 Inc.「Philippines『Metro Manila』」
# ╭╯
# ╰AS37963 Aliyun「ALIDNS.COM『ALIDNS.COM』」
nexttrace --route-path www.time.com.my
# Disable color output
nexttrace --no-color 1.1.1.1
# or use ENV
export NO_COLOR=1
```
#### Advanced tuning quick guide
| Flag | What it controls | Default / starting point | When to change it |
| --- | --- | --- | --- |
| `--queries` | Samples per hop in normal traceroute; explicit probe count per hop in MTR | traceroute: `3`; MTR report: `10` when omitted; MTR TUI/raw: unlimited when omitted | Raise to `5-10` on unstable paths |
| `--max-attempts` | Hard cap on probe packets per hop | auto-sized from `--queries` | Raise on lossy links when replies arrive slowly |
| `--parallel-requests` | Total in-flight probes across TTLs | `18` | Use `1` on multipath/load-balanced paths; keep `6-18` on stable links |
| `--send-time` | Gap between packets inside one TTL group | `50ms` | Raise to `100-200ms` on rate-limited devices; ignored in MTR |
| `--ttl-time` | Gap between TTL groups in traceroute; per-hop interval in MTR | traceroute: `300ms`; MTR: `1000ms` when omitted | Lower to speed up; raise on remote/rate-limited paths |
| `--timeout` | Per-probe timeout | `1000ms` | Raise to `2000-3000ms` for intercontinental or high-loss paths |
| `--psize` | Probe packet size | Protocol/IP-family minimum | Inclusive IP + probe headers; negative values randomize each probe up to `abs(value)`; sizes above the egress/path MTU may fragment on wire |
| `-Q`, `--tos` | IP TOS / traffic class | `0` | Set DSCP/TOS style marking in the IP header; on Windows only `ICMPv6` with a non-zero value requires `WinDivert` |
These probe knobs are CLI-only today; `nt_config.yaml` does not yet store them. If you want reusable profiles, keep them in shell aliases or small wrapper scripts.
```bash
# Conservative profile for multipath or ECMP networks
nexttrace --parallel-requests 1 --send-time 100 --ttl-time 500 --timeout 2000 example.com
# Faster profile for stable single-path networks
nexttrace --parallel-requests 18 --send-time 20 --ttl-time 150 example.com
# Lossy long-haul profile
nexttrace --queries 5 --max-attempts 10 --timeout 2500 example.com
```
#### `NextTrace` supports MTR (My Traceroute) continuous probing mode
```bash
# MTR mode: continuous probing with ICMP (default), refreshes table in real-time
nexttrace -t 1.1.1.1
# or equivalently:
nexttrace --mtr 1.1.1.1
# MTR mode with TCP SYN probing
nexttrace -t --tcp --port 443 www.bing.com
# MTR mode with UDP probing
nexttrace -t --udp 1.0.0.1
# Set per-hop probe interval (default: 1000ms in MTR; -z/--send-time is ignored in MTR mode)
nexttrace -t -i 500 1.1.1.1
# Limit the max probes per hop (default: infinite in TUI, 10 in report mode)
nexttrace -t -q 20 1.1.1.1
# Report mode: probe each hop N times then print a final summary (like mtr -r)
nexttrace -r 1.1.1.1 # = --mtr --report, 10 probes per hop by default
nexttrace -r -q 5 1.1.1.1 # 5 probes per hop
# Wide report: no host column truncation (like mtr -rw)
nexttrace -w 1.1.1.1 # = --mtr --report --wide
# Show PTR and IP together (PTR first, IP in parentheses) in MTR output
nexttrace --mtr --show-ips 1.1.1.1
nexttrace -r --show-ips 1.1.1.1
nexttrace -w --show-ips 1.1.1.1
# MTR raw stream mode (machine-friendly, one event per line)
nexttrace --mtr --raw 1.1.1.1
nexttrace -r --raw 1.1.1.1
# Combine with other options
nexttrace -t --tcp --max-hops 20 --first 3 --no-rdns 8.8.8.8
```
When running in a terminal (TTY), MTR mode uses an **interactive full-screen TUI**:
- **`q` / `Q`** — quit (restores terminal, no output left behind)
- **`p`** — pause probing
- **`SPACE`** — resume probing
- **`r`** — reset statistics (counters are cleared, display mode is preserved)
- **`y`** — cycle host display mode: ASN → City → Owner → Full
- **`n`** — toggle host name display:
- default: PTR (or IP fallback) ↔ IP only
- with `--show-ips`: PTR (IP) ↔ IP only
- **`e`** — toggle MPLS label display on/off
- The TUI header displays **source → destination**, with `--source`/`--dev` information when specified.
- When using LeoMoeAPI, the preferred API IP address is shown in the header.
- Uses the **alternate screen buffer**, so your previous terminal history is preserved on exit.
- When stdin is not a TTY (e.g. piped), it falls back to a simple table refresh.
The **report mode** (`-r`/`--report`) produces a one-shot summary after all probes complete, suitable for scripting:
```text
Start: 2025-07-14T09:12:00+08:00
HOST: myhost Loss% Snt Last Avg Best Wrst StDev
1. one.one.one.one 0.0% 10 1.23 1.45 0.98 2.10 0.32
2. 10.0.0.2 100.0% 10 0.00 0.00 0.00 0.00 0.00
```
Rows shown as `(waiting for reply)` keep the same table layout; the metric cells on that row are left blank.
In non-wide report mode, NextTrace intentionally keeps the host column compact:
- only `PTR/IP` is shown
- no Geo API lookup is performed
- no ASN / owner / location fields are shown
- MPLS labels are hidden
Wide report mode (`-w` / `--wide`) keeps the current full-information behavior, including Geo-derived fields and MPLS output.
When `--raw` is used together with MTR (`--mtr`, `-r`, or `-w`), NextTrace enters **MTR raw stream mode**.
If the active data provider is `LeoMoeAPI`, NextTrace first prints one uncolored API info preamble line:
```text
[NextTrace API] preferred API IP - [2403:18c0:1001:462:dd:38ff:fe48:e0c5] - 21.33ms - DMIT.NRT
```
After that, it prints one `|`-delimited event per line:
```
4|84.17.33.106|po66-3518.cr01.nrt04.jp.misaka.io|0.27|60068|Japan|Tokyo|Tokyo||cdn77.com|35.6804|139.7690
```
Field order:
`ttl|ip|ptr|rtt|asn|country|prov|city|district|owner|lat|lng`
Timeout rows keep the same 12-column layout:
`ttl|*||||||||||`
In MTR mode (`--mtr`, `-r`, `-w`, including `--raw`), `-i/--ttl-time` sets the **per-hop probe interval**: how long to wait between successive probes to the same hop (default: 1000ms when omitted). `-z/--send-time` is ignored in MTR mode.
> Note: `--show-ips` only takes effect in MTR mode (`--mtr`, `-r`, `-w`); otherwise it is ignored.
>
> Note: `--mtr` cannot be used together with `--table`, `--classic`, `--json`, `--output`, `--output-default`, `--route-path`, `--from`, `--fast-trace`, `--file`, or `--deploy`.
#### `NextTrace` supports users to select their own IP API (currently supports: `LeoMoeAPI`, `IP.SB`, `IPInfo`, `IPInsight`, `IPAPI.com`, `IPInfoLocal`, `CHUNZHEN`)
```bash
# You can specify the IP database by yourself [IP-API.com here], if not specified, LeoMoeAPI will be used
nexttrace --data-provider ip-api.com
## Note There are frequency limits for free queries of the ipinfo and IPInsight APIs. You can purchase services from these providers to remove the limits
## If necessary, you can clone this project, add the token provided by ipinfo or IPInsight and compile it yourself
## Fill the token to: ipgeo/tokens.go
## Note For the offline database IPInfoLocal, please download it manually and rename it to ipinfoLocal.mmdb. (You can download it from here: https://ipinfo.io/signup?ref=free-database-downloads)
## Current directory, nexttrace binary directory and FHS directories (Unix-like) will be searched.
## To customize it, please use environment variables,
export NEXTTRACE_IPINFOLOCALPATH=/xxx/yyy.mmdb
## Please be aware: Due to the serious abuse of IP.SB, you will often be not able to query IP data from this source
## IP-API.com has a stricter restiction on API calls, if you can't query IP data from this source, please try again in a few minutes
# The Pure-FTPd IP database defaults to using http://127.0.0.1:2060 as the query interface. To customize it, please use environment variables
export NEXTTRACE_CHUNZHENURL=http://127.0.0.1:2060
## You can use https://github.com/freshcn/qqwry to build your own Pure-FTPd IP database service
# You can also specify the default IP database by setting an environment variable
export NEXTTRACE_DATAPROVIDER=ipinfo
```
#### `NextTrace` supports mixed parameters and shortened parameters
```bash
Example:
nexttrace --data-provider IPAPI.com --max-hops 20 --tcp --port 443 --queries 5 --no-rdns 1.1.1.1
nexttrace -tcp --queries 2 --parallel-requests 1 --table --route-path 2001:4860:4860::8888
Equivalent to:
nexttrace -d ip-api.com -m 20 -T -p 443 -q 5 -n 1.1.1.1
nexttrace -T -q 2 --parallel-requests 1 --table -P 2001:4860:4860::8888
```
### Globalping
[Globalping](https://globalping.io/) provides access to thousands of community-hosted probes to run network tests and measurements.
Run traceroute from a specified location by using the `--from` flag. The location field accepts continents, countries, regions, cities, ASNs, ISPs, or cloud regions.
```bash
nexttrace google.com --from Germany
nexttrace google.com --from comcast+california
```
A limit of 250 tests per hour is set for all anonymous users. To double the limit to 500 per hour please set the `GLOBALPING_TOKEN` environment variable with your token.
```bash
export GLOBALPING_TOKEN=your_token_here
```
### IP Database
We use [bgp.tools](https://bgp.tools) as a data provider for routing tables.
NextTrace BackEnd is now open-source.
https://github.com/sjlleo/nexttrace-backend
NextTrace `LeoMoeAPI` now utilizes the Proof of Work (POW) mechanism to prevent abuse, where NextTrace introduces the powclient library as a client-side component. Both the POW CLIENT and SERVER are open source, and everyone is welcome to use them. (Please direct any POW module-related questions to the corresponding repositories)
- [GitHub - tsosunchia/powclient: Proof of Work CLIENT for NextTrace](https://github.com/tsosunchia/powclient)
- [GitHub - tsosunchia/powserver: Proof of Work SERVER for NextTrace](https://github.com/tsosunchia/powserver)
All NextTrace IP geolocation `API DEMO` can refer to [here](https://github.com/nxtrace/NTrace-core/blob/main/ipgeo/)
### Environment Variables
NextTrace currently reads the following environment variables. For boolean switches, only `1` and `0` are recognized; other values fall back to the built-in default. For consistency, restart NextTrace after changing them.
#### Core Runtime / Network
| Variable | Default | Description |
| --- | --- | --- |
| `NEXTTRACE_DEVMODE` | `0` | Turn fatal errors into panics with stack traces for debugging. |
| `NEXTTRACE_DEBUG` | unset | Print detected environment values while `GetEnv*` helpers parse them. |
| `NEXTTRACE_DISABLEMPLS` | `0` | Disable MPLS display globally, similar to `--disable-mpls`. |
| `NEXTTRACE_ENABLEHIDDENDSTIP` | `0` | Mask the destination IP and omit its hostname in output. |
| `NEXTTRACE_RANDOMPORT` | `0` | Use a different random source port for each TCP/UDP probe. |
| `NEXTTRACE_MAXATTEMPTS` | auto | Provide a default `--max-attempts` value when the CLI flag is not set. |
| `NEXTTRACE_ICMPMODE` | `0` | Provide a default `--icmp-mode` value (`0=auto`, `1=socket`, `2=WinDivert` on Windows). |
| `NEXTTRACE_UNINTERRUPTED` | `0` | When used together with `--raw`, rerun traceroute continuously instead of stopping after one round. |
| `NEXTTRACE_PROXY` | unset | Outbound proxy URL for HTTP / WebSocket requests used by PoW, Geo APIs, tracemap, etc. |
| `NEXTTRACE_DATAPROVIDER` | unset | Override the default IP geolocation provider (for example `ipinfo`). |
#### Service / Web / Backend
| Variable | Default | Description |
| --- | --- | --- |
| `NEXTTRACE_HOSTPORT` | `api.nxtrace.org` | Override the backend host or `host:port` used by LeoMoeAPI, tracemap, and FastIP flows. |
| `NEXTTRACE_TOKEN` | unset | Pre-supplied LeoMoeAPI bearer token; when present, token fetching via PoW is skipped. |
| `NEXTTRACE_POWPROVIDER` | `api.nxtrace.org` | Select the PoW provider. The built-in non-default alias is `sakura`. |
| `NEXTTRACE_DEPLOY_ADDR` | unset | Default listen address for `--deploy` when `--listen` is not provided. |
| `NEXTTRACE_ALLOW_CROSS_ORIGIN` | `0` | Only for `--deploy`: allow cross-origin browser access to the Web UI / API. Disabled by default for safety. |
#### IP Database / Third-Party Providers
| Variable | Default | Description |
| --- | --- | --- |
| `NEXTTRACE_IPINFOLOCALPATH` | auto search | Full path to `ipinfoLocal.mmdb` for the `IPInfoLocal` provider. |
| `NEXTTRACE_CHUNZHENURL` | `http://127.0.0.1:2060` | Base URL of the Chunzhen lookup service. |
| `NEXTTRACE_IPINFO_TOKEN` | unset | Token for the `IPInfo` provider. |
| `NEXTTRACE_IPINSIGHT_TOKEN` | unset | Token for the `IPInsight` provider. |
| `NEXTTRACE_IPAPI_BASE` | provider built-in URL | Override the base URL used by compatible IP API clients in the current implementation (`IPInfo`, `IPInsight`, `ip-api.com`). |
| `IPDBONE_BASE_URL` | `https://api.ipdb.one` | Override the IPDB.One API base URL. |
| `IPDBONE_API_ID` | unset | IPDB.One API ID. |
| `IPDBONE_API_KEY` | unset | IPDB.One API key. |
| `GLOBALPING_TOKEN` | unset | Authentication token for Globalping; raises the anonymous hourly limit when provided. |
#### Config Discovery
| Variable | Default | Description |
| --- | --- | --- |
| `XDG_CONFIG_HOME` | OS / shell default | If set, NextTrace also searches `$XDG_CONFIG_HOME/nexttrace` for `nt_config.yaml`. |
### For full usage list, please refer to the usage menu
```shell
Usage: nexttrace [-h|--help] [--init] [-4|--ipv4] [-6|--ipv6] [-T|--tcp]
[-U|--udp] [-F|--fast-trace] [-p|--port <integer>]
[--icmp-mode <integer>] [-q|--queries <integer>]
[--max-attempts <integer>] [--parallel-requests <integer>]
[-m|--max-hops <integer>] [-d|--data-provider
(IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal|chunzhen|LeoMoeAPI|leomoeapi|ipdb.one|disable-geoip)]
[--pow-provider (api.nxtrace.org|sakura)] [-n|--no-rdns]
[-a|--always-rdns] [-P|--route-path] [--dn42] [-o|--output
"<value>"] [-O|--output-default] [--table] [--raw]
[-j|--json] [-c|--classic] [-f|--first <integer>] [-M|--map]
[-e|--disable-mpls] [-V|--version]
[-s|--source "<value>"] [--source-port <integer>] [-D|--dev
"<value>"] [--listen "<value>"] [--deploy] [-z|--send-time
<integer>] [-i|--ttl-time <integer>] [--timeout <integer>]
[--psize <integer>] [--dot-server
(dnssb|aliyun|dnspod|google|cloudflare)] [-g|--language
(en|cn)] [-C|--no-color] [--from "<value>"] [-t|--mtr]
[-r|--report] [-w|--wide] [--show-ips] [-y|--ipinfo <integer>]
[--file "<value>"] [TARGET "<value>"]
Arguments:
-h --help Print help information
--init Windows ONLY: Extract WinDivert runtime to
current directory
-4 --ipv4 Use IPv4 only
-6 --ipv6 Use IPv6 only
-T --tcp Use TCP SYN for tracerouting (default
dest-port is 80)
-U --udp Use UDP SYN for tracerouting (default
dest-port is 33494)
-F --fast-trace One-Key Fast Trace to China ISPs
-p --port Set the destination port to use. With
default of 80 for "tcp", 33494 for "udp"
--icmp-mode Windows ONLY: Choose the method to listen
for ICMP packets (1=Socket, 2=WinDivert;
0=Auto)
-q --queries Latency samples per hop. Increase to 5-10
on unstable paths for a steadier view.
Default: 3
--max-attempts Advanced: hard cap on probe packets per
hop. Leave unset for auto sizing; raise on
lossy links if --queries is not enough
--parallel-requests Advanced: total concurrent in-flight
probes across TTLs. Use 1 on
multipath/load-balanced paths; 6-18 is a
good starting range on stable links.
Default: 18
-m --max-hops Set the max number of hops (max TTL to be
reached). Default: 30
-d --data-provider Choose IP Geograph Data Provider [IP.SB,
IPInfo, IPInsight, IP-API.com,
IPInfoLocal, CHUNZHEN, disable-geoip].
Default: LeoMoeAPI
--pow-provider Choose PoW Provider [api.nxtrace.org,
sakura] For China mainland users, please
use sakura. Default: api.nxtrace.org
-n --no-rdns Do not resolve IP addresses to their
domain names
-a --always-rdns Always resolve IP addresses to their
domain names
-P --route-path Print traceroute hop path by ASN and
location
--dn42 DN42 Mode
-o --output Write trace result to FILE
(RealtimePrinter only)
-O --output-default Write trace result to the default log file
(/tmp/trace.log)
--table Output trace results as a final summary
table (traceroute report mode)
--raw Machine-friendly output. With MTR
(--mtr/-r/-w), enables streaming raw event
mode
-j --json Output trace results as JSON
-c --classic Classic Output trace results like
BestTrace
-f --first Start from the first_ttl hop (instead of
1). Default: 1
-M --map Disable Print Trace Map
-e --disable-mpls Disable MPLS
-V --version Print version info and exit
-s --source Use source address src_addr for outgoing
packets
--source-port Use source port src_port for outgoing
packets
-D --dev Use the following Network Devices as the
source address in outgoing packets
--listen Set listen address for web console (e.g.
127.0.0.1:30080)
--deploy Start the Gin powered web console
-z --send-time Advanced: per-packet gap [ms] inside the
same TTL group. Lower is faster; raise to
100-200ms on rate-limited links. Ignored
in MTR mode. Default: 50
-i --ttl-time Advanced: TTL-group interval [ms] in
normal traceroute. In MTR mode
(--mtr/-r/-w, including --raw), this
becomes per-hop probe interval. 500-1000ms
is a good MTR starting range
--timeout Per-probe timeout [ms]. Raise to 2000-3000
on slow intercontinental or high-loss
paths. Default: 1000
--psize Probe packet size in bytes, inclusive IP
and active probe headers. Default is the
minimum legal size for the chosen
protocol and IP family; raise for MTU or
large-packet testing. Negative values
randomize each probe up to abs(value).
-Q --tos Set the IP type-of-service / traffic class
value [0-255]. Default: 0
--dot-server Use DoT Server for DNS Parse [dnssb,
aliyun, dnspod, google, cloudflare]
-g --language Choose the language for displaying [en,
cn]. Default: cn
-C --no-color Disable Colorful Output
--from Run traceroute via Globalping
(https://globalping.io/network) from a
specified location. The location field
accepts continents, countries, regions,
cities, ASNs, ISPs, or cloud regions.
-t --mtr Enable MTR (My Traceroute) continuous
probing mode
-r --report MTR report mode (non-interactive, implies
--mtr); can trigger MTR without --mtr
-w --wide MTR wide report mode (implies --mtr
--report); alone equals --mtr --report
--wide
--show-ips MTR only: display both PTR hostnames and
numeric IPs (PTR first, IP in parentheses)
-y --ipinfo Set initial MTR TUI host info mode (0-4).
TUI only; ignored in --report/--raw.
0:IP/PTR 1:ASN 2:City 3:Owner 4:Full.
Default: 0
--file Read IP Address or domain name from file
TARGET Trace target: IPv4 address (e.g. 8.8.8.8),
IPv6 address (e.g. 2001:db8::1), domain
name (e.g. example.com), or URL (e.g.
https://example.com)
```
## Project screenshot


## OpenTrace
`OpenTrace` is the cross-platform `GUI` version of `NextTrace` developed by @Archeb, bringing a familiar but more powerful user experience.
This software is still in the early stages of development and may have many flaws and errors. We value your feedback.
[https://github.com/Archeb/opentrace](https://github.com/Archeb/opentrace)
## NEXTTRACE WEB API
`NextTraceWebApi` is a web-based server implementation of `NextTrace` in the `MTR` style, offering various deployment options including `Docker`.
For WebSocket continuous tracing, MTR now streams per-event payloads with `type: "mtr_raw"` (instead of periodic `mtr` snapshots).
[https://github.com/nxtrace/nexttracewebapi](https://github.com/nxtrace/nexttracewebapi)
## NextTraceroute
`NextTraceroute` is a root-free Android route tracing application that defaults to using the `NextTrace API`, developed by @surfaceocean.
Thank you to all the test users for your enthusiastic support. This app has successfully passed the closed testing phase and is now officially available on the Google Play Store.
[https://github.com/nxtrace/NextTraceroute](https://github.com/nxtrace/NextTraceroute)
<a href='https://play.google.com/store/apps/details?id=com.surfaceocean.nexttraceroute&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' width="128" height="48" src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png'/></a>
## LeoMoeAPI Credits
NextTrace focuses on Golang Traceroute implementations, and its LeoMoeAPI geolocation information is not supported by raw data, so a commercial version is not possible.
The LeoMoeAPI data is subject to copyright restrictions from multiple data sources, and is only used for the purpose of displaying the geolocation of route tracing.
1. We would like to credit samleong123 for providing nodes in Malaysia, TOHUNET Looking Glass for global nodes, and Ping.sx from Misaka, where more than 80% of reliable calibration data comes from ping/mtr reports.
2. At the same time, we would like to credit isyekong for their contribution to rDNS-based calibration ideas and data. LeoMoeAPI is accelerating the development of rDNS resolution function, and has already achieved automated geolocation resolution for some backbone networks, but there are some misjudgments. We hope that NextTrace will become a One-Man ISP-friendly traceroute tool in the future, and we are working on improving the calibration of these ASN micro-backbones as much as possible.
3. In terms of development, I would like to credit missuo and zhshch for their help with Go cross-compilation, design concepts and TCP/UDP Traceroute refactoring, and tsosunchia for their support on TraceMap.
4. I would also like to credit FFEE_CO, TheresaQWQ, stydxm and others for their help. LeoMoeAPI has received a lot of support since its first release, so I would like to credit them all!
We hope you can give us as much feedback as possible on IP geolocation errors (see issue) so that it can be calibrated in the first place and others can benefit from it.
## Cloudflare Support
This project is sponsored by [Project Alexandria](http://www.cloudflare.com/oss-credits).
<img src="https://cf-assets.www.cloudflare.com/slt3lc6tev37/2I3y49Uz9Y61lBS0kIPZu6/db6df1e6f99a8659267c442b75a0dff9/image.png" alt="Cloudflare Logo" width="331">
## AIWEN TECH Support
This project is sponsored by [AIWEN TECH](https://www.ipplus360.com). We’re pleased to enhance the accuracy and completeness of this project’s GEOIP lookups using `AIWEN TECH City-Level IP Database`, and to make it freely available to the public.
<img src="https://www.ipplus360.com/img/LOGO.c86cd0e1.svg" title="" alt="AIWEN TECH IP Geolocation Data" width="331">
## JetBrain Support
This Project uses [JetBrain Open-Source Project License](https://jb.gg/OpenSourceSupport). We Proudly Develop By `Goland`.
<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/GoLand.png" title="" alt="GoLand logo" width="331">
## Credits
[Gubo](https://www.gubo.org) Reliable Host Recommendation Website
[IPInfo](https://ipinfo.io) Provided most of the data support for this project free of charge
[BGP.TOOLS](https://bgp.tools) Provided some data support for this project free of charge
[PeeringDB](https://www.peeringdb.com) Provided some data support for this project free of charge
[Globalping](https://globalping.io) An open-source and free project that provides global access to run network tests like traceroute
[sjlleo](https://github.com/sjlleo) The perpetual leader, founder, and core contributors
[tsosunchia](https://github.com/tsosunchia) The project chair, infra maintainer, and core contributors
[Yunlq](https://github.com/Yunlq) An active community contributor
[Vincent Young](https://github.com/missuo)
[zhshch2002](https://github.com/zhshch2002)
[Sam Sam](https://github.com/samleong123)
[waiting4new](https://github.com/waiting4new)
[FFEE_CO](https://github.com/fkx4-p)
[bobo liu](https://github.com/fakeboboliu)
[YekongTAT](https://github.com/isyekong)
### Others
- Although other third-party APIs are integrated in this project, please refer to the official website of the third-party APIs for specific TOS and AUP. If you encounter IP data errors, please contact them directly to correct them.
- For feedback related to corrections about IP information, we currently have two channels available:
> - [IP 错误报告汇总帖](https://github.com/orgs/nxtrace/discussions/222) in the GITHUB ISSUES section of this project (Recommended)
> - This project's dedicated correction email: `correct#nxtrace.org` (Please note that this email is only for correcting IP-related information. For other feedback, please submit an ISSUE)
- How to obtain the freshly baked binary executable of the latest commit?
> Please go to the most recent [Build & Release](https://github.com/nxtrace/NTrace-dev/actions/workflows/build.yml) workflow in GitHub Actions.
- Common questions
- On Windows, ICMP mode requires manual firewall allowance for ICMP/ICMPv6
- On macOS, only ICMP mode does not require elevated privileges
- In some cases, running multiple instances of NextTrace simultaneously may interfere with each other’s results (observed so far only in TCP mode)
## Star History
[](https://star-history.com/#nxtrace/NTrace-core&Date)
================================================
FILE: README_zh_CN.md
================================================
<div align="center">
<img src="assets/logo.png" height="200px" alt="NextTrace Logo"/>
</div>
<h1 align="center">
<br>NextTrace<br>
</h1>
<h4 align="center">一款追求轻量化的开源可视化路由跟踪工具。</h4>
---
<h6 align="center">主页:www.nxtrace.org</h6>
<p align="center">
<a href="https://github.com/nxtrace/NTrace-dev/actions">
<img src="https://img.shields.io/github/actions/workflow/status/nxtrace/NTrace-dev/build.yml?branch=main&style=flat-square" alt="Github Actions">
</a>
<a href="https://goreportcard.com/report/github.com/nxtrace/NTrace-dev">
<img src="https://goreportcard.com/badge/github.com/nxtrace/NTrace-dev?style=flat-square">
</a>
<a href="https://github.com/nxtrace/NTrace-dev/releases">
<img src="https://img.shields.io/github/release/nxtrace/NTrace-dev/all.svg?style=flat-square">
</a>
</p>
## IAAS Sponsor
<div style="text-align: center;">
<a href="https://dmit.io">
<img src="https://assets.nxtrace.org/dmit.svg" width="170.7" height="62.9">
</a>
<a href="https://misaka.io" >
<img src="https://assets.nxtrace.org/misaka.svg" width="170.7" height="62.9">
</a>
<a href="https://portal.saltyfish.io" >
<img src="https://assets.nxtrace.org/snapstack.svg" width="170.7" height="62.9">
</a>
</div>
我们非常感谢 [DMIT](https://dmit.io)、 [Misaka](https://misaka.io) 和 [SnapStack](https://portal.saltyfish.io) 提供了支持本项目所需的网络基础设施。
## How To Use
Document Language: [English](README.md) | 简体中文
⚠️ 请注意:我们欢迎来自社区的PR提交,但是请将您的PR提交至 [NTrace-dev](https://github.com/nxtrace/NTrace-dev) 仓库,而不是 [NTrace-core](https://github.com/nxtrace/NTrace-core) 仓库。<br>
关于NTrace-dev和NTrace-core两个仓库的说明:<br>
二者将大体上保持一致。所有的开发工作均在NTrace-dev仓库中进行。NTrace-dev仓库首先发布新版本,在稳定运行一段时间后(时长不定),我们会把版本同步至NTrace-core。这意味着NTrace-dev仓库充当了一个“测试版”的角色。<br>
请注意,版本同步也存在例外。如果NTrace-dev的某个版本出现了严重的bug,NTrace-core会跳过这一有缺陷的版本,直接同步到下一个修复了该问题的版本。
### Before Using
使用 NextTrace 之前,我们建议您先阅读 [#IP 数据以及精准度说明](https://github.com/nxtrace/NTrace-core/blob/main/README_zh_CN.md#ip-%E6%95%B0%E6%8D%AE%E4%BB%A5%E5%8F%8A%E7%B2%BE%E5%87%86%E5%BA%A6%E8%AF%B4%E6%98%8E),在了解您自己的对数据精准度需求以后再进行抉择。
### Automated Install
- Linux
- 一键安装脚本
```shell
curl -sL https://nxtrace.org/nt | bash
```
- 从 nxtrace的APT源安装
- 支持 AMD64/ARM64 架构
```shell
curl -fsSL https://github.com/nxtrace/nexttrace-debs/releases/latest/download/nexttrace-archive-keyring.gpg | sudo tee /etc/apt/keyrings/nexttrace.gpg >/dev/null
echo "Types: deb
URIs: https://github.com/nxtrace/nexttrace-debs/releases/latest/download/
Suites: ./
Signed-By: /etc/apt/keyrings/nexttrace.gpg" | sudo tee /etc/apt/sources.list.d/nexttrace.sources >/dev/null
sudo apt update
sudo apt install nexttrace
```
- APT源由 wcbing, nxtrace 维护
- Arch Linux AUR 安装命令
- 直接下载bin包(仅支持amd64)
```shell
yay -S nexttrace-bin
```
- 从源码构建(仅支持amd64)
```shell
yay -S nexttrace
```
- AUR 的构建分别由 ouuan, huyz 维护
- Linuxbrew 安装命令
同macOS Homebrew安装方法(homebrew-core版仅支持amd64)
- deepin 安装命令
```shell
apt install nexttrace
```
- [x-cmd](https://cn.x-cmd.com/pkg/nexttrace) 安装命令
```shell
x env use nexttrace
```
- Termux 安装命令
```shell
pkg install root-repo
pkg install nexttrace
```
- ImmortalWrt 安装命令
```shell
opkg install nexttrace
```
- macOS
- macOS Homebrew 安装命令
- homebrew-core版
```shell
brew install nexttrace
```
- 本仓库ACTIONS自动构建版(更新更快)
```shell
brew tap nxtrace/nexttrace && brew install nxtrace/nexttrace/nexttrace
```
- homebrew-core 构建由 chenrui333 维护,请注意该版本更新可能会落后仓库Action自动构建版本
- Windows
- Windows WinGet 安装命令
- WinGet 版
```powershell
winget install nexttrace
```
- WinGet 构建由 Dragon1573 维护
- Windows Scoop 安装命令
- scoop-extras 版
```powershell
scoop bucket add extras && scoop install extras/nexttrace
```
- scoop-extra 由 soenggam 维护
请注意,以上多种安装方式的仓库均由开源爱好者自行维护,不保证可用性和及时更新,如遇到问题请联系仓库维护者解决,或使用本项目官方编译提供的二进制包。
### Manual Install
- 下载预编译的可执行程序
对于以上方法没有涵盖的用户,请直接前往 [Release](https://www.nxtrace.org/downloads) 下载编译好的二进制可执行文件。
- `Release`里面为很多系统以及不同架构提供了编译好的二进制可执行文件,如果没有可以自行编译。
- 一些本项目的必要依赖在`Windows`上`Golang`底层实现不完全,所以目前`NextTrace`在`Windows`平台出于实验性支持阶段。
### 版本说明
从本版本开始,NextTrace 在同一 release tag 下发布 **三种构建版本**,按需选用:
| 功能 | `nexttrace`(完整版) | `nexttrace-tiny` | `ntr` |
| ----------------------- | :-------------------: | :--------------: | :--------: |
| 常规 traceroute | ✅ | ✅ | — |
| 独立 MTU(`--mtu`) | ✅ | ✅ | — |
| MTR TUI | ✅ | — | ✅(默认) |
| MTR 报告(`-r`) | ✅ | — | ✅ |
| MTR 宽报告(`-w`) | ✅ | — | ✅ |
| MTR 原始输出(`--raw`) | ✅ | — | ✅ |
| Globalping(`--from`) | ✅ | — | — |
| WebUI(`--deploy`) | ✅ | — | — |
| 快速跟踪(`-F`) | ✅ | ✅ | — |
| 默认运行模式 | traceroute | traceroute | MTR TUI |
| 二进制名 | `nexttrace` | `nexttrace-tiny` | `ntr` |
> **注意:** 包管理器(Homebrew、AUR、Scoop 等)目前仅安装 **完整版**(`nexttrace`)。
### 功能对比
- **`nexttrace`** — 完整版。包含所有功能:traceroute、MTR、Globalping 与 WebUI。
- **`nexttrace-tiny`** — 精简版。仅保留常规 traceroute,不含 MTR / Globalping / WebUI。适合嵌入式或极简环境。
- **`ntr`** — MTR 专用版。默认启动 MTR TUI。无 Globalping / WebUI,无常规 traceroute 模式,也不带独立 `--mtu` 模式。
### 手动编译
需要 Go 1.22+ 环境:
```bash
# 完整版(所有功能)
go build -trimpath -o dist/nexttrace -ldflags "-w -s" .
# 精简版(无 MTR、无 Globalping、无 WebUI)
go build -tags flavor_tiny -trimpath -o dist/nexttrace-tiny -ldflags "-w -s" .
# MTR 专用版
go build -tags flavor_ntr -trimpath -o dist/ntr -ldflags "-w -s" .
```
交叉编译示例:
```bash
# Linux arm64 精简版
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 \
go build -tags flavor_tiny -trimpath -o dist/nexttrace-tiny_linux_arm64 -ldflags "-w -s" .
```
`tiny` 和 `ntr` 版本通过 **编译期 build tags** 裁剪模块——不是运行时开关。可通过 `go version -m <binary>` 验证 `nexttrace-tiny` 和 `ntr` 中不包含 `gin` 与 `globalping-cli`。
`.cross_compile.sh` 脚本支持按版本构建:
```bash
./.cross_compile.sh all # 构建全部三个版本(所有平台)
./.cross_compile.sh full # 仅构建 nexttrace(完整版)
./.cross_compile.sh tiny # 仅构建 nexttrace-tiny
./.cross_compile.sh ntr # 仅构建 ntr
```
### 发行资产命名规则
Release 二进制文件命名格式:
```text
{二进制名}_{操作系统}_{架构}[v{arm版本}][.exe][_softfloat]
```
示例:
- `nexttrace_linux_amd64`、`nexttrace-tiny_linux_amd64`、`ntr_linux_amd64`
- `nexttrace_darwin_universal`、`nexttrace-tiny_darwin_universal`、`ntr_darwin_universal`
- `nexttrace_windows_amd64.exe`、`ntr_windows_amd64.exe`
### Get Started
`NextTrace` 默认使用`ICMP`协议发起`TraceRoute`请求,该协议同时支持`IPv4`和`IPv6`
```bash
# IPv4 ICMP Trace
nexttrace 1.0.0.1
# URL
nexttrace http://example.com:8080/index.html?q=1
# 表格输出(报告模式):运行一次探测后打印最终汇总表格
nexttrace --table 1.0.0.1
# 机器可读输出:stdout 只包含一个 JSON 文档
nexttrace --raw 1.0.0.1
nexttrace --json 1.0.0.1
# 将实时 traceroute 输出写入自定义文件
nexttrace --output ./trace.log 1.0.0.1
# 将实时 traceroute 输出写入默认日志文件
nexttrace --output-default 1.0.0.1
# 只进行IPv4/IPv6解析,且当多个IP时自动选择第一个IP
nexttrace --ipv4 g.co
nexttrace --ipv6 g.co
# IPv6 ICMP Trace
nexttrace 2606:4700:4700::1111
# 普通 traceroute 模式下设置 TTL 分组间隔(默认 300ms)
nexttrace -i 300 1.1.1.1
# 禁用路径可视化 使用 --map / -M 参数
nexttrace koreacentral.blob.core.windows.net
# MapTrace URL: https://api.nxtrace.org/tracemap/html/c14e439e-3250-5310-8965-42a1e3545266.html
# 禁用MPLS显示 使用 --disable-mpls / -e 参数 或 NEXTTRACE_DISABLEMPLS 环境变量
nexttrace --disable-mpls example.com
export NEXTTRACE_DISABLEMPLS=1
```
PS: 路由可视化的绘制模块为独立模块,具体代码可在 [nxtrace/traceMap](https://github.com/nxtrace/traceMap) 查看
路由可视化功能因为需要每个 Hop 的地理位置坐标,而第三方 API 通常不提供此类信息,所以此功能目前只支持搭配 LeoMoeAPI 使用。
#### `Windows` 用户必须完成的配置步骤
- 对于普通用户模式:
只能使用 **ICMP mode**,且需防火墙配置允许`ICMP/ICMPv6`。
```powershell
netsh advfirewall firewall add rule name="All ICMP v4" dir=in action=allow protocol=icmpv4:any,any
netsh advfirewall firewall add rule name="All ICMP v6" dir=in action=allow protocol=icmpv6:any,any
```
- 对于管理员模式:
**TCP/UDP mode** 依赖 `WinDivert`。
**ICMP mode** 支持 `1=Socket` 与 `2=WinDivert`(`0=Auto`)。使用 Socket 模式时,需防火墙配置允许`ICMP/ICMPv6`。
在 `Windows` 上,`ICMPv6` 未传 `--tos` 或显式 `--tos 0` 时继续走原生 Socket 发送路径;只有非零 `ICMPv6 --tos` 才额外依赖 `WinDivert` 发送能力,并要求管理员权限。
`WinDivert` 可使用 `--init` 参数自动配置环境。
#### `NextTrace` 现已经支持快速测试,有一次性测试回程路由需求的朋友可以使用
```bash
# 北上广(电信+联通+移动+教育网)IPv4 / IPv6 ICMP 快速测试
nexttrace --fast-trace
# 也可以使用 TCP SYN 而非 ICMP 进行测试
nexttrace --fast-trace --tcp
# 也可以通过自定义的IP/DOMAIN列表文件进行快速测试
nexttrace --file /path/to/your/iplist.txt
# 自定义的IP/DOMAIN列表文件格式
## 一行一个IP/DOMAIN + 空格 + 描述信息(可选)
## 例如:
## 106.37.67.1 北京电信
## 240e:928:101:31a::1 北京电信
## bj.10086.cn 北京移动
## 2409:8080:0:1::1
## 223.5.5.5
```
#### `NextTrace` 已支持指定网卡进行路由跟踪
```bash
# 请注意 Lite 版本此参数不能和快速测试联用,如有需要请使用 enhanced 版本
# 使用 eth0 网卡
nexttrace --dev eth0 2606:4700:4700::1111
# 使用 eth0 网卡IP
# 网卡 IP 可以使用 ip a 或者 ifconfig 获取
# 使用网卡IP进行路由跟踪时需要注意跟踪的IP类型应该和网卡IP类型一致(如都为 IPv4)
nexttrace --source 204.98.134.56 9.9.9.9
```
#### `NextTrace` 也可以使用`TCP`和`UDP`协议发起`Traceroute`请求
```bash
# TCP SYN Trace
nexttrace --tcp www.bing.com
# 可以自行指定目标端口[此处为443],默认80端口
nexttrace --tcp --port 443 2001:4860:4860::8888
# UDP Trace
nexttrace --udp 1.0.0.1
# 可以自行指定目标端口[此处为5353],默认33494端口
nexttrace --udp --port 5353 1.0.0.1
# TCP/UDP Trace 可以自行指定源端口,默认使用随机一个固定的端口(如需每次发包随机使用不同的源端口,请设置`ENV` `NEXTTRACE_RANDOMPORT`)
nexttrace --tcp --source-port 14514 www.bing.com
```
#### `NextTrace` 也支持独立的路径 MTU 探测模式
```bash
# 类 tracepath 的 UDP PMTU 探测,运行中实时刷行
nexttrace --mtu 1.1.1.1
# mtu 模式同样复用常规的 GeoIP / RDNS 参数
nexttrace --mtu --data-provider IPInfo --language en 1.1.1.1
# JSON 输出沿用独立 mtu schema,并包含 hop.geo
nexttrace --mtu --json 1.1.1.1
```
- `--mtu` 是独立的 UDP-only 模式,不复用普通 traceroute 引擎。
- TTY 下会原地更新当前 hop,并为 hop 状态 / PMTU 高亮加色;重定向/管道输出会退化成“定稿一跳输出一行”的无 ANSI 流式文本。
- `--mtu --json` 在 stdout 上只输出独立的 MTU JSON 文档。
- GeoIP、RDNS、`--data-provider`、`--language`、`--no-rdns`、`--always-rdns`、`--dot-server` 都对该模式生效。
#### `NextTrace`也同样支持一些进阶功能,如 TTL 控制、并发数控制、模式切换等
```bash
# 每一跳发送2个探测包
nexttrace --queries 2 www.hkix.net
# 无并发,每次只发送一个探测包
nexttrace --parallel-requests 1 www.hkix.net
# 从TTL为5开始发送探测包,直到TTL为10结束
nexttrace --first 5 --max-hops 10 www.decix.net
# 此外还提供了一个ENV,可以设置是否隐匿目的IP
export NEXTTRACE_ENABLEHIDDENDSTIP=1
# 关闭IP反向解析功能
nexttrace --no-rdns www.bbix.net
# 设置探测包总大小为1024字节(含 IP + 探测协议头)
nexttrace --psize 1024 example.com
# 让每个 probe 在 1500 字节内随机大小
nexttrace --psize -1500 example.com
# 设置 TOS / traffic class 字段
nexttrace -Q 46 example.com
# 特色功能:打印Route-Path图
# Route-Path图示例:
# AS6453 塔塔通信「Singapore『Singapore』」
# ╭╯
# ╰AS9299 Philippine Long Distance Telephone Co.「Philippines『Metro Manila』」
# ╭╯
# ╰AS36776 Five9 Inc.「Philippines『Metro Manila』」
# ╭╯
# ╰AS37963 阿里云「ALIDNS.COM『ALIDNS.COM』」
nexttrace --route-path www.time.com.my
# 禁止色彩输出
nexttrace --no-color 1.1.1.1
# 或者使用环境变量
export NO_COLOR=1
```
#### 高级参数调优速查
| 参数 | 控制内容 | 默认值 / 起步建议 | 什么时候调 |
| --- | --- | --- | --- |
| `--queries` | 常规 traceroute 的每跳采样数;MTR 中显式指定每跳探测次数 | traceroute: `3`;MTR report: 未指定时 `10`;MTR TUI/raw: 未指定时无限 | 链路抖动大时可升到 `5-10` |
| `--max-attempts` | 每跳最大发包上限 | 默认按 `--queries` 自动推导 | 丢包严重、回包慢时增大 |
| `--parallel-requests` | 跨 TTL 的总并发 in-flight 探测数 | `18` | 多路径/负载均衡链路用 `1`;稳定链路一般 `6-18` |
| `--send-time` | 同一 TTL 组内相邻探测包间隔 | `50ms` | 设备限速时升到 `100-200ms`;MTR 下忽略 |
| `--ttl-time` | 常规 traceroute 的 TTL 组间隔;MTR 的每跳探测间隔 | traceroute: `300ms`;MTR: 未指定时 `1000ms` | 想加速就调低;远程/限速链路调高 |
| `--timeout` | 单个探测包超时 | `1000ms` | 跨洲或高丢包链路升到 `2000-3000ms` |
| `--psize` | 探测包大小 | 按协议/IP 族自动取最小合法值 | 含 IP + 探测协议头;负值表示每个 probe 在 `abs(value)` 内随机;超过出接口/路径 MTU 时,链路上可能看到分片 |
| `-Q`, `--tos` | IP TOS / traffic class | `0` | 设置 IP 头里的 TOS / traffic class;在 Windows 上仅 `ICMPv6` 且值非零时额外依赖 `WinDivert` |
这些探测参数目前仍是 CLI 级配置,`nt_config.yaml` 还不能直接保存它们。若要复用一组调优参数,建议写成 shell alias 或小脚本。
```bash
# 适合多路径 / ECMP 的保守配置
nexttrace --parallel-requests 1 --send-time 100 --ttl-time 500 --timeout 2000 example.com
# 适合稳定单路径链路的快速配置
nexttrace --parallel-requests 18 --send-time 20 --ttl-time 150 example.com
# 适合高丢包长途链路的配置
nexttrace --queries 5 --max-attempts 10 --timeout 2500 example.com
```
#### `NextTrace` 支持 MTR(My Traceroute)连续探测模式
```bash
# MTR 模式:使用 ICMP(默认)连续探测,实时刷新表格
nexttrace -t 1.1.1.1
# 等价写法:
nexttrace --mtr 1.1.1.1
# MTR 模式使用 TCP SYN 探测
nexttrace -t --tcp --port 443 www.bing.com
# MTR 模式使用 UDP 探测
nexttrace -t --udp 1.0.0.1
# 设置每个跳点的探测间隔(MTR 模式下默认 1000ms;-z/--send-time 在 MTR 模式下无效)
nexttrace -t -i 500 1.1.1.1
# 限制每个跳点的最大探测次数(TUI 默认无限,报告模式默认 10)
nexttrace -t -q 20 1.1.1.1
# 报告模式:对每个跳点探测 N 次后一次性输出统计摘要(类似 mtr -r)
nexttrace -r 1.1.1.1 # = --mtr --report,默认每跳点 10 次
nexttrace -r -q 5 1.1.1.1 # 每跳点 5 次
# 宽报告模式:主机列不截断(类似 mtr -rw)
nexttrace -w 1.1.1.1 # = --mtr --report --wide
# 在 MTR 输出中同时显示 PTR 和 IP(PTR 在前,IP 括号)
nexttrace --mtr --show-ips 1.1.1.1
nexttrace -r --show-ips 1.1.1.1
nexttrace -w --show-ips 1.1.1.1
# MTR 原始流式模式(面向程序解析,逐事件输出)
nexttrace --mtr --raw 1.1.1.1
nexttrace -r --raw 1.1.1.1
# 与其他选项组合使用
nexttrace -t --tcp --max-hops 20 --first 3 --no-rdns 8.8.8.8
```
在终端(TTY)中运行时,MTR 模式使用**交互式全屏 TUI**:
- **`q` / `Q`** — 退出(恢复终端,不留下输出)
- **`p`** — 暂停探测
- **空格** — 恢复探测
- **`r`** — 重置统计(计数器清零,显示模式保持不变)
- **`y`** — 循环切换主机显示模式:ASN → City → Owner → Full
- **`n`** — 切换主机名显示方式:
- 默认:PTR(无 PTR 时回退 IP)↔ 仅 IP
- 启用 `--show-ips`:PTR (IP) ↔ 仅 IP
- **`e`** — 切换 MPLS 标签显示开/关
- TUI 标题栏显示**源 → 目标**路由信息,指定 `--source`/`--dev` 时会展示对应信息。
- 使用 LeoMoeAPI 时,标题栏会显示首选 API IP 地址。
- 使用**备用屏幕缓冲区**,退出后恢复之前的终端历史记录。
- 当 stdin 非 TTY(如管道输入)时,降级为简单表格刷新模式。
**报告模式**(`-r`/`--report`)在所有探测完成后一次性输出统计,适合脚本使用:
```text
Start: 2025-07-14T09:12:00+08:00
HOST: myhost Loss% Snt Last Avg Best Wrst StDev
1. one.one.one.one 0.0% 10 1.23 1.45 0.98 2.10 0.32
2. 10.0.0.2 100.0% 10 0.00 0.00 0.00 0.00 0.00
```
显示为 `(waiting for reply)` 的行仍然保留同样的表格列布局,只是该行的指标单元格会留空。
非 wide 报告模式会刻意保持 Host 列精简:
- 只显示 `PTR/IP`
- 不发起 Geo API 查询
- 不显示 ASN / 运营商 / 地理位置字段
- 不显示 MPLS 标签
wide 报告模式(`-w` / `--wide`)继续保留当前完整信息行为,包括 Geo 衍生字段和 MPLS 输出。
当 `--raw` 与 MTR(`--mtr`、`-r`、`-w`)一起使用时,会进入 **MTR 原始流式模式**。
如果当前数据源是 `LeoMoeAPI`,会先输出一行无色的 API 信息头:
```text
[NextTrace API] preferred API IP - [2403:18c0:1001:462:dd:38ff:fe48:e0c5] - 21.33ms - DMIT.NRT
```
之后再逐行输出 `|` 分隔的事件流:
```
4|84.17.33.106|po66-3518.cr01.nrt04.jp.misaka.io|0.27|60068|日本|东京都|东京||cdn77.com|35.6804|139.7690
```
字段顺序:
`ttl|ip|ptr|rtt|asn|一级行政区|二级行政区|三级行政区|四级行政区|owner|纬度|经度`
超时行保持固定 12 列:
`ttl|*||||||||||`
在 MTR 模式(`--mtr`、`-r`、`-w`,包括 `--raw`)下,`-i/--ttl-time` 设置的是**每个跳点的探测间隔**:同一跳点两次连续探测之间的等待时间(未显式指定时默认 1000ms)。`-z/--send-time` 在 MTR 模式下被忽略。
> 注意:`--show-ips` 仅在 MTR 模式(`--mtr`、`-r`、`-w`)生效,其他模式会忽略。
>
> 注意:`--mtr` 不可与 `--table`、`--classic`、`--json`、`--output`、`--output-default`、`--route-path`、`--from`、`--fast-trace`、`--file`、`--deploy` 同时使用。
#### `NextTrace`支持用户自主选择 IP 数据库(目前支持:`LeoMoeAPI`, `IP.SB`, `IPInfo`, `IPInsight`, `IPAPI.com`, `IPInfoLocal`, `CHUNZHEN`)
```bash
# 可以自行指定IP数据库[此处为IP-API.com],不指定则默认为LeoMoeAPI
nexttrace --data-provider ip-api.com
## 特别的: 其中 ipinfo 和 IPInsight API 对于免费版查询有频率限制,可从这些服务商自行购买服务以解除限制,如有需要可以 clone 本项目添加其提供的 token 自行编译
## TOKEN填写路径:ipgeo/tokens.go
## 特别的: 对于离线库 IPInfoLocal,请自行下载并命名为 ipinfoLocal.mmdb
## (可以从这里下载:https://ipinfo.io/signup?ref=free-database-downloads),
## 默认搜索用户当前路径、程序所在路径、和 FHS 路径(Unix-like)
## 如果需要自定义路径,请设置环境变量
export NEXTTRACE_IPINFOLOCALPATH=/xxx/yyy.mmdb
## 另外:由于IP.SB被滥用比较严重,会经常出现无法查询的问题,请知悉。
## IP-API.com限制调用较为严格,如有查询不到的情况,请几分钟后再试。
# 纯真IP数据库默认使用 http://127.0.0.1:2060 作为查询接口,如需自定义请使用环境变量
export NEXTTRACE_CHUNZHENURL=http://127.0.0.1:2060
## 可使用 https://github.com/freshcn/qqwry 自行搭建纯真IP数据库服务
# 也可以通过设置环境变量来指定默认IP数据库
export NEXTTRACE_DATAPROVIDER=ipinfo
```
#### `NextTrace`支持使用混合参数和简略参数
```bash
Example:
nexttrace --data-provider ip-api.com --max-hops 20 --tcp --port 443 --queries 5 --no-rdns 1.1.1.1
nexttrace -tcp --queries 2 --parallel-requests 1 --table --route-path 2001:4860:4860::8888
Equivalent to:
nexttrace -d ip-api.com -m 20 -T -p 443 -q 5 -n 1.1.1.1
nexttrace -T -q 2 --parallel-requests 1 --table -P 2001:4860:4860::8888
```
### Globalping
[Globalping](https://globalping.io/) 提供了对成千上万由社区托管的探针的访问能力,可用于运行网络测试和测量。
通过 `--from` 参数可以选择使用指定位置的探针来执行 traceroute。位置字段支持洲、国家、地区、城市、ASN、ISP 或云厂商区域等多种类型。
```bash
nexttrace google.com --from Germany
nexttrace google.com --from comcast+california
```
匿名用户默认每小时限额为 250 次测试。将 `GLOBALPING_TOKEN` 环境变量设置为你的令牌后,可将限额提升至每小时 500 次。
```bash
export GLOBALPING_TOKEN=your_token_here
```
### 环境变量总览
NextTrace 当前会读取下列环境变量。对于布尔开关,只识别 `1` 和 `0`,其他值会回退到内置默认值。为了避免混淆,修改后建议重启 NextTrace。
#### 核心运行 / 网络
| 变量名 | 默认值 | 说明 |
| --- | --- | --- |
| `NEXTTRACE_DEVMODE` | `0` | 开发调试模式:致命错误改为 panic,并打印堆栈。 |
| `NEXTTRACE_DEBUG` | 未设置 | 在 `GetEnv*` 解析环境变量时打印检测到的值。 |
| `NEXTTRACE_DISABLEMPLS` | `0` | 全局禁用 MPLS 显示,效果类似 `--disable-mpls`。 |
| `NEXTTRACE_ENABLEHIDDENDSTIP` | `0` | 隐匿目的 IP,并省略其主机名显示。 |
| `NEXTTRACE_RANDOMPORT` | `0` | TCP/UDP 每个探测包使用不同的随机源端口。 |
| `NEXTTRACE_MAXATTEMPTS` | 自动计算 | 当未显式传入 `--max-attempts` 时,提供默认最大重试次数。 |
| `NEXTTRACE_ICMPMODE` | `0` | 当未显式传入 `--icmp-mode` 时提供默认值(`0=自动`、`1=Socket`、`2=WinDivert`)。 |
| `NEXTTRACE_UNINTERRUPTED` | `0` | 与 `--raw` 一起使用时,会在一次探测结束后继续循环执行,而不是退出。 |
| `NEXTTRACE_PROXY` | 未设置 | 为 PoW、Geo API、tracemap 等出站 HTTP / WebSocket 请求设置代理 URL。 |
| `NEXTTRACE_DATAPROVIDER` | 未设置 | 覆盖默认 IP 地理信息源,例如 `ipinfo`。 |
#### 服务 / Web / 后端
| 变量名 | 默认值 | 说明 |
| --- | --- | --- |
| `NEXTTRACE_HOSTPORT` | `api.nxtrace.org` | 覆盖 LeoMoeAPI、tracemap、FastIP 等使用的后端地址,支持 `host` 或 `host:port`。 |
| `NEXTTRACE_TOKEN` | 未设置 | 预置 LeoMoeAPI Bearer Token;设置后将跳过 PoW 取 token 流程。 |
| `NEXTTRACE_POWPROVIDER` | `api.nxtrace.org` | 指定 PoW 服务提供方;当前内置的非默认别名为 `sakura`。 |
| `NEXTTRACE_DEPLOY_ADDR` | 未设置 | `--deploy` 模式下,当未传 `--listen` 时使用的默认监听地址。 |
| `NEXTTRACE_ALLOW_CROSS_ORIGIN` | `0` | 仅对 `--deploy` 生效:是否允许跨站浏览器访问 Web UI / API。默认关闭以保证安全。 |
#### IP 数据库 / 第三方服务
| 变量名 | 默认值 | 说明 |
| --- | --- | --- |
| `NEXTTRACE_IPINFOLOCALPATH` | 自动搜索 | `IPInfoLocal` 离线库 `ipinfoLocal.mmdb` 的完整路径。 |
| `NEXTTRACE_CHUNZHENURL` | `http://127.0.0.1:2060` | 纯真 IP 查询服务的基础 URL。 |
| `NEXTTRACE_IPINFO_TOKEN` | 未设置 | `IPInfo` 数据源使用的 token。 |
| `NEXTTRACE_IPINSIGHT_TOKEN` | 未设置 | `IPInsight` 数据源使用的 token。 |
| `NEXTTRACE_IPAPI_BASE` | 各 provider 内置地址 | 覆盖当前实现里兼容 HTTP 接口的数据源基础地址(`IPInfo`、`IPInsight`、`ip-api.com`)。 |
| `IPDBONE_BASE_URL` | `https://api.ipdb.one` | 覆盖 IPDB.One API 基础地址。 |
| `IPDBONE_API_ID` | 未设置 | IPDB.One API ID。 |
| `IPDBONE_API_KEY` | 未设置 | IPDB.One API Key。 |
| `GLOBALPING_TOKEN` | 未设置 | Globalping 鉴权 token;设置后可提升匿名用户的每小时测试额度。 |
#### 配置文件搜索
| 变量名 | 默认值 | 说明 |
| --- | --- | --- |
| `XDG_CONFIG_HOME` | 取决于系统 / Shell | 如果设置了该变量,NextTrace 也会从 `$XDG_CONFIG_HOME/nexttrace` 搜索 `nt_config.yaml`。 |
### 全部用法详见 Usage 菜单
```shell
Usage: nexttrace [-h|--help] [--init] [-4|--ipv4] [-6|--ipv6] [-T|--tcp]
[-U|--udp] [-F|--fast-trace] [-p|--port <integer>]
[--icmp-mode <integer>] [-q|--queries <integer>]
[--max-attempts <integer>] [--parallel-requests <integer>]
[-m|--max-hops <integer>] [-d|--data-provider
(IP.SB|ip.sb|IPInfo|ipinfo|IPInsight|ipinsight|IPAPI.com|ip-api.com|IPInfoLocal|ipinfolocal|chunzhen|LeoMoeAPI|leomoeapi|ipdb.one|disable-geoip)]
[--pow-provider (api.nxtrace.org|sakura)] [-n|--no-rdns]
[-a|--always-rdns] [-P|--route-path] [--dn42] [-o|--output
"<value>"] [-O|--output-default] [--table] [--raw]
[-j|--json] [-c|--classic] [-f|--first <integer>] [-M|--map]
[-e|--disable-mpls] [-V|--version]
[-s|--source "<value>"] [--source-port <integer>] [-D|--dev
"<value>"] [--listen "<value>"] [--deploy] [-z|--send-time
<integer>] [-i|--ttl-time <integer>] [--timeout <integer>]
[--psize <integer>] [--dot-server
(dnssb|aliyun|dnspod|google|cloudflare)] [-g|--language
(en|cn)] [-C|--no-color] [--from "<value>"] [-t|--mtr]
[-r|--report] [-w|--wide] [--show-ips] [-y|--ipinfo <integer>]
[--file "<value>"] [TARGET "<value>"]
Arguments:
-h --help Print help information
--init Windows ONLY: Extract WinDivert runtime to
current directory
-4 --ipv4 Use IPv4 only
-6 --ipv6 Use IPv6 only
-T --tcp Use TCP SYN for tracerouting (default
dest-port is 80)
-U --udp Use UDP SYN for tracerouting (default
dest-port is 33494)
-F --fast-trace One-Key Fast Trace to China ISPs
-p --port Set the destination port to use. With
default of 80 for "tcp", 33494 for "udp"
--icmp-mode Windows ONLY: Choose the method to listen
for ICMP packets (1=Socket, 2=WinDivert;
0=Auto)
-q --queries Latency samples per hop. Increase to 5-10
on unstable paths for a steadier view.
Default: 3
--max-attempts Advanced: hard cap on probe packets per
hop. Leave unset for auto sizing; raise on
lossy links if --queries is not enough
--parallel-requests Advanced: total concurrent in-flight
probes across TTLs. Use 1 on
multipath/load-balanced paths; 6-18 is a
good starting range on stable links.
Default: 18
-m --max-hops Set the max number of hops (max TTL to be
reached). Default: 30
-d --data-provider Choose IP Geograph Data Provider [IP.SB,
IPInfo, IPInsight, IP-API.com,
IPInfoLocal, CHUNZHEN, disable-geoip].
Default: LeoMoeAPI
--pow-provider Choose PoW Provider [api.nxtrace.org,
sakura] For China mainland users, please
use sakura. Default: api.nxtrace.org
-n --no-rdns Do not resolve IP addresses to their
domain names
-a --always-rdns Always resolve IP addresses to their
domain names
-P --route-path Print traceroute hop path by ASN and
location
--dn42 DN42 Mode
-o --output Write trace result to FILE
(RealtimePrinter only)
-O --output-default Write trace result to the default log file
(/tmp/trace.log)
--table Output trace results as a final summary
table (traceroute report mode)
--raw Machine-friendly output. With MTR
(--mtr/-r/-w), enables streaming raw event
mode
-j --json Output trace results as JSON
-c --classic Classic Output trace results like
BestTrace
-f --first Start from the first_ttl hop (instead of
1). Default: 1
-M --map Disable Print Trace Map
-e --disable-mpls Disable MPLS
-V --version Print version info and exit
-s --source Use source address src_addr for outgoing
packets
--source-port Use source port src_port for outgoing
packets
-D --dev Use the following Network Devices as the
source address in outgoing packets
--listen Set listen address for web console (e.g.
127.0.0.1:30080)
--deploy Start the Gin powered web console
-z --send-time Advanced: per-packet gap [ms] inside the
same TTL group. Lower is faster; raise to
100-200ms on rate-limited links. Ignored
in MTR mode. Default: 50
-i --ttl-time Advanced: TTL-group interval [ms] in
normal traceroute. In MTR mode
(--mtr/-r/-w, including --raw), this
becomes per-hop probe interval. 500-1000ms
is a good MTR starting range
--timeout Per-probe timeout [ms]. Raise to 2000-3000
on slow intercontinental or high-loss
paths. Default: 1000
--psize Probe packet size in bytes, inclusive IP
and active probe headers. Default is the
minimum legal size for the chosen
protocol and IP family; raise for MTU or
large-packet testing. Negative values
randomize each probe up to abs(value).
-Q --tos Set the IP type-of-service / traffic class
value [0-255]. Default: 0
--dot-server Use DoT Server for DNS Parse [dnssb,
aliyun, dnspod, google, cloudflare]
-g --language Choose the language for displaying [en,
cn]. Default: cn
-C --no-color Disable Colorful Output
--from Run traceroute via Globalping
(https://globalping.io/network) from a
specified location. The location field
accepts continents, countries, regions,
cities, ASNs, ISPs, or cloud regions.
-t --mtr Enable MTR (My Traceroute) continuous
probing mode
-r --report MTR report mode (non-interactive, implies
--mtr); can trigger MTR without --mtr
-w --wide MTR wide report mode (implies --mtr
--report); alone equals --mtr --report
--wide
--show-ips MTR only: display both PTR hostnames and
numeric IPs (PTR first, IP in parentheses)
-y --ipinfo Set initial MTR TUI host info mode (0-4).
TUI only; ignored in --report/--raw.
0:IP/PTR 1:ASN 2:City 3:Owner 4:Full.
Default: 0
--file Read IP Address or domain name from file
TARGET Trace target: IPv4 address (e.g. 8.8.8.8),
IPv6 address (e.g. 2001:db8::1), domain
name (e.g. example.com), or URL (e.g.
https://example.com)
```
## 项目截图


## 第三方 IP 数据库 API 开发接口
NextTrace 所有的的 IP 地理位置 `API DEMO` 可以参考[这里](https://github.com/nxtrace/NTrace-core/blob/main/ipgeo/)
你可以在这里添加你自己的 API 接口,为了 NextTrace 能够正确显示你接口中的内容,请参考 `leo.go` 中所需要的信息
✨NextTrace `LeoMoeAPI` 的后端 Demo
[GitHub - sjlleo/nexttrace-backend: NextTrace BackEnd](https://github.com/sjlleo/nexttrace-backend)
NextTrace `LeoMoeAPI`现已使用Proof of Work(POW)机制来防止滥用,其中NextTrace作为客户端引入了powclient库,POW CLIENT/SERVER均已开源,欢迎大家使用。(POW模块相关问题请发到对应的仓库)
- [GitHub - tsosunchia/powclient: Proof of Work CLIENT for NextTrace](https://github.com/tsosunchia/powclient)
- [GitHub - tsosunchia/powserver: Proof of Work SERVER for NextTrace](https://github.com/tsosunchia/powserver)
对于中国大陆用户,可以使用 [Nya Labs](https://natfrp.com) 提供的位于大陆的POW服务器优化访问速度
```shell
#使用方法任选其一
#1. 在环境变量中设置
export NEXTTRACE_POWPROVIDER=sakura
#2. 在命令行中设置
nexttrace --pow-provider sakura
```
## OpenTrace
`OpenTrace`是 @Archeb 开发的`NextTrace`的跨平台`GUI`版本,带来您熟悉但更强大的用户体验。
该软件仍然处于早期开发阶段,可能存在许多缺陷和错误,需要您宝贵的使用反馈。
[https://github.com/Archeb/opentrace](https://github.com/Archeb/opentrace)
## NEXTTRACE WEB API
`NextTraceWebApi`是一个`MTR`风格的`NextTrace`网页版服务端实现,提供了包括`Docker`在内多种部署方式。
在 WebSocket 持续探测模式中,MTR 现改为逐事件推送 `type: "mtr_raw"`(不再使用周期性 `mtr` 快照消息)。
[https://github.com/nxtrace/nexttracewebapi](https://github.com/nxtrace/nexttracewebapi)
## NextTraceroute
`NextTraceroute`,一款默认使用`NextTrace API`的免`root`安卓版路由跟踪应用,由 @surfaceocean 开发。
感谢所有测试用户的热情支持,本应用已经通过封闭测试,正式进入 Google Play 商店。
[https://github.com/nxtrace/NextTraceroute](https://github.com/nxtrace/NextTraceroute)
<a href='https://play.google.com/store/apps/details?id=com.surfaceocean.nexttraceroute&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' width="128" height="48" src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png'/></a>
## Cloudflare Support
本项目受 [Alexandria 计划](http://www.cloudflare.com/oss-credits)赞助。
<img src="https://cf-assets.www.cloudflare.com/slt3lc6tev37/2I3y49Uz9Y61lBS0kIPZu6/db6df1e6f99a8659267c442b75a0dff9/image.png" alt="Cloudflare Logo" width="331">
## AIWEN TECH Support
本项目受 [埃文科技](https://www.ipplus360.com) 赞助。 很高兴使用`埃文科技城市级IP库`增强本项目 GEOIP 查询的准确性与完整性,并免费提供给公众。
<img src="https://www.ipplus360.com/img/LOGO.c86cd0e1.svg" title="" alt="埃文科技 IP 定位数据" width="331">
## JetBrain Support
本项目受 [JetBrain Open-Source Project License](https://jb.gg/OpenSourceSupport) 支持。 很高兴使用`Goland`作为我们的开发工具。
<img src="https://resources.jetbrains.com/storage/products/company/brand/logos/GoLand.png" title="" alt="GoLand logo" width="331">
## Credits
[Gubo](https://www.gubo.org) 靠谱主机推荐
[IPInfo](https://ipinfo.io) 无偿提供了本项目大部分数据支持
[BGP.TOOLS](https://bgp.tools) 无偿提供了本项目的一些数据支持
[PeeringDB](https://www.peeringdb.com) 无偿提供了本项目的一些数据支持
[Globalping](https://globalping.io) 一个开源且免费的项目,提供全球范围内运行 traceroute 等网络测试的访问服务
[sjlleo](https://github.com/sjlleo) 项目永远的领导者、创始人及核心贡献者
[tsosunchia](https://github.com/tsosunchia) 项目现任管理、基础设施运维及核心贡献者
[Yunlq](https://github.com/Yunlq) 活跃的社区贡献者
[Vincent Young](https://github.com/missuo)
[zhshch2002](https://github.com/zhshch2002)
[Sam Sam](https://github.com/samleong123)
[waiting4new](https://github.com/waiting4new)
[FFEE_CO](https://github.com/fkx4-p)
[bobo liu](https://github.com/fakeboboliu)
[YekongTAT](https://github.com/isyekong)
## Others
- 其他第三方 API 尽管集成在本项目内,但是具体的 TOS 以及 AUP,请详见第三方 API 官网。如遇到 IP 数据错误,也请直接联系他们纠错。
- 如何获取最新commit的新鲜出炉的二进制可执行文件?
> 请前往GitHub Actions中最新一次 [Build & Release](https://github.com/nxtrace/NTrace-dev/actions/workflows/build.yml) workflow.
- 常见疑问
- Windows 平台下,ICMP 模式须手动放行ICMP/ICMPv6防火墙
- macOS 平台下,仅 ICMP 模式不需要提权运行
- 在一些情况下,同时运行多个 NextTrace 实例可能会导致互相干扰结果(目前仅在 TCP 模式下有观察到)
## IP 数据以及精准度说明
对于IP相关信息的纠错反馈,我们目前开放了两个渠道:
> - 本项目的GITHUB ISSUES区中的[IP 错误报告汇总帖](https://github.com/orgs/nxtrace/discussions/222)
> - 本项目的纠错专用邮箱: `correct#nxtrace.org` (请注意此邮箱仅供IP相关信息纠错专用,其他反馈请发送ISSUE)
NextTrace 有多个数据源可以选择,目前默认使用的 LeoMoeAPI 为我们项目维护的数据源。
该项目由 OwO Network 的 [Missuo](https://github.com/missuo) && [Leo](https://github.com/sjlleo) 发起,由 [Zhshch](https://github.com/zhshch2002/) 完成最早期架构的编写和指导,后由 Leo 完成了大部分开发工作,现主要交由 [tsosunchia](https://github.com/tsosunchia) 完成后续的二开和维护工作。
LeoMoeAPI 是 [Leo](https://github.com/sjlleo) 的作品,归属于 Leo Network,由 [Leo](https://github.com/sjlleo) 完成整套后端 API 编写,该接口未经允许不可用于任何第三方用途。
LeoMoeAPI 早期数据主要来自 IPInsight、IPInfo,随着项目发展,越来越多的志愿者参与进了这个项目。目前 LeoMoeAPI 有近一半的数据是社区提供的,而另外一半主要来自于包含 IPInfo、IPData、BigDataCloud、IPGeoLocation 在内的多个第三方数据。
LeoMoeAPI 的骨干网数据有近 70% 是社区自发反馈又或者是项目组成员校准的,这给本项目的路由跟踪基础功能带来了一定的保证,但是全球骨干网的体量庞大,我们并无能力如 IPIP 等商业公司拥有海量监测节点,这使得 LeoMoeAPI 的数据精准度无法和形如 BestTrace(IPIP)相提并论。
LeoMoeAPI 已经尽力校准了比较常见的骨干网路由,这部分在测试的时候经常会命中,但是如果遇到封闭型 ISP 的路由,大概率可以遇到错误,此类数据不仅是我们,哪怕 IPInsight、IPInfo 也无法正确定位,目前只有 IPIP 能够标记正确,如对此类数据的精确性有着非常高的要求,请务必使用 BestTrace 作为首选。
我们不保证我们的数据一定会及时更新,也不保证数据的精确性,我们希望您在发现数据错误的时候可以前往 issue 页面提交错误报告,谢谢。
当您使用 LeoMoeAPI 即视为您已经完全了解 NextTrace LeoMoeAPI 的数据精确性,并且同意如果您引用 LeoMoeAPI 其中的数据从而引发的一切问题,均由您自己承担。
## DN42 模式使用说明
使用这个模式需要您配置 2 个文件,分别是 geofeed.csv 以及 ptr.csv
当您初次运行 DN42 模式,NT 会为您生成 nt_config.yaml 文件,您可以自定义 2 个文件的存放位置,默认应该存放在 NT 的运行目录下
### GeoFeed
对于 geofeed.csv 来说,格式如下:
```
IP_CDIR,LtdCode,ISO3166-2,CityName,ASN,IPWhois
```
比如,您可以这么写:
```
58.215.96.0/20,CN,CN-JS,Wuxi,23650,CHINANET-JS
```
如果您有一个大段作为骨干网使用,您也可以不写地理位置信息,如下:
```
202.97.0.0/16,,,4134,CHINANET-BACKBONE
```
### PTR
对于 ptr.csv 来说,格式如下:
```
IATA_CODE,LtdCode,RegionName,CityName
```
比如对于美国洛杉矶,您可以这么写
```
LAX,US,California,Los Anegles
```
需要注意的是,NextTrace 支持自动匹配 CSV 中的城市名,如果您的 PTR 记录中有 `losangeles`,您可以只添加上面一条记录就可以正常识别并读取。
## Star History
[](https://star-history.com/#nxtrace/NTrace-core&Date)
================================================
FILE: _config.yml
================================================
theme: jekyll-theme-cayman
================================================
FILE: assets/windivert/divert.go
================================================
package windivert
import (
"bytes"
"crypto/sha256"
_ "embed"
"errors"
"io"
"os"
"path/filepath"
"runtime"
)
//go:embed x64/WinDivert.dll
var winDivertDLL64 []byte
//go:embed x64/WinDivert64.sys
var winDivertSYS64 []byte
//go:embed x86/WinDivert.dll
var winDivertDLL32 []byte
//go:embed x86/WinDivert32.sys
var winDivertSYS32 []byte
// PrepareWinDivertRuntime 将内嵌的 WinDivert DLL/驱动解压到可执行文件同目录
func PrepareWinDivertRuntime() error {
exe, err := os.Executable()
if err != nil {
return err
}
exeDir := filepath.Dir(exe)
var dllBytes, sysBytes []byte
var sysName string
switch runtime.GOARCH {
case "amd64", "arm64":
dllBytes, sysBytes, sysName = winDivertDLL64, winDivertSYS64, "WinDivert64.sys"
case "386", "arm":
dllBytes, sysBytes, sysName = winDivertDLL32, winDivertSYS32, "WinDivert32.sys"
default:
return errors.New("unsupported GOARCH for WinDivert: " + runtime.GOARCH)
}
// DLL
if err := writeIfChecksumDiff(filepath.Join(exeDir, "WinDivert.dll"), dllBytes); err != nil {
return err
}
// SYS
if err := writeIfChecksumDiff(filepath.Join(exeDir, sysName), sysBytes); err != nil {
return err
}
return nil
}
// writeIfChecksumDiff 通过比较 SHA-256 来判断是否覆写目标文件
func writeIfChecksumDiff(dst string, data []byte) error {
file, err := os.Open(dst)
if err != nil {
return os.WriteFile(dst, data, 0o644) // 读失败,则尝试覆盖
}
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
_ = file.Close() // 先关再写,避免 Windows 共享冲突
return os.WriteFile(dst, data, 0o644) // 读失败,则尝试覆盖
}
sumFile := hash.Sum(nil)
_ = file.Close() // 先关再写,避免 Windows 共享冲突
sumMem := sha256.Sum256(data)
if bytes.Equal(sumFile, sumMem[:]) {
return nil // 一致,跳过
}
return os.WriteFile(dst, data, 0o644) // 不一致,则尝试覆盖
}
================================================
FILE: cmd/cmd.go
================================================
package cmd
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net"
"os"
"os/signal"
"runtime"
"strconv"
"strings"
"syscall"
"time"
"github.com/akamensky/argparse"
"github.com/fatih/color"
"github.com/nxtrace/NTrace-core/assets/windivert"
"github.com/nxtrace/NTrace-core/config"
fastTrace "github.com/nxtrace/NTrace-core/fast_trace"
"github.com/nxtrace/NTrace-core/ipgeo"
"github.com/nxtrace/NTrace-core/printer"
"github.com/nxtrace/NTrace-core/reporter"
"github.com/nxtrace/NTrace-core/trace"
"github.com/nxtrace/NTrace-core/tracelog"
"github.com/nxtrace/NTrace-core/tracemap"
"github.com/nxtrace/NTrace-core/util"
"github.com/nxtrace/NTrace-core/wshandle"
)
func ptrBool(v bool) *bool { return &v }
func ptrStr(v string) *string { return &v }
func ptrInt(v int) *int { return &v }
type listenInfo struct {
Binding string
Access string
}
const (
defaultPacketIntervalMs = 50
defaultTracerouteTTLIntervalMs = 300
)
var (
domainLookupFn = util.DomainLookUpWithContext
)
func normalizeListenAddr(addr string) string {
trimmed := strings.TrimSpace(addr)
if trimmed == "" {
return ":1080"
}
if isDigitsOnly(trimmed) {
return ":" + trimmed
}
return trimmed
}
func splitListenAddr(effective string) (host, port string, ok bool) {
host, port, err := net.SplitHostPort(effective)
if err == nil {
if port == "" {
port = "1080"
}
return host, port, true
}
if strings.HasPrefix(effective, ":") {
return "", strings.TrimPrefix(effective, ":"), true
}
return "", "", false
}
func formatHTTPListenURL(host, port string) string {
if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") {
host = "[" + host + "]"
}
return fmt.Sprintf("http://%s:%s", host, port)
}
func resolveListenAccessHost(host string) string {
if host == "" || host == "0.0.0.0" || host == "::" {
return guessLocalIPv4()
}
return host
}
func buildListenInfo(addr string) listenInfo {
effective := normalizeListenAddr(addr)
host, port, ok := splitListenAddr(effective)
if !ok {
return listenInfo{Binding: effective}
}
rawHost := host
if rawHost == "" {
rawHost = "0.0.0.0"
}
info := listenInfo{
Binding: formatHTTPListenURL(rawHost, port),
}
accessHost := resolveListenAccessHost(host)
if accessHost != "" {
info.Access = formatHTTPListenURL(accessHost, port)
}
return info
}
func isDigitsOnly(s string) bool {
if s == "" {
return false
}
for _, r := range s {
if r < '0' || r > '9' {
return false
}
}
return true
}
func normalizeNegativePacketSizeArgs(args []string) []string {
if len(args) < 3 {
return args
}
normalized := make([]string, 0, len(args))
for i := 0; i < len(args); i++ {
cur := args[i]
if cur == "--psize" && i+1 < len(args) && isNegativeInteger(args[i+1]) {
normalized = append(normalized, "--psize="+args[i+1])
i++
continue
}
normalized = append(normalized, cur)
}
return normalized
}
func isNegativeInteger(s string) bool {
if !strings.HasPrefix(s, "-") || len(s) < 2 {
return false
}
v, err := strconv.Atoi(s)
return err == nil && v < 0
}
func guessLocalIPv4() string {
addrs, err := net.InterfaceAddrs()
if err == nil {
for _, address := range addrs {
if ipNet, ok := address.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ip4 := ipNet.IP.To4(); ip4 != nil {
return ip4.String()
}
}
}
}
return "127.0.0.1"
}
func defaultLocalListenAddr() string {
if hasIPv4Loopback() {
return "127.0.0.1:1080"
}
if hasIPv6Loopback() {
return "[::1]:1080"
}
return "127.0.0.1:1080"
}
func hasIPv4Loopback() bool {
addrs, err := net.InterfaceAddrs()
if err != nil {
return false
}
for _, address := range addrs {
if ipNet, ok := address.(*net.IPNet); ok && ipNet.IP.IsLoopback() {
if ip4 := ipNet.IP.To4(); ip4 != nil {
return true
}
}
}
return false
}
func hasIPv6Loopback() bool {
addrs, err := net.InterfaceAddrs()
if err != nil {
return false
}
for _, address := range addrs {
if ipNet, ok := address.(*net.IPNet); ok && ipNet.IP.IsLoopback() {
if ip := ipNet.IP; ip.To4() == nil && len(ip) == net.IPv6len {
return true
}
}
}
return false
}
// sanitizeUsagePositionalArgs replaces the auto-generated positional argument
// name (e.g. "_positionalArg_nexttrace_33") with a friendlier label in the
// usage string produced by argparse.
func sanitizeUsagePositionalArgs(usage string) string {
// argparse generates names like "_positionalArg_nexttrace_<N>"
// We scan for the prefix and replace the whole token with "TARGET".
const prefix = "_positionalArg_"
for {
idx := strings.Index(usage, prefix)
if idx < 0 {
break
}
// Find the end of the token (next space, newline, or end of string).
end := idx + len(prefix)
for end < len(usage) && usage[end] != ' ' && usage[end] != '\n' && usage[end] != '\r' && usage[end] != '\t' && usage[end] != ']' {
end++
}
usage = usage[:idx] + "TARGET" + usage[end:]
}
// argparse renders the positional as "--TARGET" in the description list;
// strip the leading "--" so it reads as a plain positional placeholder.
usage = strings.ReplaceAll(usage, "--TARGET", "TARGET")
// Fix the description column alignment for the TARGET entry.
// argparse gives positional args minimal spacing (" TARGET desc"), but named
// flags are padded to a consistent description column (" --name desc").
// Detect that column from any named-flag line and re-pad the TARGET line to match.
usage = fixPositionalAlignment(usage)
return usage
}
// fixPositionalAlignment detects the description column used by named flags in the
// argparse help output and re-pads the TARGET positional entry to match it.
func fixPositionalAlignment(usage string) string {
// Scan flag lines to find where descriptions start.
// A flag line looks like " -X --name<spaces>Description" or " --name<spaces>Description".
// We find the column of the first non-space character after the flag name (past position 8).
descCol := 0
for _, line := range strings.Split(usage, "\n") {
trimmed := strings.TrimLeft(line, " ")
if !strings.HasPrefix(trimmed, "-") || strings.Contains(line, "TARGET") {
continue
}
inGap := false
for i := 8; i < len(line); i++ {
if line[i] == ' ' {
inGap = true
} else if inGap {
descCol = i
break
}
}
if descCol > 0 {
break
}
}
if descCol == 0 {
return usage
}
// Find the TARGET description entry: "\n TARGET <description>"
const namePrefix = " TARGET"
marker := "\n" + namePrefix
idx := strings.Index(usage, marker)
if idx < 0 {
return usage
}
// afterName points to the character right after " TARGET" on that line.
afterName := idx + 1 + len(namePrefix)
// Skip the existing (minimal) spacing.
end := afterName
for end < len(usage) && usage[end] == ' ' {
end++
}
needed := descCol - len(namePrefix)
if needed <= 0 {
return usage
}
return usage[:afterName] + strings.Repeat(" ", needed) + usage[end:]
}
type effectiveMTRModes struct {
mtr bool
report bool
wide bool
raw bool
}
type tracerouteOutputFlags struct {
routePath *bool
outputPath *string
outputDefault *bool
tablePrint *bool
jsonPrint *bool
classicPrint *bool
}
type webUIFlags struct {
deployListen *string
deploy *bool
}
type mtrCLIFlags struct {
mtrMode *bool
reportMode *bool
wideMode *bool
showIPs *bool
ipInfoMode *int
}
func registerInitFlag(parser *argparse.Parser) *bool {
if runtime.GOOS == "windows" {
return parser.Flag("", "init", &argparse.Options{Help: "Extract WinDivert runtime to current directory"})
}
return ptrBool(false)
}
func registerFastTraceFlag(parser *argparse.Parser) *bool {
if !defaultMTR {
return parser.Flag("F", "fast-trace", &argparse.Options{Help: "One-Key Fast Trace to China ISPs"})
}
return ptrBool(false)
}
func registerMTUFlag(parser *argparse.Parser) *bool {
if enableMTU {
return parser.Flag("", "mtu", &argparse.Options{Help: "Run standalone UDP path-MTU discovery mode with streaming output and GeoIP/RDNS"})
}
return ptrBool(false)
}
func registerICMPModeFlag(parser *argparse.Parser) *int {
if runtime.GOOS == "windows" {
return parser.Int("", "icmp-mode", &argparse.Options{Help: "Choose the method to listen for ICMP packets (1=Socket, 2=WinDivert; 0=Auto)"})
}
return ptrInt(0)
}
func buildQueriesHelp() string {
if defaultMTR {
return "MTR only: max probes per hop. 0 = unlimited in TUI/raw; --report defaults to 10 when omitted. Start with 10-20 on unstable paths"
}
return "Latency samples per hop. Increase to 5-10 on unstable paths for a steadier view"
}
func buildMaxAttemptsHelp() string {
return "Advanced: hard cap on probe packets per hop. Leave unset for auto sizing; raise on lossy links if --queries is not enough"
}
func buildParallelRequestsHelp() string {
return "Advanced: total concurrent in-flight probes across TTLs. Use 1 on multipath/load-balanced paths; 6-18 is a good starting range on stable links"
}
func buildPacketIntervalHelp() string {
help := "Advanced: per-packet gap [ms] inside the same TTL group. Lower is faster; raise to 100-200ms on rate-limited links"
if enableMTR {
help += ". Ignored in MTR mode"
}
return help
}
func buildTimeoutHelp() string {
return "Per-probe timeout [ms]. Raise to 2000-3000 on slow intercontinental or high-loss paths"
}
func buildPayloadSizeHelp() string {
return "Probe packet size in bytes, inclusive IP and active probe headers. Default is the minimum legal size for the chosen protocol and IP family; raise for MTU or large-packet testing. Negative values randomize each probe up to abs(value)"
}
func buildTOSHelp() string {
return "Set the IP type-of-service / traffic class value [0-255]"
}
func registerTracerouteOutputFlags(parser *argparse.Parser) tracerouteOutputFlags {
if !defaultMTR {
return tracerouteOutputFlags{
routePath: parser.Flag("P", "route-path", &argparse.Options{Help: "Print traceroute hop path by ASN and location"}),
outputPath: parser.String("o", "output", &argparse.Options{Help: "Write trace result to FILE (RealtimePrinter only)"}),
outputDefault: parser.Flag("O", "output-default", &argparse.Options{Help: "Write trace result to the default log file (/tmp/trace.log)"}),
tablePrint: parser.Flag("", "table", &argparse.Options{Help: "Output trace results as a final summary table (traceroute report mode)"}),
jsonPrint: parser.Flag("j", "json", &argparse.Options{Help: "Output trace results as JSON"}),
classicPrint: parser.Flag("c", "classic", &argparse.Options{Help: "Classic Output trace results like BestTrace"}),
}
}
return tracerouteOutputFlags{
routePath: ptrBool(false),
outputPath: ptrStr(""),
outputDefault: ptrBool(false),
tablePrint: ptrBool(false),
jsonPrint: ptrBool(false),
classicPrint: ptrBool(false),
}
}
func registerWebUIFlags(parser *argparse.Parser) webUIFlags {
return registerWebUIFlagsWithAvailability(parser, enableWebUI)
}
func registerWebUIFlagsWithAvailability(parser *argparse.Parser, enabled bool) webUIFlags {
if enabled {
return webUIFlags{
deployListen: parser.String("", "listen", &argparse.Options{Help: "Set listen address for web console (e.g. 127.0.0.1:30080)"}),
deploy: parser.Flag("", "deploy", &argparse.Options{Help: "Start the Gin powered web console"}),
}
}
return webUIFlags{
deployListen: parser.String("", "listen", &argparse.Options{Help: "Set listen address for web console (full build only; unavailable in this binary)"}),
deploy: parser.Flag("", "deploy", &argparse.Options{Help: "Start the Gin powered web console (full build only; unavailable in this binary)"}),
}
}
func registerPacketIntervalFlag(parser *argparse.Parser) *int {
if !defaultMTR {
return parser.Int("z", "send-time", &argparse.Options{Default: defaultPacketIntervalMs, Help: buildPacketIntervalHelp()})
}
return ptrInt(defaultPacketIntervalMs)
}
func buildRawHelp() string {
rawHelp := "Machine-friendly output"
if enableMTR {
mtrFlags := "--mtr/-r/-w"
if defaultMTR {
mtrFlags = "-r/-w"
}
rawHelp += ". With MTR (" + mtrFlags + "), enables streaming raw event mode"
}
return rawHelp
}
func buildTTLIntervalHelp() string {
if !enableMTR {
return "Advanced: TTL-group interval [ms] in normal traceroute. 100-300ms is usually safe; lower is faster but may trigger rate limits"
}
if defaultMTR {
return "Advanced: per-hop probe interval [ms] in MTR mode. 500-1000ms is a good starting point; omitted defaults to 1000ms"
}
return "Advanced: TTL-group interval [ms] in normal traceroute. In MTR mode (--mtr/-r/-w, including --raw), this becomes per-hop probe interval. 500-1000ms is a good MTR starting range"
}
func registerTTLIntervalFlag(parser *argparse.Parser) *int {
return registerTTLIntervalFlagWithMTRSupport(parser, enableMTR)
}
func registerTTLIntervalFlagWithMTRSupport(parser *argparse.Parser, mtrEnabled bool) *int {
options := &argparse.Options{Help: buildTTLIntervalHelp()}
if !mtrEnabled {
options.Default = defaultTracerouteTTLIntervalMs
}
return parser.Int("i", "ttl-time", options)
}
func applyTTLIntervalDefault(ttlInterval *int, ttlTimeExplicit, effectiveMTR bool) {
if ttlInterval == nil || ttlTimeExplicit || effectiveMTR {
return
}
*ttlInterval = defaultTracerouteTTLIntervalMs
}
func registerDisableMaptraceFlag(parser *argparse.Parser) *bool {
if !defaultMTR {
return parser.Flag("M", "map", &argparse.Options{Help: "Disable Print Trace Map"})
}
return ptrBool(true)
}
func registerGlobalpingFlag(parser *argparse.Parser) *string {
return registerGlobalpingFlagWithAvailability(parser, enableGlobalping)
}
func registerGlobalpingFlagWithAvailability(parser *argparse.Parser, enabled bool) *string {
if enabled {
return parser.String("", "from", &argparse.Options{Help: "Run traceroute via Globalping (https://globalping.io/network) from a specified location. The location field accepts continents, countries, regions, cities, ASNs, ISPs, or cloud regions."})
}
return parser.String("", "from", &argparse.Options{Help: "Run traceroute via Globalping (full build only; unavailable in this binary)"})
}
func registerMTRFlags(parser *argparse.Parser) mtrCLIFlags {
if enableMTR {
mtrMode := ptrBool(true)
if !defaultMTR {
mtrMode = parser.Flag("t", "mtr", &argparse.Options{Help: "Enable MTR (My Traceroute) continuous probing mode"})
}
return mtrCLIFlags{
mtrMode: mtrMode,
reportMode: parser.Flag("r", "report", &argparse.Options{Help: "MTR report mode (non-interactive, implies --mtr); can trigger MTR without --mtr"}),
wideMode: parser.Flag("w", "wide", &argparse.Options{Help: "MTR wide report mode (implies --mtr --report); alone equals --mtr --report --wide"}),
showIPs: parser.Flag("", "show-ips", &argparse.Options{Help: "MTR only: display both PTR hostnames and numeric IPs (PTR first, IP in parentheses)"}),
ipInfoMode: parser.Int("y", "ipinfo", &argparse.Options{Default: 0, Help: "Set initial MTR TUI host info mode (0-4). TUI only; ignored in --report/--raw. 0:IP/PTR 1:ASN 2:City 3:Owner 4:Full"}),
}
}
return mtrCLIFlags{
mtrMode: ptrBool(false),
reportMode: ptrBool(false),
wideMode: ptrBool(false),
showIPs: ptrBool(false),
ipInfoMode: ptrInt(0),
}
}
func registerFileFlag(parser *argparse.Parser) *string {
if !defaultMTR {
return parser.String("", "file", &argparse.Options{Help: "Read IP Address or domain name from file"})
}
return ptrStr("")
}
func deriveEffectiveMTRModes(mtrMode, reportMode, wideMode, rawPrint bool) effectiveMTRModes {
mtr := mtrMode || reportMode || wideMode
return effectiveMTRModes{
mtr: mtr,
report: reportMode || wideMode,
wide: wideMode,
raw: mtr && rawPrint,
}
}
func detectExplicitProbeFlags(parser *argparse.Parser) (queriesExplicit, ttlTimeExplicit, packetSizeExplicit, tosExplicit bool) {
for _, a := range parser.GetArgs() {
if !a.GetParsed() {
continue
}
switch a.GetLname() {
case "queries":
queriesExplicit = true
case "ttl-time":
ttlTimeExplicit = true
case "psize":
packetSizeExplicit = true
case "tos":
tosExplicit = true
}
}
return queriesExplicit, ttlTimeExplicit, packetSizeExplicit, tosExplicit
}
func resolvePacketSizeArg(packetSize int, explicit bool, method trace.Method, dstIP net.IP) int {
if explicit {
return packetSize
}
return trace.DefaultPacketSize(method, dstIP)
}
func applyColorMode(noColor bool) {
color.NoColor = noColor
}
func shouldForceNoColorForMTUNonTTY(mtuMode, jsonPrint, stdoutIsTTY bool) bool {
return mtuMode && !jsonPrint && !stdoutIsTTY
}
func printStartupBanner(jsonPrint bool, effectiveMTR bool) {
if !jsonPrint && !effectiveMTR {
printer.Version()
}
}
func maybePrintVersion(ver bool) bool {
if !ver {
return false
}
printer.CopyRight()
os.Exit(0)
return true
}
func maybeRunDeployMode(deploy bool, deployListen string) bool {
if !deploy {
return false
}
if !enableWebUI {
if err := runDeploy(""); err != nil {
if util.EnvDevMode {
panic(err)
}
log.Fatal(err)
}
return true
}
capabilitiesCheck()
listenAddr := strings.TrimSpace(deployListen)
envAddr := strings.TrimSpace(util.EnvDeployAddr)
userProvided := listenAddr != "" || envAddr != ""
if listenAddr == "" {
listenAddr = envAddr
}
if listenAddr == "" {
listenAddr = defaultLocalListenAddr()
}
info := buildListenInfo(listenAddr)
fmt.Printf("启动 NextTrace Web 控制台,监听地址: %s\n", info.Binding)
if !userProvided {
fmt.Println("远程访问请显式设置 --listen(例如 --listen 0.0.0.0:1080)。")
}
if info.Access != "" && info.Access != info.Binding {
fmt.Printf("如需远程访问,请尝试: %s\n", info.Access)
}
fmt.Println("注意:Web 控制台的安全性有限,请在确保安全的前提下使用,如有必要请使用ACL等方式加强安全性")
if err := runDeploy(listenAddr); err != nil {
if util.EnvDevMode {
panic(err)
}
log.Fatal(err)
}
return true
}
func handleStartupModes(noColor, jsonPrint bool, modes effectiveMTRModes, ver, deploy bool, deployListen string, init bool, osType int) bool {
applyColorMode(noColor)
printStartupBanner(jsonPrint, modes.mtr)
if maybePrintVersion(ver) {
return true
}
if maybeRunDeployMode(deploy, deployListen) {
return true
}
return maybePrepareWinDivert(init, osType)
}
func resolveOSType() int {
switch runtime.GOOS {
case "darwin":
return 1
case "windows":
return 2
default:
return 3
}
}
func maybePrepareWinDivert(init bool, osType int) bool {
if !init || osType != 2 {
return false
}
if err := windivert.PrepareWinDivertRuntime(); err != nil {
if util.EnvDevMode {
panic(err)
}
log.Fatal(err)
}
fmt.Println("WinDivert runtime is ready.")
return true
}
func applyDefaultPort(port *int, udp bool) {
if *port != 0 {
return
}
if udp {
*port = 33494
return
}
*port = 80
}
func clampProbeSettings(tcp bool, numMeasurements, maxAttempts *int) {
if tcp {
return
}
if *numMeasurements > 255 {
fmt.Println("Query 最大值为 255,已自动调整为 255")
*numMeasurements = 255
}
if *maxAttempts > 255 {
fmt.Println("MaxAttempt 最大值为 255,已自动调整为 255")
*maxAttempts = 255
}
}
func resolveTraceMethod(tcp, udp bool) trace.Method {
switch {
case tcp:
return trace.TCPTrace
case udp:
return trace.UDPTrace
default:
return trace.ICMPTrace
}
}
func maybeRunFastTraceMode(from string, fastTraceFlag bool, file string, params fastTrace.ParamsFastTrace, method trace.Method) bool {
if from != "" || (!fastTraceFlag && file == "") {
return false
}
fastTrace.FastTest(method, params)
if params.OutputPath != "" {
fmt.Printf("您的追踪日志已经存放在 %s 中\n", params.OutputPath)
}
os.Exit(0)
return true
}
func configureGeoDNS(dot string) {
if dot != "" {
util.SetGeoDNSResolver(dot)
}
}
func normalizeCLITarget(raw string) string {
domain := raw
if strings.Contains(domain, "/") {
domain = "n" + domain
parts := strings.Split(domain, "/")
if len(parts) < 3 {
return ""
}
domain = parts[2]
}
if strings.Contains(domain, "]") && strings.Contains(domain, "[") {
inner := strings.SplitN(domain, "]", 2)[0]
parts := strings.SplitN(inner, "[", 2)
if len(parts) >= 2 {
return parts[1]
}
return domain
}
if strings.Contains(domain, ":") && strings.Count(domain, ":") == 1 {
return strings.Split(domain, ":")[0]
}
return domain
}
func resolveCLITargetOrExit(raw string, usage string) string {
if raw == "" {
fmt.Print(usage)
return ""
}
domain := normalizeCLITarget(raw)
if domain == "" {
if strings.Contains(raw, "/") {
fmt.Println("Invalid input")
} else {
fmt.Print(usage)
}
}
return domain
}
func applyDN42Mode(enabled bool, dataOrigin *string, disableMaptrace *bool) {
if !enabled {
return
}
config.InitConfig()
*dataOrigin = "DN42"
*disableMaptrace = true
}
func prepareRuntimeEnvironment(ctx context.Context, dn42 bool, dataOrigin *string, disableMaptrace *bool, powProvider *string) *wshandle.WsConn {
capabilitiesCheck()
applyDN42Mode(dn42, dataOrigin, disableMaptrace)
return initLeoWebsocket(ctx, dataOrigin, powProvider)
}
func initLeoWebsocket(ctx context.Context, dataOrigin, powProvider *string) *wshandle.WsConn {
if !strings.EqualFold(*dataOrigin, "LEOMOEAPI") {
return nil
}
if !strings.EqualFold(*powProvider, "api.nxtrace.org") {
util.PowProviderParam = *powProvider
}
if util.EnvDataProvider != "" {
*dataOrigin = util.EnvDataProvider
}
if !strings.EqualFold(*dataOrigin, "LEOMOEAPI") {
return nil
}
leoWs := wshandle.NewWithContext(ctx)
if leoWs != nil {
leoWs.Interrupt = make(chan os.Signal, 1)
signal.Notify(leoWs.Interrupt, os.Interrupt)
}
return leoWs
}
func closeLeoWebsocket(leoWs *wshandle.WsConn) {
if leoWs != nil {
leoWs.Close()
}
}
func maybeHandleGlobalping(from string, opts *trace.GlobalpingOptions, conf *trace.Config) bool {
if from == "" {
return false
}
handleGlobalpingTrace(opts, conf)
return true
}
func lookupTargetIP(ctx context.Context, domain string, ipv4Only, ipv6Only bool, dot string, jsonPrint bool) (net.IP, error) {
switch {
case ipv6Only:
return domainLookupFn(ctx, domain, "6", dot, jsonPrint)
case ipv4Only:
return domainLookupFn(ctx, domain, "4", dot, jsonPrint)
default:
return domainLookupFn(ctx, domain, "all", dot, jsonPrint)
}
}
func lookupTargetIPOrExit(ctx context.Context, domain string, ipv4Only, ipv6Only bool, dot string, jsonPrint bool) net.IP {
ip, err := lookupTargetIP(ctx, domain, ipv4Only, ipv6Only, dot, jsonPrint)
if err != nil {
if util.EnvDevMode {
panic(err)
}
log.Fatal(err)
}
return ip
}
func resolveSourceDevice(srcDev string) (*net.Interface, error) {
trimmed := strings.TrimSpace(srcDev)
if trimmed == "" {
return nil, nil
}
dev, err := net.InterfaceByName(trimmed)
if err != nil || dev == nil {
return nil, fmt.Errorf("无法找到网卡 %q: %v", trimmed, err)
}
return dev, nil
}
func resolveSourceDeviceAddr(dev *net.Interface, dstIP net.IP) string {
if dev == nil || dstIP == nil {
return ""
}
addrs, err := dev.Addrs()
if err != nil {
return ""
}
var candidate string
for _, addr := range addrs {
ipNet, ok := addr.(*net.IPNet)
if !ok {
continue
}
if (ipNet.IP.To4() == nil) != (dstIP.To4() == nil) {
continue
}
candidate = ipNet.IP.String()
parsed := net.ParseIP(candidate)
if parsed != nil && !(parsed.IsPrivate() ||
parsed.IsLoopback() ||
parsed.IsLinkLocalUnicast() ||
parsed.IsLinkLocalMulticast()) {
return candidate
}
}
return candidate
}
func resolveFallbackSrcAddr(dstIP net.IP) string {
if dstIP == nil {
return ""
}
if util.IsIPv6(dstIP) {
resolved, _ := util.LocalIPPortv6(dstIP, nil, "udp6")
if resolved != nil {
return resolved.String()
}
return ""
}
resolved, _ := util.LocalIPPort(dstIP, nil, "udp")
if resolved != nil {
return resolved.String()
}
return ""
}
func resolveConfiguredSrcAddr(dstIP net.IP, srcAddr, srcDev string) (resolved string, explicit bool, err error) {
if trimmed := strings.TrimSpace(srcAddr); trimmed != "" {
return trimmed, true, nil
}
dev, err := resolveSourceDevice(srcDev)
if err != nil {
return "", false, err
}
if resolved := resolveSourceDeviceAddr(dev, dstIP); resolved != "" {
return resolved, false, nil
}
return resolveFallbackSrcAddr(dstIP), false, nil
}
func applySourceDevice(srcDev string, dstIP net.IP, srcAddr *string) {
dev, err := resolveSourceDevice(srcDev)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if dev == nil {
return
}
util.SrcDev = dev.Name
if srcAddr == nil || strings.TrimSpace(*srcAddr) != "" {
return
}
if resolved := resolveSourceDeviceAddr(dev, dstIP); resolved != "" {
*srcAddr = resolved
}
}
func printTraceNav(jsonPrint bool, effectiveMTR bool, ip net.IP, domain, dataOrigin string, maxHops, packetSize int, srcAddr string, method trace.Method) {
if !jsonPrint && !effectiveMTR {
printer.PrintTraceRouteNav(ip, domain, dataOrigin, maxHops, packetSize, srcAddr, string(method))
}
}
func buildTraceConfig(
osType, icmpMode int,
dn42 bool,
srcAddr string,
sourceDevice string,
srcPort int,
beginHop int,
ip net.IP,
port int,
maxHops int,
packetInterval int,
ttlInterval int,
numMeasurements int,
maxAttempts int,
parallelRequests int,
lang string,
noRDNS bool,
alwaysRDNS bool,
dataOrigin string,
timeout int,
packetSize int,
randomPacketSize bool,
tos int,
disableMPLS bool,
) trace.Config {
return trace.Config{
OSType: osType,
ICMPMode: icmpMode,
DN42: dn42,
SrcAddr: srcAddr,
SrcPort: srcPort,
SourceDevice: strings.TrimSpace(sourceDevice),
BeginHop: beginHop,
DstIP: ip,
DstPort: port,
MaxHops: maxHops,
PacketInterval: packetInterval,
TTLInterval: ttlInterval,
NumMeasurements: numMeasurements,
MaxAttempts: maxAttempts,
ParallelRequests: parallelRequests,
Lang: lang,
RDNS: !noRDNS,
AlwaysWaitRDNS: alwaysRDNS,
IPGeoSource: ipgeo.GetSource(dataOrigin),
Timeout: time.Duration(timeout) * time.Millisecond,
PktSize: packetSize,
RandomPacketSize: randomPacketSize,
TOS: tos,
DisableMPLS: disableMPLS,
}
}
func maybeRunMTRMode(
modes effectiveMTRModes,
method trace.Method,
conf trace.Config,
queriesExplicit bool,
numMeasurements int,
ttlTimeExplicit bool,
ttlInterval int,
domain string,
dataOrigin string,
showIPs bool,
ipInfoMode int,
) bool {
if !modes.mtr {
return false
}
mtrMaxPerHop, mtrHopIntervalMs := deriveMTRProbeParams(
modes.report,
queriesExplicit,
numMeasurements,
ttlTimeExplicit,
ttlInterval,
)
switch chooseMTRRunMode(modes.raw, modes.report) {
case mtrRunRaw:
runMTRRaw(method, conf, mtrHopIntervalMs, mtrMaxPerHop, dataOrigin)
case mtrRunReport:
runMTRReport(method, conf, mtrHopIntervalMs, mtrMaxPerHop, domain, dataOrigin, modes.wide, showIPs)
default:
if ipInfoMode < 0 || ipInfoMode > 4 {
fmt.Fprintf(os.Stderr, "--ipinfo/-y 必须在 0-4 范围内,当前值: %d\n", ipInfoMode)
os.Exit(1)
}
runMTRTUI(method, conf, mtrHopIntervalMs, mtrMaxPerHop, domain, dataOrigin, showIPs, ipInfoMode)
}
return true
}
func resolveOutputPath(outputPath string, outputDefault bool) (string, error) {
trimmed := strings.TrimSpace(outputPath)
if trimmed != "" && outputDefault {
return "", errors.New("--output 与 --output-default 不能同时使用")
}
if trimmed != "" {
return trimmed, nil
}
if outputDefault {
return tracelog.DefaultPath, nil
}
return "", nil
}
func validateJSONRealtimeOutput(jsonPrint bool, outputPath string) error {
if jsonPrint && strings.TrimSpace(outputPath) != "" {
return errors.New("--json 不能与 --output/--output-default 同时使用")
}
return nil
}
func setFastIPOutputSuppression(suppress bool) func() {
prev := util.SuppressFastIPOutput
util.SuppressFastIPOutput = suppress
return func() {
util.SuppressFastIPOutput = prev
}
}
func configureTracePrinters(conf *trace.Config, tablePrint, classicPrint, rawPrint bool, outputPath string) (func() error, error) {
if tablePrint {
return nil, nil
}
router := false
switch {
case classicPrint:
conf.RealtimePrinter = printer.ClassicPrinter
case rawPrint:
conf.RealtimePrinter = printer.EasyPrinter
case outputPath != "":
f, err := tracelog.OpenFile(outputPath)
if err != nil {
return nil, err
}
conf.RealtimePrinter = tracelog.NewRealtimePrinter(io.MultiWriter(os.Stdout, f))
return f.Close, nil
case router:
conf.RealtimePrinter = printer.RealtimePrinterWithRouter
fmt.Println("路由表数据源由 BGP.Tools 提供,在此特表感谢")
default:
conf.RealtimePrinter = printer.RealtimePrinter
}
return nil, nil
}
func applyJSONOutputMode(conf *trace.Config, jsonPrint bool) {
if jsonPrint {
conf.RealtimePrinter = nil
conf.AsyncPrinter = nil
}
}
func maybeRunUninterruptedRaw(rawPrint bool, method trace.Method, conf trace.Config) {
if !(util.Uninterrupted && rawPrint) {
return
}
for {
if _, err := trace.Traceroute(method, conf); err != nil {
fmt.Println(err)
}
}
}
func runTraceOnce(method trace.Method, conf trace.Config) (*trace.Result, bool) {
res, err := trace.Traceroute(method, conf)
if err != nil {
if !errors.Is(err, context.Canceled) {
fmt.Println(err)
}
return nil, false
}
return res, true
}
func finalizeTraceResult(ctx context.Context, res *trace.Result, tablePrint, tableClearScreen, routePath bool, dstIP net.IP, disableMaptrace, jsonPrint bool, dataOrigin string) {
if tablePrint {
printer.TracerouteTablePrinter(res, tableClearScreen)
}
if routePath {
reporter.New(res, dstIP.String()).Print()
}
r, err := json.Marshal(res)
if err != nil {
fmt.Println(err)
return
}
if !disableMaptrace &&
(util.StringInSlice(strings.ToUpper(dataOrigin), []string{"LEOMOEAPI", "IPINFO", "IP-API.COM", "IPAPI.COM"})) {
url, err := tracemap.GetMapUrlWithContext(ctx, string(r))
if err != nil {
fmt.Println(err)
return
}
res.TraceMapUrl = url
if !jsonPrint {
tracemap.PrintMapUrl(url)
}
}
r, err = json.Marshal(res)
if err != nil {
fmt.Println(err)
return
}
if jsonPrint {
fmt.Println(string(r))
}
}
func Execute() {
parser := argparse.NewParser(appBinName, "An open source visual route tracking CLI tool")
// Override HelpFunc so positional arg names are sanitized in --help output
parser.HelpFunc = func(c *argparse.Command, msg interface{}) string {
return sanitizeUsagePositionalArgs(c.Usage(msg))
}
init := registerInitFlag(parser)
ipv4Only := parser.Flag("4", "ipv4", &argparse.Options{Help: "Use IPv4 only"})
ipv6Only := parser.Flag("6", "ipv6", &argparse.Options{Help: "Use IPv6 only"})
tcp := parser.Flag("T", "tcp", &argparse.Options{Help: "Use TCP SYN for tracerouting (default dest-port is 80)"})
udp := parser.Flag("U", "udp", &argparse.Options{Help: "Use UDP SYN for tracerouting (default dest-port is 33494)"})
mtuMode := registerMTUFlag(parser)
fastTraceFlag := registerFastTraceFlag(parser)
port := parser.Int("p", "port", &argparse.Options{Help: "Set the destination port to use. With default of 80 for \"tcp\", 33494 for \"udp\""})
icmpMode := registerICMPModeFlag(parser)
numMeasurements := parser.Int("q", "queries", &argparse.Options{Default: 3, Help: buildQueriesHelp()})
maxAttempts := parser.Int("", "max-attempts", &argparse.Options{Help: buildMaxAttemptsHelp()})
parallelRequests := parser.Int("", "parallel-requests", &argparse.Options{Default: 18, Help: buildParallelRequestsHelp()})
maxHops := parser.Int("m", "max-hops", &argparse.Options{Default: 30, Help: "Set the max number of hops (max TTL to be reached)"})
dataOrigin := parser.Selector("d", "data-provider", []string{"IP.SB", "ip.sb", "IPInfo", "ipinfo", "IPInsight", "ipinsight", "IPAPI.com", "ip-api.com", "IPInfoLocal", "ipinfolocal", "chunzhen", "LeoMoeAPI", "leomoeapi", "ipdb.one", "disable-geoip"}, &argparse.Options{Default: "LeoMoeAPI",
Help: "Choose IP Geograph Data Provider [IP.SB, IPInfo, IPInsight, IP-API.com, IPInfoLocal, CHUNZHEN, disable-geoip]"})
powProvider := parser.Selector("", "pow-provider", []string{"api.nxtrace.org", "sakura"}, &argparse.Options{Default: "api.nxtrace.org",
Help: "Choose PoW Provider [api.nxtrace.org, sakura] For China mainland users, please use sakura"})
norDNS := parser.Flag("n", "no-rdns", &argparse.Options{Help: "Do not resolve IP addresses to their domain names"})
alwaysrDNS := parser.Flag("a", "always-rdns", &argparse.Options{Help: "Always resolve IP addresses to their domain names"})
outputFlags := registerTracerouteOutputFlags(parser)
routePath := outputFlags.routePath
outputPath := outputFlags.outputPath
outputDefault := outputFlags.outputDefault
tablePrint := outputFlags.tablePrint
jsonPrint := outputFlags.jsonPrint
classicPrint := outputFlags.classicPrint
dn42 := parser.Flag("", "dn42", &argparse.Options{Help: "DN42 Mode"})
rawPrint := parser.Flag("", "raw", &argparse.Options{Help: buildRawHelp()})
beginHop := parser.Int("f", "first", &argparse.Options{Default: 1, Help: "Start from the first_ttl hop (instead of 1)"})
disableMaptrace := registerDisableMaptraceFlag(parser)
disableMPLS := parser.Flag("e", "disable-mpls", &argparse.Options{Help: "Disable MPLS"})
ver := parser.Flag("V", "version", &argparse.Options{Help: "Print version info and exit"})
srcAddr := parser.String("s", "source", &argparse.Options{Help: "Use source address src_addr for outgoing packets"})
srcPort := parser.Int("", "source-port", &argparse.Options{Help: "Use source port src_port for outgoing packets"})
srcDev := parser.String("D", "dev", &argparse.Options{Help: "Use the following Network Devices as the source address in outgoing packets"})
webFlags := registerWebUIFlags(parser)
deployListen := webFlags.deployListen
deploy := webFlags.deploy
//router := parser.Flag("R", "route", &argparse.Options{Help: "Show Routing Table [Provided By BGP.Tools]"})
// ── Send-time: hidden in ntr (always ignored in MTR mode) ──
packetInterval := registerPacketIntervalFlag(parser)
ttlInterval := registerTTLIntervalFlag(parser)
timeout := parser.Int("", "timeout", &argparse.Options{Default: 1000, Help: buildTimeoutHelp()})
packetSize := parser.Int("", "psize", &argparse.Options{Help: buildPayloadSizeHelp()})
tos := parser.Int("Q", "tos", &argparse.Options{Default: 0, Help: buildTOSHelp()})
dot := parser.Selector("", "dot-server", []string{"dnssb", "aliyun", "dnspod", "google", "cloudflare"}, &argparse.Options{
Help: "Use DoT Server for DNS Parse [dnssb, aliyun, dnspod, google, cloudflare]"})
lang := parser.Selector("g", "language", []string{"en", "cn"}, &argparse.Options{Default: "cn",
Help: "Choose the language for displaying [en, cn]"})
noColor := parser.Flag("C", "no-color", &argparse.Options{Help: "Disable Colorful Output"})
// ── Globalping flag (full only) ──
from := registerGlobalpingFlag(parser)
// ── MTR flags (full & ntr only) ──
mtrFlags := registerMTRFlags(parser)
mtrMode := mtrFlags.mtrMode
reportMode := mtrFlags.reportMode
wideMode := mtrFlags.wideMode
showIPs := mtrFlags.showIPs
ipInfoMode := mtrFlags.ipInfoMode
// ── File: hidden in ntr (conflicts with default MTR mode) ──
file := registerFileFlag(parser)
str := parser.StringPositional(&argparse.Options{Help: "Trace target: IPv4 address (e.g. 8.8.8.8), IPv6 address (e.g. 2001:db8::1), domain name (e.g. example.com), or URL (e.g. https://example.com)"})
err := parser.Parse(normalizeNegativePacketSizeArgs(os.Args))
if err != nil {
// In case of error print error and print usage
// This can also be done by passing -h or --help flags
fmt.Print(sanitizeUsagePositionalArgs(parser.Usage(err)))
return
}
rootCtx, stop
gitextract_otbi_aku/
├── .cross_compile.sh
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── build.yml
│ ├── publishNewFormula.yml
│ ├── test.yml
│ └── triggerDebRepo.yml
├── .gitignore
├── AGENTS.md
├── CLAUDE.md
├── LICENSE
├── README.md
├── README_zh_CN.md
├── _config.yml
├── assets/
│ └── windivert/
│ ├── divert.go
│ ├── x64/
│ │ └── WinDivert64.sys
│ └── x86/
│ └── WinDivert32.sys
├── cmd/
│ ├── cmd.go
│ ├── cmd_test.go
│ ├── deploy_disabled.go
│ ├── deploy_full.go
│ ├── flavor_full.go
│ ├── flavor_ntr.go
│ ├── flavor_tiny.go
│ ├── globalping_disabled.go
│ ├── globalping_full.go
│ ├── listen_info_test.go
│ ├── mtr_mode.go
│ ├── mtr_mode_test.go
│ ├── mtr_ui.go
│ ├── mtu_mode.go
│ └── mtu_mode_test.go
├── config/
│ ├── basic.go
│ └── viper.go
├── dn42/
│ ├── dn42.go
│ ├── geofeed.go
│ ├── geofeed_test.go
│ ├── ptr.go
│ └── ptr_test.go
├── fast_trace/
│ ├── basic.go
│ ├── fast_trace ipv6.go
│ ├── fast_trace.go
│ └── fast_trace_test.go
├── geofeed.example.csv
├── go.mod
├── go.sum
├── internal/
│ └── hoprender/
│ └── group.go
├── ipgeo/
│ ├── chunzhen.go
│ ├── dn42.go
│ ├── dn42_test.go
│ ├── ipapicom.go
│ ├── ipdbone.go
│ ├── ipfilter.go
│ ├── ipfilter_test.go
│ ├── ipgeo.go
│ ├── ipgeo_test.go
│ ├── ipinfo.go
│ ├── ipinfoLocal.go
│ ├── ipinsight.go
│ ├── ipsb.go
│ ├── leo.go
│ ├── tokens.go
│ └── tokens_test.go
├── main.go
├── nt_config.yaml
├── nt_install.sh
├── pow/
│ ├── pow.go
│ └── pow_test.go
├── printer/
│ ├── basic.go
│ ├── classic_printer.go
│ ├── easy.go
│ ├── mtr_raw.go
│ ├── mtr_table.go
│ ├── mtr_table_test.go
│ ├── mtr_tui.go
│ ├── mtr_tui_color.go
│ ├── printer.go
│ ├── printer_test.go
│ ├── realtime_common.go
│ ├── realtime_printer.go
│ ├── realtime_printer_router.go
│ ├── tableprinter.go
│ └── tableprinter_test.go
├── ptr.example.csv
├── reporter/
│ ├── reporter.go
│ └── reporter_test.go
├── server/
│ ├── browser_access.go
│ ├── browser_access_test.go
│ ├── cache_handler.go
│ ├── handlers.go
│ ├── mtr.go
│ ├── server.go
│ ├── trace_handler.go
│ ├── trace_handler_test.go
│ ├── web/
│ │ ├── assets/
│ │ │ ├── app.js
│ │ │ ├── mtr_agg.js
│ │ │ ├── mtr_agg.test.cjs
│ │ │ ├── mtr_truncation.test.cjs
│ │ │ ├── style.css
│ │ │ ├── trace_form.js
│ │ │ └── trace_form.test.cjs
│ │ └── index.html
│ ├── ws_handler.go
│ └── ws_handler_test.go
├── trace/
│ ├── cache.go
│ ├── globalping.go
│ ├── globalping_test.go
│ ├── globalping_types.go
│ ├── icmp_ipv4.go
│ ├── icmp_ipv6.go
│ ├── internal/
│ │ ├── icmp_common.go
│ │ ├── icmp_darwin.go
│ │ ├── icmp_decode.go
│ │ ├── icmp_decode_test.go
│ │ ├── icmp_unix.go
│ │ ├── icmp_windows.go
│ │ ├── icmp_windows_test.go
│ │ ├── packet_listener.go
│ │ ├── tcp_common.go
│ │ ├── tcp_darwin.go
│ │ ├── tcp_probe_decode.go
│ │ ├── tcp_probe_decode_test.go
│ │ ├── tcp_unix.go
│ │ ├── tcp_windows.go
│ │ ├── udp_common.go
│ │ ├── udp_darwin.go
│ │ ├── udp_unix.go
│ │ ├── udp_windows.go
│ │ └── windivert_sniff_windows.go
│ ├── mtr_loop_runtime.go
│ ├── mtr_raw.go
│ ├── mtr_raw_test.go
│ ├── mtr_runner.go
│ ├── mtr_runner_test.go
│ ├── mtr_scheduler.go
│ ├── mtr_scheduler_runtime.go
│ ├── mtr_scheduler_test.go
│ ├── mtr_stats.go
│ ├── mtr_stats_helpers.go
│ ├── mtr_stats_test.go
│ ├── mtu/
│ │ ├── decode.go
│ │ ├── decode_test.go
│ │ ├── metadata.go
│ │ ├── metadata_test.go
│ │ ├── runner.go
│ │ ├── runner_test.go
│ │ ├── socket_prober.go
│ │ ├── socket_prober_read_default.go
│ │ ├── socket_prober_read_windows.go
│ │ ├── socket_prober_test.go
│ │ ├── socketopts_darwin.go
│ │ ├── socketopts_linux.go
│ │ ├── socketopts_stub.go
│ │ ├── socketopts_windows.go
│ │ └── types.go
│ ├── packet_size.go
│ ├── packet_size_test.go
│ ├── quic.go
│ ├── tcp_ipv4.go
│ ├── tcp_ipv6.go
│ ├── tcp_match.go
│ ├── tcp_match_test.go
│ ├── temp_printer.go
│ ├── trace.go
│ ├── trace_runtime_test.go
│ ├── udp_ipv4.go
│ └── udp_ipv6.go
├── tracelog/
│ ├── log.go
│ └── log_test.go
├── tracemap/
│ ├── tracemap.go
│ └── tracemap_test.go
├── util/
│ ├── common.go
│ ├── dns_resolver.go
│ ├── dns_resolver_test.go
│ ├── dot.go
│ ├── env.go
│ ├── env_test.go
│ ├── frag.go
│ ├── http_client_geo.go
│ ├── http_client_geo_test.go
│ ├── latency.go
│ ├── latency_test.go
│ ├── pcap.go
│ ├── privilege_stub.go
│ ├── privilege_windows.go
│ ├── trace.go
│ ├── trace_privilege.go
│ ├── trace_privilege_darwin.go
│ ├── trace_privilege_linux.go
│ ├── trace_privilege_stub.go
│ ├── trace_privilege_windows.go
│ ├── trace_test.go
│ ├── udp.go
│ ├── util.go
│ └── util_test.go
└── wshandle/
├── client.go
└── client_test.go
SYMBOL INDEX (1907 symbols across 168 files)
FILE: assets/windivert/divert.go
function PrepareWinDivertRuntime (line 27) | func PrepareWinDivertRuntime() error {
function writeIfChecksumDiff (line 59) | func writeIfChecksumDiff(dst string, data []byte) error {
FILE: cmd/cmd.go
function ptrBool (line 35) | func ptrBool(v bool) *bool { return &v }
function ptrStr (line 36) | func ptrStr(v string) *string { return &v }
function ptrInt (line 37) | func ptrInt(v int) *int { return &v }
type listenInfo (line 39) | type listenInfo struct
constant defaultPacketIntervalMs (line 45) | defaultPacketIntervalMs = 50
constant defaultTracerouteTTLIntervalMs (line 46) | defaultTracerouteTTLIntervalMs = 300
function normalizeListenAddr (line 53) | func normalizeListenAddr(addr string) string {
function splitListenAddr (line 64) | func splitListenAddr(effective string) (host, port string, ok bool) {
function formatHTTPListenURL (line 78) | func formatHTTPListenURL(host, port string) string {
function resolveListenAccessHost (line 85) | func resolveListenAccessHost(host string) string {
function buildListenInfo (line 92) | func buildListenInfo(addr string) listenInfo {
function isDigitsOnly (line 116) | func isDigitsOnly(s string) bool {
function normalizeNegativePacketSizeArgs (line 128) | func normalizeNegativePacketSizeArgs(args []string) []string {
function isNegativeInteger (line 146) | func isNegativeInteger(s string) bool {
function guessLocalIPv4 (line 154) | func guessLocalIPv4() string {
function defaultLocalListenAddr (line 168) | func defaultLocalListenAddr() string {
function hasIPv4Loopback (line 178) | func hasIPv4Loopback() bool {
function hasIPv6Loopback (line 193) | func hasIPv6Loopback() bool {
function sanitizeUsagePositionalArgs (line 211) | func sanitizeUsagePositionalArgs(usage string) string {
function fixPositionalAlignment (line 240) | func fixPositionalAlignment(usage string) string {
type effectiveMTRModes (line 287) | type effectiveMTRModes struct
type tracerouteOutputFlags (line 294) | type tracerouteOutputFlags struct
type webUIFlags (line 303) | type webUIFlags struct
type mtrCLIFlags (line 308) | type mtrCLIFlags struct
function registerInitFlag (line 316) | func registerInitFlag(parser *argparse.Parser) *bool {
function registerFastTraceFlag (line 323) | func registerFastTraceFlag(parser *argparse.Parser) *bool {
function registerMTUFlag (line 330) | func registerMTUFlag(parser *argparse.Parser) *bool {
function registerICMPModeFlag (line 337) | func registerICMPModeFlag(parser *argparse.Parser) *int {
function buildQueriesHelp (line 344) | func buildQueriesHelp() string {
function buildMaxAttemptsHelp (line 351) | func buildMaxAttemptsHelp() string {
function buildParallelRequestsHelp (line 355) | func buildParallelRequestsHelp() string {
function buildPacketIntervalHelp (line 359) | func buildPacketIntervalHelp() string {
function buildTimeoutHelp (line 367) | func buildTimeoutHelp() string {
function buildPayloadSizeHelp (line 371) | func buildPayloadSizeHelp() string {
function buildTOSHelp (line 375) | func buildTOSHelp() string {
function registerTracerouteOutputFlags (line 379) | func registerTracerouteOutputFlags(parser *argparse.Parser) tracerouteOu...
function registerWebUIFlags (line 400) | func registerWebUIFlags(parser *argparse.Parser) webUIFlags {
function registerWebUIFlagsWithAvailability (line 404) | func registerWebUIFlagsWithAvailability(parser *argparse.Parser, enabled...
function registerPacketIntervalFlag (line 417) | func registerPacketIntervalFlag(parser *argparse.Parser) *int {
function buildRawHelp (line 424) | func buildRawHelp() string {
function buildTTLIntervalHelp (line 436) | func buildTTLIntervalHelp() string {
function registerTTLIntervalFlag (line 446) | func registerTTLIntervalFlag(parser *argparse.Parser) *int {
function registerTTLIntervalFlagWithMTRSupport (line 450) | func registerTTLIntervalFlagWithMTRSupport(parser *argparse.Parser, mtrE...
function applyTTLIntervalDefault (line 458) | func applyTTLIntervalDefault(ttlInterval *int, ttlTimeExplicit, effectiv...
function registerDisableMaptraceFlag (line 465) | func registerDisableMaptraceFlag(parser *argparse.Parser) *bool {
function registerGlobalpingFlag (line 472) | func registerGlobalpingFlag(parser *argparse.Parser) *string {
function registerGlobalpingFlagWithAvailability (line 476) | func registerGlobalpingFlagWithAvailability(parser *argparse.Parser, ena...
function registerMTRFlags (line 483) | func registerMTRFlags(parser *argparse.Parser) mtrCLIFlags {
function registerFileFlag (line 506) | func registerFileFlag(parser *argparse.Parser) *string {
function deriveEffectiveMTRModes (line 513) | func deriveEffectiveMTRModes(mtrMode, reportMode, wideMode, rawPrint boo...
function detectExplicitProbeFlags (line 523) | func detectExplicitProbeFlags(parser *argparse.Parser) (queriesExplicit,...
function resolvePacketSizeArg (line 542) | func resolvePacketSizeArg(packetSize int, explicit bool, method trace.Me...
function applyColorMode (line 549) | func applyColorMode(noColor bool) {
function shouldForceNoColorForMTUNonTTY (line 553) | func shouldForceNoColorForMTUNonTTY(mtuMode, jsonPrint, stdoutIsTTY bool...
function printStartupBanner (line 557) | func printStartupBanner(jsonPrint bool, effectiveMTR bool) {
function maybePrintVersion (line 563) | func maybePrintVersion(ver bool) bool {
function maybeRunDeployMode (line 572) | func maybeRunDeployMode(deploy bool, deployListen string) bool {
function handleStartupModes (line 615) | func handleStartupModes(noColor, jsonPrint bool, modes effectiveMTRModes...
function resolveOSType (line 627) | func resolveOSType() int {
function maybePrepareWinDivert (line 638) | func maybePrepareWinDivert(init bool, osType int) bool {
function applyDefaultPort (line 652) | func applyDefaultPort(port *int, udp bool) {
function clampProbeSettings (line 663) | func clampProbeSettings(tcp bool, numMeasurements, maxAttempts *int) {
function resolveTraceMethod (line 677) | func resolveTraceMethod(tcp, udp bool) trace.Method {
function maybeRunFastTraceMode (line 688) | func maybeRunFastTraceMode(from string, fastTraceFlag bool, file string,...
function configureGeoDNS (line 700) | func configureGeoDNS(dot string) {
function normalizeCLITarget (line 706) | func normalizeCLITarget(raw string) string {
function resolveCLITargetOrExit (line 730) | func resolveCLITargetOrExit(raw string, usage string) string {
function applyDN42Mode (line 746) | func applyDN42Mode(enabled bool, dataOrigin *string, disableMaptrace *bo...
function prepareRuntimeEnvironment (line 755) | func prepareRuntimeEnvironment(ctx context.Context, dn42 bool, dataOrigi...
function initLeoWebsocket (line 761) | func initLeoWebsocket(ctx context.Context, dataOrigin, powProvider *stri...
function closeLeoWebsocket (line 783) | func closeLeoWebsocket(leoWs *wshandle.WsConn) {
function maybeHandleGlobalping (line 789) | func maybeHandleGlobalping(from string, opts *trace.GlobalpingOptions, c...
function lookupTargetIP (line 797) | func lookupTargetIP(ctx context.Context, domain string, ipv4Only, ipv6On...
function lookupTargetIPOrExit (line 808) | func lookupTargetIPOrExit(ctx context.Context, domain string, ipv4Only, ...
function resolveSourceDevice (line 819) | func resolveSourceDevice(srcDev string) (*net.Interface, error) {
function resolveSourceDeviceAddr (line 831) | func resolveSourceDeviceAddr(dev *net.Interface, dstIP net.IP) string {
function resolveFallbackSrcAddr (line 860) | func resolveFallbackSrcAddr(dstIP net.IP) string {
function resolveConfiguredSrcAddr (line 878) | func resolveConfiguredSrcAddr(dstIP net.IP, srcAddr, srcDev string) (res...
function applySourceDevice (line 892) | func applySourceDevice(srcDev string, dstIP net.IP, srcAddr *string) {
function printTraceNav (line 910) | func printTraceNav(jsonPrint bool, effectiveMTR bool, ip net.IP, domain,...
function buildTraceConfig (line 916) | func buildTraceConfig(
function maybeRunMTRMode (line 969) | func maybeRunMTRMode(
function resolveOutputPath (line 1008) | func resolveOutputPath(outputPath string, outputDefault bool) (string, e...
function validateJSONRealtimeOutput (line 1022) | func validateJSONRealtimeOutput(jsonPrint bool, outputPath string) error {
function setFastIPOutputSuppression (line 1029) | func setFastIPOutputSuppression(suppress bool) func() {
function configureTracePrinters (line 1037) | func configureTracePrinters(conf *trace.Config, tablePrint, classicPrint...
function applyJSONOutputMode (line 1063) | func applyJSONOutputMode(conf *trace.Config, jsonPrint bool) {
function maybeRunUninterruptedRaw (line 1070) | func maybeRunUninterruptedRaw(rawPrint bool, method trace.Method, conf t...
function runTraceOnce (line 1081) | func runTraceOnce(method trace.Method, conf trace.Config) (*trace.Result...
function finalizeTraceResult (line 1092) | func finalizeTraceResult(ctx context.Context, res *trace.Result, tablePr...
function Execute (line 1127) | func Execute() {
type mtrRunMode (line 1509) | type mtrRunMode
constant mtrRunTUI (line 1512) | mtrRunTUI mtrRunMode = iota
constant mtrRunReport (line 1513) | mtrRunReport
constant mtrRunRaw (line 1514) | mtrRunRaw
function chooseMTRRunMode (line 1517) | func chooseMTRRunMode(effectiveMTRRaw, effectiveReport bool) mtrRunMode {
function deriveMTRProbeParams (line 1531) | func deriveMTRProbeParams(
function deriveMTRRoundParams (line 1555) | func deriveMTRRoundParams(effectiveReport, queriesExplicit bool, numMeas...
function capabilitiesCheck (line 1576) | func capabilitiesCheck() {
function checkRuntimePrivileges (line 1583) | func checkRuntimePrivileges(requireWindowsAdmin bool) bool {
FILE: cmd/cmd_test.go
function TestLookupTargetIPHonorsContextCancellation (line 17) | func TestLookupTargetIPHonorsContextCancellation(t *testing.T) {
function TestRegisterGlobalpingFlagWithAvailability_DisabledStillParses (line 38) | func TestRegisterGlobalpingFlagWithAvailability_DisabledStillParses(t *t...
function TestRegisterWebUIFlagsWithAvailability_DisabledStillParses (line 50) | func TestRegisterWebUIFlagsWithAvailability_DisabledStillParses(t *testi...
function TestRegisterTTLIntervalFlagWithMTRSupport_HelpOmitsTracerouteDefault (line 65) | func TestRegisterTTLIntervalFlagWithMTRSupport_HelpOmitsTracerouteDefaul...
function TestApplyTTLIntervalDefault (line 75) | func TestApplyTTLIntervalDefault(t *testing.T) {
function TestAdvancedHelpTextMentionsTuningGuidance (line 95) | func TestAdvancedHelpTextMentionsTuningGuidance(t *testing.T) {
function TestProbeOptionHelpMentionsRandomPacketSizeAndTOS (line 116) | func TestProbeOptionHelpMentionsRandomPacketSizeAndTOS(t *testing.T) {
function TestDetectExplicitProbeFlags (line 132) | func TestDetectExplicitProbeFlags(t *testing.T) {
function TestNormalizeNegativePacketSizeArgs (line 158) | func TestNormalizeNegativePacketSizeArgs(t *testing.T) {
function TestNegativePacketSizeParsesBeforeTarget (line 173) | func TestNegativePacketSizeParsesBeforeTarget(t *testing.T) {
function TestResolvePacketSizeArg_DefaultsToProtocolMinimum (line 194) | func TestResolvePacketSizeArg_DefaultsToProtocolMinimum(t *testing.T) {
function TestRegisterTracerouteOutputFlagsParsesOutputPath (line 201) | func TestRegisterTracerouteOutputFlagsParsesOutputPath(t *testing.T) {
function TestRegisterTracerouteOutputFlagsParsesOutputDefault (line 220) | func TestRegisterTracerouteOutputFlagsParsesOutputDefault(t *testing.T) {
function TestResolveOutputPath (line 239) | func TestResolveOutputPath(t *testing.T) {
function TestSetFastIPOutputSuppressionRestoresPreviousValue (line 272) | func TestSetFastIPOutputSuppressionRestoresPreviousValue(t *testing.T) {
function TestResolveConfiguredSrcAddrPrefersExplicitSource (line 286) | func TestResolveConfiguredSrcAddrPrefersExplicitSource(t *testing.T) {
function TestValidateJSONRealtimeOutput (line 300) | func TestValidateJSONRealtimeOutput(t *testing.T) {
function TestShouldForceNoColorForMTUNonTTY (line 309) | func TestShouldForceNoColorForMTUNonTTY(t *testing.T) {
FILE: cmd/deploy_disabled.go
function runDeploy (line 7) | func runDeploy(_ string) error {
FILE: cmd/deploy_full.go
function runDeploy (line 9) | func runDeploy(listenAddr string) error {
FILE: cmd/flavor_full.go
constant appBinName (line 6) | appBinName = "nexttrace"
constant enableWebUI (line 7) | enableWebUI = true
constant enableGlobalping (line 8) | enableGlobalping = true
constant enableMTR (line 9) | enableMTR = true
constant enableMTU (line 10) | enableMTU = true
constant defaultMTR (line 11) | defaultMTR = false
FILE: cmd/flavor_ntr.go
constant appBinName (line 6) | appBinName = "ntr"
constant enableWebUI (line 7) | enableWebUI = false
constant enableGlobalping (line 8) | enableGlobalping = false
constant enableMTR (line 9) | enableMTR = true
constant enableMTU (line 10) | enableMTU = false
constant defaultMTR (line 11) | defaultMTR = true
FILE: cmd/flavor_tiny.go
constant appBinName (line 6) | appBinName = "nexttrace-tiny"
constant enableWebUI (line 7) | enableWebUI = false
constant enableGlobalping (line 8) | enableGlobalping = false
constant enableMTR (line 9) | enableMTR = false
constant enableMTU (line 10) | enableMTU = true
constant defaultMTR (line 11) | defaultMTR = false
FILE: cmd/globalping_disabled.go
function handleGlobalpingTrace (line 12) | func handleGlobalpingTrace(_ *trace.GlobalpingOptions, _ *trace.Config) {
FILE: cmd/globalping_full.go
function handleGlobalpingTrace (line 19) | func handleGlobalpingTrace(opts *trace.GlobalpingOptions, config *trace....
function globalpingNoResultMessage (line 81) | func globalpingNoResultMessage(lang string) string {
FILE: cmd/listen_info_test.go
function TestIsDigitsOnly (line 10) | func TestIsDigitsOnly(t *testing.T) {
function TestBuildListenInfoPortOnly (line 16) | func TestBuildListenInfoPortOnly(t *testing.T) {
function TestBuildListenInfoHostPort (line 23) | func TestBuildListenInfoHostPort(t *testing.T) {
function TestBuildListenInfoKeepsInvalidInput (line 29) | func TestBuildListenInfoKeepsInvalidInput(t *testing.T) {
FILE: cmd/mtr_mode.go
constant defaultMTRInternalTTLIntervalMs (line 20) | defaultMTRInternalTTLIntervalMs = 0
function checkMTRConflicts (line 24) | func checkMTRConflicts(flags map[string]bool) (conflict string, ok bool) {
function runMTRTUI (line 51) | func runMTRTUI(method trace.Method, conf trace.Config, hopIntervalMs int...
function runMTRReport (line 117) | func runMTRReport(method trace.Method, conf trace.Config, hopIntervalMs ...
function runMTRRaw (line 175) | func runMTRRaw(method trace.Method, conf trace.Config, hopIntervalMs int...
function normalizeMTRTraceConfig (line 201) | func normalizeMTRTraceConfig(conf trace.Config) trace.Config {
function normalizeMTRReportConfig (line 207) | func normalizeMTRReportConfig(conf trace.Config, wide bool) trace.Config {
function writeMTRRawRuntimeError (line 220) | func writeMTRRawRuntimeError(w io.Writer, err error) {
function resolveSrcIP (line 229) | func resolveSrcIP(conf trace.Config) string {
function buildAPIInfo (line 242) | func buildAPIInfo(dataOrigin string) string {
function buildRawAPIInfoLine (line 257) | func buildRawAPIInfoLine(dataOrigin string) string {
FILE: cmd/mtr_mode_test.go
function TestCheckMTRConflicts_NoConflict (line 17) | func TestCheckMTRConflicts_NoConflict(t *testing.T) {
function TestCheckMTRConflicts_Table (line 30) | func TestCheckMTRConflicts_Table(t *testing.T) {
function TestCheckMTRConflicts_JSON (line 46) | func TestCheckMTRConflicts_JSON(t *testing.T) {
function TestCheckMTRConflicts_OutputDefault (line 62) | func TestCheckMTRConflicts_OutputDefault(t *testing.T) {
function TestCheckMTRConflicts_FastTrace (line 78) | func TestCheckMTRConflicts_FastTrace(t *testing.T) {
function TestCheckMTRConflicts_Deploy (line 94) | func TestCheckMTRConflicts_Deploy(t *testing.T) {
function TestCheckMTRConflicts_From (line 110) | func TestCheckMTRConflicts_From(t *testing.T) {
function TestCheckMTRConflicts_AllConflicts (line 126) | func TestCheckMTRConflicts_AllConflicts(t *testing.T) {
function TestCheckMTRConflicts_RawAllowed (line 140) | func TestCheckMTRConflicts_RawAllowed(t *testing.T) {
function TestChooseMTRRunMode_RawPriority (line 152) | func TestChooseMTRRunMode_RawPriority(t *testing.T) {
function TestDeriveMTRRoundParams_DefaultsAndOverrides (line 164) | func TestDeriveMTRRoundParams_DefaultsAndOverrides(t *testing.T) {
function TestDeriveMTRProbeParams_DefaultsAndOverrides (line 234) | func TestDeriveMTRProbeParams_DefaultsAndOverrides(t *testing.T) {
function TestNormalizeMTRTraceConfig_UsesMTRInternalTTLInterval50 (line 300) | func TestNormalizeMTRTraceConfig_UsesMTRInternalTTLInterval50(t *testing...
function TestDefaultConstants_NormalVsMTR (line 325) | func TestDefaultConstants_NormalVsMTR(t *testing.T) {
function TestNormalizeMTRReportConfig_NonWideDisablesGeoAndKeepsRDNS (line 337) | func TestNormalizeMTRReportConfig_NonWideDisablesGeoAndKeepsRDNS(t *test...
function TestNormalizeMTRReportConfig_NonWideRespectsNoRDNS (line 373) | func TestNormalizeMTRReportConfig_NonWideRespectsNoRDNS(t *testing.T) {
function TestNormalizeMTRReportConfig_WidePreservesGeoSettings (line 397) | func TestNormalizeMTRReportConfig_WidePreservesGeoSettings(t *testing.T) {
function TestBuildRawAPIInfoLine_LeoMoeAPI (line 428) | func TestBuildRawAPIInfoLine_LeoMoeAPI(t *testing.T) {
function TestWriteMTRRawRuntimeError_WritesToProvidedWriter (line 448) | func TestWriteMTRRawRuntimeError_WritesToProvidedWriter(t *testing.T) {
function TestParseMTRKey_Quit (line 461) | func TestParseMTRKey_Quit(t *testing.T) {
function TestParseMTRKey_Pause (line 469) | func TestParseMTRKey_Pause(t *testing.T) {
function TestParseMTRKey_Resume (line 477) | func TestParseMTRKey_Resume(t *testing.T) {
function TestParseMTRKey_Unknown (line 483) | func TestParseMTRKey_Unknown(t *testing.T) {
function TestParseMTRKey_Restart (line 495) | func TestParseMTRKey_Restart(t *testing.T) {
function TestParseMTRKey_DisplayMode (line 503) | func TestParseMTRKey_DisplayMode(t *testing.T) {
function TestParseMTRKey_Unknown_IncludesY (line 511) | func TestParseMTRKey_Unknown_IncludesY(t *testing.T) {
function TestMTRUI_ConsumeRestartRequest (line 520) | func TestMTRUI_ConsumeRestartRequest(t *testing.T) {
function TestMTRUI_DisplayModeCycle (line 550) | func TestMTRUI_DisplayModeCycle(t *testing.T) {
function TestMTRUI_DisplayModeNotResetByRestart (line 587) | func TestMTRUI_DisplayModeNotResetByRestart(t *testing.T) {
function TestMTRUI_InitialDisplayMode_FromFlag (line 610) | func TestMTRUI_InitialDisplayMode_FromFlag(t *testing.T) {
function TestMTRUI_InitialDisplayMode_CycleFromNonZero (line 621) | func TestMTRUI_InitialDisplayMode_CycleFromNonZero(t *testing.T) {
function TestCheckTTY_PipeFd (line 643) | func TestCheckTTY_PipeFd(t *testing.T) {
function TestCheckTTY_StdoutRedirected (line 660) | func TestCheckTTY_StdoutRedirected(t *testing.T) {
function TestCheckTTY_EmptyFds (line 677) | func TestCheckTTY_EmptyFds(t *testing.T) {
function TestParseMTRKey_NameToggle (line 688) | func TestParseMTRKey_NameToggle(t *testing.T) {
function TestMTRUI_NameModeToggle (line 696) | func TestMTRUI_NameModeToggle(t *testing.T) {
function TestMTRUI_NameModeNotResetByRestart (line 719) | func TestMTRUI_NameModeNotResetByRestart(t *testing.T) {
function feedAll (line 745) | func feedAll(p *mtrInputParser, data []byte) []mtrInputAction {
function TestMTRInputParser_IgnoresX10MouseSequence (line 756) | func TestMTRInputParser_IgnoresX10MouseSequence(t *testing.T) {
function TestMTRInputParser_IgnoresSGRMouseSequence (line 774) | func TestMTRInputParser_IgnoresSGRMouseSequence(t *testing.T) {
function TestMTRInputParser_IgnoresFocusSequence (line 790) | func TestMTRInputParser_IgnoresFocusSequence(t *testing.T) {
function TestMTRInputParser_RecognizesNormalKeysAfterEscapeNoise (line 807) | func TestMTRInputParser_RecognizesNormalKeysAfterEscapeNoise(t *testing....
function TestMTRInputParser_SS3Ignored (line 842) | func TestMTRInputParser_SS3Ignored(t *testing.T) {
function TestMTRInputParser_OSCIgnored (line 852) | func TestMTRInputParser_OSCIgnored(t *testing.T) {
function TestMTRInputParser_BracketedPasteCSISwallowed (line 862) | func TestMTRInputParser_BracketedPasteCSISwallowed(t *testing.T) {
FILE: cmd/mtr_ui.go
type mtrUI (line 18) | type mtrUI struct
method IsTTY (line 41) | func (u *mtrUI) IsTTY() bool {
method IsPaused (line 56) | func (u *mtrUI) IsPaused() bool {
method CycleDisplayMode (line 61) | func (u *mtrUI) CycleDisplayMode() {
method CurrentDisplayMode (line 72) | func (u *mtrUI) CurrentDisplayMode() int {
method ToggleNameMode (line 77) | func (u *mtrUI) ToggleNameMode() int32 {
method CurrentNameMode (line 88) | func (u *mtrUI) CurrentNameMode() int {
method ToggleMPLS (line 93) | func (u *mtrUI) ToggleMPLS() {
method IsMPLSDisabled (line 104) | func (u *mtrUI) IsMPLSDisabled() bool {
method Enter (line 132) | func (u *mtrUI) Enter() {
method Leave (line 153) | func (u *mtrUI) Leave() {
method ReadKeysLoop (line 340) | func (u *mtrUI) ReadKeysLoop(ctx context.Context) {
method ConsumeRestartRequest (line 386) | func (u *mtrUI) ConsumeRestartRequest() bool {
function newMTRUI (line 32) | func newMTRUI(cancel context.CancelFunc, initialDisplayMode int) *mtrUI {
function CheckTTY (line 46) | func CheckTTY(fds ...int) bool {
function disableTerminalInputModes (line 115) | func disableTerminalInputModes() {
type mtrInputAction (line 175) | type mtrInputAction
constant mtrActionNone (line 178) | mtrActionNone mtrInputAction = iota
constant mtrActionQuit (line 179) | mtrActionQuit
constant mtrActionPause (line 180) | mtrActionPause
constant mtrActionResume (line 181) | mtrActionResume
constant mtrActionRestart (line 182) | mtrActionRestart
constant mtrActionDisplayMode (line 183) | mtrActionDisplayMode
constant mtrActionNameToggle (line 184) | mtrActionNameToggle
constant mtrActionMPLSToggle (line 185) | mtrActionMPLSToggle
type mtrInputParser (line 190) | type mtrInputParser struct
method Feed (line 212) | func (p *mtrInputParser) Feed(b byte) mtrInputAction {
method feedGround (line 234) | func (p *mtrInputParser) feedGround(b byte) mtrInputAction {
method feedEsc (line 242) | func (p *mtrInputParser) feedEsc(b byte) mtrInputAction {
method feedCSI (line 257) | func (p *mtrInputParser) feedCSI(b byte) mtrInputAction {
method feedSS3 (line 275) | func (p *mtrInputParser) feedSS3() mtrInputAction {
method feedOSC (line 280) | func (p *mtrInputParser) feedOSC(b byte) mtrInputAction {
method feedX10Mouse (line 290) | func (p *mtrInputParser) feedX10Mouse() mtrInputAction {
method feedSGRMouse (line 298) | func (p *mtrInputParser) feedSGRMouse(b byte) mtrInputAction {
type mtrParserState (line 195) | type mtrParserState
constant mtrStateGround (line 198) | mtrStateGround mtrParserState = iota
constant mtrStateEsc (line 199) | mtrStateEsc
constant mtrStateCSI (line 200) | mtrStateCSI
constant mtrStateSS3 (line 201) | mtrStateSS3
constant mtrStateOSC (line 202) | mtrStateOSC
constant mtrStateX10Mouse (line 203) | mtrStateX10Mouse
constant mtrStateSGRMouse (line 204) | mtrStateSGRMouse
constant mtrParserMaxCSI (line 208) | mtrParserMaxCSI = 64
function mapKeyToAction (line 306) | func mapKeyToAction(b byte) mtrInputAction {
function ParseMTRKey (line 392) | func ParseMTRKey(b byte) string {
FILE: cmd/mtu_mode.go
type mtuConflictFlag (line 23) | type mtuConflictFlag struct
function checkMTUConflicts (line 28) | func checkMTUConflicts(flags []mtuConflictFlag) (string, bool) {
function normalizeMTUProtocolFlags (line 37) | func normalizeMTUProtocolFlags(tcp, udp *bool) error {
function buildMTUConflictFlags (line 47) | func buildMTUConflictFlags(
function resolveMTUSourceIP (line 71) | func resolveMTUSourceIP(dstIP net.IP, srcAddr string) (net.IP, error) {
function runStandaloneMTUMode (line 104) | func runStandaloneMTUMode(cfg mtutrace.Config, jsonPrint bool) error {
function printMTUResult (line 141) | func printMTUResult(w io.Writer, result *mtutrace.Result) error {
function printMTUResultWithStyle (line 145) | func printMTUResultWithStyle(w io.Writer, result *mtutrace.Result, style...
function formatMTUHopLine (line 160) | func formatMTUHopLine(hop mtutrace.Hop) string {
function formatMTUHopLineWithStyle (line 164) | func formatMTUHopLineWithStyle(hop mtutrace.Hop, style mtuTextStyle) str...
function formatMTUHopSnapshot (line 190) | func formatMTUHopSnapshot(event mtutrace.StreamEvent) string {
function formatMTUHopSnapshotWithStyle (line 194) | func formatMTUHopSnapshotWithStyle(event mtutrace.StreamEvent, style mtu...
function printMTUHeader (line 201) | func printMTUHeader(w io.Writer, target, resolvedIP string, startMTU, pr...
function printMTUSummary (line 207) | func printMTUSummary(w io.Writer, pathMTU int, style mtuTextStyle) error {
type mtuStreamRenderer (line 212) | type mtuStreamRenderer struct
method Render (line 228) | func (r *mtuStreamRenderer) Render(event mtutrace.StreamEvent) error {
method ensureHeader (line 264) | func (r *mtuStreamRenderer) ensureHeader(event mtutrace.StreamEvent) e...
method renderTTYLine (line 278) | func (r *mtuStreamRenderer) renderTTYLine(line string, final bool) err...
function newMTUStreamRenderer (line 220) | func newMTUStreamRenderer(w io.Writer, isTTY bool) *mtuStreamRenderer {
type mtuTextStyle (line 290) | type mtuTextStyle struct
method apply (line 298) | func (s mtuTextStyle) apply(text string, attrs ...color.Attribute) str...
method header (line 305) | func (s mtuTextStyle) header(text string) string {
method ttl (line 309) | func (s mtuTextStyle) ttl(ttl int) string {
method placeholder (line 313) | func (s mtuTextStyle) placeholder() string {
method timeout (line 317) | func (s mtuTextStyle) timeout() string {
method hopTarget (line 321) | func (s mtuTextStyle) hopTarget(event mtutrace.Event, target string) s...
method pmtu (line 330) | func (s mtuTextStyle) pmtu(pmtu int) string {
method summary (line 334) | func (s mtuTextStyle) summary(pathMTU int) string {
function newMTUTextStyle (line 294) | func newMTUTextStyle(enabled bool) mtuTextStyle {
function buildMTUTraceConfig (line 338) | func buildMTUTraceConfig(
function formatMTUGeo (line 374) | func formatMTUGeo(hop mtutrace.Hop) string {
FILE: cmd/mtu_mode_test.go
function TestNormalizeMTUProtocolFlagsAutoEnablesUDP (line 15) | func TestNormalizeMTUProtocolFlagsAutoEnablesUDP(t *testing.T) {
function TestNormalizeMTUProtocolFlagsRejectsTCP (line 26) | func TestNormalizeMTUProtocolFlagsRejectsTCP(t *testing.T) {
function TestCheckMTUConflicts (line 34) | func TestCheckMTUConflicts(t *testing.T) {
function TestBuildMTUConflictFlagsIncludesOutputDefault (line 47) | func TestBuildMTUConflictFlagsIncludesOutputDefault(t *testing.T) {
function TestPrintMTUResultIncludesPMTUAndSummary (line 58) | func TestPrintMTUResultIncludesPMTUAndSummary(t *testing.T) {
function TestFormatMTUHopSnapshotStartPlaceholder (line 89) | func TestFormatMTUHopSnapshotStartPlaceholder(t *testing.T) {
function TestMTUStreamRendererTTYRewritesCurrentLine (line 99) | func TestMTUStreamRendererTTYRewritesCurrentLine(t *testing.T) {
function TestMTUStreamRendererTTYAppliesColorsWhenEnabled (line 156) | func TestMTUStreamRendererTTYAppliesColorsWhenEnabled(t *testing.T) {
function TestMTUStreamRendererNonTTYPrintsOnlyFinalLines (line 200) | func TestMTUStreamRendererNonTTYPrintsOnlyFinalLines(t *testing.T) {
function TestMTUResultJSONIncludesGeo (line 252) | func TestMTUResultJSONIncludesGeo(t *testing.T) {
FILE: config/viper.go
function InitConfig (line 13) | func InitConfig() {
FILE: dn42/geofeed.go
type GeoFeedRow (line 13) | type GeoFeedRow struct
function GetGeoFeed (line 23) | func GetGeoFeed(ip string) (GeoFeedRow, bool) {
function ReadGeoFeed (line 35) | func ReadGeoFeed() ([]GeoFeedRow, error) {
function FindGeoFeedRow (line 90) | func FindGeoFeedRow(ipStr string, rows []GeoFeedRow) (GeoFeedRow, bool) {
FILE: dn42/geofeed_test.go
function TestFindGeoFeedRowInvalidIP (line 9) | func TestFindGeoFeedRowInvalidIP(t *testing.T) {
FILE: dn42/ptr.go
type PtrRow (line 14) | type PtrRow struct
function matchesPattern (line 21) | func matchesPattern(prefix string, s string) bool {
function FindPtrRecord (line 33) | func FindPtrRecord(ptr string) (PtrRow, error) {
FILE: dn42/ptr_test.go
function TestFindPtrRecordMatchesCity (line 13) | func TestFindPtrRecordMatchesCity(t *testing.T) {
function TestFindPtrRecordMatchesIATACode (line 30) | func TestFindPtrRecordMatchesIATACode(t *testing.T) {
function TestFindPtrRecordNotFound (line 46) | func TestFindPtrRecordNotFound(t *testing.T) {
FILE: fast_trace/basic.go
type AllLocationCollection (line 3) | type AllLocationCollection struct
type BackBoneCollection (line 12) | type BackBoneCollection struct
type ISPCollection (line 24) | type ISPCollection struct
constant CT163 (line 31) | CT163 string = "电信 163 AS4134"
constant CTCN2 (line 32) | CTCN2 string = "电信 CN2 AS4809"
constant CU169 (line 33) | CU169 string = "联通 169 AS4837"
constant CU9929 (line 34) | CU9929 string = "联通 A网(CNC) AS9929"
constant CM (line 35) | CM string = "移动 CMNET AS9808"
constant CMIN2 (line 36) | CMIN2 string = "移动 CMIN2 AS58807"
constant EDU (line 37) | EDU string = "教育网 CERNET AS4538"
constant CST (line 38) | CST string = "科技网 CSTNET AS7497"
FILE: fast_trace/fast_trace ipv6.go
method tracert_v6 (line 21) | func (f *FastTracer) tracert_v6(location string, ispCollection ISPCollec...
method testAll_v6 (line 89) | func (f *FastTracer) testAll_v6() {
method testCT_v6 (line 99) | func (f *FastTracer) testCT_v6() {
method testCU_v6 (line 106) | func (f *FastTracer) testCU_v6() {
method testCM_v6 (line 114) | func (f *FastTracer) testCM_v6() {
method testEDU_v6 (line 121) | func (f *FastTracer) testEDU_v6() {
method testFastBJ_v6 (line 131) | func (f *FastTracer) testFastBJ_v6() {
method testFastSH_v6 (line 139) | func (f *FastTracer) testFastSH_v6() {
method testFastGZ_v6 (line 145) | func (f *FastTracer) testFastGZ_v6() {
function FastTestv6 (line 151) | func FastTestv6(traceMode trace.Method, paramsFastTrace ParamsFastTrace) {
function readFastTestv6Choice (line 169) | func readFastTestv6Choice() string {
function fastTestMethod (line 179) | func fastTestMethod(traceMode trace.Method) trace.Method {
function runFastTestv6Selection (line 188) | func runFastTestv6Selection(ft *FastTracer, choice string) {
FILE: fast_trace/fast_trace.go
type FastTracer (line 25) | type FastTracer struct
method tracert (line 314) | func (f *FastTracer) tracert(location string, ispCollection ISPCollect...
method testAll (line 417) | func (f *FastTracer) testAll() {
method testCT (line 427) | func (f *FastTracer) testCT() {
method testCU (line 437) | func (f *FastTracer) testCU() {
method testCM (line 448) | func (f *FastTracer) testCM() {
method testEDU (line 458) | func (f *FastTracer) testEDU() {
method testFastBJ (line 469) | func (f *FastTracer) testFastBJ() {
method testFastSH (line 477) | func (f *FastTracer) testFastSH() {
method testFastGZ (line 483) | func (f *FastTracer) testFastGZ() {
type ParamsFastTrace (line 30) | type ParamsFastTrace struct
type IpListElement (line 52) | type IpListElement struct
function resolveTraceMethod (line 58) | func resolveTraceMethod(traceMode trace.Method) trace.Method {
function resolveFastTraceSourceAddr (line 69) | func resolveFastTraceSourceAddr(srcDev string, wantV4 bool) string {
function withFastTraceSourceAddr (line 98) | func withFastTraceSourceAddr(params ParamsFastTrace, wantV4 bool) Params...
function promptFastTraceChoice (line 107) | func promptFastTraceChoice(prompt, defaultChoice string) string {
function initFastTraceWS (line 116) | func initFastTraceWS(ctx context.Context) *wshandle.WsConn {
function closeFastTraceWS (line 123) | func closeFastTraceWS(w *wshandle.WsConn) {
function newFastTracer (line 129) | func newFastTracer(traceMode trace.Method, params ParamsFastTrace) FastT...
function runFastTraceByChoice (line 136) | func runFastTraceByChoice(ft FastTracer, choice string) {
function parseIPListLine (line 157) | func parseIPListLine(ctx context.Context, line string) (IpListElement, b...
function loadIPList (line 186) | func loadIPList(ctx context.Context, filePath string) []IpListElement {
function printFileTraceHeader (line 216) | func printFileTraceHeader(ip IpListElement, params ParamsFastTrace, trac...
function buildFileTraceConfig (line 229) | func buildFileTraceConfig(params ParamsFastTrace, tracerouteMethod trace...
function configureFastTraceRealtimePrinter (line 263) | func configureFastTraceRealtimePrinter(conf *trace.Config, outputPath, h...
function runFileTraceTarget (line 285) | func runFileTraceTarget(params ParamsFastTrace, tracerouteMethod trace.M...
function FastTest (line 383) | func FastTest(traceMode trace.Method, paramsFastTrace ParamsFastTrace) {
function testFile (line 407) | func testFile(paramsFastTrace ParamsFastTrace, traceMode trace.Method) {
FILE: fast_trace/fast_trace_test.go
function TestTrace (line 7) | func TestTrace(t *testing.T) {
FILE: internal/hoprender/group.go
type Group (line 9) | type Group struct
function GroupHopAttempts (line 15) | func GroupHopAttempts(hops []trace.Hop) []Group {
FILE: ipgeo/chunzhen.go
function Chunzhen (line 15) | func Chunzhen(ip string, timeout time.Duration, _ string, _ bool) (*IPGe...
FILE: ipgeo/dn42.go
function LtdCodeToCountryOrAreaName (line 10) | func LtdCodeToCountryOrAreaName(Code string) string {
function DN42 (line 22) | func DN42(ip string, _ time.Duration, _ string, _ bool) (*IPGeoData, err...
FILE: ipgeo/dn42_test.go
function TestDN42GeoFeedAndPtrIntegration (line 14) | func TestDN42GeoFeedAndPtrIntegration(t *testing.T) {
function TestDN42PtrFallback (line 39) | func TestDN42PtrFallback(t *testing.T) {
function TestDN42UnknownDefaults (line 60) | func TestDN42UnknownDefaults(t *testing.T) {
FILE: ipgeo/ipapicom.go
function IPApiCom (line 18) | func IPApiCom(ip string, timeout time.Duration, _ string, _ bool) (*IPGe...
FILE: ipgeo/ipdbone.go
type IPDBOneConfig (line 25) | type IPDBOneConfig struct
function GetDefaultConfig (line 32) | func GetDefaultConfig() *IPDBOneConfig {
type IPDBOneTokenCache (line 41) | type IPDBOneTokenCache struct
method GetToken (line 48) | func (c *IPDBOneTokenCache) GetToken() string {
method SetToken (line 59) | func (c *IPDBOneTokenCache) SetToken(token string, expiresIn time.Dura...
type IPDBOneClient (line 68) | type IPDBOneClient struct
method cloneWithTimeout (line 85) | func (c *IPDBOneClient) cloneWithTimeout(timeout time.Duration) *IPDBO...
method fetchToken (line 98) | func (c *IPDBOneClient) fetchToken() error {
method ensureToken (line 140) | func (c *IPDBOneClient) ensureToken() error {
method LookupIP (line 166) | func (c *IPDBOneClient) LookupIP(ip string, lang string) (*IPGeoData, ...
function NewIPDBOneClient (line 76) | func NewIPDBOneClient() *IPDBOneClient {
function parseIPDBOneResponse (line 211) | func parseIPDBOneResponse(ip string, responseBody []byte) (*IPGeoData, e...
function hasJSONValue (line 221) | func hasJSONValue(result gjson.Result) bool {
function parseIPDBOneGeo (line 225) | func parseIPDBOneGeo(geoData gjson.Result, result *IPGeoData) {
function parseIPDBOneRouting (line 247) | func parseIPDBOneRouting(routingData gjson.Result, result *IPGeoData) {
function IPDBOne (line 271) | func IPDBOne(ip string, timeout time.Duration, lang string, _ bool) (*IP...
FILE: ipgeo/ipfilter.go
type cidrFilterRule (line 7) | type cidrFilterRule struct
function cidrRangeContains (line 53) | func cidrRangeContains(cidrRange string, checkIP string) bool {
function matchCIDRFilterRule (line 62) | func matchCIDRFilterRule(ip string, rules []cidrFilterRule) (string, boo...
function classifyPrivateIP (line 71) | func classifyPrivateIP(parsedIP net.IP, rawIP string) (string, bool) {
function isInvalidScopedIPv6 (line 81) | func isInvalidScopedIPv6(parsedIP net.IP, rawIP string) bool {
function Filter (line 86) | func Filter(ip string) (*IPGeoData, bool) {
FILE: ipgeo/ipfilter_test.go
function TestCidrRangeContains_Match (line 12) | func TestCidrRangeContains_Match(t *testing.T) {
function TestCidrRangeContains_NoMatch (line 16) | func TestCidrRangeContains_NoMatch(t *testing.T) {
function TestCidrRangeContains_InvalidCIDR (line 20) | func TestCidrRangeContains_InvalidCIDR(t *testing.T) {
function TestCidrRangeContains_InvalidIP (line 24) | func TestCidrRangeContains_InvalidIP(t *testing.T) {
function TestFilter_RFC1918_Private (line 31) | func TestFilter_RFC1918_Private(t *testing.T) {
function TestFilter_Loopback (line 39) | func TestFilter_Loopback(t *testing.T) {
function TestFilter_LinkLocal (line 45) | func TestFilter_LinkLocal(t *testing.T) {
function TestFilter_CGNAT (line 51) | func TestFilter_CGNAT(t *testing.T) {
function TestFilter_Documentation_192_0_2 (line 57) | func TestFilter_Documentation_192_0_2(t *testing.T) {
function TestFilter_Documentation_198_51_100 (line 63) | func TestFilter_Documentation_198_51_100(t *testing.T) {
function TestFilter_Documentation_203_0_113 (line 69) | func TestFilter_Documentation_203_0_113(t *testing.T) {
function TestFilter_Benchmark (line 75) | func TestFilter_Benchmark(t *testing.T) {
function TestFilter_Multicast (line 81) | func TestFilter_Multicast(t *testing.T) {
function TestFilter_DOD (line 87) | func TestFilter_DOD(t *testing.T) {
function TestFilter_PublicIPv4_NotFiltered (line 97) | func TestFilter_PublicIPv4_NotFiltered(t *testing.T) {
function TestFilter_PublicIPv4_1_1_1_1_NotFiltered (line 102) | func TestFilter_PublicIPv4_1_1_1_1_NotFiltered(t *testing.T) {
function TestFilter_IPv6_LinkLocal (line 109) | func TestFilter_IPv6_LinkLocal(t *testing.T) {
function TestFilter_IPv6_ULA (line 115) | func TestFilter_IPv6_ULA(t *testing.T) {
function TestFilter_IPv6_Documentation (line 121) | func TestFilter_IPv6_Documentation(t *testing.T) {
function TestFilter_IPv6_Multicast (line 127) | func TestFilter_IPv6_Multicast(t *testing.T) {
function TestFilter_IPv6_GlobalUnicast_NotFiltered (line 133) | func TestFilter_IPv6_GlobalUnicast_NotFiltered(t *testing.T) {
function TestFilter_IPv6_InvalidScope (line 138) | func TestFilter_IPv6_InvalidScope(t *testing.T) {
FILE: ipgeo/ipgeo.go
type IPGeoData (line 10) | type IPGeoData struct
function GetSource (line 33) | func GetSource(s string) Source {
function GetSourceWithGeoDNS (line 62) | func GetSourceWithGeoDNS(s string, dotServer string) Source {
function disableGeoIP (line 75) | func disableGeoIP(string, time.Duration, string, bool) (*IPGeoData, erro...
FILE: ipgeo/ipgeo_test.go
function TestGetSourceMappings (line 12) | func TestGetSourceMappings(t *testing.T) {
function TestDisableGeoIP (line 43) | func TestDisableGeoIP(t *testing.T) {
FILE: ipgeo/ipinfo.go
function IPInfo (line 14) | func IPInfo(ip string, timeout time.Duration, _ string, _ bool) (*IPGeoD...
FILE: ipgeo/ipinfoLocal.go
constant ipinfoDataBaseFilename (line 19) | ipinfoDataBaseFilename = "ipinfoLocal.mmdb"
function getIPInfoLocalPath (line 30) | func getIPInfoLocalPath() error {
function IPInfoLocal (line 65) | func IPInfoLocal(ip string, _ time.Duration, _ string, _ bool) (*IPGeoDa...
FILE: ipgeo/ipinsight.go
function IPInSight (line 12) | func IPInSight(ip string, timeout time.Duration, _ string, _ bool) (*IPG...
FILE: ipgeo/ipsb.go
function IPSB (line 15) | func IPSB(ip string, timeout time.Duration, _ string, _ bool) (*IPGeoDat...
FILE: ipgeo/leo.go
type IPPool (line 24) | type IPPool struct
function sendIPRequest (line 33) | func sendIPRequest(ip string) {
function receiveParse (line 38) | func receiveParse() {
function LeoIP (line 111) | func LeoIP(ip string, timeout time.Duration, lang string, maptrace bool)...
FILE: ipgeo/tokens.go
type tokenData (line 5) | type tokenData struct
method BaseOrDefault (line 12) | func (t *tokenData) BaseOrDefault(def string) string {
FILE: ipgeo/tokens_test.go
function TestBaseOrDefault_Empty (line 9) | func TestBaseOrDefault_Empty(t *testing.T) {
function TestBaseOrDefault_Custom (line 14) | func TestBaseOrDefault_Custom(t *testing.T) {
FILE: main.go
function main (line 7) | func main() {
FILE: pow/pow.go
constant baseURL (line 15) | baseURL = "/v3/challenge"
function resolveTokenRequestTimeout (line 20) | func resolveTokenRequestTimeout(ctx context.Context, fallback time.Durat...
function GetToken (line 41) | func GetToken(fastIp string, host string, port string) (string, error) {
function GetTokenWithContext (line 45) | func GetTokenWithContext(ctx context.Context, fastIp string, host string...
FILE: pow/pow_test.go
function TestGetToken (line 15) | func TestGetToken(t *testing.T) {
function TestGetTokenWithContextReturnsCanceled (line 33) | func TestGetTokenWithContextReturnsCanceled(t *testing.T) {
function TestGetTokenWithContextClampsRequestTimeoutToContextDeadline (line 64) | func TestGetTokenWithContextClampsRequestTimeoutToContextDeadline(t *tes...
FILE: printer/basic.go
function Version (line 19) | func Version() {
function CopyRight (line 28) | func CopyRight() {
function sponsor (line 47) | func sponsor() {
function PrintTraceRouteNav (line 60) | func PrintTraceRouteNav(ip net.IP, domain string, dataOrigin string, max...
function applyLangSetting (line 78) | func applyLangSetting(h *trace.Hop) {
FILE: printer/classic_printer.go
type HopInfo (line 10) | type HopInfo
constant General (line 13) | General HopInfo = 0
constant IXP (line 14) | IXP HopInfo = 1
constant Peer (line 15) | Peer HopInfo = 2
constant PoP (line 16) | PoP HopInfo = 3
constant Aboard (line 17) | Aboard HopInfo = 4
function findLatestAvailableHop (line 20) | func findLatestAvailableHop(res *trace.Result, ttl int, probesIndex int)...
function unifyName (line 38) | func unifyName(name string) string {
function chinaISPPeer (line 50) | func chinaISPPeer(hostname string) bool {
function chinaMainland (line 60) | func chinaMainland(h trace.Hop) bool {
function makeHopsType (line 68) | func makeHopsType(res *trace.Result, ttl int) map[int]HopInfo {
function ClassicPrinter (line 98) | func ClassicPrinter(res *trace.Result, ttl int) {
FILE: printer/easy.go
function EasyPrinter (line 10) | func EasyPrinter(res *trace.Result, ttl int) {
FILE: printer/mtr_raw.go
function FormatMTRRawLine (line 12) | func FormatMTRRawLine(rec trace.MTRRawRecord) string {
function sanitizeRawField (line 47) | func sanitizeRawField(s string) string {
FILE: printer/mtr_table.go
function MTRTablePrinter (line 24) | func MTRTablePrinter(stats []trace.MTRHopStat, iteration int, mode int, ...
function MTRRenderTable (line 62) | func MTRRenderTable(stats []trace.MTRHopStat, mode int, nameMode int, la...
type MTRRow (line 89) | type MTRRow struct
function formatLoss (line 106) | func formatLoss(pct float64) string {
function formatMs (line 111) | func formatMs(ms float64) string {
function isWaitingHopStat (line 117) | func isWaitingHopStat(s trace.MTRHopStat) bool {
type mtrMetrics (line 122) | type mtrMetrics struct
function formatMTRMetricStrings (line 128) | func formatMTRMetricStrings(s trace.MTRHopStat) mtrMetrics {
constant HostModeBase (line 148) | HostModeBase = 0
constant HostModeASN (line 149) | HostModeASN = 1
constant HostModeCity (line 150) | HostModeCity = 2
constant HostModeOwner (line 151) | HostModeOwner = 3
constant HostModeFull (line 152) | HostModeFull = 4
constant HostNamePTRorIP (line 160) | HostNamePTRorIP = 0
constant HostNameIPOnly (line 161) | HostNameIPOnly = 1
function formatMTRHostBase (line 175) | func formatMTRHostBase(s trace.MTRHopStat, nameMode int, showIPs bool) s...
function geoField (line 211) | func geoField(cn, en, lang string) string {
function formatMTRHostByMode (line 237) | func formatMTRHostByMode(s trace.MTRHopStat, mode int, nameMode int, lan...
function formatMTRHostWithMPLS (line 242) | func formatMTRHostWithMPLS(s trace.MTRHopStat, mode int, nameMode int, l...
function formatMTRHost (line 260) | func formatMTRHost(s trace.MTRHopStat) string {
type mtrHostParts (line 269) | type mtrHostParts struct
function buildMTRHostParts (line 280) | func buildMTRHostParts(s trace.MTRHopStat, mode int, nameMode int, lang ...
function buildTUIHostParts (line 298) | func buildTUIHostParts(s trace.MTRHopStat, mode int, nameMode int, lang ...
function formatTUIHost (line 315) | func formatTUIHost(parts mtrHostParts, asnW int) string {
function formatReportHost (line 334) | func formatReportHost(s trace.MTRHopStat, mode int, nameMode int, lang s...
function formatCompactReportHost (line 348) | func formatCompactReportHost(s trace.MTRHopStat, nameMode int, showIPs b...
function formatMTRGeoData (line 356) | func formatMTRGeoData(data *ipgeo.IPGeoData) string {
type MTRReportOptions (line 405) | type MTRReportOptions struct
function MTRReportPrint (line 428) | func MTRReportPrint(stats []trace.MTRHopStat, opts MTRReportOptions) {
function joinMTRHostParts (line 437) | func joinMTRHostParts(parts mtrHostParts, extrasSep string) string {
function mtrASNLabel (line 452) | func mtrASNLabel(data *ipgeo.IPGeoData) string {
function mtrGeoExtras (line 459) | func mtrGeoExtras(data *ipgeo.IPGeoData, mode int, lang string) []string {
function singleMTRGeoExtra (line 472) | func singleMTRGeoExtra(value string) []string {
function mtrBestLocation (line 479) | func mtrBestLocation(data *ipgeo.IPGeoData, lang string) string {
function mtrGeoOwner (line 489) | func mtrGeoOwner(data *ipgeo.IPGeoData) string {
function buildMTRFullGeoExtras (line 499) | func buildMTRFullGeoExtras(data *ipgeo.IPGeoData, lang string) []string {
function normalizeMTRReportLang (line 519) | func normalizeMTRReportLang(lang string) string {
function prepareMTRReportHosts (line 526) | func prepareMTRReportHosts(stats []trace.MTRHopStat, opts MTRReportOptio...
function buildMTRReportHost (line 539) | func buildMTRReportHost(s trace.MTRHopStat, opts MTRReportOptions, lang ...
function computeWideMTRReportHostWidth (line 546) | func computeWideMTRReportHostWidth(hosts []string, srcHost string) int {
function narrowMTRReportHostWidth (line 556) | func narrowMTRReportHostWidth() int {
function truncateMTRReportHosts (line 571) | func truncateMTRReportHosts(hosts []string, hostColW int) {
function printMTRReportHeader (line 579) | func printMTRReportHeader(opts MTRReportOptions, hostColW int) {
function mtrReportHeaderMetrics (line 587) | func mtrReportHeaderMetrics() string {
function printMTRReportRows (line 592) | func printMTRReportRows(stats []trace.MTRHopStat, hosts []string, hostCo...
function mtrReportPrefix (line 600) | func mtrReportPrefix(ttl int, prevTTL int) string {
function formatMTRReportMetrics (line 607) | func formatMTRReportMetrics(s trace.MTRHopStat) string {
function reportDisplayWidth (line 614) | func reportDisplayWidth(s string) int {
function reportTruncateToWidth (line 619) | func reportTruncateToWidth(s string, maxW int) string {
function reportPadRight (line 627) | func reportPadRight(s string, width int) string {
FILE: printer/mtr_table_test.go
function captureStdout (line 16) | func captureStdout(t *testing.T, fn func()) string {
function TestMTRRenderTable_HeaderOrder (line 41) | func TestMTRRenderTable_HeaderOrder(t *testing.T) {
function TestMTRRenderTable_NumericFormatting (line 80) | func TestMTRRenderTable_NumericFormatting(t *testing.T) {
function TestMTRRenderTable_NilGeo (line 111) | func TestMTRRenderTable_NilGeo(t *testing.T) {
function TestMTRRenderTable_EmptyHostname (line 125) | func TestMTRRenderTable_EmptyHostname(t *testing.T) {
function TestMTRRenderTable_HostnameAndIP (line 143) | func TestMTRRenderTable_HostnameAndIP(t *testing.T) {
function TestMTRRenderTable_MultiPath (line 158) | func TestMTRRenderTable_MultiPath(t *testing.T) {
function TestMTRRenderTable_UnknownHost (line 183) | func TestMTRRenderTable_UnknownHost(t *testing.T) {
function TestFormatLoss (line 194) | func TestFormatLoss(t *testing.T) {
function TestFormatMs (line 212) | func TestFormatMs(t *testing.T) {
function TestMTRTUIRenderString_Header (line 234) | func TestMTRTUIRenderString_Header(t *testing.T) {
function TestMTRTUIRenderString_UsesCRLFOnly (line 274) | func TestMTRTUIRenderString_UsesCRLFOnly(t *testing.T) {
function TestMTRTablePrinter_NoRoundText (line 305) | func TestMTRTablePrinter_NoRoundText(t *testing.T) {
function TestMTRTUIRenderString_FramePrefix (line 325) | func TestMTRTUIRenderString_FramePrefix(t *testing.T) {
function TestMTRTUIRenderString_PausedStatus (line 349) | func TestMTRTUIRenderString_PausedStatus(t *testing.T) {
function TestMTRTUIRenderString_HopRows (line 363) | func TestMTRTUIRenderString_HopRows(t *testing.T) {
function TestMTRTUIRenderString_MultiPath (line 390) | func TestMTRTUIRenderString_MultiPath(t *testing.T) {
function TestFormatTUIHopPrefix (line 409) | func TestFormatTUIHopPrefix(t *testing.T) {
function TestTruncateStr (line 430) | func TestTruncateStr(t *testing.T) {
function TestTUI_RightAlignedMetricsBlock (line 454) | func TestTUI_RightAlignedMetricsBlock(t *testing.T) {
function TestTUI_HostExpandsOnWideTerminal (line 503) | func TestTUI_HostExpandsOnWideTerminal(t *testing.T) {
function TestTUI_ComputeLayout_NonZeroSntHint (line 515) | func TestTUI_ComputeLayout_NonZeroSntHint(t *testing.T) {
function TestTUI_HostShrinksWhenWidthReduced (line 536) | func TestTUI_HostShrinksWhenWidthReduced(t *testing.T) {
function TestTUI_DualHeaderPacketsPings (line 548) | func TestTUI_DualHeaderPacketsPings(t *testing.T) {
function TestTUI_VeryNarrowNoPanic (line 611) | func TestTUI_VeryNarrowNoPanic(t *testing.T) {
function TestTUI_DisplayWidthCJK (line 641) | func TestTUI_DisplayWidthCJK(t *testing.T) {
function TestTUI_ComputeLayoutZeroWidth (line 670) | func TestTUI_ComputeLayoutZeroWidth(t *testing.T) {
function TestTUI_TotalWidthInvariant (line 682) | func TestTUI_TotalWidthInvariant(t *testing.T) {
function TestTUI_NarrowRightAnchor (line 697) | func TestTUI_NarrowRightAnchor(t *testing.T) {
function TestMTRTUI_HeaderContainsVersion (line 712) | func TestMTRTUI_HeaderContainsVersion(t *testing.T) {
function TestMTRTUI_HeaderContainsDomainAndIP (line 725) | func TestMTRTUI_HeaderContainsDomainAndIP(t *testing.T) {
function TestMTRTUI_HeaderContainsResetKey (line 745) | func TestMTRTUI_HeaderContainsResetKey(t *testing.T) {
function TestMTRTUI_HeaderIPOnlyWhenNoDomain (line 757) | func TestMTRTUI_HeaderIPOnlyWhenNoDomain(t *testing.T) {
function TestFormatTUIHopPrefix_MinimalStyle (line 779) | func TestFormatTUIHopPrefix_MinimalStyle(t *testing.T) {
function TestFormatMTRHost_IncludesMPLS (line 813) | func TestFormatMTRHost_IncludesMPLS(t *testing.T) {
function TestFormatMTRHost_NoMPLS (line 834) | func TestFormatMTRHost_NoMPLS(t *testing.T) {
function TestMTRTUI_HeaderIPNoDuplicate (line 849) | func TestMTRTUI_HeaderIPNoDuplicate(t *testing.T) {
function TestFormatMTRHostByMode_Base (line 872) | func TestFormatMTRHostByMode_Base(t *testing.T) {
function TestFormatMTRHostByMode_Base_NilGeo (line 898) | func TestFormatMTRHostByMode_Base_NilGeo(t *testing.T) {
function TestBuildTUIHostParts_BaseModeNoASNPlaceholder (line 906) | func TestBuildTUIHostParts_BaseModeNoASNPlaceholder(t *testing.T) {
function TestBuildTUIHostParts_ASNModeHasPlaceholder (line 923) | func TestBuildTUIHostParts_ASNModeHasPlaceholder(t *testing.T) {
function TestFormatMTRHostByMode_ASN (line 936) | func TestFormatMTRHostByMode_ASN(t *testing.T) {
function TestFormatMTRHostByMode_City (line 954) | func TestFormatMTRHostByMode_City(t *testing.T) {
function TestFormatMTRHostByMode_Owner (line 972) | func TestFormatMTRHostByMode_Owner(t *testing.T) {
function TestFormatMTRHostByMode_Full (line 988) | func TestFormatMTRHostByMode_Full(t *testing.T) {
function TestFormatMTRHostByMode_NilGeo (line 1006) | func TestFormatMTRHostByMode_NilGeo(t *testing.T) {
function TestFormatMTRHostByMode_NoASN (line 1016) | func TestFormatMTRHostByMode_NoASN(t *testing.T) {
function TestGeoField_CN (line 1033) | func TestGeoField_CN(t *testing.T) {
function TestGeoField_EN (line 1040) | func TestGeoField_EN(t *testing.T) {
function TestGeoField_Fallback (line 1047) | func TestGeoField_Fallback(t *testing.T) {
function TestFormatMTRHostByMode_LangCN (line 1060) | func TestFormatMTRHostByMode_LangCN(t *testing.T) {
function TestTUI_MPLSMultiLine (line 1091) | func TestTUI_MPLSMultiLine(t *testing.T) {
function TestTUI_MPLSMultiLine_NoMPLS (line 1121) | func TestTUI_MPLSMultiLine_NoMPLS(t *testing.T) {
function TestMTRTUI_HeaderSrcDstFormat (line 1136) | func TestMTRTUI_HeaderSrcDstFormat(t *testing.T) {
function TestMTRTUI_HeaderNoSrcInfo (line 1172) | func TestMTRTUI_HeaderNoSrcInfo(t *testing.T) {
function TestMTRTUI_DisplayModeInKeys (line 1193) | func TestMTRTUI_DisplayModeInKeys(t *testing.T) {
function TestMTRTUI_DisplayModeAffectsHopData (line 1209) | func TestMTRTUI_DisplayModeAffectsHopData(t *testing.T) {
function TestFormatMTRHostByMode_IPOnly_ShowsIP (line 1250) | func TestFormatMTRHostByMode_IPOnly_ShowsIP(t *testing.T) {
function TestFormatMTRHostByMode_PTRorIP_ShowsPTR (line 1269) | func TestFormatMTRHostByMode_PTRorIP_ShowsPTR(t *testing.T) {
function TestFormatMTRHostByMode_IPOnly_NoPTR (line 1287) | func TestFormatMTRHostByMode_IPOnly_NoPTR(t *testing.T) {
function TestMTRRenderTable_IPOnly (line 1301) | func TestMTRRenderTable_IPOnly(t *testing.T) {
function TestFormatMTRHostByMode_ShowIPs_PTRAndIP (line 1318) | func TestFormatMTRHostByMode_ShowIPs_PTRAndIP(t *testing.T) {
function TestFormatMTRHostByMode_ShowIPs_NoPTRFallsBackToIP (line 1332) | func TestFormatMTRHostByMode_ShowIPs_NoPTRFallsBackToIP(t *testing.T) {
function TestFormatMTRHostByMode_ShowIPs_PTREqualsIP_NoDup (line 1345) | func TestFormatMTRHostByMode_ShowIPs_PTREqualsIP_NoDup(t *testing.T) {
function TestFormatMTRHostByMode_IPOnly_IgnoreShowIPs (line 1359) | func TestFormatMTRHostByMode_IPOnly_IgnoreShowIPs(t *testing.T) {
function TestFormatReportHost_ShowIPs_PTRAndIP (line 1374) | func TestFormatReportHost_ShowIPs_PTRAndIP(t *testing.T) {
function TestMTRTUI_HeaderAPIInfo (line 1392) | func TestMTRTUI_HeaderAPIInfo(t *testing.T) {
function TestMTRTUI_HeaderNoAPIInfo (line 1417) | func TestMTRTUI_HeaderNoAPIInfo(t *testing.T) {
function TestMTRTUI_NameModeInKeys (line 1430) | func TestMTRTUI_NameModeInKeys(t *testing.T) {
function TestMTRTUI_NameModeInKeys_ShowIPs (line 1446) | func TestMTRTUI_NameModeInKeys_ShowIPs(t *testing.T) {
function TestMTRTUI_ShowIPsRendersPTRAndIP (line 1463) | func TestMTRTUI_ShowIPsRendersPTRAndIP(t *testing.T) {
function TestMTRTUI_FirstLineCentered (line 1496) | func TestMTRTUI_FirstLineCentered(t *testing.T) {
function TestMTRTUI_FirstLineTruncatedOnNarrow (line 1519) | func TestMTRTUI_FirstLineTruncatedOnNarrow(t *testing.T) {
function TestTUI_WaitingForReplyOn100Loss (line 1561) | func TestTUI_WaitingForReplyOn100Loss(t *testing.T) {
function TestTUI_HostSeparators_ManualSpaceAlignment (line 1588) | func TestTUI_HostSeparators_ManualSpaceAlignment(t *testing.T) {
function TestFormatTUIHost_ManualASNAlignment (line 1640) | func TestFormatTUIHost_ManualASNAlignment(t *testing.T) {
function TestBuildTUIHostParts_MissingASNUsesPlaceholder (line 1663) | func TestBuildTUIHostParts_MissingASNUsesPlaceholder(t *testing.T) {
function TestBuildTUIHostParts_WaitingDoesNotUsePlaceholder (line 1681) | func TestBuildTUIHostParts_WaitingDoesNotUsePlaceholder(t *testing.T) {
function TestTUI_MissingASNRenderedAsPlaceholder (line 1694) | func TestTUI_MissingASNRenderedAsPlaceholder(t *testing.T) {
function TestTUI_ManualASNAlignment_StillRightAnchored (line 1722) | func TestTUI_ManualASNAlignment_StillRightAnchored(t *testing.T) {
function TestReport_WaitingForReplyOn100Loss (line 1784) | func TestReport_WaitingForReplyOn100Loss(t *testing.T) {
function TestReport_FullExtrasUseSpaces_NoComma (line 1810) | func TestReport_FullExtrasUseSpaces_NoComma(t *testing.T) {
function TestFormatCompactReportHost_Waiting (line 1833) | func TestFormatCompactReportHost_Waiting(t *testing.T) {
function TestFormatCompactReportHost_BaseOnly_NoASNNoGeoNoMPLS (line 1842) | func TestFormatCompactReportHost_BaseOnly_NoASNNoGeoNoMPLS(t *testing.T) {
function TestFormatCompactReportHost_ShowIPs (line 1866) | func TestFormatCompactReportHost_ShowIPs(t *testing.T) {
function TestMTRReportPrint_NonWideUsesBaseHostOnly (line 1878) | func TestMTRReportPrint_NonWideUsesBaseHostOnly(t *testing.T) {
function TestMTRReportPrint_WideStillIncludesGeoOrMPLS (line 1914) | func TestMTRReportPrint_WideStillIncludesGeoOrMPLS(t *testing.T) {
function TestTUI_ThreeDigitTTLAlignment (line 1953) | func TestTUI_ThreeDigitTTLAlignment(t *testing.T) {
function TestTUI_PrefixWidthForMaxTTL (line 2011) | func TestTUI_PrefixWidthForMaxTTL(t *testing.T) {
function TestTUI_TotalWidthInvariant_ThreeDigitTTL (line 2033) | func TestTUI_TotalWidthInvariant_ThreeDigitTTL(t *testing.T) {
function TestMTRRenderTable_WaitingMetricsBlank (line 2053) | func TestMTRRenderTable_WaitingMetricsBlank(t *testing.T) {
function TestTUI_WaitingMetricsBlank (line 2089) | func TestTUI_WaitingMetricsBlank(t *testing.T) {
function TestFormatMTRRawLine_Success (line 2120) | func TestFormatMTRRawLine_Success(t *testing.T) {
function TestFormatMTRRawLine_TimeoutFixedColumns (line 2142) | func TestFormatMTRRawLine_TimeoutFixedColumns(t *testing.T) {
function TestMTRTUI_PacketsColorByLoss (line 2155) | func TestMTRTUI_PacketsColorByLoss(t *testing.T) {
function TestMTRTUI_ColorDisabled_NoANSI (line 2179) | func TestMTRTUI_ColorDisabled_NoANSI(t *testing.T) {
FILE: printer/mtr_tui.go
type MTRTUIStatus (line 21) | type MTRTUIStatus
constant MTRTUIRunning (line 24) | MTRTUIRunning MTRTUIStatus = iota
constant MTRTUIPaused (line 25) | MTRTUIPaused
type MTRTUIHeader (line 29) | type MTRTUIHeader struct
type mtrTUILayout (line 54) | type mtrTUILayout struct
method metricsWidth (line 69) | func (lo *mtrTUILayout) metricsWidth() int {
method totalWidth (line 74) | func (lo *mtrTUILayout) totalWidth() int {
constant tuiPrefixW (line 80) | tuiPrefixW = 4
constant tuiPrefixGap (line 81) | tuiPrefixGap = 0
constant tuiHostGap (line 82) | tuiHostGap = 2
constant tuiMetricGap (line 83) | tuiMetricGap = 1
constant tuiDefaultTerm (line 84) | tuiDefaultTerm = 120
constant tuiTabStop (line 85) | tuiTabStop = 8
constant tuiLossDefault (line 87) | tuiLossDefault = 5
constant tuiSntDefault (line 88) | tuiSntDefault = 3
constant tuiRTTDefault (line 89) | tuiRTTDefault = 7
constant tuiHostDefault (line 90) | tuiHostDefault = 40
constant tuiHostMin (line 91) | tuiHostMin = 8
constant tuiLossMin (line 92) | tuiLossMin = 5
constant tuiSntMin (line 93) | tuiSntMin = 3
constant tuiRTTMin (line 94) | tuiRTTMin = 5
function tuiPrefixWidthForMaxTTL (line 99) | func tuiPrefixWidthForMaxTTL(maxTTL int) int {
function sntWidthForMax (line 122) | func sntWidthForMax(maxSnt int) int {
function computeLayout (line 130) | func computeLayout(termWidth, prefixW, sntHint int) mtrTUILayout {
function shrinkMetrics (line 190) | func shrinkMetrics(available, sntDefault int) (lossW, sntW, lastW, avgW,...
function displayWidth (line 244) | func displayWidth(s string) int {
function truncateByDisplayWidth (line 250) | func truncateByDisplayWidth(s string, max int) string {
function padRight (line 265) | func padRight(s string, width int) string {
function padLeft (line 274) | func padLeft(s string, width int) string {
function displayWidthWithTabs (line 288) | func displayWidthWithTabs(s string, tabStop int) int {
function truncateWithTabs (line 301) | func truncateWithTabs(s string, maxW int, tabStop int) string {
function fitRight (line 325) | func fitRight(s string, width int) string {
function fitLeft (line 334) | func fitLeft(s string, width int) string {
function tuiLine (line 348) | func tuiLine(b *strings.Builder, format string, a ...any) {
function MTRTUIRender (line 364) | func MTRTUIRender(w io.Writer, header MTRTUIHeader, stats []trace.MTRHop...
function mtrTUIRenderWithWidth (line 369) | func mtrTUIRenderWithWidth(w io.Writer, header MTRTUIHeader, stats []tra...
function buildMTRTUILayout (line 380) | func buildMTRTUILayout(stats []trace.MTRHopStat, termWidth int) mtrTUILa...
function scanMTRTUIStats (line 386) | func scanMTRTUIStats(stats []trace.MTRHopStat) (int, int) {
function writeMTRTUIFramePrefix (line 400) | func writeMTRTUIFramePrefix(b *strings.Builder) {
function renderMTRTUIHeader (line 404) | func renderMTRTUIHeader(b *strings.Builder, header MTRTUIHeader, termWid...
function buildMTRTUITitleLine (line 410) | func buildMTRTUITitleLine(header MTRTUIHeader, termWidth int) string {
function resolveMTRTUITitleParts (line 432) | func resolveMTRTUITitleParts(header MTRTUIHeader) (string, string) {
function buildMTRTUIRouteLine (line 444) | func buildMTRTUIRouteLine(header MTRTUIHeader, termWidth int, now time.T...
function buildMTRTUIRouteText (line 460) | func buildMTRTUIRouteText(header MTRTUIHeader) string {
function resolveMTRTUISourceLabel (line 469) | func resolveMTRTUISourceLabel(header MTRTUIHeader) string {
function resolveMTRTUIDestinationLabel (line 480) | func resolveMTRTUIDestinationLabel(header MTRTUIHeader) string {
function buildMTRTUIControlsLine (line 493) | func buildMTRTUIControlsLine(header MTRTUIHeader, termWidth int) string {
function buildMTRTUIKeyItems (line 505) | func buildMTRTUIKeyItems(header MTRTUIHeader) []string {
function mtrTUIStatusText (line 517) | func mtrTUIStatusText(status MTRTUIStatus) string {
function mtrTUIDisplayModeLabel (line 524) | func mtrTUIDisplayModeLabel(mode int) string {
function mtrTUINameModeLabel (line 532) | func mtrTUINameModeLabel(nameMode int, showIPs bool) string {
function mtrTUIMPLSLabel (line 542) | func mtrTUIMPLSLabel(disabled bool) string {
function renderMTRTUIRows (line 549) | func renderMTRTUIRows(b *strings.Builder, header MTRTUIHeader, stats []t...
function buildTUIHostPartSet (line 561) | func buildTUIHostPartSet(stats []trace.MTRHopStat, header MTRTUIHeader) ...
function renderMTRTUIMPLSRows (line 573) | func renderMTRTUIMPLSRows(b *strings.Builder, lo mtrTUILayout, labels []...
function computeTUIASNWidth (line 585) | func computeTUIASNWidth(stats []trace.MTRHopStat, mode int, nameMode int...
function computeTUIASNWidthFromParts (line 593) | func computeTUIASNWidthFromParts(allParts []mtrHostParts) int {
function renderDualHeader (line 617) | func renderDualHeader(b *strings.Builder, lo mtrTUILayout) {
function centerIn (line 658) | func centerIn(s string, width int) string {
function renderDataRow (line 672) | func renderDataRow(b *strings.Builder, lo mtrTUILayout, hopPrefix, host ...
function MTRTUIRenderString (line 727) | func MTRTUIRenderString(header MTRTUIHeader, stats []trace.MTRHopStat) s...
function mtrTUIRenderStringWithWidth (line 734) | func mtrTUIRenderStringWithWidth(header MTRTUIHeader, stats []trace.MTRH...
function formatTUIHopPrefix (line 744) | func formatTUIHopPrefix(ttl, prevTTL, prefixW int) string {
function truncateStr (line 757) | func truncateStr(s string, maxLen int) string {
function MTRTUIPrinter (line 769) | func MTRTUIPrinter(target, domain, targetIP, version string, startTime t...
FILE: printer/mtr_tui_color.go
function mtrColorLossBucket (line 24) | func mtrColorLossBucket(loss float64, waiting bool) color.Attribute {
function mtrColorPacketsByLoss (line 42) | func mtrColorPacketsByLoss(lossCell, sntCell string, loss float64, waiti...
FILE: printer/printer.go
constant RED_PREFIX (line 25) | RED_PREFIX = "\033[1;31m"
constant GREEN_PREFIX (line 26) | GREEN_PREFIX = "\033[1;32m"
constant YELLOW_PREFIX (line 27) | YELLOW_PREFIX = "\033[1;33m"
constant BLUE_PREFIX (line 28) | BLUE_PREFIX = "\033[1;34m"
constant CYAN_PREFIX (line 29) | CYAN_PREFIX = "\033[1;36m"
constant RESET_PREFIX (line 30) | RESET_PREFIX = "\033[0m"
function HopPrinter (line 33) | func HopPrinter(h trace.Hop, info HopInfo) {
function FormatIPGeoData (line 71) | func FormatIPGeoData(ip string, data *ipgeo.IPGeoData) string {
FILE: printer/realtime_common.go
function printRealtimeTTL (line 16) | func printRealtimeTTL(ttl int) {
function printRealtimeEmptyHop (line 20) | func printRealtimeEmptyHop() {
function displayRealtimeIP (line 24) | func displayRealtimeIP(ip string) string {
function printRealtimeIPColumn (line 31) | func printRealtimeIPColumn(ip string) bool {
function ensureHopGeo (line 41) | func ensureHopGeo(hop *trace.Hop) {
function formatWhoisPrefix (line 47) | func formatWhoisPrefix(whois string, suppressReserved bool) string {
function highlightRealtimeBackbone (line 62) | func highlightRealtimeBackbone(hop *trace.Hop, whoisPrefix string) bool {
function printASNColumn (line 89) | func printASNColumn(hop *trace.Hop, highlight bool) {
function printWhoisColumn (line 101) | func printWhoisColumn(prefix string, highlight bool) {
function displayRealtimeHostname (line 109) | func displayRealtimeHostname(ip, hostname string) string {
function printLocationLine (line 116) | func printLocationLine(hop *trace.Hop, ip string, isIPv6 bool) {
function printTimingSeries (line 133) | func printTimingSeries(values []string) {
function printHopMPLS (line 143) | func printHopMPLS(labels []string) {
function renderRealtimeHopLine (line 149) | func renderRealtimeHopLine(res *trace.Result, ttl int, group hoprender.G...
function prepareRouterGeo (line 171) | func prepareRouterGeo(hop *trace.Hop) {
function renderRouterHopLine (line 179) | func renderRouterHopLine(res *trace.Result, ttl int, group hoprender.Gro...
FILE: printer/realtime_printer.go
function RealtimePrinter (line 8) | func RealtimePrinter(res *trace.Result, ttl int) {
FILE: printer/realtime_printer_router.go
function RealtimePrinterWithRouter (line 12) | func RealtimePrinterWithRouter(res *trace.Result, ttl int) {
function renderRouterSummary (line 30) | func renderRouterSummary(res *trace.Result, ttl int) {
function GetRouter (line 46) | func GetRouter(r *map[string][]string, node string) {
FILE: printer/tableprinter.go
type rowData (line 16) | type rowData struct
function writeTracerouteTable (line 28) | func writeTracerouteTable(w io.Writer, res *trace.Result, clearScreen bo...
function TracerouteTablePrinter (line 58) | func TracerouteTablePrinter(res *trace.Result, clearScreen bool) {
function New (line 62) | func New() table.Table {
function tableDataGenerator (line 72) | func tableDataGenerator(h trace.Hop) *rowData {
FILE: printer/tableprinter_test.go
function testTracerouteTableResult (line 16) | func testTracerouteTableResult() *trace.Result {
function TestWriteTracerouteTableNonTTYOmitsClearScreenANSI (line 36) | func TestWriteTracerouteTableNonTTYOmitsClearScreenANSI(t *testing.T) {
function TestWriteTracerouteTableTTYIncludesClearScreenANSI (line 55) | func TestWriteTracerouteTableTTYIncludesClearScreenANSI(t *testing.T) {
FILE: reporter/reporter.go
type Reporter (line 13) | type Reporter interface
function New (line 17) | func New(rs *trace.Result, ip string) Reporter {
type reporter (line 26) | type reporter struct
method generateRouteReportNode (line 46) | func (r *reporter) generateRouteReportNode(ip string, ipGeoData ipgeo....
method appendRouteReportNode (line 102) | func (r *reporter) appendRouteReportNode(ttl uint16, node routeReportN...
method InitialBaseData (line 108) | func (r *reporter) InitialBaseData() Reporter {
method Print (line 130) | func (r *reporter) Print() {
type routeReportNode (line 35) | type routeReportNode struct
function experimentTag (line 42) | func experimentTag() {
function routeReportNodeIX (line 65) | func routeReportNodeIX(ip string, ipGeoData ipgeo.IPGeoData) bool {
function routeReportContainsIX (line 73) | func routeReportContainsIX(value string) bool {
function routeReportNodeASN (line 78) | func routeReportNodeASN(ip string, ipGeoData ipgeo.IPGeoData) string {
function routeReportNodeGeo (line 85) | func routeReportNodeGeo(ip string, ipGeoData ipgeo.IPGeoData, targetIP s...
function routeReportNodeISP (line 95) | func routeReportNodeISP(ipGeoData ipgeo.IPGeoData) string {
FILE: reporter/reporter_test.go
function captureStdout (line 117) | func captureStdout(t *testing.T, fn func()) string {
function TestPrint (line 137) | func TestPrint(t *testing.T) {
FILE: server/browser_access.go
constant maxTraceRequestBodyBytes (line 14) | maxTraceRequestBodyBytes = 64 << 10
constant maxWSInitMessageBytes (line 15) | maxWSInitMessageBytes = 64 << 10
function browserOriginAllowed (line 18) | func browserOriginAllowed(r *http.Request) bool {
function browserAccessMiddleware (line 36) | func browserAccessMiddleware() gin.HandlerFunc {
FILE: server/browser_access_test.go
function TestTraceUpgraderCheckOrigin_DefaultsToSameOriginOnly (line 13) | func TestTraceUpgraderCheckOrigin_DefaultsToSameOriginOnly(t *testing.T) {
function TestTraceUpgraderCheckOrigin_CanBeRelaxedViaEnv (line 35) | func TestTraceUpgraderCheckOrigin_CanBeRelaxedViaEnv(t *testing.T) {
function TestBrowserAccessMiddleware_DefaultRejectsCrossOriginHTTP (line 46) | func TestBrowserAccessMiddleware_DefaultRejectsCrossOriginHTTP(t *testin...
function TestBrowserAccessMiddleware_CanEnableCORSViaEnv (line 67) | func TestBrowserAccessMiddleware_CanEnableCORSViaEnv(t *testing.T) {
FILE: server/cache_handler.go
function cacheClearHandler (line 11) | func cacheClearHandler(c *gin.Context) {
FILE: server/handlers.go
function optionsHandler (line 38) | func optionsHandler(c *gin.Context) {
FILE: server/mtr.go
type mtrAggregator (line 17) | type mtrAggregator struct
method ensureHopAccum (line 164) | func (agg *mtrAggregator) ensureHopAccum(ttl int, accMap map[string]*h...
method Update (line 233) | func (agg *mtrAggregator) Update(res *trace.Result, queries int) []mtr...
method Snapshot (line 261) | func (agg *mtrAggregator) Snapshot() []mtrHopJSON {
method buildSnapshotLocked (line 267) | func (agg *mtrAggregator) buildSnapshotLocked() []mtrHopJSON {
type hopAccum (line 23) | type hopAccum struct
type groupMetrics (line 40) | type groupMetrics struct
type mtrHopJSON (line 54) | type mtrHopJSON struct
type mtrSnapshot (line 72) | type mtrSnapshot struct
function newMTRAggregator (line 77) | func newMTRAggregator() *mtrAggregator {
function buildAttemptGroups (line 83) | func buildAttemptGroups(attempts []trace.Hop) map[string]*groupMetrics {
function mergeAttemptIntoGroup (line 107) | func mergeAttemptIntoGroup(group *groupMetrics, attempt trace.Hop) {
function addGroupMPLS (line 125) | func addGroupMPLS(group *groupMetrics, labels []string) {
function updateGroupRTT (line 140) | func updateGroupRTT(group *groupMetrics, attempt trace.Hop) {
function attemptErrorKey (line 153) | func attemptErrorKey(attempt trace.Hop) string {
function mergeGroup (line 182) | func mergeGroup(acc *hopAccum, group *groupMetrics) {
function mergeErrorCounts (line 209) | func mergeErrorCounts(acc *hopAccum, errors map[string]int) {
function mergeMPLSSet (line 221) | func mergeMPLSSet(acc *hopAccum, mpls map[string]struct{}) {
function hopKey (line 336) | func hopKey(ip, host string) string {
function copyErrors (line 348) | func copyErrors(src map[string]int) map[string]int {
function sortedSet (line 359) | func sortedSet(set map[string]struct{}) []string {
function failureTypeFromErrors (line 371) | func failureTypeFromErrors(errors map[string]int, received, lossCount in...
FILE: server/server.go
constant defaultListenAddr (line 22) | defaultListenAddr = ":1080"
function init (line 27) | func init() {
function Run (line 41) | func Run(listenAddr string) error {
FILE: server/trace_handler.go
type traceExecution (line 35) | type traceExecution struct
type traceRequest (line 47) | type traceRequest struct
type hopAttempt (line 86) | type hopAttempt struct
type hopResponse (line 96) | type hopResponse struct
type traceResponse (line 101) | type traceResponse struct
type traceProtocolSelection (line 112) | type traceProtocolSelection struct
function normalizeTraceRequest (line 118) | func normalizeTraceRequest(req *traceRequest) (int, error) {
function resolveTraceProtocol (line 145) | func resolveTraceProtocol(req traceRequest) (traceProtocolSelection, int...
function resolveTraceDataProvider (line 179) | func resolveTraceDataProvider(req *traceRequest) (string, bool) {
function resolveTraceIPVersion (line 203) | func resolveTraceIPVersion(req traceRequest) string {
function prepareTrace (line 214) | func prepareTrace(ctx context.Context, req traceRequest) (*traceExecutio...
function traceHandler (line 255) | func traceHandler(c *gin.Context) {
function buildTraceConfig (line 335) | func buildTraceConfig(req traceRequest, method trace.Method, ip net.IP, ...
function withTraceSetupContext (line 426) | func withTraceSetupContext[T any](setup *traceExecution, callback func()...
function withTraceGeoDNSScope (line 453) | func withTraceGeoDNSScope[T any](setup *traceExecution, callback func() ...
function traceMapURLForResult (line 465) | func traceMapURLForResult(setup *traceExecution, res *trace.Result) stri...
function convertHops (line 486) | func convertHops(res *trace.Result, lang string) []hopResponse {
function buildHopResponse (line 502) | func buildHopResponse(attempts []trace.Hop, idx int, lang string) hopRes...
function parseTargetURLHost (line 533) | func parseTargetURLHost(target string) (string, string, error) {
function extractTargetHost (line 552) | func extractTargetHost(target, fallbackSource string) (string, error) {
function stripTargetPort (line 577) | func stripTargetPort(target string) string {
function normalizeTarget (line 596) | func normalizeTarget(input string) (string, error) {
function normalizeDataProvider (line 618) | func normalizeDataProvider(provider string, alias string) string {
function contains (line 654) | func contains(list []string, v string) bool {
function shouldGenerateMap (line 663) | func shouldGenerateMap(provider string) bool {
function validateSourceDevice (line 673) | func validateSourceDevice(device string) error {
function ensureLeoMoeConnection (line 692) | func ensureLeoMoeConnection() {
function localizeGeo (line 709) | func localizeGeo(src *ipgeo.IPGeoData, lang string) *ipgeo.IPGeoData {
FILE: server/trace_handler_test.go
function TestPrepareTrace_DoesNotForceLegacyInterval (line 19) | func TestPrepareTrace_DoesNotForceLegacyInterval(t *testing.T) {
function TestResolveWebMTRHopInterval_DefaultsToOneSecond (line 33) | func TestResolveWebMTRHopInterval_DefaultsToOneSecond(t *testing.T) {
function TestResolveWebMTRHopInterval_PrefersHopIntervalMs (line 40) | func TestResolveWebMTRHopInterval_PrefersHopIntervalMs(t *testing.T) {
function TestBuildTraceConfig_PropagatesSessionScopedFields (line 47) | func TestBuildTraceConfig_PropagatesSessionScopedFields(t *testing.T) {
function TestBuildTraceConfig_PreservesNegativePacketSizeAndTOS (line 75) | func TestBuildTraceConfig_PreservesNegativePacketSizeAndTOS(t *testing.T) {
function TestBuildTraceConfig_DefaultsPacketSizeByProtocolAndFamily (line 93) | func TestBuildTraceConfig_DefaultsPacketSizeByProtocolAndFamily(t *testi...
function TestNormalizeTraceRequest_RejectsInvalidTOS (line 106) | func TestNormalizeTraceRequest_RejectsInvalidTOS(t *testing.T) {
function TestPrepareTrace_RejectsUnknownSourceDevice (line 117) | func TestPrepareTrace_RejectsUnknownSourceDevice(t *testing.T) {
function TestNormalizeTarget (line 131) | func TestNormalizeTarget(t *testing.T) {
function TestTraceHandler_RejectsOversizedJSONBody (line 169) | func TestTraceHandler_RejectsOversizedJSONBody(t *testing.T) {
function TestExecuteMTRRaw_PerHopDoesNotMutateSessionGlobals (line 186) | func TestExecuteMTRRaw_PerHopDoesNotMutateSessionGlobals(t *testing.T) {
function TestTraceMapURLForResult_UsesRequestScopedMapHelper (line 253) | func TestTraceMapURLForResult_UsesRequestScopedMapHelper(t *testing.T) {
function TestPrepareTraceHonorsCanceledContext (line 304) | func TestPrepareTraceHonorsCanceledContext(t *testing.T) {
FILE: server/web/assets/app.js
constant MTR_RENDER_MIN_INTERVAL_MS (line 51) | const MTR_RENDER_MIN_INTERVAL_MS = 100;
function t (line 194) | function t(key) {
function updateStatusDisplay (line 198) | function updateStatusDisplay(state, text) {
function setStatus (line 203) | function setStatus(state, message, translate = true) {
function refreshStatus (line 213) | function refreshStatus() {
function loadOptions (line 221) | async function loadOptions() {
function fillSelect (line 247) | function fillSelect(selectEl, values, defaultValue) {
function readNumericValue (line 260) | function readNumericValue(inputEl) {
function clearResult (line 269) | function clearResult(resetState = false) {
function renderMeta (line 288) | function renderMeta(summary = {}) {
function renderAttemptsGrouped (line 315) | function renderAttemptsGrouped(attempts) {
function renderHops (line 550) | function renderHops(hops) {
function renderHopsFromStore (line 587) | function renderHopsFromStore() {
function escapeHTML (line 592) | function escapeHTML(str) {
function createMetaItem (line 601) | function createMetaItem(label, value, allowHTML = false) {
function buildPayload (line 613) | function buildPayload() {
function closeExistingSocket (line 634) | function closeExistingSocket(hideStop = true) {
function flushMTRRender (line 652) | function flushMTRRender(force = false) {
function scheduleMTRRender (line 680) | function scheduleMTRRender() {
function cancelScheduledMTRRender (line 709) | function cancelScheduledMTRRender() {
function handleSocketMessage (line 721) | function handleSocketMessage(event) {
function runTrace (line 821) | function runTrace(evt) {
function clearCache (line 891) | async function clearCache(silent = false) {
function toggleLanguage (line 912) | function toggleLanguage() {
function applyTranslations (line 918) | function applyTranslations() {
function updateDstPortState (line 961) | function updateDstPortState() {
function updateStartButtonText (line 996) | function updateStartButtonText() {
function updateModeUI (line 1004) | function updateModeUI() {
function stopTrace (line 1043) | function stopTrace() {
function mtrRawKey (line 1056) | function mtrRawKey(rec) {
function onlyTimeoutErrors (line 1061) | function onlyTimeoutErrors(errors) {
function recomputeMTRRawDerived (line 1072) | function recomputeMTRRawDerived(row) {
function ingestMTRRawRecord (line 1085) | function ingestMTRRawRecord(rec) {
function buildMTRStatsFromRawAgg (line 1209) | function buildMTRStatsFromRawAgg() {
function renderMTRStats (line 1222) | function renderMTRStats(stats) {
function getHostDisplayParts (line 1316) | function getHostDisplayParts(stat) {
function formatMPLSText (line 1328) | function formatMPLSText(mpls) {
function formatLatency (line 1336) | function formatLatency(value, received) {
function formatGeoDisplay (line 1343) | function formatGeoDisplay(geo) {
FILE: server/web/assets/mtr_agg.js
function normalizeErrorKey (line 12) | function normalizeErrorKey(key) {
function mergeErrorMaps (line 20) | function mergeErrorMaps(target, source) {
function cloneErrors (line 46) | function cloneErrors(source) {
function pickFailureType (line 61) | function pickFailureType(current, candidate) {
function cloneStat (line 77) | function cloneStat(stat) {
function isKnownStat (line 86) | function isKnownStat(stat) {
function aggregateUnknown (line 92) | function aggregateUnknown(group) {
function mergeUnknownIntoSingleKnown (line 108) | function mergeUnknownIntoSingleKnown(rows) {
function normalizeRenderableMTRStats (line 151) | function normalizeRenderableMTRStats(stats) {
FILE: server/web/assets/mtr_truncation.test.cjs
function createCtx (line 13) | function createCtx(resolvedIP) {
FILE: server/web/assets/trace_form.js
function readNumericValueFromRaw (line 8) | function readNumericValueFromRaw(raw) {
function defaultOptionValue (line 17) | function defaultOptionValue(defaultOptions, key, fallback) {
function buildTracePayload (line 24) | function buildTracePayload(values) {
FILE: server/ws_handler.go
constant wsSendQueueSize (line 30) | wsSendQueueSize = 1024
constant wsWriteTimeout (line 31) | wsWriteTimeout = 5 * time.Second
function sanitizeLogParam (line 42) | func sanitizeLogParam(s string) string {
function newWSSessionContext (line 58) | func newWSSessionContext(parent context.Context) (context.Context, conte...
type wsEnvelope (line 65) | type wsEnvelope struct
type wsConn (line 72) | type wsConn interface
type wsInitConn (line 80) | type wsInitConn interface
type wsTraceSession (line 86) | type wsTraceSession struct
method writeLoop (line 130) | func (s *wsTraceSession) writeLoop() {
method send (line 157) | func (s *wsTraceSession) send(msg wsEnvelope) error {
method closeWithCode (line 172) | func (s *wsTraceSession) closeWithCode(code int, reason string) {
method finish (line 182) | func (s *wsTraceSession) finish() {
function newWSTraceSession (line 99) | func newWSTraceSession(conn wsConn, lang string, queueSize int) *wsTrace...
function readWSInitMessage (line 115) | func readWSInitMessage(conn wsInitConn) ([]byte, error) {
function traceWebsocketHandler (line 197) | func traceWebsocketHandler(c *gin.Context) {
function runSingleTrace (line 279) | func runSingleTrace(ctx context.Context, session *wsTraceSession, setup ...
function runMTRTrace (line 346) | func runMTRTrace(parentCtx context.Context, session *wsTraceSession, set...
function executeMTRRaw (line 376) | func executeMTRRaw(ctx context.Context, session *wsTraceSession, setup *...
function executeTrace (line 423) | func executeTrace(ctx context.Context, session *wsTraceSession, setup *t...
function resolveWebMTRHopInterval (line 449) | func resolveWebMTRHopInterval(req traceRequest) time.Duration {
FILE: server/ws_handler_test.go
type fakeWSConn (line 15) | type fakeWSConn struct
method WriteJSON (line 35) | func (f *fakeWSConn) WriteJSON(v interface{}) error {
method SetWriteDeadline (line 62) | func (f *fakeWSConn) SetWriteDeadline(time.Time) error {
method WriteControl (line 69) | func (f *fakeWSConn) WriteControl(messageType int, data []byte, deadli...
method Close (line 76) | func (f *fakeWSConn) Close() error {
method NextReader (line 88) | func (f *fakeWSConn) NextReader() (messageType int, r io.Reader, err e...
function newFakeWSConn (line 26) | func newFakeWSConn(blockWrites bool) *fakeWSConn {
type fakeWSInitConn (line 92) | type fakeWSInitConn struct
method SetReadDeadline (line 100) | func (f *fakeWSInitConn) SetReadDeadline(t time.Time) error {
method SetReadLimit (line 110) | func (f *fakeWSInitConn) SetReadLimit(limit int64) {
method ReadMessage (line 114) | func (f *fakeWSInitConn) ReadMessage() (messageType int, p []byte, err...
function TestReadWSInitMessage_ClearsDeadlineAfterSuccessfulRead (line 121) | func TestReadWSInitMessage_ClearsDeadlineAfterSuccessfulRead(t *testing....
function TestReadWSInitMessage_ReturnsInitialDeadlineError (line 145) | func TestReadWSInitMessage_ReturnsInitialDeadlineError(t *testing.T) {
function TestReadWSInitMessage_ReturnsClearDeadlineError (line 156) | func TestReadWSInitMessage_ReturnsClearDeadlineError(t *testing.T) {
function TestNewWSSessionContextInheritsParentCancellation (line 167) | func TestNewWSSessionContextInheritsParentCancellation(t *testing.T) {
function TestWSTraceSessionSend_QueueOverflowReturnsErrSlowConsumer (line 184) | func TestWSTraceSessionSend_QueueOverflowReturnsErrSlowConsumer(t *testi...
function TestWSTraceSessionWriter_PreservesEnvelopeOrder (line 207) | func TestWSTraceSessionWriter_PreservesEnvelopeOrder(t *testing.T) {
function TestWSTraceSessionClose_IsIdempotent (line 230) | func TestWSTraceSessionClose_IsIdempotent(t *testing.T) {
function TestSanitizeLogParam (line 252) | func TestSanitizeLogParam(t *testing.T) {
FILE: trace/cache.go
function ClearCaches (line 3) | func ClearCaches() {
FILE: trace/globalping.go
function GlobalpingTraceroute (line 20) | func GlobalpingTraceroute(opts *GlobalpingOptions, config *Config) (*Res...
function newGlobalpingClient (line 38) | func newGlobalpingClient(ctx context.Context) globalping.Client {
function newContextBoundTransport (line 55) | func newContextBoundTransport(ctx context.Context) http.RoundTripper {
type roundTripperFunc (line 68) | type roundTripperFunc
method RoundTrip (line 70) | func (fn roundTripperFunc) RoundTrip(req *http.Request) (*http.Respons...
function buildGlobalpingMeasurement (line 74) | func buildGlobalpingMeasurement(opts *GlobalpingOptions) *globalping.Mea...
function globalpingProtocol (line 92) | func globalpingProtocol(opts *GlobalpingOptions) string {
function assignGlobalpingIPVersion (line 103) | func assignGlobalpingIPVersion(options *globalping.MeasurementOptions, o...
function createGlobalpingMeasurement (line 112) | func createGlobalpingMeasurement(ctx context.Context, client globalping....
function awaitGlobalpingMeasurement (line 120) | func awaitGlobalpingMeasurement(ctx context.Context, client globalping.C...
function decodeGlobalpingMeasurementHops (line 145) | func decodeGlobalpingMeasurementHops(measurement *globalping.Measurement...
function resolveGlobalpingHopLimit (line 159) | func resolveGlobalpingHopLimit(opts *GlobalpingOptions, config *Config, ...
function buildGlobalpingResult (line 170) | func buildGlobalpingResult(gpHops []globalping.MTRHop, limit int, config...
function maxGlobalpingTimings (line 180) | func maxGlobalpingTimings(gpHops []globalping.MTRHop, limit int) int {
function buildGlobalpingTTLHops (line 190) | func buildGlobalpingTTLHops(ttl int, gpHop *globalping.MTRHop, maxTiming...
function globalpingTimingAt (line 198) | func globalpingTimingAt(gpHop *globalping.MTRHop, index int) *globalping...
function mapGlobalpingHop (line 205) | func mapGlobalpingHop(ttl int, gpHop *globalping.MTRHop, timing *globalp...
function hasGlobalpingProbeLocation (line 246) | func hasGlobalpingProbeLocation(probe globalping.ProbeDetails) bool {
function formatGlobalpingCity (line 255) | func formatGlobalpingCity(probe globalping.ProbeDetails) string {
function formatGlobalpingNetwork (line 265) | func formatGlobalpingNetwork(probe globalping.ProbeDetails) string {
function appendGlobalpingPart (line 279) | func appendGlobalpingPart(parts []string, value string) []string {
function GlobalpingFormatLocation (line 286) | func GlobalpingFormatLocation(m *globalping.ProbeMeasurement) string {
FILE: trace/globalping_test.go
type fakeGlobalpingClient (line 14) | type fakeGlobalpingClient struct
method CreateMeasurement (line 19) | func (f fakeGlobalpingClient) CreateMeasurement(measurement *globalpin...
method GetMeasurement (line 23) | func (f fakeGlobalpingClient) GetMeasurement(id string) (*globalping.M...
method AwaitMeasurement (line 27) | func (f fakeGlobalpingClient) AwaitMeasurement(id string) (*globalping...
method GetMeasurementRaw (line 31) | func (f fakeGlobalpingClient) GetMeasurementRaw(id string) ([]byte, er...
method Authorize (line 35) | func (f fakeGlobalpingClient) Authorize(func(error)) (*globalping.Auth...
method TokenIntrospection (line 39) | func (f fakeGlobalpingClient) TokenIntrospection(string) (*globalping....
method Logout (line 43) | func (f fakeGlobalpingClient) Logout() error {
method RevokeToken (line 47) | func (f fakeGlobalpingClient) RevokeToken(string) error {
method Limits (line 51) | func (f fakeGlobalpingClient) Limits() (*globalping.LimitsResponse, er...
function TestAwaitGlobalpingMeasurementReturnsCanceled (line 55) | func TestAwaitGlobalpingMeasurementReturnsCanceled(t *testing.T) {
function TestCreateGlobalpingMeasurementHonorsCanceledContext (line 81) | func TestCreateGlobalpingMeasurementHonorsCanceledContext(t *testing.T) {
FILE: trace/globalping_types.go
type GlobalpingOptions (line 6) | type GlobalpingOptions struct
FILE: trace/icmp_ipv4.go
type ICMPTracer (line 23) | type ICMPTracer struct
method waitAllReady (line 39) | func (t *ICMPTracer) waitAllReady(ctx context.Context) {
method ttlComp (line 55) | func (t *ICMPTracer) ttlComp(ttl int) bool {
method PrintFunc (line 62) | func (t *ICMPTracer) PrintFunc(ctx context.Context, cancel context.Can...
method launchTTL (line 95) | func (t *ICMPTracer) launchTTL(ctx context.Context, s *internal.ICMPSp...
method initEchoID (line 123) | func (t *ICMPTracer) initEchoID() {
method markPending (line 137) | func (t *ICMPTracer) markPending(seq int) {
method clearPending (line 143) | func (t *ICMPTracer) clearPending(seq int) bool {
method storeSent (line 151) | func (t *ICMPTracer) storeSent(seq int, start time.Time) {
method lookupSent (line 157) | func (t *ICMPTracer) lookupSent(seq int) (start time.Time, ok bool) {
method dropSent (line 167) | func (t *ICMPTracer) dropSent(seq int) {
method addHopWithIndex (line 173) | func (t *ICMPTracer) addHopWithIndex(peer net.Addr, ttl, i int, rtt ti...
method matchWorker (line 200) | func (t *ICMPTracer) matchWorker(ctx context.Context) {
method Execute (line 246) | func (t *ICMPTracer) Execute() (res *Result, err error) {
method handleICMPMessage (line 353) | func (t *ICMPTracer) handleICMPMessage(msg internal.ReceivedMessage, f...
method send (line 366) | func (t *ICMPTracer) send(ctx context.Context, s *internal.ICMPSpec, t...
FILE: trace/icmp_ipv6.go
type ICMPTracerv6 (line 23) | type ICMPTracerv6 struct
method waitAllReady (line 39) | func (t *ICMPTracerv6) waitAllReady(ctx context.Context) {
method ttlComp (line 55) | func (t *ICMPTracerv6) ttlComp(ttl int) bool {
method PrintFunc (line 62) | func (t *ICMPTracerv6) PrintFunc(ctx context.Context, cancel context.C...
method launchTTL (line 95) | func (t *ICMPTracerv6) launchTTL(ctx context.Context, s *internal.ICMP...
method initEchoID (line 123) | func (t *ICMPTracerv6) initEchoID() {
method markPending (line 137) | func (t *ICMPTracerv6) markPending(seq int) {
method clearPending (line 143) | func (t *ICMPTracerv6) clearPending(seq int) bool {
method storeSent (line 151) | func (t *ICMPTracerv6) storeSent(seq int, start time.Time) {
method lookupSent (line 157) | func (t *ICMPTracerv6) lookupSent(seq int) (start time.Time, ok bool) {
method dropSent (line 167) | func (t *ICMPTracerv6) dropSent(seq int) {
method addHopWithIndex (line 173) | func (t *ICMPTracerv6) addHopWithIndex(peer net.Addr, ttl, i int, rtt ...
method matchWorker (line 200) | func (t *ICMPTracerv6) matchWorker(ctx context.Context) {
method Execute (line 246) | func (t *ICMPTracerv6) Execute() (res *Result, err error) {
method handleICMPMessage (line 353) | func (t *ICMPTracerv6) handleICMPMessage(msg internal.ReceivedMessage,...
method send (line 366) | func (t *ICMPTracerv6) send(ctx context.Context, s *internal.ICMPSpec,...
FILE: trace/internal/icmp_common.go
type ipLayer (line 17) | type ipLayer interface
function NewICMPSpec (line 22) | func NewICMPSpec(IPVersion, ICMPMode, echoID int, srcIP, dstIP net.IP) *...
method InitICMP (line 26) | func (s *ICMPSpec) InitICMP() {
method listenICMPSock (line 48) | func (s *ICMPSpec) listenICMPSock(ctx context.Context, ready chan struct...
method decodeICMPSocketMessage (line 69) | func (s *ICMPSpec) decodeICMPSocketMessage(msg ReceivedMessage) (time.Ti...
FILE: trace/internal/icmp_darwin.go
type ICMPSpec (line 23) | type ICMPSpec struct
method Close (line 396) | func (s *ICMPSpec) Close() {
method ListenICMP (line 400) | func (s *ICMPSpec) ListenICMP(ctx context.Context, ready chan struct{}...
method SendICMP (line 404) | func (s *ICMPSpec) SendICMP(ctx context.Context, ipHdr gopacket.Networ...
type icmpPacketConn (line 42) | type icmpPacketConn struct
method ReadFrom (line 55) | func (c *icmpPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
method WriteTo (line 95) | func (c *icmpPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
method Close (line 117) | func (c *icmpPacketConn) Close() error { return c.file.Close() }
method LocalAddr (line 119) | func (c *icmpPacketConn) LocalAddr() net.Addr {
method RemoteAddr (line 126) | func (c *icmpPacketConn) RemoteAddr() net.Addr { return ...
method SetDeadline (line 127) | func (c *icmpPacketConn) SetDeadline(t time.Time) error { return ...
method SetReadDeadline (line 128) | func (c *icmpPacketConn) SetReadDeadline(t time.Time) error { return ...
method SetWriteDeadline (line 129) | func (c *icmpPacketConn) SetWriteDeadline(t time.Time) error { return ...
method Read (line 133) | func (c *icmpPacketConn) Read(b []byte) (int, error) {
method Write (line 139) | func (c *icmpPacketConn) Write(b []byte) (int, error) {
method ReadMsgIP (line 146) | func (c *icmpPacketConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int,...
method SyscallConn (line 189) | func (c *icmpPacketConn) SyscallConn() (syscall.RawConn, error) { retu...
function recvmsgRaw (line 182) | func recvmsgRaw(fd int, b, oob []byte) (n, oobn int, err error, sa sysca...
function addrToSockaddr (line 192) | func addrToSockaddr(addr net.Addr, af int) (syscall.Sockaddr, error) {
function stripIPv4Header (line 214) | func stripIPv4Header(n int, b []byte) int {
function zoneToName (line 230) | func zoneToName(idx uint32) string {
type darwinICMPSocketSpec (line 252) | type darwinICMPSocketSpec struct
function darwinICMPSocketSpecForNetwork (line 257) | func darwinICMPSocketSpecForNetwork(network string) (darwinICMPSocketSpe...
function mustOpenDarwinICMPSocket (line 268) | func mustOpenDarwinICMPSocket(spec darwinICMPSocketSpec) int {
function interfaceHasIP (line 279) | func interfaceHasIP(iface net.Interface, target net.IP) bool {
function interfaceIndexByIP (line 293) | func interfaceIndexByIP(ip net.IP) (int, error) {
function setDarwinBoundInterface (line 306) | func setDarwinBoundInterface(fd, proto, ifIndex int) error {
function bindDarwinICMPInterface (line 319) | func bindDarwinICMPInterface(fd, proto int, laddr string) error {
function darwinICMPBindSockaddr (line 330) | func darwinICMPBindSockaddr(af int, laddr string) syscall.Sockaddr {
function bindDarwinICMPSocket (line 346) | func bindDarwinICMPSocket(fd, af int, laddr string) error {
function finalizeDarwinICMPSocket (line 353) | func finalizeDarwinICMPSocket(fd, af int) (net.PacketConn, error) {
function ListenPacket (line 377) | func ListenPacket(network string, laddr string) (net.PacketConn, error) {
FILE: trace/internal/icmp_decode.go
function parseSocketICMPMessage (line 13) | func parseSocketICMPMessage(ipVersion int, raw []byte) (*icmp.Message, b...
function matchSocketICMPEchoReply (line 25) | func matchSocketICMPEchoReply(ipVersion int, rm *icmp.Message, peerIP, d...
function isSocketICMPEchoReply (line 39) | func isSocketICMPEchoReply(ipVersion int, rm *icmp.Message) bool {
function extractSocketICMPPayload (line 50) | func extractSocketICMPPayload(ipVersion int, rm *icmp.Message, dstIP net...
function extractSocketICMPErrorBody (line 58) | func extractSocketICMPErrorBody(ipVersion int, rm *icmp.Message) ([]byte...
function extractSocketICMPv4Body (line 69) | func extractSocketICMPv4Body(rm *icmp.Message) ([]byte, bool) {
function extractSocketICMPv6Body (line 82) | func extractSocketICMPv6Body(rm *icmp.Message) ([]byte, bool) {
function icmpTimeExceededData (line 98) | func icmpTimeExceededData(body *icmp.TimeExceeded, ok bool) ([]byte, boo...
function icmpDstUnreachData (line 105) | func icmpDstUnreachData(body *icmp.DstUnreach, ok bool) ([]byte, bool) {
function icmpPacketTooBigData (line 112) | func icmpPacketTooBigData(body *icmp.PacketTooBig, ok bool) ([]byte, boo...
function matchesEmbeddedDstIP (line 119) | func matchesEmbeddedDstIP(ipVersion int, data []byte, dstIP net.IP) bool {
function extractEmbeddedDstIP (line 127) | func extractEmbeddedDstIP(ipVersion int, data []byte) (net.IP, bool) {
function extractEmbeddedICMPSeq (line 144) | func extractEmbeddedICMPSeq(data []byte, echoID int) (int, bool) {
FILE: trace/internal/icmp_decode_test.go
function mustMarshalICMP (line 13) | func mustMarshalICMP(t *testing.T, message icmp.Message) []byte {
function buildIPv4InnerPacket (line 22) | func buildIPv4InnerPacket(dstIP net.IP, echoID, seq int) []byte {
function buildIPv6InnerPacket (line 31) | func buildIPv6InnerPacket(dstIP net.IP, echoID, seq int) []byte {
function TestMatchSocketICMPEchoReplyIPv4 (line 41) | func TestMatchSocketICMPEchoReplyIPv4(t *testing.T) {
function TestMatchSocketICMPEchoReplyIPv6 (line 59) | func TestMatchSocketICMPEchoReplyIPv6(t *testing.T) {
function TestExtractSocketICMPPayloadIPv4 (line 77) | func TestExtractSocketICMPPayloadIPv4(t *testing.T) {
function TestExtractSocketICMPPayloadIPv6 (line 99) | func TestExtractSocketICMPPayloadIPv6(t *testing.T) {
function TestExtractSocketICMPPayloadRejectsWrongDestination (line 121) | func TestExtractSocketICMPPayloadRejectsWrongDestination(t *testing.T) {
FILE: trace/internal/icmp_unix.go
type ICMPSpec (line 19) | type ICMPSpec struct
method Close (line 35) | func (s *ICMPSpec) Close() {
method ListenICMP (line 39) | func (s *ICMPSpec) ListenICMP(ctx context.Context, ready chan struct{}...
method SendICMP (line 43) | func (s *ICMPSpec) SendICMP(ctx context.Context, ipHdr gopacket.Networ...
function ListenPacket (line 31) | func ListenPacket(network string, laddr string) (net.PacketConn, error) {
FILE: trace/internal/icmp_windows.go
type ICMPSpec (line 22) | type ICMPSpec struct
method Close (line 40) | func (s *ICMPSpec) Close() {
method resolveICMPMode (line 59) | func (s *ICMPSpec) resolveICMPMode() int {
method ListenICMP (line 88) | func (s *ICMPSpec) ListenICMP(ctx context.Context, ready chan struct{}...
method listenICMPWinDivert (line 97) | func (s *ICMPSpec) listenICMPWinDivert(ctx context.Context, ready chan...
method SendICMP (line 135) | func (s *ICMPSpec) SendICMP(ctx context.Context, ipHdr gopacket.Networ...
method sendICMPv6WithWinDivert (line 229) | func (s *ICMPSpec) sendICMPv6WithWinDivert(ip6 *layers.IPv6, icmpHdr, ...
method ensureICMPSendHandle (line 253) | func (s *ICMPSpec) ensureICMPSendHandle(ipv6 bool) error {
function ListenPacket (line 36) | func ListenPacket(network string, laddr string) (net.PacketConn, error) {
function winDivertAvailable (line 48) | func winDivertAvailable() (bool, error) {
function shouldUseICMPv6RawSend (line 225) | func shouldUseICMPv6RawSend(ip6 *layers.IPv6) bool {
FILE: trace/internal/icmp_windows_test.go
function TestShouldUseICMPv6RawSend (line 11) | func TestShouldUseICMPv6RawSend(t *testing.T) {
FILE: trace/internal/packet_listener.go
type ReceivedMessage (line 10) | type ReceivedMessage struct
type PacketListener (line 18) | type PacketListener struct
method Start (line 33) | func (l *PacketListener) Start(ctx context.Context) {
function NewPacketListener (line 27) | func NewPacketListener(conn net.PacketConn) *PacketListener {
FILE: trace/internal/tcp_common.go
function NewTCPSpec (line 13) | func NewTCPSpec(IPVersion, ICMPMode int, srcIP, dstIP net.IP, dstPort in...
method InitICMP (line 17) | func (s *TCPSpec) InitICMP() {
method listenICMPSock (line 33) | func (s *TCPSpec) listenICMPSock(ctx context.Context, ready chan struct{...
method decodeICMPSocketMessage (line 54) | func (s *TCPSpec) decodeICMPSocketMessage(msg ReceivedMessage) (time.Tim...
FILE: trace/internal/tcp_darwin.go
type TCPSpec (line 23) | type TCPSpec struct
method InitTCP (line 38) | func (s *TCPSpec) InitTCP() {
method Close (line 60) | func (s *TCPSpec) Close() {
method ListenICMP (line 65) | func (s *TCPSpec) ListenICMP(ctx context.Context, ready chan struct{},...
method captureDevice (line 69) | func (s *TCPSpec) captureDevice() string {
method tcpCaptureFilter (line 79) | func (s *TCPSpec) tcpCaptureFilter() string {
method ListenTCP (line 106) | func (s *TCPSpec) ListenTCP(ctx context.Context, ready chan struct{}, ...
method SendTCP (line 133) | func (s *TCPSpec) SendTCP(ctx context.Context, ipHdr gopacket.NetworkL...
function mustOpenDarwinTCPSniffHandle (line 86) | func mustOpenDarwinTCPSniffHandle(dev string) *pcap.Handle {
function mustSetDarwinTCPFilter (line 97) | func mustSetDarwinTCPFilter(handle *pcap.Handle, filter string) {
FILE: trace/internal/tcp_probe_decode.go
function tcpIPVersionPrefix (line 10) | func tcpIPVersionPrefix(ipVersion int) string {
function tcpProbeReply (line 17) | func tcpProbeReply(tcp *layers.TCP) (seq int, ack int, ok bool) {
function tcpProbePeerIP (line 30) | func tcpProbePeerIP(ipVersion int, pkt gopacket.Packet) (net.IP, bool) {
function decodeTCPProbePacket (line 46) | func decodeTCPProbePacket(ipVersion, dstPort int, pkt gopacket.Packet) (...
FILE: trace/internal/tcp_probe_decode_test.go
function mustSerializeTCPProbePacket (line 11) | func mustSerializeTCPProbePacket(t *testing.T, ipLayer gopacket.NetworkL...
function TestDecodeTCPProbePacketIPv4RSTAck (line 40) | func TestDecodeTCPProbePacketIPv4RSTAck(t *testing.T) {
function TestDecodeTCPProbePacketIPv6SYNAck (line 71) | func TestDecodeTCPProbePacketIPv6SYNAck(t *testing.T) {
function TestDecodeTCPProbePacketRejectsUnexpectedPort (line 101) | func TestDecodeTCPProbePacketRejectsUnexpectedPort(t *testing.T) {
FILE: trace/internal/tcp_unix.go
type TCPSpec (line 22) | type TCPSpec struct
method InitTCP (line 37) | func (s *TCPSpec) InitTCP() {
method Close (line 59) | func (s *TCPSpec) Close() {
method ListenICMP (line 64) | func (s *TCPSpec) ListenICMP(ctx context.Context, ready chan struct{},...
method ListenTCP (line 68) | func (s *TCPSpec) ListenTCP(ctx context.Context, ready chan struct{}, ...
method SendTCP (line 114) | func (s *TCPSpec) SendTCP(ctx context.Context, ipHdr gopacket.NetworkL...
FILE: trace/internal/tcp_windows.go
type TCPSpec (line 19) | type TCPSpec struct
method sourceDeviceUnsupportedErr (line 32) | func (s *TCPSpec) sourceDeviceUnsupportedErr() error {
method InitTCP (line 39) | func (s *TCPSpec) InitTCP() {
method Close (line 62) | func (s *TCPSpec) Close() {
method resolveICMPMode (line 68) | func (s *TCPSpec) resolveICMPMode() int {
method ListenICMP (line 90) | func (s *TCPSpec) ListenICMP(ctx context.Context, ready chan struct{},...
method listenICMPWinDivert (line 99) | func (s *TCPSpec) listenICMPWinDivert(ctx context.Context, ready chan ...
method ListenTCP (line 135) | func (s *TCPSpec) ListenTCP(ctx context.Context, ready chan struct{}, ...
method SendTCP (line 172) | func (s *TCPSpec) SendTCP(ctx context.Context, ipHdr ipLayer, tcpHdr *...
FILE: trace/internal/udp_common.go
function NewUDPSpec (line 13) | func NewUDPSpec(IPVersion, ICMPMode int, srcIP, dstIP net.IP, dstPort in...
method InitICMP (line 17) | func (s *UDPSpec) InitICMP() {
method listenICMPSock (line 33) | func (s *UDPSpec) listenICMPSock(ctx context.Context, ready chan struct{...
method decodeICMPSocketMessage (line 54) | func (s *UDPSpec) decodeICMPSocketMessage(msg ReceivedMessage) (time.Tim...
FILE: trace/internal/udp_darwin.go
type UDPSpec (line 22) | type UDPSpec struct
method InitUDP (line 36) | func (s *UDPSpec) InitUDP() {
method Close (line 58) | func (s *UDPSpec) Close() {
method ListenOut (line 63) | func (s *UDPSpec) ListenOut(ctx context.Context, ready chan struct{}, ...
method ListenICMP (line 139) | func (s *UDPSpec) ListenICMP(ctx context.Context, ready chan struct{},...
method SendUDP (line 143) | func (s *UDPSpec) SendUDP(ctx context.Context, ipHdr gopacket.NetworkL...
FILE: trace/internal/udp_unix.go
type UDPSpec (line 22) | type UDPSpec struct
method InitUDP (line 37) | func (s *UDPSpec) InitUDP() {
method Close (line 73) | func (s *UDPSpec) Close() {
method ListenOut (line 78) | func (s *UDPSpec) ListenOut(_ context.Context, _ chan struct{}, _ func...
method ListenICMP (line 81) | func (s *UDPSpec) ListenICMP(ctx context.Context, ready chan struct{},...
method sendUDPIPv4 (line 107) | func (s *UDPSpec) sendUDPIPv4(ipHdr *layers.IPv4, udpHdr *layers.UDP, ...
method sendUDPIPv6 (line 145) | func (s *UDPSpec) sendUDPIPv6(ipHdr *layers.IPv6, udpHdr *layers.UDP, ...
method SendUDP (line 174) | func (s *UDPSpec) SendUDP(ctx context.Context, ipHdr ipLayer, udpHdr *...
function serializeUDPPacket (line 85) | func serializeUDPPacket(payload []byte, layersToSerialize ...gopacket.Se...
function parseIPv4Packet (line 98) | func parseIPv4Packet(packet []byte) (*ipv4.Header, []byte, error) {
FILE: trace/internal/udp_windows.go
type UDPSpec (line 19) | type UDPSpec struct
method InitUDP (line 31) | func (s *UDPSpec) InitUDP() {
method Close (line 47) | func (s *UDPSpec) Close() {
method ListenOut (line 52) | func (s *UDPSpec) ListenOut(_ context.Context, _ chan struct{}, _ func...
method resolveICMPMode (line 56) | func (s *UDPSpec) resolveICMPMode() int {
method ListenICMP (line 78) | func (s *UDPSpec) ListenICMP(ctx context.Context, ready chan struct{},...
method listenICMPWinDivert (line 87) | func (s *UDPSpec) listenICMPWinDivert(ctx context.Context, ready chan ...
method SendUDP (line 116) | func (s *UDPSpec) SendUDP(ctx context.Context, ipHdr ipLayer, udpHdr *...
FILE: trace/internal/windivert_sniff_windows.go
type winDivertICMPPacket (line 20) | type winDivertICMPPacket struct
method message (line 178) | func (p *winDivertICMPPacket) message() ReceivedMessage {
method echoReplyFor (line 185) | func (p *winDivertICMPPacket) echoReplyFor(dstIP net.IP, echoID int) (...
method errorPayloadFor (line 192) | func (p *winDivertICMPPacket) errorPayloadFor(dstIP net.IP) ([]byte, b...
function winDivertICMPFilter (line 30) | func winDivertICMPFilter(ipVersion int, srcIP net.IP) string {
function winDivertTCPFilter (line 37) | func winDivertTCPFilter(ipVersion int, dstIP, srcIP net.IP, dstPort int)...
function openWinDivertSniffHandle (line 50) | func openWinDivertSniffHandle(ctx context.Context, filter, action string...
function packetDecoderForIPVersion (line 71) | func packetDecoderForIPVersion(ipVersion int) gopacket.Decoder {
function receiveWinDivertPacket (line 78) | func receiveWinDivertPacket(ctx context.Context, handle wd.Handle, buf [...
function decodeWinDivertICMPPacket (line 101) | func decodeWinDivertICMPPacket(ipVersion int, raw []byte) (*winDivertICM...
function decodeWinDivertTCPPacket (line 109) | func decodeWinDivertTCPPacket(ipVersion int, raw []byte, dstPort int) (s...
function decodeWinDivertICMPv4Packet (line 114) | func decodeWinDivertICMPv4Packet(pkt gopacket.Packet, raw []byte) (*winD...
function decodeWinDivertICMPv6Packet (line 144) | func decodeWinDivertICMPv6Packet(pkt gopacket.Packet, raw []byte) (*winD...
FILE: trace/mtr_loop_runtime.go
type mtrLoopRuntime (line 10) | type mtrLoopRuntime struct
method run (line 53) | func (rt *mtrLoopRuntime) run() error {
method snapshotContextError (line 85) | func (rt *mtrLoopRuntime) snapshotContextError() error {
method emitSnapshot (line 93) | func (rt *mtrLoopRuntime) emitSnapshot() {
method handleReset (line 99) | func (rt *mtrLoopRuntime) handleReset() {
method waitWhilePaused (line 113) | func (rt *mtrLoopRuntime) waitWhilePaused() error {
method runProbeRound (line 129) | func (rt *mtrLoopRuntime) runProbeRound() (*Result, error) {
method runProbeRoundWithPreview (line 137) | func (rt *mtrLoopRuntime) runProbeRoundWithPreview(peeker mtrPeeker) (...
method emitPreview (line 168) | func (rt *mtrLoopRuntime) emitPreview(peeker mtrPeeker) {
method handleProbeError (line 177) | func (rt *mtrLoopRuntime) handleProbeError(err error) (bool, error) {
method waitBackoff (line 199) | func (rt *mtrLoopRuntime) waitBackoff() error {
method recordSuccess (line 211) | func (rt *mtrLoopRuntime) recordSuccess(res *Result) {
method waitInterval (line 226) | func (rt *mtrLoopRuntime) waitInterval() error {
function newMTRLoopRuntime (line 24) | func newMTRLoopRuntime(
FILE: trace/mtr_raw.go
type MTRRawOptions (line 16) | type MTRRawOptions struct
type MTRRawRecord (line 36) | type MTRRawRecord struct
type MTRRawOnRecord (line 55) | type MTRRawOnRecord
function RunMTRRaw (line 63) | func RunMTRRaw(ctx context.Context, method Method, cfg Config, opts MTRR...
function runMTRRawPerHop (line 71) | func runMTRRawPerHop(ctx context.Context, method Method, cfg Config, opt...
function runMTRRawRoundBased (line 130) | func runMTRRawRoundBased(ctx context.Context, method Method, cfg Config,...
function buildMTRRawRecord (line 217) | func buildMTRRawRecord(iteration int, h Hop, cfg Config) MTRRawRecord {
function addrToIPString (line 259) | func addrToIPString(addr net.Addr) string {
function geoTextByLang (line 281) | func geoTextByLang(lang, cn, en string) string {
function buildMTRRawRecordFromProbe (line 297) | func buildMTRRawRecordFromProbe(iteration int, pr mtrProbeResult, cfg Co...
function newMTRRawRecord (line 306) | func newMTRRawRecord(iteration int, pr mtrProbeResult) MTRRawRecord {
function applyMTRRawProbeMetadata (line 324) | func applyMTRRawProbeMetadata(rec *MTRRawRecord, pr mtrProbeResult, cfg ...
function applyMTRRawGeo (line 339) | func applyMTRRawGeo(rec *MTRRawRecord, geo *ipgeo.IPGeoData, lang string) {
function applyMTRRawHostname (line 356) | func applyMTRRawHostname(rec *MTRRawRecord, hostname string) {
FILE: trace/mtr_raw_test.go
function TestRunMTRRaw_EmitsPerAttemptRecords (line 13) | func TestRunMTRRaw_EmitsPerAttemptRecords(t *testing.T) {
function TestRunMTRRaw_RespectsMaxRoundsAndInterval (line 74) | func TestRunMTRRaw_RespectsMaxRoundsAndInterval(t *testing.T) {
function TestRunMTRRaw_ContextCancelStopsLoop (line 101) | func TestRunMTRRaw_ContextCancelStopsLoop(t *testing.T) {
function TestRunMTRRaw_UsesRunRoundOverride (line 133) | func TestRunMTRRaw_UsesRunRoundOverride(t *testing.T) {
function TestRunMTRRaw_RoundBasedNormalizesRuntimeConfig (line 153) | func TestRunMTRRaw_RoundBasedNormalizesRuntimeConfig(t *testing.T) {
FILE: trace/mtr_runner.go
type MTROptions (line 24) | type MTROptions struct
type MTROnSnapshot (line 46) | type MTROnSnapshot
type mtrBackoffCfg (line 49) | type mtrBackoffCfg struct
type mtrProber (line 62) | type mtrProber interface
type mtrResetter (line 68) | type mtrResetter interface
type mtrPeeker (line 74) | type mtrPeeker interface
function RunMTR (line 87) | func RunMTR(ctx context.Context, method Method, baseConfig Config, opts ...
function runMTRPerHop (line 95) | func runMTRPerHop(ctx context.Context, method Method, baseConfig Config,...
function runMTRRoundBased (line 149) | func runMTRRoundBased(ctx context.Context, method Method, baseConfig Con...
function mtrLoop (line 199) | func mtrLoop(
function mtrFillGeoRDNS (line 216) | func mtrFillGeoRDNS(res *Result, config Config) {
type mtrICMPEngine (line 239) | type mtrICMPEngine struct
method start (line 325) | func (e *mtrICMPEngine) start(ctx context.Context) error {
method close (line 350) | func (e *mtrICMPEngine) close() {
method resetFinalTTL (line 358) | func (e *mtrICMPEngine) resetFinalTTL() {
method peekPartialResult (line 364) | func (e *mtrICMPEngine) peekPartialResult() *Result {
method rotateEngine (line 420) | func (e *mtrICMPEngine) rotateEngine(ctx context.Context) error {
method onICMP (line 458) | func (e *mtrICMPEngine) onICMP(msg internal.ReceivedMessage, finish ti...
method shouldDiscardProbeReplyLocked (line 479) | func (e *mtrICMPEngine) shouldDiscardProbeReplyLocked(seq int, start m...
method validProbeRTT (line 491) | func (e *mtrICMPEngine) validProbeRTT(rtt time.Duration) bool {
method discardProbeLocked (line 499) | func (e *mtrICMPEngine) discardProbeLocked(seq int) {
method storeProbeReplyLocked (line 504) | func (e *mtrICMPEngine) storeProbeReplyLocked(seq int, msg internal.Re...
method closeProbeNotifyLocked (line 514) | func (e *mtrICMPEngine) closeProbeNotifyLocked(seq int) {
method detectRoundFinalTTLCandidate (line 521) | func (e *mtrICMPEngine) detectRoundFinalTTLCandidate(peer net.Addr, tt...
method updateRoundFinalTTL (line 542) | func (e *mtrICMPEngine) updateRoundFinalTTL(ttl int32) {
method signalReplyReady (line 552) | func (e *mtrICMPEngine) signalReplyReady() {
method sendProbe (line 560) | func (e *mtrICMPEngine) sendProbe(ctx context.Context, ttl, seq int) (...
method probeRound (line 609) | func (e *mtrICMPEngine) probeRound(ctx context.Context) (*Result, erro...
method prepareProbeRound (line 629) | func (e *mtrICMPEngine) prepareProbeRound(ctx context.Context) mtrProb...
method resetProbeRoundMaps (line 659) | func (e *mtrICMPEngine) resetProbeRoundMaps() {
method drainNotifySignal (line 666) | func (e *mtrICMPEngine) drainNotifySignal() {
method rotateProbeEngineIfNeeded (line 673) | func (e *mtrICMPEngine) rotateProbeEngineIfNeeded(ctx context.Context,...
method effectiveProbeRoundMax (line 680) | func (e *mtrICMPEngine) effectiveProbeRoundMax(maxHops int) int {
method initProbeRoundPreview (line 687) | func (e *mtrICMPEngine) initProbeRoundPreview(beginHop, effectiveMax i...
method probeRoundDelay (line 695) | func (e *mtrICMPEngine) probeRoundDelay() time.Duration {
method sendProbeSweep (line 703) | func (e *mtrICMPEngine) sendProbeSweep(ctx context.Context, round mtrP...
method sendProbeForTTL (line 722) | func (e *mtrICMPEngine) sendProbeForTTL(ctx context.Context, ttl int, ...
method waitProbeInterval (line 757) | func (e *mtrICMPEngine) waitProbeInterval(ctx context.Context, delay t...
method waitForProbeReplies (line 766) | func (e *mtrICMPEngine) waitForProbeReplies(ctx context.Context) {
method probeResponseTimeout (line 779) | func (e *mtrICMPEngine) probeResponseTimeout() time.Duration {
method hasPendingProbeReplies (line 787) | func (e *mtrICMPEngine) hasPendingProbeReplies() bool {
method finalizeProbeRound (line 793) | func (e *mtrICMPEngine) finalizeProbeRound(effectiveMax int) int {
method updateKnownFinalTTLFromRound (line 798) | func (e *mtrICMPEngine) updateKnownFinalTTLFromRound() {
method roundFinalMax (line 807) | func (e *mtrICMPEngine) roundFinalMax(effectiveMax int) int {
method buildProbeRoundResult (line 814) | func (e *mtrICMPEngine) buildProbeRoundResult(beginHop, finalMax int) ...
method probeRoundHop (line 824) | func (e *mtrICMPEngine) probeRoundHop(ttl int) Hop {
method ProbeTTL (line 866) | func (e *mtrICMPEngine) ProbeTTL(ctx context.Context, ttl int) (mtrPro...
method Reset (line 956) | func (e *mtrICMPEngine) Reset() error {
method Close (line 973) | func (e *mtrICMPEngine) Close() error {
type mtrProbeMeta (line 276) | type mtrProbeMeta struct
type mtrProbeReply (line 282) | type mtrProbeReply struct
function newMTRICMPEngine (line 288) | func newMTRICMPEngine(config Config) (*mtrICMPEngine, error) {
function seqWillWrap (line 410) | func seqWillWrap(seqCounter uint32, probeCount int) bool {
function mtrPeerIP (line 529) | func mtrPeerIP(addr net.Addr) net.IP {
type mtrProbeRoundState (line 621) | type mtrProbeRoundState struct
type mtrFallbackProber (line 849) | type mtrFallbackProber struct
method probeRound (line 854) | func (p *mtrFallbackProber) probeRound(ctx context.Context) (*Result, ...
method close (line 858) | func (p *mtrFallbackProber) close() {}
type mtrFallbackTTLProber (line 983) | type mtrFallbackTTLProber struct
method ProbeTTL (line 988) | func (p *mtrFallbackTTLProber) ProbeTTL(ctx context.Context, ttl int) ...
method Reset (line 1020) | func (p *mtrFallbackTTLProber) Reset() error { return nil }
method Close (line 1021) | func (p *mtrFallbackTTLProber) Close() error { return nil }
FILE: trace/mtr_runner_test.go
type mockProber (line 18) | type mockProber struct
method probeRound (line 23) | func (m *mockProber) probeRound(ctx context.Context) (*Result, error) {
method close (line 27) | func (m *mockProber) close() {
function constantResultProber (line 31) | func constantResultProber(res *Result) *mockProber {
function TestMTRLoopMaxRounds (line 50) | func TestMTRLoopMaxRounds(t *testing.T) {
function TestMTRLoopCancel (line 78) | func TestMTRLoopCancel(t *testing.T) {
function TestMTRLoopErrorBackoff (line 108) | func TestMTRLoopErrorBackoff(t *testing.T) {
function TestMTRLoopErrorRecovery (line 147) | func TestMTRLoopErrorRecovery(t *testing.T) {
function TestMTRLoopTimeoutHops (line 180) | func TestMTRLoopTimeoutHops(t *testing.T) {
function TestMTRLoopSnapshotIterations (line 208) | func TestMTRLoopSnapshotIterations(t *testing.T) {
function TestMTRLoopCloseCalledOnError (line 242) | func TestMTRLoopCloseCalledOnError(t *testing.T) {
function TestMTRLoopCloseCalledOnSuccess (line 259) | func TestMTRLoopCloseCalledOnSuccess(t *testing.T) {
function TestMTRLoopNilOnSnapshot (line 275) | func TestMTRLoopNilOnSnapshot(t *testing.T) {
function TestMTRLoopCancelDuringIntervalCallsSnapshot (line 298) | func TestMTRLoopCancelDuringIntervalCallsSnapshot(t *testing.T) {
function TestMTRLoopCancelDuringBackoffCallsSnapshot (line 338) | func TestMTRLoopCancelDuringBackoffCallsSnapshot(t *testing.T) {
function TestMTRLoopPause (line 385) | func TestMTRLoopPause(t *testing.T) {
function newTestICMPEngine (line 433) | func newTestICMPEngine(timeout time.Duration) *mtrICMPEngine {
function TestOnICMP_NormalReply (line 446) | func TestOnICMP_NormalReply(t *testing.T) {
function TestOnICMP_StaleRoundReply (line 466) | func TestOnICMP_StaleRoundReply(t *testing.T) {
function TestOnICMP_SeqWrapStaleReply (line 496) | func TestOnICMP_SeqWrapStaleReply(t *testing.T) {
function TestOnICMP_NegativeRTT (line 526) | func TestOnICMP_NegativeRTT(t *testing.T) {
function TestOnICMP_ExactTimeoutBoundary (line 545) | func TestOnICMP_ExactTimeoutBoundary(t *testing.T) {
function TestOnICMP_UnknownSeq (line 565) | func TestOnICMP_UnknownSeq(t *testing.T) {
function TestSeqWillWrap_NoWrap (line 581) | func TestSeqWillWrap_NoWrap(t *testing.T) {
function TestSeqWillWrap_JustBelowBoundary (line 588) | func TestSeqWillWrap_JustBelowBoundary(t *testing.T) {
function TestSeqWillWrap_OneOver (line 596) | func TestSeqWillWrap_OneOver(t *testing.T) {
function TestSeqWillWrap_AtMax (line 604) | func TestSeqWillWrap_AtMax(t *testing.T) {
function TestSeqWillWrap_HighBitsIgnored (line 611) | func TestSeqWillWrap_HighBitsIgnored(t *testing.T) {
function TestSeqWillWrap_HighBitsWrap (line 619) | func TestSeqWillWrap_HighBitsWrap(t *testing.T) {
function TestSeqWillWrap_ZeroProbes (line 627) | func TestSeqWillWrap_ZeroProbes(t *testing.T) {
function TestSeqWillWrap_NegativeProbes (line 633) | func TestSeqWillWrap_NegativeProbes(t *testing.T) {
function TestProbeRound_BeginHopExceedsMaxHops (line 644) | func TestProbeRound_BeginHopExceedsMaxHops(t *testing.T) {
function TestMTRLoop_RestartStatistics (line 681) | func TestMTRLoop_RestartStatistics(t *testing.T) {
function TestResetClearsKnownFinalTTL (line 748) | func TestResetClearsKnownFinalTTL(t *testing.T) {
function TestOnICMP_DetectsDestination (line 764) | func TestOnICMP_DetectsDestination(t *testing.T) {
function TestOnICMP_NonDestinationDoesNotSetFinal (line 784) | func TestOnICMP_NonDestinationDoesNotSetFinal(t *testing.T) {
function TestPeekPartialResult_EmptyBeforeRound (line 807) | func TestPeekPartialResult_EmptyBeforeRound(t *testing.T) {
function TestPeekPartialResult_PartialReplies (line 815) | func TestPeekPartialResult_PartialReplies(t *testing.T) {
function TestPeekPartialResult_UnsentTTLsAreNil (line 852) | func TestPeekPartialResult_UnsentTTLsAreNil(t *testing.T) {
function TestPeekPartialResult_TrimsByRoundFinalTTL (line 892) | func TestPeekPartialResult_TrimsByRoundFinalTTL(t *testing.T) {
type mockPeekerProber (line 916) | type mockPeekerProber struct
method peekPartialResult (line 921) | func (m *mockPeekerProber) peekPartialResult() *Result {
function TestMTRLoop_StreamingProgress (line 928) | func TestMTRLoop_StreamingProgress(t *testing.T) {
function TestMTRLoop_NonPeekerNoStreaming (line 973) | func TestMTRLoop_NonPeekerNoStreaming(t *testing.T) {
FILE: trace/mtr_scheduler.go
type mtrProbeResult (line 16) | type mtrProbeResult struct
type mtrTTLProber (line 27) | type mtrTTLProber interface
type mtrSchedulerConfig (line 37) | type mtrSchedulerConfig struct
type mtrHopState (line 56) | type mtrHopState struct
type mtrCompletedProbe (line 65) | type mtrCompletedProbe struct
function runMTRScheduler (line 81) | func runMTRScheduler(
function mtrAddrToIP (line 98) | func mtrAddrToIP(addr net.Addr) net.IP {
FILE: trace/mtr_scheduler_runtime.go
type mtrSchedulerRuntime (line 11) | type mtrSchedulerRuntime struct
method run (line 109) | func (rt *mtrSchedulerRuntime) run() error {
method effectiveMax (line 137) | func (rt *mtrSchedulerRuntime) effectiveMax() int {
method computeIteration (line 145) | func (rt *mtrSchedulerRuntime) computeIteration() int {
method maybeSnapshot (line 163) | func (rt *mtrSchedulerRuntime) maybeSnapshot(force bool) {
method launchProbe (line 175) | func (rt *mtrSchedulerRuntime) launchProbe(ttl int) {
method processResult (line 193) | func (rt *mtrSchedulerRuntime) processResult(cp mtrCompletedProbe) {
method processProbeError (line 214) | func (rt *mtrSchedulerRuntime) processProbeError(ttl int, err error) {
method recordSyntheticTimeout (line 231) | func (rt *mtrSchedulerRuntime) recordSyntheticTimeout(ttl int) {
method resultHopCount (line 239) | func (rt *mtrSchedulerRuntime) resultHopCount() int {
method timeoutProbeResult (line 249) | func (rt *mtrSchedulerRuntime) timeoutProbeResult(ttl int) *Result {
method processProbeSuccess (line 258) | func (rt *mtrSchedulerRuntime) processProbeSuccess(ttl int, result mtr...
method detectDestination (line 278) | func (rt *mtrSchedulerRuntime) detectDestination(ttl int, result mtrPr...
method disableHigherTTLs (line 303) | func (rt *mtrSchedulerRuntime) disableHigherTTLs(fromTTL int) {
method probeBudgetReached (line 309) | func (rt *mtrSchedulerRuntime) probeBudgetReached(ttl int) bool {
method markProbeCompleted (line 313) | func (rt *mtrSchedulerRuntime) markProbeCompleted(ttl int) {
method singleProbeResult (line 318) | func (rt *mtrSchedulerRuntime) singleProbeResult(ttl int, result mtrPr...
method scheduleReady (line 341) | func (rt *mtrSchedulerRuntime) scheduleReady() {
method canLaunchProbe (line 358) | func (rt *mtrSchedulerRuntime) canLaunchProbe(ttl int, now time.Time) ...
method isDone (line 372) | func (rt *mtrSchedulerRuntime) isDone() bool {
method handleReset (line 390) | func (rt *mtrSchedulerRuntime) handleReset() {
method handleCancel (line 404) | func (rt *mtrSchedulerRuntime) handleCancel() error {
method drainInFlight (line 410) | func (rt *mtrSchedulerRuntime) drainInFlight() {
function newMTRSchedulerRuntime (line 33) | func newMTRSchedulerRuntime(
FILE: trace/mtr_scheduler_test.go
type mockTTLProber (line 20) | type mockTTLProber struct
method ProbeTTL (line 29) | func (m *mockTTLProber) ProbeTTL(ctx context.Context, ttl int) (mtrPro...
method Reset (line 40) | func (m *mockTTLProber) Reset() error {
method Close (line 45) | func (m *mockTTLProber) Close() error {
method getProbeCount (line 50) | func (m *mockTTLProber) getProbeCount() int {
function TestScheduler_ResultBuildersUseBoundedHopCount (line 58) | func TestScheduler_ResultBuildersUseBoundedHopCount(t *testing.T) {
function TestScheduler_MaxPerHopCompletion (line 87) | func TestScheduler_MaxPerHopCompletion(t *testing.T) {
function TestScheduler_ContextCancel (line 154) | func TestScheduler_ContextCancel(t *testing.T) {
function TestScheduler_DestinationDetection (line 190) | func TestScheduler_DestinationDetection(t *testing.T) {
function TestScheduler_Reset (line 243) | func TestScheduler_Reset(t *testing.T) {
function TestScheduler_Pause (line 308) | func TestScheduler_Pause(t *testing.T) {
function TestScheduler_IterationIsMinSnt (line 355) | func TestScheduler_IterationIsMinSnt(t *testing.T) {
function TestScheduler_OnProbeCallback (line 405) | func TestScheduler_OnProbeCallback(t *testing.T) {
function TestScheduler_BeginHopGreaterThanMaxHops (line 457) | func TestScheduler_BeginHopGreaterThanMaxHops(t *testing.T) {
function TestScheduler_ConcurrencyLimit (line 474) | func TestScheduler_ConcurrencyLimit(t *testing.T) {
function TestMtrAddrToIP (line 519) | func TestMtrAddrToIP(t *testing.T) {
function TestScheduler_ErrorBudgetExhausted (line 540) | func TestScheduler_ErrorBudgetExhausted(t *testing.T) {
function TestScheduler_ErrorBudgetEmitsOnProbe (line 575) | func TestScheduler_ErrorBudgetEmitsOnProbe(t *testing.T) {
function TestScheduler_ErrorResetsOnSuccess (line 626) | func TestScheduler_ErrorResetsOnSuccess(t *testing.T) {
function TestScheduler_FallbackGeoCarriedToAggregator (line 677) | func TestScheduler_FallbackGeoCarriedToAggregator(t *testing.T) {
function TestBuildMTRRawRecordFromProbe_PreResolvedGeo (line 732) | func TestBuildMTRRawRecordFromProbe_PreResolvedGeo(t *testing.T) {
function TestBuildMTRRawRecordFromProbe_NoGeoNoSource_NoHostname (line 770) | func TestBuildMTRRawRecordFromProbe_NoGeoNoSource_NoHostname(t *testing....
function TestScheduler_RawRecordCountMatchesAggSnt_ErrorBudget (line 795) | func TestScheduler_RawRecordCountMatchesAggSnt_ErrorBudget(t *testing.T) {
function TestBuildMTRRawRecordFromProbe_RDNSOnlyPath (line 864) | func TestBuildMTRRawRecordFromProbe_RDNSOnlyPath(t *testing.T) {
function TestScheduler_HigherTTLDestinationRepliesDiscarded (line 902) | func TestScheduler_HigherTTLDestinationRepliesDiscarded(t *testing.T) {
function TestScheduler_DiscardedDestinationRepliesCannotExceedMaxPerHop (line 995) | func TestScheduler_DiscardedDestinationRepliesCannotExceedMaxPerHop(t *t...
function TestScheduler_NonDestinationRepliesOnDisabledHigherTTLDiscarded (line 1058) | func TestScheduler_NonDestinationRepliesOnDisabledHigherTTLDiscarded(t *...
function TestScheduler_FinalTTLLowered_MigratesStatsToNewFinal (line 1129) | func TestScheduler_FinalTTLLowered_MigratesStatsToNewFinal(t *testing.T) {
function TestScheduler_FinalTTLLowered_ChainMigration (line 1227) | func TestScheduler_FinalTTLLowered_ChainMigration(t *testing.T) {
function TestScheduler_LateHigherTTLDestinationReply_Discarded_NoSntBump (line 1300) | func TestScheduler_LateHigherTTLDestinationReply_Discarded_NoSntBump(t *...
function TestScheduler_DiscardedOverFinal_DoesNotEmitOnProbe (line 1384) | func TestScheduler_DiscardedOverFinal_DoesNotEmitOnProbe(t *testing.T) {
function TestScheduler_FinalTTLLowering_Chain_WithMaxPerHop_NoGhostRow_StableStats (line 1459) | func TestScheduler_FinalTTLLowering_Chain_WithMaxPerHop_NoGhostRow_Stabl...
function TestScheduler_FinalHopSntNotInflated_NoLowering (line 1604) | func TestScheduler_FinalHopSntNotInflated_NoLowering(t *testing.T) {
function TestScheduler_FinalHopSntNotInflated_WithLowering (line 1656) | func TestScheduler_FinalHopSntNotInflated_WithLowering(t *testing.T) {
function TestScheduler_MultiInFlightPerHop_HighLossEqualSnt (line 1728) | func TestScheduler_MultiInFlightPerHop_HighLossEqualSnt(t *testing.T) {
function TestScheduler_MultiInFlightPerHop_TimeoutHopsKeepUp (line 1794) | func TestScheduler_MultiInFlightPerHop_TimeoutHopsKeepUp(t *testing.T) {
function TestScheduler_NextAtBasedOnLaunchTime (line 1860) | func TestScheduler_NextAtBasedOnLaunchTime(t *testing.T) {
function TestScheduler_MaxPerHopRespectedWithMultiInFlight (line 1921) | func TestScheduler_MaxPerHopRespectedWithMultiInFlight(t *testing.T) {
function TestScheduler_SingleInFlightPerHopConfig (line 1975) | func TestScheduler_SingleInFlightPerHopConfig(t *testing.T) {
function TestScheduler_DynamicMaxInFlightPerHop (line 2021) | func TestScheduler_DynamicMaxInFlightPerHop(t *testing.T) {
function TestScheduler_DynamicMaxInFlightPerHop_SmallTimeout (line 2083) | func TestScheduler_DynamicMaxInFlightPerHop_SmallTimeout(t *testing.T) {
FILE: trace/mtr_stats.go
type MTRHopStat (line 16) | type MTRHopStat struct
type MTRSnapshot (line 33) | type MTRSnapshot struct
type mtrHopAccum (line 42) | type mtrHopAccum struct
type MTRAggregator (line 60) | type MTRAggregator struct
method Update (line 74) | func (agg *MTRAggregator) Update(res *Result, queries int) []MTRHopStat {
method Reset (line 100) | func (agg *MTRAggregator) Reset() {
method ClearHop (line 110) | func (agg *MTRAggregator) ClearHop(ttl int) {
method MigrateStats (line 120) | func (agg *MTRAggregator) MigrateStats(fromTTL, toTTL, maxPerHop int) {
method Clone (line 149) | func (agg *MTRAggregator) Clone() *MTRAggregator {
method Snapshot (line 177) | func (agg *MTRAggregator) Snapshot() []MTRHopStat {
method snapshotLocked (line 183) | func (agg *MTRAggregator) snapshotLocked() []MTRHopStat {
function NewMTRAggregator (line 67) | func NewMTRAggregator() *MTRAggregator {
constant mtrUnknownKey (line 218) | mtrUnknownKey = "unknown"
function mtrHopKey (line 220) | func mtrHopKey(ip, host string) string {
function mergeUnknownIntoSingleKnown (line 237) | func mergeUnknownIntoSingleKnown(accMap map[string]*mtrHopAccum) {
FILE: trace/mtr_stats_helpers.go
type mtrHopGroup (line 12) | type mtrHopGroup struct
method includeAttempt (line 53) | func (g *mtrHopGroup) includeAttempt(attempt Hop) {
function newMTRHopGroup (line 26) | func newMTRHopGroup(host, ip string) *mtrHopGroup {
function groupMTRHopAttempts (line 34) | func groupMTRHopAttempts(attempts []Hop) map[string]*mtrHopGroup {
method accMapForTTLLocked (line 76) | func (agg *MTRAggregator) accMapForTTLLocked(ttl int) map[string]*mtrHop...
method newHopAccum (line 85) | func (agg *MTRAggregator) newHopAccum(ttl int, key string) *mtrHopAccum {
method mergeGroupedHopLocked (line 97) | func (agg *MTRAggregator) mergeGroupedHopLocked(ttl int, accMap map[stri...
function mergeMTRHopGroupIntoAccum (line 106) | func mergeMTRHopGroupIntoAccum(acc *mtrHopAccum, group *mtrHopGroup) {
function mergeMTRHopAccum (line 132) | func mergeMTRHopAccum(dst, src *mtrHopAccum) {
function mergeMTRLabels (line 158) | func mergeMTRLabels(dst *map[string]struct{}, labels []string) {
function mergeMTRLabelSet (line 173) | func mergeMTRLabelSet(dst, src map[string]struct{}) {
function capMTRHopAccum (line 179) | func capMTRHopAccum(acc *mtrHopAccum, maxPerHop int) {
function buildMTRHopStat (line 211) | func buildMTRHopStat(acc *mtrHopAccum) MTRHopStat {
FILE: trace/mtr_stats_test.go
function mkHop (line 12) | func mkHop(ttl int, ip string, rtt time.Duration) Hop {
function mkTimeoutHop (line 21) | func mkTimeoutHop(ttl int) Hop {
function mkResult (line 30) | func mkResult(hopsByTTL ...[]Hop) *Result {
function roundN (line 38) | func roundN(v float64, n int) float64 {
function TestSinglePath (line 43) | func TestSinglePath(t *testing.T) {
function TestMultiPath (line 112) | func TestMultiPath(t *testing.T) {
function TestErrorMix (line 144) | func TestErrorMix(t *testing.T) {
function TestGeoPropagation (line 176) | func TestGeoPropagation(t *testing.T) {
function TestStDevSingleSample (line 194) | func TestStDevSingleSample(t *testing.T) {
function TestAllTimeout (line 206) | func TestAllTimeout(t *testing.T) {
function TestUpdate_NilResult (line 228) | func TestUpdate_NilResult(t *testing.T) {
function TestHostnamePropagation (line 238) | func TestHostnamePropagation(t *testing.T) {
function TestMTRAggregator_Reset (line 252) | func TestMTRAggregator_Reset(t *testing.T) {
function TestMTRAggregator_CloneIsolation (line 278) | func TestMTRAggregator_CloneIsolation(t *testing.T) {
function TestUnknownMergedAfterLaterReply_SinglePath (line 327) | func TestUnknownMergedAfterLaterReply_SinglePath(t *testing.T) {
function TestUnknownPreserved_Multipath (line 359) | func TestUnknownPreserved_Multipath(t *testing.T) {
function TestMTRAggregator_ClearHop_RemovesData (line 396) | func TestMTRAggregator_ClearHop_RemovesData(t *testing.T) {
function TestMTRAggregator_ClearHop_NoopIfMissing (line 430) | func TestMTRAggregator_ClearHop_NoopIfMissing(t *testing.T) {
function TestMTRAggregator_ClearHop_DoesNotAffectOtherTTLs (line 456) | func TestMTRAggregator_ClearHop_DoesNotAffectOtherTTLs(t *testing.T) {
function TestMTRAggregator_MigrateStats_MovesToNewTTL (line 491) | func TestMTRAggregator_MigrateStats_MovesToNewTTL(t *testing.T) {
function TestMTRAggregator_MigrateStats_MergesIntoExisting (line 532) | func TestMTRAggregator_MigrateStats_MergesIntoExisting(t *testing.T) {
function TestMTRAggregator_MigrateStats_NoopIfFromEmpty (line 568) | func TestMTRAggregator_MigrateStats_NoopIfFromEmpty(t *testing.T) {
function TestMTRAggregator_MigrateStats_CapsAtMaxPerHop (line 588) | func TestMTRAggregator_MigrateStats_CapsAtMaxPerHop(t *testing.T) {
function TestMTRAggregator_MigrateStats_CapsReceived (line 623) | func TestMTRAggregator_MigrateStats_CapsReceived(t *testing.T) {
function TestMTRAggregator_MigrateStats_CapsPreservesAvgStDev (line 666) | func TestMTRAggregator_MigrateStats_CapsPreservesAvgStDev(t *testing.T) {
function TestMTRAggregator_MigrateStats_CapsPreservesNonZeroStDev (line 704) | func TestMTRAggregator_MigrateStats_CapsPreservesNonZeroStDev(t *testing...
FILE: trace/mtu/decode.go
constant probePayloadMinLen (line 13) | probePayloadMinLen = 8
type probeResponse (line 15) | type probeResponse struct
function buildProbePayload (line 22) | func buildProbePayload(size int) []byte {
function parseICMPProbeResult (line 29) | func parseICMPProbeResult(ipVersion int, raw []byte, peerIP, dstIP net.I...
function matchesEmbeddedUDP (line 117) | func matchesEmbeddedUDP(data []byte, ipVersion int, dstIP net.IP, dstPor...
type embeddedUDPPacket (line 127) | type embeddedUDPPacket struct
function parseEmbeddedUDPPacket (line 133) | func parseEmbeddedUDPPacket(data []byte, ipVersion int) (embeddedUDPPack...
function parseEmbeddedIPv6UDP (line 157) | func parseEmbeddedIPv6UDP(data []byte) (embeddedUDPPacket, bool) {
function parseEmbeddedUDPFromOffsets (line 202) | func parseEmbeddedUDPFromOffsets(data []byte, udpOffset int, dstIP net.I...
FILE: trace/mtu/decode_test.go
function TestParseICMPProbeResultIPv4FragNeeded (line 15) | func TestParseICMPProbeResultIPv4FragNeeded(t *testing.T) {
function TestParseICMPProbeResultIPv6PacketTooBig (line 46) | func TestParseICMPProbeResultIPv6PacketTooBig(t *testing.T) {
function TestParseICMPProbeResultIPv4MatchesMinimumQuotedUDPHeader (line 73) | func TestParseICMPProbeResultIPv4MatchesMinimumQuotedUDPHeader(t *testin...
function TestParseEmbeddedUDPPacketIPv6WithExtensionHeaders (line 99) | func TestParseEmbeddedUDPPacketIPv6WithExtensionHeaders(t *testing.T) {
function mustSerializeIPv4UDP (line 123) | func mustSerializeIPv4UDP(t *testing.T, srcIP, dstIP net.IP, srcPort, ds...
function mustSerializeIPv6UDP (line 142) | func mustSerializeIPv6UDP(t *testing.T, srcIP, dstIP net.IP, srcPort, ds...
function mustSerializeLayers (line 161) | func mustSerializeLayers(t *testing.T, layersToSerialize ...gopacket.Ser...
FILE: trace/mtu/metadata.go
constant mtuTimeoutGeoSource (line 13) | mtuTimeoutGeoSource = "timeout"
type mtuGeoLookupResult (line 17) | type mtuGeoLookupResult struct
function enrichHopMetadata (line 22) | func enrichHopMetadata(ctx context.Context, cfg Config, hop Hop) (Hop, b...
function shouldFetchHopMetadata (line 43) | func shouldFetchHopMetadata(cfg Config, hop Hop) bool {
function startMTUPTRLookup (line 50) | func startMTUPTRLookup(ctx context.Context, ipStr string) <-chan []string {
function applyMTUPTRResult (line 63) | func applyMTUPTRResult(h *Hop, ptrs []string) {
function startMTUGeoLookup (line 70) | func startMTUGeoLookup(cfg Config, ipStr string) <-chan mtuGeoLookupResu...
function waitForMTUGeoAndPTR (line 96) | func waitForMTUGeoAndPTR(ctx context.Context, cfg Config, hop Hop, geoCh...
function ctxDoneChan (line 158) | func ctxDoneChan(ctx context.Context) <-chan struct{} {
function normalizeMTUGeoData (line 165) | func normalizeMTUGeoData(geo *ipgeo.IPGeoData) *ipgeo.IPGeoData {
function mtuTimeoutGeo (line 194) | func mtuTimeoutGeo() *ipgeo.IPGeoData {
FILE: trace/mtu/metadata_test.go
function TestEnrichHopMetadataGeoSuccess (line 12) | func TestEnrichHopMetadataGeoSuccess(t *testing.T) {
function TestEnrichHopMetadataDisableGeoIPReturnsNoGeo (line 34) | func TestEnrichHopMetadataDisableGeoIPReturnsNoGeo(t *testing.T) {
function TestEnrichHopMetadataRDNSOnly (line 48) | func TestEnrichHopMetadataRDNSOnly(t *testing.T) {
function TestEnrichHopMetadataRDNSOnlyWithoutAlwaysWaitStillSetsHostname (line 69) | func TestEnrichHopMetadataRDNSOnlyWithoutAlwaysWaitStillSetsHostname(t *...
function TestEnrichHopMetadataAlwaysWaitRDNSWaitsForPTR (line 89) | func TestEnrichHopMetadataAlwaysWaitRDNSWaitsForPTR(t *testing.T) {
function TestEnrichHopMetadataGeoTimeout (line 119) | func TestEnrichHopMetadataGeoTimeout(t *testing.T) {
function TestEnrichHopMetadataCancelStopsWaitingForPTR (line 135) | func TestEnrichHopMetadataCancelStopsWaitingForPTR(t *testing.T) {
FILE: trace/mtu/runner.go
type prober (line 12) | type prober interface
type probePlan (line 17) | type probePlan struct
type localMTUError (line 24) | type localMTUError struct
method Error (line 28) | func (e *localMTUError) Error() string {
function Run (line 38) | func Run(ctx context.Context, cfg Config) (*Result, error) {
function RunStream (line 42) | func RunStream(ctx context.Context, cfg Config, sink StreamSink) (*Resul...
function runWithProber (line 55) | func runWithProber(ctx context.Context, cfg Config, p prober) (*Result, ...
function runStreamWithProber (line 59) | func runStreamWithProber(ctx context.Context, cfg Config, p prober, sink...
function normalizeConfig (line 171) | func normalizeConfig(cfg Config) (Config, error) {
method ipVersion (line 205) | func (cfg Config) ipVersion() int {
function initialPathMTU (line 215) | func initialPathMTU(cfg Config) int {
function initialProbeMTU (line 225) | func initialProbeMTU(ipVersion int) int {
function payloadSizeForMTU (line 232) | func payloadSizeForMTU(pathMTU, ipVersion int) int {
function minProbeMTU (line 243) | func minProbeMTU(ipVersion int) int {
function nextLocalProbeMTU (line 250) | func nextLocalProbeMTU(currentProbeMTU, reportedMTU, ipVersion int) (int...
function candidatePathMTU (line 262) | func candidatePathMTU(current, discovered int) int {
function buildHop (line 272) | func buildHop(cfg Config, ttl int, resp probeResponse) Hop {
function sleepContext (line 287) | func sleepContext(ctx context.Context, d time.Duration) error {
function emitStreamEvent (line 298) | func emitStreamEvent(sink StreamSink, kind StreamEventKind, res *Result,...
FILE: trace/mtu/runner_test.go
type scriptedStep (line 13) | type scriptedStep struct
type scriptedProber (line 18) | type scriptedProber struct
method Probe (line 23) | func (p *scriptedProber) Probe(_ context.Context, plan probePlan) (pro...
method Close (line 33) | func (p *scriptedProber) Close() error { return nil }
function TestRunWithProberShrinksPMTUAndRetriesSameTTL (line 35) | func TestRunWithProberShrinksPMTUAndRetriesSameTTL(t *testing.T) {
function TestRunWithProberKeepsLocalPMTUOffHopOutput (line 81) | func TestRunWithProberKeepsLocalPMTUOffHopOutput(t *testing.T) {
function TestRunWithProberAnnotatesFirstHopWithLocalStartMTU (line 116) | func TestRunWithProberAnnotatesFirstHopWithLocalStartMTU(t *testing.T) {
function TestRunWithProberAnnotatesFirstHopWithStartMTUWithoutLocalEvent (line 148) | func TestRunWithProberAnnotatesFirstHopWithStartMTUWithoutLocalEvent(t *...
function TestRunWithProberStopsTTLAfterFirstNonTimeout (line 179) | func TestRunWithProberStopsTTLAfterFirstNonTimeout(t *testing.T) {
function TestRunWithProberWritesTimeoutAfterExhaustingQueries (line 210) | func TestRunWithProberWritesTimeoutAfterExhaustingQueries(t *testing.T) {
function TestRunWithProberTimeoutHopDoesNotExposeLocalPMTU (line 242) | func TestRunWithProberTimeoutHopDoesNotExposeLocalPMTU(t *testing.T) {
function TestNormalizeConfigRejectsSourceDestinationFamilyMismatch (line 274) | func TestNormalizeConfigRejectsSourceDestinationFamilyMismatch(t *testin...
function TestRunWithProberFallbackShrinksAfterRepeatedLocalMTUErrors (line 286) | func TestRunWithProberFallbackShrinksAfterRepeatedLocalMTUErrors(t *test...
function TestRunStreamWithProberEmitsOrderedEvents (line 334) | func TestRunStreamWithProberEmitsOrderedEvents(t *testing.T) {
function TestRunStreamWithProberEmitsTimeoutFinalEvent (line 396) | func TestRunStreamWithProberEmitsTimeoutFinalEvent(t *testing.T) {
function TestRunStreamWithProberEmitsGeoUpdateBeforeFinal (line 434) | func TestRunStreamWithProberEmitsGeoUpdateBeforeFinal(t *testing.T) {
function TestCandidatePathMTUNeverIncreases (line 492) | func TestCandidatePathMTUNeverIncreases(t *testing.T) {
FILE: trace/mtu/socket_prober.go
type socketProber (line 16) | type socketProber struct
method Close (line 72) | func (p *socketProber) Close() error {
method Probe (line 85) | func (p *socketProber) Probe(ctx context.Context, plan probePlan) (pro...
method send (line 120) | func (p *socketProber) send(ttl int, payload []byte, dstPort int) error {
method readICMPResponseFromSocket (line 177) | func (p *socketProber) readICMPResponseFromSocket(ctx context.Context,...
function newSocketProber (line 30) | func newSocketProber(cfg Config) (*socketProber, error) {
function probeDstPort (line 137) | func probeDstPort(base int, token uint32) int {
function buildWinDivertMTUFilter (line 152) | func buildWinDivertMTUFilter(ipVersion int, srcIP net.IP) string {
type icmpResponseCapture (line 165) | type icmpResponseCapture interface
function deadlineFromStart (line 169) | func deadlineFromStart(ctx context.Context, start time.Time, timeout tim...
FILE: trace/mtu/socket_prober_read_default.go
method beginICMPResponseCapture (line 10) | func (p *socketProber) beginICMPResponseCapture(context.Context, time.Ti...
method readICMPResponse (line 14) | func (p *socketProber) readICMPResponse(ctx context.Context, _ icmpRespo...
FILE: trace/mtu/socket_prober_read_windows.go
type winDivertCapture (line 16) | type winDivertCapture struct
method Close (line 25) | func (c *winDivertCapture) Close() error {
method beginICMPResponseCapture (line 39) | func (p *socketProber) beginICMPResponseCapture(ctx context.Context, _ t...
method readICMPResponse (line 63) | func (p *socketProber) readICMPResponse(ctx context.Context, capture icm...
method readICMPResponseViaWinDivert (line 70) | func (p *socketProber) readICMPResponseViaWinDivert(ctx context.Context,...
function winDivertMTUFilter (line 111) | func winDivertMTUFilter(ipVersion int, localAddr net.Addr) string {
function extractWinDivertICMPMessage (line 115) | func extractWinDivertICMPMessage(ipVersion int, raw []byte) (net.IP, []b...
FILE: trace/mtu/socket_prober_test.go
function TestProbeDstPortHandlesZeroToken (line 8) | func TestProbeDstPortHandlesZeroToken(t *testing.T) {
function TestBuildWinDivertMTUFilter (line 14) | func TestBuildWinDivertMTUFilter(t *testing.T) {
FILE: trace/mtu/socketopts_darwin.go
function configurePMTUSocket (line 12) | func configurePMTUSocket(conn *net.UDPConn, ipVersion int) error {
function socketPathMTU (line 30) | func socketPathMTU(_ *net.UDPConn, _ int) int {
function isSendSizeErr (line 34) | func isSendSizeErr(err error) bool {
function isRecvSizeErr (line 38) | func isRecvSizeErr(err error) bool {
FILE: trace/mtu/socketopts_linux.go
function configurePMTUSocket (line 12) | func configurePMTUSocket(conn *net.UDPConn, ipVersion int) error {
function socketPathMTU (line 30) | func socketPathMTU(conn *net.UDPConn, ipVersion int) int {
function isSendSizeErr (line 46) | func isSendSizeErr(err error) bool {
function isRecvSizeErr (line 50) | func isRecvSizeErr(err error) bool {
FILE: trace/mtu/socketopts_stub.go
function configurePMTUSocket (line 7) | func configurePMTUSocket(_ *net.UDPConn, _ int) error {
function socketPathMTU (line 11) | func socketPathMTU(_ *net.UDPConn, _ int) int {
function isSendSizeErr (line 15) | func isSendSizeErr(_ error) bool {
function isRecvSizeErr (line 19) | func isRecvSizeErr(_ error) bool {
FILE: trace/mtu/socketopts_windows.go
constant ipDontFragment (line 14) | ipDontFragment = 14
constant ipv6DontFrag (line 15) | ipv6DontFrag = 14
function configurePMTUSocket (line 18) | func configurePMTUSocket(conn *net.UDPConn, ipVersion int) error {
function socketPathMTU (line 52) | func socketPathMTU(conn *net.UDPConn, _ int) int {
function isSendSizeErr (line 63) | func isSendSizeErr(err error) bool {
function isRecvSizeErr (line 67) | func isRecvSizeErr(err error) bool {
FILE: trace/mtu/types.go
type Event (line 10) | type Event
constant EventTimeExceeded (line 13) | EventTimeExceeded Event = "time_exceeded"
constant EventPacketTooBig (line 14) | EventPacketTooBig Event = "packet_too_big"
constant EventFragNeeded (line 15) | EventFragNeeded Event = "frag_needed"
constant EventDestination (line 16) | EventDestination Event = "destination"
constant EventTimeout (line 17) | EventTimeout Event = "timeout"
type StreamEventKind (line 20) | type StreamEventKind
constant StreamEventTTLStart (line 23) | StreamEventTTLStart StreamEventKind = "ttl_start"
constant StreamEventTTLUpdate (line 24) | StreamEventTTLUpdate StreamEventKind = "ttl_update"
constant StreamEventTTLFinal (line 25) | StreamEventTTLFinal StreamEventKind = "ttl_final"
constant StreamEventDone (line 26) | StreamEventDone StreamEventKind = "done"
type Config (line 29) | type Config struct
type Hop (line 47) | type Hop struct
type Result (line 57) | type Result struct
type StreamEvent (line 68) | type StreamEvent struct
type StreamSink (line 81) | type StreamSink
FILE: trace/packet_size.go
constant ipv4HeaderBytes (line 12) | ipv4HeaderBytes = 20
constant ipv6HeaderBytes (line 13) | ipv6HeaderBytes = 40
constant icmpHeaderBytes (line 14) | icmpHeaderBytes = 8
constant udpHeaderBytes (line 15) | udpHeaderBytes = 8
constant tcpProbeHeaderBytes (line 16) | tcpProbeHeaderBytes = 24
constant udpV6MinPayload (line 17) | udpV6MinPayload = 2
type PacketSizeSpec (line 20) | type PacketSizeSpec struct
function DefaultPacketSize (line 25) | func DefaultPacketSize(method Method, dstIP net.IP) int {
function packetSizeIPHeaderBytes (line 29) | func packetSizeIPHeaderBytes(dstIP net.IP) int {
function packetSizeProtocolHeaderBytes (line 36) | func packetSizeProtocolHeaderBytes(method Method) int {
function packetSizeMinPayload (line 47) | func packetSizeMinPayload(method Method, dstIP net.IP) int {
function MinPacketSize (line 54) | func MinPacketSize(method Method, dstIP net.IP) int {
function NormalizePacketSize (line 58) | func NormalizePacketSize(method Method, dstIP net.IP, packetSize int) (P...
function resolveProbePayloadSize (line 81) | func resolveProbePayloadSize(method Method, dstIP net.IP, maxPayloadSize...
function packetSizeFamilyLabel (line 89) | func packetSizeFamilyLabel(dstIP net.IP) string {
function FormatPacketSizeLabel (line 96) | func FormatPacketSizeLabel(packetSize int) string {
FILE: trace/packet_size_test.go
function TestNormalizePacketSize (line 8) | func TestNormalizePacketSize(t *testing.T) {
function TestNormalizePacketSizeRejectsTooSmallValues (line 41) | func TestNormalizePacketSizeRejectsTooSmallValues(t *testing.T) {
function TestMinPacketSize (line 65) | func TestMinPacketSize(t *testing.T) {
function TestDefaultPacketSizeMatchesMinimum (line 86) | func TestDefaultPacketSizeMatchesMinimum(t *testing.T) {
FILE: trace/quic.go
function GenerateQuicPayloadWithRandomIds (line 12) | func GenerateQuicPayloadWithRandomIds() []byte {
FILE: trace/tcp_ipv4.go
type TCPTracer (line 23) | type TCPTracer struct
method waitAllReady (line 39) | func (t *TCPTracer) waitAllReady(ctx context.Context) {
method ttlComp (line 57) | func (t *TCPTracer) ttlComp(ttl int) bool {
method PrintFunc (line 64) | func (t *TCPTracer) PrintFunc(ctx context.Context, cancel context.Canc...
method launchTTL (line 97) | func (t *TCPTracer) launchTTL(ctx context.Context, s *internal.TCPSpec...
method markPending (line 125) | func (t *TCPTracer) markPending(seq int) {
method clearPending (line 131) | func (t *TCPTracer) clearPending(seq int) bool {
method storeSent (line 139) | func (t *TCPTracer) storeSent(seq, srcPort, payloadSize int, start tim...
method lookupSent (line 145) | func (t *TCPTracer) lookupSent(seq int) (srcPort int, start time.Time,...
method lookupSentByAck (line 155) | func (t *TCPTracer) lookupSentByAck(srcPort, ack int) (seq int, start ...
method dropSent (line 161) | func (t *TCPTracer) dropSent(seq int) {
method addHopWithIndex (line 167) | func (t *TCPTracer) addHopWithIndex(peer net.Addr, ttl, i int, rtt tim...
method matchWorker (line 194) | func (t *TCPTracer) matchWorker(ctx context.Context) {
method Execute (line 250) | func (t *TCPTracer) Execute() (res *Result, err error) {
method handleICMPMessage (line 372) | func (t *TCPTracer) handleICMPMessage(msg internal.ReceivedMessage, fi...
method send (line 404) | func (t *TCPTracer) send(ctx context.Context, s *internal.TCPSpec, ttl...
FILE: trace/tcp_ipv6.go
type TCPTracerIPv6 (line 23) | type TCPTracerIPv6 struct
method waitAllReady (line 39) | func (t *TCPTracerIPv6) waitAllReady(ctx context.Context) {
method ttlComp (line 57) | func (t *TCPTracerIPv6) ttlComp(ttl int) bool {
method PrintFunc (line 64) | func (t *TCPTracerIPv6) PrintFunc(ctx context.Context, cancel context....
method launchTTL (line 97) | func (t *TCPTracerIPv6) launchTTL(ctx context.Context, s *internal.TCP...
method markPending (line 125) | func (t *TCPTracerIPv6) markPending(seq int) {
method clearPending (line 131) | func (t *TCPTracerIPv6) clearPending(seq int) bool {
method storeSent (line 139) | func (t *TCPTracerIPv6) storeSent(seq, srcPort, payloadSize int, start...
method lookupSent (line 145) | func (t *TCPTracerIPv6) lookupSent(seq int) (srcPort int, start time.T...
method lookupSentByAck (line 155) | func (t *TCPTracerIPv6) lookupSentByAck(srcPort, ack int) (seq int, st...
method dropSent (line 161) | func (t *TCPTracerIPv6) dropSent(seq int) {
method addHopWithIndex (line 167) | func (t *TCPTracerIPv6) addHopWithIndex(peer net.Addr, ttl, i int, rtt...
method matchWorker (line 194) | func (t *TCPTracerIPv6) matchWorker(ctx context.Context) {
method Execute (line 250) | func (t *TCPTracerIPv6) Execute() (res *Result, err error) {
method handleICMPMessage (line 372) | func (t *TCPTracerIPv6) handleICMPMessage(msg internal.ReceivedMessage...
method send (line 404) | func (t *TCPTracerIPv6) send(ctx context.Context, s *internal.TCPSpec,...
FILE: trace/tcp_match.go
function tcpReplyAckForProbe (line 5) | func tcpReplyAckForProbe(seq int, payloadSize int) int {
function lookupTCPSentByAck (line 9) | func lookupTCPSentByAck(sentAt map[int]sentInfo, srcPort, ack int) (seq ...
FILE: trace/tcp_match_test.go
function TestLookupTCPSentByAck (line 8) | func TestLookupTCPSentByAck(t *testing.T) {
FILE: trace/temp_printer.go
function HopPrinter (line 10) | func HopPrinter(h Hop) {
function formatIpGeoData (line 30) | func formatIpGeoData(ip string, data *ipgeo.IPGeoData) string {
FILE: trace/trace.go
type Config (line 33) | type Config struct
type Method (line 65) | type Method
constant ICMPTrace (line 68) | ICMPTrace Method = "icmp"
constant UDPTrace (line 69) | UDPTrace Method = "udp"
constant TCPTrace (line 70) | TCPTrace Method = "tcp"
type attemptKey (line 73) | type attemptKey struct
type attemptPort (line 78) | type attemptPort struct
type sentInfo (line 83) | type sentInfo struct
type matchTask (line 91) | type matchTask struct
type Tracer (line 100) | type Tracer interface
function applyTracerouteDefaults (line 104) | func applyTracerouteDefaults(config *Config) {
function waitForTraceDelay (line 119) | func waitForTraceDelay(ctx context.Context, d time.Duration) bool {
function stopAndDrainTimer (line 139) | func stopAndDrainTimer(timer *time.Timer) {
function acquireTraceSemaphore (line 152) | func acquireTraceSemaphore(ctx context.Context, sem *semaphore.Weighted)...
function normalizeICMPMode (line 165) | func normalizeICMPMode(config *Config) {
function deriveMaxAttempts (line 179) | func deriveMaxAttempts(config *Config) {
function selectTracer (line 201) | func selectTracer(method Method, config Config) (Tracer, error) {
function waitForPendingGeoData (line 224) | func waitForPendingGeoData(ctx context.Context, result *Result) {
function ctxDoneChan (line 243) | func ctxDoneChan(ctx context.Context) <-chan struct{} {
function Traceroute (line 250) | func Traceroute(method Method, config Config) (*Result, error) {
function TracerouteWithContext (line 269) | func TracerouteWithContext(ctx context.Context, method Method, config Co...
function normalizeRuntimeConfig (line 277) | func normalizeRuntimeConfig(config *Config) {
type Result (line 286) | type Result struct
method add (line 344) | func (s *Result) add(hop Hop, attemptIdx, numMeasurements, maxAttempts...
method setGeoWait (line 389) | func (s *Result) setGeoWait(numMeasurements int) {
method reduce (line 393) | func (s *Result) reduce(final int) {
method updateHop (line 453) | func (s *Result) updateHop(ttl, idx int, updated Hop) {
method waitGeo (line 477) | func (s *Result) waitGeo(ctx context.Context, ttlIdx int) {
method hasPendingGeo (line 507) | func (s *Result) hasPendingGeo(ttlIdx int) bool {
method markPendingGeoTimeout (line 526) | func (s *Result) markPendingGeoTimeout(ttlIdx int) {
method markAllPendingGeoTimeout (line 543) | func (s *Result) markAllPendingGeoTimeout() {
method addWithGeoAsync (line 558) | func (s *Result) addWithGeoAsync(hop Hop, attemptIdx, numMeasurements,...
constant PendingGeoSource (line 296) | PendingGeoSource = "pending"
constant timeoutGeoSource (line 297) | timeoutGeoSource = "timeout"
function isPendingGeo (line 299) | func isPendingGeo(geo *ipgeo.IPGeoData) bool {
function pendingGeo (line 303) | func pendingGeo() *ipgeo.IPGeoData {
function timeoutGeo (line 307) | func timeoutGeo() *ipgeo.IPGeoData {
function geoWaitForMeasurements (line 315) | func geoWaitForMeasurements(numMeasurements int) time.Duration {
function isValidHop (line 336) | func isValidHop(h Hop) bool {
type Hop (line 402) | type Hop struct
method resolveDN42Metadata (line 671) | func (h *Hop) resolveDN42Metadata(c Config, ipStr string) error {
method startGeoLookup (line 692) | func (h *Hop) startGeoLookup(c Config, ipStr string) <-chan error {
method waitForGeoAndPTR (line 716) | func (h *Hop) waitForGeoAndPTR(c Config, ipGeoCh <-chan error, rDNSSta...
method fetchIPData (line 756) | func (h *Hop) fetchIPData(c Config) error {
function isLDHASCII (line 414) | func isLDHASCII(label string) bool {
function CanonicalHostname (line 428) | func CanonicalHostname(s string) string {
function geoLookupMaxRetries (line 583) | func geoLookupMaxRetries(numMeasurements int) int {
function geoTimeoutForAttempt (line 594) | func geoTimeoutForAttempt(attempt int) time.Duration {
function lookupGeoWithRetry (line 602) | func lookupGeoWithRetry(c Config, cacheKey, query string, dn42 bool) (*i...
function lookupPTR (line 643) | func lookupPTR(ctx context.Context, ipStr string) []string {
function applyPTRResult (line 654) | func applyPTRResult(h *Hop, ptrs []string) {
function startPTRLookup (line 660) | func startPTRLookup(ctx context.Context, ipStr string) <-chan []string {
function parse (line 772) | func parse(s string, bitSize int) (uint64, bool) {
function findValid (line 784) | func findValid(hexStr string) string {
function extractMPLS (line 815) | func extractMPLS(msg internal.ReceivedMessage, disableMPLS bool) []string {
FILE: trace/trace_runtime_test.go
function TestWaitForTraceDelayCanceledContextReturnsImmediately (line 14) | func TestWaitForTraceDelayCanceledContextReturnsImmediately(t *testing.T) {
function TestWaitForTraceDelayZeroDelaySucceeds (line 27) | func TestWaitForTraceDelayZeroDelaySucceeds(t *testing.T) {
function TestAcquireTraceSemaphoreChecksCanceledContextFirst (line 33) | func TestAcquireTraceSemaphoreChecksCanceledContextFirst(t *testing.T) {
function TestWaitForPendingGeoDataReturnsOnCanceledContext (line 58) | func TestWaitForPendingGeoDataReturnsOnCanceledContext(t *testing.T) {
function TestWaitForPendingGeoDataReturnsImmediatelyForCompletedWorkers (line 92) | func TestWaitForPendingGeoDataReturnsImmediatelyForCompletedWorkers(t *t...
FILE: trace/udp_ipv4.go
type UDPTracer (line 23) | type UDPTracer struct
method waitAllReady (line 42) | func (t *UDPTracer) waitAllReady(ctx context.Context) {
method ttlComp (line 62) | func (t *UDPTracer) ttlComp(ttl int) bool {
method PrintFunc (line 69) | func (t *UDPTracer) PrintFunc(ctx context.Context, cancel context.Canc...
method launchTTL (line 102) | func (t *UDPTracer) launchTTL(ctx context.Context, s *internal.UDPSpec...
method tryMatchTTLPort (line 130) | func (t *UDPTracer) tryMatchTTLPort(ttl, srcPort int) (int, bool) {
method enqueueTTLPort (line 145) | func (t *UDPTracer) enqueueTTLPort(ttl, i, srcPort int) {
method markPending (line 152) | func (t *UDPTracer) markPending(ttl, i int) {
method clearPending (line 159) | func (t *UDPTracer) clearPending(ttl, i int) bool {
method storeSent (line 168) | func (t *UDPTracer) storeSent(seq, ttl, i, srcPort int, start time.Tim...
method lookupSent (line 178) | func (t *UDPTracer) lookupSent(seq int) (ttl, i, srcPort int, start ti...
method dropSent (line 188) | func (t *UDPTracer) dropSent(seq int) {
method dropByAttempt (line 194) | func (t *UDPTracer) dropByAttempt(ttl, i int) {
method addHopWithIndex (line 205) | func (t *UDPTracer) addHopWithIndex(peer net.Addr, ttl, i int, rtt tim...
method matchWorker (line 232) | func (t *UDPTracer) matchWorker(ctx context.Context) {
method Execute (line 284) | func (t *UDPTracer) Execute() (res *Result, err error) {
method handleICMPMessage (line 409) | func (t *UDPTracer) handleICMPMessage(msg internal.ReceivedMessage, fi...
method acquireSendPermit (line 450) | func (t *UDPTracer) acquireSendPermit(ctx context.Context, ttl int) (f...
method resolveSourcePort (line 469) | func (t *UDPTracer) resolveSourcePort() int {
method buildUDPPacket (line 477) | func (t *UDPTracer) buildUDPPacket(ttl, i, srcPort int) (int, *layers....
method startSendTimeout (line 496) | func (t *UDPTracer) startSendTimeout(ctx context.Context, ttl, i, seq ...
method prepareDarwinSend (line 529) | func (t *UDPTracer) prepareDarwinSend(ttl, i, srcPort int) {
method finalizeSent (line 535) | func (t *UDPTracer) finalizeSent(seq, srcPort int, start time.Time) {
method send (line 541) | func (t *UDPTracer) send(ctx context.Context, s *internal.UDPSpec, ttl...
function randomPayload (line 441) | func randomPayload(size int, offset int) []byte {
FILE: trace/udp_ipv6.go
type UDPTracerIPv6 (line 23) | type UDPTracerIPv6 struct
method waitAllReady (line 39) | func (t *UDPTracerIPv6) waitAllReady(ctx context.Context) {
method ttlComp (line 57) | func (t *UDPTracerIPv6) ttlComp(ttl int) bool {
method PrintFunc (line 64) | func (t *UDPTracerIPv6) PrintFunc(ctx context.Context, cancel context....
method launchTTL (line 97) | func (t *UDPTracerIPv6) launchTTL(ctx context.Context, s *internal.UDP...
method markPending (line 125) | func (t *UDPTracerIPv6) markPending(seq int) {
method clearPending (line 131) | func (t *UDPTracerIPv6) clearPending(seq int) bool {
method storeSent (line 139) | func (t *UDPTracerIPv6) storeSent(seq, srcPort int, start time.Time) {
method lookupSent (line 145) | func (t *UDPTracerIPv6) lookupSent(seq int) (srcPort int, start time.T...
method dropSent (line 155) | func (t *UDPTracerIPv6) dropSent(seq int) {
method addHopWithIndex (line 161) | func (t *UDPTracerIPv6) addHopWithIndex(peer net.Addr, ttl, i int, rtt...
method matchWorker (line 188) | func (t *UDPTracerIPv6) matchWorker(ctx context.Context) {
method Execute (line 238) | func (t *UDPTracerIPv6) Execute() (res *Result, err error) {
method handleICMPMessage (line 345) | func (t *UDPTracerIPv6) handleICMPMessage(msg internal.ReceivedMessage...
method send (line 377) | func (t *UDPTracerIPv6) send(ctx context.Context, s *internal.UDPSpec,...
FILE: tracelog/log.go
function formatTraceLogWhois (line 18) | func formatTraceLogWhois(whois string) string {
function traceLogLocationLine (line 29) | func traceLogLocationLine(hop *trace.Hop, ip string) string {
function traceLogTimingLine (line 40) | func traceLogTimingLine(values []string) string {
function OpenFile (line 44) | func OpenFile(path string) (*os.File, error) {
function WriteHeader (line 48) | func WriteHeader(w io.Writer, header string) error {
function renderTraceLogLine (line 56) | func renderTraceLogLine(res *trace.Result, ttl int, group hoprender.Grou...
function WriteRealtime (line 88) | func WriteRealtime(w io.Writer, res *trace.Result, ttl int) error {
function NewRealtimePrinter (line 108) | func NewRealtimePrinter(w io.Writer) func(res *trace.Result, ttl int) {
function RealtimePrinter (line 114) | func RealtimePrinter(res *trace.Result, ttl int) {
FILE: tracelog/log_test.go
function testTraceLogResult (line 17) | func testTraceLogResult() *trace.Result {
function TestWriteHeader (line 37) | func TestWriteHeader(t *testing.T) {
function TestWriteRealtimeUsesProvidedWriter (line 47) | func TestWriteRealtimeUsesProvidedWriter(t *testing.T) {
function TestNewRealtimePrinterWrapsWriter (line 60) | func TestNewRealtimePrinterWrapsWriter(t *testing.T) {
function captureStdIO (line 69) | func captureStdIO(t *testing.T, fn func()) (string, string) {
function TestDefaultPathUsesTempDir (line 106) | func TestDefaultPathUsesTempDir(t *testing.T) {
function TestRealtimePrinterFallsBackToStdoutWhenOpenFails (line 113) | func TestRealtimePrinterFallsBackToStdoutWhenOpenFails(t *testing.T) {
FILE: tracemap/tracemap.go
function GetMapUrl (line 23) | func GetMapUrl(r string) (string, error) {
function GetMapUrlWithContext (line 27) | func GetMapUrlWithContext(ctx context.Context, r string) (string, error) {
function newTraceMapHTTPClient (line 85) | func newTraceMapHTTPClient(host string) *http.Client {
function PrintMapUrl (line 96) | func PrintMapUrl(r string) {
FILE: tracemap/tracemap_test.go
type blockingRoundTripper (line 13) | type blockingRoundTripper struct
method RoundTrip (line 15) | func (blockingRoundTripper) RoundTrip(req *http.Request) (*http.Respon...
function TestGetMapUrlWithContextReturnsCanceled (line 20) | func TestGetMapUrlWithContextReturnsCanceled(t *testing.T) {
FILE: util/common.go
function Dnspod (line 5) | func Dnspod() *net.Resolver {
function Aliyun (line 9) | func Aliyun() *net.Resolver {
function DNSSB (line 13) | func DNSSB() *net.Resolver {
function Cloudflare (line 17) | func Cloudflare() *net.Resolver {
function Google (line 21) | func Google() *net.Resolver {
FILE: util/dns_resolver.go
function setGeoResolverOverride (line 36) | func setGeoResolverOverride(resolver *net.Resolver) {
function getGeoResolverOverride (line 42) | func getGeoResolverOverride() *net.Resolver {
function SetGeoDNSResolver (line 50) | func SetGeoDNSResolver(dotServer string) {
function SetGeoDNSFallback (line 57) | func SetGeoDNSFallback(enabled bool) {
function WithGeoDNSResolver (line 65) | func WithGeoDNSResolver[T any](dotServer string, callback func() (T, err...
function releaseGeoDNSResolverScope (line 97) | func releaseGeoDNSResolverScope() {
function getGeoDNSConfig (line 122) | func getGeoDNSConfig() (dotServer string, fallback bool) {
function ResolverForDot (line 130) | func ResolverForDot(dotServer string) *net.Resolver {
function LookupHostForGeo (line 153) | func LookupHostForGeo(ctx context.Context, host string) ([]net.IP, error) {
function resolveHost (line 189) | func resolveHost(ctx context.Context, r *net.Resolver, host string) ([]n...
FILE: util/dns_resolver_test.go
function TestResolverMapping (line 12) | func TestResolverMapping(t *testing.T) {
function TestLookupHostForGeo_IPLiteral (line 34) | func TestLookupHostForGeo_IPLiteral(t *testing.T) {
function TestLookupHostForGeo_DoTSuccess (line 54) | func TestLookupHostForGeo_DoTSuccess(t *testing.T) {
function TestLookupHostForGeo_NoDotFallsToSystem (line 77) | func TestLookupHostForGeo_NoDotFallsToSystem(t *testing.T) {
function TestLookupHostForGeo_DoTFailFallback (line 100) | func TestLookupHostForGeo_DoTFailFallback(t *testing.T) {
function TestLookupHostForGeo_DoTFailNoFallback (line 133) | func TestLookupHostForGeo_DoTFailNoFallback(t *testing.T) {
function TestGeoDNSConfig_ConcurrentAccess (line 160) | func TestGeoDNSConfig_ConcurrentAccess(t *testing.T) {
function TestWithGeoDNSResolver_RestoresPreviousConfig (line 176) | func TestWithGeoDNSResolver_RestoresPreviousConfig(t *testing.T) {
function TestWithGeoDNSResolver_AllowsNestedSameResolver (line 209) | func TestWithGeoDNSResolver_AllowsNestedSameResolver(t *testing.T) {
FILE: util/dot.go
function newDoTResolver (line 10) | func newDoTResolver(serverName string, addrs string) *net.Resolver {
FILE: util/env.go
constant EnvAllowCrossOriginKey (line 27) | EnvAllowCrossOriginKey = "NEXTTRACE_ALLOW_CROSS_ORIGIN"
function GetEnvTrimmed (line 29) | func GetEnvTrimmed(key string) (string, bool) {
function GetEnvBool (line 41) | func GetEnvBool(key string, def bool) bool {
function GetEnvDefault (line 55) | func GetEnvDefault(key string, def string) string {
function GetEnvInt (line 62) | func GetEnvInt(key string, def int) int {
function AllowCrossOriginBrowserAccess (line 73) | func AllowCrossOriginBrowserAccess() bool {
FILE: util/env_test.go
function TestGetEnvTrimmed (line 9) | func TestGetEnvTrimmed(t *testing.T) {
function TestGetEnvBool (line 20) | func TestGetEnvBool(t *testing.T) {
function TestGetEnvDefault (line 31) | func TestGetEnvDefault(t *testing.T) {
function TestGetEnvInt (line 38) | func TestGetEnvInt(t *testing.T) {
function TestAllowCrossOriginBrowserAccess (line 48) | func TestAllowCrossOriginBrowserAccess(t *testing.T) {
FILE: util/frag.go
type IPv4Fragment (line 10) | type IPv4Fragment struct
function getNamedDeviceMTU (line 15) | func getNamedDeviceMTU(srcDev string) (int, bool) {
function addressIP (line 25) | func addressIP(addr net.Addr) net.IP {
function matchInterfaceIP (line 36) | func matchInterfaceIP(candidate, target net.IP, isIPv6 bool) bool {
function GetMTUByIPForDevice (line 49) | func GetMTUByIPForDevice(srcIP net.IP, srcDev string) int {
function GetMTUByIP (line 78) | func GetMTUByIP(srcIP net.IP) int {
function IPv4Fragmentize (line 83) | func IPv4Fragmentize(base *ipv4.Header, body []byte, mtu int) ([]IPv4Fra...
FILE: util/http_client_geo.go
function NewGeoHTTPClient (line 15) | func NewGeoHTTPClient(timeout time.Duration) *http.Client {
FILE: util/http_client_geo_test.go
function TestNewGeoHTTPClient_ReturnsValidClient (line 9) | func TestNewGeoHTTPClient_ReturnsValidClient(t *testing.T) {
function TestNewGeoHTTPClient_HasCustomTransport (line 19) | func TestNewGeoHTTPClient_HasCustomTransport(t *testing.T) {
function TestNewGeoHTTPClient_DifferentTimeouts (line 30) | func TestNewGeoHTTPClient_DifferentTimeouts(t *testing.T) {
FILE: util/latency.go
type ResponseInfo (line 18) | type ResponseInfo struct
type FastIPMeta (line 36) | type FastIPMeta struct
function GetFastIP (line 49) | func GetFastIP(domain string, port string, enableOutput bool) string {
function GetFastIPCache (line 58) | func GetFastIPCache() string {
function GetFastIPMetaCache (line 64) | func GetFastIPMetaCache() FastIPMeta {
function SetFastIPCacheState (line 70) | func SetFastIPCacheState(ip string, meta FastIPMeta) {
function GetFastIPWithContext (line 77) | func GetFastIPWithContext(ctx context.Context, domain string, port strin...
function defaultFastIPCandidates (line 150) | func defaultFastIPCandidates() []net.IP {
function defaultFastIP (line 157) | func defaultFastIP() string {
function checkLatencyWithContext (line 161) | func checkLatencyWithContext(ctx context.Context, domain string, ip stri...
FILE: util/latency_test.go
function TestGetFastIPWithContextReturnsCanceled (line 11) | func TestGetFastIPWithContextReturnsCanceled(t *testing.T) {
FILE: util/pcap.go
function ipKey (line 17) | func ipKey(ip net.IP) string {
function PcapDeviceByIP (line 25) | func PcapDeviceByIP(srcip net.IP) (string, error) {
function OpenLiveImmediate (line 70) | func OpenLiveImmediate(dev string, snaplen int, promisc bool, bufferSize...
FILE: util/privilege_stub.go
function HasAdminPrivileges (line 5) | func HasAdminPrivileges() bool {
FILE: util/privilege_windows.go
function HasAdminPrivileges (line 12) | func HasAdminPrivileges() bool {
FILE: util/trace.go
function GetIPHeaderLength (line 8) | func GetIPHeaderLength(data []byte) (int, error) {
function extractIPv4Payload (line 27) | func extractIPv4Payload(data []byte, hdrLen int) ([]byte, error) {
function nextIPv6PayloadOffset (line 34) | func nextIPv6PayloadOffset(data []byte, offset int, next byte) (int, byt...
function extractIPv6Payload (line 68) | func extractIPv6Payload(data []byte, hdrLen int) ([]byte, error) {
function GetICMPResponsePayload (line 91) | func GetICMPResponsePayload(data []byte) ([]byte, error) {
function GetICMPID (line 110) | func GetICMPID(data []byte) (int, error) {
function GetICMPSeq (line 118) | func GetICMPSeq(data []byte) (int, error) {
function GetTCPPorts (line 126) | func GetTCPPorts(data []byte) (int, int, error) {
function GetTCPSeq (line 135) | func GetTCPSeq(data []byte) (int, error) {
function GetUDPPorts (line 143) | func GetUDPPorts(data []byte) (int, int, error) {
function GetUDPSeq (line 152) | func GetUDPSeq(data []byte) (int, error) {
function GetUDPSeqv6 (line 167) | func GetUDPSeqv6(data []byte) (int, error) {
FILE: util/trace_privilege.go
type TracePrivilegeCheck (line 3) | type TracePrivilegeCheck struct
FILE: util/trace_privilege_darwin.go
function TracePrivilegeStatus (line 6) | func TracePrivilegeStatus(string, bool) TracePrivilegeCheck {
FILE: util/trace_privilege_linux.go
function TracePrivilegeStatus (line 12) | func TracePrivilegeStatus(appBinName string, _ bool) TracePrivilegeCheck {
FILE: util/trace_privilege_stub.go
function TracePrivilegeStatus (line 5) | func TracePrivilegeStatus(string, bool) TracePrivilegeCheck {
FILE: util/trace_privilege_windows.go
function TracePrivilegeStatus (line 5) | func TracePrivilegeStatus(_ string, requireWindowsAdmin bool) TracePrivi...
FILE: util/trace_test.go
function TestGetIPHeaderLength_IPv4_MinIHL (line 13) | func TestGetIPHeaderLength_IPv4_MinIHL(t *testing.T) {
function TestGetIPHeaderLength_IPv4_WithOptions (line 21) | func TestGetIPHeaderLength_IPv4_WithOptions(t *testing.T) {
function TestGetIPHeaderLength_IPv4_InvalidIHL (line 29) | func TestGetIPHeaderLength_IPv4_InvalidIHL(t *testing.T) {
function TestGetIPHeaderLength_IPv6 (line 37) | func TestGetIPHeaderLength_IPv6(t *testing.T) {
function TestGetIPHeaderLength_UnknownVersion (line 44) | func TestGetIPHeaderLength_UnknownVersion(t *testing.T) {
function TestGetIPHeaderLength_Empty (line 51) | func TestGetIPHeaderLength_Empty(t *testing.T) {
function TestGetICMPID_Valid (line 58) | func TestGetICMPID_Valid(t *testing.T) {
function TestGetICMPID_TooShort (line 67) | func TestGetICMPID_TooShort(t *testing.T) {
function TestGetICMPSeq_Valid (line 73) | func TestGetICMPSeq_Valid(t *testing.T) {
function TestGetICMPSeq_TooShort (line 81) | func TestGetICMPSeq_TooShort(t *testing.T) {
function TestGetTCPPorts_Valid (line 89) | func TestGetTCPPorts_Valid(t *testing.T) {
function TestGetTCPPorts_TooShort (line 99) | func TestGetTCPPorts_TooShort(t *testing.T) {
function TestGetTCPSeq_Valid (line 105) | func TestGetTCPSeq_Valid(t *testing.T) {
function TestGetTCPSeq_TooShort (line 113) | func TestGetTCPSeq_TooShort(t *testing.T) {
function TestGetUDPPorts_Valid (line 121) | func TestGetUDPPorts_Valid(t *testing.T) {
function TestGetUDPPorts_TooShort (line 131) | func TestGetUDPPorts_TooShort(t *testing.T) {
function TestGetUDPSeq_Valid (line 137) | func TestGetUDPSeq_Valid(t *testing.T) {
function TestGetUDPSeq_TooShort (line 147) | func TestGetUDPSeq_TooShort(t *testing.T) {
function TestGetUDPSeqv6_Valid (line 152) | func TestGetUDPSeqv6_Valid(t *testing.T) {
function TestGetUDPSeqv6_TooShort (line 160) | func TestGetUDPSeqv6_TooShort(t *testing.T) {
function TestGetICMPResponsePayload_IPv4_Simple (line 168) | func TestGetICMPResponsePayload_IPv4_Simple(t *testing.T) {
function TestGetICMPResponsePayload_IPv6_NoExtHeaders (line 181) | func TestGetICMPResponsePayload_IPv6_NoExtHeaders(t *testing.T) {
function TestGetICMPResponsePayload_IPv6_WithHopByHopHeader (line 195) | func TestGetICMPResponsePayload_IPv6_WithHopByHopHeader(t *testing.T) {
function TestGetICMPResponsePayload_Empty (line 211) | func TestGetICMPResponsePayload_Empty(t *testing.T) {
FILE: util/udp.go
function newUDPResolver (line 7) | func newUDPResolver() *net.Resolver {
FILE: util/util.go
constant dnsLookupTimeout (line 33) | dnsLookupTimeout = 5 * time.Second
type addrLookupResolver (line 35) | type addrLookupResolver interface
function IsIPv6 (line 44) | func IsIPv6(ip net.IP) bool {
function AddrIP (line 50) | func AddrIP(a net.Addr) net.IP {
function RandomPortEnabled (line 63) | func RandomPortEnabled() bool {
function LookupAddr (line 67) | func LookupAddr(addr string) ([]string, error) {
function LookupAddrWithContext (line 71) | func LookupAddrWithContext(ctx context.Context, addr string) ([]string, ...
function getLocalIPPort (line 107) | func getLocalIPPort(dstIP net.IP, srcIP net.IP, proto string) (net.IP, i...
function getLocalIPPortv6 (line 162) | func getLocalIPPortv6(dstIP net.IP, srcIP net.IP, proto string) (net.IP,...
function LocalIPPort (line 210) | func LocalIPPort(dstIP net.IP, srcIP net.IP, proto string) (net.IP, int) {
function LocalIPPortv6 (line 228) | func LocalIPPortv6(dstIP net.IP, srcIP net.IP, proto string) (net.IP, in...
type hostLookupResolver (line 245) | type hostLookupResolver interface
type resolvedIPPrompt (line 249) | type resolvedIPPrompt
function resolverFactory (line 251) | func resolverFactory(dotServer string) hostLookupResolver {
function lookupIPs (line 268) | func lookupIPs(ctx context.Context, resolver hostLookupResolver, host st...
function filterByFamily (line 283) | func filterByFamily(ips []net.IP, ipVersion string) []net.IP {
function resolveFamilyLabel (line 301) | func resolveFamilyLabel(ipVersion string) string {
function promptResolvedIPChoice (line 314) | func promptResolvedIPChoice(ips []net.IP) (int, error) {
function selectResolvedIP (line 332) | func selectResolvedIP(ips []net.IP, disableOutput bool, prompt resolvedI...
function DomainLookUp (line 353) | func DomainLookUp(host string, ipVersion string, dotServer string, disab...
function DomainLookUpWithContext (line 357) | func DomainLookUpWithContext(ctx context.Context, host string, ipVersion...
function GetHostAndPort (line 382) | func GetHostAndPort() (host string, port string) {
function GetProxy (line 408) | func GetProxy() *url.URL {
function GetPowProvider (line 420) | func GetPowProvider() string {
function StringInSlice (line 433) | func StringInSlice(val string, list []string) bool {
function HideIPPart (line 442) | func HideIPPart(ip string) string {
function fold16 (line 457) | func fold16(sum uint32) uint16 {
function addBytes (line 467) | func addBytes(sum uint32, data []byte) uint32 {
function UDPBaseSum (line 482) | func UDPBaseSum(srcIP, dstIP net.IP, srcPort, dstPort, udpLen int, paylo...
function FudgeWordForSeq (line 514) | func FudgeWordForSeq(S0, targetChecksum uint16) uint16 {
function MakePayloadWithTargetChecksum (line 522) | func MakePayloadWithTargetChecksum(payload []byte, srcIP, dstIP net.IP, ...
FILE: util/util_test.go
function TestIsIPv6_True (line 17) | func TestIsIPv6_True(t *testing.T) {
function TestIsIPv6_False (line 23) | func TestIsIPv6_False(t *testing.T) {
function TestAddrIP_IPAddr (line 31) | func TestAddrIP_IPAddr(t *testing.T) {
function TestAddrIP_TCPAddr (line 37) | func TestAddrIP_TCPAddr(t *testing.T) {
function TestAddrIP_UDPAddr (line 43) | func TestAddrIP_UDPAddr(t *testing.T) {
function TestAddrIP_UnixAddr (line 49) | func TestAddrIP_UnixAddr(t *testing.T) {
function TestAddrIP_Nil (line 54) | func TestAddrIP_Nil(t *testing.T) {
function TestStringInSlice_Found (line 61) | func TestStringInSlice_Found(t *testing.T) {
function TestStringInSlice_NotFound (line 65) | func TestStringInSlice_NotFound(t *testing.T) {
function TestStringInSlice_EmptySlice (line 69) | func TestStringInSlice_EmptySlice(t *testing.T) {
function TestHideIPPart_IPv4 (line 75) | func TestHideIPPart_IPv4(t *testing.T) {
function TestHideIPPart_IPv6 (line 79) | func TestHideIPPart_IPv6(t *testing.T) {
function TestHideIPPart_Invalid (line 84) | func TestHideIPPart_Invalid(t *testing.T) {
function TestUDPBaseSum_IPv4_KnownValue (line 90) | func TestUDPBaseSum_IPv4_KnownValue(t *testing.T) {
function TestUDPBaseSum_IPv6_NonZero (line 100) | func TestUDPBaseSum_IPv6_NonZero(t *testing.T) {
function TestFudgeWordForSeq_RoundTrip (line 111) | func TestFudgeWordForSeq_RoundTrip(t *testing.T) {
function TestMakePayloadWithTargetChecksum_RoundTrip (line 128) | func TestMakePayloadWithTargetChecksum_RoundTrip(t *testing.T) {
function TestMakePayloadWithTargetChecksum_TooShort (line 144) | func TestMakePayloadWithTargetChecksum_TooShort(t *testing.T) {
function TestMakePayloadWithTargetChecksum_VersionMismatch (line 153) | func TestMakePayloadWithTargetChecksum_VersionMismatch(t *testing.T) {
type fakeHostLookupResolver (line 162) | type fakeHostLookupResolver struct
method LookupHost (line 167) | func (f fakeHostLookupResolver) LookupHost(context.Context, string) ([...
type fakeHostLookupResolverWithContext (line 174) | type fakeHostLookupResolverWithContext struct
method LookupHost (line 178) | func (f fakeHostLookupResolverWithContext) LookupHost(ctx context.Cont...
type fakeAddrLookupResolver (line 182) | type fakeAddrLookupResolver struct
method LookupAddr (line 186) | func (f fakeAddrLookupResolver) LookupAddr(ctx context.Context, addr s...
function TestLookupIPs_SkipsInvalidValues (line 190) | func TestLookupIPs_SkipsInvalidValues(t *testing.T) {
function TestLookupIPs_ReturnsWrappedError (line 200) | func TestLookupIPs_ReturnsWrappedError(t *testing.T) {
function TestDomainLookUpWithContextReturnsContextCanceled (line 206) | func TestDomainLookUpWithContextReturnsContextCanceled(t *testing.T) {
function TestLookupAddrWithContextUsesCache (line 232) | func TestLookupAddrWithContextUsesCache(t *testing.T) {
function TestLookupAddrWithContextStoresResultInCache (line 250) | func TestLookupAddrWithContextStoresResultInCache(t *testing.T) {
function TestLookupAddrWithContextReturnsContextCanceled (line 270) | func TestLookupAddrWithContextReturnsContextCanceled(t *testing.T) {
function TestFilterByFamily_PicksFirstMatchingAddress (line 295) | func TestFilterByFamily_PicksFirstMatchingAddress(t *testing.T) {
function TestSelectResolvedIP_PromptErrorFallsBackToFirst (line 306) | func TestSelectResolvedIP_PromptErrorFallsBackToFirst(t *testing.T) {
function TestSelectResolvedIP_InvalidIndex (line 315) | func TestSelectResolvedIP_InvalidIndex(t *testing.T) {
function TestResolveFamilyLabel (line 324) | func TestResolveFamilyLabel(t *testing.T) {
function TestGetPowProvider_Default (line 332) | func TestGetPowProvider_Default(t *testing.T) {
function TestGetPowProvider_Sakura (line 342) | func TestGetPowProvider_Sakura(t *testing.T) {
FILE: wshandle/client.go
function formatHostPort (line 23) | func formatHostPort(addr, port string) string {
type wsWriteJob (line 32) | type wsWriteJob struct
constant wsClientWriteQueueSize (line 38) | wsClientWriteQueueSize = 1024
constant wsClientWriteTimeout (line 39) | wsClientWriteTimeout = 5 * time.Second
constant wsClientDialTimeout (line 40) | wsClientDialTimeout = 5 * time.Second
type WsConn (line 43) | type WsConn struct
method getConn (line 64) | func (c *WsConn) getConn() *websocket.Conn {
method setConn (line 70) | func (c *WsConn) setConn(conn *websocket.Conn) {
method getDoneChan (line 76) | func (c *WsConn) getDoneChan() chan struct{} {
method setDoneChan (line 82) | func (c *WsConn) setDoneChan(done chan struct{}) {
method initWriteLoop (line 90) | func (c *WsConn) initWriteLoop() {
method writeLoop (line 97) | func (c *WsConn) writeLoop() {
method enqueueWrite (line 122) | func (c *WsConn) enqueueWrite(job wsWriteJob) error {
method startLoop (line 196) | func (c *WsConn) startLoop(fn func()) {
method isClosed (line 204) | func (c *WsConn) isClosed() bool {
method closeConn (line 226) | func (c *WsConn) closeConn() {
method replaceConn (line 235) | func (c *WsConn) replaceConn(conn *websocket.Conn) {
method Close (line 245) | func (c *WsConn) Close() {
method setConnectionState (line 268) | func (c *WsConn) setConnectionState(connected, connecting bool) {
method setConnected (line 275) | func (c *WsConn) setConnected(v bool) {
method setConnecting (line 281) | func (c *WsConn) setConnecting(v bool) {
method IsConnected (line 287) | func (c *WsConn) IsConnected() bool {
method IsConnecting (line 293) | func (c *WsConn) IsConnecting() bool {
method startReconnecting (line 299) | func (c *WsConn) startReconnecting() bool {
method keepAlive (line 312) | func (c *WsConn) keepAlive() {
method messageReceiveHandler (line 341) | func (c *WsConn) messageReceiveHandler() {
method trySendReceiveMessage (line 385) | func (c *WsConn) trySendReceiveMessage(msg string) {
method waitForNextDoneChan (line 394) | func (c *WsConn) waitForNextDoneChan(doneCh chan struct{}) chan struct...
method sendQueuedMessage (line 408) | func (c *WsConn) sendQueuedMessage(msg string) {
method handleInterrupt (line 424) | func (c *WsConn) handleInterrupt(doneCh chan struct{}) {
method messageSendHandler (line 436) | func (c *WsConn) messageSendHandler() {
method recreateWsConn (line 460) | func (c *WsConn) recreateWsConn() {
function newWsConn (line 154) | func newWsConn(conn *websocket.Conn, interrupt chan os.Signal) *WsConn {
function normalizeContext (line 167) | func normalizeContext(ctx context.Context) context.Context {
function deriveOperationContext (line 174) | func deriveOperationContext(parent context.Context, stopCh <-chan struct...
function closeSignalChan (line 216) | func closeSignalChan(ch chan struct{}) {
function apiServerErrorMessage (line 381) | func apiServerErrorMessage(ip string) string {
function createWsConn (line 553) | func createWsConn(ctx context.Context) *WsConn {
function NewWithContext (line 649) | func NewWithContext(ctx context.Context) *WsConn {
function New (line 669) | func New() *WsConn {
function GetWsConn (line 673) | func GetWsConn() *WsConn {
FILE: wshandle/client_test.go
function newStartedTestWsConn (line 13) | func newStartedTestWsConn() *WsConn {
function saveAndRestoreGlobalWsConn (line 22) | func saveAndRestoreGlobalWsConn(t *testing.T) {
function TestWsConnCloseStopsBackgroundLoops (line 40) | func TestWsConnCloseStopsBackgroundLoops(t *testing.T) {
function TestNewClosesPreviousGlobalWsConn (line 60) | func TestNewClosesPreviousGlobalWsConn(t *testing.T) {
function TestGetWsConnDoesNotBlockWhileNewClosesPreviousConn (line 93) | func TestGetWsConnDoesNotBlockWhileNewClosesPreviousConn(t *testing.T) {
function TestSendQueuedMessageDoesNotBlockWhenDisconnectedAndReceiveQueueIsUnavailable (line 154) | func TestSendQueuedMessageDoesNotBlockWhenDisconnectedAndReceiveQueueIsU...
function TestSendQueuedMessageDoesNotBlockWhenEnqueueWriteFails (line 172) | func TestSendQueuedMessageDoesNotBlockWhenEnqueueWriteFails(t *testing.T) {
function TestMessageReceiveHandlerCloseRaceDoesNotPanic (line 195) | func TestMessageReceiveHandlerCloseRaceDoesNotPanic(t *testing.T) {
function TestCreateWsConnHonorsCanceledContextDuringFastIP (line 223) | func TestCreateWsConnHonorsCanceledContextDuringFastIP(t *testing.T) {
function TestRecreateWsConnCloseCancelsFastIP (line 257) | func TestRecreateWsConnCloseCancelsFastIP(t *testing.T) {
Condensed preview — 198 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,285K chars).
[
{
"path": ".cross_compile.sh",
"chars": 6474,
"preview": "#!/usr/bin/env bash\n\nset -Eeuo pipefail\n\n# -------- Config --------\n# Usage: .cross_compile.sh [full|tiny|ntr|all] [debu"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 746,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n---\nname: nexttr"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 595,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
},
{
"path": ".github/dependabot.yml",
"chars": 562,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/workflows/build.yml",
"chars": 13606,
"preview": "name: Build & Release\n\npermissions:\n contents: read\n\ndefaults:\n run:\n shell: bash\n\nconcurrency:\n group: ${{ github"
},
{
"path": ".github/workflows/publishNewFormula.yml",
"chars": 1810,
"preview": "name: Publish New Formula\n\nconcurrency:\n group: ${{ github.workflow }}-${{ github.ref }}\n cancel-in-progress: true\n\n# "
},
{
"path": ".github/workflows/test.yml",
"chars": 1411,
"preview": "name: Test\n\npermissions:\n contents: read\n\nconcurrency:\n group: ${{ github.workflow }}-${{ github.event.pull_request.nu"
},
{
"path": ".github/workflows/triggerDebRepo.yml",
"chars": 682,
"preview": "name: Trigger Deb Repo\n\npermissions:\n contents: read\n\nconcurrency:\n group: ${{ github.workflow }}-${{ github.event.rel"
},
{
"path": ".gitignore",
"chars": 3006,
"preview": "### VisualStudioCode template\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensi"
},
{
"path": "AGENTS.md",
"chars": 16452,
"preview": "# NTrace-core 项目记忆文件(2026-03 快照,rev-3)\n\n# 供 LLM 在后续会话中快速加载上下文,减少重复分析。\n\n## 项目概览\n\n- 名称:NextTrace (NTrace-core)\n- 仓库:github"
},
{
"path": "CLAUDE.md",
"chars": 33,
"preview": "每次执行命令前均需阅读项目根目录下的 ./AGENTS.md 文件"
},
{
"path": "LICENSE",
"chars": 35149,
"preview": " GNU GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
},
{
"path": "README.md",
"chars": 45274,
"preview": "<div align=\"center\">\n\n<img src=\"assets/logo.png\" height=\"200px\" alt=\"NextTrace Logo\"/>\n\n</div>\n\n<h1 align=\"center\">\n <b"
},
{
"path": "README_zh_CN.md",
"chars": 34566,
"preview": "<div align=\"center\">\n\n<img src=\"assets/logo.png\" height=\"200px\" alt=\"NextTrace Logo\"/>\n\n</div>\n\n<h1 align=\"center\">\n <b"
},
{
"path": "_config.yml",
"chars": 26,
"preview": "theme: jekyll-theme-cayman"
},
{
"path": "assets/windivert/divert.go",
"chars": 1771,
"preview": "package windivert\n\nimport (\n\t\"bytes\"\n\t\"crypto/sha256\"\n\t_ \"embed\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n)\n\n//"
},
{
"path": "cmd/cmd.go",
"chars": 45265,
"preview": "package cmd\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"runtime\"\n\t\"s"
},
{
"path": "cmd/cmd_test.go",
"chars": 10639,
"preview": "package cmd\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/akamensky/argparse\"\n\t\"gith"
},
{
"path": "cmd/deploy_disabled.go",
"chars": 211,
"preview": "//go:build flavor_tiny || flavor_ntr\n\npackage cmd\n\nimport \"fmt\"\n\nfunc runDeploy(_ string) error {\n\treturn fmt.Errorf(\"We"
},
{
"path": "cmd/deploy_full.go",
"chars": 181,
"preview": "//go:build !flavor_tiny && !flavor_ntr\n\npackage cmd\n\nimport (\n\t\"github.com/nxtrace/NTrace-core/server\"\n)\n\nfunc runDeploy"
},
{
"path": "cmd/flavor_full.go",
"chars": 221,
"preview": "//go:build !flavor_tiny && !flavor_ntr\n\npackage cmd\n\nconst (\n\tappBinName = \"nexttrace\"\n\tenableWebUI = true\n\te"
},
{
"path": "cmd/flavor_ntr.go",
"chars": 200,
"preview": "//go:build flavor_ntr\n\npackage cmd\n\nconst (\n\tappBinName = \"ntr\"\n\tenableWebUI = false\n\tenableGlobalping = fals"
},
{
"path": "cmd/flavor_tiny.go",
"chars": 213,
"preview": "//go:build flavor_tiny\n\npackage cmd\n\nconst (\n\tappBinName = \"nexttrace-tiny\"\n\tenableWebUI = false\n\tenableGloba"
},
{
"path": "cmd/globalping_disabled.go",
"chars": 326,
"preview": "//go:build flavor_tiny || flavor_ntr\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/nxtrace/NTrace-core/trace\"\n)\n\nfun"
},
{
"path": "cmd/globalping_full.go",
"chars": 1975,
"preview": "//go:build !flavor_tiny && !flavor_ntr\n\npackage cmd\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.co"
},
{
"path": "cmd/listen_info_test.go",
"chars": 870,
"preview": "package cmd\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestIsDigitsOnly(t *testing.T"
},
{
"path": "cmd/mtr_mode.go",
"chars": 6947,
"preview": "package cmd\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/n"
},
{
"path": "cmd/mtr_mode_test.go",
"chars": 24985,
"preview": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"os\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace"
},
{
"path": "cmd/mtr_ui.go",
"chars": 9639,
"preview": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"sync/atomic\"\n\n\t\"golang.org/x/term\"\n)\n\n// -------------------------"
},
{
"path": "cmd/mtu_mode.go",
"chars": 9799,
"preview": "package cmd\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"time\"\n\n\t"
},
{
"path": "cmd/mtu_mode_test.go",
"chars": 7537,
"preview": "package cmd\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/fatih/color\"\n\n\t\"github.com/nxtrace/N"
},
{
"path": "config/basic.go",
"chars": 82,
"preview": "package config\n\nvar Version = \"v0.0.0.alpha\"\nvar BuildDate = \"\"\nvar CommitID = \"\"\n"
},
{
"path": "config/viper.go",
"chars": 1818,
"preview": "package config\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\n\t\"github.com/spf13/viper\"\n)\n\nfunc InitConfi"
},
{
"path": "dn42/dn42.go",
"chars": 89,
"preview": "package dn42\n\n/***\n\t[DN42 Package]\n\t\t谨献给 DN42 所有的小伙伴们,祝你们终有一天能有自己的公网 ASN ~\n\t\tBy Leo\n***/\n"
},
{
"path": "dn42/geofeed.go",
"chars": 1932,
"preview": "package dn42\n\nimport (\n\t\"encoding/csv\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"sort\"\n\n\t\"github.com/spf13/viper\"\n)\n\ntype GeoFeedRow struct "
},
{
"path": "dn42/geofeed_test.go",
"chars": 235,
"preview": "package dn42\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestFindGeoFeedRowInvalidIP(t *testing."
},
{
"path": "dn42/ptr.go",
"chars": 1466,
"preview": "package dn42\n\nimport (\n\t\"encoding/csv\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/spf13/viper\"\n)\n\ntype Pt"
},
{
"path": "dn42/ptr_test.go",
"chars": 1441,
"preview": "package dn42\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\n\t\"github.com/spf13/viper\"\n\t\"github.com/stretchr/testify/assert"
},
{
"path": "fast_trace/basic.go",
"chars": 4885,
"preview": "package fastTrace\n\ntype AllLocationCollection struct {\n\tBeijing BackBoneCollection\n\tShanghai BackBoneCollection\n\tGuan"
},
{
"path": "fast_trace/fast_trace ipv6.go",
"chars": 7146,
"preview": "package fastTrace\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\n\t\"github.com/fatih/color\"\n\n\t\"github.com/"
},
{
"path": "fast_trace/fast_trace.go",
"chars": 15319,
"preview": "package fastTrace\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"time\"\n\n\t\"gith"
},
{
"path": "fast_trace/fast_trace_test.go",
"chars": 1047,
"preview": "package fastTrace\n\nimport (\n\t\"testing\"\n)\n\nfunc TestTrace(t *testing.T) {\n\t//pFastTrace := ParamsFastTrace{\n\t//\tSrcDev: "
},
{
"path": "geofeed.example.csv",
"chars": 138,
"preview": "154.48.0.0/12,,,,174,COGENT-NET\n200.15.12.0/22,BR,BR-SP,Sao Paulo,2914,NTT-BACKBONE\n2001:0418:1403::/48,US,US-VA,Ashburn"
},
{
"path": "go.mod",
"chars": 2983,
"preview": "module github.com/nxtrace/NTrace-core\n\ngo 1.26.1\n\nrequire (\n\tgithub.com/akamensky/argparse v1.4.0\n\tgithub.com/fatih/colo"
},
{
"path": "go.sum",
"chars": 15744,
"preview": "github.com/akamensky/argparse v1.4.0 h1:YGzvsTqCvbEZhL8zZu2AiA5nq805NZh75JNj4ajn1xc=\ngithub.com/akamensky/argparse v1.4."
},
{
"path": "internal/hoprender/group.go",
"chars": 1050,
"preview": "package hoprender\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/nxtrace/NTrace-core/trace\"\n)\n\ntype Group struct {\n\tIP string\n\tInde"
},
{
"path": "ipgeo/chunzhen.go",
"chars": 1818,
"preview": "package ipgeo\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace"
},
{
"path": "ipgeo/dn42.go",
"chars": 6071,
"preview": "package ipgeo\n\nimport (\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/dn42\"\n)\n\nfunc LtdCodeToCountryOrAreaName(Co"
},
{
"path": "ipgeo/dn42_test.go",
"chars": 2330,
"preview": "package ipgeo\n\nimport (\n\t\"os\"\n\t\"path/filepath\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/spf13/viper\"\n\t\"github.com/stretchr/testi"
},
{
"path": "ipgeo/ipapicom.go",
"chars": 1807,
"preview": "package ipgeo\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjs"
},
{
"path": "ipgeo/ipdbone.go",
"chars": 7086,
"preview": "package ipgeo\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjson\"\n\n\t\"gi"
},
{
"path": "ipgeo/ipfilter.go",
"chars": 2992,
"preview": "package ipgeo\n\nimport (\n\t\"net\"\n)\n\ntype cidrFilterRule struct {\n\tcidr string\n\twhois string\n}\n\nvar reservedCIDRRules = []"
},
{
"path": "ipgeo/ipfilter_test.go",
"chars": 3595,
"preview": "package ipgeo\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testify/require\"\n)\n\n// ─"
},
{
"path": "ipgeo/ipgeo.go",
"chars": 2068,
"preview": "package ipgeo\n\nimport (\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/util\"\n)\n\ntype IPGeoData struct {\n\tIP "
},
{
"path": "ipgeo/ipgeo_test.go",
"chars": 1346,
"preview": "package ipgeo\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testi"
},
{
"path": "ipgeo/ipinfo.go",
"chars": 7436,
"preview": "package ipgeo\n\nimport (\n\t\"io\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjson\"\n\n\t\"github.com/nxtrace/NTrace-co"
},
{
"path": "ipgeo/ipinfoLocal.go",
"chars": 2971,
"preview": "package ipgeo\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/oschw"
},
{
"path": "ipgeo/ipinsight.go",
"chars": 685,
"preview": "package ipgeo\n\nimport (\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjson\"\n\n\t\"github.com/nxtrace/NTrace-core/util\"\n)\n\nfunc IPInS"
},
{
"path": "ipgeo/ipsb.go",
"chars": 1295,
"preview": "package ipgeo\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjson\"\n\n\t\"github.com/nxtrace/NTrac"
},
{
"path": "ipgeo/leo.go",
"chars": 3357,
"preview": "package ipgeo\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"strconv\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/tidwall/gjson\"\n\n\t\"github.com"
},
{
"path": "ipgeo/tokens.go",
"chars": 515,
"preview": "package ipgeo\n\nimport \"github.com/nxtrace/NTrace-core/util\"\n\ntype tokenData struct {\n\tipinsight string\n\tipinfo string"
},
{
"path": "ipgeo/tokens_test.go",
"chars": 454,
"preview": "package ipgeo\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestBaseOrDefault_Empty(t *testing.T) "
},
{
"path": "main.go",
"chars": 95,
"preview": "package main\n\nimport (\n\t\"github.com/nxtrace/NTrace-core/cmd\"\n)\n\nfunc main() {\n\tcmd.Execute()\n}\n"
},
{
"path": "nt_config.yaml",
"chars": 46,
"preview": "geofeedpath: ./geofeed.csv\nptrpath: ./ptr.csv\n"
},
{
"path": "nt_install.sh",
"chars": 3188,
"preview": "#!/bin/bash\n\nif [ \"$1\" = \"http\" ]; then\n protocol=\"http\"\nelse\n protocol=\"https\"\nfi\n\n\nGreen_font=\"\\033[32m\"\nYellow_"
},
{
"path": "pow/pow.go",
"chars": 2092,
"preview": "package pow\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"time\"\n\n\t\"github.com/tsosunchia/powclient\"\n\n\t\"github.com/nxtrace/NTr"
},
{
"path": "pow/pow_test.go",
"chars": 2363,
"preview": "package pow\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"git"
},
{
"path": "printer/basic.go",
"chars": 3844,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/fatih/color\"\n\n\t\"github.com/nxtrace/NTrace-core/config\"\n"
},
{
"path": "printer/classic_printer.go",
"chars": 2827,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/nxtrace/NTrace-core/trace\"\n)\n\ntype HopInfo int\n\nconst (\n\tGener"
},
{
"path": "printer/easy.go",
"chars": 875,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n\t\"github.com/nxtrace/NTrace-core/trace\"\n)\n\nfun"
},
{
"path": "printer/mtr_raw.go",
"chars": 1298,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/nxtrace/NTrace-core/trace\"\n)\n\n// FormatMTRRawLine formats one "
},
{
"path": "printer/mtr_table.go",
"chars": 16004,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/mattn/go-runewidth\"\n\t\""
},
{
"path": "printer/mtr_table_test.go",
"chars": 62883,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/nxtra"
},
{
"path": "printer/mtr_tui.go",
"chars": 21548,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/mattn/go-runewidth\"\n\t\"golang.org/x/term\"\n\n"
},
{
"path": "printer/mtr_tui_color.go",
"chars": 1436,
"preview": "package printer\n\nimport (\n\t\"strings\"\n\n\t\"github.com/fatih/color\"\n)\n\nvar (\n\tmtrTUITitleColor = color.New(color.FgHiWhite)"
},
{
"path": "printer/printer.go",
"chars": 2626,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n\t\"github.com/nxtrace/NTrace-core/tr"
},
{
"path": "printer/printer_test.go",
"chars": 2205,
"preview": "package printer\n\n// func TestPrintTraceRouteNav(t *testing.T) {\n// \tPrintTraceRouteNav(util.DomainLookUp(\"1.1.1.1\", fals"
},
{
"path": "printer/realtime_common.go",
"chars": 5108,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/fatih/color\"\n\n\t\"github.com/nxtrace/NTrace-core/internal"
},
{
"path": "printer/realtime_printer.go",
"chars": 448,
"preview": "package printer\n\nimport (\n\t\"github.com/nxtrace/NTrace-core/internal/hoprender\"\n\t\"github.com/nxtrace/NTrace-core/trace\"\n)"
},
{
"path": "printer/realtime_printer_router.go",
"chars": 1637,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/fatih/color\"\n\n\t\"github.com/nxtrace/NTrace-core/internal/hoprender\"\n\t\"gith"
},
{
"path": "printer/tableprinter.go",
"chars": 2798,
"preview": "package printer\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/fatih/color\"\n\t\"github.com/rodaine/table\"\n\n\t\"github"
},
{
"path": "printer/tableprinter_test.go",
"chars": 1568,
"preview": "package printer\n\nimport (\n\t\"bytes\"\n\t\"net\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/fatih/color\"\n\n\t\"github.com/nxtrace"
},
{
"path": "ptr.example.csv",
"chars": 97,
"preview": "snge,SG,,Singapore\nCXS,CN,Hunan,Changsha\nLAX,US,California,Los Angeles\nSJC,US,California,San Jose"
},
{
"path": "reporter/reporter.go",
"chars": 4555,
"preview": "package reporter\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n\t\"github.com/nxtrac"
},
{
"path": "reporter/reporter_test.go",
"chars": 3685,
"preview": "package reporter\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/i"
},
{
"path": "server/browser_access.go",
"chars": 1162,
"preview": "package server\n\nimport (\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/nxtrace/NTrace-cor"
},
{
"path": "server/browser_access_test.go",
"chars": 2574,
"preview": "package server\n\nimport (\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"testing\"\n\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/nxtrace/"
},
{
"path": "server/cache_handler.go",
"chars": 216,
"preview": "package server\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/nxtrace/NTrace-core/trace\"\n)\n\nfunc cache"
},
{
"path": "server/handlers.go",
"chars": 834,
"preview": "package server\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\nvar (\n\tsupportedProtocols = []string{\"icmp\", \"udp\","
},
{
"path": "server/mtr.go",
"chars": 8474,
"preview": "package server\n\nimport (\n\t\"math\"\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n\t\"github.co"
},
{
"path": "server/server.go",
"chars": 1888,
"preview": "package server\n\nimport (\n\t\"context\"\n\t\"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"net/http\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"sysca"
},
{
"path": "server/trace_handler.go",
"chars": 19773,
"preview": "package server\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"runtime\"\n\t\""
},
{
"path": "server/trace_handler_test.go",
"chars": 9635,
"preview": "package server\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"g"
},
{
"path": "server/web/assets/app.js",
"chars": 41037,
"preview": "const form = document.getElementById('trace-form');\nconst protocolSelect = document.getElementById('protocol');\nconst pr"
},
{
"path": "server/web/assets/mtr_agg.js",
"chars": 4645,
"preview": "(function(root, factory) {\n const api = factory();\n if (typeof module !== 'undefined' && module.exports) {\n module."
},
{
"path": "server/web/assets/mtr_agg.test.cjs",
"chars": 1481,
"preview": "const test = require('node:test');\nconst assert = require('node:assert/strict');\n\nconst { normalizeRenderableMTRStats } "
},
{
"path": "server/web/assets/mtr_truncation.test.cjs",
"chars": 6668,
"preview": "/**\n * Tests for the mtrRawKnownFinalTTL truncation logic in app.js.\n *\n * Since ingestMTRRawRecord lives inside app.js "
},
{
"path": "server/web/assets/style.css",
"chars": 8694,
"preview": "*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFo"
},
{
"path": "server/web/assets/trace_form.js",
"chars": 2003,
"preview": "(function (root, factory) {\n const api = factory();\n if (typeof module !== 'undefined' && module.exports) {\n module"
},
{
"path": "server/web/assets/trace_form.test.cjs",
"chars": 1581,
"preview": "const test = require('node:test');\nconst assert = require('node:assert/strict');\n\nconst { buildTracePayload, defaultOpti"
},
{
"path": "server/web/index.html",
"chars": 3980,
"preview": "<!doctype html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"utf-8\">\n <title>NextTrace Web</title>\n <meta name=\"viewpor"
},
{
"path": "server/ws_handler.go",
"chars": 12760,
"preview": "package server\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic"
},
{
"path": "server/ws_handler_test.go",
"chars": 6972,
"preview": "package server\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"io\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gorilla/we"
},
{
"path": "trace/cache.go",
"chars": 123,
"preview": "package trace\n\nfunc ClearCaches() {\n\tgeoCache.Range(func(key, value any) bool {\n\t\tgeoCache.Delete(key)\n\t\treturn true\n\t})"
},
{
"path": "trace/globalping.go",
"chars": 7927,
"preview": "//go:build !flavor_tiny && !flavor_ntr\n\npackage trace\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"net/http\"\n\t\"strings\"\n"
},
{
"path": "trace/globalping_test.go",
"chars": 3086,
"preview": "//go:build !flavor_tiny && !flavor_ntr\n\npackage trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/js"
},
{
"path": "trace/globalping_types.go",
"chars": 518,
"preview": "package trace\n\n// GlobalpingOptions configures a Globalping-based traceroute request.\n// Defined in an untagged file so "
},
{
"path": "trace/icmp_ipv4.go",
"chars": 9018,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"sysc"
},
{
"path": "trace/icmp_ipv6.go",
"chars": 9125,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"sysc"
},
{
"path": "trace/internal/icmp_common.go",
"chars": 1987,
"preview": "package internal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/google/gopacket\"\n\t\"golang.org/x/net/ipv"
},
{
"path": "trace/internal/icmp_darwin.go",
"chars": 12525,
"preview": "//go:build darwin\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"os\"\n\t\"sync\"\n\t\"syscall\"\n\t\"time\""
},
{
"path": "trace/internal/icmp_decode.go",
"chars": 3632,
"preview": "package internal\n\nimport (\n\t\"net\"\n\n\t\"golang.org/x/net/icmp\"\n\t\"golang.org/x/net/ipv4\"\n\t\"golang.org/x/net/ipv6\"\n\n\t\"github."
},
{
"path": "trace/internal/icmp_decode_test.go",
"chars": 3677,
"preview": "package internal\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n\t\"testing\"\n\n\t\"golang.org/x/net/icmp\"\n\t\"golang.org/x/net/ipv4\"\n\t\"gol"
},
{
"path": "trace/internal/icmp_unix.go",
"chars": 3164,
"preview": "//go:build !darwin && !(windows && amd64)\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\""
},
{
"path": "trace/internal/icmp_windows.go",
"chars": 6562,
"preview": "//go:build windows && amd64\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"git"
},
{
"path": "trace/internal/icmp_windows_test.go",
"chars": 468,
"preview": "//go:build windows && amd64\n\npackage internal\n\nimport (\n\t\"testing\"\n\n\t\"github.com/google/gopacket/layers\"\n)\n\nfunc TestSho"
},
{
"path": "trace/internal/packet_listener.go",
"chars": 1347,
"preview": "package internal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"time\"\n)\n\ntype ReceivedMessage struct {\n\tPeer net.Addr\n\tMsg []b"
},
{
"path": "trace/internal/tcp_common.go",
"chars": 1535,
"preview": "package internal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/util\"\n)\n\nfunc NewTC"
},
{
"path": "trace/internal/tcp_darwin.go",
"chars": 5362,
"preview": "//go:build darwin\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/go"
},
{
"path": "trace/internal/tcp_probe_decode.go",
"chars": 1327,
"preview": "package internal\n\nimport (\n\t\"net\"\n\n\t\"github.com/google/gopacket\"\n\t\"github.com/google/gopacket/layers\"\n)\n\nfunc tcpIPVersi"
},
{
"path": "trace/internal/tcp_probe_decode_test.go",
"chars": 3176,
"preview": "package internal\n\nimport (\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/google/gopacket\"\n\t\"github.com/google/gopacket/layers\"\n)\n\nfunc"
},
{
"path": "trace/internal/tcp_unix.go",
"chars": 4552,
"preview": "//go:build !darwin && !(windows && amd64)\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"sync\"\n"
},
{
"path": "trace/internal/tcp_windows.go",
"chars": 4489,
"preview": "//go:build windows && amd64\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/google/gop"
},
{
"path": "trace/internal/udp_common.go",
"chars": 1504,
"preview": "package internal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/util\"\n)\n\nfunc NewUD"
},
{
"path": "trace/internal/udp_darwin.go",
"chars": 5374,
"preview": "//go:build darwin\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/go"
},
{
"path": "trace/internal/udp_unix.go",
"chars": 4665,
"preview": "//go:build !darwin && !(windows && amd64)\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"sync\"\n"
},
{
"path": "trace/internal/udp_windows.go",
"chars": 3257,
"preview": "//go:build windows && amd64\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/google/gop"
},
{
"path": "trace/internal/windivert_sniff_windows.go",
"chars": 5156,
"preview": "//go:build windows && amd64\n\npackage internal\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/go"
},
{
"path": "trace/mtr_loop_runtime.go",
"chars": 4724,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"time\"\n)\n\ntype mtrLoopRuntime struct {\n\tctx context.Conte"
},
{
"path": "trace/mtr_raw.go",
"chars": 9232,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n\t\"g"
},
{
"path": "trace/mtr_raw_test.go",
"chars": 4866,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n\t\"github.com/nxtra"
},
{
"path": "trace/mtr_runner.go",
"chars": 25516,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/google/"
},
{
"path": "trace/mtr_runner_test.go",
"chars": 26883,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/"
},
{
"path": "trace/mtr_scheduler.go",
"chars": 3286,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n)\n\n// -----------------------"
},
{
"path": "trace/mtr_scheduler_runtime.go",
"chars": 9189,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\ntype mtrSchedulerRuntime struct {\n\tctx "
},
{
"path": "trace/mtr_scheduler_test.go",
"chars": 58688,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtra"
},
{
"path": "trace/mtr_stats.go",
"chars": 5991,
"preview": "package trace\n\nimport (\n\t\"sort\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n)\n\n// ----------------------"
},
{
"path": "trace/mtr_stats_helpers.go",
"chars": 5221,
"preview": "package trace\n\nimport (\n\t\"math\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n)\n\ntype mtrHopGroup "
},
{
"path": "trace/mtr_stats_test.go",
"chars": 19669,
"preview": "package trace\n\nimport (\n\t\"math\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n)\n\nfunc mkHop(ttl int"
},
{
"path": "trace/mtu/decode.go",
"chars": 4833,
"preview": "package mtu\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n\t\"time\"\n\n\t\"golang.org/x/net/icmp\"\n\t\"golang.org/x/net/ipv4\"\n\t\"golang.org/"
},
{
"path": "trace/mtu/decode_test.go",
"chars": 4675,
"preview": "package mtu\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/google/gopacket\"\n\t\"github.com/google/gopacket/l"
},
{
"path": "trace/mtu/metadata.go",
"chars": 4013,
"preview": "package mtu\n\nimport (\n\t\"context\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n\t\"github.com/nxt"
},
{
"path": "trace/mtu/metadata_test.go",
"chars": 5085,
"preview": "package mtu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n)\n\nfunc TestEnric"
},
{
"path": "trace/mtu/runner.go",
"chars": 7267,
"preview": "package mtu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/util\"\n)\n\ntype prober interfa"
},
{
"path": "trace/mtu/runner_test.go",
"chars": 14198,
"preview": "package mtu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n)\n\ntype sc"
},
{
"path": "trace/mtu/socket_prober.go",
"chars": 4859,
"preview": "package mtu\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\ttraceinternal \"github.com/nxtrace/NTrace-core/trace/"
},
{
"path": "trace/mtu/socket_prober_read_default.go",
"chars": 414,
"preview": "//go:build !windows\n\npackage mtu\n\nimport (\n\t\"context\"\n\t\"time\"\n)\n\nfunc (p *socketProber) beginICMPResponseCapture(context"
},
{
"path": "trace/mtu/socket_prober_read_windows.go",
"chars": 3513,
"preview": "//go:build windows\n\npackage mtu\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/uti"
},
{
"path": "trace/mtu/socket_prober_test.go",
"chars": 1421,
"preview": "package mtu\n\nimport (\n\t\"net\"\n\t\"testing\"\n)\n\nfunc TestProbeDstPortHandlesZeroToken(t *testing.T) {\n\tif got := probeDstPort"
},
{
"path": "trace/mtu/socketopts_darwin.go",
"chars": 766,
"preview": "//go:build darwin\n\npackage mtu\n\nimport (\n\t\"errors\"\n\t\"net\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc configurePMTUSocket(conn *ne"
},
{
"path": "trace/mtu/socketopts_linux.go",
"chars": 1130,
"preview": "//go:build linux\n\npackage mtu\n\nimport (\n\t\"errors\"\n\t\"net\"\n\n\t\"golang.org/x/sys/unix\"\n)\n\nfunc configurePMTUSocket(conn *net"
},
{
"path": "trace/mtu/socketopts_stub.go",
"chars": 304,
"preview": "//go:build !linux && !darwin && !windows\n\npackage mtu\n\nimport \"net\"\n\nfunc configurePMTUSocket(_ *net.UDPConn, _ int) err"
},
{
"path": "trace/mtu/socketopts_windows.go",
"chars": 1437,
"preview": "//go:build windows\n\npackage mtu\n\nimport (\n\t\"errors\"\n\t\"net\"\n\n\t\"github.com/nxtrace/NTrace-core/util\"\n\t\"golang.org/x/sys/wi"
},
{
"path": "trace/mtu/types.go",
"chars": 2149,
"preview": "package mtu\n\nimport (\n\t\"net\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n)\n\ntype Event string\n\nconst (\n\tEventTimeEx"
},
{
"path": "trace/packet_size.go",
"chars": 2519,
"preview": "package trace\n\nimport (\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\n\t\"github.com/nxtrace/NTrace-core/util\"\n)\n\nconst (\n\tipv4HeaderBytes "
},
{
"path": "trace/packet_size_test.go",
"chars": 3090,
"preview": "package trace\n\nimport (\n\t\"net\"\n\t\"testing\"\n)\n\nfunc TestNormalizePacketSize(t *testing.T) {\n\ttests := []struct {\n\t\tname "
},
{
"path": "trace/quic.go",
"chars": 12221,
"preview": "package trace\n\nimport (\n\t\"math/rand\"\n\t\"time\"\n)\n\n// var Packet = []byte{202, 255, 255, 255, 255, 10, 253, 187, 139, 161, "
},
{
"path": "trace/tcp_ipv4.go",
"chars": 10375,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"sysc"
},
{
"path": "trace/tcp_ipv6.go",
"chars": 10471,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"sysc"
},
{
"path": "trace/tcp_match.go",
"chars": 492,
"preview": "package trace\n\nimport \"time\"\n\nfunc tcpReplyAckForProbe(seq int, payloadSize int) int {\n\treturn int(uint32(seq) + 1 + uin"
},
{
"path": "trace/tcp_match_test.go",
"chars": 573,
"preview": "package trace\n\nimport (\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestLookupTCPSentByAck(t *testing.T) {\n\tstartA := time.Unix(10, 0)\n\ts"
},
{
"path": "trace/temp_printer.go",
"chars": 1607,
"preview": "package trace\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n)\n\nfunc HopPrinter(h Hop) {\n\tif h.Add"
},
{
"path": "trace/trace.go",
"chars": 17362,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"syscall\"\n\t\"tim"
},
{
"path": "trace/trace_runtime_test.go",
"chars": 2845,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/ipgeo\"\n\t\"golang"
},
{
"path": "trace/udp_ipv4.go",
"chars": 11925,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"sysc"
},
{
"path": "trace/udp_ipv6.go",
"chars": 9667,
"preview": "package trace\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"os/signal\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"sysc"
},
{
"path": "tracelog/log.go",
"chars": 3072,
"preview": "package tracelog\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/nxtrace/NTrace-core/inter"
},
{
"path": "tracelog/log_test.go",
"chars": 2867,
"preview": "package tracelog\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtr"
},
{
"path": "tracemap/tracemap.go",
"chars": 2480,
"preview": "package tracemap\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\t\"ti"
},
{
"path": "tracemap/tracemap_test.go",
"chars": 1358,
"preview": "package tracemap\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/nxtrace/NTrace-core/util\"\n)"
},
{
"path": "util/common.go",
"chars": 479,
"preview": "package util\n\nimport \"net\"\n\nfunc Dnspod() *net.Resolver {\n\treturn newDoTResolver(\"dot.pub\", \"dot.pub:853\")\n}\n\nfunc Aliyu"
},
{
"path": "util/dns_resolver.go",
"chars": 4599,
"preview": "package util\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n)\n\n// ──────────────────────────────────────────────────\n// Geo"
},
{
"path": "util/dns_resolver_test.go",
"chars": 6893,
"preview": "package util\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n)\n\n// ── ResolverForDot 映射 ─────────────────────────────\n\nfu"
},
{
"path": "util/dot.go",
"chars": 606,
"preview": "package util\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"net\"\n\t\"time\"\n)\n\nfunc newDoTResolver(serverName string, addrs string) *"
},
{
"path": "util/env.go",
"chars": 1852,
"preview": "package util\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nvar (\n\tDisableMPLS = GetEnvBool(\"NEXTTRACE_DISABLEMPLS\""
},
{
"path": "util/env_test.go",
"chars": 1386,
"preview": "package util\n\nimport (\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n)\n\nfunc TestGetEnvTrimmed(t *testing.T) {\n\tt.Se"
},
{
"path": "util/frag.go",
"chars": 2879,
"preview": "package util\n\nimport (\n\t\"errors\"\n\t\"net\"\n\n\t\"golang.org/x/net/ipv4\"\n)\n\ntype IPv4Fragment struct {\n\tHdr ipv4.Header\n\tBody "
},
{
"path": "util/http_client_geo.go",
"chars": 1314,
"preview": "package util\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n)\n\n// NewGeoHTTPClient 返回一个使用 Geo DNS 解析策略的 *http.Cl"
},
{
"path": "util/http_client_geo_test.go",
"chars": 918,
"preview": "package util\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestNewGeoHTTPClient_ReturnsValidClient(t *testing.T) {\n\tc"
},
{
"path": "util/latency.go",
"chars": 5030,
"preview": "package util\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"git"
},
{
"path": "util/latency_test.go",
"chars": 1211,
"preview": "package util\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestGetFastIPWithContextReturnsCanceled(t "
},
{
"path": "util/pcap.go",
"chars": 2040,
"preview": "//go:build darwin\n\npackage util\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"sync\"\n\n\t\"github.com/google/gopacket/pcap\"\n)\n\nvar (\n\tDevCache s"
},
{
"path": "util/privilege_stub.go",
"chars": 83,
"preview": "//go:build !windows\n\npackage util\n\nfunc HasAdminPrivileges() bool {\n\treturn true\n}\n"
},
{
"path": "util/privilege_windows.go",
"chars": 711,
"preview": "//go:build windows\n\npackage util\n\nimport (\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n)\n\n// HasAdminPrivileges reports wheth"
},
{
"path": "util/trace.go",
"chars": 4254,
"preview": "package util\n\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n)\n\nfunc GetIPHeaderLength(data []byte) (int, error) {\n\tif len(data) "
},
{
"path": "util/trace_privilege.go",
"chars": 80,
"preview": "package util\n\ntype TracePrivilegeCheck struct {\n\tMessage string\n\tFatal bool\n}\n"
},
{
"path": "util/trace_privilege_darwin.go",
"chars": 163,
"preview": "//go:build darwin\n\npackage util\n\n// macOS 上旧逻辑不会因为权限检查阻断执行,这里保持同样语义。\nfunc TracePrivilegeStatus(string, bool) TracePrivil"
},
{
"path": "util/trace_privilege_linux.go",
"chars": 1001,
"preview": "//go:build linux\n\npackage util\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/syndtr/gocapability/capability\"\n)\n\nfunc TracePrivile"
},
{
"path": "util/trace_privilege_stub.go",
"chars": 150,
"preview": "//go:build !linux && !darwin && !windows\n\npackage util\n\nfunc TracePrivilegeStatus(string, bool) TracePrivilegeCheck {\n\tr"
},
{
"path": "util/trace_privilege_windows.go",
"chars": 354,
"preview": "//go:build windows\n\npackage util\n\nfunc TracePrivilegeStatus(_ string, requireWindowsAdmin bool) TracePrivilegeCheck {\n\ti"
},
{
"path": "util/trace_test.go",
"chars": 5435,
"preview": "package util\n\nimport (\n\t\"encoding/binary\"\n\t\"testing\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"github.com/stretchr/testif"
},
{
"path": "util/udp.go",
"chars": 158,
"preview": "package util\n\nimport (\n\t\"net\"\n)\n\nfunc newUDPResolver() *net.Resolver {\n\treturn &net.Resolver{\n\t\t// 指定使用 Go Build-in 的 DN"
},
{
"path": "util/util.go",
"chars": 12560,
"preview": "package util\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"log\"\n\t\"net\"\n\t\"net/url\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"git"
},
{
"path": "util/util_test.go",
"chars": 9986,
"preview": "package util\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/stretchr/testify/assert\"\n\t\"g"
},
{
"path": "wshandle/client.go",
"chars": 14922,
"preview": "package wshandle\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"log\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"os/signal\"\n\t\""
},
{
"path": "wshandle/client_test.go",
"chars": 6483,
"preview": "package wshandle\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"os\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/gorilla/websocket\"\n)\n\nfunc newSta"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the nxtrace/NTrace-core GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 198 files (1.1 MB), approximately 381.8k tokens, and a symbol index with 1907 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.