Package ready for go get & import usage

This commit is contained in:
Dionysus 2024-12-01 01:32:40 -05:00
parent d6ad25efdb
commit 5853af0490
Signed by: acidvegas
GPG Key ID: EF4B922DB85DC9DE
4 changed files with 80 additions and 64 deletions

View File

@ -19,7 +19,7 @@
## Installation ## Installation
```bash ```bash
go install github.com/acidvegas/golcg go install github.com/acidvegas/golcg/cmd/golcg@latest
``` ```
## Usage ## Usage
@ -91,7 +91,6 @@ Every IPv4 address is fundamentally a 32-bit number. For example, the IP address
192.168.1.1 = (192 × 256³) + (168 × 256²) + (1 × 256¹) + (1 × 256⁰) 192.168.1.1 = (192 × 256³) + (168 × 256²) + (1 × 256¹) + (1 × 256⁰)
= 3232235777 = 3232235777
``` ```
This integer representation allows us to treat IP ranges as simple number sequences. A CIDR block like "192.168.0.0/16" becomes a continuous range of integers: This integer representation allows us to treat IP ranges as simple number sequences. A CIDR block like "192.168.0.0/16" becomes a continuous range of integers:
- Start: 192.168.0.0 → 3232235520 - Start: 192.168.0.0 → 3232235520
- End: 192.168.255.255 → 3232301055 - End: 192.168.255.255 → 3232301055
@ -143,3 +142,4 @@ The sharding system employs an interleaved approach that ensures even distributi
--- ---
###### Mirrors: [acid.vegas](https://git.acid.vegas/golcg) • [SuperNETs](https://git.supernets.org/acidvegas/golcg) • [GitHub](https://github.com/acidvegas/golcg) • [GitLab](https://gitlab.com/acidvegas/golcg) • [Codeberg](https://codeberg.org/acidvegas/golcg) ###### Mirrors: [acid.vegas](https://git.acid.vegas/golcg) • [SuperNETs](https://git.supernets.org/acidvegas/golcg) • [GitHub](https://github.com/acidvegas/golcg) • [GitLab](https://gitlab.com/acidvegas/golcg) • [Codeberg](https://codeberg.org/acidvegas/golcg)

54
cmd/golcg/main.go Normal file
View File

@ -0,0 +1,54 @@
package main
import (
"flag"
"fmt"
"os"
"strconv"
"github.com/acidvegas/golcg"
)
const Version = "1.0.0"
func main() {
cidr := flag.String("cidr", "", "Target IP range in CIDR format")
shardNum := flag.Int("shard-num", 1, "Shard number (1-based)")
totalShards := flag.Int("total-shards", 1, "Total number of shards")
seed := flag.Int("seed", 0, "Random seed for LCG")
stateStr := flag.String("state", "", "Resume from specific LCG state")
version := flag.Bool("version", false, "Show version information")
flag.Parse()
if *version {
fmt.Printf("golcg version %s\n", Version)
os.Exit(0)
}
if *cidr == "" {
fmt.Println("Error: CIDR is required")
flag.Usage()
os.Exit(1)
}
var state *uint32
if *stateStr != "" {
stateVal, err := strconv.ParseUint(*stateStr, 10, 32)
if err != nil {
fmt.Printf("Error parsing state: %v\n", err)
os.Exit(1)
}
stateUint32 := uint32(stateVal)
state = &stateUint32
}
stream, err := golcg.IPStream(*cidr, *shardNum, *totalShards, *seed, state)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
for ip := range stream {
fmt.Println(ip)
}
}

4
go.mod
View File

@ -1,3 +1,3 @@
module golcg module github.com/acidvegas/golcg
go 1.23.2 go 1.21

View File

