# How GeositeUpdater Fetches and Updates the Geosite Database in Shadowsocks-Windows

> Learn how GeositeUpdater fetches and updates the geosite database in Shadowsocks-Windows. It downloads, verifies, caches, and reloads data from v2fly/domain-list-community for efficient routing.

- Repository: [shadowsocks/shadowsocks-windows](https://github.com/shadowsocks/shadowsocks-windows)
- Tags: how-to-guide
- Published: 2026-03-05

---

**The GeositeUpdater service downloads the latest `dlc.dat` binary and its SHA-256 checksum from the v2fly/domain-list-community repository, verifies file integrity against the hash, caches the validated data locally, and reloads the routing tables to regenerate the PAC file.**

The `GeositeUpdater` class in the shadowsocks/shadowsocks-windows client automates the retrieval and maintenance of domain routing data from the community-maintained v2fly/domain-list-community project. This component ensures your local PAC (Proxy Auto-Config) file always contains the latest domain classifications without manual intervention. By implementing cryptographic verification and local caching, the updater balances freshness with performance and security.

## Configuration and Remote Source URLs

The updater relies on two hard-coded constants defined in [`shadowsocks-csharp/Controller/Service/GeositeUpdater.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/shadowsocks-csharp/Controller/Service/GeositeUpdater.cs) at lines 38-39:

- **`GEOSITE_URL`**: Points to the binary `dlc.dat` file containing the GeoSite protobuf database
- **`GEOSITE_SHA256SUM_URL`**: Points to the SHA-256 checksum file used for integrity verification

If you provide custom URLs through the configuration file, the updater substitutes these defaults at runtime during the URL resolution phase (lines 87-94). This allows users to mirror the database internally or use alternative distribution endpoints.

## Local Cache Initialization

When the `GeositeUpdater` class initializes, it attempts to load an existing cache before fetching remote data. The system checks for `dlc.dat` in the temporary folder returned by `Utils.GetTempPath("dlc.dat")`.

If the cached file exists and contains data, the updater loads it into the `geositeDB` byte array (lines 46-49). When no cache exists, the system falls back to the embedded resource `Resources.dlc_dat` and writes it to the temporary location to bootstrap the database (lines 52-54).

After loading the raw bytes, the `LoadGeositeList()` method parses the protobuf using `GeositeList.Parser.ParseFrom` and populates the static dictionary `Geosites` for runtime lookups (lines 63-68).

## The Update Workflow in UpdatePACFromGeosite()

The core logic resides in `UpdatePACFromGeosite()`, which executes the following sequence when triggered by the UI or startup routine:

1. **Resolve URLs**: The method first checks for user-provided override URLs and determines whether SHA-256 verification is enabled (lines 78-97).

2. **Download Checksum**: If verification is enabled, the system fetches the remote SHA-256 hash using `await httpClient.GetStringAsync(geositeSha256sumUrl)` (line 106).

3. **Compare Local Hash**: The updater computes the SHA-256 hash of the cached `geositeDB` using `mySHA256.ComputeHash()` and compares it against the remote checksum. If they match, the process skips downloading to conserve bandwidth (lines 110-118).

4. **Download New Database**: When the hashes differ, the system downloads the fresh database via `await httpClient.GetByteArrayAsync(geositeUrl)` (line 123).

5. **Verify Download**: The updater recomputes the SHA-256 hash of the downloaded bytes and validates against the remote checksum, aborting the operation if the verification fails (lines 126-138).

6. **Persist to Cache**: Valid data overwrites the local `dlc.dat` file in the temporary directory (lines 143-145).

7. **Reload Memory Structures**: The `geositeDB` variable updates with the new bytes, and `LoadGeositeList()` repopulates the in-memory dictionary (lines 147-148).

8. **Regenerate PAC**: The `MergeAndWritePACFile` method rebuilds [`pac.txt`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/pac.txt) using the refreshed domain groups (line 149).

9. **Fire Events**: The system raises `UpdateCompleted` on success (line 150) or `Error` if any exception occurs (lines 152-155).

## Parsing the Protobuf Database

The binary database conforms to the schema defined in `shadowsocks-csharp/Model/Geosite/geosite.proto`. The key protobuf definitions include:

- **`GeositeList`**: A container holding repeated `Geosite` entries
- **`Geosite`**: Contains a `group_name` field and a repeated list of `DomainObject` entries
- **`DomainObject`**: Specifies the domain type, value, and optional attributes

The `GeositeList.Parser.ParseFrom` method (line 63) deserializes the byte array into these C# objects, enabling the PAC generator to iterate over domain groups like "google", "cn", or "geolocation-!cn".

## Integration with PAC Generation

After a successful update, the `MergeAndWritePACFile` method performs three critical operations:

1. Reads the user-provided ABP script template from `Resources.abp_js` or a custom file path
2. Merges user-defined rules with the generated rules from the GeoSite groups using `GenerateRules`, `GenerateBlockingRules`, and `GenerateExceptionRules`
3. Writes the final output to `PACDaemon.PAC_FILE` (typically [`pac.txt`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/pac.txt))

This integration ensures that new domain classifications immediately affect routing decisions without requiring a client restart.

## Event-Driven Notifications

Client code can subscribe to update notifications through two static events declared at lines 32-34:

```csharp
GeositeUpdater.UpdateCompleted += (sender, args) => {
    Console.WriteLine($"GeoSite update finished. PAC changed: {args.Success}");
};

GeositeUpdater.Error += (sender, err) => {
    Console.WriteLine($"Update failed: {err.GetException().Message}");
};

```

The `UpdateCompleted` event includes a `Success` property indicating whether the PAC file actually changed, while the `Error` event provides exception details for logging or UI alerts.

## Triggering Updates Programmatically

You can manually initiate an update cycle or check for specific domain groups using the following patterns.

**Manual update trigger:**

```csharp
using Shadowsocks.Controller;

// Typically called from UI threads or background timers
await GeositeUpdater.UpdatePACFromGeosite();

```

**Checking specific groups:**

```csharp
bool hasGoogle = GeositeUpdater.CheckGeositeGroup("google");
if (hasGoogle)
{
    var domains = GeositeUpdater.Geosites["google"]; // keys are lower-cased
    // Process domains for custom rule generation
}

```

## Summary

- **Hard-coded URLs**: `GEOSITE_URL` and `GEOSITE_SHA256SUM_URL` in [`GeositeUpdater.cs`](https://github.com/shadowsocks/shadowsocks-windows/blob/main/GeositeUpdater.cs) (lines 38-39) define the default v2fly/domain-list-community endpoints
- **Smart caching**: The system loads from `Utils.GetTempPath("dlc.dat")` or falls back to the embedded `Resources.dlc_dat` resource
- **Cryptographic verification**: SHA-256 checksums validate both existing caches and fresh downloads to prevent corruption
- **Atomic updates**: The `UpdatePACFromGeosite()` method downloads, verifies, persists, and reloads data in a single workflow
- **Protobuf parsing**: `GeositeList.Parser.ParseFrom` converts the binary `dlc.dat` into searchable domain group dictionaries
- **PAC integration**: Successful updates immediately trigger `MergeAndWritePACFile` to rebuild the proxy auto-configuration script

## Frequently Asked Questions

### How does GeositeUpdater handle network failures during download?

If the HTTP request to fetch either the checksum or the database fails, the method catches the exception and fires the `Error` event (lines 152-155). The existing cached database remains untouched and continues to serve requests, ensuring the proxy remains functional even when updates fail.

### Can I use a custom mirror for the geosite database instead of GitHub?

Yes. The updater checks the configuration file during the URL resolution phase (lines 87-94). If you specify custom values for the geosite URL and SHA-256 URL in your settings, the system uses those endpoints instead of the hard-coded defaults pointing to v2fly/domain-list-community.

### What format is the geosite database and how is it parsed?

The database is a binary protobuf file defined by `geosite.proto` in the `Model/Geosite` directory. The updater uses `GeositeList.Parser.ParseFrom` to deserialize the byte array into C# objects, creating a dictionary where keys are lowercase group names (like "google" or "cn") and values are lists of domain objects with type information.

### Why does the updater skip downloading sometimes?

The updater computes the SHA-256 hash of the local cache and compares it with the remote checksum before initiating a download (lines 110-118). If the hashes match, the database is already current, so the system skips the download to save bandwidth and immediately fires `UpdateCompleted` with `Success` set to indicate no changes were necessary.