Makko, the people-oriented static site generator made for blogging.
forge.starlightnet.work/Team/Makko
ssg
static-site-generator
makko
starlight-network
1const std = @import("std");
2
3const sockaddr = std.posix.sockaddr;
4
5const in_addr = extern struct {
6 s_addr: u32,
7};
8
9const ifaddrs = extern struct {
10 ifa_next: ?*ifaddrs,
11 ifa_name: [*]const u8,
12 ifa_flags: u32,
13 ifa_addr: ?*sockaddr,
14 ifa_netmask: ?*sockaddr,
15 ifa_ifu: ?*sockaddr,
16 ifa_data: ?*anyopaque,
17};
18
19extern fn getifaddrs(ifap: *?*ifaddrs) c_int;
20extern fn freeifaddrs(ifa: *ifaddrs) void;
21
22extern fn inet_ntop(
23 af: c_int,
24 src: *const anyopaque,
25 dst: [*]u8,
26 size: std.posix.socklen_t,
27) ?[*]u8;
28
29const INET_ADDRSTRLEN = 16;
30const INADDR_LOOPBACK: u32 = std.mem.nativeToBig(u32, 0x7f000001);
31
32fn getLanIP_unix(out: *[32]u8) ![]u8 {
33 var ifap: ?*ifaddrs = null;
34
35 if (getifaddrs(&ifap) != 0)
36 return error.GetIfAddrsFailed;
37
38 defer freeifaddrs(ifap.?);
39
40 var buf: [INET_ADDRSTRLEN]u8 = undefined;
41
42 var cursor = ifap;
43 while (cursor) |ifa| : (cursor = ifa.ifa_next) {
44 const addr = ifa.ifa_addr orelse continue;
45 if (addr.family != std.posix.AF.INET) continue;
46
47 const sa: *const sockaddr.in = @ptrCast(@alignCast(addr));
48
49 if (sa.addr == INADDR_LOOPBACK)
50 continue;
51
52 if (inet_ntop(std.posix.AF.INET, &sa.addr, &buf, buf.len) != null) {
53 const size = std.mem.indexOfScalar(u8, &buf, 0) orelse buf.len;
54 @memcpy(out[0..size], buf[0..size]);
55
56 return out[0..size];
57 }
58 }
59
60 return error.CannotFindIP;
61}
62
63fn getLanIP_windows(out: *[32]u8) !?[]u8 {
64 const gpa = std.heap.page_allocator;
65
66 var child = std.process.Child.init(
67 &[_][]const u8{
68 "powershell",
69 "-NoProfile",
70 "-Command",
71 "Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -ne '127.0.0.1' -and $_.PrefixOrigin -ne 'WellKnown' } | Select-Object -First 1 -ExpandProperty IPAddress",
72 },
73 gpa,
74 );
75
76 child.stdout_behavior = .Pipe;
77 child.stderr_behavior = .Ignore;
78
79 try child.spawn();
80
81 // Capture stdout
82 var stdout = child.stdout.?;
83 var buf = std.ArrayList(u8).init(gpa);
84 defer buf.deinit();
85
86 try stdout.reader().readAllArrayList(&buf, 4096);
87
88 _ = try child.wait();
89
90 var trimmed = std.mem.trim(u8, buf.items, " \r\n\t");
91 if (trimmed.len == 0) return null;
92
93 const size = @min(out.len, trimmed.len);
94 @memcpy(out[0..size], trimmed[0..size]);
95 return out[0..size];
96}
97
98pub fn getLanIP(out: *[32]u8) ?[]u8 {
99 const os = @import("builtin").os.tag;
100
101 return switch (os) {
102 .windows => return getLanIP_windows(out) catch null,
103 .linux, .macos, .freebsd => return getLanIP_unix(out) catch null,
104 else => null,
105 };
106}