IP Address Extractor

Paste a log and every IP address in it comes back as a CSV, each one labelled public, private, loopback, link-local, carrier NAT, multicast, documentation or reserved. IPv6 is handled properly, compressed forms and IPv4-mapped addresses included, and the CIDR box filters on real prefix arithmetic rather than string matching.

Try an example loads ten lines of a realistic access log with a mix of both address families.

A list of addresses is rarely the actual question

Nobody reads a log for the pleasure of collecting IP addresses. The question underneath is one of three, and none of them is answered by a plain list:

  • Which of these are ours? Answered by a CIDR filter. Type 10.0.0.0/8 and the output holds only addresses inside your private range; type your public allocation and you get the reverse.
  • Which of these came from outside? Answered by the classification column. Sort on it and the public addresses are together.
  • How many distinct sources are there? Answered by deduplication plus the count in the summary strip.

So all three are on the page by default, and the summary strip reports the split: how many IPv4 and how many IPv6, how many public and how many not routable on the internet.

IPv6 is a first-class citizen here, not an afterthought

Most extractors handle IPv4 and either ignore IPv6 or match it so loosely that timestamps and MAC addresses come through as addresses. Both failures are avoidable, and the fix is the same one: match loosely, then validate properly.

Every one of these is read correctly:

WrittenMeansClass
::1all zeros then 1loopback
2001:db8::1compressed middledocumentation
fe80::1ff:fe23:4567:890alink-local with a compressed runlink-local
::ffff:192.0.2.1an IPv4 address inside IPv6IPv4-mapped
fd00::1unique localprivate
2606:4700::1111a global unicast addresspublic

And these are refused, which is just as important: 10:30:00 is a timestamp and has three groups rather than eight. 00:1A:2B:3C:4D:5E is a MAC address and has six. 2001:db8::1::2 has two compressed runs, which is ambiguous and therefore invalid. Each is rejected because the validation counts groups after expansion, not because a pattern happened to miss it.

The IPv4 tail of a mapped address is not reported as a second, separate address. That sounds obvious and almost nothing gets it right: the dotted quad inside ::ffff:192.0.2.1 matches an IPv4 pattern perfectly, and an extractor that runs two independent passes emits both. This one records which stretches of text the IPv6 pass claimed and the IPv4 pass steps over them.

Worked example: ten log lines

The sample is ten lines of a gateway log. With the defaults on, this comes out:

ip,version,classification
203.0.113.42,IPv4,documentation
198.51.100.9,IPv4,documentation
10.1.4.19,IPv4,private
10.2.8.7,IPv4,private
172.16.0.5,IPv4,private
2001:db8:1::a41,IPv6,documentation
fe80::1ff:fe23:4567:890a,IPv6,link-local
::ffff:192.0.2.1,IPv6,IPv4-mapped
127.0.0.1,IPv4,loopback

Eleven matches became nine rows, because 203.0.113.42 appears twice in the log. The summary strip reads "11 IP addresses found, 2 duplicates removed, 9 in the output, 6 IPv4, 3 IPv6, 0 public, 9 not routable on the internet".

That last count deserves a note. The sample uses 203.0.113.0/24, 198.51.100.0/24 and 192.0.2.0/24, which are the three ranges reserved by the standards body specifically for documentation and examples, so a sample log cannot accidentally point at somebody's real server. That is why the classification says "documentation" rather than "public". Real logs will read "public" for the outside world.

Type 10.0.0.0/8 into the CIDR box and the output narrows to the three private addresses in that block, with the summary reporting six skipped. 172.16.0.5 is private too, but it is in 172.16.0.0/12, not in 10.0.0.0/8, and a filter that told you otherwise would be doing string matching rather than arithmetic.

How the classification is decided

By checking membership of the reserved blocks the standards actually define, in the order that resolves the overlaps:

  • private: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, and fc00::/7 for IPv6. Note that 172.32.0.1 is public: the private block stops at 172.31.255.255, and treating the whole of 172. as private is a common and consequential mistake.
  • loopback: 127.0.0.0/8 and ::1.
  • link-local: 169.254.0.0/16 and fe80::/10. An address here usually means DHCP failed.
  • carrier NAT: 100.64.0.0/10. Shared address space for internet providers. It looks public and is not routable.
  • documentation: 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 and 2001:db8::/32. Reserved for examples.
  • multicast: 224.0.0.0/4 and ff00::/8. reserved: 240.0.0.0/4 and 0.0.0.0/8.
  • public: everything else, meaning an address that could genuinely be routed on the internet.

Leading zeros in an IPv4 octet are refused outright. 010.1.1.1 is octal to some resolvers and decimal to others, which has been the root of more than one security advisory, so an ambiguous address is reported as no address rather than guessed at.

The CIDR filter does arithmetic

Type an address, a slash and a prefix length. The address is masked to its network, every extracted address is masked the same way, and the two are compared as numbers. IPv6 ranges work identically, computed as 128-bit integers, so 2001:db8::/32 correctly includes 2001:db8:1::1 and correctly excludes 2001:db9::1.

Ranges worth keeping to hand:

  • 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16: the private blocks, one at a time.
  • 100.64.0.0/10: carrier-grade NAT, which is where a surprising share of consumer traffic now originates.
  • 169.254.0.0/16: link-local, which in a log means something failed to get an address.
  • ::/0 or 0.0.0.0/0: everything of that family, which is a quick way to split IPv6 from IPv4.

A range the parser cannot read does not silently filter everything away. It says so in a note, names what it expected, and leaves the full result in place.

Frequently Asked Questions

Does it find IPv6 addresses inside a log full of timestamps?

Yes, and it does not mistake the timestamps for addresses. A candidate is matched loosely and then validated by expanding it to eight 16-bit groups. 10:30:00 expands to three groups and is refused; a MAC address expands to six and is refused. Only something that genuinely resolves to eight groups comes through.

Why is 172.32.0.1 classified as public?

Because it is. The private range is 172.16.0.0/12, which covers 172.16.0.0 through 172.31.255.255. Anything from 172.32.0.0 up is ordinary public address space. Treating all of 172. as private is a widespread assumption and a wrong one.

Can I filter to more than one range at a time?

Not in one pass. Run it once per range, or pick the wider prefix that covers both. For the three private blocks specifically, the classification column already does the job in one go: sort or filter on private and you have all three.

What happens to an address with a port on the end?

For IPv4, 203.0.113.42:8080 gives you the address and the port is left behind, which is what you want. For IPv6 the convention is to bracket the address, as in [2001:db8::1]:8080, and the brackets act as boundaries so that works too. An unbracketed IPv6 address with a port is genuinely ambiguous and no tool can resolve it reliably.

How big a log can I paste?

Up to 100 MB as a dropped file, with no line limit under that. Pasting is limited by what your browser will hold in a textarea, which is usually a few megabytes; for anything larger, drop the file instead.

Are the addresses in log order?

IPv4 and IPv6 are found in two passes, so the two families come out grouped rather than interleaved in strict document order. Within each family the order is the order they appeared. Tick "Sort numerically" and you get a proper numeric sort, where 10.0.0.9 comes before 10.0.0.100 rather than after it the way a text sort would have it.

Does anything I paste leave my computer?

No. There is no upload endpoint on this page and no network request in the code that does the work. JavaScript in your own tab reads the text, processes it and hands back the result. Nothing is stored between visits either, so reloading gives you an empty box again. You can confirm it by opening your browser's network panel and watching it stay quiet while you work.

Read the log, not the addresses

Free, no account, no upload. Paste the lines, filter the range, take the classified CSV.

Back to the extractor