mirror of
https://github.com/irssi/irssi.git
synced 2024-12-04 14:46:39 -05:00
irssi proxy: allow listening on unix sockets
This commit is contained in:
parent
3fc7e4d4ea
commit
8c1da2890c
@ -6,7 +6,7 @@
|
|||||||
#define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */
|
#define IRSSI_GLOBAL_CONFIG "irssi.conf" /* config file name in /etc/ */
|
||||||
#define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */
|
#define IRSSI_HOME_CONFIG "config" /* config file name in ~/.irssi/ */
|
||||||
|
|
||||||
#define IRSSI_ABI_VERSION 1
|
#define IRSSI_ABI_VERSION 2
|
||||||
|
|
||||||
#define DEFAULT_SERVER_ADD_PORT 6667
|
#define DEFAULT_SERVER_ADD_PORT 6667
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
#include "fe-common/core/printtext.h" /* FIXME: evil. need to do fe-proxy */
|
#include "fe-common/core/printtext.h" /* FIXME: evil. need to do fe-proxy */
|
||||||
|
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
GSList *proxy_listens;
|
GSList *proxy_listens;
|
||||||
GSList *proxy_clients;
|
GSList *proxy_clients;
|
||||||
|
|
||||||
@ -39,6 +41,66 @@ static int ignore_next;
|
|||||||
|
|
||||||
static int enabled = FALSE;
|
static int enabled = FALSE;
|
||||||
|
|
||||||
|
static int is_all_digits(const char *s)
|
||||||
|
{
|
||||||
|
return strspn(s, "0123456789") == strlen(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GIOChannel *net_listen_unix(const char *path)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
int saved_errno, handle;
|
||||||
|
|
||||||
|
g_return_val_if_fail(path != NULL, NULL);
|
||||||
|
|
||||||
|
handle = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (handle == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fcntl(handle, F_SETFL, O_NONBLOCK);
|
||||||
|
|
||||||
|
memset(&sa, '\0', sizeof sa);
|
||||||
|
sa.sun_family = AF_UNIX;
|
||||||
|
strncpy(sa.sun_path, path, sizeof sa.sun_path - 1);
|
||||||
|
if (bind(handle, (struct sockaddr *)&sa, sizeof sa) == -1) {
|
||||||
|
saved_errno = errno;
|
||||||
|
goto error_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(handle, 1) == -1) {
|
||||||
|
saved_errno = errno;
|
||||||
|
goto error_unlink;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_io_channel_new(handle);
|
||||||
|
|
||||||
|
error_unlink:
|
||||||
|
unlink(sa.sun_path);
|
||||||
|
error_close:
|
||||||
|
close(handle);
|
||||||
|
errno = saved_errno;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GIOChannel *net_accept_unix(GIOChannel *handle)
|
||||||
|
{
|
||||||
|
struct sockaddr_un sa;
|
||||||
|
int ret;
|
||||||
|
socklen_t addrlen;
|
||||||
|
|
||||||
|
g_return_val_if_fail(handle != NULL, NULL);
|
||||||
|
|
||||||
|
addrlen = sizeof sa;
|
||||||
|
ret = accept(g_io_channel_unix_get_fd(handle), (struct sockaddr *)&sa, &addrlen);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
fcntl(ret, F_SETFL, O_NONBLOCK);
|
||||||
|
return g_io_channel_new(ret);
|
||||||
|
}
|
||||||
|
|
||||||
static void remove_client(CLIENT_REC *rec)
|
static void remove_client(CLIENT_REC *rec)
|
||||||
{
|
{
|
||||||
g_return_if_fail(rec != NULL);
|
g_return_if_fail(rec != NULL);
|
||||||
@ -48,13 +110,13 @@ static void remove_client(CLIENT_REC *rec)
|
|||||||
|
|
||||||
signal_emit("proxy client disconnected", 1, rec);
|
signal_emit("proxy client disconnected", 1, rec);
|
||||||
printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE,
|
printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||||
"Proxy: Client %s:%d disconnected", rec->host, rec->port);
|
"Proxy: Client %s disconnected", rec->addr);
|
||||||
|
|
||||||
g_free(rec->proxy_address);
|
g_free(rec->proxy_address);
|
||||||
net_sendbuffer_destroy(rec->handle, TRUE);
|
net_sendbuffer_destroy(rec->handle, TRUE);
|
||||||
g_source_remove(rec->recv_tag);
|
g_source_remove(rec->recv_tag);
|
||||||
g_free_not_null(rec->nick);
|
g_free_not_null(rec->nick);
|
||||||
g_free_not_null(rec->host);
|
g_free_not_null(rec->addr);
|
||||||
g_free(rec);
|
g_free(rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,8 +222,8 @@ static void handle_client_connect_cmd(CLIENT_REC *client,
|
|||||||
} else {
|
} else {
|
||||||
signal_emit("proxy client connected", 1, client);
|
signal_emit("proxy client connected", 1, client);
|
||||||
printtext(client->server, NULL, MSGLEVEL_CLIENTNOTICE,
|
printtext(client->server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||||
"Proxy: Client %s:%d connected",
|
"Proxy: Client %s connected",
|
||||||
client->host, client->port);
|
client->addr);
|
||||||
client->connected = TRUE;
|
client->connected = TRUE;
|
||||||
proxy_dump_data(client);
|
proxy_dump_data(client);
|
||||||
}
|
}
|
||||||
@ -370,20 +432,30 @@ static void sig_listen(LISTEN_REC *listen)
|
|||||||
GIOChannel *handle;
|
GIOChannel *handle;
|
||||||
char host[MAX_IP_LEN];
|
char host[MAX_IP_LEN];
|
||||||
int port;
|
int port;
|
||||||
|
char *addr;
|
||||||
|
|
||||||
g_return_if_fail(listen != NULL);
|
g_return_if_fail(listen != NULL);
|
||||||
|
|
||||||
/* accept connection */
|
/* accept connection */
|
||||||
handle = net_accept(listen->handle, &ip, &port);
|
if (listen->port) {
|
||||||
if (handle == NULL)
|
handle = net_accept(listen->handle, &ip, &port);
|
||||||
return;
|
if (handle == NULL)
|
||||||
net_ip2host(&ip, host);
|
return;
|
||||||
|
net_ip2host(&ip, host);
|
||||||
|
addr = g_strdup_printf("%s:%d", host, port);
|
||||||
|
} else {
|
||||||
|
/* no port => this is a unix socket */
|
||||||
|
handle = net_accept_unix(listen->handle);
|
||||||
|
if (handle == NULL)
|
||||||
|
return;
|
||||||
|
addr = g_strdup("(local)");
|
||||||
|
}
|
||||||
|
|
||||||
sendbuf = net_sendbuffer_create(handle, 0);
|
sendbuf = net_sendbuffer_create(handle, 0);
|
||||||
rec = g_new0(CLIENT_REC, 1);
|
rec = g_new0(CLIENT_REC, 1);
|
||||||
rec->listen = listen;
|
rec->listen = listen;
|
||||||
rec->handle = sendbuf;
|
rec->handle = sendbuf;
|
||||||
rec->host = g_strdup(host);
|
rec->addr = addr;
|
||||||
rec->port = port;
|
|
||||||
if (g_strcmp0(listen->ircnet, "?") == 0) {
|
if (g_strcmp0(listen->ircnet, "?") == 0) {
|
||||||
rec->multiplex = TRUE;
|
rec->multiplex = TRUE;
|
||||||
rec->proxy_address = g_strdup("multiplex.proxy");
|
rec->proxy_address = g_strdup("multiplex.proxy");
|
||||||
@ -404,8 +476,8 @@ static void sig_listen(LISTEN_REC *listen)
|
|||||||
|
|
||||||
signal_emit("proxy client connecting", 1, rec);
|
signal_emit("proxy client connecting", 1, rec);
|
||||||
printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE,
|
printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||||
"Proxy: New client %s:%d on port %d (%s)",
|
"Proxy: New client %s on port %s (%s)",
|
||||||
rec->host, rec->port, listen->port, listen->ircnet);
|
rec->addr, listen->port_or_path, listen->ircnet);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sig_incoming(IRC_SERVER_REC *server, const char *line)
|
static void sig_incoming(IRC_SERVER_REC *server, const char *line)
|
||||||
@ -601,14 +673,19 @@ static void sig_message_own_action(IRC_SERVER_REC *server, const char *msg,
|
|||||||
proxy_outserver_all(server, "PRIVMSG %s :\001ACTION %s\001", target, msg);
|
proxy_outserver_all(server, "PRIVMSG %s :\001ACTION %s\001", target, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static LISTEN_REC *find_listen(const char *ircnet, int port)
|
static LISTEN_REC *find_listen(const char *ircnet, int port, const char *port_or_path)
|
||||||
{
|
{
|
||||||
GSList *tmp;
|
GSList *tmp;
|
||||||
|
|
||||||
for (tmp = proxy_listens; tmp != NULL; tmp = tmp->next) {
|
for (tmp = proxy_listens; tmp != NULL; tmp = tmp->next) {
|
||||||
LISTEN_REC *rec = tmp->data;
|
LISTEN_REC *rec = tmp->data;
|
||||||
|
|
||||||
if (rec->port == port &&
|
if ((port
|
||||||
|
? /* a tcp port */
|
||||||
|
rec->port == port
|
||||||
|
: /* a unix socket path */
|
||||||
|
g_strcmp0(rec->port_or_path, port_or_path) == 0
|
||||||
|
) &&
|
||||||
g_ascii_strcasecmp(rec->ircnet, ircnet) == 0)
|
g_ascii_strcasecmp(rec->ircnet, ircnet) == 0)
|
||||||
return rec;
|
return rec;
|
||||||
}
|
}
|
||||||
@ -616,43 +693,48 @@ static LISTEN_REC *find_listen(const char *ircnet, int port)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_listen(const char *ircnet, int port)
|
static void add_listen(const char *ircnet, int port, const char *port_or_path)
|
||||||
{
|
{
|
||||||
LISTEN_REC *rec;
|
LISTEN_REC *rec;
|
||||||
IPADDR ip4, ip6, *my_ip;
|
IPADDR ip4, ip6, *my_ip;
|
||||||
|
GIOChannel *handle;
|
||||||
|
|
||||||
if (port <= 0 || *ircnet == '\0')
|
if (*port_or_path == '\0' || port < 0 || *ircnet == '\0')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* bind to specific host/ip? */
|
if (port == 0) {
|
||||||
my_ip = NULL;
|
/* listening on a unix socket */
|
||||||
if (*settings_get_str("irssiproxy_bind") != '\0') {
|
handle = net_listen_unix(port_or_path);
|
||||||
if (net_gethostbyname(settings_get_str("irssiproxy_bind"),
|
} else {
|
||||||
&ip4, &ip6) != 0) {
|
/* bind to specific host/ip? */
|
||||||
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
|
my_ip = NULL;
|
||||||
"Proxy: can not resolve '%s' - aborting",
|
if (*settings_get_str("irssiproxy_bind") != '\0') {
|
||||||
settings_get_str("irssiproxy_bind"));
|
if (net_gethostbyname(settings_get_str("irssiproxy_bind"),
|
||||||
return;
|
&ip4, &ip6) != 0) {
|
||||||
}
|
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
|
||||||
|
"Proxy: can not resolve '%s' - aborting",
|
||||||
|
settings_get_str("irssiproxy_bind"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 ||
|
my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 ||
|
||||||
settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4;
|
settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4;
|
||||||
|
}
|
||||||
|
handle = net_listen(my_ip, &port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle == NULL) {
|
||||||
|
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
|
||||||
|
"Proxy: Listen in port %s failed: %s",
|
||||||
|
port_or_path, g_strerror(errno));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rec = g_new0(LISTEN_REC, 1);
|
rec = g_new0(LISTEN_REC, 1);
|
||||||
|
rec->handle = handle;
|
||||||
rec->ircnet = g_strdup(ircnet);
|
rec->ircnet = g_strdup(ircnet);
|
||||||
rec->port = port;
|
rec->port = port;
|
||||||
|
rec->port_or_path = g_strdup(port_or_path);
|
||||||
rec->handle = net_listen(my_ip, &rec->port);
|
|
||||||
|
|
||||||
if (rec->handle == NULL) {
|
|
||||||
printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
|
|
||||||
"Proxy: Listen in port %d failed: %s",
|
|
||||||
rec->port, g_strerror(errno));
|
|
||||||
g_free(rec->ircnet);
|
|
||||||
g_free(rec);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rec->tag = g_input_add(rec->handle, G_INPUT_READ,
|
rec->tag = g_input_add(rec->handle, G_INPUT_READ,
|
||||||
(GInputFunction) sig_listen, rec);
|
(GInputFunction) sig_listen, rec);
|
||||||
@ -667,8 +749,13 @@ static void remove_listen(LISTEN_REC *rec)
|
|||||||
while (rec->clients != NULL)
|
while (rec->clients != NULL)
|
||||||
remove_client(rec->clients->data);
|
remove_client(rec->clients->data);
|
||||||
|
|
||||||
|
/* remove unix socket because bind wants to (re)create it */
|
||||||
|
if (rec->port == 0)
|
||||||
|
unlink(rec->port_or_path);
|
||||||
|
|
||||||
net_disconnect(rec->handle);
|
net_disconnect(rec->handle);
|
||||||
g_source_remove(rec->tag);
|
g_source_remove(rec->tag);
|
||||||
|
g_free(rec->port_or_path);
|
||||||
g_free(rec->ircnet);
|
g_free(rec->ircnet);
|
||||||
g_free(rec);
|
g_free(rec);
|
||||||
}
|
}
|
||||||
@ -678,7 +765,7 @@ static void read_settings(void)
|
|||||||
LISTEN_REC *rec;
|
LISTEN_REC *rec;
|
||||||
GSList *remove_listens = NULL;
|
GSList *remove_listens = NULL;
|
||||||
GSList *add_listens = NULL;
|
GSList *add_listens = NULL;
|
||||||
char **ports, **tmp, *ircnet, *port;
|
char **ports, **tmp, *ircnet, *port_or_path;
|
||||||
int portnum;
|
int portnum;
|
||||||
|
|
||||||
remove_listens = g_slist_copy(proxy_listens);
|
remove_listens = g_slist_copy(proxy_listens);
|
||||||
@ -686,20 +773,25 @@ static void read_settings(void)
|
|||||||
ports = g_strsplit(settings_get_str("irssiproxy_ports"), " ", -1);
|
ports = g_strsplit(settings_get_str("irssiproxy_ports"), " ", -1);
|
||||||
for (tmp = ports; *tmp != NULL; tmp++) {
|
for (tmp = ports; *tmp != NULL; tmp++) {
|
||||||
ircnet = *tmp;
|
ircnet = *tmp;
|
||||||
port = strchr(ircnet, '=');
|
port_or_path = strchr(ircnet, '=');
|
||||||
if (port == NULL)
|
if (port_or_path == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
*port++ = '\0';
|
*port_or_path++ = '\0';
|
||||||
portnum = atoi(port);
|
if (is_all_digits(port_or_path)) {
|
||||||
if (portnum <= 0)
|
portnum = atoi(port_or_path);
|
||||||
continue;
|
if (portnum <= 0)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
portnum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
rec = find_listen(ircnet, portnum);
|
rec = find_listen(ircnet, portnum, port_or_path);
|
||||||
if (rec == NULL) {
|
if (rec == NULL) {
|
||||||
rec = g_new0(LISTEN_REC, 1);
|
rec = g_new0(LISTEN_REC, 1);
|
||||||
rec->ircnet = ircnet; /* borrow */
|
rec->ircnet = ircnet; /* borrow */
|
||||||
rec->port = portnum;
|
rec->port = portnum;
|
||||||
|
rec->port_or_path = port_or_path; /* borrow */
|
||||||
add_listens = g_slist_prepend(add_listens, rec);
|
add_listens = g_slist_prepend(add_listens, rec);
|
||||||
} else {
|
} else {
|
||||||
/* remove from the list of listens to remove == keep it */
|
/* remove from the list of listens to remove == keep it */
|
||||||
@ -714,7 +806,7 @@ static void read_settings(void)
|
|||||||
|
|
||||||
while (add_listens != NULL) {
|
while (add_listens != NULL) {
|
||||||
rec = add_listens->data;
|
rec = add_listens->data;
|
||||||
add_listen(rec->ircnet, rec->port);
|
add_listen(rec->ircnet, rec->port, rec->port_or_path);
|
||||||
add_listens = g_slist_remove(add_listens, rec);
|
add_listens = g_slist_remove(add_listens, rec);
|
||||||
g_free(rec);
|
g_free(rec);
|
||||||
}
|
}
|
||||||
|
@ -44,10 +44,10 @@ static void cmd_irssiproxy_status(const char *data, IRC_SERVER_REC *server)
|
|||||||
CLIENT_REC *rec = tmp->data;
|
CLIENT_REC *rec = tmp->data;
|
||||||
|
|
||||||
printtext(server, NULL, MSGLEVEL_CLIENTNOTICE,
|
printtext(server, NULL, MSGLEVEL_CLIENTNOTICE,
|
||||||
" %s:%d connect%s to %d (%s)",
|
" %s connect%s to %s (%s)",
|
||||||
rec->host, rec->port,
|
rec->addr,
|
||||||
rec->connected ? "ed" : "ing",
|
rec->connected ? "ed" : "ing",
|
||||||
rec->listen->port, rec->listen->ircnet);
|
rec->listen->port_or_path, rec->listen->ircnet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,17 +9,18 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int port;
|
int port;
|
||||||
|
char *port_or_path;
|
||||||
char *ircnet;
|
char *ircnet;
|
||||||
|
|
||||||
int tag;
|
int tag;
|
||||||
GIOChannel *handle;
|
GIOChannel *handle;
|
||||||
|
|
||||||
GSList *clients;
|
GSList *clients;
|
||||||
|
|
||||||
} LISTEN_REC;
|
} LISTEN_REC;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *nick, *host;
|
char *nick, *addr;
|
||||||
int port;
|
|
||||||
NET_SENDBUF_REC *handle;
|
NET_SENDBUF_REC *handle;
|
||||||
int recv_tag;
|
int recv_tag;
|
||||||
char *proxy_address;
|
char *proxy_address;
|
||||||
|
@ -149,8 +149,7 @@ static void perl_notifylist_fill_hash(HV *hv, NOTIFYLIST_REC *notify)
|
|||||||
static void perl_client_fill_hash(HV *hv, CLIENT_REC *client)
|
static void perl_client_fill_hash(HV *hv, CLIENT_REC *client)
|
||||||
{
|
{
|
||||||
(void) hv_store(hv, "nick", 4, new_pv(client->nick), 0);
|
(void) hv_store(hv, "nick", 4, new_pv(client->nick), 0);
|
||||||
(void) hv_store(hv, "host", 4, new_pv(client->host), 0);
|
(void) hv_store(hv, "addr", 4, new_pv(client->addr), 0);
|
||||||
(void) hv_store(hv, "port", 4, newSViv(client->port), 0);
|
|
||||||
(void) hv_store(hv, "proxy_address", 13, new_pv(client->proxy_address), 0);
|
(void) hv_store(hv, "proxy_address", 13, new_pv(client->proxy_address), 0);
|
||||||
(void) hv_store(hv, "server", 6, iobject_bless(client->server), 0);
|
(void) hv_store(hv, "server", 6, iobject_bless(client->server), 0);
|
||||||
(void) hv_store(hv, "pass_sent", 9, newSViv(client->pass_sent), 0);
|
(void) hv_store(hv, "pass_sent", 9, newSViv(client->pass_sent), 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user