@ -1,42 +1,40 @@
package main package golcg
import ( import (
"errors" "errors"
"flag"
"fmt" "fmt"
"math/rand" "math/rand"
"net" "net"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"time" "time"
) )
type LCG struct { type LCG struct {
m uint32 M uint32
a uint32 A uint32
c uint32 C uint32
current uint32 Current uint32
} }
func NewLCG(seed int, m uint32) *LCG { func NewLCG(seed int, m uint32) *LCG {
return &LCG{ return &LCG{
m: m, M: m,
a: 1664525, A: 1664525,
c: 1013904223, C: 1013904223,
current: uint32(seed), Current: uint32(seed),
} }
} }
func (l *LCG) Next() uint32 { func (l *LCG) Next() uint32 {
l.current = (l.a*l.current + l.c) % l.m l.Current = (l.A*l.Current + l.C) % l.M
return l.current return l.Current
} }
type IPRange struct { type IPRange struct {
start uint32 Start uint32
total uint32 Total uint32
} }
func NewIPRange(cidr string) (*IPRange, error) { func NewIPRange(cidr string) (*IPRange, error) {
@ -52,17 +50,17 @@ func NewIPRange(cidr string) (*IPRange, error) {
total := broadcast - start + 1 total := broadcast - start + 1
return &IPRange{ return &IPRange{
start: start, Start: start,
total: uint32(total), Total: uint32(total),
}, nil }, nil
} }
func (r *IPRange) GetIPAtIndex(index uint32) (string, error) { func (r *IPRange) GetIPAtIndex(index uint32) (string, error) {
if index >= r.total { if index >= r.Total {
return "", errors.New("IP index out of range") return "", errors.New("IP index out of range")
} }
ip := uint32ToIP(r.start + index) ip := uint32ToIP(r.Start + index)
return ip.String(), nil return ip.String(), nil
} }
@ -102,12 +100,12 @@ func IPStream(cidr string, shardNum, totalShards, seed int, state *uint32) (<-ch
lcg := NewLCG(seed+shardIndex, 1<<32-1) lcg := NewLCG(seed+shardIndex, 1<<32-1)
if state != nil { if state != nil {
lcg.current = *state lcg.Current = *state
} }
shardSize := ipRange.total / uint32(totalShards) shardSize := ipRange.Total / uint32(totalShards)
if uint32(shardIndex) < (ipRange.total % uint32(totalShards)) { if uint32(shardIndex) < (ipRange.Total % uint32(totalShards)) {
shardSize++ shardSize++
} }
@ -117,7 +115,7 @@ func IPStream(cidr string, shardNum, totalShards, seed int, state *uint32) (<-ch
remaining := shardSize remaining := shardSize
for remaining > 0 { for remaining > 0 {
index := lcg.Next() % ipRange.total index := lcg.Next() % ipRange.Total
if totalShards == 1 || index%uint32(totalShards) == uint32(shardIndex) { if totalShards == 1 || index%uint32(totalShards) == uint32(shardIndex) {
ip, err := ipRange.GetIPAtIndex(index) ip, err := ipRange.GetIPAtIndex(index)
if err != nil { if err != nil {
@ -127,7 +125,7 @@ func IPStream(cidr string, shardNum, totalShards, seed int, state *uint32) (<-ch
remaining-- remaining--
if remaining%1000 == 0 { if remaining%1000 == 0 {
SaveState(seed, cidr, shardNum, totalShards, lcg.current) SaveState(seed, cidr, shardNum, totalShards, lcg.Current)
} }
} }
} }
@ -135,39 +133,3 @@ func IPStream(cidr string, shardNum, totalShards, seed int, state *uint32) (<-ch
return out, nil return out, nil
} }
func main() {
cidr := flag.String("cidr", "", "Target IP range in CIDR format")
shardNum := flag.Int("shard-num", 1, "Shard number (1-based)")
totalShards := flag.Int("total-shards", 1, "Total number of shards")
seed := flag.Int("seed", 0, "Random seed for LCG")
stateStr := flag.String("state", "", "Resume from specific LCG state")
flag.Parse()
if *cidr == "" {
fmt.Println("Error: CIDR is required")
flag.Usage()
os.Exit(1)
}
var state *uint32
if *stateStr != "" {
stateVal, err := strconv.ParseUint(*stateStr, 10, 32)
if err != nil {
fmt.Printf("Error parsing state: %v\n", err)
os.Exit(1)
}
stateUint32 := uint32(stateVal)
state = &stateUint32
}
stream, err := IPStream(*cidr, *shardNum, *totalShards, *seed, state)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
for ip := range stream {
fmt.Println(ip)
}
}