Arrange bytes for relay

This commit is contained in:
2026-01-18 19:36:50 -05:00
parent 8a53c7366a
commit 9947c21b4c
2 changed files with 145 additions and 72 deletions

View File

@@ -90,79 +90,81 @@ pub fn main(init: std.process.Init) !void {
std.debug.print("dest: {s}\n", .{flags.dest orelse "<null>"}); std.debug.print("dest: {s}\n", .{flags.dest orelse "<null>"});
std.debug.print("connect: {s}\n", .{flags.connect orelse "<null>"}); std.debug.print("connect: {s}\n", .{flags.connect orelse "<null>"});
// 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 }; // const net_interface: std.Io.net.Interface = .{ .index = 1 };
// std.debug.print("Interface: {s}\n", .{(try net_interface.name(init.io)).toSlice()}); // 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) ---
checksum: u16 = 0,
udp_len: u16,
dst_port: u16,
src_port: u16,
const linux_socket = blk: { // --- IP ---
const linux_socket = std.os.linux.socket(AF.PACKET, SOCK.RAW, 0); dst_addr: u32,
const errno = std.os.linux.errno(linux_socket); src_addr: u32,
if (errno != .SUCCESS) { header_checksum: u16 = 0,
std.debug.print("Failed to open socket: {t}\n", .{errno}); protocol: u8 = 17, // udp
return error.Error; // TODO: better error ttl: u8 = 0x40,
}
break :blk linux_socket;
};
const socket_fd = blk: {
const socket_fd = std.os.linux.bind(@intCast(linux_socket), @bitCast(std.os.linux.sockaddr.ll{
// https://codeberg.org/jeffective/gatorcat/src/commit/1da40c85c2d063368e2e5c130e654cb32b6bff0e/src/module/nic.zig#L137
.protocol = std.mem.nativeToBig(u16, @as(u16, std.os.linux.ETH.P.ALL)),
.ifindex = 1,
.hatype = 0,
.pkttype = 0,
.halen = 0,
.addr = @splat(0),
}), @sizeOf(std.os.linux.sockaddr.ll));
const errno = std.os.linux.errno(socket_fd); // 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 = 0,
more_fragments: u1 = 0,
} = .{},
if (errno != .SUCCESS) { id: u16,
std.debug.print("Failed to create link layer socket: {t}\n", .{errno}); total_length: u16,
return error.Error; // TODO: better error tos: u8 = undefined,
}
break :blk socket_fd;
};
const EthIpUdp = struct { // ip_version (4 bits) + ihl (4 bits) = 8 bits
// eth // To have version appear first (high nibble), define it last.
dst_mac: [6]u8 = @splat(0xff), ihl: u4 = 5,
src_mac: [6]u8,
eth_type: u16 = std.os.linux.ETH.P.IP,
// ip
ip_version: u4 = 4, 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;
}
}; };
// const ip: std.Io.net.IpAddress = .{ .ip4 = .unspecified(0) }; const headers: EthIpUdp = .{
// const socket = try ip.bind(init.io, .{ .mode = .rdm, .protocol = .raw }); .src_mac = @splat(0x0e),
// defer socket.close(init.io); .id = 0,
.src_addr = 0,
.dst_addr = @bitCast([_]u8{ 255, 255, 255, 255 }),
.src_port = undefined, // TODO: change this?
.dst_port = 8888,
// try socket.send(init.io, &.{ .ip4 = .{ .bytes = @splat(255), .port = 8888 } }, "foo"); .total_length = undefined,
.udp_len = undefined,
};
std.debug.print("headers: {any}\n", .{&headers.toBytes()});
// var sock_buffer: [1500]u8 = undefined; const relay: SaprusMessage = .{
// var raw_socket_writer: RawSocketWriter = try .init("enp7s0", &sock_buffer); // /proc/net/dev .relay = .{
// var net_buffer: [1500]u8 = undefined; .dest = .fromBytes(&parseDest(flags.dest)),
// var net_writer: NetWriter = try .init(&raw_socket_writer.interface, &net_buffer); .payload = flags.relay.?,
// var client = try SaprusClient.init(&net_writer.interface); },
// defer client.deinit(); };
// if (res.args.relay) |r| { var relay_bytes: [2048]u8 = undefined;
// const dest = parseDest(res.args.dest); std.debug.print("payload: {any}\n", .{relay.toBytes(&relay_bytes)});
// try client.sendRelay(
// if (r.len > 0) r else "Hello darkness my old friend",
// dest,
// );
// return;
// } else if (res.args.connect) |c| {
// if (false) {
// _ = client.connect(if (c.len > 0) c else "Hello darkness my old friend") catch |err| switch (err) {
// error.WouldBlock => null,
// else => return err,
// };
// return;
// }
// @panic("Not implemented");
// }
// return clap.helpToFile(.stderr(), clap.Help, &params, .{});
} }
fn parseDest(in: ?[]const u8) [4]u8 { fn parseDest(in: ?[]const u8) [4]u8 {
@@ -189,16 +191,81 @@ const SaprusClient = zaprus.Client;
const SaprusMessage = zaprus.Message; const SaprusMessage = zaprus.Message;
const RawSocketWriter = zaprus.RawSocketWriter; const RawSocketWriter = zaprus.RawSocketWriter;
// Import C headers for network constants and structs
const c = @cImport({
@cInclude("sys/socket.h");
@cInclude("linux/if_packet.h");
@cInclude("net/ethernet.h");
@cInclude("sys/ioctl.h");
@cInclude("net/if.h");
@cInclude("arpa/inet.h");
});
const AF = std.os.linux.AF; const AF = std.os.linux.AF;
const SOCK = std.os.linux.SOCK; const SOCK = std.os.linux.SOCK;
// const NetWriter = zaprus.NetWriter;
const RawSocket = struct {
fd: i32,
sockaddr_ll: std.posix.sockaddr.ll,
fn init(ifname: []const u8) RawSocket {
const socket: i32 = @intCast(std.os.linux.socket(AF.PACKET, SOCK.RAW, 0));
var ifr: std.posix.ifreq = std.mem.zeroInit(std.posix.ifreq, .{});
@memcpy(ifr.ifrn.name[0..ifname.len], ifname);
ifr.ifrn.name[ifname.len] = 0;
try std.posix.ioctl_SIOCGIFINDEX(socket, &ifr);
const ifindex: i32 = ifr.ifru.ivalue;
var rval = std.posix.errno(std.os.linux.ioctl(socket, std.os.linux.SIOCGIFFLAGS, @intFromPtr(&ifr)));
switch (rval) {
.SUCCESS => {},
else => {
return error.NicError;
},
}
ifr.ifru.flags.BROADCAST = true;
ifr.ifru.flags.PROMISC = true;
rval = std.posix.errno(std.os.linux.ioctl(socket, std.os.linux.SIOCSIFFLAGS, @intFromPtr(&ifr)));
switch (rval) {
.SUCCESS => {},
else => {
return error.NicError;
},
}
std.debug.print("ifindex: {}\n", .{ifindex});
const sockaddr_ll = std.posix.sockaddr.ll{
.family = std.posix.AF.PACKET,
.ifindex = ifindex,
.protocol = std.mem.nativeToBig(u16, @as(u16, std.os.linux.ETH.P.IP)),
.halen = 0, //not used
.addr = .{ 0, 0, 0, 0, 0, 0, 0, 0 }, //not used
.pkttype = 0, //not used
.hatype = 0, //not used
};
_ = std.os.linux.bind(socket, @ptrCast(&sockaddr_ll), @sizeOf(@TypeOf(sockaddr_ll)));
return .{
.fd = socket,
.sockaddr_ll = sockaddr_ll,
};
}
fn deinit() void {}
fn send(self: RawSocket, payload: []const u8) !void {
const sent_bytes = std.os.linux.sendto(
self.fd,
payload.ptr,
payload.len,
0,
@ptrCast(&self.sockaddr_ll),
@sizeOf(@TypeOf(self.sockaddr_ll)),
);
std.debug.assert(sent_bytes == payload.len);
}
fn receive(self: RawSocket, buf: []u8) ![]u8 {
const len = std.os.linux.recvfrom(
self.fd,
buf.ptr,
buf.len,
0, // flags
null,
null,
);
return buf[0..len];
}
};
const Writer = std.Io.Writer;

View File

@@ -22,6 +22,12 @@ pub const Message = union(PacketType) {
pub const Relay = message.Relay; pub const Relay = message.Relay;
pub const Connection = message.Connection; pub const Connection = message.Connection;
pub fn toBytes(self: message.Message, buf: []u8) []u8 {
return switch (self) {
inline else => |m| m.toBytes(buf),
};
}
}; };
pub const relay_dest_len = 4; pub const relay_dest_len = 4;