1
0
mirror of https://github.com/irssi/irssi.git synced 2024-11-03 04:27:19 -05:00

Merge pull request #425 from mauke/irssiproxy-multiplex

irssi proxy: allow multiplexing multiple networks over a single port
This commit is contained in:
ailin-nemui 2016-02-24 16:14:43 +01:00
commit f83a29b764
5 changed files with 112 additions and 47 deletions

View File

@ -30,6 +30,18 @@ There we have 3 different irc networks answering in 3 ports. Note that
you'll have to make the correct /IRCNET ADD and /SERVER ADD commands to you'll have to make the correct /IRCNET ADD and /SERVER ADD commands to
make it work properly. make it work properly.
The special network name "?" allows the client to select the network
dynamically on connect:
/SET irssiproxy_ports ?=2777
Now the client can send <network>:<password> as the server password, e.g.
/CONNECT ... 2777 efnet:secret
to connect to efnet. If there is no irssiproxy_password set, you can
omit the ":" and just send the network name as the password.
By default, the proxy binds to all available interfaces. To make it By default, the proxy binds to all available interfaces. To make it
only listen on (for example) the loopback address: only listen on (for example) the loopback address:

View File

@ -735,6 +735,13 @@ reason, and you only use one server connection, you may simply set:</p>
/SET irssiproxy_ports *=2777 /SET irssiproxy_ports *=2777
</pre> </pre>
<p>The special network name <code>?</code> allows the client to select the
network dynamically on connect (see below):</p>
<pre>
/SET irssiproxy_ports ?=2777
</pre>
<p>Usage in client side:</p> <p>Usage in client side:</p>
<p>Just connect to the irssi proxy like it is a normal server with password <p>Just connect to the irssi proxy like it is a normal server with password
@ -745,6 +752,16 @@ specified in <code>/SET irssiproxy_password</code>. For example:</p>
/SERVER ADD -network efnet my.irssi-proxy.org 2778 secret /SERVER ADD -network efnet my.irssi-proxy.org 2778 secret
</pre> </pre>
<p>Or, if you used <code>?</code> in <code>irssiproxy_ports</code>:</p>
<pre>
/SERVER ADD -network IRCnet my.irssi-proxy.org 2777 IRCnet:secret
/SERVER ADD -network efnet my.irssi-proxy.org 2777 efnet:secret
</pre>
<p>I.e. the network to connect to is specified as part of the password,
separated by <code>:</code> from the actual proxy password.</p>
<p>Irssi proxy works fine with other IRC clients as well.</p> <p>Irssi proxy works fine with other IRC clients as well.</p>
<p><strong>SOCKS</strong></p> <p><strong>SOCKS</strong></p>

View File

@ -48,7 +48,7 @@ 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:%d disconnected", rec->host, rec->port);
g_free(rec->proxy_address); g_free(rec->proxy_address);
net_sendbuffer_destroy(rec->handle, TRUE); net_sendbuffer_destroy(rec->handle, TRUE);
@ -59,7 +59,7 @@ static void remove_client(CLIENT_REC *rec)
} }
static void proxy_redirect_event(CLIENT_REC *client, const char *command, static void proxy_redirect_event(CLIENT_REC *client, const char *command,
int count, const char *arg, int remote) int count, const char *arg, int remote)
{ {
char *str; char *str;
@ -67,7 +67,7 @@ static void proxy_redirect_event(CLIENT_REC *client, const char *command,
str = g_strdup_printf("proxy %p", client); str = g_strdup_printf("proxy %p", client);
server_redirect_event(client->server, command, count, server_redirect_event(client->server, command, count,
arg, remote, NULL, "", str, NULL); arg, remote, NULL, "", str, NULL);
g_free(str); g_free(str);
} }
@ -94,28 +94,58 @@ static void grab_who(CLIENT_REC *client, const char *channel)
} }
proxy_redirect_event(client, "who", proxy_redirect_event(client, "who",
client->server->one_endofwho ? 1 : count, client->server->one_endofwho ? 1 : count,
arg->str, -1); arg->str, -1);
g_strfreev(list); g_strfreev(list);
g_string_free(arg, TRUE); g_string_free(arg, TRUE);
} }
static void handle_client_connect_cmd(CLIENT_REC *client, static void handle_client_connect_cmd(CLIENT_REC *client,
const char *cmd, const char *args) const char *cmd, const char *args)
{ {
const char *password; const char *password;
password = settings_get_str("irssiproxy_password"); password = settings_get_str("irssiproxy_password");
if (password != NULL && g_strcmp0(cmd, "PASS") == 0) { if (g_strcmp0(cmd, "PASS") == 0) {
if (g_strcmp0(password, args) == 0) const char *args_pass;
client->pass_sent = TRUE;
else { if (!client->multiplex) {
args_pass = args;
} else {
IRC_SERVER_REC *server;
char *tag;
const char *tag_end;
if ((tag_end = strchr(args, ':')) != NULL) {
args_pass = tag_end + 1;
} else {
tag_end = args + strlen(args);
args_pass = "";
}
tag = g_strndup(args, tag_end - args);
server = IRC_SERVER(server_find_chatnet(tag));
g_free(tag);
if (!server) {
/* an invalid network was specified */
remove_client(client);
return;
}
client->server = server;
g_free(client->proxy_address);
client->proxy_address = g_strdup_printf("%*s.proxy", (int)(tag_end - args), args);
}
if (g_strcmp0(password, args_pass) != 0) {
/* wrong password! */ /* wrong password! */
remove_client(client); remove_client(client);
return; return;
} }
client->pass_sent = TRUE;
} else if (g_strcmp0(cmd, "NICK") == 0) { } else if (g_strcmp0(cmd, "NICK") == 0) {
g_free_not_null(client->nick); g_free_not_null(client->nick);
client->nick = g_strdup(args); client->nick = g_strdup(args);
@ -124,14 +154,14 @@ static void handle_client_connect_cmd(CLIENT_REC *client,
} }
if (client->nick != NULL && client->user_sent) { if (client->nick != NULL && client->user_sent) {
if (*password != '\0' && !client->pass_sent) { if ((*password != '\0' || client->multiplex) && !client->pass_sent) {
/* client didn't send us PASS, kill it */ /* client didn't send us PASS, kill it */
remove_client(client); remove_client(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:%d connected",
client->host, client->port); client->host, client->port);
client->connected = TRUE; client->connected = TRUE;
proxy_dump_data(client); proxy_dump_data(client);
} }
@ -139,7 +169,7 @@ static void handle_client_connect_cmd(CLIENT_REC *client,
} }
static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
const char *data) const char *data)
{ {
GSList *tmp; GSList *tmp;
if (!client->connected) { if (!client->connected) {
@ -162,8 +192,8 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
g_ascii_strcasecmp(target, client->proxy_address) == 0 || g_ascii_strcasecmp(target, client->proxy_address) == 0 ||
g_ascii_strcasecmp(target, client->nick) == 0) { g_ascii_strcasecmp(target, client->nick) == 0) {
proxy_outdata(client, ":%s PONG %s :%s\r\n", proxy_outdata(client, ":%s PONG %s :%s\r\n",
client->proxy_address, client->proxy_address,
client->proxy_address, origin); client->proxy_address, origin);
g_free(params); g_free(params);
return; return;
} }
@ -174,25 +204,25 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
if (g_ascii_strcasecmp(args, "CTCP ON") == 0) { if (g_ascii_strcasecmp(args, "CTCP ON") == 0) {
/* client wants all ctcps */ /* client wants all ctcps */
client->want_ctcp = 1; client->want_ctcp = 1;
for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) {
CLIENT_REC *rec = tmp->data; CLIENT_REC *rec = tmp->data;
if ((g_ascii_strcasecmp(client->listen->ircnet,rec->listen->ircnet) == 0) && if (g_ascii_strcasecmp(client->listen->ircnet, rec->listen->ircnet) == 0 &&
/* kludgy way to check if the clients aren't the same */ /* kludgy way to check if the clients aren't the same */
(client->recv_tag != rec->recv_tag)) { client->recv_tag != rec->recv_tag) {
if (rec->want_ctcp == 1) if (rec->want_ctcp == 1)
proxy_outdata(rec, ":%s NOTICE %s :Another client is now receiving CTCPs sent to %s\r\n", proxy_outdata(rec, ":%s NOTICE %s :Another client is now receiving CTCPs sent to %s\r\n",
rec->proxy_address, rec->nick, rec->listen->ircnet); rec->proxy_address, rec->nick, rec->listen->ircnet);
rec->want_ctcp = 0; rec->want_ctcp = 0;
} }
} }
proxy_outdata(client, ":%s NOTICE %s :You're now receiving CTCPs sent to %s\r\n", proxy_outdata(client, ":%s NOTICE %s :You're now receiving CTCPs sent to %s\r\n",
client->proxy_address, client->nick,client->listen->ircnet); client->proxy_address, client->nick, client->listen->ircnet);
} else if (g_ascii_strcasecmp(args, "CTCP OFF") == 0) { } else if (g_ascii_strcasecmp(args, "CTCP OFF") == 0) {
/* client wants proxy to handle all ctcps */ /* client wants proxy to handle all ctcps */
client->want_ctcp = 0; client->want_ctcp = 0;
proxy_outdata(client, ":%s NOTICE %s :Proxy is now handling itself CTCPs sent to %s\r\n", proxy_outdata(client, ":%s NOTICE %s :Proxy is now handling itself CTCPs sent to %s\r\n",
client->proxy_address, client->nick, client->listen->ircnet); client->proxy_address, client->nick, client->listen->ircnet);
} else { } else {
signal_emit("proxy client command", 3, client, args, data); signal_emit("proxy client command", 3, client, args, data);
} }
@ -201,11 +231,11 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
if (client->server == NULL || !client->server->connected) { if (client->server == NULL || !client->server->connected) {
proxy_outdata(client, ":%s NOTICE %s :Not connected to server\r\n", proxy_outdata(client, ":%s NOTICE %s :Not connected to server\r\n",
client->proxy_address, client->nick); client->proxy_address, client->nick);
return; return;
} }
/* check if the command could be redirected */ /* check if the command could be redirected */
if (g_strcmp0(cmd, "WHO") == 0) if (g_strcmp0(cmd, "WHO") == 0)
grab_who(client, args); grab_who(client, args);
else if (g_strcmp0(cmd, "WHOWAS") == 0) else if (g_strcmp0(cmd, "WHOWAS") == 0)
@ -263,29 +293,29 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args,
char *params, *target, *msg; char *params, *target, *msg;
params = event_get_params(args, 2 | PARAM_FLAG_GETREST, params = event_get_params(args, 2 | PARAM_FLAG_GETREST,
&target, &msg); &target, &msg);
proxy_outserver_all_except(client, "PRIVMSG %s", args); proxy_outserver_all_except(client, "PRIVMSG %s", args);
ignore_next = TRUE; ignore_next = TRUE;
if (*msg != '\001' || msg[strlen(msg)-1] != '\001') { if (*msg != '\001' || msg[strlen(msg)-1] != '\001') {
signal_emit(server_ischannel(SERVER(client->server), target) ? signal_emit(server_ischannel(SERVER(client->server), target) ?
"message own_public" : "message own_private", 4, "message own_public" : "message own_private", 4,
client->server, msg, target, target); client->server, msg, target, target);
} else if (strncmp(msg+1, "ACTION ", 7) == 0) { } else if (strncmp(msg+1, "ACTION ", 7) == 0) {
/* action */ /* action */
msg[strlen(msg)-1] = '\0'; msg[strlen(msg)-1] = '\0';
signal_emit("message irc own_action", 3, signal_emit("message irc own_action", 3,
client->server, msg+8, target); client->server, msg+8, target);
} else { } else {
/* CTCP */ /* CTCP */
char *p; char *p;
msg[strlen(msg)-1] = '\0'; msg[strlen(msg)-1] = '\0';
p = strchr(msg, ' '); p = strchr(msg, ' ');
if (p != NULL) *p++ = '\0'; else p = ""; if (p != NULL) *p++ = '\0'; else p = "";
signal_emit("message irc own_ctcp", 4, signal_emit("message irc own_ctcp", 4,
client->server, msg+1, p, target); client->server, msg+1, p, target);
} }
ignore_next = FALSE; ignore_next = FALSE;
g_free(params); g_free(params);
@ -337,7 +367,7 @@ static void sig_listen(LISTEN_REC *listen)
CLIENT_REC *rec; CLIENT_REC *rec;
IPADDR ip; IPADDR ip;
NET_SENDBUF_REC *sendbuf; NET_SENDBUF_REC *sendbuf;
GIOChannel *handle; GIOChannel *handle;
char host[MAX_IP_LEN]; char host[MAX_IP_LEN];
int port; int port;
@ -352,9 +382,13 @@ static void sig_listen(LISTEN_REC *listen)
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->host = g_strdup(host);
rec->port = port; rec->port = port;
if (g_strcmp0(listen->ircnet, "*") == 0) { if (g_strcmp0(listen->ircnet, "?") == 0) {
rec->multiplex = TRUE;
rec->proxy_address = g_strdup("multiplex.proxy");
rec->server = NULL;
} else if (g_strcmp0(listen->ircnet, "*") == 0) {
rec->proxy_address = g_strdup("irc.proxy"); rec->proxy_address = g_strdup("irc.proxy");
rec->server = servers == NULL ? NULL : IRC_SERVER(servers->data); rec->server = servers == NULL ? NULL : IRC_SERVER(servers->data);
} else { } else {
@ -363,15 +397,15 @@ static void sig_listen(LISTEN_REC *listen)
IRC_SERVER(server_find_chatnet(listen->ircnet)); IRC_SERVER(server_find_chatnet(listen->ircnet));
} }
rec->recv_tag = g_input_add(handle, G_INPUT_READ, rec->recv_tag = g_input_add(handle, G_INPUT_READ,
(GInputFunction) sig_listen_client, rec); (GInputFunction) sig_listen_client, rec);
proxy_clients = g_slist_prepend(proxy_clients, rec); proxy_clients = g_slist_prepend(proxy_clients, rec);
rec->listen->clients = g_slist_prepend(rec->listen->clients, rec); listen->clients = g_slist_prepend(listen->clients, rec);
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:%d on port %d (%s)",
rec->host, rec->port, listen->port, listen->ircnet); rec->host, rec->port, listen->port, listen->ircnet);
} }
static void sig_incoming(IRC_SERVER_REC *server, const char *line) static void sig_incoming(IRC_SERVER_REC *server, const char *line)

View File

@ -29,6 +29,7 @@ typedef struct {
unsigned int user_sent:1; unsigned int user_sent:1;
unsigned int connected:1; unsigned int connected:1;
unsigned int want_ctcp:1; unsigned int want_ctcp:1;
unsigned int multiplex:1;
} CLIENT_REC; } CLIENT_REC;
#endif #endif

View File

@ -157,6 +157,7 @@ static void perl_client_fill_hash(HV *hv, CLIENT_REC *client)
(void) hv_store(hv, "user_sent", 9, newSViv(client->user_sent), 0); (void) hv_store(hv, "user_sent", 9, newSViv(client->user_sent), 0);
(void) hv_store(hv, "connected", 9, newSViv(client->connected), 0); (void) hv_store(hv, "connected", 9, newSViv(client->connected), 0);
(void) hv_store(hv, "want_ctcp", 9, newSViv(client->want_ctcp), 0); (void) hv_store(hv, "want_ctcp", 9, newSViv(client->want_ctcp), 0);
(void) hv_store(hv, "multiplex", 9, newSViv(client->multiplex), 0);
(void) hv_store(hv, "ircnet", 6, new_pv(client->listen->ircnet), 0); (void) hv_store(hv, "ircnet", 6, new_pv(client->listen->ircnet), 0);
} }