161 lines
4.8 KiB
Go
161 lines
4.8 KiB
Go
package parser
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
// TextExtract defines the function signature for extracting IP addresses from a text item.
|
|
type TextExtract interface {
|
|
// Extract extracts an IP address from the given text line.
|
|
Extract(line string) (string, bool)
|
|
}
|
|
|
|
// defaultTextExtract is a default implementation of TextExtract.
|
|
type defaultTextExtract struct {
|
|
// fieldIndexOne is the index of the field that contains the IP address.
|
|
fieldIndexOne uint8
|
|
|
|
// separator is the separator used to split the fields.
|
|
separator string
|
|
}
|
|
|
|
// Extract extracts an IP address from the given text line.
|
|
// It returns the IP address and a boolean indicating whether the IP address was found.
|
|
func (d *defaultTextExtract) Extract(line string) (string, bool) {
|
|
fields := strings.Split(line, d.separator)
|
|
if len(fields) <= int(d.fieldIndexOne) {
|
|
return "", false
|
|
}
|
|
|
|
return fields[d.fieldIndexOne], true
|
|
}
|
|
|
|
// intervalTextExtract is a TextExtract implementation that extracts an IP address range from a text line.
|
|
type intervalTextExtract struct {
|
|
// fieldIndexOne specifies the index of the first field to extract from the split string.
|
|
// From this field, the IP address range will be extracted.
|
|
fieldIndexOne uint8
|
|
|
|
// fieldIndexTwo specifies the index of the second field to extract from the split string.
|
|
// This field will be used as the end of the IP address range.
|
|
fieldIndexTwo uint8
|
|
|
|
// separator specifies the separator used to split the fields.
|
|
separator string
|
|
}
|
|
|
|
// Extract extracts an IP address range from the given text line.
|
|
// It returns the IP address range and a boolean indicating whether the IP address range was found.
|
|
func (d *intervalTextExtract) Extract(line string) (string, bool) {
|
|
fields := strings.Split(line, d.separator)
|
|
if len(fields) <= int(d.fieldIndexOne) || len(fields) <= int(d.fieldIndexTwo) {
|
|
return "", false
|
|
}
|
|
|
|
return fields[d.fieldIndexOne] + "-" + fields[d.fieldIndexTwo], true
|
|
}
|
|
|
|
// cidrTextExtract is a TextExtract implementation that extracts an IP address range from a text line.
|
|
type cidrTextExtract struct {
|
|
// fieldIndexOne is the index of the field that contains the IP address.
|
|
fieldIndexOne uint8
|
|
|
|
// fieldIndexTwo is the index of the field that contains the CIDR prefix length.
|
|
fieldIndexTwo uint8
|
|
|
|
// separator is the separator used to split the fields.
|
|
separator string
|
|
}
|
|
|
|
// Extract extracts an IP address range from the given text line.
|
|
// It returns the IP address range and a boolean indicating whether the IP address range was found.
|
|
func (d *cidrTextExtract) Extract(line string) (string, bool) {
|
|
fields := strings.Split(line, d.separator)
|
|
if len(fields) <= int(d.fieldIndexOne) || len(fields) <= int(d.fieldIndexTwo) {
|
|
return "", false
|
|
}
|
|
return fields[d.fieldIndexOne] + "/" + fields[d.fieldIndexTwo], true
|
|
}
|
|
|
|
// NewDefaultTextExtract creates a new default TextExtract instance.
|
|
func NewDefaultTextExtract(fieldIndexOne uint8, separator string) TextExtract {
|
|
return &defaultTextExtract{
|
|
fieldIndexOne: fieldIndexOne,
|
|
separator: separator,
|
|
}
|
|
}
|
|
|
|
// NewIntervalTextExtract creates a new TextExtract instance that extracts an IP address range.
|
|
func NewIntervalTextExtract(fieldIndexOne uint8, fieldIndexTwo uint8, separator string) TextExtract {
|
|
return &intervalTextExtract{
|
|
fieldIndexOne: fieldIndexOne,
|
|
fieldIndexTwo: fieldIndexTwo,
|
|
separator: separator,
|
|
}
|
|
}
|
|
|
|
// NewCIDRTextExtract creates a new TextExtract instance that extracts an IP address range.
|
|
func NewCIDRTextExtract(fieldIndexOne uint8, fieldIndexTwo uint8, separator string) TextExtract {
|
|
return &cidrTextExtract{
|
|
fieldIndexOne: fieldIndexOne,
|
|
fieldIndexTwo: fieldIndexTwo,
|
|
separator: separator,
|
|
}
|
|
}
|
|
|
|
// textParser is a parser implementation that reads text data from an io.Reader and extracts IP addresses.
|
|
type textParser struct {
|
|
textExtract TextExtract
|
|
}
|
|
|
|
// NewText creates a new TextParser instance.
|
|
func NewText(textExtract TextExtract) (Parser, error) {
|
|
if textExtract == nil || textExtract.Extract == nil {
|
|
return nil, fmt.Errorf("text extract is nil")
|
|
}
|
|
|
|
return &textParser{
|
|
textExtract: textExtract,
|
|
}, nil
|
|
}
|
|
|
|
// Parse reads text data from the given io.Reader and extracts IP addresses.
|
|
func (p *textParser) Parse(body io.Reader, validator IPValidator, limit uint) (IPs, error) {
|
|
scanner := bufio.NewScanner(body)
|
|
|
|
buf := make([]byte, 0, 64*1024)
|
|
scanner.Buffer(buf, 1024*1024)
|
|
|
|
var ips IPs
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if line == "" || strings.HasPrefix(line, ";") || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
|
|
ip, isFound := p.textExtract.Extract(line)
|
|
if !isFound {
|
|
continue
|
|
}
|
|
|
|
ip = strings.TrimSpace(ip)
|
|
if !validator.IsValid(ip) {
|
|
continue
|
|
}
|
|
|
|
ips = append(ips, ip)
|
|
if limit > 0 && uint(len(ips)) >= limit {
|
|
break
|
|
}
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
return nil, fmt.Errorf("read response: %w", err)
|
|
}
|
|
|
|
return ips, nil
|
|
}
|