mirror of
https://github.com/therootcompany/golib.git
synced 2026-11-04 15:05:00 +00:00
IPv4 host + CIDR membership testing backed by sorted /32 binary search and a linear scan of CIDR ranges. CSV/text loader with bounded reads (maxBytes is required so callers pick a limit appropriate to their input source — 1 KB allowlists through 100+ MB threat feeds). Returns errors for unparseable IPs so callers can decide fail-open vs fail-closed; partial cohorts are returned alongside parse errors.
88 lines
1.6 KiB
Go
88 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// isTTYish reports whether f is a terminal (character device).
|
|
func isTTYish(f *os.File) bool {
|
|
fi, err := f.Stat()
|
|
if err != nil {
|
|
return false
|
|
}
|
|
m := os.ModeDevice | os.ModeCharDevice
|
|
return fi.Mode()&m == m
|
|
}
|
|
|
|
// writeTable renders results in the chosen format to stdout.
|
|
func writeTable(format string, results []result) error {
|
|
switch format {
|
|
case formatPretty:
|
|
w := 0
|
|
for _, r := range results {
|
|
if len(r.IP) > w {
|
|
w = len(r.IP)
|
|
}
|
|
}
|
|
for _, r := range results {
|
|
fmt.Printf("%-*s %s\n", w, r.IP, statusLabel(r.Found))
|
|
}
|
|
case formatTSV:
|
|
for _, r := range results {
|
|
fmt.Printf("%s\t%s\n", r.IP, statusLabel(r.Found))
|
|
}
|
|
case formatCSV:
|
|
cw := csv.NewWriter(os.Stdout)
|
|
_ = cw.Write([]string{"ip", "status"})
|
|
for _, r := range results {
|
|
if err := cw.Write([]string{r.IP, statusLabel(r.Found)}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
cw.Flush()
|
|
return cw.Error()
|
|
case formatJSON:
|
|
enc := json.NewEncoder(os.Stdout)
|
|
enc.SetIndent("", " ")
|
|
return enc.Encode(results)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func statusLabel(found bool) string {
|
|
if found {
|
|
return "FOUND"
|
|
}
|
|
return "NOT FOUND"
|
|
}
|
|
|
|
// commafy renders n with thousands separators, e.g. 1234567 -> "1,234,567".
|
|
func commafy(n int) string {
|
|
s := strconv.Itoa(n)
|
|
neg := ""
|
|
if n < 0 {
|
|
neg, s = "-", s[1:]
|
|
}
|
|
if len(s) <= 3 {
|
|
return neg + s
|
|
}
|
|
var b strings.Builder
|
|
head := len(s) % 3
|
|
if head > 0 {
|
|
b.WriteString(s[:head])
|
|
b.WriteByte(',')
|
|
}
|
|
for i := head; i < len(s); i += 3 {
|
|
b.WriteString(s[i : i+3])
|
|
if i+3 < len(s) {
|
|
b.WriteByte(',')
|
|
}
|
|
}
|
|
return neg + b.String()
|
|
}
|