diff options
Diffstat (limited to 'src/main.zig')
| -rw-r--r-- | src/main.zig | 217 |
1 files changed, 142 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, ¶ms, .{}); + 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; |
