const std = @import("std"); const sockaddr = std.posix.sockaddr; const in_addr = extern struct { s_addr: u32, }; const ifaddrs = extern struct { ifa_next: ?*ifaddrs, ifa_name: [*]const u8, ifa_flags: u32, ifa_addr: ?*sockaddr, ifa_netmask: ?*sockaddr, ifa_ifu: ?*sockaddr, ifa_data: ?*anyopaque, }; extern fn getifaddrs(ifap: *?*ifaddrs) c_int; extern fn freeifaddrs(ifa: *ifaddrs) void; extern fn inet_ntop( af: c_int, src: *const anyopaque, dst: [*]u8, size: std.posix.socklen_t, ) ?[*]u8; const INET_ADDRSTRLEN = 16; const INADDR_LOOPBACK: u32 = std.mem.nativeToBig(u32, 0x7f000001); fn getLanIP_unix(out: *[32]u8) ![]u8 { var ifap: ?*ifaddrs = null; if (getifaddrs(&ifap) != 0) return error.GetIfAddrsFailed; defer freeifaddrs(ifap.?); var buf: [INET_ADDRSTRLEN]u8 = undefined; var cursor = ifap; while (cursor) |ifa| : (cursor = ifa.ifa_next) { const addr = ifa.ifa_addr orelse continue; if (addr.family != std.posix.AF.INET) continue; const sa: *const sockaddr.in = @ptrCast(@alignCast(addr)); if (sa.addr == INADDR_LOOPBACK) continue; if (inet_ntop(std.posix.AF.INET, &sa.addr, &buf, buf.len) != null) { const size = std.mem.indexOfScalar(u8, &buf, 0) orelse buf.len; @memcpy(out[0..size], buf[0..size]); return out[0..size]; } } return error.CannotFindIP; } fn getLanIP_windows(out: *[32]u8) !?[]u8 { const gpa = std.heap.page_allocator; var child = std.process.Child.init( &[_][]const u8{ "powershell", "-NoProfile", "-Command", "Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -ne '127.0.0.1' -and $_.PrefixOrigin -ne 'WellKnown' } | Select-Object -First 1 -ExpandProperty IPAddress", }, gpa, ); child.stdout_behavior = .Pipe; child.stderr_behavior = .Ignore; try child.spawn(); // Capture stdout var stdout = child.stdout.?; var buf = std.ArrayList(u8).init(gpa); defer buf.deinit(); try stdout.reader().readAllArrayList(&buf, 4096); _ = try child.wait(); var trimmed = std.mem.trim(u8, buf.items, " \r\n\t"); if (trimmed.len == 0) return null; const size = @min(out.len, trimmed.len); @memcpy(out[0..size], trimmed[0..size]); return out[0..size]; } pub fn getLanIP(out: *[32]u8) ?[]u8 { const os = @import("builtin").os.tag; return switch (os) { .windows => return getLanIP_windows(out) catch null, .linux, .macos, .freebsd => return getLanIP_unix(out) catch null, else => null, }; }