Skip to content

Commit

Permalink
Hexadecimal ranges (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
Al-ex-and-er authored Jan 15, 2021
1 parent 201e79e commit 7f3967a
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 16 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ In addition, at least one of these is required:
* -include-cidr - Include the network in CIDR format
* -include-range - Include the IP range of the network in string format
* -include-integer-range - Include the IP range of the network in integer format
* -include-hex-range - Include the IP range of the network in hexadecimal format

Output
======
Expand All @@ -41,6 +42,11 @@ are string representations of the first and last IP address in the network.
This adds `network_start_integer` and `network_last_integer` columns. These
are integer representations of the first and last IP address in the network.

### Integer Range (-include-hex-range)

This adds `network_start_hex` and `network_last_hex` columns. These
are hexadecimal representations of the first and last IP address in the network.

Copyright and License
=====================

Expand Down
29 changes: 27 additions & 2 deletions convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ type (
// ConvertFile converts the MaxMind GeoIP2 or GeoLite2 CSV file `inputFile` to
// `outputFile` file using a different representation of the network. The
// representation can be specified by setting one or more of `cidr`,
// `ipRange`, or `intRange` to true. If none of these are set to true, it will
// `ipRange`, `intRange` or `hexRange` to true. If none of these are set to true, it will
// strip off the network information.
func ConvertFile( // nolint: golint
inputFile string,
outputFile string,
cidr bool,
ipRange bool,
intRange bool,
hexRange bool,
) error {
outFile, err := os.Create(outputFile)
if err != nil {
Expand All @@ -41,7 +42,7 @@ func ConvertFile( // nolint: golint
}
defer inFile.Close() // nolint: gosec

err = Convert(inFile, outFile, cidr, ipRange, intRange)
err = Convert(inFile, outFile, cidr, ipRange, intRange, hexRange)
if err != nil {
return err
}
Expand All @@ -62,10 +63,16 @@ func Convert(
cidr bool,
ipRange bool,
intRange bool,
hexRange bool,
) error {
makeHeader := func(orig []string) []string { return orig }
makeLine := func(_ *ipaddr.Prefix, orig []string) []string { return orig }

if hexRange {
makeHeader = addHeaderFunc(makeHeader, hexRangeHeader)
makeLine = addLineFunc(makeLine, hexRangeLine)
}

if intRange {
makeHeader = addHeaderFunc(makeHeader, intRangeHeader)
makeLine = addLineFunc(makeLine, intRangeLine)
Expand Down Expand Up @@ -133,6 +140,24 @@ func intRangeLine(network *ipaddr.Prefix, orig []string) []string {
)
}

func hexRangeHeader(orig []string) []string {
return append([]string{"network_start_hex", "network_last_hex"}, orig...)
}

func hexRangeLine(network *ipaddr.Prefix, orig []string) []string {
startInt := new(big.Int)

startInt.SetBytes(canonicalizeIP(network.IP))

endInt := new(big.Int)
endInt.SetBytes(canonicalizeIP(network.Last()))

return append(
[]string{startInt.Text(16), endInt.Text(16)},
orig...,
)
}

func canonicalizeIP(ip net.IP) net.IP {
if v4 := ip.To4(); v4 != nil {
return v4
Expand Down
74 changes: 63 additions & 11 deletions convert/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,31 @@ func TestIntRange(t *testing.T) {
)
}

func TestHexRange(t *testing.T) {
checkHeader(
t,
hexRangeHeader,
[]string{"network_start_hex", "network_last_hex"},
)

checkLine(
t,
hexRangeLine,
"1.1.1.0/24",
[]string{"1010100", "10101ff"},
)

checkLine(
t,
hexRangeLine,
"2001:0db8:85a3:0042::/64",
[]string{
"20010db885a300420000000000000000",
"20010db885a30042ffffffffffffffff",
},
)
}

func checkHeader(
t *testing.T,
makeHeader headerFunc,
Expand Down Expand Up @@ -120,6 +145,7 @@ func TestCIDROutput(t *testing.T) {
true,
false,
false,
false,
[]interface{}{
"network",
"1.0.0.0/24",
Expand All @@ -139,6 +165,7 @@ func TestRangeOutput(t *testing.T) {
false,
true,
false,
false,
[]interface{}{
"network_start_ip,network_last_ip",
"1.0.0.0,1.0.0.255",
Expand All @@ -158,6 +185,7 @@ func TestIntRangeOutput(t *testing.T) {
false,
false,
true,
false,
[]interface{}{
"network_start_integer,network_last_integer",
"16777216,16777471",
Expand All @@ -170,24 +198,46 @@ func TestIntRangeOutput(t *testing.T) {
)
}

func TestHexRangeOutput(t *testing.T) {
checkOutput(
t,
"hex range only",
false,
false,
false,
true,
[]interface{}{
"network_start_hex,network_last_hex",
"1000000,10000ff",
"4458c10,4458c17",
"53dc000,53dc7ff",
"20014220000000000000000000000000,20014220ffffffffffffffffffffffff",
"2402d000000000000000000000000000,2402d000ffffffffffffffffffffffff",
"24064000000000000000000000000000,24064000ffffffffffffffffffffffff",
},
)
}

func TestAllOutput(t *testing.T) {
checkOutput(
t,
"all output options",
true,
true,
true,
true,
[]interface{}{
"network,network_start_ip,network_last_ip,network_start_integer,network_last_integer",
"1.0.0.0/24,1.0.0.0,1.0.0.255,16777216,16777471",
"4.69.140.16/29,4.69.140.16,4.69.140.23,71666704,71666711",
"5.61.192.0/21,5.61.192.0,5.61.199.255,87932928,87934975",
// nolint: lll
"2001:4220::/32,2001:4220::,2001:4220:ffff:ffff:ffff:ffff:ffff:ffff,42541829336310884227257139937291534336,42541829415539046741521477530835484671",
"network,network_start_ip,network_last_ip,network_start_integer,network_last_integer,network_start_hex,network_last_hex",
"1.0.0.0/24,1.0.0.0,1.0.0.255,16777216,16777471,1000000,10000ff",
"4.69.140.16/29,4.69.140.16,4.69.140.23,71666704,71666711,4458c10,4458c17",
"5.61.192.0/21,5.61.192.0,5.61.199.255,87932928,87934975,53dc000,53dc7ff",
// nolint: lll
"2402:d000::/32,2402:d000::,2402:d000:ffff:ffff:ffff:ffff:ffff:ffff,47866811183171600627242296191018336256,47866811262399763141506633784562286591",
"2001:4220::/32,2001:4220::,2001:4220:ffff:ffff:ffff:ffff:ffff:ffff,42541829336310884227257139937291534336,42541829415539046741521477530835484671,20014220000000000000000000000000,20014220ffffffffffffffffffffffff",
// nolint: lll
"2406:4000::/32,2406:4000::,2406:4000:ffff:ffff:ffff:ffff:ffff:ffff,47884659703622814097215369772150030336,47884659782850976611479707365693980671",
"2402:d000::/32,2402:d000::,2402:d000:ffff:ffff:ffff:ffff:ffff:ffff,47866811183171600627242296191018336256,47866811262399763141506633784562286591,2402d000000000000000000000000000,2402d000ffffffffffffffffffffffff",
// nolint: lll
"2406:4000::/32,2406:4000::,2406:4000:ffff:ffff:ffff:ffff:ffff:ffff,47884659703622814097215369772150030336,47884659782850976611479707365693980671,24064000000000000000000000000000,24064000ffffffffffffffffffffffff",
},
)
}
Expand All @@ -198,6 +248,7 @@ func checkOutput(
cidr bool,
ipRange bool,
intRange bool,
hexRange bool,
expected []interface{},
) {
// nolint: lll
Expand All @@ -211,7 +262,7 @@ func checkOutput(
`
var outbuf bytes.Buffer

err := Convert(strings.NewReader(input), &outbuf, cidr, ipRange, intRange)
err := Convert(strings.NewReader(input), &outbuf, cidr, ipRange, intRange, hexRange)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -241,8 +292,9 @@ func TestFileWriting(t *testing.T) {
1.0.0.0/24,"some more"
`

expected := `network,network_start_ip,network_last_ip,network_start_integer,network_last_integer,something
1.0.0.0/24,1.0.0.0,1.0.0.255,16777216,16777471,some more
// nolint: lll
expected := `network,network_start_ip,network_last_ip,network_start_integer,network_last_integer,network_start_hex,network_last_hex,something
1.0.0.0/24,1.0.0.0,1.0.0.255,16777216,16777471,1000000,10000ff,some more
`

inFile, err := ioutil.TempFile("", "input")
Expand All @@ -260,7 +312,7 @@ func TestFileWriting(t *testing.T) {
_, err = inFile.WriteString(input)
require.NoError(t, err)

err = ConvertFile(inFile.Name(), outFile.Name(), true, true, true)
err = ConvertFile(inFile.Name(), outFile.Name(), true, true, true, true)
if err != nil {
t.Fatal(err)
}
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
Expand Down
8 changes: 5 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func main() {
output := flag.String("output-file", "", "The path to the output CSV (REQUIRED)")
ipRange := flag.Bool("include-range", false, "Include the IP range of the network in string format")
intRange := flag.Bool("include-integer-range", false, "Include the IP range of the network in integer format")
hexRange := flag.Bool("include-hex-range", false, "Include the IP range of the network in hexadecimal format")
cidr := flag.Bool("include-cidr", false, "Include the network in CIDR format")

flag.Parse()
Expand All @@ -28,8 +29,9 @@ func main() {
errors = append(errors, "-output-file is required")
}

if !*ipRange && !*intRange && !*cidr {
errors = append(errors, "-include-cidr, -include-range, or -include-integer-range is required")
if !*ipRange && !*intRange && !*cidr && !*hexRange {
errors = append(errors, "-include-cidr, -include-range, -include-integer-range,"+
" or -include-hex-range is required")
}

args := flag.Args()
Expand All @@ -42,7 +44,7 @@ func main() {
os.Exit(1)
}

err := convert.ConvertFile(*input, *output, *cidr, *ipRange, *intRange)
err := convert.ConvertFile(*input, *output, *cidr, *ipRange, *intRange, *hexRange)
if err != nil {
fmt.Fprintf(flag.CommandLine.Output(), "Error: %v\n", err)
os.Exit(1)
Expand Down

0 comments on commit 7f3967a

Please sign in to comment.