libtower

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 15 Imported by: 2

README

libtower

Go Reference Go Report Card

Network health-check primitives for Go — TCP, TLS, HTTP, HTTPS, DNS, ICMP ping, WebSocket, and certificate expiry. Flat package, no sub-packages.

Install

go get github.com/mismatched/libtower

Quick start

package main

import (
    "context"
    "net/url"
    "time"

    "github.com/mismatched/libtower"
)

func main() {
    ctx := context.Background()

    // TCP port check
    u, _ := url.Parse("tcp://example.com:443")
    tcp := &libtower.TCP{URL: u, Timeout: 5 * time.Second}
    ok, _ := tcp.TCPPortCheck(ctx)

    // DNS lookup
    ip, dur, _ := libtower.DNSLookup("example.com")

    // TLS cert check with expiry warning
    hs := &libtower.HTTPS{
        Host:                  "example.com",
        Timeout:               5 * time.Second,
        WarnIfExpiringWithin:  30 * 24 * time.Hour,
    }
    r := hs.Check(ctx)
    if r.Warning != nil {
        println("cert expiring soon:", r.Warning.Error())
    }

    _ = ok
    _ = ip
    _ = dur
}

Checks

Check Type/Function Returns
TCP port TCP.TCPPortCheck(ctx) (bool, error)
TLS port (client cert) TCP.TLSPortCheck(ctx) (bool, error)
HTTP status HTTP.HTTPStatus() error (receiver populated)
HTTP trace (per-phase timing) HTTPTrace.Trace() error (receiver populated)
TLS cert validity HTTPS.HTTPSCheck(ctx) (bool, time.Time, error)
DNS lookup DNSLookup(addr) (*net.IPAddr, time.Duration, error)
Direct DNS query DNSLookupFrom(addr, server) (*net.IPAddr, time.Duration, error)
ICMP ping ⚠️ Ping(addr, seq) (*net.IPAddr, time.Duration, error)
WebSocket WebSocket.WSCheck(ctx) error

⚠️ Ping requires root (or CAP_NET_RAW on Linux).

Composing checks

All types implement Checker, so you can run them uniformly:

checks := []libtower.Checker{
    &libtower.TCP{URL: u, Timeout: time.Second},
    &libtower.HTTPS{Host: "example.com", WarnIfExpiringWithin: 30 * 24 * time.Hour},
    &libtower.DNS{ADDR: "example.com"},
}
for _, c := range checks {
    r := c.Check(ctx)
    if !r.OK { panic(r.Error) }
}

Context variants

Short names (Ping, DNSLookup) use context.Background(). Use the ...Context variants for cancellation:

PingContext(ctx, addr, seq)
DNSLookupContext(ctx, addr)
DNSLookupFromContext(ctx, addr, server)
HTTPStatusContext(ctx)
TraceContext(ctx)

License

MIT

Documentation

Overview

Package libtower provides network health-check primitives for Go.

It covers TCP dials, TLS handshakes (with client certificates), HTTP status checks, per-phase HTTP timing traces, TLS certificate validation with expiry warnings, DNS resolution (both system resolver and direct queries), ICMP ping, and WebSocket connectivity.

Common pattern

Every check follows the same pattern: create a struct, set its input fields, call its method (which records Start, End, and Duration), and read the result. All I/O methods accept a context.Context.

Checker interface

All check types implement the Checker interface, returning a Result:

checks := []Checker{
    &TCP{URL: u, Timeout: time.Second},
    &HTTPS{Host: "example.com", WarnIfExpiringWithin: 30 * 24 * time.Hour},
    &DNS{ADDR: "example.com"},
}
for _, c := range checks {
    r := c.Check(ctx)
    if !r.OK { log.Fatal(r.Error) }
}

Context variants

Short-form functions (Ping, DNSLookup) use context.Background internally. Use the ...Context variants (PingContext, DNSLookupContext) for cancellation and timeouts:

ip, dur, err := libtower.PingContext(ctx, "example.com", 1)

Root requirement

Ping and PingContext require raw ICMP sockets, which need root privileges (or CAP_NET_RAW on Linux). All other checks work without special permissions.

Index

Examples

Constants

View Source
const (
	// ProtocolICMP DSCP
	IPv4ProtocolICMP = 1
	IPv6ProtocolICMP = 58
)
View Source
const DefaultHTTPSPort = "443"

Variables

This section is empty.

Functions

func DNSLookup

func DNSLookup(addr string) (*net.IPAddr, time.Duration, error)

DNSLookup func

Example
package main

import (
	"fmt"

	"github.com/mismatched/libtower"
)

