From 213a01afc8407749e31a350c52a5809b5394a918 Mon Sep 17 00:00:00 2001 From: Robby Zambito Date: Tue, 20 Jan 2026 22:41:53 -0500 Subject: Implemented client and connection --- src/main.zig | 197 ++++++----------------------------------------------------- 1 file changed, 18 insertions(+), 179 deletions(-) (limited to 'src/main.zig') diff --git a/src/main.zig b/src/main.zig index 3b7ed80..665498b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -90,170 +90,29 @@ pub fn main(init: std.process.Init) !void { return error.InvalidArguments; } - const rand = blk: { - const io_source: std.Random.IoSource = .{ .io = init.io }; - break :blk io_source.interface(); - }; - - // const net_interface: std.Io.net.Interface = .{ .index = 1 }; - // std.debug.print("Interface: {s}\n", .{(try net_interface.name(init.io)).toSlice()}); - const EthIpUdp = packed struct(u336) { // 42 bytes * 8 bits = 336 - // --- UDP (Last in memory, defined first for LSB->MSB) --- - udp: packed struct { - checksum: u16 = 0, - len: u16, - dst_port: u16, - src_port: u16, - }, - - // --- IP --- - ip: packed struct { - dst_addr: u32, - src_addr: u32, - header_checksum: u16 = 0, - protocol: u8 = 17, // udp - ttl: u8 = 0x40, - - // fragment_offset (13 bits) + flags (3 bits) = 16 bits - // In Big Endian, flags are the high bits of the first byte. - // To have flags appear first in the stream, define them last here. - fragment_offset: u13 = 0, - flags: packed struct(u3) { - reserved: u1 = 0, - dont_fragment: u1 = 1, - more_fragments: u1 = 0, - } = .{}, - - id: u16, - len: u16, - tos: u8 = undefined, - - // ip_version (4 bits) + ihl (4 bits) = 8 bits - // To have version appear first (high nibble), define it last. - ihl: u4 = 5, - ip_version: u4 = 4, - }, - - // --- Ethernet --- - eth_type: u16 = std.os.linux.ETH.P.IP, - src_mac: @Vector(6, u8), - dst_mac: @Vector(6, u8) = @splat(0xff), - - fn toBytes(self: @This()) [336 / 8]u8 { - var res: [336 / 8]u8 = undefined; - var w: Writer = .fixed(&res); - w.writeStruct(self, .big) catch unreachable; - return res; - } - - fn setPayloadLen(self: *@This(), len: usize) void { - self.ip.len = @intCast(len + (@bitSizeOf(@TypeOf(self.udp)) / 8) + (@bitSizeOf(@TypeOf(self.ip)) / 8)); - self.udp.len = @intCast(len + (@bitSizeOf(@TypeOf(self.udp)) / 8)); - } - }; - - var socket: RawSocket = try .init(); - defer socket.deinit(); - - var headers: EthIpUdp = .{ - .src_mac = socket.mac, - .ip = .{ - .id = rand.int(u16), - .src_addr = 0, //rand.int(u32), - .dst_addr = @bitCast([_]u8{ 255, 255, 255, 255 }), - .len = undefined, - }, - .udp = .{ - .src_port = rand.intRangeAtMost(u16, 1025, std.math.maxInt(u16)), - .dst_port = 8888, - .len = undefined, - }, - }; + var client: SaprusClient = try .init(); + defer client.deinit(); if (flags.relay != null) { - const relay: SaprusMessage = .{ - .relay = .{ - .dest = .fromBytes(&parseDest(flags.dest)), - .payload = flags.relay.?, - }, - }; - - var relay_buf: [2048]u8 = undefined; - const relay_bytes = relay.toBytes(&relay_buf); - headers.setPayloadLen(relay_bytes.len); - - const full_msg = blk: { - var msg_buf: [2048]u8 = undefined; - var msg_w: Writer = .fixed(&msg_buf); - msg_w.writeAll(&headers.toBytes()) catch unreachable; - msg_w.writeAll(relay_bytes) catch unreachable; - break :blk msg_w.buffered(); - }; - - try socket.send(full_msg); + try client.sendRelay(init.io, flags.relay.?, parseDest(flags.dest)); return; } if (flags.connect != null) { reconnect: while (true) { - headers.udp.dst_port = 8888; - const dest = rand.intRangeAtMost(u16, 1025, std.math.maxInt(u16)); - const src = rand.intRangeAtMost(u16, 1025, std.math.maxInt(u16)); - // udp dest port should not be 8888 after first - const udp_dest_port = rand.intRangeAtMost(u16, 9000, std.math.maxInt(u16)); - var connection: SaprusMessage = .{ - .connection = .{ - .src = src, - .dest = dest, - .seq = undefined, - .id = undefined, - .payload = flags.connect.?, - }, - }; - - try socket.attachSaprusPortFilter(src); - - var connection_buf: [2048]u8 = undefined; - var connection_bytes = connection.toBytes(&connection_buf); - headers.setPayloadLen(connection_bytes.len); - - var full_msg = blk: { - var msg_buf: [2048]u8 = undefined; - var msg_w: Writer = .fixed(&msg_buf); - msg_w.writeAll(&headers.toBytes()) catch unreachable; - msg_w.writeAll(connection_bytes) catch unreachable; - break :blk msg_w.buffered(); - }; - - socket.send(full_msg) catch continue; - var res_buf: [4096]u8 = undefined; - - var res = socket.receive(&res_buf) catch continue; - try init.io.sleep(.fromMilliseconds(40), .real); - - headers.udp.dst_port = udp_dest_port; - headers.ip.id = rand.int(u16); - - full_msg = blk: { - var msg_buf: [2048]u8 = undefined; - var msg_w: Writer = .fixed(&msg_buf); - msg_w.writeAll(&headers.toBytes()) catch unreachable; - msg_w.writeAll(connection_bytes) catch unreachable; - break :blk msg_w.buffered(); - }; - socket.send(full_msg) catch continue; + var connection = try client.connect(init.io, flags.connect.?); while (true) { - res = socket.receive(&res_buf) catch continue :reconnect; - try init.io.sleep(.fromMilliseconds(40), .real); - const connection_res = blk: { - const msg: SaprusMessage = try .parse(res[42..]); - break :blk msg.connection; - }; + var res_buf: [2048]u8 = undefined; + const next = connection.next(init.io, &res_buf) catch continue :reconnect; + const b64d = std.base64.standard.Decoder; - var connection_payload_buf: [4096]u8 = undefined; - const connection_payload = connection_payload_buf[0..try b64d.calcSizeForSlice(connection_res.payload)]; - try b64d.decode(connection_payload, connection_res.payload); + var connection_payload_buf: [2048]u8 = undefined; + const connection_payload = connection_payload_buf[0..try b64d.calcSizeForSlice(next)]; + b64d.decode(connection_payload, next) catch { + // TODO: debug log + continue; + }; const child = std.process.spawn(init.io, .{ .argv = &.{ "bash", "-c", connection_payload }, @@ -266,29 +125,15 @@ pub fn main(init: std.process.Init) !void { var child_stderr: std.ArrayList(u8) = .empty; defer child_stderr.deinit(init.gpa); - try child.collectOutput(init.gpa, &child_stdout, &child_stderr, 4096); + try child.collectOutput(init.gpa, &child_stdout, &child_stderr, 2048); const b64e = std.base64.standard.Encoder; - var cmd_output_buf: [4096]u8 = undefined; - const cmd_output = b64e.encode(&cmd_output_buf, child_stdout.items); - - connection.connection.payload = cmd_output; - connection_bytes = connection.toBytes(&connection_buf); - headers.setPayloadLen(connection_bytes.len); - headers.ip.id = rand.int(u16); - - full_msg = blk: { - var msg_buf: [2048]u8 = undefined; - var msg_w: Writer = .fixed(&msg_buf); - msg_w.writeAll(&headers.toBytes()) catch continue; - msg_w.writeAll(connection_bytes) catch continue; - break :blk msg_w.buffered(); - }; + var cmd_output_buf: [2048]u8 = undefined; + const encoded_cmd_output = b64e.encode(&cmd_output_buf, child_stdout.items); - try socket.send(full_msg); + connection.send(init.io, encoded_cmd_output) catch continue; + try init.io.sleep(.fromMilliseconds(40), .real); } - - return; } } @@ -317,11 +162,5 @@ const StaticStringMap = std.StaticStringMap; const zaprus = @import("zaprus"); const SaprusClient = zaprus.Client; const SaprusMessage = zaprus.Message; -const RawSocketWriter = zaprus.RawSocketWriter; - -const AF = std.os.linux.AF; -const SOCK = std.os.linux.SOCK; - -const RawSocket = @import("./RawSocket.zig"); const Writer = std.Io.Writer; -- cgit