EZ LearnEZ Learn
Courses
EZ Board
Dashboard
All articles
python-for-cyber-securitypythongeoipcollections-counter

Correlating IP Addresses to Physical Locations

An old landline number carried its city in its area code. A GeoIP lookup does the same for an IP address, turning a bare list of attacking addresses into a map of where an attack is actually coming from.

Ashish Revar18 October 20266 min read
1 video lesson 6:24 total
Sign in to track your progress

Video lesson

A capture full of IP addresses is a list of numbers until you know where each one actually sits in the world. This article turns that list into a map, and then into a ranked table of who is talking to your network the most.

Analogy: The STD code

An old landline number carried its city in its STD code: a number beginning 011 was in Delhi, 022 in Mumbai, 079 in Ahmedabad. You could place a caller on the map before they said a word. A GeoIP lookup does the same for an IP address, mapping it to an approximate country and city based on how address ranges are allocated to providers worldwide. It turns a bare list of attacking addresses into a map of where an attack is coming from.

Tool in focus: PyGeoIP and its modern successor

The original syllabus names pygeoip with MaxMind's legacy GeoLiteCity.dat database. MaxMind has since retired that format in favour of GeoLite2, read by the newer geoip2 package, so a script written today should prefer geoip2 while the idea and most of the surrounding code stay the same. A GeoLite2 database is free to download with a MaxMind account and is refreshed periodically as allocations change.

geolocate_ip.py (current geoip2 package, GeoLite2 database)

import geoip2.database

reader = geoip2.database.Reader("GeoLite2-City.mmdb")

def locate(ip_address):
    try:
        r = reader.city(ip_address)
        return {"country": r.country.name, "city": r.city.name,
                "lat": r.location.latitude, "lon": r.location.longitude}
    except geoip2.errors.AddressNotFoundError:
        return None

info = locate("8.8.8.8")
print(f"{info['city']}, {info['country']}" if info else "Not found")

Caution: This one needs a database file this course cannot ship

geoip2.database.Reader opens a local .mmdb file, which is several megabytes and updated regularly, so it is never bundled with a course. The lab exercise at the end of this unit walks through getting a free one from MaxMind. The function's shape is exactly what you will use once you have it: reader.city() returns a rich object on a match, and raises geoip2.errors.AddressNotFoundError on a miss, which locate() turns into a plain None the rest of a script can check with a simple if.

Turning a capture into a ranked, located list

Correlating every unique source address in a capture with a location turns a list of numbers into intelligence, and the busiest sources are usually the first question an analyst asks of an unfamiliar capture.

correlate_sources.py

# correlate_sources.py
from collections import Counter
import dpkt, socket
from open_capture import read_packets

source_counts = Counter()
for ts, raw in read_packets("capture.pcap"):
    try:
        ip = dpkt.ethernet.Ethernet(raw).data
        source_counts[socket.inet_ntoa(ip.src)] += 1
    except AttributeError:
        continue

for ip_address, count in source_counts.most_common(10):
    info = locate(ip_address)
    where = f"{info['city']}, {info['country']}" if info else "unknown"
    print(f"{ip_address}  ({count} packets)  -  {where}")

Run without a GeoLite2 database attached, the counting half alone, against a lab capture built for this unit, already shows the shape an analyst looks for:

Sample output (counts only; locations need a GeoLite2 database, see above)

185.220.101.44  (600 packets)
45.83.64.12  (600 packets)
103.145.13.9  (600 packets)
10.0.0.9  (40 packets)
10.0.0.20  (5 packets)

Three foreign addresses sending six hundred packets each, against the lab host's handful, are not customers. A capture that looks like this is a distributed attack, and once a GeoLite2 database is attached, the geography would show whether those three sources are spread across the world or clustered in one place, which is the next two articles' subject.

Python concept: collections.Counter

collections.Counter is a dictionary built for tallying. Each time you add a key it increments that key's count, and .most_common(10) returns the ten highest tallies, already sorted. It turns "which source sent the most packets" into two lines of code, a question you will ask constantly in the denial-of-service work ahead.

What a GeoIP lookup can and cannot tell you

It can

Place an address within a country, usually a city, with reasonable confidence for most ranges, based on how address blocks are publicly allocated to ISPs and organisations.

It cannot

Identify a person, confirm an address was not spoofed, or guarantee precision down to a street. A VPN, a proxy, or a compromised relay machine all show the location of that intermediate point, not necessarily the attacker sitting behind it.

Check your understanding

Question 1: Explain the STD-code analogy for GeoIP, and state one thing a GeoIP lookup can and cannot tell you about an attacker.

An old landline's area code placed a caller's city before they said a word, the same way an IP address's allocated range places it in an approximate location before any other evidence is read. It can place an address within a country and usually a city with reasonable confidence; it cannot identify the actual person behind the address or confirm the traffic was not routed through a VPN or proxy that hides the real source.

Question 2: What does Counter.most_common(10) return, and why is it useful on a capture with thousands of packets?

It returns the ten keys with the highest tallies, already sorted from most to least frequent. On a capture with thousands of packets, it is the fastest way to answer "who is sending the most traffic" without writing any sorting logic yourself.

Question 3: In correlate_sources.py, what does the except AttributeError clause actually catch?

A non-IP frame, such as ARP, whose data does not have a .src attribute in the shape the code expects. Accessing .src on something that is not an IP packet raises an AttributeError, and catching it lets the loop skip that one frame and continue with the rest of the capture.

Key takeaway: Key takeaway

A GeoIP lookup turns a bare address into an approximate place, and Counter turns a capture into a ranked list of who is talking the most. Together they are usually the first two questions an analyst asks of an unfamiliar capture, well before reading a single packet's payload.

Assessments

Unit Assessment

Network Traffic Analysis with Python

20 questions30 minPass: 60%

Start exam →

Comprehensive Assessment

Python for Cyber Security: Complete Assessment

100 questions120 minPass: 60%

Start final exam →

Related to this topic

Continue learning

Reference material

Cheatsheet

Python for Cyber Security — Cheatsheet

v1.0

Open resource

MCQ Bank

Python for Cyber Security — MCQ Bank

v1.0

Open resource

Question Bank

Python for Cyber Security — Question Bank

v1.0

Open resource

eBook

Python for Cyber Security — eBook

v1.0

Open resource

Discussion

Loading comments…
More articlesTest your knowledge
EZ MentorAI · Free

Correlating IP Addresses to Physical Locations

Hi! I'm EZ Mentor

Your AI tutor for
Correlating IP Addresses to Physical Locations

Sign in to ask, it's free.

EZ Mentor is AI-powered · Answers may not be perfect · 10 free questions / day

EZ Learn

Structured learning across Reverse Engineering, Cloud Security and Research Methodology, plus games and practice tools. Free, and open to anyone.

Learn

  • Courses
  • EZ Articles
  • EZ Watch
  • EZ Bytes
  • EZ Talks
  • Community

Library & Exams

  • All Resources
  • eBooks & PDFs
  • Question Banks
  • Cheatsheets
  • All Exams
  • EZ Board

EZ Arena

  • EZ Games
  • Byte Rush
  • Firewall Defence
  • 3D Case Files
  • Live Quiz
  • ML Challenges

EZ Cyber Hygiene

  • Hygiene Journey
  • Cyber Safety Check
  • दिशा - Hygiene
  • सजग - Awareness
  • अभ्यास - Practice
  • Scammed? Call 1930

Platform

  • About
  • Contact
  • Events
  • Verify Certificate
  • Terms of Use
  • Disclaimer

© 2026 EZ Learn by EpochZero. Educational content for learning purposes.

Platform Lead: Ashish Revar