Connection Types
Every edge type in WhisperGraph — direction, source and target labels, and the physical-vs-virtual rules that decide how you traverse it.
On this page (16)
- Edge types
- DNS resolution & hierarchy
- BGP & routing
- WHOIS & registration
- Geo
- Threat intelligence & attribution
- Email security & TLS
- Physical infrastructure
- Certificate Transparency
- Web, technology & similarity
- Declared but unpopulated
- Direction conventions worth memorising
- Technology and company layer
- Where the planes are thin
- Physical vs. virtual edges
- Confirm an edge before you traverse
Connection Types Documentation
Connections are what make a pre-joined graph worth querying. This page covers every edge type the engine exposes — each one's direction, the labels it runs between, and what it means. For the nodes on either end, see Entities; for the chains that string edges across layers, see Pivoting Examples.
The table below is generated from CALL db.relationshipTypes(), so its row set is whatever the census last saw. Several edge types are computed at query time rather than stored, and a computed type can be absent from one live listing while its edges still traverse. If an edge you expect is missing from a listing, anchor a node by name and follow the edge directly before you conclude it is gone.
The From → To column is the source and target labels the call reports, not the ones a writer remembered. Where they name a label CALL db.labels() does not return, the row says so.
Direction matters. Several edges point the opposite way to how you would read them in English — NAMESERVER_FOR and MAIL_FOR run server → domain, so you traverse them backwards to answer "what serves this domain". The table's From → To column is the engine's own answer to which way each one points.
Edge types
DNS resolution & hierarchy
| Edge | Rows | From → To | What it means |
|---|---|---|---|
RESOLVES_TO | 3,125,689,316 | HOSTNAME → IPV4, IPV6 | A host resolves to an IP (forward only — reverse-DNS via (ip)<-[:RESOLVES_TO]-(h)). |
ALIAS_OF | 455,347,689 | HOSTNAME → HOSTNAME | A CNAME alias. |
CHILD_OF | 2,451,196,569 | EMAIL, HOSTNAME, IPV4, PREFIX → HOSTNAME, ORGANIZATION, PREFIX, TLD | A subdomain points up to its parent (and to the TLD). |
NAMESERVER_FOR | 9,173,662,411 | HOSTNAME → HOSTNAME | A nameserver serves a domain (edge points server → domain). |
MAIL_FOR | 591,149,876 | HOSTNAME → HOSTNAME | A mail server handles mail for a domain (edge points server → domain). |
LINKS_TO | 15,169 | HOSTNAME, URL → HOSTNAME | A phishing-kit URL path served by a host (URL → HOSTNAME), plus a small sample of host-to-host hyperlinks. |
BGP & routing
| Edge | Rows | From → To | What it means |
|---|---|---|---|
BELONGS_TO | 619,734,764 | IPV4, IPV6 → PREFIX | An IP falls inside an allocated prefix. It also carries the FEED_SOURCE → CATEGORY taxonomy hop. |
ANNOUNCED_BY | 4,329,053,043 | IPV4, IPV6 → ANNOUNCED_PREFIX | An IP is covered by a BGP-announced prefix. |
ROUTES | 1,447,179 | ASN → ANNOUNCED_PREFIX, PREFIX | An ASN announces a prefix (matches in either direction). |
HAS_NAME | 31,460 | ASN → ASN_NAME | An ASN's registered network name (asn.name is the AS number; the network name lives on ASN_NAME). |
BGP_NEIGHBOR | 427,752 | ASN → ASN | The canonical ASN↔ASN BGP adjacency edge. |
PEERS_WITH | 427,752 | ASN → ASN | Alias of BGP_NEIGHBOR. The same adjacency under its older name. Both spellings traverse. |
BGP_PATH | 21,330,490 | BGP_PATH_OBSERVATION → ASN | One hop of an observed AS path — the only route to the BGP_PATH_OBSERVATION label. |
CONFLICTS_WITH | 10,682 | ANNOUNCED_PREFIX → ASN | A multi-origin (MOAS) conflict over a prefix. Synthesized at expand time. |
ROA_AUTHORIZES_ORIGIN | 3,019,352 | ROA → ASN | An RPKI ROA authorizes an AS as origin. |
ROA_AUTHORIZES_PREFIX | 882,431 | ROA → ANNOUNCED_PREFIX, PREFIX, REGISTERED_PREFIX | An RPKI ROA authorizes a prefix. |
OPERATES | 1,449 | TLD_OPERATOR → TLD | A registry operates a TLD. |
WHOIS & registration
| Edge | Rows | From → To | What it means |
|---|---|---|---|
HAS_REGISTRAR | 649,320,946 | HOSTNAME → REGISTRAR | The domain's current registrar. |
PREV_REGISTRAR | 618,353,159 | HOSTNAME → REGISTRAR | A prior registrar. |
HAS_EMAIL | 546,846,860 | HOSTNAME → EMAIL | A WHOIS contact email. |
HAS_PHONE | 550,324,627 | HOSTNAME → PHONE | A WHOIS contact phone. |
REGISTERED_BY | 916,255,242 | ASN, HOSTNAME, REGISTERED_PREFIX → ORGANIZATION | The registrant or owning organization. |
SAME_ORG_AS | 7,678 | ORGANIZATION → ORGANIZATION | Two organizations resolved to the same entity. |
PARENT_OF | 4,687,568 | CATEGORY, HOSTNAME → CATEGORY, HOSTNAME | A parent-child relationship between two entities of the same kind — a parent organization and a subsidiary, for instance. |
REGISTERED_TO_ENTITY | 375,236 | ASN, PREFIX → RDAP_ENTITY | A prefix or an ASN registered to an RDAP entity — the edge that reaches RDAP_ENTITY. |
Geo
| Edge | Rows | From → To | What it means |
|---|---|---|---|
LOCATED_IN | 118,196,249 | IPV4, IPV6 → CITY | An IP's GeoIP city (chain HAS_COUNTRY for the country). |
HAS_COUNTRY | 194,925,670 | ANNOUNCED_PREFIX, ASN, CITY, HOSTNAME, IPV4, IPV6, ORGANIZATION, PHONE, PREFIX, REGISTERED_PREFIX → COUNTRY | The associated country. |
Threat intelligence & attribution
| Edge | Rows | From → To | What it means |
|---|---|---|---|
LISTED_IN | 14,315,745 | HOSTNAME, IPV4, IPV6 → FEED_SOURCE | An indicator appears on a threat feed. |
HAS_SIGNAL | 157,674 | ASN, HOSTNAME, PREFIX → THREAT_SIGNAL_TYPE | A node carries a threat signal. |
OPERATES_EXIT_NODE | 1,269 | IPV4, PREFIX → TOR_RELAY | An IP operates a Tor exit relay. |
DELEGATED_TO | 377,648 | IPV4, PREFIX, VENDOR → VENDOR | Address space operated by a vendor (distinct from the WHOIS owner). |
TAGGED_AS | 139,213 | HOSTNAME, IPV4, PREFIX → THREAT_TAG | A MISP-style classification tag on an indicator — the only route to the THREAT_TAG label. |
USES_TECHNIQUE | 9,630 | ACTOR → ATTACK_PATTERN | A threat actor uses a MITRE ATT&CK technique. |
USES_TACTIC | 881 | ATTACK_PATTERN → ATTACK_PATTERN | A technique grouped under its ATT&CK tactic. |
ATTRIBUTED_TO | 345 | HOSTNAME, IPV4, PREFIX → ACTOR | An indicator attributed to a named actor. |
Email security & TLS
| Edge | Rows | From → To | What it means |
|---|---|---|---|
SPF_INCLUDE | 248,657,397 | HOSTNAME → HOSTNAME | An SPF include: mechanism. |
SPF_IP | 184,041,835 | HOSTNAME → IPV4, IPV6, PREFIX | An SPF ip4:/ip6: authorization. |
SPF_A | 93,812,710 | HOSTNAME → HOSTNAME | The SPF a mechanism. |
SPF_MX | 84,451,018 | HOSTNAME → HOSTNAME | The SPF mx mechanism. |
SPF_EXISTS | 327,825 | HOSTNAME → HOSTNAME | The SPF exists: mechanism. |
SPF_REDIRECT | 2,751,803 | HOSTNAME → HOSTNAME | The SPF redirect= modifier. |
DMARC_REPORTS_TO | 53,153 | HOSTNAME → DMARC_RECIPIENT | Where a domain sends DMARC aggregate reports. |
DKIM_SIGNED_BY | 30,545 | HOSTNAME → VENDOR | The mail vendor whose DKIM key signs a domain's outbound mail. |
EMITS_TLS_FINGERPRINT | 271 | IPV4 → TLS_FINGERPRINT | An IP presents a JA3/JARM TLS fingerprint. |
Physical infrastructure
| Edge | Rows | From → To | What it means |
|---|---|---|---|
AS_PRESENT_AT | 519,951 | ASN → FACILITY | A network is present in a datacenter. |
IX_MEMBER | 57,700 | ASN → INTERNET_EXCHANGE | A network is a member of an IXP. |
IX_HOSTED_AT | 4,545 | INTERNET_EXCHANGE → FACILITY | An IXP is hosted in a facility. |
CABLE_LANDS_AT | 3,217 | SUBMARINE_CABLE → CABLE_LANDING | A subsea cable lands at a landing point. |
LANDING_NEAR | 5,251 | CABLE_LANDING → FACILITY | A landing point is near a facility. |
CDN_POP_AT | 1,668 | CDN_POP → FACILITY | A CDN PoP is in a facility. |
FIBER_SEGMENT | 9,998 | FACILITY → FACILITY | A fiber link between facilities (symmetric). |
PREFIX_IN_REGION | 3,281 | PREFIX → CLOUD_REGION | A prefix sits in a cloud region. |
Certificate Transparency
| Edge | Rows | From → To | What it means |
|---|---|---|---|
SEEN_IN_CT | 9,037,971 | HOSTNAME → CT_OBSERVATION | A host appears in a Certificate Transparency observation. |
Web, technology & similarity
| Edge | Rows | From → To | What it means |
|---|---|---|---|
RUNS_TECHNOLOGY | 1,584,990,259 | HOSTNAME → TECHNOLOGY | A host or IP runs a detected technology — a CMS, a web server, a framework. |
SIMILAR_TO | 94,253,913 | HOSTNAME → HOSTNAME | Two entities the engine judged similar — near-duplicate organization names or lookalike domains, for instance. |
Declared but unpopulated
None. Every edge type in this reading reported rows, and none came back declaredButEmpty.
Rows measured live from CALL db.relationshipTypes(), 2026-10-22. The counts render as tokens resolved from the same live figures, so a replica disagreeing by a few million moves the number without moving the table.
Direction conventions worth memorising
A handful of edges account for most wrong-direction queries.
CHILD_OFpoints upward:www.google.com → google.com → com. Its sources areHOSTNAMEandEMAIL(an address points at its host domain); its targets areHOSTNAMEandTLD.MAIL_FORandNAMESERVER_FORpoint from the server to the domain it serves. A domain's mail hosts are(d:HOSTNAME {name: "…"})<-[:MAIL_FOR]-(mx).RESOLVES_TOis forward only (HOSTNAME → IPV4/IPV6). Reverse DNS is the same edge read backwards:(ip)<-[:RESOLVES_TO]-(h).ANNOUNCED_BYgoesIP → ANNOUNCED_PREFIX, not to the ASN.ROUTESgoesASN → PREFIXorANNOUNCED_PREFIXand matches in either arrow direction. Walk from an IP to the network that routes it withANNOUNCED_BYthenROUTES; do not joinROUTESandBELONGS_TOin one pattern to do the same job.BELONGS_TOis overloaded:IPV4/IPV6 → PREFIXin the addressing plane,FEED_SOURCE → CATEGORYin the feed taxonomy. Label both endpoints so the planner knows which you mean.BGP_NEIGHBORis the ASN-to-ASN adjacency edge.PEERS_WITHis its deprecated alias; writeBGP_NEIGHBOR.CONFLICTS_WITHrunsANNOUNCED_PREFIX → ASN: the prefix is the source, the competing origin AS the target.BGP_PATHrunsBGP_PATH_OBSERVATION → ASN, one edge per AS on the path. The observation'snameis the hyphen-joined AS path, origin last.LOCATED_INisIPV4/IPV6 → CITYonly. ChainHAS_COUNTRYfrom the city for the country.HAS_COUNTRYitself has many sources: ASNs, prefixes, organizations, phones and hostnames carry one too.HAS_NAMEisASN → ASN_NAME.asn.nameis the AS number; the network name lives on theASN_NAMEnode.REGISTERED_TO_ENTITYrunsPREFIX/ASN → RDAP_ENTITYand is the way in toRDAP_ENTITY. Hostnames do not carry it; a domain's registration data is onEMAIL,PHONE,REGISTRARandORGANIZATION.LINKS_TO's live use isURL → HOSTNAME: this phishing-kit path has been served by this host. TheHOSTNAME → HOSTNAMEform the listing reports is a small sample of hyperlinks, not a web-scale link graph, so do not plan a link-graph question on it. Anchor theURLnode by{name: …}, which holds the path and is indexed, or bound it withWITH u LIMIT n, before following the edge.SIGNED_WITHrunsHOSTNAME → DNSSEC_ALGORITHM, presence-only. It confirms a domain is DNSSEC-signed and names the algorithm; it does not say whether the signature validates. It is also invisible toCALL db.relationshipTypes()— the census will not list it — so anchor a hostname and follow the edge directly rather than concluding from the table above that it does not exist.
Technology and company layer
WhisperGraph also joins a hostname to the technology stack it runs and to the wider company it belongs to, available to accounts with company-data access. A worked example: Which technologies does a vendor run, and who else does it own?
RUNS_TECHNOLOGYrunsHOSTNAME → TECHNOLOGY, 1,584,990,259 edges. It names a specific product (Cloudflare DNS,Atlassian Statuspage) with acategoryand the technology vendor's own apex domain, not just a vendor name.PARENT_OFrunsHOSTNAME → HOSTNAME, 4,687,568 edges, and covers two distinct relationships: the same brand under another ccTLD or gTLD (google.com → google.af) and a parent company to a differently branded subsidiary or product domain (meta.com → rewind.ai).CALL db.relationshipTypes()also lists aTLD → HOSTNAMEsource for this edge; that source returns no edges live, so anchorHOSTNAMEon both ends rather than building a query off aTLDnode.SIMILAR_TOrunsHOSTNAME → HOSTNAME, 94,253,913 edges, and is directional, not symmetric:google.comnamesbing.comas similar, but the reverse edge does not exist. Read it as one company's own outbound comparison set, and query both directions if you need the full pairing.
Where the planes are thin
Some of these planes are small enough that a zero-row result says more about Whisper's coverage than about the indicator, and reading one as evidence of absence is the most expensive mistake on this page. The row count in the table above is what tells them apart.
The ATT&CK layer is a curated reference plane, not Whisper's own attribution: 9,630 USES_TECHNIQUE and 881 USES_TACTIC edges reflect what public reporting has mapped. The edge that joins it to live infrastructure is sparse: ATTRIBUTED_TO, a published attribution from an indicator to a named group, holds 345 edges. It answers no attribution question at scale, and an empty result from it is no-data — coverage: no-data. Not in coverage. This is not a verdict — nothing was looked at., never evidence of absence.
The email and TLS planes are not the same size, and lumping them together hides which results you can trust: DKIM_SIGNED_BY holds 30,545 edges and DMARC_REPORTS_TO 53,153 — populated planes where an empty result usually means the domain publishes no such record. EMITS_TLS_FINGERPRINT holds 271, a small fraction of either.
TLS-fingerprint coverage is partial. Expect no match on almost any indicator. A zero-row result here means Whisper holds no observation — not that the host shares no infrastructure.
Certificate Transparency coverage is partial. Many well-known hosts have no
SEEN_IN_CTedge at all. A zero-row result here means Whisper holds no CT observation for that host. It never means the host has a clean certificate history. If certificate history is load-bearing for your decision, query a CT log directly — crt.sh or the Google CT API — and come back with the hostnames you find.
Physical vs. virtual edges
Edge types come in two kinds, and the distinction changes how you write the query. Read the split from the engine rather than from a list here: CALL db.schema('json') marks every edge type virtual: true or false.
Physical edges are materialized on disk — the DNS, geo and SPF sets, and most of the WHOIS set. An unanchored MATCH ()-[r:RESOLVES_TO]->(h) returns rows.
Virtual edges are computed at query time and are not in the physical store: the routing set, the whole threat and attribution set, the DMARC/DKIM/TLS-fingerprint edges, SEEN_IN_CT, REGISTERED_TO_ENTITY, and the physical-infrastructure set. BELONGS_TO is mixed — the IP → PREFIX side is stored, the FEED_SOURCE → CATEGORY taxonomy hop is computed — and the engine treats it as virtual when it plans a traversal. Five rules follow:
- Label or anchor at least one endpoint. A pattern with both ends bare is refused, not answered:
MATCH (a)-[:LISTED_IN]->(b) RETURN a.name, b.namereturns HTTP 400query-unservable, naming the edge type. Label one end —MATCH ()-[:LISTED_IN]->(f:FEED_SOURCE)— and it answers. - Variable-length patterns work. Computed edges expand inside
[*1..N]andshortestPath(), andlength(p)reports correctly, as long as one endpoint is labelled or anchored. Bound the range, and on a peering walk filterWHERE n <> a— an undirected mesh routinely returns to the origin AS. - Type the edge when you expand outward from an announced prefix. Write
-[:ROUTES]->,-[:CONFLICTS_WITH]->or-[:HAS_COUNTRY]->rather than a bare-[r]->, or anchor on thePREFIX-labelled node for the same CIDR. - De-duplicate on the client, or aggregate. Over a routing chain that projects an
ANNOUNCED_PREFIX, usecount(DISTINCT …)orcollect(DISTINCT …), or de-duplicate the rows yourself, rather thanRETURN DISTINCT. - Read edge counts from the census calls.
CALL db.relationshipTypes() YIELD type, countandGET /api/query/statsgive the per-type totals. An unanchoredcount(r)over a computed edge is not the way to get one.
ROUTES and HAS_NAME do appear in db.relationshipTypes() with real counts — read them off the table above. Anchor them and they work.
CALL db.schema() in its default form attaches a traversalHints list to many relationship rows — copy-pasteable starter patterns anchored on the labels that edge actually accepts. The db.schema('json') form carries no hints. See Best Practices for the full set of query rules.
Confirm an edge before you traverse
CALL db.relationshipTypes() YIELD type, sourceLabels, targetLabels
RETURN type, sourceLabels, targetLabels ORDER BY type
db.relationshipTypes() lists every edge type with the source and target labels observed on it, and it is cheap — it answers immediately. Checking it first — alongside db.labels() — is the fastest cure for empty, error-free results from a mistyped edge name.