func main() {
	ip, dur, err := libtower.DNSLookup("example.com")
	fmt.Println("ip:", ip, "duration:", dur, "err:", err)
}

func DNSLookupContext

func DNSLookupContext(ctx context.Context, addr string) (*net.IPAddr, time.Duration, error)

DNSLookupContext resolves addr via the default resolver, respecting ctx cancellation.

func DNSLookupFrom

func DNSLookupFrom(addr string, server string) (*net.IPAddr, time.Duration, error)

DNSLookupFrom func

func DNSLookupFromContext

func DNSLookupFromContext(ctx context.Context, addr string, server string) (*net.IPAddr, time.Duration, error)

DNSLookupFromContext performs a direct DNS query to server, respecting ctx cancellation.

func Ping

func Ping(addr string, seq int) (*net.IPAddr, time.Duration, error)

Ping sends an ICMP echo request to addr and returns the resolved address, round-trip time, and any error.

Requires root privileges (or CAP_NET_RAW on Linux) for raw ICMP sockets. Without root, this returns "socket: operation not permitted". Use -tags offline for rootless testing.

Example
package main

import (
	"fmt"

	"github.com/mismatched/libtower"
)

func main() {
	ip, dur, err := libtower.Ping("example.com", 1)
	fmt.Println("ip:", ip, "rtt:", dur, "err:", err)
}

func PingContext

func PingContext(ctx context.Context, addr string, seq int) (*net.IPAddr, time.Duration, error)

PingContext sends an ICMP echo request to addr, respecting ctx cancellation.

Requires root privileges (or CAP_NET_RAW on Linux) for raw ICMP sockets. Without root, this returns "socket: operation not permitted". Use -tags offline for rootless testing.

Types

type CertData

type CertData struct{ NotAfter time.Time }

CertData holds the earliest certificate NotAfter time from a TLS check.

func (CertData) Kind

func (CertData) Kind() string

type CertExpiringWarning

type CertExpiringWarning struct {
	NotAfter  time.Time
	Remaining time.Duration
}

CertExpiringWarning is returned as Result.Warning when a certificate is expiring soon.

func (*CertExpiringWarning) Error

func (w *CertExpiringWarning) Error() string

type CheckData

type CheckData interface {
	// Kind returns a short identifier for the check type.
	Kind() string
}

CheckData is implemented by types carrying check-specific result data.

type Checker

type Checker interface {
	Check(ctx context.Context) Result
}

Checker is implemented by types that can perform a health check.

Example
package main

import (
	"context"
	"fmt"
	"net/url"
	"time"

	"github.com/mismatched/libtower"
)

func main() {
	u, _ := url.Parse("tcp://example.com:443")
	checks := []libtower.Checker{
		&libtower.TCP{URL: u, Timeout: time.Second},
		&libtower.DNS{ADDR: "example.com"},
	}
	for _, c := range checks {
		r := c.Check(context.Background())
		fmt.Printf("%T ok=%v duration=%v\n", c, r.OK, r.Duration)
	}
}

type DNS

type DNS struct {
	ADDR    string
	Timeout time.Duration

	Start    time.Time
	End      time.Time
	Duration time.Duration
}

DNS type

func (*DNS) Check

func (d *DNS) Check(ctx context.Context) Result

Check performs a DNS lookup check.

type DNSData

type DNSData struct{ IP *net.IPAddr }

DNSData holds the resolved IP address from a DNS check.

func (DNSData) Kind

func (DNSData) Kind() string

type HTTP

type HTTP struct {
	URL     string
	Method  string
	Timeout Timeout

	Status           string // e.g. "200 OK"
	StatusCode       int
	Proto            string // e.g. "HTTP/1.0"
	ProtoMajor       int    // e.g. 1
	ProtoMinor       int    // e.g. 0
	Header           map[string][]string
	Body             []byte
	ContentLength    int64
	TransferEncoding []string
	Close            bool
	Uncompressed     bool
	Trailer          map[string][]string

	Time
}

HTTP type

func (*HTTP) Check

func (hsr *HTTP) Check(ctx context.Context) Result

Check performs an HTTP status check.

func (*HTTP) HTTPStatus

func (hsr *HTTP) HTTPStatus() error

HTTPStatus check

func (*HTTP) HTTPStatusContext

func (hsr *HTTP) HTTPStatusContext(ctx context.Context) error

HTTPStatusContext performs an HTTP request, respecting ctx cancellation.

type HTTPS

type HTTPS struct {
	Host    string
	Port    string
	Timeout time.Duration

	InsecureSkipVerify bool

	// WarnIfExpiringWithin, when > 0, triggers a Result.Warning if the
	// earliest certificate NotAfter falls within this window from now.
	WarnIfExpiringWithin time.Duration

	Start    time.Time
	End      time.Time
	Duration time.Duration
}

HTTPS type

func (*HTTPS) Check

func (hs *HTTPS) Check(ctx context.Context) Result

Check performs a TLS certificate check.

Example
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/mismatched/libtower"
)

func main() {
	hs := &libtower.HTTPS{
		Host:                 "example.com",
		Timeout:              5 * time.Second,
		WarnIfExpiringWithin: 30 * 24 * time.Hour,
	}
	r := hs.Check(context.Background())
	fmt.Println("ok:", r.OK)
	if r.Data != nil {
		certData := r.Data.(libtower.CertData)
		fmt.Println("notAfter:", certData.NotAfter.Format(time.RFC3339))
	}
	if r.Warning != nil {
		fmt.Println("warning:", r.Warning)
	}
}

func (*HTTPS) HTTPSCheck

func (hs *HTTPS) HTTPSCheck(ctx context.Context) (bool, time.Time, error)

HTTPSCheck checks tls certificate is valid

type HTTPTrace

type HTTPTrace struct {
	URL                  string
	Method               string
	DNS                  time.Duration
	TLSHandshake         time.Duration
	Connect              time.Duration
	GotFirstResponseByte time.Duration
	Total                time.Duration

	Time
}

HTTPTrace type

func (*HTTPTrace) Check

func (ht *HTTPTrace) Check(ctx context.Context) Result

Check performs an HTTP trace check.

func (*HTTPTrace) Trace

func (ht *HTTPTrace) Trace() error

Trace http

func (*HTTPTrace) TraceContext

func (ht *HTTPTrace) TraceContext(ctx context.Context) error

TraceContext round-trips an HTTP request capturing per-phase latency, respecting ctx cancellation.

type PingCheck

type PingCheck struct {
	Addr string
	Seq  int
}

PingCheck is a struct wrapper that makes the Ping function implement Checker.

func (*PingCheck) Check

func (pc *PingCheck) Check(ctx context.Context) Result

Check sends an ICMP echo request to Addr.

type PingData

type PingData struct{ IP *net.IPAddr }

PingData holds the resolved IP address from a Ping check.

func (PingData) Kind

func (PingData) Kind() string

type Result

type Result struct {
	OK       bool
	Duration time.Duration
	Data     CheckData // check-specific data, nil if none
	Warning  error     // non-nil when the check passed but with a warning (e.g., cert expiring soon)
	Error    error
}

Result is the unified return type for all health checks.

type TCP

type TCP struct {
	URL     *url.URL
	Timeout time.Duration

	CertFile       string
	PrivateKeyFile string

	Start    time.Time
	End      time.Time
	Duration time.Duration
}

TCP type

func (*TCP) Check

func (tr *TCP) Check(ctx context.Context) Result

Check performs a TCP port check.

func (*TCP) TCPPortCheck

func (tr *TCP) TCPPortCheck(ctx context.Context) (bool, error)

TCPPortCheck checks if a tcp port is open

Example
package main

import (
	"context"
	"fmt"
	"net/url"
	"time"

	"github.com/mismatched/libtower"
)

func main() {
	u, _ := url.Parse("tcp://example.com:443")
	tcp := &libtower.TCP{URL: u, Timeout: 5 * time.Second}
	ok, err := tcp.TCPPortCheck(context.Background())
	fmt.Println("ok:", ok, "err:", err)
}

func (*TCP) TLSPortCheck

func (tr *TCP) TLSPortCheck(ctx context.Context) (bool, error)

TLSPortCheck checks if a secured TLS port is open

type Time

type Time struct {
	Start    time.Time
	End      time.Time
	Duration time.Duration
}

Time type

type Timeout

type Timeout time.Duration

Timeout type

type WebSocket

type WebSocket struct {
	URL     string
	Timeout time.Duration

	Start    time.Time
	End      time.Time
	Duration time.Duration
}

WebSocket type

func (*WebSocket) Check

func (ws *WebSocket) Check(ctx context.Context) Result

Check performs a WebSocket health check.

func (*WebSocket) WSCheck

func (ws *WebSocket) WSCheck(ctx context.Context) error

WSCheck performs a WebSocket health check by dialing and verifying the upgrade.

Example
package main

import (
	"context"
	"fmt"
	"time"

	"github.com/mismatched/libtower"
)

func main() {
	ws := &libtower.WebSocket{
		URL:     "ws://echo.example.com",
		Timeout: 5 * time.Second,
	}
	err := ws.WSCheck(context.Background())
	fmt.Println("err:", err)
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL