> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/fr/architecture/ip-data-sources.md).

# Sources de données IP

Deux questions pilotent l'essentiel de MyIP, et elles sont traitées par des mécanismes différents :

* **"Qu'est-ce que mon IP ?"** — le navigateur interroge directement plusieurs points de terminaison d'écho tiers. Le backend n'est pas impliqué.
* **"Où se trouve cette IP ?"** — le navigateur interroge *notre* backend, qui interroge un fournisseur de géolocalisation (ou une base de données locale) et normalise la réponse.

Les garder séparées est délibéré : un point de terminaison d'écho doit voir la connexion propre du visiteur, il ne peut donc pas être relayé par un proxy.

```mermaid
flowchart TD
    subgraph Browser
      G["utils/getips/ — une fonction par source"]
      T["utils/transform-ip-data.js"]
      C["cartes IP"]
    end
    subgraph Backend
      H["gestionnaires de géolocalisation dans api/<br/>ipinfo-io, ipapi-com, ipapi-is,<br/>ip2location-io, ip-sb, ipcheck-ing, maxmind"]
      M["common/maxmind-service.js — mmdb locale"]
    end
    P["points de terminaison d'écho tiers<br/>Cloudflare, IPCheck.ing, IPIP.net, ..."]
    U["fournisseurs de géolocalisation"]

    G -->|"récupération directe"| P
    G -->|"l'adresse IP"| H
    H --> U
    H --> M
    H -->|"JSON canonique"| T --> C
```

## Étape 1 — résolution de votre propre IP

`frontend/utils/getips/` contient un petit module par source. Chacun exporte une `async` fonction renvoyant `{ ip, source }`, valide le résultat avec `isValidIP()` depuis `common/valid-ip.js`, et passe par `fetchWithTimeout` (délai navigateur par défaut de 5 secondes).

`frontend/components/IpInfos.vue` affiche jusqu'à six cartes et attribue une fonction source à chacune, par index :

| Carte | Source principale  | Point de terminaison                   | Se rabat sur                                          |
| ----- | ------------------ | -------------------------------------- | ----------------------------------------------------- |
| 0     | IPCheck.ing IPv4   | `4.ipcheck.ing`                        | IPify IPv4 (`api4.ipify.org`)                         |
| 1     | IPCheck.ing IPv6   | `6.ipcheck.ing`                        | IPify IPv6 (`api6.ipify.org`)                         |
| 2     | Cloudflare IPv4    | `1.0.0.1/cdn-cgi/trace`                | MyExternalIP IPv4                                     |
| 3     | Cloudflare IPv6    | `[2606:4700:4700::1111]/cdn-cgi/trace` | MyExternalIP IPv6                                     |
| 4     | IPIP.net           | `myip.ipip.net/json`                   | Upai (`pubstatic.b0.upaiyun.com`)                     |
| 5     | IPCheck.ing IPv6/4 | `64.ipcheck.ing`                       | — (JSON, puis le texte du même hôte `/cdn-cgi/trace`) |

{% hint style="info" %}
Les trois sources IPCheck.ing prennent un argument `originalSite` . Dans le déploiement canonique, elles lisent le point de terminaison JSON ; ailleurs, elles lisent le texte de type Cloudflare `/cdn-cgi/trace` du même hôte. Si l'appel JSON échoue, elles réessayent via trace avant d'abandonner.
{% endhint %}

La gestion des échecs est hiérarchisée :

1. Une source qui lève une exception ou renvoie une IP invalide consigne un `console.warn` et renvoie son repli déclaré, ou `{ ip: null, source }`.
2. Chaque carte exécute son propre pipeline de résolution puis de détail, et les six tournent sous `Promise.allSettled`, donc une source défaillante ne peut pas faire échouer le lot. Les cartes s'affichent indépendamment à mesure qu'elles arrivent.
3. Quand toute la chaîne d'une carte échoue, la SPA émet un `ip-source:exhausted` événement sur le bus de l'application. Sentry (lorsqu'il est configuré) ne le capture que si une autre carte de la même version d'IP a réussi — sinon « notre chaîne a échoué » est indiscernable d'un visiteur sans IPv6, ce qui est du bruit courant.

Les échecs de source individuels sont `console.warn` par conception, donc ils n'atteignent jamais la surveillance des erreurs ; l'événement d'épuisement par carte est le signal de santé.

## Étape 2 — géolocalisation d'une IP

Une fois qu'une carte a une IP, elle appelle le backend. `frontend/data/ip-databases.js` est le registre des sources sélectionnables :

| id | Nom            | Point de terminaison                      | Nécessite une clé                                          |
| -- | -------------- | ----------------------------------------- | ---------------------------------------------------------- |
| 0  | IPCheck.ing    | `/api/ipchecking?ip={{ip}}&lang={{lang}}` | `IPCHECKING_API_KEY` (API privée)                          |
| 1  | IPinfo.io      | `/api/ipinfo?ip={{ip}}`                   | Facultatif (`IPINFO_API_KEY`)                              |
| 2  | IP-API.com     | `/api/ipapicom?ip={{ip}}&lang={{lang}}`   | Non                                                        |
| 3  | IPAPI.is       | `/api/ipapiis?ip={{ip}}`                  | `IPAPIIS_API_KEY`                                          |
| 4  | IP2Location.io | `/api/ip2location?ip={{ip}}`              | `IP2LOCATION_API_KEY`                                      |
| 5  | IP.sb          | `/api/ipsb?ip={{ip}}`                     | Non                                                        |
| 6  | MaxMind        | `/api/maxmind?ip={{ip}}&lang={{lang}}`    | Base de données locale, pas de clé au moment de la requête |

`buildDbUrl(db, ip, lang)` substitue les `{{ip}}` et `{{lang}}` espaces réservés. Le `enabled` de chaque source est dérivé des indicateurs de fonctionnalité de `/api/configs` à leur chargement (`applyConfigAvailability`) — les sources protégées par clé suivent leur indicateur, celles sans clé sont toujours disponibles — et les échecs de récupération à l'exécution n'y touchent jamais. Les utilisateurs changent de source dans Préférences ; si un choix enregistré pointe vers une source qui n'est plus configurée, il est migré vers la plus proche disponible (`nearestEnabledId`, en avançant dans l'ordre des id) avec un toast — le seul cas où la préférence enregistrée est réécrite. La configuration des clés est traitée dans [Clés API facultatives](/developer/fr/configuration/optional-api-keys.md).

### Chaîne de repli côté client

`IpInfos.vue` ne se contente pas d'interroger la source préférée puis d'abandonner. À l'intérieur de `fetchIPDetails()`:

