From e8e31b25e82e264b354e7d3610b7c0be96ba1173 Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Thu, 8 Jan 2026 20:38:17 -0800 Subject: [PATCH] store proper ip strings in new ip2l cache --- src/location/Ip2location.zig | 40 ++++++++++++++++++++++++++---------- src/location/resolver.zig | 7 ++++--- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/location/Ip2location.zig b/src/location/Ip2location.zig index 3968866..05fe038 100644 --- a/src/location/Ip2location.zig +++ b/src/location/Ip2location.zig @@ -232,13 +232,14 @@ pub const Cache = struct { const lat = try std.fmt.parseFloat(f64, lat_str); const lon = try std.fmt.parseFloat(f64, lon_str); - // Parse IP to u128 - const addr = try std.net.Address.parseIp(ip_str, 0); - const ip_u128: u128 = switch (addr.any.family) { - std.posix.AF.INET => @as(u128, @intCast(std.mem.readInt(u32, @ptrCast(&addr.in.sa.addr), .big))), - std.posix.AF.INET6 => std.mem.readInt(u128, @ptrCast(&addr.in6.sa.addr), .big), - else => return error.InvalidIpFamily, - }; + // Try parsing as IP address first, fall back to u128 + const ip_u128 = if (std.net.Address.parseIp(ip_str, 0)) |addr| blk: { + break :blk switch (addr.any.family) { + std.posix.AF.INET => @as(u128, @intCast(std.mem.readInt(u32, @ptrCast(&addr.in.sa.addr), .big))), + std.posix.AF.INET6 => std.mem.readInt(u128, @ptrCast(&addr.in6.sa.addr), .big), + else => return error.InvalidIpFamily, + }; + } else |_| try std.fmt.parseInt(u128, ip_str, 10); const name_copy = try allocator.dupe(u8, name); return .{ @@ -255,7 +256,7 @@ pub const Cache = struct { return self.entries.get(ip); } - pub fn put(self: *Cache, ip: u128, _: u8, loc: Location) !void { + pub fn put(self: *Cache, ip: u128, family: u8, loc: Location) !void { const name_copy = try self.allocator.dupe(u8, loc.name); try self.entries.put(ip, .{ .allocator = self.allocator, @@ -267,8 +268,25 @@ pub const Cache = struct { if (self.file) |file| { try file.seekFromEnd(0); // Format IP as string for file - var buf: [39]u8 = undefined; - const ip_str = try std.fmt.bufPrint(&buf, "{}", .{ip}); + var buf: [64]u8 = undefined; + const ip_str = if (family == 4) + try std.fmt.bufPrint(&buf, "{}.{}.{}.{}", .{ + @as(u8, @truncate(ip >> 24)), + @as(u8, @truncate(ip >> 16)), + @as(u8, @truncate(ip >> 8)), + @as(u8, @truncate(ip)), + }) + else + try std.fmt.bufPrint(&buf, "{x:0>4}:{x:0>4}:{x:0>4}:{x:0>4}:{x:0>4}:{x:0>4}:{x:0>4}:{x:0>4}", .{ + @as(u16, @truncate(ip >> 112)), + @as(u16, @truncate(ip >> 96)), + @as(u16, @truncate(ip >> 80)), + @as(u16, @truncate(ip >> 64)), + @as(u16, @truncate(ip >> 48)), + @as(u16, @truncate(ip >> 32)), + @as(u16, @truncate(ip >> 16)), + @as(u16, @truncate(ip)), + }); const line = try std.fmt.allocPrint(self.allocator, "{s},{d},{d},{s}\n", .{ ip_str, loc.coords.latitude, @@ -323,7 +341,7 @@ test "parseCacheLine: missing fields" { test "parseCacheLine: invalid IP" { const allocator = std.testing.allocator; const line = "not.an.ip,37.5,-122.5,Test"; - try std.testing.expectError(error.InvalidIPAddressFormat, Cache.parseCacheLine(allocator, line)); + try std.testing.expectError(error.InvalidCharacter, Cache.parseCacheLine(allocator, line)); } test "parseCacheLine: invalid latitude" { diff --git a/src/location/resolver.zig b/src/location/resolver.zig index 4c36056..414a4b5 100644 --- a/src/location/resolver.zig +++ b/src/location/resolver.zig @@ -134,9 +134,10 @@ pub const Resolver = struct { return error.LocationNotFound; } - // Format IP address - const ip_str = try std.fmt.allocPrint(self.allocator, "{any}", .{addr_list.addrs[0].any}); - defer self.allocator.free(ip_str); + // Format IP address using std.net.Address.format + const addr = addr_list.addrs[0]; + var buf: [64]u8 = undefined; + const ip_str = try std.fmt.bufPrint(&buf, "{f}", .{addr}); return self.resolveIP(ip_str); }