-
Notifications
You must be signed in to change notification settings - Fork 158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tool to grep for ips that overlap #185
Merged
UmanShahzad
merged 31 commits into
master
from
talhahameed/be-2457-cli-tool-to-grep-for-ips-that-overlap
Nov 16, 2023
Merged
Changes from 3 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
6ad098e
init
talhahwahla 1798dd0
Merge branch 'master' into talhahameed/be-2457-cli-tool-to-grep-for-i…
talhahwahla a69c666
improvements
talhahwahla 689c69d
Merge branch 'master' into talhahameed/be-2457-cli-tool-to-grep-for-i…
talhahwahla 64c9135
update matchip help
talhahwahla 4d1e8c9
use --expresssion flag only
talhahwahla 633a31c
rm `parseInput` from `findOverlapping`
talhahwahla e706ece
rm usage of `FilterFile` and `CriteriaFile` flags
talhahwahla 53c0486
rm `scanrdr`, use `ProcessStringsFromStdin`, `ProcessStringsFromFile`
talhahwahla ea0aa85
separate `source_op` and `filter_op`
talhahwahla b8e2243
parse ip
talhahwahla add06f6
add `rangeToCidrs()`
talhahwahla 4e3a3d6
parse cidr, use SubnetPair
talhahwahla 4c9643c
fix filter_op, source_op
talhahwahla 7413b78
export InputHelper for external use
talhahwahla c14f828
accept inline input
talhahwahla 60157bf
fix code repetition
talhahwahla 37cea24
refactor
talhahwahla fd344b9
print help when no arg provided
talhahwahla 0d9102b
handle matchip completions
talhahwahla 511d6dd
fix matchip help
talhahwahla 2ef983c
make `matchip` available as a separate tool
talhahwahla a0bd1a6
make `matchip` available as a separate tool
talhahwahla 43673fc
update help
talhahwahla 132edf1
update README.md
talhahwahla 9404e69
update .gitignore
talhahwahla 2a4f616
update default help
talhahwahla 3e8fb39
update scripts
talhahwahla a7b9e96
fix vsn
talhahwahla 67f4b69
fix spacing
talhahwahla 9744342
Merge branch 'master' into talhahameed/be-2457-cli-tool-to-grep-for-i…
talhahwahla File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/ipinfo/cli/lib" | ||
"github.com/spf13/pflag" | ||
) | ||
|
||
func printHelpMatchIP() { | ||
fmt.Printf( | ||
`Usage: %s matchip --filter <file(s) | stdin> --criteria <file(s) | stdin> | ||
Description: | ||
Prints the overlapping IPs and subnets. | ||
|
||
Examples: | ||
# Match from a file | ||
$ %[1]s matchip --filter /path/to/list1.txt --criteria /path/to/list2.txt | ||
|
||
# Match from multiple files | ||
$ %[1]s matchip --filter=/path/to/list.txt,/path/to/list1.txt --criteria=/path/to/list2.txt,/path/to/list3.txt | ||
|
||
# Match from stdin | ||
$ cat /path/to/list1.txt | %[1]s matchip --filter - --criteria /path/to/list2.txt | ||
|
||
Options: | ||
General: | ||
--filter, -f | ||
IPs, CIDRs, and/or Ranges to be filtered. | ||
--criteria, -c | ||
CIDRs and/or Ranges to check overlap with. | ||
--help | ||
show help. | ||
`, progBase) | ||
} | ||
|
||
func cmdMatchIP() error { | ||
f := lib.CmdMatchIPFlags{} | ||
f.Init() | ||
pflag.Parse() | ||
|
||
return lib.CmdMatchIP(f, pflag.Args()[1:], printHelpMatchIP) | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
package lib | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"net" | ||
"os" | ||
"strings" | ||
|
||
"github.com/spf13/pflag" | ||
) | ||
|
||
type CmdMatchIPFlags struct { | ||
FilterFile []string | ||
CriteriaFile []string | ||
Help bool | ||
} | ||
|
||
func (f *CmdMatchIPFlags) Init() { | ||
pflag.StringSliceVarP( | ||
&f.FilterFile, | ||
"filter", "f", nil, | ||
"IPs, subnets to be filtered.", | ||
) | ||
pflag.StringSliceVarP( | ||
&f.CriteriaFile, | ||
"criteria", "c", nil, | ||
"subnets to check overlap with.", | ||
) | ||
pflag.BoolVarP( | ||
&f.Help, | ||
"help", "", false, | ||
"show help.", | ||
) | ||
} | ||
|
||
func CmdMatchIP( | ||
f CmdMatchIPFlags, | ||
args []string, | ||
printHelp func(), | ||
) error { | ||
if f.Help || f.FilterFile[0] == "" || f.CriteriaFile[0] == "" { | ||
printHelp() | ||
return nil | ||
} | ||
|
||
stat, _ := os.Stdin.Stat() | ||
isStdin := (stat.Mode() & os.ModeCharDevice) == 0 | ||
|
||
scanrdr := func(r io.Reader) ([]string, error) { | ||
var hitEOF bool | ||
buf := bufio.NewReader(r) | ||
var ips []string | ||
|
||
for { | ||
if hitEOF { | ||
return ips, nil | ||
} | ||
|
||
d, err := buf.ReadString('\n') | ||
d = strings.TrimRight(d, "\n") | ||
if err == io.EOF { | ||
if len(d) == 0 { | ||
return ips, nil | ||
} | ||
|
||
hitEOF = true | ||
} else if err != nil { | ||
return ips, err | ||
} | ||
|
||
if len(d) == 0 { | ||
continue | ||
} | ||
|
||
ips = append(ips, d) | ||
} | ||
} | ||
|
||
var filter []string | ||
var err error | ||
if len(f.FilterFile) == 1 && f.FilterFile[0] == "-" && isStdin { | ||
filter, err = scanrdr(os.Stdin) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
for _, file := range f.FilterFile { | ||
f, err := os.Open(file) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
res, err := scanrdr(f) | ||
if err != nil { | ||
return err | ||
} | ||
filter = append(filter, res...) | ||
} | ||
} | ||
|
||
var criteria []string | ||
if len(f.CriteriaFile) == 1 && f.CriteriaFile[0] == "-" && isStdin { | ||
criteria, err = scanrdr(os.Stdin) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
for _, file := range f.CriteriaFile { | ||
f, err := os.Open(file) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
res, err := scanrdr(f) | ||
if err != nil { | ||
return err | ||
} | ||
criteria = append(criteria, res...) | ||
} | ||
} | ||
|
||
matches := findOverlapping(filter, criteria) | ||
for _, v := range matches { | ||
fmt.Println(v) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type SubnetPair struct { | ||
Raw string | ||
Parsed []net.IPNet | ||
} | ||
|
||
func findOverlapping(filter, criteria []string) []string { | ||
parseInput := func(rows []string) ([]SubnetPair, []net.IP) { | ||
parseCIDRs := func(cidrs []string) []net.IPNet { | ||
parsedCIDRs := make([]net.IPNet, 0) | ||
for _, cidrStr := range cidrs { | ||
_, ipNet, err := net.ParseCIDR(cidrStr) | ||
if err != nil { | ||
continue | ||
} | ||
parsedCIDRs = append(parsedCIDRs, *ipNet) | ||
} | ||
|
||
return parsedCIDRs | ||
} | ||
|
||
parsedCIDRs := make([]SubnetPair, 0) | ||
parsedIPs := make([]net.IP, 0) | ||
var separator string | ||
for _, rowStr := range rows { | ||
if strings.ContainsAny(rowStr, ",-") { | ||
if delim := strings.ContainsRune(rowStr, ','); delim { | ||
separator = "," | ||
} else { | ||
separator = "-" | ||
} | ||
|
||
ipRange := strings.Split(rowStr, separator) | ||
if len(ipRange) != 2 { | ||
continue | ||
} | ||
|
||
if strings.ContainsRune(rowStr, ':') { | ||
cidrs, err := CIDRsFromIP6RangeStrRaw(rowStr) | ||
if err == nil { | ||
pair := SubnetPair{ | ||
Raw: rowStr, | ||
Parsed: parseCIDRs(cidrs), | ||
} | ||
parsedCIDRs = append(parsedCIDRs, pair) | ||
} else { | ||
continue | ||
} | ||
} else { | ||
cidrs, err := CIDRsFromIPRangeStrRaw(rowStr) | ||
if err == nil { | ||
pair := SubnetPair{ | ||
Raw: rowStr, | ||
Parsed: parseCIDRs(cidrs), | ||
} | ||
parsedCIDRs = append(parsedCIDRs, pair) | ||
} else { | ||
continue | ||
} | ||
} | ||
} else if strings.ContainsRune(rowStr, '/') { | ||
pair := SubnetPair{ | ||
Raw: rowStr, | ||
Parsed: parseCIDRs([]string{rowStr}), | ||
} | ||
parsedCIDRs = append(parsedCIDRs, pair) | ||
} else { | ||
if ip := net.ParseIP(rowStr); ip != nil { | ||
parsedIPs = append(parsedIPs, ip) | ||
} | ||
} | ||
} | ||
|
||
return parsedCIDRs, parsedIPs | ||
} | ||
|
||
sourceCIDRs, sourceIPs := parseInput(filter) | ||
filterCIDRs, filterIPs := parseInput(criteria) | ||
|
||
var matches []string | ||
for _, sourceCIDR := range sourceCIDRs { | ||
foundMatch := false | ||
for _, v := range sourceCIDR.Parsed { | ||
for _, filterCIDR := range filterCIDRs { | ||
for _, fv := range filterCIDR.Parsed { | ||
if isCIDROverlapping(&v, &fv) { | ||
if !foundMatch { | ||
matches = append(matches, sourceCIDR.Raw) | ||
foundMatch = true | ||
} | ||
break | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
for _, sourceIP := range sourceIPs { | ||
foundMatch := false | ||
for _, filterCIDR := range filterCIDRs { | ||
for _, fv := range filterCIDR.Parsed { | ||
if isIPRangeOverlapping(&sourceIP, &fv) { | ||
if !foundMatch { | ||
matches = append(matches, sourceIP.String()) | ||
foundMatch = true | ||
} | ||
break | ||
} | ||
} | ||
} | ||
|
||
for _, filterIP := range filterIPs { | ||
if sourceIP.String() == filterIP.String() { | ||
matches = append(matches, sourceIP.String()) | ||
break | ||
} | ||
} | ||
} | ||
|
||
return matches | ||
} | ||
|
||
func isCIDROverlapping(cidr1, cidr2 *net.IPNet) bool { | ||
return cidr1.Contains(cidr2.IP) || cidr2.Contains(cidr1.IP) | ||
} | ||
|
||
func isIPRangeOverlapping(ip *net.IP, cidr *net.IPNet) bool { | ||
return cidr.Contains(*ip) | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A more ideal form is one that matches
grep
's solution to this:I.e., use an 'expression' or 'input' flag to label each input, equivalent to the
--filter
flag you currently have. However-f
wouldn't be a great option since it commonly stands forfile
so could cause confusion.-e
/--expression
is whatgrep
uses, so in the spirit of trying to re-use people's habits / knowledge ofgrep
like we did ingrepip
, maybe that's ideal.