* La source demandée est recherchée dans la **enabled** liste ; si elle est absente (son indicateur de configuration est désactivé, ou les configurations n'ont pas encore chargé), la traversée commence à la première activée.
* En cas d'erreur, il consigne, passe à la source activée suivante et réessaie — jusqu'à ce que toutes les sources activées aient été tentées.
* Tomber sur une source différente de celle demandée affiche un toast unique et bascule la source d'exécution de la session, de sorte que les requêtes suivantes commencent par celle qui fonctionne — la préférence enregistrée n'est jamais réécrite.
* Les résultats sont mis en cache par IP, et les requêtes en vol sont dédupliquées par IP, de sorte que six cartes affichant la même adresse produisent une seule requête.

## La forme canonique de la réponse

Chaque gestionnaire de géolocalisation renvoie le même JSON, quelle que soit la forme de l'amont. À partir de `api/ipinfo-io.js`:

```js
{
    ip,
    city,
    region,
    country,        // ISO 3166-1 alpha-2
    country_name,
    country_code,   // même code que `country`
    latitude,
    longitude,
    asn,            // "AS13335" — avec le préfixe AS
    org
}
```

| Champ                      | Notes                                                                                                  |
| -------------------------- | ------------------------------------------------------------------------------------------------------ |
| `ip`                       | Renvoyé en écho par l'amont                                                                            |
| `city` / `region`          | Chaînes en texte libre ; `'N/A'` quand l'amont n'a rien                                                |
| `country` / `country_code` | Les deux portent le code ISO alpha-2                                                                   |
| `country_name`             | Nom propre de l'amont — le frontend le remplace généralement                                           |
| `latitude` / `longitude`   | Nombres                                                                                                |
| `asn`                      | Normalisé au format `AS<number>` ; les sources renvoyant un simple nombre se voient ajouter le préfixe |
| `org`                      | Nom de l'organisation ou du FAI                                                                        |

Deux sources l'étendent. `api/ipapi-is.js` ajoute `isHosting` et `isProxy` des booléens. `api/ipcheck-ing.js` est un proxy de passage vers l'API privée IPCheck.ing et renvoie la charge utile de cette API telle quelle, y compris un objet `advancedData` que le frontend déplie en champs proxy, type d'IP, IP native, score de qualité, protocole et fournisseur.

<details>

<summary>Ce que le frontend fait avec la charge utile</summary>

`frontend/utils/transform-ip-data.js` transforme une réponse canonique en données de carte :

* `country_name` est reconstitué à partir du **code** du pays localement, afin que chaque source affiche le même nom dans la langue de l'UI ; la chaîne amont n'est qu'un repli.
* `country_code` de `'N/A'` devient une chaîne vide.
* `org` devient `isp`, et un `asn` commençant par `AS` obtient un `asnlink` vers bgp.tools.
* Les coordonnées sont arrondies à un dixième de degré pour `mapUrl` / `mapUrl_dark`, qui pointent vers `/api/map`. Au niveau de zoom de la carte, \~0,176° font un pixel, donc 0,1° est sous-pixel — le marqueur paraît identique tandis que chaque IP dans la même cellule de grille se réduit à une seule clé de cache en périphérie. Les coordonnées en pleine précision sont conservées pour l'affichage.
* Pour la source `0` (IPCheck.ing), il extrait aussi les `advancedData` champs.

</details>

Ajouter une source signifie écrire un gestionnaire qui produit cette forme et ajouter une ligne à `data/ip-databases.js`. Les nouveaux gestionnaires doivent utiliser la `makeGeoHandler({ name, buildUrl, normalize })` dans `common/geo-handler.js`, qui prend en charge l'enveloppe partagée : lire le `?ip`, déjà validé, récupérer via `fetchUpstream`, lever une erreur sur un statut non-2xx (les pages de panne reviennent en HTML et feraient sinon planter `JSON.parse`), normaliser, répondre, et consigner puis renvoyer 500 en cas d'échec.

## Jeux de données locaux

Deux jeux de données vivent sur disque dans `common/` et sont lus de manière synchrone au moment de la requête. Les deux disposent d'un mécanisme de mise à jour automatique qui s'exécute dans le même processus.

### MaxMind GeoLite2

`common/maxmind-service.js` ouvre `GeoLite2-City.mmdb` et `GeoLite2-ASN.mmdb` depuis `common/maxmind-db/` et garde les deux lecteurs en mémoire. `lookupMaxMind(ip, lang)` fusionne un enregistrement City et un enregistrement ASN en la forme canonique, en résolvant les noms localisés avec un repli en anglais puis `'N/A'` . Si l'un des lecteurs manque, il lève avec `statusCode` 503, et `/api/maxmind` répond 503 — l'API se dégrade, le serveur continue de tourner.

La mise à jour est gérée par `common/maxmind-updater.js`:

| Comportement                    | Valeur                                                                                                                           |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Bootstrap au démarrage          | Télécharge uniquement si les fichiers manquent, avec un plafond de 5 minutes ; s'exécute indépendamment de `MAXMIND_AUTO_UPDATE` |
| Première vérification planifiée | 60 secondes après le démarrage                                                                                                   |
| Intervalle de répétition        | Toutes les 24 heures                                                                                                             |
| Condition pour le planificateur | `MAXMIND_AUTO_UPDATE=true` plus `MAXMIND_ACCOUNT_ID` et `MAXMIND_LICENSE_KEY`                                                    |
| Concurrence                     | Un fichier de verrouillage, considéré comme périmé après 2 heures                                                                |

Les téléchargements sont mis en scène puis publiés atomiquement. Un watcher de fichiers séparé (`startMaxMindFileWatcher()`) interroge les deux fichiers toutes les 5 secondes et recharge les lecteurs quand un autre processus les remplace, avec anti-rebond d'une seconde pour que City et ASN arrivent comme un seul rechargement. Si le nouveau fichier est invalide, les lecteurs existants restent en place. Les instructions de configuration se trouvent dans [Configuration MaxMind](/developer/fr/getting-started/maxmind-setup.md).

### CAIDA as2org et relations AS

`common/caida-updater.js` gère deux jeux de données avec la même machinerie de verrou / état / publication atomique / validation / rechargement :

| Jeu de données | Fichier                            | Source                                                                                             | Utilisé par                        |
| -------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------- | ---------------------------------- |
| `as2org`       | `common/as-org-db/as-org2info.txt` | `publicdata.caida.org/datasets/as-organizations/latest.as-org2info.txt.gz`                         | recherches AS → nom d'organisation |
| `as-rel`       | `common/as-rel-db/as-rel2.txt`     | Le plus récent `*.as-rel2.txt.bz2` dans `publicdata.caida.org/datasets/as-relationships/serial-2/` | Le graphe de connectivité AS       |

`as2org` dispose en amont d'un lien symbolique stable latest, donc un `latest` HEAD `Last-Modified` plus `suffit pour détecter un nouveau snapshot.` n'en a pas, donc le metteur à jour parcourt la liste du répertoire et prend le `as-rel` plus récent lexicographiquement `YYYYMMDD` nom de fichier. Les deux sont décompressés à la volée et validés avant publication.

Le calendrier suit MaxMind : bootstrap au démarrage s'ils manquent (limite 2 minutes), première vérification 60 secondes après le démarrage, puis toutes les 24 heures, avec le planificateur périodique gardé derrière `CAIDA_AUTO_UPDATE=true`. Le bootstrap s'exécute toujours pour qu'un checkout frais fonctionne.

`common/as-rel-db.js` analyse les lignes délimitées par des pipes et ne conserve que les relations fournisseur-vers-client (`-1`) relations, en construisant un index client → fournisseurs et un comptage de clients par AS. L'ensemble Tier 1 est dérivé du snapshot plutôt que codé en dur : un AS sans fournisseurs dans la topologie p2c qui fournit aussi le transit à au moins 100 autres. `/api/asn-connectivity` effectue ensuite un BFS entièrement local et synchrone depuis l'AS d'origine jusqu'aux Tier 1.

`common/as-org-db.js` analyse le TXT CAIDA délimité par des pipes (\~12 MB) au lieu du JSONL équivalent (\~28 MB) — contenu identique, et `split('|')` bat `JSON.parse` par ligne d'environ 40 %. Les deux modules choisissent le fichier correspondant le plus récent selon la date de modification, donc un snapshot téléchargé manuellement avec un nom différent fonctionne quand même.

## Ce qui se passe quand quelque chose échoue

| Échec                                                              | Résultat                                                                                                                           |
| ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| Un point de terminaison d’écho est hors service                    | Son module retombe sur un second point de terminaison ; si celui-ci échoue, la carte n’affiche rien et émet `ip-source:exhausted`  |
| Un fournisseur de géolocalisation renvoie une erreur               | Le client retombe sur la prochaine source activée et affiche un toast ; les requêtes suivantes partent de la source qui fonctionne |
| Toutes les sources de géolocalisation échouent pour une adresse IP | Les champs de détail de la carte restent vides ; l’erreur est consignée côté client                                                |
| Un service amont se bloque                                         | `fetchUpstream` s’arrête au bout de 8 secondes et le gestionnaire renvoie `500 { error }`                                          |
| Les bases de données MaxMind sont manquantes ou invalides          | `/api/maxmind` renvoie 503 ; le reste de l’API n’est pas affecté                                                                   |
| Les instantanés CAIDA sont manquants                               | Le graphe de connectivité revient vide, et les recherches de nom d’organisation retombent sur celles de RIPEstat `as-overview`     |
| Un service amont renvoie une page HTML de panne                    | `makeGeoHandler` lève une erreur sur le statut non 2xx avant l’analyse                                                             |

## Pages associées

* [Backend](/developer/fr/architecture/backend.md) — les garde-fous, les niveaux de cache et la séquence de démarrage
* [Clés API facultatives](/developer/fr/configuration/optional-api-keys.md) — quelles sources nécessitent des identifiants
* [Configuration MaxMind](/developer/fr/getting-started/maxmind-setup.md) — obtenir et actualiser GeoLite2
* [Points de terminaison de l’API](/developer/fr/reference/api-endpoints.md) — le contrat complet requête/réponse


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/fr/architecture/ip-data-sources.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
