# How loyalsoldier/geoip Defines and Processes Special Categories Like Cloudflare, CloudFront, and Facebook

> Discover how loyalsoldier/geoip defines and processes special categories like Cloudflare and Facebook using IP lists ASN mappings and hard-coded CIDRs for efficient lookups.

- Repository: [Loyalsoldier/geoip](https://github.com/loyalsoldier/geoip)
- Tags: internals
- Published: 2026-03-06

---

**Special categories in loyalsoldier/geoip are defined through three distinct input mechanisms—plain-text IP lists, MaxMind ASN mappings, and hard-coded private CIDRs—and processed as generic `lib.Entry` instances that the lookup plugin resolves by iterating over all stored prefixes.**

The loyalsoldier/geoip repository aggregates IP ranges for major internet services into categorized datasets. Understanding how special categories like **cloudflare**, **cloudfront**, and **facebook** are defined and processed internally requires examining the input plugin architecture and the container lookup implementation.

## How Special Categories Are Defined

The repository categorizes IP ranges using three input strategies defined in [`config.json`](https://github.com/loyalsoldier/geoip/blob/main/config.json) and specialized plugins.

### Plain-Text IP Lists via the Text Input Plugin

Categories like **cloudflare**, **cloudfront**, **telegram**, **tor**, and **cn** originate from plain-text CIDR lists. In [`config.json`](https://github.com/loyalsoldier/geoip/blob/main/config.json), these use the `"text"` input type referencing remote or local files:

```json
{
  "type": "text",
  "action": "add",
  "args": {
    "name": "cloudflare",
    "uri": "https://www.cloudflare.com/ips-v4"
  }
},
{
  "type": "text",
  "action": "add",
  "args": {
    "name": "cloudflare",
    "uri": "https://www.cloudflare.com/ips-v6"
  }
}

```

The [`plugin/plaintext/text_in.go`](https://github.com/loyalsoldier/geoip/blob/main/plugin/plaintext/text_in.go) converter reads the URI, creates a `lib.Entry` named `"cloudflare"`, and populates it via `Entry.AddPrefix` for each CIDR block.

### ASN-Based Mappings via MaxMind GeoLite2 ASN CSV

Categories like **facebook**, **google**, **fastly**, **netflix**, and **twitter** derive from Autonomous System Number (ASN) mappings. The [`config.json`](https://github.com/loyalsoldier/geoip/blob/main/config.json) defines a `wantedList` (lines 123-174) mapping category names to AS numbers:

```json
"wantedList": {
  "cloudflare": [ "AS395747", "AS394536" ],
  "facebook": [ "AS63293", "AS54115", "AS32934" ]
}

```

The [`plugin/maxmind/maxmind_asn_csv_in.go`](https://github.com/loyalsoldier/geoip/blob/main/plugin/maxmind/maxmind_asn_csv_in.go) parser processes the MaxMind CSV, extracts prefixes for the listed AS numbers, and creates entries named after the map keys.

### Hard-Coded Private CIDRs via the Special Plugin

The **private** category is built-in. The [`plugin/special/private.go`](https://github.com/loyalsoldier/geoip/blob/main/plugin/special/private.go) file contains a hard-coded slice (lines 15-37):

```go
var privateCIDRs = []string{
    "0.0.0.0/8", "10.0.0.0/8", "127.0.0.0/8",
    "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24",
    "192.0.2.0/24", "192.88.99.0/24", "192.168.0.0/16",
    "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24",
    "224.0.0.0/4", "240.0.0.0/4", "255.255.255.255/32",
    "::/128", "::1/128", "64:ff9b::/96", "fc00::/7"
}

```

When [`config.json`](https://github.com/loyalsoldier/geoip/blob/main/config.json) specifies `{ "type": "private", "action": "add" }`, the plugin creates an entry named `"PRIVATE"` and inserts all CIDRs from this slice.

## Container Storage and Entry Management

All categories are stored as instances of `lib.Entry`. After parsing, input plugins invoke:

```go
container.Add(entry, ignoreIPType)

```

This method, implemented in [`lib/container.go`](https://github.com/loyalsoldier/geoip/blob/main/lib/container.go) (lines 63-111), merges the entry into a global map keyed by the upper-cased entry name (e.g., `"CLOUDFLARE"`). Each entry maintains separate IPv4 and IPv6 prefix sets accessible via `GetIPv4Set()` and `GetIPv6Set()`.

## Runtime Category Resolution via the Lookup Plugin

The [`plugin/special/lookup.go`](https://github.com/loyalsoldier/geoip/blob/main/plugin/special/lookup.go) plugin resolves IP addresses to category names. When executing a lookup:

```go
lists, found, _ := container.Lookup(l.Search, l.SearchList...)

```

The `Container.Lookup` method in [`lib/container.go`](https://github.com/loyalsoldier/geoip/blob/main/lib/container.go) (lines 195-226) parses the target IP and iterates over all entries:

```go
for entry := range c.Loop() {
    if len(searchMap) > 0 && !searchMap[entry.GetName()] {
        continue
    }
    ipset, _ := entry.GetIPv4Set()
    if ipset.Contains(addrOrPrefix) {
        isfound = true
        result = append(result, entry.GetName())
    }
}

```

Key behaviors:

- **Entry names are the category names.** Matching prefixes return the entry's name (e.g., `"CLOUDFLARE"`).
- **Optional filtering.** If `searchList` is provided (e.g., `["CLOUDFLARE","FACEBOOK"]`), only those entries are checked against the `searchMap`.
- **Sorted output.** Results are sorted alphabetically and returned as lower-case comma-separated strings.

## Practical Lookup Examples

To query which categories contain a specific IP:

```bash

# Build and lookup a single IP

./geoip lookup --search 1.1.1.1

# Output: cloudflare

```

To filter results to specific categories:

```bash
./geoip lookup --search 1.1.1.1 --searchList cloudflare,facebook

# Output: cloudflare

```

Under the hood, the lookup iterates through the container entries, checks if `1.1.1.1` falls within the Cloudflare prefix set loaded from the text input, and returns the matching category name.

## Summary

- **Three definition methods** populate special categories: plain-text IP lists for CDNs and anonymity networks, ASN mappings for major tech companies, and hard-coded constants for private ranges.
- **Unified storage** occurs in [`lib/container.go`](https://github.com/loyalsoldier/geoip/blob/main/lib/container.go), where entries are keyed by upper-cased names and contain partitioned IPv4/IPv6 prefix sets.
- **Generic resolution** happens in [`plugin/special/lookup.go`](https://github.com/loyalsoldier/geoip/blob/main/plugin/special/lookup.go) by iterating all entries and testing prefix containment, with optional filtering by category name.

## Frequently Asked Questions

### How does loyalsoldier/geoip differentiate between Cloudflare IPs defined via text lists versus ASN mappings?

The repository treats both sources as distinct inputs that converge into a single entry. Text-defined entries (like Cloudflare's official IP lists) and ASN-defined entries (mapping AS numbers to Cloudflare) both create `lib.Entry` instances named `"CLOUDFLARE"`. If both sources are enabled in [`config.json`](https://github.com/loyalsoldier/geoip/blob/main/config.json), the `container.Add` method merges their prefixes under the same entry name. You can verify the source by checking whether both `type: "text"` and `type: "maxmindGeoLite2ASNCSV"` configurations exist for the same name.

### Can I add custom special categories to the geoip repository?

Yes. You can define new categories by adding entries to [`config.json`](https://github.com/loyalsoldier/geoip/blob/main/config.json) using either the `"text"` input type (pointing to a CIDR list URL or local file) or the `"maxmindGeoLite2ASNCSV"` type with a custom `wantedList` mapping your category name to specific AS numbers. The repository processes these through the existing [`plugin/plaintext/text_in.go`](https://github.com/loyalsoldier/geoip/blob/main/plugin/plaintext/text_in.go) or [`plugin/maxmind/maxmind_asn_csv_in.go`](https://github.com/loyalsoldier/geoip/blob/main/plugin/maxmind/maxmind_asn_csv_in.go) pipelines and stores them as standard entries in the container.

### Why is the private category handled by a special plugin instead of a config file?

The **private** category uses hard-coded RFC 1918 and IPv6 private range constants defined directly in [`plugin/special/private.go`](https://github.com/loyalsoldier/geoip/blob/main/plugin/special/private.go). This ensures the private IP ranges are always available and correctly defined without requiring external file dependencies or network requests, making the build reproducible and eliminating external configuration drift for these standardized ranges.

### How does the lookup plugin handle IP addresses that belong to multiple categories?

The `container.Lookup` method iterates over every entry in the container and collects all matching category names into a result slice. If an IP address falls within both a Cloudflare prefix and a Facebook prefix (possible via ASN overlap or custom configuration), both names are returned as a comma-separated list (e.g., `"cloudflare,facebook"`). The results are sorted alphabetically before being printed as lower-case output.