SPB Git forge
15commits 1branches 0releases
29.7 MBsize
maindefault branch
10 days agolast push
TypeScript 36.3% Python 31.8% Go 18% JavaScript 9.8% Shell 1.9% SQL 1.4% CSS 0.5%
3.9 KB · 124 lines go
Raw Blame History
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