/// <summary> /// Gets country code from an IPv4 address. /// </summary> private string getCountryCodeIPv4(IPAddress addr) { // Get IP address as unsigned 32-bit byte[] bytes = addr.GetAddressBytes(); UInt32 val = 0; for (int i = 0; i != bytes.Length; ++i) { val <<= 8; val += bytes[i]; } // Find largest RangeFirst that's not greater than value // Binary search on ranges sorted by their first values int bottom = 0; int top = ip4Ranges.Length - 1; int middle = top >> 1; while (top >= bottom) { if (ip4Ranges[middle].RangeFirst == val) { break; } if (ip4Ranges[middle].RangeFirst > val) { top = middle - 1; } else { bottom = middle + 1; } middle = (bottom + top) >> 1; } // We're looking for equal or nearest smaller while (middle > 0 && ip4Ranges[middle].RangeFirst > val) { --middle; } IPv4Range range = ip4Ranges[middle]; // We just have a larger one: no country if (range.RangeFirst > val) { return(GetNoCountry()); } // We're actually within range: return that country if (range.RangeFirst <= val && range.RangeLast >= val) { return(countries[range.CountryId]); } // No country return(GetNoCountry()); }
/// <summary> /// Serializes IP range data in binary form. /// </summary> public void WriteBin(BinaryWriter bw) { // Number of ranges UInt32 count = (UInt32)ip4Ranges.Length; bw.Write(count); // Write each range for (UInt32 i = 0; i != count; ++i) { IPv4Range range = ip4Ranges[i]; bw.Write(range.RangeFirst); bw.Write(range.RangeLast); bw.Write(range.CountryId); } }
/// <summary> /// Reads IPv4 range file; returns sorted array, with contiguous same-country ranges merged. /// </summary> private IPv4Range[] loadIp4(StreamReader sr) { // Reserve List <IPv4Range> res = new List <IPv4Range>(180000); // Parse file string line; while ((line = sr.ReadLine()) != null) { if (line == string.Empty || line.StartsWith("#")) { continue; } string[] parts = getParts(line); UInt32 first = UInt32.Parse(parts[0]); UInt32 last = UInt32.Parse(parts[1]); string country = parts[5]; byte countryId = getCountryId(country); res.Add(new IPv4Range { RangeFirst = first, RangeLast = last, CountryId = countryId }); } // Sort by range starts res.Sort((a, b) => a.RangeFirst.CompareTo(b.RangeFirst)); // Eliminate duplicates List <IPv4Range> cpy = new List <IPv4Range>(res.Count); cpy.Add(res[0]); for (int i = 1; i < res.Count; ++i) { IPv4Range curr = res[i]; IPv4Range prev = cpy[cpy.Count - 1]; // Current range is contiguous to previous one; same country too if (curr.CountryId == prev.CountryId && curr.RangeFirst == prev.RangeLast + 1) { prev.RangeLast = curr.RangeLast; cpy[cpy.Count - 1] = prev; } // Nop, add new item else { cpy.Add(curr); } } // Return redcued array (with contiguous country ranges merged) return(cpy.ToArray()); }