summaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig185
1 files changed, 3 insertions, 182 deletions
diff --git a/src/main.zig b/src/main.zig
index 2175cf9..3b7ed80 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -229,6 +229,7 @@ pub fn main(init: std.process.Init) !void {
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);
@@ -244,6 +245,7 @@ pub fn main(init: std.process.Init) !void {
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;
@@ -320,187 +322,6 @@ const RawSocketWriter = zaprus.RawSocketWriter;
const AF = std.os.linux.AF;
const SOCK = std.os.linux.SOCK;
-const RawSocket = struct {
- fd: i32,
- sockaddr_ll: std.posix.sockaddr.ll,
- mac: [6]u8,
-
- const IFF_LOOPBACK = 0x8;
-
- const ifconf = extern struct {
- ifc_len: i32,
- ifc_ifcu: extern union {
- ifcu_buf: ?[*]u8,
- ifcu_req: ?[*]std.os.linux.ifreq,
- },
- };
-
- fn init() !RawSocket {
- const socket: i32 = @intCast(std.os.linux.socket(std.posix.AF.PACKET, std.posix.SOCK.RAW, 0));
- if (socket < 0) return error.SocketError;
-
- // 1. Enumerate interfaces
- var ifreq_storage: [16]std.os.linux.ifreq = undefined;
- var ifc = ifconf{
- .ifc_len = @sizeOf(@TypeOf(ifreq_storage)),
- .ifc_ifcu = .{ .ifcu_req = &ifreq_storage },
- };
-
- if (std.os.linux.ioctl(socket, std.os.linux.SIOCGIFCONF, @intFromPtr(&ifc)) != 0) {
- return error.NicError;
- }
-
- const count = @divExact(ifc.ifc_len, @sizeOf(std.os.linux.ifreq));
- var target_ifr: ?std.os.linux.ifreq = null;
-
- for (ifreq_storage[0..@intCast(count)]) |ifr| {
- var temp_ifr = ifr;
- if (std.os.linux.ioctl(socket, std.os.linux.SIOCGIFFLAGS, @intFromPtr(&temp_ifr)) == 0) {
- // Cast the packed flags to u16 to match the kernel's ifr_flags size
- const flags: u16 = @bitCast(temp_ifr.ifru.flags);
- if (flags & IFF_LOOPBACK != 0) continue;
-
- target_ifr = ifr;
- break;
- }
- }
-
- var ifr = target_ifr orelse return error.NoInterfaceFound;
-
- // 2. Get Interface Index
- if (std.os.linux.ioctl(socket, std.os.linux.SIOCGIFINDEX, @intFromPtr(&ifr)) != 0) {
- return error.NicError;
- }
- const ifindex: i32 = ifr.ifru.ivalue;
-
- // 3. Get Real MAC Address
- if (std.os.linux.ioctl(socket, std.os.linux.SIOCGIFHWADDR, @intFromPtr(&ifr)) != 0) {
- return error.NicError;
- }
- var mac: [6]u8 = ifr.ifru.hwaddr.data[0..6].*;
- std.mem.reverse(u8, &mac);
-
- // 4. Set Flags (Promiscuous/Broadcast)
- if (std.os.linux.ioctl(socket, std.os.linux.SIOCGIFFLAGS, @intFromPtr(&ifr)) != 0) {
- return error.NicError;
- }
- ifr.ifru.flags.BROADCAST = true;
- ifr.ifru.flags.PROMISC = true;
- if (std.os.linux.ioctl(socket, std.os.linux.SIOCSIFFLAGS, @intFromPtr(&ifr)) != 0) {
- return error.NicError;
- }
-
- 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,
- .addr = .{ 0, 0, 0, 0, 0, 0, 0, 0 },
- .pkttype = 0,
- .hatype = 0,
- };
-
- const bind_ret = std.os.linux.bind(socket, @ptrCast(&sockaddr_ll), @sizeOf(@TypeOf(sockaddr_ll)));
- if (bind_ret != 0) return error.BindError;
-
- const timeout: std.os.linux.timeval = .{ .sec = 600, .usec = 0 };
- const timeout_ret = std.os.linux.setsockopt(socket, std.os.linux.SOL.SOCKET, std.os.linux.SO.RCVTIMEO, @ptrCast(&timeout), @sizeOf(@TypeOf(timeout)));
- if (timeout_ret != 0) return error.SetTimeoutError;
-
- return .{
- .fd = socket,
- .sockaddr_ll = sockaddr_ll,
- .mac = mac,
- };
- }
-
- fn deinit(self: *RawSocket) void {
- _ = std.os.linux.close(self.fd);
- self.* = undefined;
- }
-
- 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)),
- );
- _ = sent_bytes;
- }
-
- fn receive(self: RawSocket, buf: []u8) ![]u8 {
- const len = std.os.linux.recvfrom(
- self.fd,
- buf.ptr,
- buf.len,
- 0,
- null,
- null,
- );
- if (std.os.linux.errno(len) != .SUCCESS) {
- return error.Timeout; // TODO: get the real error, assume timeout for now.
- }
- return buf[0..len];
- }
-
- fn attachSaprusPortFilter(self: RawSocket, port: u16) !void {
- const linux = std.os.linux;
- // BPF instruction structure for classic BPF
- const sock_filter = extern struct {
- code: u16,
- jt: u8,
- jf: u8,
- k: u32,
- };
-
- const sock_fprog = extern struct {
- len: u16,
- filter: [*]const sock_filter,
- };
-
- // BPF instruction opcodes
- const BPF_LD = 0x00;
- const BPF_H = 0x08; // Half-word (2 bytes)
- const BPF_ABS = 0x20;
- const BPF_JMP = 0x05;
- const BPF_JEQ = 0x10;
- const BPF_K = 0x00;
- const BPF_RET = 0x06;
-
- // Build the filter program
- const filter = [_]sock_filter{
- // Load 2 bytes at offset 46 (absolute)
- .{ .code = BPF_LD | BPF_H | BPF_ABS, .jt = 0, .jf = 0, .k = 46 },
- // Jump if equal to port (skip 0 if true, skip 1 if false)
- .{ .code = BPF_JMP | BPF_JEQ | BPF_K, .jt = 0, .jf = 1, .k = @as(u32, port) },
- // Return 0xffff (pass)
- .{ .code = BPF_RET | BPF_K, .jt = 0, .jf = 0, .k = 0xffff },
- // Return 0x0 (fail)
- .{ .code = BPF_RET | BPF_K, .jt = 0, .jf = 0, .k = 0x0 },
- };
-
- const fprog = sock_fprog{
- .len = filter.len,
- .filter = &filter,
- };
-
- // Attach filter to socket using setsockopt
- const SO_ATTACH_FILTER = 26;
- const rc = linux.setsockopt(
- self.fd,
- linux.SOL.SOCKET,
- SO_ATTACH_FILTER,
- @ptrCast(&fprog),
- @sizeOf(sock_fprog),
- );
-
- if (rc != 0) {
- return error.BpfAttachFailed;
- }
- }
-};
+const RawSocket = @import("./RawSocket.zig");
const Writer = std.Io.Writer;