summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobby Zambito <contact@robbyzambito.me>2026-01-18 19:36:50 -0500
committerRobby Zambito <contact@robbyzambito.me>2026-01-19 12:12:23 -0500
commit9947c21b4cdc8dea7ee456cdf76226807614d091 (patch)
treebab774b358687158a602102f882c0e5b5c3b13a5 /src
parent8a53c7366aca7530bdb367ea46293a6109000d41 (diff)
Arrange bytes for relay
Diffstat (limited to 'src')
-rw-r--r--src/main.zig217
-rw-r--r--src/message.zig6
2 files changed, 148 insertions, 75 deletions
diff --git a/src/main.zig b/src/main.zig
index b9d9e88..d128e33 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -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("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 };
// 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,
+
+ // --- IP ---
+ 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 = 0,
+ more_fragments: u1 = 0,
+ } = .{},
+
+ id: u16,
+ total_length: 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),
- const linux_socket = blk: {
- const linux_socket = std.os.linux.socket(AF.PACKET, SOCK.RAW, 0);
- const errno = std.os.linux.errno(linux_socket);
- if (errno != .SUCCESS) {
- std.debug.print("Failed to open socket: {t}\n", .{errno});
- return error.Error; // TODO: better error
+ 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;
}
- 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);
-
- if (errno != .SUCCESS) {
- std.debug.print("Failed to create link layer socket: {t}\n", .{errno});
- return error.Error; // TODO: better error
- }
- break :blk socket_fd;
+
+ const headers: EthIpUdp = .{
+ .src_mac = @splat(0x0e),
+ .id = 0,
+ .src_addr = 0,
+ .dst_addr = @bitCast([_]u8{ 255, 255, 255, 255 }),
+ .src_port = undefined, // TODO: change this?
+ .dst_port = 8888,
+
+ .total_length = undefined,
+ .udp_len = undefined,
};
+ std.debug.print("headers: {any}\n", .{&headers.toBytes()});
- const EthIpUdp = struct {
- // eth
- dst_mac: [6]u8 = @splat(0xff),
- src_mac: [6]u8,
- eth_type: u16 = std.os.linux.ETH.P.IP,
- // ip
- ip_version: u4 = 4,
+ const relay: SaprusMessage = .{
+ .relay = .{
+ .dest = .fromBytes(&parseDest(flags.dest)),
+ .payload = flags.relay.?,
+ },
};
- // const ip: std.Io.net.IpAddress = .{ .ip4 = .unspecified(0) };
- // const socket = try ip.bind(init.io, .{ .mode = .rdm, .protocol = .raw });
- // defer socket.close(init.io);
-
- // try socket.send(init.io, &.{ .ip4 = .{ .bytes = @splat(255), .port = 8888 } }, "foo");
-
- // var sock_buffer: [1500]u8 = undefined;
- // var raw_socket_writer: RawSocketWriter = try .init("enp7s0", &sock_buffer); // /proc/net/dev
- // var net_buffer: [1500]u8 = undefined;
- // var net_writer: NetWriter = try .init(&raw_socket_writer.interface, &net_buffer);
- // var client = try SaprusClient.init(&net_writer.interface);
- // defer client.deinit();
-
- // if (res.args.relay) |r| {
- // const dest = parseDest(res.args.dest);
- // 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, .{});
+ var relay_bytes: [2048]u8 = undefined;
+ std.debug.print("payload: {any}\n", .{relay.toBytes(&relay_bytes)});
}
fn parseDest(in: ?[]const u8) [4]u8 {
@@ -189,16 +191,81 @@ const SaprusClient = zaprus.Client;
const SaprusMessage = zaprus.Message;
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 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;
diff --git a/src/message.zig b/src/message.zig
index c847fc9..0f7bef5 100644
--- a/src/message.zig
+++ b/src/message.zig
@@ -22,6 +22,12 @@ pub const Message = union(PacketType) {
pub const Relay = message.Relay;
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;