diff --git a/authd/providers/opm.c b/authd/providers/opm.c index 6156d617..832872d6 100644 --- a/authd/providers/opm.c +++ b/authd/providers/opm.c @@ -32,6 +32,7 @@ typedef enum protocol_t PROTO_NONE, PROTO_SOCKS4, PROTO_SOCKS5, + PROTO_HTTP_CONNECT, } protocol_t; struct opm_lookup @@ -88,12 +89,14 @@ static bool opm_enable = false; static struct opm_listener listeners[2]; static inline protocol_t -get_protocol_from_string(const char *string) +get_protocol_from_string(const char *str) { - if(strcasecmp(string, "socks4") == 0) + if(strcasecmp(str, "socks4") == 0) return PROTO_SOCKS4; - else if(strcasecmp(string, "socks5") == 0) + else if(strcasecmp(str, "socks5") == 0) return PROTO_SOCKS5; + else if(strcasecmp(str, "httpconnect") == 0) + return PROTO_HTTP_CONNECT; else return PROTO_NONE; } @@ -145,7 +148,7 @@ read_opm_reply(rb_fde_t *F, void *data) { struct opm_proxy *proxy = ptr->data; - if(strncmp(proxy->note, readbuf, sizeof(readbuf)) == 0) + if(strncmp(proxy->note, readbuf, strlen(proxy->note)) == 0) { rb_dlink_node *ptr, *nptr; @@ -293,7 +296,7 @@ static void socks5_connected(rb_fde_t *F, int error, void *data) { struct opm_scan *scan = data; - struct opm_lookup *lookup; + struct opm_lookup *lookup; struct opm_listener *listener; struct auth_client *auth; uint8_t sendbuf[25]; /* Size we're building */ @@ -307,7 +310,7 @@ socks5_connected(rb_fde_t *F, int error, void *data) goto end; /* Build the version header and socks request - * version header (3 bytes): version, number of auth methods, auth type (0 for none) + * version header (3 bytes): version, number of auth methods, auth type (0 for none) * connect req (3 bytes): version, command (1 = connect), reserved (0) */ memcpy(c, "\x05\x01\x00\x05\x01\x00", 6); c += 6; @@ -352,6 +355,62 @@ end: rb_free(scan); } +static void +http_connect_connected(rb_fde_t *F, int error, void *data) +{ + struct opm_scan *scan = data; + struct opm_lookup *lookup; + struct opm_listener *listener; + struct auth_client *auth; + char sendbuf[128]; /* A bit bigger than we need but better safe than sorry */ + char *c = sendbuf; + ssize_t ret; + + if(scan == NULL || (auth = scan->auth) == NULL || (lookup = auth->data[PROVIDER_OPM]) == NULL) + return; + + if(error || !opm_enable) + goto end; + + switch(GET_SS_FAMILY(&auth->c_addr)) + { + case AF_INET: + listener = &listeners[LISTEN_IPV4]; + if(!listener->F) + goto end; + break; +#ifdef RB_IPV6 + case AF_INET6: + listener = &listeners[LISTEN_IPV6]; + if(!listener->F) + goto end; + break; +#endif + default: + goto end; + } + + /* Simple enough to build */ + snprintf(sendbuf, sizeof(sendbuf), "CONNECT %s:%hu HTTP/1.0\r\n\r\n", listener->ip, listener->port); + + /* Send request */ + if(rb_write(scan->F, sendbuf, strlen(sendbuf)) <= 0) + goto end; + + /* Now the note in a separate write */ + if(rb_write(scan->F, scan->proxy->note, strlen(scan->proxy->note) + 1) <= 0) + goto end; + + /* MiroTik needs this, and as a separate write */ + if(rb_write(scan->F, "\r\n", 2) <= 0) + goto end; + +end: + rb_close(scan->F); + rb_dlinkDelete(&scan->node, &lookup->scans); + rb_free(scan); +} + /* Establish connections */ static inline void establish_connection(struct auth_client *auth, struct opm_proxy *proxy) @@ -378,6 +437,8 @@ establish_connection(struct auth_client *auth, struct opm_proxy *proxy) case PROTO_SOCKS5: callback = socks5_connected; break; + case PROTO_HTTP_CONNECT: + callback = http_connect_connected; default: return; } @@ -697,6 +758,9 @@ create_opm_scanner(const char *key __unused, int parc __unused, const char **par case PROTO_SOCKS5: snprintf(proxy->note, sizeof(proxy->note), "socks5:%hu", proxy->port); break; + case PROTO_HTTP_CONNECT: + snprintf(proxy->note, sizeof(proxy->note), "httpconnect:%hu", proxy->port); + break; default: warn_opers(L_CRIT, "OPM: got an unknown proxy type: %s (port %hu)", parv[0], proxy->port); exit(EX_PROVIDER_ERROR); diff --git a/doc/ircd.conf.example b/doc/ircd.conf.example index dfaa03cc..0ad8bf32 100644 --- a/doc/ircd.conf.example +++ b/doc/ircd.conf.example @@ -475,6 +475,12 @@ opm { * with other scan types. Sensible defaults are given below. */ socks5_ports = 1080, 10800, 443, 80, 8080, 8000; + + /* These are the ports to scan for HTTP connect proxies on (plaintext). + * They may overlap with other scan types. Sensible defaults are given + * below. + */ + httpconnect_ports = 80, 8080, 8000; }; alias "NickServ" { diff --git a/doc/reference.conf b/doc/reference.conf index b327ed3f..5d37ed5e 100644 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -950,6 +950,12 @@ opm { * with other scan types. Sensible defaults are given below. */ socks5_ports = 80, 443, 1080, 8000, 8080, 10800; + + /* These are the ports to scan for HTTP connect proxies on (plaintext). + * They may overlap with other scan types. Sensible defaults are given + * below. + */ + httpconnect_ports = 80, 8080, 8000; }; /* diff --git a/ircd/newconf.c b/ircd/newconf.c index c2fb980c..c3a8fb00 100644 --- a/ircd/newconf.c +++ b/ircd/newconf.c @@ -2290,6 +2290,12 @@ conf_set_opm_scan_ports_socks5(void *data) conf_set_opm_scan_ports_all(data, "opm::socks5_ports", "socks5"); } +static void +conf_set_opm_scan_ports_httpconnect(void *data) +{ + conf_set_opm_scan_ports_all(data, "opm::httpconnect_ports", "httpconnect"); +} + /* public functions */ @@ -2828,4 +2834,5 @@ newconf_init() add_conf_item("opm", "listen_port", CF_INT, conf_set_opm_listen_port); add_conf_item("opm", "socks4_ports", CF_INT | CF_FLIST, conf_set_opm_scan_ports_socks4); add_conf_item("opm", "socks5_ports", CF_INT | CF_FLIST, conf_set_opm_scan_ports_socks5); + add_conf_item("opm", "httpconnect_ports", CF_INT | CF_FLIST, conf_set_opm_scan_ports_httpconnect); }