Skip to content

Instantly share code, notes, and snippets.

@ssrlive
Last active July 19, 2021 11:22
Show Gist options
  • Save ssrlive/98b12b0c15d3c33954101b0e11e19dde to your computer and use it in GitHub Desktop.
Save ssrlive/98b12b0c15d3c33954101b0e11e19dde to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uv.h>
uv_loop_t *loop;
typedef struct {
uv_write_t req;
uv_buf_t buf;
} write_req_t;
void free_write_req(uv_write_t *req) {
write_req_t *wr = (write_req_t*) req;
free(wr->buf.base);
free(wr);
}
void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
buf->base = malloc(suggested_size);
buf->len = suggested_size;
}
void echo_write(uv_write_t *req, int status) {
if (status < 0) {
fprintf(stderr, "Write error %s\n", uv_err_name(status));
}
free_write_req(req);
}
void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
if (nread > 0) {
write_req_t *req = (write_req_t*) calloc(1, sizeof(write_req_t));
if (req == NULL) {
return;
}
req->buf = uv_buf_init(buf->base, (unsigned int)nread);
uv_write((uv_write_t*) req, client, &req->buf, 1, echo_write);
return;
}
if (nread < 0) {
if (nread != UV_EOF)
fprintf(stderr, "Read error %s\n", uv_err_name(nread));
uv_close((uv_handle_t*) client, NULL);
}
free(buf->base);
}
void on_new_connection(uv_stream_t *server, int status) {
uv_pipe_t *client;
if (status == -1) {
// error!
return;
}
client = (uv_pipe_t*) malloc(sizeof(uv_pipe_t));
uv_pipe_init(loop, client, 0);
if (uv_accept(server, (uv_stream_t*) client) == 0) {
uv_read_start((uv_stream_t*) client, alloc_buffer, echo_read);
}
else {
uv_close((uv_handle_t*) client, NULL);
}
}
#if defined(__unix__)
static const char* pipe_name = "/tmp/.uv.ipc.sock";
#else
static const char* pipe_name = "\\\\.\\pipe\\OutlineService.Pipe";
#endif
void close_pipe(uv_loop_t *loop, const char *pipe) {
uv_fs_t req;
uv_fs_unlink(loop, &req, pipe, NULL);
printf("exiting pipe \"%s\"\n", pipe);
}
void ctrl_c_handler(int sig) {
close_pipe(loop, pipe_name);
exit(0);
}
#define SIGTERM_MSG "SIGTERM received.\n"
#if defined(__unix__) || defined(__linux__)
#include <signal.h>
void sig_term_handler(int signum, siginfo_t *info, void *ptr)
{
printf("%s\n", SIGTERM_MSG);
close_pipe(loop, pipe_name);
exit(0);
}
#endif // defined(__unix__) || defined(__linux__)
void catch_sigterm()
{
#if (defined(__unix__) || defined(__linux__)) && !defined(__mips)
static struct sigaction _sigact;
memset(&_sigact, 0, sizeof(_sigact));
_sigact.sa_sigaction = sig_term_handler;
_sigact.sa_flags = SA_SIGINFO;
sigaction(SIGTERM, &_sigact, NULL);
#endif // (defined(__unix__) || defined(__linux__)) && !defined(__mips)
}
int main() {
union uv_any_handle server; // uv_pipe_t //
int r;
loop = uv_default_loop();
// close_pipe(loop, pipe_name);
uv_pipe_init(loop, &server.pipe, 0);
signal(SIGINT, ctrl_c_handler);
catch_sigterm();
printf("listening on pipe \"%s\"\n", pipe_name);
if ((r = uv_pipe_bind(&server.pipe, pipe_name))) {
fprintf(stderr, "Bind error %s\n", uv_err_name(r));
return 1;
}
uv_pipe_chmod(&server.pipe, UV_WRITABLE | UV_READABLE);
if ((r = uv_listen((uv_stream_t*) &server.stream, 128, on_new_connection))) {
fprintf(stderr, "Listen error %s\n", uv_err_name(r));
return 2;
}
return uv_run(loop, UV_RUN_DEFAULT);
}
@ssrlive
Copy link
Author

ssrlive commented Jul 19, 2021

test.js file

//
// usage: node ./test.js <remoteProxyIp> <tapDeviceName> <tapDeviceGatewayIp>
// 
// for example: node ./test.js 123.45.67.89 ssr-route-tap0 10.0.85.1
//

var net = require('net');
var domain = require('domain');

var remoteProxyIp = process.argv[2];
if (remoteProxyIp == undefined) {
    remoteProxyIp = "123.45.67.89";
}

var tapDeviceName = process.argv[3];
if (tapDeviceName == undefined) {
    tapDeviceName = "ssr-route-tap0";
}

var tapDeviceGatewayIp = process.argv[4];
if (tapDeviceGatewayIp == undefined) {
    tapDeviceGatewayIp = "10.0.85.1";
}

var addr = '/tmp/.uv.ipc.sock';

var d = domain.create();
d.on('error', function(err) {
    console.error(err);
});

d.run(function() {
    var client = net.createConnection({ path: addr }, function() {
        console.log("Connected");
        client.on('data', function(data) {
            console.log("Recieved: " + data);
        });
        client.on('error', function(){
            console.log(arguments);
        });

        client.on('end', function() { 
            console.log('Disconnecting server...');
        });

        const cleanup = () => {
            client.removeAllListeners();
            process.exit();
        };
        client.once('close', cleanup);
        client.once('error', cleanup);

        client.write(`{"action":"configureRouting","parameters":{"proxyIp":"${remoteProxyIp}","tapDeviceName":"${tapDeviceName}","tapDeviceGatewayIp":"${tapDeviceGatewayIp}","isAutoConnect":false}}`);

    }.bind(this));

    function timeoutQuit(arg) {
        // client.destroy();
        process.exit();
    }

    process.on('SIGINT', function() {
        console.log("Caught interrupt signal");
        client.write('{"action":"resetRouting","parameters":{}}');
        setTimeout(timeoutQuit, 2000, 'JustExit');
    });
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment