Skip to content
Permalink
Browse files

relay: add UNIX socket support (closes #733)

  • Loading branch information...
ryan-farley authored and flashcode committed May 12, 2019
1 parent 5f87112 commit ffefd1b7851c3ee01ef259ea406fbcfaa564bead
@@ -3194,6 +3194,27 @@ websocket = new WebSocket("ws://server.com:9000/weechat");
The port (9000 in example) is the port defined in Relay plugin.
The URI must always end with "/weechat" (for _irc_ and _weechat_ protocols).

[[relay_unixsocket]]
==== UNIX domain sockets

Using the protocol option "unix" with the "/relay add" command, you can
listen using any protocol on a UNIX domain socket at a given path. For exmaple:

----
/relay add unix.weechat /tmp/weesock
----

will allow clients to connect using the WeeChat protocol to /tmp/weesock. This
is particularly useful to allow SSH forwarding for relay clients, when other
ports cannot be opened. Using OpenSSH:

----
$ ssh -L9000:/tmp/weesock foo_host
----

will then allow for local relay clients to connect on port 9000 to a WeeChat
instance running on "foo_host".

[[relay_commands]]
==== Commands

@@ -1355,9 +1355,9 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
relay_clients = new_client;

weechat_printf_date_tags (NULL, 0, "relay_client",
_("%s: new client on port %d: %s%s%s"),
_("%s: new client on port/path %s: %s%s%s"),
RELAY_PLUGIN_NAME,
server->port,
server->path,
RELAY_COLOR_CHAT_CLIENT,
new_client->desc,
RELAY_COLOR_CHAT);
@@ -134,7 +134,7 @@ relay_command_server_list ()
if (relay_servers)
{
weechat_printf (NULL, "");
weechat_printf (NULL, _("Listening on ports:"));
weechat_printf (NULL, _("Listening on:"));
i = 1;
for (ptr_server = relay_servers; ptr_server;
ptr_server = ptr_server->next_server)
@@ -143,14 +143,15 @@ relay_command_server_list ()
{
weechat_printf (
NULL,
_(" port %s%d%s, relay: %s%s%s, %s (not started)"),
_(" %s %s%s%s, relay: %s%s%s, %s (not started)"),
RELAY_COLOR_CHAT_BUFFER,
ptr_server->port,
ptr_server->un ? _("path") : _("port"),
ptr_server->path,
RELAY_COLOR_CHAT,
RELAY_COLOR_CHAT_BUFFER,
ptr_server->protocol_string,
RELAY_COLOR_CHAT,
((ptr_server->ipv4 && ptr_server->ipv6) ? "IPv4+6" : ((ptr_server->ipv6) ? "IPv6" : "IPv4")));
((ptr_server->ipv4 && ptr_server->ipv6) ? "IPv4+6" : ((ptr_server->ipv6) ? "IPv6" : ((ptr_server->ipv4) ? "IPv4" : "UNIX"))));
}
else
{
@@ -164,15 +165,16 @@ relay_command_server_list ()
}
weechat_printf (
NULL,
_(" port %s%d%s, relay: %s%s%s, %s, started on: %s"),
_(" %s %s%s%s, relay: %s%s%s, %s, started on: %s"),
ptr_server->un ? _("path") : _("port"),
RELAY_COLOR_CHAT_BUFFER,
ptr_server->port,
ptr_server->path,
RELAY_COLOR_CHAT,
RELAY_COLOR_CHAT_BUFFER,
ptr_server->protocol_string,
RELAY_COLOR_CHAT,
((ptr_server->ipv4 && ptr_server->ipv6) ? "IPv4+6" : ((ptr_server->ipv6) ? "IPv6" : "IPv4")),
date_start);
((ptr_server->ipv4 && ptr_server->ipv6) ? "IPv4+6" : ((ptr_server->ipv6) ? "IPv6" : ((ptr_server->ipv4) ? "IPv4" : "UNIX"))),
date_start);
}
i++;
}
@@ -192,7 +194,8 @@ relay_command_relay (const void *pointer, void *data,
{
struct t_relay_server *ptr_server;
struct t_config_option *ptr_option;
int port;
struct t_config_section *port_path_section;
char *path;

/* make C compiler happy */
(void) pointer;
@@ -222,15 +225,19 @@ relay_command_relay (const void *pointer, void *data,
if (weechat_strcasecmp (argv[1], "add") == 0)
{
WEECHAT_COMMAND_MIN_ARGS(4, "add");
/* check if we're expecting a path or a port */
port_path_section = strncmp (argv[2], "unix.", 5) ?
relay_config_section_port :
relay_config_section_path;
if (relay_config_create_option_port (
NULL, NULL,
relay_config_file,
relay_config_section_port,
port_path_section,
argv[2],
argv_eol[3]) != WEECHAT_CONFIG_OPTION_SET_ERROR)
{
weechat_printf (NULL,
_("%s: relay \"%s\" (port %s) added"),
_("%s: relay \"%s\" (path/port: %s) added"),
RELAY_PLUGIN_NAME,
argv[2], argv_eol[3]);
}
@@ -243,17 +250,21 @@ relay_command_relay (const void *pointer, void *data,
ptr_server = relay_server_search (argv_eol[2]);
if (ptr_server)
{
port = ptr_server->port;
path = strdup (ptr_server->path);
relay_server_free (ptr_server);
ptr_option = weechat_config_search_option (relay_config_file,
relay_config_section_port,
ptr_server->un ?
relay_config_section_path :
relay_config_section_port,
argv_eol[2]);
if (ptr_option)
weechat_config_option_free (ptr_option);
weechat_printf (NULL,
_("%s: relay \"%s\" (port %d) removed"),
_("%s: relay \"%s\" (%s %s) removed"),
RELAY_PLUGIN_NAME,
argv[2], port);
argv[2], ptr_server->un ? _("path") : _("port"),
path);
free (path);
}
else
{
@@ -391,7 +402,7 @@ relay_command_init ()
N_(" list: list relay clients (only active relays)\n"
" listfull: list relay clients (verbose, all relays)\n"
" listrelay: list relays (name and port)\n"
" add: add a relay (listen on a port)\n"
" add: add a relay (listen on a port/path)\n"
" del: remove a relay (clients remain connected)\n"
" start: listen on port\n"
" restart: close the server socket and listen again on port "
@@ -407,6 +418,7 @@ relay_command_init ()
" ipv4: force use of IPv4\n"
" ipv6: force use of IPv6\n"
" ssl: enable SSL\n"
" unix: use UNIX domain socket\n"
"protocol.name: protocol and name to relay:\n"
" - protocol \"irc\": name is the server to share "
"(optional, if not given, the server name must be sent by client in "
@@ -437,7 +449,9 @@ relay_command_init ()
" weechat protocol with SSL, using only IPv6:\n"
" /relay add ipv6.ssl.weechat 9001\n"
" weechat protocol with SSL, using IPv4 + IPv6:\n"
" /relay add ipv4.ipv6.ssl.weechat 9001"),
" /relay add ipv4.ipv6.ssl.weechat 9001\n"
" weechat protocol over UNIX domain socket:\n"
" /relay add unix.weechat /tmp/weesock\n"),
"list %(relay_relays)"
" || listfull %(relay_relays)"
" || listrelay"
@@ -23,6 +23,7 @@
#include <string.h>
#include <limits.h>
#include <regex.h>
#include <sys/un.h>

#include "../weechat-plugin.h"
#include "relay.h"
@@ -36,6 +37,7 @@

struct t_config_file *relay_config_file = NULL;
struct t_config_section *relay_config_section_port = NULL;
struct t_config_section *relay_config_section_path = NULL;

/* relay config, look section */

@@ -185,7 +187,7 @@ relay_config_change_network_ipv6_cb (const void *pointer, void *data,
{
relay_server_get_protocol_args (ptr_server->protocol_string,
&ptr_server->ipv4, &ptr_server->ipv6,
NULL, NULL, NULL);
NULL, &ptr_server->un, NULL, NULL);
relay_server_close_socket (ptr_server);
relay_server_create_socket (ptr_server);
}
@@ -509,6 +511,75 @@ relay_config_check_port_cb (const void *pointer, void *data,
return 1;
}

/*
* Checks if a UNIX path is too long or empty.
*
* Returns:
* 1: path is valid
* 0: path is empty, or too long
*/

int
relay_config_check_path_len (const char *path)
{
struct sockaddr_un addr;
size_t max_path, path_len;

max_path = sizeof (addr.sun_path);
path_len = strlen (path);
if (!path_len)
{
weechat_printf (NULL, _("%s%s: error: path is empty"),
weechat_prefix ("error"), RELAY_PLUGIN_NAME);
return 0;
}
if (path_len >= max_path)
{
weechat_printf (NULL,
_("%s%s: error: path \"%s\" too long (length: %d; max: %d)"),
weechat_prefix ("error"), RELAY_PLUGIN_NAME, path,
path_len, max_path);
return 0;
}

return 1;
}

/*
* Checks if a path is valid.
*
* Returns:
* 1: path is valid
* 0: path is not valid
*/

int
relay_config_check_path_cb (const void *pointer, void *data,
struct t_config_option *option,
const char *value)
{
struct t_relay_server *ptr_server;

/* make C compiler happy */
(void) pointer;
(void) data;
(void) option;

if (!relay_config_check_path_len (value))
return 0;

ptr_server = relay_server_search_path (value);
if (ptr_server)
{
weechat_printf (NULL, _("%s%s: error: path \"%s\" is already used"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME, value);
return 0;
}

return 1;
}

/*
* Callback for changes on options in section "port".
*/
@@ -561,7 +632,7 @@ relay_config_create_option_port (const void *pointer, void *data,
const char *option_name,
const char *value)
{
int rc, protocol_number, ipv4, ipv6, ssl;
int rc, protocol_number, ipv4, ipv6, ssl, un;
char *error, *protocol, *protocol_args;
long port;
struct t_relay_server *ptr_server;
@@ -575,7 +646,7 @@ relay_config_create_option_port (const void *pointer, void *data,
protocol_number = -1;
port = -1;

relay_server_get_protocol_args (option_name, &ipv4, &ipv6, &ssl,
relay_server_get_protocol_args (option_name, &ipv4, &ipv6, &ssl, &un,
&protocol, &protocol_args);

#ifndef HAVE_GNUTLS
@@ -625,31 +696,53 @@ relay_config_create_option_port (const void *pointer, void *data,

if (rc != WEECHAT_CONFIG_OPTION_SET_ERROR)
{
error = NULL;
port = strtol (value, &error, 10);
ptr_server = relay_server_search_port ((int)port);
if (un)
{
ptr_server = relay_server_search_path (value);
}
else
{
error = NULL;
port = strtol (value, &error, 10);
ptr_server = relay_server_search_port ((int)port);
}
if (ptr_server)
{
weechat_printf (NULL, _("%s%s: error: port \"%d\" is already used"),
weechat_printf (NULL, _("%s%s: error: %s \"%s\" is already used"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME, (int)port);
RELAY_PLUGIN_NAME,
un ? _("path") : _("port"),
value);
rc = WEECHAT_CONFIG_OPTION_SET_ERROR;
}
}

if (rc != WEECHAT_CONFIG_OPTION_SET_ERROR)
{
if (relay_server_new (option_name, protocol_number, protocol_args,
port, ipv4, ipv6, ssl))
port, value, ipv4, ipv6, ssl, un))
{
/* create configuration option */
weechat_config_new_option (
if (un)
{
weechat_config_new_option (
config_file, section,
option_name, "string", NULL,
NULL, 0, 0, "", value, 0,
&relay_config_check_path_cb, NULL, NULL,
&relay_config_change_port_cb, NULL, NULL,
&relay_config_delete_port_cb, NULL, NULL);
}
else
{
weechat_config_new_option (
config_file, section,
option_name, "integer", NULL,
NULL, 0, 65535, "", value, 0,
&relay_config_check_port_cb, NULL, NULL,
&relay_config_change_port_cb, NULL, NULL,
&relay_config_delete_port_cb, NULL, NULL);
}
rc = WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE;
}
else
@@ -1067,6 +1160,23 @@ relay_config_init ()

relay_config_section_port = ptr_section;

/* section path */
ptr_section = weechat_config_new_section (
relay_config_file, "path",
1, 1,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
&relay_config_create_option_port, NULL, NULL,
NULL, NULL, NULL);
if (!ptr_section)
{
weechat_config_free (relay_config_file);
relay_config_file = NULL;
return 0;
}

relay_config_section_path = ptr_section;
return 1;
}

@@ -26,6 +26,7 @@

extern struct t_config_file *relay_config_file;
extern struct t_config_section *relay_config_section_port;
extern struct t_config_section *relay_config_section_path;

extern struct t_config_option *relay_config_look_auto_open_buffer;
extern struct t_config_option *relay_config_look_raw_messages;
@@ -72,6 +73,7 @@ extern int relay_config_create_option_port (const void *pointer, void *data,
struct t_config_section *section,
const char *option_name,
const char *value);
extern int relay_config_check_path_len (const char *path);
extern int relay_config_init ();
extern int relay_config_read ();
extern int relay_config_write ();
Oops, something went wrong.

0 comments on commit ffefd1b

Please sign in to comment.
You can’t perform that action at this time.