first
This commit is contained in:
commit
dcb58a7554
7 changed files with 792 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/zig-cache
|
||||
/zig-out
|
||||
|
70
build.zig
Normal file
70
build.zig
Normal file
|
@ -0,0 +1,70 @@
|
|||
const std = @import("std");
|
||||
|
||||
// Although this function looks imperative, note that its job is to
|
||||
// declaratively construct a build graph that will be executed by an external
|
||||
// runner.
|
||||
pub fn build(b: *std.Build) void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
// what target to build for. Here we do not override the defaults, which
|
||||
// means any target is allowed, and the default is native. Other options
|
||||
// for restricting supported target set are available.
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
||||
// Standard optimization options allow the person running `zig build` to select
|
||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "ztacacs",
|
||||
// In this case the main source file is merely a path, however, in more
|
||||
// complicated build scripts, this could be a generated file.
|
||||
.root_source_file = .{ .path = "src/main.zig" },
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
// This declares intent for the executable to be installed into the
|
||||
// standard location when the user invokes the "install" step (the default
|
||||
// step when running `zig build`).
|
||||
b.installArtifact(exe);
|
||||
|
||||
// This *creates* a Run step in the build graph, to be executed when another
|
||||
// step is evaluated that depends on it. The next line below will establish
|
||||
// such a dependency.
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
|
||||
// By making the run step depend on the install step, it will be run from the
|
||||
// installation directory rather than directly from within the cache directory.
|
||||
// This is not necessary, however, if the application depends on other installed
|
||||
// files, this ensures they will be present and in the expected location.
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
// This allows the user to pass arguments to the application in the build
|
||||
// command itself, like this: `zig build run -- arg1 arg2 etc`
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
// This creates a build step. It will be visible in the `zig build --help` menu,
|
||||
// and can be selected like this: `zig build run`
|
||||
// This will evaluate the `run` step rather than the default, which is "install".
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
// Creates a step for unit testing. This only builds the test executable
|
||||
// but does not run it.
|
||||
const unit_tests = b.addTest(.{
|
||||
.root_source_file = .{ .path = "src/main.zig" },
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const run_unit_tests = b.addRunArtifact(unit_tests);
|
||||
|
||||
// Similar to creating the run step earlier, this exposes a `test` step to
|
||||
// the `zig build --help` menu, providing a way for the user to request
|
||||
// running the unit tests.
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&run_unit_tests.step);
|
||||
}
|
292
flake.lock
Normal file
292
flake.lock
Normal file
|
@ -0,0 +1,292 @@
|
|||
{
|
||||
"nodes": {
|
||||
"bash": {
|
||||
"locked": {
|
||||
"lastModified": 1678247195,
|
||||
"narHash": "sha256-m/wSwlSket+hob3JED4XUvoWJLtW7yhtOiZrlRDMShs=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "e7a00dcc0e75bc3ef6856bdd94d7d809245f5636",
|
||||
"revCount": 1,
|
||||
"type": "git",
|
||||
"url": "https://git.ocjtech.us/jeff/nixos-bash-prompt-builder.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.ocjtech.us/jeff/nixos-bash-prompt-builder.git"
|
||||
}
|
||||
},
|
||||
"binned_allocator": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-m/kr4kmkG2rLkAj5YwvM0HmXTd+chAiQHzYK6ozpWlw=",
|
||||
"type": "tarball",
|
||||
"url": "https://gist.github.com/antlilja/8372900fcc09e38d7b0b6bbaddad3904/archive/6c3321e0969ff2463f8335da5601986cf2108690.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://gist.github.com/antlilja/8372900fcc09e38d7b0b6bbaddad3904/archive/6c3321e0969ff2463f8335da5601986cf2108690.tar.gz"
|
||||
}
|
||||
},
|
||||
"diffz": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-3CdYo6WevT0alRwKmbABahjhFKz7V9rdkDUZ43VtDeU=",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/ziglibs/diffz/archive/90353d401c59e2ca5ed0abe5444c29ad3d7489aa.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/ziglibs/diffz/archive/90353d401c59e2ca5ed0abe5444c29ad3d7489aa.tar.gz"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"locked": {
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"zls",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694102001,
|
||||
"narHash": "sha256-vky6VPK1n1od6vXbqzOXnekrQpTL4hbPAwUhT5J9c9E=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "9e21c80adf67ebcb077d75bd5e7d724d21eeafd6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"known_folders": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-bZfn+jgCzrtm8vKPDDMNWLkJYoo7vKxZu+e2tGvSGHY=",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/ziglibs/known-folders/archive/a564f582122326328dad6b59209d070d57c4e6ae.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/ziglibs/known-folders/archive/a564f582122326328dad6b59209d070d57c4e6ae.tar.gz"
|
||||
}
|
||||
},
|
||||
"langref": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-UDwr6vJynfpD5SEoZzhXouoKu+Okdtpv20Vx2E5Ltcc=",
|
||||
"type": "file",
|
||||
"url": "https://raw.githubusercontent.com/ziglang/zig/f1992a39a59b941f397b8501a525b38e5863a527/doc/langref.html.in"
|
||||
},
|
||||
"original": {
|
||||
"type": "file",
|
||||
"url": "https://raw.githubusercontent.com/ziglang/zig/f1992a39a59b941f397b8501a525b38e5863a527/doc/langref.html.in"
|
||||
}
|
||||
},
|
||||
"make-shell": {
|
||||
"locked": {
|
||||
"lastModified": 1634940815,
|
||||
"narHash": "sha256-P69OmveboXzS+es1vQGS4bt+ckwbeIExqxfGLjGuJqA=",
|
||||
"owner": "ursi",
|
||||
"repo": "nix-make-shell",
|
||||
"rev": "8add91681170924e4d0591b22f294aee3f5516f9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ursi",
|
||||
"repo": "nix-make-shell",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1694959747,
|
||||
"narHash": "sha256-CXQ2MuledDVlVM5dLC4pB41cFlBWxRw4tCBsFrq3cRk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "970a59bd19eff3752ce552935687100c46e820a5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1689088367,
|
||||
"narHash": "sha256-Y2tl2TlKCWEHrOeM9ivjCLlRAKH3qoPUE/emhZECU14=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5c9ddb86679c400d6b7360797b8a22167c2053f8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-23.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"bash": "bash",
|
||||
"flake-utils": "flake-utils",
|
||||
"make-shell": "make-shell",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"zig": "zig",
|
||||
"zls": "zls"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zig": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1695125316,
|
||||
"narHash": "sha256-9Ewco7m4zgajBhppCM1mEmQE/K6ObkbwUhtJ3lJlfto=",
|
||||
"owner": "mitchellh",
|
||||
"repo": "zig-overlay",
|
||||
"rev": "078666381440c3303566a8a0f34628703202b54e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "mitchellh",
|
||||
"repo": "zig-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zls": {
|
||||
"inputs": {
|
||||
"binned_allocator": "binned_allocator",
|
||||
"diffz": "diffz",
|
||||
"flake-utils": "flake-utils_3",
|
||||
"gitignore": "gitignore",
|
||||
"known_folders": "known_folders",
|
||||
"langref": "langref",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"zig-overlay": [
|
||||
"zig"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1695231678,
|
||||
"narHash": "sha256-R6z0+6U7okQxmOR867nUTCzbRwtuGokGgtqvXP78XK8=",
|
||||
"owner": "zigtools",
|
||||
"repo": "zls",
|
||||
"rev": "20b80784998e342296473a2192ea70935ab84b8d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "zigtools",
|
||||
"repo": "zls",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
78
flake.nix
Normal file
78
flake.nix
Normal file
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
description = "ztacacs";
|
||||
|
||||
inputs = {
|
||||
nixpkgs = {
|
||||
url = "nixpkgs/nixos-unstable";
|
||||
};
|
||||
flake-utils = {
|
||||
url = "github:numtide/flake-utils";
|
||||
};
|
||||
bash = {
|
||||
url = "git+https://git.ocjtech.us/jeff/nixos-bash-prompt-builder.git";
|
||||
};
|
||||
make-shell = {
|
||||
url = "github:ursi/nix-make-shell";
|
||||
};
|
||||
zig = {
|
||||
url = "github:mitchellh/zig-overlay";
|
||||
};
|
||||
zls = {
|
||||
url = "github:zigtools/zls";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.zig-overlay.follows = "zig";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, bash, ... }@inputs:
|
||||
let
|
||||
# overlays = [
|
||||
# (
|
||||
# final: prev: {
|
||||
# zigpkgs = inputs.zig.packages.${prev.system};
|
||||
# }
|
||||
|
||||
# )
|
||||
# ];
|
||||
systems = builtins.attrNames inputs.zig.packages;
|
||||
in
|
||||
flake-utils.lib.eachSystem systems (
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
in
|
||||
{
|
||||
devShells.default =
|
||||
let
|
||||
project = "ztacacs";
|
||||
prompt = (
|
||||
bash.build_prompt
|
||||
bash.ansi_normal_blue
|
||||
"${project} - ${bash.username}@${bash.hostname_short}: ${bash.current_working_directory}"
|
||||
"${project}:${bash.current_working_directory}"
|
||||
);
|
||||
make-shell = import inputs.make-shell {
|
||||
inherit system;
|
||||
pkgs = pkgs;
|
||||
};
|
||||
in
|
||||
make-shell {
|
||||
packages = [
|
||||
inputs.zig.packages.${system}.master
|
||||
inputs.zls.packages.${system}.zls
|
||||
];
|
||||
env = {
|
||||
PS1 = prompt;
|
||||
};
|
||||
};
|
||||
# packages.default = inputs.zig.packages.${system}.zigStdenv.mkDerivation {
|
||||
# pname = "ztacacs";
|
||||
# version = "0.1.0";
|
||||
# buildInputs = [ ];
|
||||
# src = ./.;
|
||||
# };
|
||||
}
|
||||
);
|
||||
}
|
57
src/main.zig
Normal file
57
src/main.zig
Normal file
|
@ -0,0 +1,57 @@
|
|||
const std = @import("std");
|
||||
const serde = @import("serde.zig");
|
||||
const packet = @import("packet.zig");
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var socket = std.net.StreamServer.init(.{ .reuse_address = true, .reuse_port = true });
|
||||
defer socket.deinit();
|
||||
|
||||
try socket.listen(std.net.Address.initIp4(.{ 127, 0, 0, 1 }, 4949));
|
||||
|
||||
while (true) {
|
||||
const server = try allocator.create(Server);
|
||||
server.* = Server{
|
||||
.allocator = allocator,
|
||||
.conn = try socket.accept(),
|
||||
};
|
||||
const thread = try std.Thread.spawn(.{ .allocator = allocator }, Server.run, .{server});
|
||||
thread.detach();
|
||||
}
|
||||
}
|
||||
|
||||
const Server = struct {
|
||||
allocator: std.mem.Allocator,
|
||||
conn: std.net.StreamServer.Connection,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn run(self: *Self) !void {
|
||||
std.debug.print("starting: {}\n", .{self.conn.address});
|
||||
defer self.deinit();
|
||||
|
||||
while (true) {
|
||||
var buffer: [@sizeOf(packet.Header)]u8 = undefined;
|
||||
const len = try self.conn.stream.read(buffer[0..]);
|
||||
// if (len < @sizeOf(packet.Header)) break;
|
||||
if (len == 0) break;
|
||||
std.debug.print("{}\n", .{len});
|
||||
_ = try self.conn.stream.write(buffer[0..len]);
|
||||
}
|
||||
|
||||
std.debug.print("finished\n", .{});
|
||||
}
|
||||
|
||||
fn deinit(self: *Self) void {
|
||||
std.debug.print("start deinit\n", .{});
|
||||
self.conn.stream.close();
|
||||
self.allocator.destroy(self);
|
||||
std.debug.print("end deinit\n", .{});
|
||||
}
|
||||
};
|
||||
|
||||
test "main" {
|
||||
std.debug.print("hello\n", .{});
|
||||
}
|
189
src/packet.zig
Normal file
189
src/packet.zig
Normal file
|
@ -0,0 +1,189 @@
|
|||
const std = @import("std");
|
||||
const serde = @import("serde.zig");
|
||||
|
||||
pub const MajorVersion = enum(u4) {
|
||||
Default = 0xc,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const MinorVersion = enum(u4) {
|
||||
Default = 0x0,
|
||||
One = 0x1,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const PacketType = enum(u8) {
|
||||
Authentication = 1,
|
||||
Authorization = 2,
|
||||
Accounting = 3,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const HeaderFlags = packed struct(u8) {
|
||||
Unencrypted: bool = false,
|
||||
_p1: u1 = 0,
|
||||
SingleConnect: bool = false,
|
||||
_p2: u5 = 0,
|
||||
|
||||
pub fn format(value: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) std.os.WriteError!void {
|
||||
try writer.print("{s}{{ .Unencrypted = {}, .SingleConnect = {} }}", .{
|
||||
@typeName(@This()),
|
||||
value.Unencrypted,
|
||||
value.SingleConnect,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
pub const Header = struct {
|
||||
major: MajorVersion,
|
||||
minor: MinorVersion,
|
||||
type: PacketType,
|
||||
seq_no: u8,
|
||||
flags: HeaderFlags,
|
||||
session_id: u32,
|
||||
length: u32,
|
||||
};
|
||||
|
||||
test "header 1" {
|
||||
const packet = [_]u8{ 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
var reader = serde.Reader.init(&packet);
|
||||
const header = try reader.read(Header);
|
||||
std.debug.print("{}\n", .{header});
|
||||
try std.testing.expect(header.major == .Default);
|
||||
try std.testing.expect(header.minor == .Default);
|
||||
try std.testing.expect(header.type == .Authentication);
|
||||
try std.testing.expect(header.seq_no == 0);
|
||||
try std.testing.expect(!header.flags.Unencrypted);
|
||||
try std.testing.expect(!header.flags.SingleConnect);
|
||||
try std.testing.expect(header.session_id == 0);
|
||||
try std.testing.expect(header.length == 0);
|
||||
}
|
||||
|
||||
test "header 2" {
|
||||
const packet = [_]u8{ 0xc0, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
var reader = serde.Reader.init(&packet);
|
||||
const header = try reader.read(Header);
|
||||
std.debug.print("{}\n", .{header});
|
||||
try std.testing.expect(header.major == .Default);
|
||||
try std.testing.expect(header.minor == .Default);
|
||||
try std.testing.expect(header.type == .Authorization);
|
||||
try std.testing.expect(header.seq_no == 2);
|
||||
try std.testing.expect(header.flags.Unencrypted);
|
||||
try std.testing.expect(!header.flags.SingleConnect);
|
||||
try std.testing.expect(header.session_id == 0);
|
||||
try std.testing.expect(header.length == 0);
|
||||
}
|
||||
|
||||
test "header 3" {
|
||||
const packet = [_]u8{ 0xc0, 0x03, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
var reader = serde.Reader.init(&packet);
|
||||
const header = try reader.read(Header);
|
||||
std.debug.print("{}\n", .{header});
|
||||
try std.testing.expect(header.major == .Default);
|
||||
try std.testing.expect(header.minor == .Default);
|
||||
try std.testing.expect(header.type == .Accounting);
|
||||
try std.testing.expect(header.seq_no == 255);
|
||||
try std.testing.expect(!header.flags.Unencrypted);
|
||||
try std.testing.expect(header.flags.SingleConnect);
|
||||
try std.testing.expect(header.session_id == 0);
|
||||
try std.testing.expect(header.length == 0);
|
||||
}
|
||||
|
||||
pub const AuthenticationAction = enum(u8) {
|
||||
Login = 0x01,
|
||||
ChangePassword = 0x02,
|
||||
SendAuth = 0x03,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const AuthenticationType = enum(u8) {
|
||||
ASCII = 0x01,
|
||||
PAP = 0x02,
|
||||
CHAP = 0x03,
|
||||
MSCHAP = 0x05,
|
||||
MSCHAPV2 = 0x06,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const AuthenticationService = enum(u8) {
|
||||
NONE = 0x00,
|
||||
LOGIN = 0x01,
|
||||
ENABLE = 0x02,
|
||||
PPP = 0x03,
|
||||
PT = 0x05,
|
||||
RCMD = 0x06,
|
||||
X25 = 0x07,
|
||||
NASI = 0x08,
|
||||
FWPROXY = 0x09,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const AuthenticationStartHeader = struct {
|
||||
action: AuthenticationAction,
|
||||
priv_lvl: u8,
|
||||
authen_type: AuthenticationType,
|
||||
authen_service: AuthenticationService,
|
||||
user_len: u8,
|
||||
port_len: u8,
|
||||
rem_addr_len: u8,
|
||||
data_len: u8,
|
||||
};
|
||||
|
||||
pub const AuthenticationStatus = enum(u8) {
|
||||
PASS = 0x01,
|
||||
FAIL = 0x02,
|
||||
GETDATA = 0x03,
|
||||
GETUSER = 0x04,
|
||||
GETPASS = 0x05,
|
||||
RESTART = 0x06,
|
||||
ERROR = 0x07,
|
||||
FOLLOW = 0x21,
|
||||
};
|
||||
|
||||
pub const AuthenticationReplyFlags = packed struct(u8) {
|
||||
NoEcho: bool,
|
||||
_p1: u7 = 0,
|
||||
|
||||
pub fn format(value: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) std.os.WriteError!void {
|
||||
try writer.print("{s}{{ .NoEcho = {}, }}", .{
|
||||
@typeName(@This()),
|
||||
value.NoEcho,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
pub const AuthenticationReplyHeader = struct {
|
||||
status: AuthenticationStatus,
|
||||
flags: AuthenticationReplyFlags,
|
||||
server_msg_len: u16,
|
||||
data_len: u16,
|
||||
};
|
||||
|
||||
pub const AuthenticationContinueFlags = packed struct(u8) {
|
||||
Abort: bool,
|
||||
_p1: u7 = 0,
|
||||
|
||||
pub fn format(value: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) std.os.WriteError!void {
|
||||
try writer.print("{s}{{ .Abort = {}, }}", .{
|
||||
@typeName(@This()),
|
||||
value.Abort,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
pub const AuthenticationContinueHeader = struct {
|
||||
user_msg: u16,
|
||||
data_len: u16,
|
||||
flags: AuthenticationContinueFlags,
|
||||
};
|
||||
|
||||
pub const AuthorizationRequestHeader = struct {
|
||||
authen_method: u8,
|
||||
priv_lvl: u8,
|
||||
authen_type: u8,
|
||||
authen_service: u8,
|
||||
user_len: u8,
|
||||
port_len: u8,
|
||||
rem_addr_len: u8,
|
||||
arg_cnt: u8,
|
||||
};
|
103
src/serde.zig
Normal file
103
src/serde.zig
Normal file
|
@ -0,0 +1,103 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub const SerdeError = error{
|
||||
IllegalSize,
|
||||
LeftoverBits,
|
||||
NotEnoughBitsLeft,
|
||||
NotEnoughBytesLeft,
|
||||
};
|
||||
|
||||
pub const Reader = struct {
|
||||
bytes: []const u8,
|
||||
index: usize,
|
||||
bits_left: usize,
|
||||
|
||||
pub fn init(bytes: []const u8) Reader {
|
||||
return .{
|
||||
.bytes = bytes,
|
||||
.index = 0,
|
||||
.bits_left = 8,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn read(self: *Reader, comptime T: type) SerdeError!T {
|
||||
if (self.index >= self.bytes.len) return error.NotEnoughBytesLeft;
|
||||
return switch (@typeInfo(T)) {
|
||||
.Int => try self.readInt(T),
|
||||
.Bool => try self.readBool(T),
|
||||
.Enum => try self.readEnum(T),
|
||||
.Struct => try self.readStruct(T),
|
||||
.Array => |array| {
|
||||
var arr: [array.len]array.child = undefined;
|
||||
var index: usize = 0;
|
||||
while (index < array.len) : (index += 1) {
|
||||
arr[index] = try self.read(array.child);
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
else => @compileError("unsupported type"),
|
||||
};
|
||||
}
|
||||
|
||||
fn readInt(self: *Reader, comptime T: type) SerdeError!T {
|
||||
const bits = @typeInfo(T).Int.bits;
|
||||
|
||||
if (bits < 8) {
|
||||
if (bits > self.bits_left) return error.NotEnoughBitsLeft;
|
||||
const shift: u3 = @truncate(self.bits_left - bits);
|
||||
const mask = (1 << bits) - 1;
|
||||
const b = (self.bytes[self.index] >> shift) & mask;
|
||||
self.bits_left -= bits;
|
||||
if (self.bits_left == 0) {
|
||||
self.bits_left = 8;
|
||||
self.index += 1;
|
||||
}
|
||||
|
||||
return @intCast(b);
|
||||
}
|
||||
|
||||
if (bits % 8 == 0 and self.bits_left != 8) return error.LeftoverBits;
|
||||
if (bits % 8 != 0) return error.IllegalSize;
|
||||
|
||||
const size = bits / 8;
|
||||
|
||||
if (self.index + size > self.bytes.len) return error.NotEnoughBytesLeft;
|
||||
|
||||
const slice = self.bytes[self.index .. self.index + size];
|
||||
const value = @as(*align(1) const T, @ptrCast(slice)).*;
|
||||
|
||||
self.index += size;
|
||||
return std.mem.bigToNative(T, value);
|
||||
}
|
||||
|
||||
fn readBool(self: *Reader, comptime T: type) SerdeError!T {
|
||||
const x = try self.read(u1);
|
||||
std.debug.print("bool {}\n", .{x});
|
||||
return x == 1;
|
||||
}
|
||||
|
||||
fn readEnum(self: *Reader, comptime T: type) SerdeError!T {
|
||||
return @enumFromInt(try self.read(@typeInfo(T).Enum.tag_type));
|
||||
}
|
||||
|
||||
fn readStruct(self: *Reader, comptime T: type) SerdeError!T {
|
||||
if (@typeInfo(T).Struct.layout == .Packed) {
|
||||
const value = try self.read(@typeInfo(T).Struct.backing_integer.?);
|
||||
return @as(*const T, @ptrCast(&value)).*;
|
||||
}
|
||||
|
||||
const fields = std.meta.fields(T);
|
||||
|
||||
var value: T = undefined;
|
||||
|
||||
inline for (fields) |field| {
|
||||
@field(value, field.name) = try self.read(field.type);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
pub fn isComplete(self: *Reader) bool {
|
||||
return self.index >= self.bytes.len;
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue