Minor improvements and documentation

This commit is contained in:
Daniel 2022-08-01 14:11:01 +02:00
parent 549fa1926f
commit ced6690acd
3 changed files with 47 additions and 42 deletions

View file

@ -28,7 +28,7 @@ Lists in the "Hosts" format are not supported.
Please note that the custom filter list is fully loaded into memory. This can have a negative impact on your device if big lists are loaded.` Please note that the custom filter list is fully loaded into memory. This can have a negative impact on your device if big lists are loaded.`
// register a setting for the file path in the ui // Register a setting for the file path in the ui
err := config.Register(&config.Option{ err := config.Register(&config.Option{
Name: "Custom Filter List", Name: "Custom Filter List",
Key: CfgOptionCustomListBlockingKey, Key: CfgOptionCustomListBlockingKey,

View file

@ -37,7 +37,7 @@ func initFilterLists() {
} }
func parseFile(filePath string) error { func parseFile(filePath string) error {
// reset all maps, previous (if any) settings will be lost. // Reset all maps, previous (if any) settings will be lost.
for key := range countryCodesFilterList { for key := range countryCodesFilterList {
delete(countryCodesFilterList, key) delete(countryCodesFilterList, key)
} }
@ -51,12 +51,12 @@ func parseFile(filePath string) error {
delete(domainsFilterList, key) delete(domainsFilterList, key)
} }
// ignore empty file path. // Ignore empty file path.
if filePath == "" { if filePath == "" {
return nil return nil
} }
// open the file if possible // Open the file if possible
file, err := os.Open(filePath) file, err := os.Open(filePath)
if err != nil { if err != nil {
log.Warningf("intel/customlists: failed to parse file %s", err) log.Warningf("intel/customlists: failed to parse file %s", err)
@ -68,18 +68,18 @@ func parseFile(filePath string) error {
var allLinesCount uint64 var allLinesCount uint64
var invalidLinesCount uint64 var invalidLinesCount uint64
// read filter file line by line. // Read filter file line by line.
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
// the scanner will error out if the line is greater than 64K, in this case it is enough. // The scanner will error out if the line is greater than 64K, in this case it is enough.
for scanner.Scan() { for scanner.Scan() {
allLinesCount++ allLinesCount++
// parse and count invalid lines (comment, empty lines, zero IPs...) // Parse and count invalid lines (comment, empty lines, zero IPs...)
if !parseLine(scanner.Text()) { if !parseLine(scanner.Text()) {
invalidLinesCount++ invalidLinesCount++
} }
} }
// check for scanner error. // Check for scanner error.
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
return err return err
} }
@ -88,8 +88,8 @@ func parseFile(filePath string) error {
if invalidLinesRation > rationForInvalidLinesUntilWarning { if invalidLinesRation > rationForInvalidLinesUntilWarning {
log.Warning("intel/customlists: Too many invalid lines") log.Warning("intel/customlists: Too many invalid lines")
module.Warning(zeroIPNotificationID, "Custom filter list has many invalid entries", module.Warning(zeroIPNotificationID, "Custom filter list has many invalid lines",
fmt.Sprintf(`%d out of %d entires are invalid. fmt.Sprintf(`%d out of %d lines are invalid.
Check if you are using the correct file format and if the path to the custom filter list is correct.`, invalidLinesCount, allLinesCount)) Check if you are using the correct file format and if the path to the custom filter list is correct.`, invalidLinesCount, allLinesCount))
} else { } else {
module.Resolve(zeroIPNotificationID) module.Resolve(zeroIPNotificationID)
@ -116,41 +116,34 @@ func parseFile(filePath string) error {
return nil return nil
} }
func parseLine(line string) bool { func parseLine(line string) (valid bool) {
// everything after the first field will be ignored. // Everything after the first field will be ignored.
fields := strings.Fields(line) fields := strings.Fields(line)
// ignore empty lines. // Ignore empty lines.
if len(fields) == 0 { if len(fields) == 0 {
return false return true // Not an entry, but a valid line.
} }
field := fields[0] field := fields[0]
// ignore comments // Ignore comments
if field[0] == '#' { if strings.HasPrefix(field, "#") {
return false return true // Not an entry, but a valid line.
} }
// check if it'a a country code. // Go through all possible field types.
// Parsing is ordered by
// 1. Parsing options (ie. the domain has most variation and goes last.)
// 2. Speed
// Check if it'a a country code.
if isCountryCode(field) { if isCountryCode(field) {
countryCodesFilterList[field] = struct{}{} countryCodesFilterList[field] = struct{}{}
return true return true
} }
// try to parse IP address. // Check if it's a Autonomous system (example AS123).
ip := net.ParseIP(field)
if ip != nil {
// check for zero ip.
if net.IP.Equal(ip, net.IPv4zero) || net.IP.Equal(ip, net.IPv6zero) {
return false
}
ipAddressesFilterList[ip.String()] = struct{}{}
return true
}
// check if it's a Autonomous system (example AS123).
if isAutonomousSystem(field) { if isAutonomousSystem(field) {
asNumber, err := strconv.ParseUint(field[2:], 10, 32) asNumber, err := strconv.ParseUint(field[2:], 10, 32)
if err != nil { if err != nil {
@ -160,7 +153,19 @@ func parseLine(line string) bool {
return true return true
} }
// check if it's a domain. // Try to parse IP address.
ip := net.ParseIP(field)
if ip != nil {
// Check for zero ip.
if net.IP.Equal(ip, net.IPv4zero) || net.IP.Equal(ip, net.IPv6zero) {
return false
}
ipAddressesFilterList[ip.String()] = struct{}{}
return true
}
// Check if it's a domain.
domain := dns.Fqdn(field) domain := dns.Fqdn(field)
if netutils.IsValidFqdn(domain) { if netutils.IsValidFqdn(domain) {
domainsFilterList[domain] = struct{}{} domainsFilterList[domain] = struct{}{}

View file

@ -43,7 +43,7 @@ func init() {
func prep() error { func prep() error {
initFilterLists() initFilterLists()
// register the config in the ui. // Register the config in the ui.
err := registerConfig() err := registerConfig()
if err != nil { if err != nil {
return err return err
@ -53,7 +53,7 @@ func prep() error {
} }
func start() error { func start() error {
// register to hook to update after config change. // Register to hook to update after config change.
if err := module.RegisterEventHook( if err := module.RegisterEventHook(
configModuleName, configModuleName,
configChangeEvent, configChangeEvent,
@ -66,13 +66,13 @@ func start() error {
return err return err
} }
// create parser task and enqueue for execution. "checkAndUpdateFilterList" will schedule the next execution. // Create parser task and enqueue for execution. "checkAndUpdateFilterList" will schedule the next execution.
parserTask = module.NewTask("intel/customlists:file-update-check", func(context.Context, *modules.Task) error { parserTask = module.NewTask("intel/customlists:file-update-check", func(context.Context, *modules.Task) error {
checkAndUpdateFilterList() checkAndUpdateFilterList()
return nil return nil
}).Schedule(time.Now().Add(20 * time.Second)) }).Schedule(time.Now().Add(20 * time.Second))
// register api endpoint for updating the filter list // Register api endpoint for updating the filter list.
if err := api.RegisterEndpoint(api.Endpoint{ if err := api.RegisterEndpoint(api.Endpoint{
Path: "customlists/update", Path: "customlists/update",
Write: api.PermitUser, Write: api.PermitUser,
@ -94,22 +94,22 @@ func checkAndUpdateFilterList() {
filterListLock.Lock() filterListLock.Lock()
defer filterListLock.Unlock() defer filterListLock.Unlock()
// get path and ignore if empty // Get path and ignore if empty
filePath := getFilePath() filePath := getFilePath()
if filePath == "" { if filePath == "" {
return return
} }
// schedule next update check // Schedule next update check
parserTask.Schedule(time.Now().Add(1 * time.Minute)) parserTask.Schedule(time.Now().Add(1 * time.Minute))
// try to get file info // Try to get file info
modifiedTime := time.Now() modifiedTime := time.Now()
if fileInfo, err := os.Stat(filePath); err == nil { if fileInfo, err := os.Stat(filePath); err == nil {
modifiedTime = fileInfo.ModTime() modifiedTime = fileInfo.ModTime()
} }
// check if file path has changed or if modified time has changed // Check if file path has changed or if modified time has changed
if filterListFilePath != filePath || !filterListFileModifiedTime.Equal(modifiedTime) { if filterListFilePath != filePath || !filterListFileModifiedTime.Equal(modifiedTime) {
err := parseFile(filePath) err := parseFile(filePath)
if err != nil { if err != nil {
@ -135,7 +135,7 @@ func LookupDomain(fullDomain string, filterSubdomains bool) (bool, string) {
defer filterListLock.RUnlock() defer filterListLock.RUnlock()
if filterSubdomains { if filterSubdomains {
// check if domain is in the list and all its subdomains. // Check if domain is in the list and all its subdomains.
listOfDomains := splitDomain(fullDomain) listOfDomains := splitDomain(fullDomain)
for _, domain := range listOfDomains { for _, domain := range listOfDomains {
_, ok := domainsFilterList[domain] _, ok := domainsFilterList[domain]
@ -144,7 +144,7 @@ func LookupDomain(fullDomain string, filterSubdomains bool) (bool, string) {
} }
} }
} else { } else {
// check only if the domain is in the list // Check only if the domain is in the list
_, ok := domainsFilterList[fullDomain] _, ok := domainsFilterList[fullDomain]
return ok, fullDomain return ok, fullDomain
} }