Something happened on Tuesday. You have the access log for the four hours around it: a few thousand lines, a few hundred distinct IP addresses, and no idea which matter. Every one is a lookup you could run, and running all of them is not a plan.
This is the gap between the tools that already exist. Enrichment for a single address is solved. A flat table of a hundred addresses is solved. Neither answers what the log actually poses, which is not "what is this address" but "which of these should I open first".
What follows is how to close that gap: getting the addresses out of arbitrary text without introducing errors, what to set aside, what to rank on, and where a ranking stops being useful. Our log IP triage tool applies exactly the reasoning below.
What triage means here#
Triage borrows its name from emergency medicine, and the borrowing is precise. It does not diagnose. It sorts, so a scarce resource gets spent in a sensible order.
Applied to a log, that means the output is an ordering with a reason attached to each position, not a verdict. Nothing available from an IP address alone can establish that the address is malicious. What the signals can do is tell you that one address is unusual in a way that needs explaining and another is exactly what you would expect. The question driving the sort is how much attention does this deserve, not how guilty is this, and that is enough to spend an hour well instead of badly.
Pulling the addresses out#
Before anything can be ranked, the addresses have to come out of the text, and that is less trivial than it looks. Log lines are not a format. They are whatever the application decided to print: timestamps, version strings, durations, ports, request paths, user agents, and somewhere in the middle, addresses.
A naive four-numbers-and-three-dots pattern gets two things wrong, and both produce wrong answers rather than obvious failures. The string 10.0.0.1.2, an ordinary version number, contains 10.0.0.1, and a careless matcher will report it. So will 192.168.1.1005, which yields a truncated 192.168.1.100 that was never in your log at all.
Both are fixed the same way: refuse any match with another digit or dot pressed against either end. A trailing port such as :443 survives that rule, because a colon is neither a digit nor a dot, so the address matches and the port is simply not part of it.
IPv6 needs the opposite discipline. A pattern loose enough to catch every legal shortening also catches 12:34 out of a timestamp, so the workable approach is to match generously and then validate: at most one ::, every group one to four hex digits, and eight groups unless a :: is shortening them.
Counting matters as much as extracting: an address seen four hundred times and one seen once are different facts, and the ranking needs both.
Most of what you found is internal#
Run that extraction over an internal application log and a large share of what comes back will be addresses that describe nobody on the public internet. They are reserved for other purposes:
10.0.0.0/8,172.16.0.0/12and192.168.0.0/16: the private ranges from RFC 1918, used inside networks everywhere.127.0.0.0/8: loopback. A machine talking to itself.169.254.0.0/16: link-local, defined in RFC 3927, self-assigned when a host cannot reach a DHCP server.100.64.0.0/10: Shared Address Space, allocated by RFC 6598 for carrier-grade NAT. Neither private nor usefully public, it numbers the link between a provider's CGN equipment and customer premises equipment.224.0.0.0and above: multicast and reserved space.
None of these can be geolocated, attributed to an operator, or checked against a blocklist, so none belongs in a ranking. The mistake is to drop them silently. "Thirty-eight of your forty addresses were internal" is a real answer about the log, and a tool that discards them misstates every total it prints. Count them, set them aside, say how many.
If the ranges are unfamiliar, the RFC 1918 write-up covers where they came from, and the CIDR calculator expands any slash notation into a range.
The four signals worth ranking on#
What is left is public addresses. Four signals separate them, and each one means something different.
Tor exit membership. The Tor Project publishes the current list of exit nodes, so this is a direct lookup, not an inference. An exit node is not evidence of wrongdoing — Tor has entirely legitimate users. It is evidence of deliberate anonymisation, uncommon enough in ordinary traffic to be worth explaining.
Blocklist membership. Whether a list operator has already flagged the address for spam, proxy abuse, or compromise. Useful, and second-hand: caveats below.
Hosting or datacenter. Derived from the autonomous system that announces the address. An ASN belonging to a cloud provider, a hosting company, or a commercial VPN says the traffic came from a server rather than somebody's home connection. This is the signal people most often misread. Hosting traffic is ordinary in an API log and odd in a log of human sign-ins, so the tool flags it and you decide which log you are holding. ASNs explained covers what the numbers are; the ASN explorer looks one up.
Residential or business ISP. The bulk of any public-facing log. Deprioritised, never dismissed: a compromised home machine still has a residential address.
There is a fifth outcome that is not a signal at all. Newly allocated space and addresses missing from the geolocation database both land in one bucket with no location and no operator. That is a gap in what you know, not a finding, and it should be labelled as one.
Ordered by the attention each deserves: Tor exit, blocklisted, hosting, residential, unknown.
Why volume is the wrong sort key#
The instinct on opening a log is to sort by count, and it is the wrong instinct. The address at the top of a count-sorted log is almost always a CDN edge node, a monitoring probe, or a search engine crawler, while the single request from a Tor exit sits around line four hundred.
One request from an anonymised exit node matters more than four thousand from a content delivery network, so volume should never promote an address past a stronger signal. It earns its place within a tier: given two hosting addresses with the same story, the one seen two hundred times is the one to open first.
Blocklists are the expensive signal#
Three of those four signals are effectively free once the data is loaded: geolocation and ASN come from a local database, and Tor membership is a set lookup against a cached list. Blocklists are different, because every check is a DNS query that has to leave the building.
The mechanism is standardised in RFC 5782, a neat piece of protocol reuse. To ask whether 192.0.2.99 appears on a list served at bad.example.com, you reverse the octets and query 99.2.0.192.bad.example.com. An A record in the answer means listed, conventionally with the value 127.0.0.2, and an accompanying TXT record carries the reason. No answer means not listed.
That is one query per list, per address. Three lists across a hundred addresses is three hundred round trips, which is not something to do while somebody waits. The workable compromise is a budget: check a small top slice chosen by the signals that were free, then re-rank everything once the answers land. A hit can and does move a row upward, so the cheap preliminary ordering is a spending decision, not the verdict.
The part that is not optional is disclosure. If ten addresses out of a hundred were checked, the output has to say which ten, because a partial check presented as complete reads as "the other ninety are clean" when they were never asked about. Checking one address thoroughly, against more lists and with the per-list result for each, is a different job: the blacklist checker does that, and how to check if an IP is on a blacklist covers reading the result.
Group by operator, not by address#
Fourteen addresses from one hosting provider is one finding, not fourteen. Grouping the ranked rows by autonomous system is the cheapest genuinely useful thing a triage pass does, and it is the step a flat table cannot take for you: a table shows fourteen rows and leaves the pattern for you to notice.
It also changes the next action. Fourteen separate addresses is fourteen lookups; one ASN with fourteen addresses behind it is a single question about whether that provider's range belongs in this log at all.
What a ranking cannot tell you#
Every signal here has a failure mode, and the honest move is to name them.
Geolocation is an estimate. Country is usually right, city often is not, and the database cannot tell you which case you are in. How IP geolocation works covers why the precision it displays is not the precision it has.
ASN classification ages. Address space is reallocated, hosting companies acquire consumer ISPs, and any curated list of datacenter networks is a snapshot of something that keeps moving.
A listing is somebody else's judgement. It was made at some point in the past, for a reason the query itself does not return, and listings go stale. Shared addresses get listed for a neighbour's behaviour.
An address is not a person. NAT, corporate proxies, and mobile carrier gateways all put many users behind one address, so a single address can carry both the legitimate traffic and the traffic you are chasing.
None of that makes a ranking useless. It makes it a shortlist, which is what it was supposed to be.
Working the shortlist#
A good triage pass leaves you with three to five addresses and a reason for each. What happens next is a person doing the actual investigation, and the tools change shape at that point:
- Everything known about one address on a single page — location, operator, our datacenter and VPN classification, Tor status, reverse DNS and a blocklist summary: IOC enrichment. What an indicator of compromise actually tells you covers how much weight each field deserves.
- A flat comparison of many addresses side by side, for when the table really is what you want: bulk IP lookup.
- Whether an address belongs to a VPN or proxy service, and what that implies: the VPN and proxy check.
All three are worth doing on three addresses and worth nobody's time on three hundred. The log gave you volume; triage gives you an order, a reason for it, and an honest note about what it did not check.
Triage a log
Paste raw log lines and get the addresses ranked by what deserves attention first, with Tor exits, blocklisted addresses and hosting infrastructure ahead of ordinary residential traffic. Extracts and counts the addresses for you, sets the internal ones aside instead of dropping them, and names every address it checked against a blocklist.
Work a log →