spb/internetpressure
Public
TypeScript 36.3%
Python 31.8%
Go 18%
JavaScript 9.8%
Shell 1.9%
SQL 1.4%
CSS 0.5%
1package main23import (4 "context"5 "encoding/json"6 "flag"7 "fmt"8 "io"9 "log/slog"10 "os"11 "time"1213 checkdns "internetpressure.io/probe-agent/internal/checks/dns"14 checkhttp "internetpressure.io/probe-agent/internal/checks/http"15 checkping "internetpressure.io/probe-agent/internal/checks/ping"16 checktrace "internetpressure.io/probe-agent/internal/checks/traceroute"17 "internetpressure.io/probe-agent/internal/client"18 "internetpressure.io/probe-agent/internal/config"19 "internetpressure.io/probe-agent/internal/protocol"20)2122// onceOutput is what `ip-probe once` prints: the batch payload shape without the envelope's probe identity.23type onceOutput struct {24 AgentVersion string `json:"agent_version"`25 Target protocol.Target `json:"target"`26 Capabilities []string `json:"capabilities"`27 Measurements []protocol.Measurement `json:"measurements"`28 Traceroutes []protocol.Traceroute `json:"traceroutes"`29 DurationMs float64 `json:"duration_ms"`30}3132// cmdOnce runs http, dns (every resolver), ping and traceroute once against an ad-hoc target. No server needed.33func cmdOnce(args []string, stdout, stderr io.Writer) int {34 fs := flag.NewFlagSet("once", flag.ContinueOnError)35 fs.SetOutput(stderr)36 target := fs.String("target", "", "hostname to check (required)")37 rawURL := fs.String("url", "", "URL for the http check (default https://<target>/)")38 ip := fs.String("ip", "", "pin the connection to this IP (hostname kept for SNI/Host)")39 port := fs.Int("port", 443, "port for tcp checks")40 noTrace := fs.Bool("no-traceroute", false, "skip traceroute")41 noPing := fs.Bool("no-ping", false, "skip ping")42 path := fs.String("config", "", "config file (optional: resolvers_override is honoured)")43 if err := fs.Parse(args); err != nil {44 return 245 }46 if *target == "" {47 fmt.Fprintln(stderr, "once: --target is required")48 return 249 }50 cfg, err := config.Load(config.ResolvePath(*path), false)51 if err != nil {52 fmt.Fprintf(stderr, "once: %v\n", err)53 return 154 }55 log := newLogger("warn", stderr)56 slog.SetDefault(log)5758 t := protocol.Target{TargetID: "adhoc", Name: *target, Hostname: *target, URL: *rawURL, Port: *port,59 Checks: []string{"http", "dns", "ping"}, Traceroute: !*noTrace, Tier: 1}60 if t.URL == "" {61 t.URL = "https://" + *target + "/"62 }63 if *ip != "" {64 t.IP = ip65 }6667 resolvers := checkdns.DefaultResolvers68 if len(cfg.ResolversOverride) > 0 {69 resolvers = resolvers[:0:0]70 for _, r := range cfg.ResolversOverride {71 if id, addr, err := config.ParseResolver(r); err == nil {72 resolvers = append(resolvers, protocol.Resolver{ID: id, Address: addr})73 }74 }75 }7677 ua := client.UserAgent(version)78 httpC := &checkhttp.Checker{UserAgent: ua}79 dnsC := &checkdns.Checker{}80 pingC := &checkping.Checker{ICMP: checkping.Detect()}81 traceC := checktrace.Detect()82 caps := []string{"http", "dns"}83 if pingC.ICMP {84 caps = append(caps, "ping")85 } else {86 caps = append(caps, "tcp")87 }88 if traceC.Available() {89 caps = append(caps, "traceroute")90 }9192 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)93 defer cancel()94 start := time.Now()95 out := onceOutput{AgentVersion: version, Target: t, Capabilities: caps, Traceroutes: []protocol.Traceroute{}}9697 out.Measurements = append(out.Measurements, httpC.Run(ctx, t))98 out.Measurements = append(out.Measurements, dnsC.Run(ctx, t, resolvers)...)99 if !*noPing {100 out.Measurements = append(out.Measurements, pingC.Run(ctx, t))101 }102 if !*noTrace {103 if traceC.Available() {104 tr, err := traceC.Run(ctx, t)105 if err != nil {106 fmt.Fprintf(stderr, "traceroute: %v\n", err)107 } else {108 out.Traceroutes = append(out.Traceroutes, tr)109 }110 } else {111 fmt.Fprintln(stderr, "traceroute: binary not found, skipped")112 }113 }114 out.DurationMs = protocol.Ms(time.Since(start))115116 enc := json.NewEncoder(stdout)117 enc.SetIndent("", " ")118 if err := enc.Encode(out); err != nil {119 fmt.Fprintf(os.Stderr, "once: %v\n", err)120 return 1121 }122 return 0123}124