examples,pkgs,pkgs.ch-proxy: init
This commit is contained in:
parent
81effc1ef3
commit
12e95630b1
4 changed files with 262 additions and 0 deletions
57
default.nix
Normal file
57
default.nix
Normal file
|
@ -0,0 +1,57 @@
|
|||
let
|
||||
pkgs = import <nixpkgs> { };
|
||||
inherit (pkgs) lib;
|
||||
dirToAttrs =
|
||||
root: patterns: f:
|
||||
lib.listToAttrs (
|
||||
lib.concatMap (
|
||||
dirent:
|
||||
let
|
||||
fname = dirent.name;
|
||||
typ = dirent.value;
|
||||
fpath = root + "/${fname}";
|
||||
doMatch =
|
||||
pat:
|
||||
let
|
||||
match = pat fpath fname typ;
|
||||
value = f match fpath typ;
|
||||
in
|
||||
if match == null then [ ] else [ (lib.nameValuePair match value) ];
|
||||
in
|
||||
(lib.take 1 (lib.concatMap (doMatch) patterns))
|
||||
) (lib.attrsToList (builtins.readDir root))
|
||||
);
|
||||
in
|
||||
{
|
||||
examples =
|
||||
dirToAttrs ./examples
|
||||
[
|
||||
(
|
||||
path: fname: _:
|
||||
lib.strings.removeSuffix ".nix" fname
|
||||
)
|
||||
]
|
||||
(
|
||||
name: fpath: _:
|
||||
import <nixpkgs/nixos/lib/eval-config.nix> { modules = [ fpath ]; }
|
||||
);
|
||||
pkgs = lib.makeScope pkgs.newScope (
|
||||
self:
|
||||
dirToAttrs ./pkgs
|
||||
[
|
||||
(
|
||||
path: fname: _:
|
||||
lib.strings.removeSuffix ".nix" fname
|
||||
)
|
||||
]
|
||||
(
|
||||
name: fpath: typ:
|
||||
if typ == "regular" then
|
||||
self.callPackage fpath { }
|
||||
else if typ == "directory" && builtins.pathExists (fpath + "/package.nix") then
|
||||
self.callPackage (fpath + "/package.nix") { }
|
||||
else
|
||||
null
|
||||
)
|
||||
);
|
||||
}
|
3
pkgs/ch-proxy/meson.build
Normal file
3
pkgs/ch-proxy/meson.build
Normal file
|
@ -0,0 +1,3 @@
|
|||
project('ch-proxy', 'c')
|
||||
|
||||
executable('ch-proxy', 'proxy.c', install: true)
|
26
pkgs/ch-proxy/package.nix
Normal file
26
pkgs/ch-proxy/package.nix
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
lib,
|
||||
stdenv,
|
||||
meson,
|
||||
ninja,
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "ch-proxy";
|
||||
version = "0.0.0";
|
||||
nativeBuildInputs = [
|
||||
meson
|
||||
ninja
|
||||
];
|
||||
src =
|
||||
let
|
||||
fs = lib.fileset;
|
||||
in
|
||||
fs.toSource {
|
||||
fileset = fs.unions [
|
||||
./proxy.c
|
||||
./meson.build
|
||||
];
|
||||
root = ./.;
|
||||
};
|
||||
}
|
176
pkgs/ch-proxy/proxy.c
Normal file
176
pkgs/ch-proxy/proxy.c
Normal file
|
@ -0,0 +1,176 @@
|
|||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
struct msghdr mk_msghdr();
|
||||
int ch_connect(const char*, const char*);
|
||||
ssize_t send_fd(int, int);
|
||||
|
||||
#define _WRITE_CONFIRM(fd, buf, buflen) {if (write((fd), (buf), (buflen)) != (buflen)) { perror("ch-proxy/write/partial write"); exit(EXIT_FAILURE); }}
|
||||
|
||||
void print_usage() {
|
||||
fprintf(stderr, "%s",
|
||||
"Usage:\n"
|
||||
"\tch-proxy uvm/$USER_VM_NAME [PORT]\n"
|
||||
"\tch-proxy uuvm/$VM_NAME [PORT]\n"
|
||||
"\tch-proxy vsock-mux%$PATH [PORT]\n");
|
||||
}
|
||||
|
||||
char *extract_vsock_mux(const char *host_string) {
|
||||
const char PREFIX[] = "vsock-mux%";
|
||||
const ssize_t PREFIX_LEN = sizeof(PREFIX) - 1;
|
||||
if (strncmp(host_string, PREFIX, PREFIX_LEN) == 0) {
|
||||
return strdup(&host_string[PREFIX_LEN]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *extract_uvm(const char *host_string) {
|
||||
const char PREFIX[] = "uuvm/";
|
||||
const ssize_t PREFIX_LEN = sizeof(PREFIX) - 1;
|
||||
|
||||
const char *home = getenv("HOME") != NULL ? getenv("HOME") : "./.";
|
||||
|
||||
if (strncmp(host_string, PREFIX, PREFIX_LEN) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *result;
|
||||
if (asprintf(&result, "%s/uvms/%s/CONNECT.sock", home, &host_string[PREFIX_LEN]) == -1) {
|
||||
perror("ch-proxy/extract_uvm");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
char *extract_muvm(const char *host_string) {
|
||||
const char PREFIX[] = "uvm/";
|
||||
const ssize_t PREFIX_LEN = sizeof(PREFIX) - 1;
|
||||
|
||||
|
||||
if (strncmp(host_string, PREFIX, PREFIX_LEN) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *result;
|
||||
if (asprintf(&result, "/var/lib/microvms/%s/CONNECT.sock", &host_string[PREFIX_LEN]) == -1) {
|
||||
perror("ch-proxy/extract_muvm");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (!(2 <= argc && argc <= 3)) {
|
||||
fprintf(stderr, "%s: Wrong # of arguments: %d\n", argv[0], argc);
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char PORT_DEFAULT[] = "22";
|
||||
|
||||
const char *ssh_host = argv[1];
|
||||
const char *port_string = argc == 3 ? argv[2] : PORT_DEFAULT;
|
||||
|
||||
char *path_un;
|
||||
if ((path_un = extract_uvm(ssh_host)) != NULL) {
|
||||
} else if ((path_un = extract_muvm(ssh_host)) != NULL) {
|
||||
} else if ((path_un = extract_vsock_mux(ssh_host)) != NULL) {
|
||||
} else {
|
||||
fprintf(stderr, "ch-proxy/main: unexpected host stirng format: %s\n", ssh_host);
|
||||
print_usage();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const int s = ch_connect(path_un, port_string);
|
||||
if (s == -1) {
|
||||
perror("ssh-vsock-proxy/main/ch_connect");
|
||||
return EXIT_FAILURE;
|
||||
};
|
||||
|
||||
if (send_fd(1, s) == -1) {
|
||||
perror("ssh-vsock-proxy/main/send_fd");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct msghdr mk_msghdr() {
|
||||
struct msghdr msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
int ch_connect(const char *path, const char *port) {
|
||||
int s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (s == -1) {
|
||||
perror("ch-proxy/ch_connect/bind");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sockaddr_un a;
|
||||
a.sun_family = AF_UNIX;
|
||||
strcpy(a.sun_path, path);
|
||||
|
||||
if (connect(s, (struct sockaddr*) &a, sizeof(a)) == -1) {
|
||||
char *err_msg;
|
||||
if (asprintf(&err_msg, "ch-proxy/ch_connect/connect(\"%s\")", path) == -1) {
|
||||
perror("ch-proxy/ch_connect/while printing connect() error");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
perror(err_msg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char CMD[] = "CONNECT ";
|
||||
const int CMD_LEN = sizeof(CMD) - 1;
|
||||
|
||||
_WRITE_CONFIRM(s, CMD, CMD_LEN);
|
||||
_WRITE_CONFIRM(s, port, strlen(port));
|
||||
_WRITE_CONFIRM(s, "\n", 1);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
ssize_t send_fd(int dst_fd, int fd) {
|
||||
struct msghdr msg = mk_msghdr();
|
||||
|
||||
/* openssh expects to receive a dummy length=1 iovec? */
|
||||
char ch;
|
||||
struct iovec vec;
|
||||
vec.iov_base = &ch;
|
||||
vec.iov_len = 1;
|
||||
msg.msg_iov = &vec;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
union {
|
||||
struct cmsghdr align;
|
||||
char buf[CMSG_SPACE(sizeof(int))];
|
||||
} u;
|
||||
|
||||
msg.msg_control = u.buf;
|
||||
msg.msg_controllen = sizeof(u.buf);
|
||||
|
||||
struct cmsghdr *cmptr;
|
||||
cmptr = CMSG_FIRSTHDR(&msg);
|
||||
|
||||
if (cmptr == NULL) {
|
||||
fprintf(stderr, "ch-proxy/send_fd/CMSG_FIRSTHDR: failed to initialize msg_control\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
cmptr->cmsg_level = SOL_SOCKET;
|
||||
cmptr->cmsg_type = SCM_RIGHTS;
|
||||
*((int*) CMSG_DATA(cmptr)) = fd;
|
||||
|
||||
return (sendmsg(dst_fd, &msg, 0));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue