Skip to content

Instantly share code, notes, and snippets.

@dgl
Last active May 28, 2025 07:53
Show Gist options
  • Save dgl/d017e986ff1099dcfe5fe6c80423f941 to your computer and use it in GitHub Desktop.
Save dgl/d017e986ff1099dcfe5fe6c80423f941 to your computer and use it in GitHub Desktop.
ALPN client (openssh s_client but in Go)
module alpnc
go 1.18
package main
import (
"crypto/tls"
"flag"
"fmt"
"io"
"net"
"os"
"strings"
"time"
)
func main() {
alpn := flag.String("alpn", "", "Comma-separated list of ALPN protocols (e.g., h2,http/1.1)")
serverName := flag.String("servername", "", "Override SNI from address")
verify := flag.Bool("verify", true, "Verify peer?")
debug := flag.Bool("debug", false, "Debug connection?")
flag.Parse()
if flag.NArg() != 1 {
fmt.Fprintf(os.Stderr, "Usage: %s [-alpn protocols] [-servername name] host:port\n", os.Args[0])
os.Exit(1)
}
addr := flag.Arg(0)
host, _, err := net.SplitHostPort(addr)
if err != nil {
fmt.Fprintf(os.Stderr, "Invalid address %q: %v\n", addr, err)
os.Exit(1)
}
if len(*serverName) == 0 {
serverName = &host
}
protos := []string{}
if *alpn != "" {
protos = strings.Split(*alpn, ",")
}
config := &tls.Config{
ServerName: *serverName,
NextProtos: protos,
InsecureSkipVerify: !*verify,
}
conn, err := tls.DialWithDialer(&net.Dialer{Timeout: 1 * time.Minute}, "tcp", addr, config)
if err != nil {
fmt.Fprintf(os.Stderr, "TLS connection failed: %v\n", err)
os.Exit(1)
}
defer conn.Close()
if *debug {
state := conn.ConnectionState()
out := func(s string, args ...any) {
fmt.Fprintf(os.Stderr, s, args...)
}
out("Negotiated Protocol: %s\n", state.NegotiatedProtocol)
out("Server Name: %s\n", state.ServerName)
out("Cipher Suite: 0x%x\n", state.CipherSuite)
// Print certificates
for i, cert := range state.PeerCertificates {
out("Certificate %d:\n", i)
out(" Subject: %s\n", cert.Subject)
out(" Issuer: %s\n", cert.Issuer)
out(" NotBefore: %s\n", cert.NotBefore)
out(" NotAfter: %s\n\n", cert.NotAfter)
}
}
go func() {
io.Copy(conn, os.Stdin)
}()
io.Copy(os.Stdout, conn)
}
@dgl
Copy link
Author

dgl commented May 28, 2025

Get an .exe with: GOOS=windows GOARCH=amd64 go build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment