aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Client.zig12
-rw-r--r--src/EthIpUdp.zig30
-rw-r--r--src/RawSocket.zig2
-rw-r--r--src/main.zig65
4 files changed, 90 insertions, 19 deletions
diff --git a/src/Client.zig b/src/Client.zig
index 2344f83..0c8bb8f 100644
--- a/src/Client.zig
+++ b/src/Client.zig
@@ -46,11 +46,11 @@ pub fn sendRelay(self: *Client, io: Io, payload: []const u8, dest: [4]u8) !void
const rand = io_source.interface();
var headers: EthIpUdp = .{
- .src_mac = self.socket.mac,
+ .src_mac = .fromBytes(self.socket.mac),
.ip = .{
.id = rand.int(u16),
- .src_addr = 0, //rand.int(u32),
- .dst_addr = @bitCast([_]u8{ 255, 255, 255, 255 }),
+ .src_addr = .fromBytes(.{ 0, 0, 0, 0 }), //rand.int(u32),
+ .dst_addr = .fromBytes(.{ 255, 255, 255, 255 }),
.len = undefined,
},
.udp = .{
@@ -86,11 +86,11 @@ pub fn connect(self: Client, io: Io, payload: []const u8) (error{ BpfAttachFaile
const rand = io_source.interface();
var headers: EthIpUdp = .{
- .src_mac = self.socket.mac,
+ .src_mac = .fromBytes(self.socket.mac),
.ip = .{
.id = rand.int(u16),
- .src_addr = 0, //rand.int(u32),
- .dst_addr = @bitCast([_]u8{ 255, 255, 255, 255 }),
+ .src_addr = .fromBytes(.{ 0, 0, 0, 0 }), //rand.int(u32),
+ .dst_addr = .fromBytes(.{ 255, 255, 255, 255 }),
.len = undefined,
},
.udp = .{
diff --git a/src/EthIpUdp.zig b/src/EthIpUdp.zig
index 251ed64..a65a96f 100644
--- a/src/EthIpUdp.zig
+++ b/src/EthIpUdp.zig
@@ -14,6 +14,28 @@
// You should have received a copy of the GNU General Public License along with
// Zaprus. If not, see <https://www.gnu.org/licenses/>.
+pub const IpAddr = packed struct {
+ int: I,
+
+ const V = @Vector(4, u8);
+ const I = u32;
+
+ pub fn fromBytes(s: V) IpAddr {
+ return .{ .int = @bitCast(s) };
+ }
+};
+
+pub const MacAddr = packed struct {
+ int: I,
+
+ const V = @Vector(6, u8);
+ const I = @Int(.unsigned, @bitSizeOf(V));
+
+ pub fn fromBytes(s: V) MacAddr {
+ return .{ .int = @bitCast(s) };
+ }
+};
+
pub const EthIpUdp = packed struct(u336) { // 42 bytes * 8 bits = 336
// --- UDP (Last in memory, defined first for LSB->MSB) ---
udp: packed struct {
@@ -25,8 +47,8 @@ pub const EthIpUdp = packed struct(u336) { // 42 bytes * 8 bits = 336
// --- IP ---
ip: packed struct {
- dst_addr: u32,
- src_addr: u32,
+ dst_addr: IpAddr,
+ src_addr: IpAddr,
header_checksum: u16 = 0,
protocol: u8 = 17, // udp
ttl: u8 = 0x40,
@@ -53,8 +75,8 @@ pub const EthIpUdp = packed struct(u336) { // 42 bytes * 8 bits = 336
// --- Ethernet ---
eth_type: u16 = std.os.linux.ETH.P.IP,
- src_mac: @Vector(6, u8),
- dst_mac: @Vector(6, u8) = @splat(0xff),
+ src_mac: MacAddr,
+ dst_mac: MacAddr = .fromBytes(@splat(0xff)),
pub fn toBytes(self: @This()) [336 / 8]u8 {
var res: [336 / 8]u8 = undefined;
diff --git a/src/RawSocket.zig b/src/RawSocket.zig
index 9561dcf..727f08a 100644
--- a/src/RawSocket.zig
+++ b/src/RawSocket.zig
@@ -100,7 +100,7 @@ pub fn init() error{
};
}
-pub fn setTimeout(self: *RawSocket, sec: isize, usec: i64) !void {
+pub fn setTimeout(self: *RawSocket, sec: isize, usec: i64) error{SetTimeoutError}!void {
const timeout: std.os.linux.timeval = .{ .sec = sec, .usec = usec };
const timeout_ret = std.os.linux.setsockopt(self.fd, std.os.linux.SOL.SOCKET, std.os.linux.SO.RCVTIMEO, @ptrCast(&timeout), @sizeOf(@TypeOf(timeout)));
if (timeout_ret != 0) return error.SetTimeoutError;
diff --git a/src/main.zig b/src/main.zig
index c5e7b0a..7684143 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -148,7 +148,7 @@ pub fn main(init: std.process.Init) !void {
reconnect: while (true) {
client = SaprusClient.init() catch |err| switch (err) {
error.NoInterfaceFound => {
- try init.io.sleep(.fromMilliseconds(100), .boot);
+ init.io.sleep(.fromMilliseconds(100), .boot) catch unreachable;
continue :reconnect;
},
else => |e| return e,
@@ -156,24 +156,44 @@ pub fn main(init: std.process.Init) !void {
defer client.deinit();
log.debug("Starting connection", .{});
- try client.socket.setTimeout(if (is_debug) 3 else 25, 0);
+ client.socket.setTimeout(if (is_debug) 3 else 25, 0) catch {
+ log.err("Unable to set timeout", .{});
+ init.io.sleep(.fromMilliseconds(100), .boot) catch unreachable;
+ continue :reconnect;
+ };
var connection = client.connect(init.io, w.buffered()) catch {
log.debug("Connection timed out", .{});
- continue;
+ continue :reconnect;
};
log.debug("Connection started", .{});
next_message: while (true) {
var res_buf: [2048]u8 = undefined;
- try client.socket.setTimeout(if (is_debug) 60 else 600, 0);
+ client.socket.setTimeout(if (is_debug) 60 else 600, 0) catch {
+ log.err("Unable to set timeout", .{});
+ init.io.sleep(.fromMilliseconds(100), .boot) catch unreachable;
+ continue :reconnect;
+ };
const next = connection.next(init.io, &res_buf) catch {
continue :reconnect;
};
const b64d = std.base64.standard.Decoder;
var connection_payload_buf: [2048]u8 = undefined;
- const connection_payload = connection_payload_buf[0..try b64d.calcSizeForSlice(next)];
+ const connection_payload = blk: {
+ const size = b64d.calcSizeForSlice(next) catch |err| switch (err) {
+ error.InvalidCharacter, error.InvalidPadding => {
+ log.warn("Invalid base64 message received, ignoring: '{s}'", .{next});
+ continue :next_message;
+ },
+ error.NoSpaceLeft => {
+ log.warn("No space left when decoding base64 string, ignoring.", .{});
+ continue :next_message;
+ },
+ };
+ break :blk connection_payload_buf[0..size];
+ };
b64d.decode(connection_payload, next) catch {
log.debug("Failed to decode message, skipping: '{s}'", .{connection_payload});
continue;
@@ -221,7 +241,7 @@ pub fn main(init: std.process.Init) !void {
var is_killed: std.atomic.Value(bool) = .init(false);
- var kill_task = try init.io.concurrent(killProcessAfter, .{ init.io, &child, .fromSeconds(3), &is_killed });
+ var kill_task = init.io.concurrent(killProcessAfter, .{ init.io, &child, .fromSeconds(3), &is_killed }) catch unreachable;
defer _ = kill_task.cancel(init.io) catch {};
var cmd_output_buf: [SaprusClient.max_payload_len * 2]u8 = undefined;
@@ -244,12 +264,41 @@ pub fn main(init: std.process.Init) !void {
break;
},
};
- cmd_output.print("{b64}", .{try child_output_reader.interface.takeArray(child_output_buf.len)}) catch unreachable;
+ const child_output_chunk = child_output_reader.interface.takeArray(child_output_buf.len) catch |err| switch (err) {
+ error.EndOfStream => {
+ log.warn("Reached end of stream when reading from the child process. Maybe this should be handled more gracefull, but ignoring for now.", .{});
+ continue :next_message;
+ },
+ error.ReadFailed => if (child_output_reader.err) |co_err| switch (co_err) {
+ error.AccessDenied,
+ error.ConnectionResetByPeer,
+ error.InputOutput,
+ error.IsDir,
+ error.LockViolation,
+ error.NotOpenForReading,
+ error.SocketUnconnected,
+ error.SystemResources,
+ error.WouldBlock,
+ => |e| {
+ log.err("Unending error reading output from child process: {t}", .{e});
+ continue :next_message;
+ },
+ error.Canceled => |e| return e,
+ error.Unexpected => {
+ log.err("Unexpected error reading output from child process.", .{});
+ continue :next_message;
+ },
+ } else {
+ log.err("Shouldn't get here :(", .{});
+ continue :next_message;
+ },
+ };
+ cmd_output.print("{b64}", .{child_output_chunk}) catch unreachable;
connection.send(init.io, .{}, cmd_output.buffered()) catch |err| {
log.debug("Failed to send connection chunk: {t}", .{err});
continue :next_message;
};
- try init.io.sleep(.fromMilliseconds(40), .boot);
+ init.io.sleep(.fromMilliseconds(40), .boot) catch unreachable;
} else {
kill_task.cancel(init.io) catch {};
killProcessAfter(init.io, &child, .zero, &is_killed) catch |err| {