Parse v6 address correctly, first working version
This commit is contained in:
parent
056da26cc0
commit
1657a643ff
3 changed files with 148 additions and 17 deletions
|
@ -20,8 +20,8 @@ pub fn build(b: *std.Build) void {
|
|||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
});
|
||||
exe.addIncludePath(.{ .path = "lib" });
|
||||
|
||||
// This declares intent for the executable to be installed into the
|
||||
// standard location when the user invokes the "install" step (the default
|
||||
|
@ -58,7 +58,6 @@ pub fn build(b: *std.Build) void {
|
|||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
sockets_unit_tests.addIncludePath(.{ .path = "lib" });
|
||||
|
||||
const run_sockets_unit_tests = b.addRunArtifact(sockets_unit_tests);
|
||||
run_sockets_unit_tests.has_side_effects = true; // needed so tests aren't cached
|
||||
|
@ -70,7 +69,6 @@ pub fn build(b: *std.Build) void {
|
|||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
process_unit_tests.addIncludePath(.{ .path = "lib" });
|
||||
|
||||
const run_process_unit_tests = b.addRunArtifact(process_unit_tests);
|
||||
run_process_unit_tests.has_side_effects = true; // needed so tests aren't cached
|
||||
|
@ -79,8 +77,8 @@ pub fn build(b: *std.Build) void {
|
|||
.root_source_file = b.path("src/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.link_libc = true,
|
||||
});
|
||||
exe_unit_tests.addIncludePath(.{ .path = "lib" });
|
||||
|
||||
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
||||
|
||||
|
|
132
src/main.zig
132
src/main.zig
|
@ -1,6 +1,11 @@
|
|||
const std = @import("std");
|
||||
const sockets = @import("sockets.zig");
|
||||
const process = @import("process.zig");
|
||||
const c = @cImport({
|
||||
@cInclude("pwd.h");
|
||||
@cInclude("arpa/inet.h");
|
||||
@cInclude("signal.h");
|
||||
});
|
||||
|
||||
pub const std_options = .{ .log_level = .info };
|
||||
|
||||
|
@ -14,19 +19,124 @@ pub fn main() !void {
|
|||
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
const clog_sockets = try sockets.parse(alloc, null);
|
||||
defer alloc.free(clog_sockets);
|
||||
const pids = try print_clogs(alloc, port);
|
||||
defer alloc.free(pids);
|
||||
|
||||
for (clog_sockets) |clog_socket| {
|
||||
if (clog_socket.port == port) {
|
||||
const p = try process.find_by_inode(alloc, clog_socket.inode, null);
|
||||
defer p.deinit();
|
||||
switch (clog_socket.protocol_data) {
|
||||
.tcp_v4 => |v4| std.log.info("Found process {any} clogging address {any}", .{ p, v4.addr }),
|
||||
.udp_v4 => |v4| std.log.info("Found process {any} clogging address {any}", .{ p, v4.addr }),
|
||||
.tcp_v6 => |v6| std.log.info("Found process {any} clogging address {any}", .{ p, v6.addr }),
|
||||
.udp_v6 => |v6| std.log.info("Found process {any} clogging address {any}", .{ p, v6.addr }),
|
||||
if (pids.len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const kill_pids = try choose_kill();
|
||||
|
||||
kill(&[_]std.posix.pid_t{
|
||||
pids[kill_pids[0]],
|
||||
});
|
||||
}
|
||||
|
||||
fn kill(pids: []const std.posix.pid_t) void {
|
||||
for (pids) |pid| {
|
||||
if (c.kill(pid, c.SIGTERM) == 0) {
|
||||
// Wait briefly for process to exit
|
||||
std.time.sleep(100000000); // 100ms
|
||||
|
||||
// Check if process still exists
|
||||
if (c.kill(pid, 0) == 0) {
|
||||
_ = c.kill(pid, c.SIGKILL); // now try with force
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn choose_kill() ![]usize {
|
||||
var stdin = std.io.getStdIn().reader();
|
||||
var stdout = std.io.getStdOut().writer();
|
||||
|
||||
try stdout.writeAll("Kill? ");
|
||||
|
||||
var buf: [2]u8 = undefined;
|
||||
_ = try stdin.readUntilDelimiter(&buf, '\n');
|
||||
|
||||
var kills = [_]usize{
|
||||
(try std.fmt.parseInt(usize, buf[0..1], 10)) - 1,
|
||||
};
|
||||
|
||||
return &kills;
|
||||
}
|
||||
|
||||
fn print_clogs(alloc: std.mem.Allocator, port: u16) ![]std.posix.pid_t {
|
||||
var writer = std.io.getStdOut().writer();
|
||||
var pids = std.ArrayList(std.posix.pid_t).init(alloc);
|
||||
defer pids.deinit(); // noop after re-owning memory at end
|
||||
|
||||
const clog_sockets = try sockets.parse(alloc, null);
|
||||
defer alloc.free(clog_sockets);
|
||||
|
||||
var any: bool = false;
|
||||
for (clog_sockets) |cs| {
|
||||
if (cs.port == port) any = true;
|
||||
}
|
||||
if (!any) {
|
||||
try writer.print("Port {d} looks unclogged\n", .{port});
|
||||
return &[_]std.posix.pid_t{};
|
||||
}
|
||||
|
||||
try writer.print("{s: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {s: <6} {s: <5}\n", .{ "#", "Command", "Path", "Protocol", "Address", "User", "Inode", "Port" });
|
||||
var idx: usize = 1;
|
||||
|
||||
for (clog_sockets) |cs| {
|
||||
if (cs.port == port) {
|
||||
const clogs = try process.find_by_inode(alloc, cs.inode, null);
|
||||
defer clogs.deinit();
|
||||
|
||||
const user = c.getpwuid(cs.uid);
|
||||
|
||||
for (clogs.items) |clog| {
|
||||
switch (cs.protocol_data) {
|
||||
// zig fmt: off
|
||||
.tcp_v4 => |proto| {
|
||||
var addr: [c.INET_ADDRSTRLEN:0]u8 = undefined;
|
||||
_ = c.inet_ntop(c.AF_INET, &proto.addr, &addr, c.INET_ADDRSTRLEN);
|
||||
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
||||
idx,
|
||||
clog.comm[0..@min(10, clog.comm.len)], clog.exe[0..@min(30, clog.exe.len)],
|
||||
"TCP/IPv4", std.mem.sliceTo(&addr, 0),
|
||||
user.*.pw_name, cs.inode, cs.port });
|
||||
},
|
||||
.tcp_v6 => |proto| {
|
||||
var addr: [c.INET6_ADDRSTRLEN:0]u8 = undefined;
|
||||
_ = c.inet_ntop(c.AF_INET6, &proto.addr, &addr, c.INET6_ADDRSTRLEN);
|
||||
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
||||
idx,
|
||||
clog.comm[0..@min(10, clog.comm.len)], clog.exe[0..@min(30, clog.exe.len)],
|
||||
"TCP/IPv6", std.mem.sliceTo(&addr, 0),
|
||||
user.*.pw_name, cs.inode, cs.port });
|
||||
},
|
||||
.udp_v4 => |proto| {
|
||||
var addr: [c.INET_ADDRSTRLEN:0]u8 = undefined;
|
||||
_ = c.inet_ntop(c.AF_INET, &proto.addr, &addr, c.INET_ADDRSTRLEN);
|
||||
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
||||
idx,
|
||||
clog.comm[0..@min(10, clog.comm.len)], clog.exe[0..@min(30, clog.exe.len)],
|
||||
"UDP/IPv4", std.mem.sliceTo(&addr, 0),
|
||||
user.*.pw_name, cs.inode, cs.port });
|
||||
},
|
||||
.udp_v6 => |proto| {
|
||||
var addr: [c.INET6_ADDRSTRLEN:0]u8 = undefined;
|
||||
_ = c.inet_ntop(c.AF_INET6, &proto.addr, &addr, c.INET6_ADDRSTRLEN);
|
||||
try writer.print("{d: <3}{s: <10} {s: <30} {s: <12} {s: <15} {s: <10} {d: <6} {d: <5}\n", .{
|
||||
idx,
|
||||
clog.comm[0..@min(10, clog.comm.len)], clog.exe[0..@min(30, clog.exe.len)],
|
||||
"UDP/IPv6", std.mem.sliceTo(&addr, 0),
|
||||
user.*.pw_name, cs.inode, cs.port });
|
||||
},
|
||||
// zig fmt: on
|
||||
}
|
||||
|
||||
try pids.append(clog.pid);
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pids.toOwnedSlice();
|
||||
}
|
||||
|
|
|
@ -124,15 +124,38 @@ fn parse_internal(path: []const u8, protocol: Protocol, buf: *std.ArrayList(Clog
|
|||
.uid = try std.fmt.parseInt(std.posix.uid_t, uid, 10),
|
||||
.protocol_data = switch (protocol) {
|
||||
.tcp_v4 => .{ .tcp_v4 = .{ .addr = try std.fmt.parseInt(u32, local_address[0..8], 16) } },
|
||||
.tcp_v6 => .{ .tcp_v6 = .{ .addr = try std.fmt.parseInt(u128, local_address[0..32], 16) } },
|
||||
.tcp_v6 => .{ .tcp_v6 = .{ .addr = try parse_v6_address(local_address[0..32]) } },
|
||||
|
||||
.udp_v4 => .{ .udp_v4 = .{ .addr = try std.fmt.parseInt(u32, local_address[0..8], 16) } },
|
||||
.udp_v6 => .{ .udp_v6 = .{ .addr = try std.fmt.parseInt(u128, local_address[0..32], 16) } },
|
||||
.udp_v6 => .{ .udp_v6 = .{ .addr = try parse_v6_address(local_address[0..32]) } },
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// v6 addresses in /proc/net are not actually one big number, but an array of 4
|
||||
// 32-bit (4 byte) numbers, each in base-16 little-endian (or just host byte order
|
||||
// probably)
|
||||
fn parse_v6_address(data: []const u8) !u128 {
|
||||
var buf: [4]u32 = undefined;
|
||||
|
||||
buf[0] = try std.fmt.parseInt(u32, data[0..8], 16);
|
||||
buf[1] = try std.fmt.parseInt(u32, data[8..16], 16);
|
||||
buf[2] = try std.fmt.parseInt(u32, data[16..24], 16);
|
||||
buf[3] = try std.fmt.parseInt(u32, data[24..32], 16);
|
||||
|
||||
// now do the fun stuff, just re-interpret the array as u128
|
||||
return std.mem.bytesToValue(u128, &buf);
|
||||
}
|
||||
|
||||
test "parse_v6" {
|
||||
std.testing.log_level = .info;
|
||||
|
||||
const data = "00000000000000000000000001000000";
|
||||
const r = try parse_v6_address(data);
|
||||
std.log.info("Got {d}", .{r});
|
||||
}
|
||||
|
||||
test "parse" {
|
||||
var alloc = std.testing.allocator;
|
||||
|
||||
|
|
Loading…
Reference in a new issue