> For the complete documentation index, see [llms.txt](https://docs.layeronecloud.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.layeronecloud.com/network-monitor/architecture/application-attribution.md).

# Destination-aware application attribution

The sensor keeps a bounded bidirectional flow tracker and pins the client and server from TCP handshakes, request-side protocol evidence, and a stable fallback heuristic.

The sensor keeps a bounded bidirectional flow tracker and pins the client and server from TCP handshakes, request-side protocol evidence, and a stable fallback heuristic. Combining that role with the local-address boundary assigns each flow to outbound Internet use, an inbound hosted service, internal LAN traffic, or an explicitly unscoped bucket. The one local endpoint supplies the device identity; for an internal flow, the initiator is the attributed device.

Destination evidence is learned on the wire. The bounded TCP inspector reassembles at most the first 4 KiB of client data and extracts TLS SNI on any TCP port, HTTP Host, or the target of HTTP CONNECT. Matched DNS A, AAAA, and CNAME answers remain usable only for their advertised TTL. Before anything is spooled, a pinned Public Suffix List reduces a hostname to its registrable domain. QUIC v1 is attributed only through a matching DNS observation; the sensor does not decrypt QUIC Initial packets. If there is no domain evidence, the destination is the canonical remote IPv4 or IPv6 address together with the observed server port.

These wire facts, including the evidence source, reach the control plane as typed `ApplicationUsagePoint` records rather than overloaded metric keys. A domain rule is the strongest classification signal. When no domain rule matches, the server uses its transport-and-port catalog; an unknown high TCP port remains `TCP N`, and bounded overflow is shown as Other. This keeps naming rules centrally updateable while preserving the destination that justified the classification. It does not retroactively classify the legacy port-only metric history.

Application detail is independently bounded from ordinary minute aggregation: 32,768 flows per capture, 131,072 per process, a 32 MiB inspection budget, and 4,096 application usage keys per minute. The usage tiers reserve 3,072 full destination/device/port keys, 768 device/port keys, 253 port-only keys, and three direction-specific overflow keys. Byte-heavy entries win when a tier is full; directional byte totals are conserved as detail falls back through the tiers. `ApplicationUsageCoverage` markers record eligible and represented bytes, domain/device/port coverage, capture and parser drops, flow or inspector exhaustion, and `detail_truncated`, including an explicit zero-traffic minute. Capture-level libpcap counters appear only on the canonical Internet/outbound marker, so sites with more VLAN coverage rows do not receive disproportionate weight.

`parser_dropped` counts each packet delivered by libpcap for which the packet parser returns no observation. Live and minute interface-total metrics carry independent deltas; the application minute's canonical Internet/outbound marker carries the same minute count, even when every packet failed parsing. Other metric dimensions and application markers keep this capture-wide counter at zero to avoid multiplying it across devices or VLANs. Successfully parsed ARP, unscoped traffic, and packets without an application name are not parser drops. The counter is separate from `pcap_dropped` and does not scale byte totals. On Linux, packet-buffer retention is `(pcap_received - pcap_dropped) / pcap_received` (clamped to zero), because received already includes buffer drops. Empty zero/zero windows return one, not proof of end-to-end completeness. Application collection and endpoint detail are marked partial when a contributing capture reports parser loss. Older sensors and pre-upgrade history default to zero without establishing that parsing was complete.

If transport parsing fails but the Ethernet/VLAN and IP headers remain readable and consistent with the original frame length, a header-only fallback preserves exact-IP host bytes using the existing local-boundary/gateway ownership rules. It does not learn ownership, emit discovery, classify applications, or feed the DDoS detector. The parser-loss counter still increments: preserved host bytes do not establish complete application or attack evidence. Invalid/unreadable IP headers remain unaccounted, rather than inventing an endpoint or byte count. Host traffic totals have a separate 20,000-key allowance per live/minute window, so application/port detail cannot consume their aggregation budget. Exhausting either budget retains the conservative capture-wide overflow warning. The live export still ranks at most 1,000 host traffic keys; minute output retains all host keys within its independent budget.

The host metric also carries `host_device_key` (protobuf tag 15), an optional contemporaneous segment/MAC identity. Each host key keeps a unanimous local-MAC claim across its independent live/minute window; an unknown or different owner makes that window permanently unowned without changing its bytes. Minute storage applies the same merge rule across additive chunks. Legacy rows are unowned. `wan_counters` selects the exact-IP source and canonical quality once for both Aegis and Devices. Device attribution uses only the chosen counter's unambiguous recorded owner, never retrospective joins to current IP bindings. Devices WAN cards and graphs derive from these selected byte deltas; MAC-based LAN usage remains separate. Missing ownership/traffic remains unknown.

LAN and WAN capture paths can see the same routed flow, while a guest bridged straight onto the uplink is visible to the WAN capture alone. Internet traffic is therefore counted where it crosses the uplink: for each site-minute, traffic scope, and direction, a WAN marker that observed eligible traffic makes the WAN facts authoritative and drops LAN observations of that minute; when the uplink is idle or absent, LAN facts stand in. Internal and unscoped traffic belongs to the bridges, with the same fallback in reverse. LAN observations the uplink superseded still name the devices behind a router or NAT gateway, which the uplink can only see as one machine; those rows contribute device names, never bytes, and are tagged with their vantage point. Only one capture role contributes to each byte total. That decision is made once per request from the coverage markers and expressed as time ranges in which a role is excluded, so the fact queries carry a few range predicates instead of correlated subqueries evaluated for every row. The ranking itself uses grouped queries over the selected facts. The first groups by destination, port, evidence and detail level -- a few thousand rows for a busy day, however many minutes or devices it holds -- and is classified in Python against the domain and port catalogs into application totals, per-application destination and port lists, and the site-wide destination ranking. The second groups device bytes by the ranked applications' own predicates, so the device dimension is summed in the database for the top applications only. An additional grouped endpoint query removes receive-only bytes belonging to inactive local IP/service-port identities; its sender-existence predicate uses the same capture authority and period. Capture-loss accounting includes the canonical counter marker once for each selected capture-minute, even when that marker's outbound traffic uses a different authority from the selected inbound or internal traffic. Application rows total each service once and expose up to ten destinations and ten devices, with pre-truncation counts and stable sorting. Applications have a fixed rolling 24-hour activity window, independent of the requested chart range. A local IP/service-port identity expires exactly 24 hours after its last observed outbound minute; inbound observations, scan results, delivery retries and activity on another IP or port cannot renew it. Hosted services use server-to-client bytes as outbound, and remain separate from client-initiated connections to the same port. Reused private LAN addresses are scoped to their segment. Pair lists, ports and application counts exclude expired identities before ranking. Legacy/reduced facts retain their available device, destination and port identity without inventing an exact local IP. The response exposes `applications_window`, `applications_retention_seconds`, and per-application `last_outbound_at`/`expires_at`. Cached applications cannot outlive their expiry. Receive-only observations remain in traffic and coverage totals, whose requested time window is unchanged.

Usage and coverage live in the daily-partitioned `monitoring_application_usage_minute` and `monitoring_application_usage_coverage_minute` tables. The applications API reads only these typed tables. During a server-first rollout it therefore shows a collecting or upgrade-required notice until destination-aware telemetry is available instead of mixing legacy port-only rows into a misleading ranking. Application totals and coverage retain their 30-day policy.

Full TCP/UDP facts also carry canonical client and service IPs from the bounded flow tracker. Replies retain the same orientation; inbound Internet facts map their inbound bytes to client-to-service bytes. Lower detail tiers discard IP pairs but keep eligibility for per-application completeness accounting. An independent endpoint-pair version on coverage markers distinguishes old sensors from upgraded sensors reporting zero traffic.

The server folds pairs out of the existing usage key and stores exact pairs and their classification summaries in `monitoring_application_endpoint_minute` and `monitoring_application_endpoint_summary_minute`. Both use daily partitions and a rolling 24-hour cutoff. Ingestion skips expired pair details; API queries also enforce the cutoff. Hourly maintenance deletes expired rows within the boundary partition and drops fully expired days. Pair queries share application catalog precedence, scope/direction filters, and LAN-before-WAN authority. They return five pairs per application with directional byte totals, the full pair count, and an explicit completeness state.


---

# 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.layeronecloud.com/network-monitor/architecture/application-attribution.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.
