add zig connector
This commit is contained in:
parent
78789b68ea
commit
4b2e5b33b6
8 changed files with 730 additions and 44 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,3 +1,5 @@
|
|||
__pycache__
|
||||
/result
|
||||
/.venv
|
||||
/zig-cache
|
||||
/zig-out
|
||||
|
|
85
build.zig
Normal file
85
build.zig
Normal file
|
@ -0,0 +1,85 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const ssh_path = b.option(
|
||||
[]const u8,
|
||||
"ssh",
|
||||
"path to ssh binary",
|
||||
) orelse "ssh";
|
||||
|
||||
const telnet_path = b.option(
|
||||
[]const u8,
|
||||
"telnet",
|
||||
"path to telnet binary",
|
||||
) orelse "telnet";
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = "hostapps",
|
||||
.root_source_file = .{ .path = "src/main.zig" },
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const build_options = b.addOptions();
|
||||
build_options.addOption([]const u8, "ssh_path", ssh_path);
|
||||
build_options.addOption([]const u8, "telnet_path", telnet_path);
|
||||
|
||||
exe.root_module.addOptions("build_options", build_options);
|
||||
|
||||
const anzi = b.dependency(
|
||||
"anzi",
|
||||
.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
},
|
||||
);
|
||||
|
||||
exe.root_module.addImport("anzi", anzi.module("anzi"));
|
||||
|
||||
const logz = b.dependency(
|
||||
"logz",
|
||||
.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
},
|
||||
);
|
||||
|
||||
exe.root_module.addImport("logz", logz.module("logz"));
|
||||
|
||||
const yazap = b.dependency(
|
||||
"yazap",
|
||||
.{
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
},
|
||||
);
|
||||
|
||||
exe.root_module.addImport("yazap", yazap.module("yazap"));
|
||||
|
||||
b.installArtifact(exe);
|
||||
|
||||
const run_cmd = b.addRunArtifact(exe);
|
||||
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
|
||||
const exe_unit_tests = b.addTest(.{
|
||||
.root_source_file = .{ .path = "src/main.zig" },
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
|
||||
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
test_step.dependOn(&run_exe_unit_tests.step);
|
||||
}
|
28
build.zig.zon
Normal file
28
build.zig.zon
Normal file
|
@ -0,0 +1,28 @@
|
|||
.{
|
||||
.name = "hostapps",
|
||||
.version = "0.1.0",
|
||||
.minimum_zig_version = "0.12.0",
|
||||
.dependencies = .{
|
||||
.logz = .{
|
||||
.url = "https://github.com/karlseguin/log.zig/archive/a70984c80eb67c448480377849ba2adb6e51cf73.tar.gz",
|
||||
.hash = "122090c83a4e52b454e006da4a804b2210136ddec0dccfae00e7097314e5acfd01d0",
|
||||
},
|
||||
.yazap = .{
|
||||
.url = "https://github.com/prajwalch/yazap/archive/5f0d5d8928d5cd1907760dc41fa6f05dd232aaa5.tar.gz",
|
||||
.hash = "1220e4674826a70402974f13b7e2aaa4e9242e1b2b9d592015de9e21c7fa5fe200bd",
|
||||
},
|
||||
.anzi = .{
|
||||
.url = "https://git.ocjtech.us/jeff/anzi/archive/0e9d395a55b16da1d5bf7bfb59e2cfa59a7f2630.tar.gz",
|
||||
.hash = "12203f0ed986047bcd860b00496979a7734c2f462da4e56a72add4b17a1a7981f8ec",
|
||||
},
|
||||
},
|
||||
.paths = .{
|
||||
// "",
|
||||
// For example...
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
// "LICENSE",
|
||||
// "README.md",
|
||||
},
|
||||
}
|
148
flake.lock
148
flake.lock
|
@ -1,15 +1,31 @@
|
|||
{
|
||||
"nodes": {
|
||||
"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=",
|
||||
"lastModified": 1701680307,
|
||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -18,6 +34,54 @@
|
|||
"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"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"zls",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1703887061,
|
||||
"narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"langref": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"narHash": "sha256-mYdDCBdNEIeMbavdhSo8qXqW+3fqPC8BAich7W3umrI=",
|
||||
"type": "file",
|
||||
"url": "https://raw.githubusercontent.com/ziglang/zig/63bd2bff12992aef0ce23ae4b344e9cb5d65f05d/doc/langref.html.in"
|
||||
},
|
||||
"original": {
|
||||
"type": "file",
|
||||
"url": "https://raw.githubusercontent.com/ziglang/zig/63bd2bff12992aef0ce23ae4b344e9cb5d65f05d/doc/langref.html.in"
|
||||
}
|
||||
},
|
||||
"make-shell": {
|
||||
"locked": {
|
||||
"lastModified": 1634940815,
|
||||
|
@ -41,11 +105,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1693660503,
|
||||
"narHash": "sha256-B/g2V4v6gjirFmy+I5mwB2bCYc0l3j5scVfwgl6WOl8=",
|
||||
"lastModified": 1698974481,
|
||||
"narHash": "sha256-yPncV9Ohdz1zPZxYHQf47S8S0VrnhV7nNhCawY46hDA=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "bd5bdbb52350e145c526108f4ef192eb8e554fa0",
|
||||
"rev": "4bb5e752616262457bc7ca5882192a564c0472d2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -56,11 +120,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1698318101,
|
||||
"narHash": "sha256-gUihHt3yPD7bVqg+k/UVHgngyaJ3DMEBchbymBMvK1E=",
|
||||
"lastModified": 1704722960,
|
||||
"narHash": "sha256-mKGJ3sPsT6//s+Knglai5YflJUF2DGj7Ai6Ynopz0kI=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "63678e9f3d3afecfeafa0acead6239cdb447574c",
|
||||
"rev": "317484b1ead87b9c1b8ac5261a8d2dd748a0492d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -83,11 +147,11 @@
|
|||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1698640399,
|
||||
"narHash": "sha256-mXzyx79/iFLZ0UDuSkqgFfejYRcSJfsCnJ9WlMusaI0=",
|
||||
"lastModified": 1705060653,
|
||||
"narHash": "sha256-puYyylgrBS4AFAHeyVRTjTUVD8DZdecJfymWJe7H438=",
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"rev": "626111646fe236cb1ddc8191a48c75e072a82b7c",
|
||||
"rev": "e0b44e9e2d3aa855d1dd77b06f067cd0e0c3860d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -101,7 +165,9 @@
|
|||
"flake-utils": "flake-utils",
|
||||
"make-shell": "make-shell",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"poetry2nix": "poetry2nix"
|
||||
"poetry2nix": "poetry2nix",
|
||||
"zig": "zig",
|
||||
"zls": "zls"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
|
@ -141,11 +207,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1697388351,
|
||||
"narHash": "sha256-63N2eBpKaziIy4R44vjpUu8Nz5fCJY7okKrkixvDQmY=",
|
||||
"lastModified": 1699786194,
|
||||
"narHash": "sha256-3h3EH1FXQkIeAuzaWB+nK0XK54uSD46pp+dMD3gAcB4=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "aae39f64f5ecbe89792d05eacea5cb241891292a",
|
||||
"rev": "e82f32aa7f06bbbd56d7b12186d555223dc399d1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -153,6 +219,56 @@
|
|||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zig": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1705040559,
|
||||
"narHash": "sha256-6SjLyxWAVMfVfkz2x/3IlAJBJ0ywus6Hr9JrBbT9zCk=",
|
||||
"owner": "mitchellh",
|
||||
"repo": "zig-overlay",
|
||||
"rev": "6022b38d2fd4e7504f1e8b6dcfccab9b655764a9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "mitchellh",
|
||||
"repo": "zig-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"zls": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"gitignore": "gitignore",
|
||||
"langref": "langref",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"zig-overlay": [
|
||||
"zig"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1705106613,
|
||||
"narHash": "sha256-nqAXd8pEiEPJfjTrs0WB2UFOuBg5QRNbHWPDPGtrULI=",
|
||||
"owner": "zigtools",
|
||||
"repo": "zls",
|
||||
"rev": "abe83cf2291381291d4c20629a5018f124c4bed2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "zigtools",
|
||||
"repo": "zls",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
|
83
flake.nix
83
flake.nix
|
@ -15,6 +15,16 @@
|
|||
make-shell = {
|
||||
url = "github:ursi/nix-make-shell";
|
||||
};
|
||||
zig = {
|
||||
url = "github:mitchellh/zig-overlay";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
zls = {
|
||||
url = "github:zigtools/zls";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.zig-overlay.follows = "zig";
|
||||
inputs.flake-utils.follows = "flake-utils";
|
||||
};
|
||||
};
|
||||
outputs = {
|
||||
self,
|
||||
|
@ -22,6 +32,8 @@
|
|||
poetry2nix,
|
||||
flake-utils,
|
||||
make-shell,
|
||||
zig,
|
||||
zls,
|
||||
} @ inputs:
|
||||
flake-utils.lib.eachDefaultSystem
|
||||
(
|
||||
|
@ -39,7 +51,8 @@
|
|||
};
|
||||
inherit (poetry2nix.lib.mkPoetry2Nix {inherit pkgs;}) mkPoetryApplication overrides;
|
||||
in {
|
||||
packages.hostapps = mkPoetryApplication {
|
||||
packages = {
|
||||
hostapps = mkPoetryApplication {
|
||||
python = pkgs.python311;
|
||||
projectDir = ./.;
|
||||
propagatedBuildInputs = [
|
||||
|
@ -67,6 +80,70 @@
|
|||
}
|
||||
);
|
||||
};
|
||||
hostapps-zig = let
|
||||
cache = src:
|
||||
pkgs.stdenvNoCC.mkDerivation {
|
||||
inherit src;
|
||||
name = "hostapps-zig-cache";
|
||||
buildInputs = [
|
||||
zig.packages.${pkgs.system}.master
|
||||
];
|
||||
dontUseZigInstall = true;
|
||||
dontUseZigBuild = true;
|
||||
dontConfigure = true;
|
||||
dontFixup = true;
|
||||
|
||||
preBuild = ''
|
||||
export ZIG_GLOBAL_CACHE_DIR=$(mktemp -d)
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
zig build --fetch
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
cp -r --reflink=auto $ZIG_GLOBAL_CACHE_DIR/p $out
|
||||
runHook postInstall
|
||||
'';
|
||||
outputHash = "sha256-GUddHnPI5zAU2JpQ1R9qjWyrYF7ytmroQxbz2kjj6ro=";
|
||||
outputHashMode = "recursive";
|
||||
};
|
||||
in
|
||||
pkgs.stdenvNoCC.mkDerivation (
|
||||
attrs: {
|
||||
pname = "hostapps-zig";
|
||||
version = "0.0.0";
|
||||
|
||||
src = ./.;
|
||||
|
||||
buildInputs = [
|
||||
zig.packages.${pkgs.system}.master
|
||||
];
|
||||
|
||||
preBuild = ''
|
||||
export ZIG_GLOBAL_CACHE_DIR=$(mktemp -d)
|
||||
cp -r --reflink=auto ${cache attrs.src} $ZIG_GLOBAL_CACHE_DIR/p
|
||||
chmod -R u+rwX $ZIG_GLOBAL_CACHE_DIR
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
runHook preBuild
|
||||
zig build -Doptimize=ReleaseSafe
|
||||
runHook postBuild
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/bin
|
||||
cp zig-out/bin/hostapps $out/bin
|
||||
runHook postInstall
|
||||
'';
|
||||
}
|
||||
);
|
||||
};
|
||||
defaultPackage = self.packages.${system}.hostapps;
|
||||
devShells.default = let
|
||||
python = pkgs.python312.withPackages (
|
||||
|
@ -84,9 +161,11 @@
|
|||
pkgs.openssh
|
||||
pkgs.poetry
|
||||
pkgs.sshpass
|
||||
zig.packages.${system}.master
|
||||
zls.packages.${system}.zls
|
||||
];
|
||||
env = {
|
||||
NIX_PROJECT = project;
|
||||
name = project;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
28
src/config.zig
Normal file
28
src/config.zig
Normal file
|
@ -0,0 +1,28 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub const ConnectionType = enum {
|
||||
ssh,
|
||||
telnet,
|
||||
};
|
||||
|
||||
pub const Config = struct {
|
||||
name: []const u8,
|
||||
type: ConnectionType,
|
||||
comment: []const u8,
|
||||
address: []const u8,
|
||||
port: u16,
|
||||
username: []const u8,
|
||||
manufacturer: []const u8,
|
||||
model: []const u8,
|
||||
part_number: []const u8,
|
||||
class: []const u8,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn read(alloc: std.mem.Allocator, path: []const u8) !Self {
|
||||
const data = try std.fs.cwd().readFileAlloc(alloc, path, 2048);
|
||||
const parsed = try std.json.parseFromSlice(Self, alloc, data, .{});
|
||||
const config = parsed.value;
|
||||
return config;
|
||||
}
|
||||
};
|
158
src/connect.zig
Normal file
158
src/connect.zig
Normal file
|
@ -0,0 +1,158 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Config = @import("config.zig").Config;
|
||||
const ansi = @import("anzi").ANSI(.{});
|
||||
|
||||
const kex_algorithms = [_][]const u8{
|
||||
"diffie-hellman-group14-sha1",
|
||||
"diffie-hellman-group1-sha1",
|
||||
"diffie-hellman-group-exchange-sha1",
|
||||
"diffie-hellman-group-exchange-sha256",
|
||||
"ecdh-sha2-nistp256",
|
||||
};
|
||||
|
||||
const ciphers = [_][]const u8{
|
||||
"aes256-cbc",
|
||||
"aes192-cbc",
|
||||
"3des-cbc",
|
||||
"aes128-cbc",
|
||||
"aes256-ctr",
|
||||
"aes192-ctr",
|
||||
"aes128-ctr",
|
||||
};
|
||||
|
||||
const macs = [_][]const u8{
|
||||
"hmac-md5",
|
||||
"hmac-sha1",
|
||||
"hmac-sha2-256-etm@openssh.com",
|
||||
"hmac-sha2-512-etm@openssh.com",
|
||||
"hmac-sha2-256",
|
||||
"hmac-sha2-512",
|
||||
};
|
||||
|
||||
const options = [_]struct { key: []const u8, value: []const u8 }{
|
||||
.{ .key = "ControlMaster", .value = "no" },
|
||||
.{ .key = "ControlPath", .value = "none" },
|
||||
.{ .key = "ForwardX11", .value = "no" },
|
||||
.{ .key = "ForwardX11Trusted", .value = "no" },
|
||||
.{ .key = "HostKeyAlgorithms", .value = "+ssh-rsa" },
|
||||
.{ .key = "PubkeyAcceptedKeyTypes", .value = "+ssh-rsa" },
|
||||
};
|
||||
|
||||
pub fn connect(
|
||||
allocator: std.mem.Allocator,
|
||||
config_path: []const u8,
|
||||
identities: ?[][]const u8,
|
||||
proxy_jump: ?[]const u8,
|
||||
ssh_path: []const u8,
|
||||
telnet_path: []const u8,
|
||||
) !void {
|
||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
||||
const alloc = arena.allocator();
|
||||
defer arena.deinit();
|
||||
|
||||
const config = try Config.read(alloc, config_path);
|
||||
|
||||
var path: []const u8 = undefined;
|
||||
var args = std.ArrayList([]const u8).init(alloc);
|
||||
|
||||
std.log.info("name: {s}", .{config.name});
|
||||
std.log.info("class {s}", .{config.class});
|
||||
std.log.info("type: {}", .{config.type});
|
||||
std.log.info("comment: {s}", .{config.comment});
|
||||
std.log.info("address: {s}", .{config.address});
|
||||
std.log.info("port: {d}", .{config.port});
|
||||
std.log.info("username: {s}", .{config.username});
|
||||
std.log.info("manufacturer: {s}", .{config.manufacturer});
|
||||
std.log.info("model: {s}", .{config.model});
|
||||
std.log.info("part number: {s}", .{config.part_number});
|
||||
|
||||
switch (config.type) {
|
||||
.ssh => {
|
||||
path = ssh_path;
|
||||
try args.append("ssh");
|
||||
try args.append("-y");
|
||||
|
||||
if (identities) |i| {
|
||||
for (i) |identity| {
|
||||
try args.append("-i");
|
||||
try args.append(identity);
|
||||
}
|
||||
}
|
||||
|
||||
if (proxy_jump) |p| {
|
||||
try args.append("-o");
|
||||
try args.append(try std.fmt.allocPrint(alloc, "ProxyJump={s}", .{p}));
|
||||
}
|
||||
|
||||
for (options) |option| {
|
||||
try args.append("-o");
|
||||
try args.append(try std.fmt.allocPrint(alloc, "{s}={s}", .{ option.key, option.value }));
|
||||
}
|
||||
|
||||
try args.append("-o");
|
||||
try args.append(try std.fmt.allocPrint(alloc, "Ciphers={s}", .{try std.mem.join(alloc, ",", &ciphers)}));
|
||||
|
||||
try args.append("-o");
|
||||
try args.append(try std.fmt.allocPrint(alloc, "KexAlgorithms={s}", .{try std.mem.join(alloc, ",", &kex_algorithms)}));
|
||||
|
||||
try args.append("-o");
|
||||
try args.append(try std.fmt.allocPrint(alloc, "MACs={s}", .{try std.mem.join(alloc, ",", &macs)}));
|
||||
|
||||
try args.append("-l");
|
||||
try args.append(config.username);
|
||||
|
||||
if (config.port != 22) {
|
||||
try args.append("-p");
|
||||
try args.append(try std.fmt.allocPrint(alloc, "{d}", .{config.port}));
|
||||
}
|
||||
|
||||
try args.append(config.address);
|
||||
},
|
||||
|
||||
.telnet => {
|
||||
if (proxy_jump) |p| {
|
||||
path = ssh_path;
|
||||
try args.append("ssh");
|
||||
try args.append("-t");
|
||||
try args.append(try std.fmt.allocPrint(alloc, "ssh://{s}", .{p}));
|
||||
try args.append("telnet");
|
||||
} else {
|
||||
path = telnet_path;
|
||||
try args.append("telnet");
|
||||
}
|
||||
|
||||
try args.append(config.address);
|
||||
|
||||
if (config.port != 23) {
|
||||
try args.append(try std.fmt.allocPrint(alloc, "{d}", .{config.port}));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const pathZ = try alloc.dupeZ(u8, path);
|
||||
const argsZ = try alloc.allocSentinel(?[*:0]const u8, args.items.len, null);
|
||||
for (args.items, 0..) |arg, i| argsZ[i] = (try alloc.dupeZ(u8, arg)).ptr;
|
||||
|
||||
for (argsZ, 0..) |arg, i| {
|
||||
if (arg) |a| std.log.info("{d} {s}", .{ i, a });
|
||||
}
|
||||
|
||||
if (builtin.output_mode == .Exe) {
|
||||
const stdout_file = std.io.getStdOut().writer();
|
||||
var bw = std.io.bufferedWriter(stdout_file);
|
||||
const stdout = bw.writer();
|
||||
try stdout.print(
|
||||
"{}",
|
||||
.{
|
||||
ansi.IconNameAndWindowTitle{
|
||||
.icon_name = config.name,
|
||||
.window_title = try std.fmt.allocPrint(alloc, "{s} \u{2013} {s}", .{ config.name, config.address }),
|
||||
},
|
||||
},
|
||||
);
|
||||
try bw.flush();
|
||||
const envp = @as([*:null]const ?[*:0]const u8, @ptrCast(std.os.environ.ptr));
|
||||
return std.os.execveZ(pathZ, argsZ, envp);
|
||||
}
|
||||
}
|
190
src/main.zig
Normal file
190
src/main.zig
Normal file
|
@ -0,0 +1,190 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const build_options = @import("build_options");
|
||||
const yazap = @import("yazap");
|
||||
const logz = @import("logz");
|
||||
const Config = @import("config.zig").Config;
|
||||
const connect = @import("connect.zig");
|
||||
|
||||
const App = yazap.App;
|
||||
const Arg = yazap.Arg;
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const alloc = gpa.allocator();
|
||||
|
||||
try logz.setup(alloc, .{
|
||||
.level = .Debug,
|
||||
.pool_size = 16,
|
||||
.max_size = 4096,
|
||||
.output = .stderr,
|
||||
});
|
||||
|
||||
var app = App.init(alloc, "hostapps", "hostapps");
|
||||
defer app.deinit();
|
||||
|
||||
var root = app.rootCommand();
|
||||
try root.addArg(Arg.booleanOption("version", null, "Print version and exit"));
|
||||
|
||||
var connect_command = app.createCommand("connect", "connect to remote host");
|
||||
try connect_command.addArg(Arg.singleValueOption("config", null, "Path to configuration file"));
|
||||
try connect_command.addArg(Arg.multiValuesOption("identity", null, "Path to identity file", 8));
|
||||
try connect_command.addArg(Arg.singleValueOption("proxy-jump", null, "Proxy jump"));
|
||||
try connect_command.addArg(Arg.singleValueOption("ssh-command", null, "Path to ssh command"));
|
||||
try connect_command.addArg(Arg.singleValueOption("telnet-command", null, "Path to telnet command"));
|
||||
|
||||
try root.addSubcommand(connect_command);
|
||||
|
||||
const matches = try app.parseProcess();
|
||||
|
||||
if (!(matches.containsArgs())) {
|
||||
try app.displayHelp();
|
||||
return;
|
||||
}
|
||||
|
||||
if (matches.containsArg("version")) {
|
||||
std.log.info("version number", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
if (matches.subcommandMatches("connect")) |connect_matches| {
|
||||
// if (!(connect_matches.containsArgs())) {
|
||||
// try app.displaySubcommandHelp();
|
||||
// return;
|
||||
// }
|
||||
|
||||
var it = connect_matches.args.keyIterator();
|
||||
while (it.next()) |key| {
|
||||
logz.info().string("key", key.*).log();
|
||||
}
|
||||
const config_path = connect_matches.getSingleValue("config") orelse {
|
||||
try app.displaySubcommandHelp();
|
||||
return;
|
||||
};
|
||||
|
||||
const identities = id: {
|
||||
const ids = connect_matches.getMultiValues("identity");
|
||||
if (ids != null) break :id ids;
|
||||
const id = connect_matches.getSingleValue("identity");
|
||||
if (id) |i| {
|
||||
break :id @as(?[][]const u8, @constCast(&[_][]const u8{i}));
|
||||
}
|
||||
break :id null;
|
||||
};
|
||||
|
||||
std.log.info("id: {any}", .{identities});
|
||||
|
||||
if (identities) |i| {
|
||||
logz.info().string("test", "test").log();
|
||||
for (i) |identity| {
|
||||
logz.info().string("identity", identity).log();
|
||||
const fullpath = fp: {
|
||||
if (identity[0] == '~') {
|
||||
const home = std.os.getenv("HOME") orelse {
|
||||
logz.err().src(@src()).string("message", "unable to get HOME environment variable to expand tilde").log();
|
||||
return;
|
||||
};
|
||||
var fp = try alloc.alloc(u8, home.len + identity.len - 1);
|
||||
@memcpy(fp[0..home.len], home);
|
||||
@memcpy(fp[home.len..], identity[1..]);
|
||||
break :fp fp;
|
||||
}
|
||||
break :fp identity;
|
||||
};
|
||||
logz.info().string("fullpath", fullpath).log();
|
||||
std.fs.cwd().access(fullpath, .{ .mode = .read_only }) catch |err| {
|
||||
logz.err().src(@src()).err(err).string("identity", identity).string("fullpath", fullpath).log();
|
||||
return;
|
||||
};
|
||||
if (identity.ptr != fullpath.ptr) alloc.free(fullpath);
|
||||
}
|
||||
} else {
|
||||
logz.warn().string("message", "no identities").log();
|
||||
}
|
||||
|
||||
const proxy_jump = connect_matches.getSingleValue("proxy-jump");
|
||||
|
||||
var ssh_path = connect_matches.getSingleValue("ssh-command") orelse build_options.ssh_path;
|
||||
|
||||
if (!std.fs.path.isAbsolute(ssh_path)) {
|
||||
const expanded = expandPath(alloc, ssh_path) catch |err| expanded: {
|
||||
std.log.warn("failed to expand ssh path={s} err={}", .{ ssh_path, err });
|
||||
break :expanded null;
|
||||
};
|
||||
if (expanded) |v| {
|
||||
ssh_path = v;
|
||||
// defer alloc.free(ssh_path);
|
||||
}
|
||||
}
|
||||
|
||||
var telnet_path = connect_matches.getSingleValue("telnet-command") orelse build_options.telnet_path;
|
||||
std.log.info("telnet path: {s}", .{telnet_path});
|
||||
|
||||
if (!std.fs.path.isAbsolute(telnet_path)) {
|
||||
const expanded = expandPath(alloc, telnet_path) catch |err| expanded: {
|
||||
std.log.warn("failed to expand telnet path={s} err={}", .{ telnet_path, err });
|
||||
break :expanded null;
|
||||
};
|
||||
if (expanded) |v| {
|
||||
std.log.info("expanded telnet path: {s}", .{v});
|
||||
telnet_path = v;
|
||||
// defer alloc.free(telnet_path);
|
||||
}
|
||||
}
|
||||
|
||||
std.log.info("ssh path: {s}", .{ssh_path});
|
||||
std.log.info("telnet path: {s}", .{telnet_path});
|
||||
try connect.connect(alloc, config_path, identities, proxy_jump, ssh_path, telnet_path);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fn expandPath(alloc: std.mem.Allocator, cmd: []const u8) !?[]u8 {
|
||||
const PATH = switch (builtin.os.tag) {
|
||||
.windows => blk: {
|
||||
const win_path = std.os.getenvW(std.unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse return null;
|
||||
const path = try std.unicode.utf16leToUtf8Alloc(alloc, win_path);
|
||||
break :blk path;
|
||||
},
|
||||
else => std.os.getenvZ("PATH") orelse return null,
|
||||
};
|
||||
defer if (builtin.os.tag == .windows) alloc.free(PATH);
|
||||
|
||||
var path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||
var it = std.mem.tokenizeScalar(u8, PATH, std.fs.path.delimiter);
|
||||
var seen_eaccess = false;
|
||||
while (it.next()) |search_path| {
|
||||
const path_len = search_path.len + cmd.len + 1;
|
||||
if (path_buf.len < path_len) return error.PathTooLong;
|
||||
|
||||
@memcpy(path_buf[0..search_path.len], search_path);
|
||||
path_buf[search_path.len] = std.fs.path.sep;
|
||||
@memcpy(path_buf[search_path.len + 1 ..][0..cmd.len], cmd);
|
||||
path_buf[path_len] = 0;
|
||||
const full_path = path_buf[0..path_len :0];
|
||||
|
||||
std.log.debug("path {s}", .{full_path});
|
||||
const stat = std.fs.cwd().statFile(full_path) catch |err| switch (err) {
|
||||
error.FileNotFound => continue,
|
||||
error.AccessDenied => {
|
||||
seen_eaccess = true;
|
||||
continue;
|
||||
},
|
||||
else => return err,
|
||||
};
|
||||
if (stat.kind != .directory and isExecutable(stat.mode)) {
|
||||
std.log.debug("executable: {s}", .{full_path});
|
||||
return try alloc.dupe(u8, full_path);
|
||||
}
|
||||
}
|
||||
|
||||
if (seen_eaccess) return error.AccessDenied;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn isExecutable(mode: std.fs.File.Mode) bool {
|
||||
if (builtin.os.tag == .windows) return true;
|
||||
return mode & 0o0111 != 0;
|
||||
}
|
Loading…
Reference in a new issue