Skip to content

Random Port Generator — Go source

Generate one or many random TCP/UDP port numbers across registered, ephemeral, or the full range - optionally unique. Runs entirely in your browser with crypto-grade randomness.

This is the Go implementation — the same logic the interactive tool runs, in a shareable, citable form.

// Package randport is the Go twin of CosmoDev's src/lib/random-port.ts (dual
// source: web lib is TypeScript, CLI lib is Go — kept in lock-step). Pure +
// deterministic, never panics. Table-driven tests share vectors with the TS suite.
package randport

import (
	"crypto/rand"
	"encoding/binary"
	"errors"
)

// Range identifies a port range. The zero value Registered matches the TS default.
type Range int

const (
	Registered Range = iota // 1024–49151
	Ephemeral               // 49152–65535
	Any                     // 1–65535
	Custom                  // use Min/Max
)

// Options mirrors PortOptions in random-port.ts. Note: Go has no RNG injection;
// all randomness comes from crypto/rand (the TS twin's default).
type Options struct {
	Range
	Min, Max int // for Custom
}

func bounds(o Options) (int, int, error) {
	switch o.Range {
	case Any:
		return 1, 65535, nil
	case Ephemeral:
		return 49152, 65535, nil
	case Custom:
		if o.Min < 0 || o.Min > 65535 || o.Max > 65535 || o.Min > o.Max {
			return 0, 0, errors.New("invalid port range")
		}
		return o.Min, o.Max, nil
	default: // Registered
		return 1024, 49151, nil
	}
}

// randBelow returns a uniform random int in [0, n).
func randBelow(n int) (int, error) {
	if n <= 0 {
		return 0, errors.New("invalid span")
	}
	var b [8]byte
	if _, err := rand.Read(b[:]); err != nil {
		return 0, err
	}
	return int(binary.LittleEndian.Uint64(b[:]) % uint64(n)), nil
}

// Port returns a single random port. Mirrors randomPort().
func Port(opts Options) (int, error) {
	lo, hi, err := bounds(opts)
	if err != nil {
		return 0, err
	}
	r, err := randBelow(hi - lo + 1)
	if err != nil {
		return 0, err
	}
	return lo + r, nil
}

// Ports returns count ports (optionally unique). Mirrors randomPorts().
func Ports(opts Options, count int, unique bool) ([]int, error) {
	lo, hi, err := bounds(opts)
	if err != nil {
		return nil, err
	}
	span := hi - lo + 1
	if count < 1 {
		count = 1
	}
	if !unique {
		out := make([]int, count)
		for i := range out {
			r, err := randBelow(span)
			if err != nil {
				return nil, err
			}
			out[i] = lo + r
		}
		return out, nil
	}
	n := min(count, span)
	pool := make([]int, span)
	for i := range pool {
		pool[i] = lo + i
	}
	for i := 0; i < n; i++ {
		r, err := randBelow(span - i)
		if err != nil {
			return nil, err
		}
		j := i + r
		pool[i], pool[j] = pool[j], pool[i]
	}
	return pool[:n], nil
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →