Changeset df67b48


Ignore:
Timestamp:
2017-04-03T20:55:50Z (3 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Children:
b1b9453
Parents:
c39cd8e
Message:

Add PROXY command. Not actually an IRC protocol command, it's a HAProxy
trick supported by stunnel to indicate where the connection originally
came from. Looks a little better on public servers.

Files:
3 edited

Legend:

Unmodified
Added
Removed
  • irc.c

    rc39cd8e rdf67b48  
    4141{
    4242        irc_t *irc;
    43         struct sockaddr_storage sock;
    44         socklen_t socklen = sizeof(sock);
    45         char *host = NULL, *myhost = NULL;
    4643        irc_user_t *iu;
    4744        GSList *l;
     
    6461        irc->iconv = (GIConv) - 1;
    6562        irc->oconv = (GIConv) - 1;
    66 
    67         if (global.conf->hostname) {
    68                 myhost = g_strdup(global.conf->hostname);
    69         } else if (getsockname(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
    70                 myhost = reverse_lookup((struct sockaddr*) &sock, socklen);
    71         }
    72 
    73         if (getpeername(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
    74                 host = reverse_lookup((struct sockaddr*) &sock, socklen);
    75         }
    76 
    77         if (host == NULL) {
    78                 host = g_strdup("localhost.localdomain");
    79         }
    80         if (myhost == NULL) {
    81                 myhost = g_strdup("localhost.localdomain");
    82         }
    8363
    8464        if (global.conf->ping_interval > 0 && global.conf->ping_timeout > 0) {
     
    128108
    129109        irc->root = iu = irc_user_new(irc, ROOT_NICK);
    130         iu->host = g_strdup(myhost);
    131110        iu->fullname = g_strdup(ROOT_FN);
    132111        iu->f = &irc_user_root_funcs;
    133112
    134113        iu = irc_user_new(irc, NS_NICK);
    135         iu->host = g_strdup(myhost);
    136114        iu->fullname = g_strdup(ROOT_FN);
    137115        iu->f = &irc_user_root_funcs;
    138116
    139117        irc->user = g_new0(irc_user_t, 1);
    140         irc->user->host = g_strdup(host);
     118       
     119        irc_set_hosts(irc, NULL, 0);
    141120
    142121        conf_loaddefaults(irc);
     
    154133        }
    155134
    156         g_free(myhost);
    157         g_free(host);
    158 
    159135        /* libpurple doesn't like fork()s after initializing itself, so this
    160136           is the right moment to initialize it. */
     
    176152
    177153        return irc;
     154}
     155
     156void irc_set_hosts(irc_t *irc, const struct sockaddr *remote_addr, const socklen_t remote_addrlen)
     157{
     158        struct sockaddr_storage sock;
     159        socklen_t socklen = sizeof(sock);
     160        char *host = NULL, *myhost = NULL;
     161        struct irc_user *iu;
     162
     163        if (global.conf->hostname) {
     164                myhost = g_strdup(global.conf->hostname);
     165        } else if (getsockname(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
     166                myhost = reverse_lookup((struct sockaddr*) &sock, socklen);
     167        }
     168
     169        if (remote_addrlen > 0) {
     170                host = reverse_lookup(remote_addr, remote_addrlen);
     171        } else if (getpeername(irc->fd, (struct sockaddr*) &sock, &socklen) == 0) {
     172                host = reverse_lookup((struct sockaddr*) &sock, socklen);
     173        }
     174
     175        if (myhost == NULL) {
     176                myhost = g_strdup("localhost.localdomain");
     177        }
     178        if (host == NULL) {
     179                host = g_strdup("localhost.localdomain");
     180        }
     181       
     182        if (irc->root->host != irc->root->nick) {
     183                g_free(irc->root->host);
     184        }
     185        irc->root->host = g_strdup(myhost);
     186        if ((iu = irc_user_by_name(irc, NS_NICK))) {
     187                if (iu->host != iu->nick) {
     188                        g_free(iu->host);
     189                }
     190                iu->host = g_strdup(myhost);
     191        }
     192       
     193        if (irc->user->host != irc->user->nick) {
     194                g_free(irc->user->host);
     195        }
     196        irc->user->host = g_strdup(host);
     197
     198        g_free(myhost);
     199        g_free(host);
    178200}
    179201
  • irc.h

    rc39cd8e rdf67b48  
    2626#ifndef _IRC_H
    2727#define _IRC_H
     28
     29#include <sys/socket.h>
    2830
    2931#define IRC_MAX_LINE 512
     
    271273
    272274irc_t *irc_new(int fd);
     275void irc_set_hosts(irc_t *irc, const struct sockaddr *remote_addr, const socklen_t remote_addrlen);
    273276void irc_abort(irc_t *irc, int immed, char *format, ...) G_GNUC_PRINTF(3, 4);
    274277void irc_free(irc_t *irc);
  • irc_commands.c

    rc39cd8e rdf67b48  
    5757                irc_check_login(irc);
    5858        }
     59}
     60
     61/* http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
     62
     63   This isn't actually IRC, it's used by for example stunnel4 to indicate
     64   the origin of the secured counterpart of the connection. It'll go wrong
     65   with arguments starting with : like for example "::1" but I guess I'm
     66   okay with that. */
     67static void irc_cmd_proxy(irc_t *irc, char **cmd)
     68{
     69        struct addrinfo hints, *ai;
     70        struct sockaddr_storage sock;
     71        socklen_t socklen = sizeof(sock);
     72
     73        if (getpeername(irc->fd, (struct sockaddr*) &sock, &socklen) != 0) {
     74                return;
     75        }
     76
     77        ipv64_normalise_mapped(&sock, &socklen);
     78
     79        /* Only accept PROXY "command" on localhost sockets. */
     80        if (!((sock.ss_family == AF_INET &&
     81               ntohl(((struct sockaddr_in*)&sock)->sin_addr.s_addr) == INADDR_LOOPBACK) ||
     82              (sock.ss_family == AF_INET6 &&
     83               IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6*)&sock)->sin6_addr)))) {
     84                return;
     85        }
     86
     87        /* And only once. Do this with a pretty dumb regex-match for
     88           now, maybe better to use some sort of flag.. */
     89        if (!g_regex_match_simple("^(ip6-)?localhost(.(localdomain.?)?)?$", irc->user->host, 0, 0)) {
     90                return;
     91        }
     92       
     93        memset(&hints, 0, sizeof(hints));
     94        hints.ai_flags = AI_NUMERICHOST;
     95        if (getaddrinfo(cmd[2], NULL, &hints, &ai) != 0) {
     96                return;
     97        }
     98       
     99        irc_set_hosts(irc, ai->ai_addr, ai->ai_addrlen);
     100        freeaddrinfo(ai);
    59101}
    60102
     
    808850        { "cap",         1, irc_cmd_cap,         0 },
    809851        { "pass",        1, irc_cmd_pass,        0 },
     852        { "proxy",       5, irc_cmd_proxy,       IRC_CMD_PRE_LOGIN },
    810853        { "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
    811854        { "nick",        1, irc_cmd_nick,        0 },
Note: See TracChangeset for help on using the changeset viewer.