# Read attack events

> See the attacks DDoS Shield detected on your addresses, how large they were and what it did about them.

Source: https://www.coritan.com/docs/ddos-shield/attack-events/

In the dashboard:

- /dashboard/ddos/events: https://www.coritan.com/dashboard/ddos/events

When DDoS Shield drops traffic to one of your floating IPs at a high rate, it records an *attack event*: which address was hit, why we dropped the traffic, how large the attack was and how long it lasted. The **Events** tab of DDoS Shield lists these events, and each one opens to show the senders and a few sampled packets.

## Before you begin

- Events exist only for floating IPs. DDoS Shield does not filter a server's shared address, so attacks on it leave no event ([How DDoS Shield works](/docs/ddos-shield/how-ddos-shield-works/#what-ddos-shield-covers)).
- An address in **Passthrough** mode records no events, because we drop almost nothing on it.
- The events of a floating IP disappear from the list when you cancel the floating IP.

## How we record an event

An event records traffic that DDoS Shield dropped for one reason, such as a reflection port or a rate limit, on one address. The routers at our points of presence that filter traffic, which the dashboard calls *scrubbing nodes*, each record their own events. One attack can therefore show as several events: one for each reason, each address and each node that received it.

- An event starts once a node drops at least 100 packets per second, or 1 Mbps, of one kind of traffic to the address. We filter smaller amounts all the same, but they make no event.
- Drops by the SYN or ICMP rate limits make an event only when they come from 10 or more senders, or reach 20,000 packets per second, so one busy client does not show as an attack.
- An event ends once that kind of traffic has stopped for about 45 seconds, so its duration includes those seconds.
- When the same kind of traffic hits the same address at the same node again, we update the earlier event instead of adding a new one. The event keeps its first start time, its peak becomes the highest seen, and it keeps its earlier end time until the new attack ends. **Recorded** shows when the event last changed.

## Find an event

