Project Overview
Scripts and output artifacts for analyzing p0f (passive OS fingerprinting) log data captured on a live server. The pipeline: parse p0f logs → GeoIP lookups → visualization/reporting. Data was collected from a server in Japan during June 2015.
There is no build system, no test suite, no CI, and no dependency manifest (no Gemfile). Scripts are standalone and run directly with Ruby.
Files
p0f-parse.rb— Parses raw p0f log lines into structured fields. Takes a p0f log file asARGV[0]. Output is intended for CSV or further data manipulation. The script's=begin/=endblock documents the p0f log format and parsing logic in detail—read it before modifying the parser.geoip-lookup.rb— Performs a GeoIP country lookup on a single IP (passed viaARGV[0]). Requires thegeoipRuby gem and aGeoIP.datdatabase file in the working directory (neither is included in the repo).geoip-map.html— Standalone HTML page using the Google Charts GeoChart visualization to map TCP connection counts by country. Data is hardcoded inline as a JS array.geoip-uniq-tcp-ip-connects.txt— Plain-text list of country names (one per line), output from running geoip lookups against unique source IPs. Used as input for the map visualization.GEOIP TCP Connects.xlsx,OS Fingerprinting Results.xlsx— Spreadsheet exports of analysis results.
Running the Scripts
ruby p0f-parse.rb <p0f-log-file>
ruby geoip-lookup.rb <ip-address>
Gotchas
- p0f log format is variable-length. Field positions shift depending on whether the OS was identified ("UNKNOWN" changes subsequent field positions). The parser uses positional indexing (
parsed[6],parsed[8], etc.) against space-split lines, so any change to p0f's output format will break it. The=beginblock inp0f-parse.rbdocuments which fields are which. p0f-parse.rbhas a hardcoded local IP (localIPaddr = "106.185.54.194") used to distinguish local vs. remote connections. Update this if working with logs from a different server.geoip-lookup.rbuses'$ARGV[0]'(single-quoted string literal, not shell-style$ARGV). In Ruby,$ARGVis the global alias forARGV, so'$ARGV[0]'is treated as a literal string "ARGV[0]" — this is a bug; it should beARGV[0](without quotes or dollar sign).- GeoIP.dat not included. The
geoipgem and the MaxMind GeoIP.dat binary database must be obtained separately. The legacy GeoIP (v1) format is used, not GeoIP2. - Google Charts API in
geoip-map.htmluses the deprecatedhttps://www.google.com/jsapiloader, which may no longer be available. - Version control is Fossil, not Git (repo has
.fslckout, no.git).