1. In the [dashboard](https://www.coritan.com/dashboard/ddos/events), select **DDoS Shield**, then the **Events** tab.
2. Choose how far back to look: **24 hours**, **7 days**, **30 days** or **All time**. The tab opens on **7 days**, and the window goes by when each event first started.
3. To narrow the list, choose an address in the **All addresses** list or a type in the **All attack types** list.

Each row shows:

- **Started**: the date and time the event started, and how long ago that was.
- **Address**: the address that was attacked. For a subnet, it is the host.
- **Attack**: the type of traffic we dropped, such as `Reflection` or `SYN rate limit`, with the drop reason under it.
- **Peak**: the highest rate in packets per second, with bits per second under it.
- **Duration**: how long the event lasted. While the event has no end time, the duration keeps counting.
- **Status**: `Mitigating` while the event has no end time, and `Mitigated` once it has one.

The tab loads the 200 newest events across your addresses. When the filters match none of them, it shows **No matches**, and **Reset filters** clears both lists and sets the window to **All time**. When there is no event at all, it shows **No attacks yet**.

## Read an event's details

Select a row to open it, and select it again to close it. On a phone, each event is a card: select **Show details**.

**What happened**
: - **Drop reason**: why we dropped the traffic, as in [Attack types](#attack-types).
  - **Why**: the same reason as a code, such as `udp_src_port_in_reflection_blocklist`.
  - **Ports hit**: the dashboard shows `—` here. The API's `payload.top_src_ports` lists the busiest source ports ([With the API](#with-the-api)).
  - **Unique sources**: how many different senders the node saw among the packets it sampled.
  - **Peak**: the highest packets and bits per second in any one second at that node. The bits per second can be an estimate from the packet rate and the average packet size.
  - **Duration**: as in the list.
  - **Volume**: the peak rate multiplied by the duration. It is an upper estimate, because an attack rarely stays at its peak.
  - **Scrubbing node**: the number of the node that recorded the event.
  - **Recorded**: when we last updated the event.

**Heaviest sources**
: A row for each of the busiest senders, up to five. The dashboard shows `—` in place of each address and rate, so read the senders from the API's `top_sources` and `payload.top_sources`.

**Sampled packets**
: Up to eight packets the node sampled, each as `source:port → destination:port`, such as `198.51.100.20:53 → 203.0.113.10:41822`.

## Attack types

The dashboard writes each type in words, such as `SYN rate limit` for `syn_rate_limit`, and the **Why** row shows its code:

| Type | Why code | What we dropped |
|---|---|---|
| `reflection` | `udp_src_port_in_reflection_blocklist` | UDP packets from a port that reflection attacks use ([Reflection ports](/docs/ddos-shield/how-ddos-shield-works/#reflection-ports)). |
| `syn_rate_limit` | `syn_rate_limit_exceeded` | New TCP connections from one sender over the SYN limit. |
| `icmp_rate_limit` | `icmp_rate_limit_exceeded` | ICMP from one sender over the ICMP limit. |
| `customer_rate_limit` | `customer_rate_limit_exceeded` | Packets from one sender over the address's per-source limit. |
| `customer_aggregate` | `customer_aggregate_rate_exceeded` | Traffic to the address over its aggregate limit. |
| `global_rate_limit` | `global_rate_limit_exceeded` | Packets from one sender over the platform-wide limit. |
| `firewall_deny` | `firewall_deny` | Packets stopped by a **Drop** rule, a blocked source, or **When no rule matches** set to **Drop**. |
| `firewall_rate_limit` | `firewall_rate_limit` | Packets over the limit of a **Rate limit** rule. |
| `fragment` | `fragment_drop` | IP fragments. |
| `invalid_protocol` | `proto_not_allowed` | Protocols other than TCP, UDP and ICMP. |
| `tcp_flags` | `invalid_tcp_flags` | TCP packets with a combination of flags that no real connection sends. |
| `udp_oversized` | `udp_payload_oversized` | UDP packets with an oversized payload. |
| `bogon` | `bogon_source` | Packets from addresses that are never used on the internet. |
| `ttl_too_low` | `ttl_below_min` | Packets whose time to live was too low. |
| `ip_options` | `ip_options_present` | Packets that carried IP options. |
| `malformed` | `malformed_packet` | Packets whose TCP, UDP or ICMP header was cut short. |

## What to do about an event

- An event means we dropped the traffic. When your service keeps working, there is nothing to do.
- When the service is down while an attack goes on, follow [Get help during an attack](/docs/ddos-shield/under-attack/).
- When an event shows that we dropped traffic you want, such as `firewall_deny` for your own users or a rate limit that a busy service goes over, change the address's rules or limits on its **Shield** tab ([Change a floating IP's DDoS protection](/docs/floating-ips/shield-settings/)). Limits of your own apply only in **Custom** mode.
- When `reflection` events hit the replies to DNS or NTP requests that your machine sent, see [Reflection ports](/docs/ddos-shield/how-ddos-shield-works/#reflection-ports).

## Troubleshooting

An attack took a service down, and no event shows
: The traffic went to a server's shared address, the address is in **Passthrough**, or the attack passed our checks and limits because it looked like real traffic. An earlier event of the same kind may also have taken the attack in, as [How we record an event](#how-we-record-an-event) explains: choose **All time** and look for a recent **Recorded** time. Then follow [Get help during an attack](/docs/ddos-shield/under-attack/).

One attack shows as several events
: Each scrubbing node records its own event for each reason and each address. Compare their **Started** times to see which belong together.

An event shows `Mitigating` long after the attack ended
: The dashboard shows `Mitigating` for any event without an end time, and an event can stay without one when its node stopped sending updates. The API's `active` field turns `false` once we have had no update for two minutes, and that is the reliable sign that the event is over.

**Heaviest sources** or **Ports hit** shows only `—`
: The dashboard does not read these parts of the event. Read `top_sources`, `payload.top_sources` and `payload.top_src_ports` from the API.

The list stops before the event you want
: The tab loads the 200 newest events. Ask the API for more with a higher `limit`.

**Could not load the events**
: Select **Try again**. If it keeps failing, [contact support](/docs/support/conversations/).

## Related

- [How DDoS Shield works](/docs/ddos-shield/how-ddos-shield-works/)
- [Change a floating IP's DDoS protection](/docs/floating-ips/shield-settings/)
- [Get help during an attack](/docs/ddos-shield/under-attack/)
- [Order and use a custom profile](/docs/ddos-shield/custom-profiles/)

## With the API

`GET /api/v1/client/shield/events` returns the attack events on your floating IPs, newest first. `limit` sets how many come back, 50 by default, and each floating IP contributes at most 500. Send a `limit` of 1 or more.

```bash
curl "https://api.coritan.com/api/v1/client/shield/events?limit=200" \
  -H "Authorization: Bearer $CORITAN_TOKEN"
```

```json
{
  "events": [
    {
      "id": 90211,
      "node_id": 3,
      "session_key": "214:7:cb00710a",
      "subject_id": 214,
      "subject_kind": "service",
      "ip_service_id": 214,
      "inventory_id": 5120,
      "address": "203.0.113.10",
      "attack_type": "reflection",
      "drop_reason_id": 7,
      "drop_reason": "reflection",
      "pps": 184000,
      "bps": 1510000000,
      "unique_sources": 3120,
      "top_sources": "[\"198.51.100.20\", \"198.51.100.21\"]",
      "started_at": "2026-09-25T14:02:11",
      "ended_at": "2026-09-25T14:09:56",
      "received_at": "2026-09-25T14:09:56",
      "active": false,
      "payload": "{\"classification\": \"policy_drop\", \"why_hint\": \"udp_src_port_in_reflection_blocklist\"}"
    }
  ]
}
```

The example shortens `top_sources` and `payload`. Both arrive as JSON text, so parse them before you read them.

| Field | Meaning |
| --- | --- |
| `address`, `ip_service_id` | The address that was attacked, and the service ID of its floating IP. For a subnet, `address` is the host. |
| `attack_type`, `drop_reason` | Why we dropped the traffic, as in [Attack types](#attack-types). `drop_reason_id` is the same reason as a number. |
| `pps`, `bps` | The peak packets and bits per second in one second at the node. `bps` can be an estimate from the packet rate and the average packet size. |
| `unique_sources` | How many different senders the node saw among the packets it sampled. |
| `top_sources` | Up to five of the busiest senders' addresses. |
| `started_at`, `ended_at` | When the event started and ended, in UTC. `ended_at` is `null` until the event ends. |
| `received_at` | When we last updated the event, in UTC. |
| `active` | `true` while the event has no end and we updated it in the last two minutes. |
| `node_id` | The scrubbing node that recorded the event. |

`subject_id`, `subject_kind`, `session_key` and `inventory_id` identify the event on our side. `payload`, once parsed, holds the node's details:

```json
{
  "classification": "policy_drop",
  "drop_reason_id": 7,
  "drop_reason": "reflection",
  "effective_mode": "standard",
  "top_sources": [{"ip": "198.51.100.20", "packets": 41}, {"ip": "198.51.100.21", "packets": 39}],
  "top_src_ports": [{"port": 53, "packets": 7410}, {"port": 123, "packets": 1590}],
  "top_protocols": [{"proto": 17, "packets": 9000}],
  "samples": [
    {"src_ip": "198.51.100.20", "dst_ip": "203.0.113.10", "ip_proto": 17, "src_port": 53, "dst_port": 41822, "ttl": 54, "pkt_len": 1242, "tcp_flags": null, "udp_len": 1208}
  ],
  "why_hint": "udp_src_port_in_reflection_blocklist"
}
```

| Field | Meaning |
| --- | --- |
| `effective_mode` | The protection mode that applied: `standard` or `custom`. |
| `top_sources` | Up to five of the busiest senders, each with how many of the sampled packets came from it. |
| `top_src_ports` | Up to five of the busiest source ports, with their sampled packets. |
| `top_protocols` | Up to five IP protocols by number, such as `17` for UDP, with their sampled packets. |
| `samples` | Up to eight sampled packets, with their addresses, protocol, ports, TTL, length in bytes, TCP flags and UDP length. |
| `why_hint` | The code that the **Why** row shows. |

The example leaves out `threshold_snapshot`, which records the node's own settings. The [DDoS Shield API reference](/docs/api/reference/client/shield/#op-get-api-v1-client-shield-events) lists every field.

## API

- `GET /api/v1/client/shield/events`: Recent attack events for this account's IP services (https://www.coritan.com/docs/api/reference/client/shield/#op-get-api-v1-client-shield-events)
