]> jfr.im git - solanum.git/blobdiff - ircd/newconf.c
opm: allow scanners to be configurable
[solanum.git] / ircd / newconf.c
index 9042ce78460c7b4ee28f60a38ccc26d4274675c3..b910957096848ee9275b929f9d8fb920a14f5f44 100644 (file)
@@ -57,6 +57,12 @@ static char *yy_blacklist_reason = NULL;
 static uint8_t yy_blacklist_iptype = 0;
 static rb_dlink_list yy_blacklist_filters = { NULL, NULL, 0 };
 
+static char *yy_opm_address_ipv4 = NULL;
+static char *yy_opm_address_ipv6 = NULL;
+static uint16_t yy_opm_port_ipv4 = 0;
+static uint16_t yy_opm_port_ipv6 = 0;
+static rb_dlink_list yy_opm_scanner_list;
+
 static char *yy_privset_extends = NULL;
 
 static const char *
@@ -886,7 +892,6 @@ conf_set_listen_port_both(void *data, int ssl)
 
                        add_listener(args->v.number, listener_address, family, ssl, ssl || yy_defer_accept);
                 }
-
        }
 }
 
@@ -1971,7 +1976,7 @@ conf_set_blacklist_reason(void *data)
                yy_blacklist_reason = rb_strdup(data);
                if (yy_blacklist_iptype & IPTYPE_IPV6)
                {
-                       /* Make sure things fit (64 = alnum count + dots in rDNS notation)
+                       /* Make sure things fit (magic number 64 = alnum count + dots)
                         * Example: 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa
                         */
                        if ((64 + strlen(yy_blacklist_host)) > IRCD_RES_HOSTLEN)
@@ -1984,8 +1989,8 @@ conf_set_blacklist_reason(void *data)
                /* Avoid doing redundant check, IPv6 is bigger than IPv4 --Elizabeth */
                if ((yy_blacklist_iptype & IPTYPE_IPV4) && !(yy_blacklist_iptype & IPTYPE_IPV6))
                {
-                       /* Make sure things fit (16 = number of nums + dots)
-                        * Example: 1.0.0.127.in-addr.arpa
+                       /* Make sure things fit for worst case (magic number 16 = number of nums + dots)
+                        * Example: 127.127.127.127.in-addr.arpa
                         */
                        if ((16 + strlen(yy_blacklist_host)) > IRCD_RES_HOSTLEN)
                        {
@@ -2014,6 +2019,268 @@ cleanup_bl:
        yy_blacklist_iptype = 0;
 }
 
+
+struct opm_scanner
+{
+       const char *type;
+       uint16_t port;
+
+       rb_dlink_node node;
+};
+
+static int
+conf_begin_opm(struct TopConf *tc)
+{
+       yy_opm_address_ipv4 = yy_opm_address_ipv6 = NULL;
+       yy_opm_port_ipv4 = yy_opm_port_ipv6 = 0;
+       return 0;
+}
+
+static int
+conf_end_opm(struct TopConf *tc)
+{
+       rb_dlink_node *ptr, *nptr;
+       bool fail = false;
+
+       if(!rb_dlink_list_length(&yy_opm_scanner_list))
+       {
+               conf_report_error("No opm scanners configured, disabling opm.");
+               fail = true;
+               goto end;
+       }
+
+       if(yy_opm_port_ipv4 > 0)
+       {
+               if(yy_opm_address_ipv4 != NULL)
+                       create_opm_listener(yy_opm_address_ipv4, yy_opm_port_ipv4);
+               else
+               {
+                       char ip[HOSTIPLEN];
+                       if(!rb_inet_ntop_sock((struct sockaddr *)&ServerInfo.ip, ip, sizeof(ip)))
+                               conf_report_error("No opm::listen_ipv4 nor serverinfo::vhost directive; cannot listen on IPv4");
+                       else
+                               create_opm_listener(ip, yy_opm_port_ipv4);
+               }
+       }
+
+       if(yy_opm_port_ipv6 > 0)
+       {
+               if(yy_opm_address_ipv6 != NULL)
+                       create_opm_listener(yy_opm_address_ipv6, yy_opm_port_ipv6);
+               else
+               {
+                       char ip[HOSTIPLEN];
+                       if(!rb_inet_ntop_sock((struct sockaddr *)&ServerInfo.ip6, ip, sizeof(ip)))
+                               conf_report_error("No opm::listen_ipv6 nor serverinfo::vhost directive; cannot listen on IPv6");
+                       else
+                               create_opm_listener(ip, yy_opm_port_ipv6);
+               }
+       }
+
+       /* If there's no listeners... */
+       fail = (yy_opm_port_ipv4 == 0 || yy_opm_port_ipv6 == 0);
+
+end:
+       RB_DLINK_FOREACH_SAFE(ptr, nptr, yy_opm_scanner_list.head)
+       {
+               struct opm_scanner *scanner = ptr->data;
+
+               if(!fail)
+                       create_opm_proxy_scanner(scanner->type, scanner->port);
+
+               rb_dlinkDelete(&scanner->node, &yy_opm_scanner_list);
+               rb_free(scanner);
+       }
+
+       rb_free(yy_opm_address_ipv4);
+       rb_free(yy_opm_address_ipv6);
+       return 0;
+}
+
+
+static void
+conf_set_opm_listen_address_both(void *data, bool ipv6)
+{
+       struct rb_sockaddr_storage addr;
+       const char *confstr = (ipv6 ? "opm::listen_ipv6" : "opm::listen_ipv4");
+       char *ip = data;
+
+       if(!rb_inet_pton_sock(ip, (struct sockaddr *)&addr))
+       {
+               conf_report_error("%s is an invalid address: %s", confstr, ip);
+               return;
+       }
+
+       if(ipv6)
+       {
+#ifdef RB_IPV6
+               if(GET_SS_FAMILY(&addr) != AF_INET6)
+               {
+                       conf_report_error("%s is of the wrong address type: %s", confstr, ip);
+                       return;
+               }
+
+               if(yy_opm_address_ipv6 != NULL)
+               {
+                       conf_report_error("%s overwrites previous address %s", confstr, ip);
+                       return;
+               }
+
+               yy_opm_address_ipv6 = rb_strdup(ip);
+#else
+               conf_report_error("%s requires IPv6 support in your ircd", confstr, ip);
+               return;
+#endif
+       }
+       else
+       {
+               if(GET_SS_FAMILY(&addr) != AF_INET)
+               {
+                       conf_report_error("%s is of the wrong address type: %s", confstr, ip);
+                       return;
+               }
+
+               if(yy_opm_address_ipv4 != NULL)
+               {
+                       conf_report_error("%s overwrites previous address %s", confstr, ip);
+                       return;
+               }
+
+               yy_opm_address_ipv4 = rb_strdup(ip);
+       }
+}
+
+static void
+conf_set_opm_listen_address_ipv4(void *data)
+{
+       conf_set_opm_listen_address_both(data, false);
+}
+
+static void
+conf_set_opm_listen_address_ipv6(void *data)
+{
+       conf_set_opm_listen_address_both(data, true);
+}
+
+static void
+conf_set_opm_listen_port_both(void *data, bool ipv6)
+{
+       int port = *((int *)data);
+       const char *confstr = (ipv6 ? "opm::port_ipv6" : "opm::port_ipv4");
+
+#ifndef RB_IPV6
+       if(ipv6)
+       {
+               conf_report_error("%s requires IPv6 support in your ircd", confstr);
+               return;
+       }
+#endif
+
+       if(port > 65535 || port <= 0)
+       {
+               conf_report_error("%s is out of range: %d", confstr, port);
+               return;
+       }
+
+       if(ipv6)
+       {
+               if(yy_opm_port_ipv4)
+               {
+                       conf_report_error("%s overwrites existing port %hu",
+                                       confstr, yy_opm_port_ipv4);
+                       return;
+               }
+
+               yy_opm_port_ipv4 = port;
+       }
+       else
+       {
+               if(yy_opm_port_ipv6)
+               {
+                       conf_report_error("%s overwrites existing port %hu",
+                                       confstr, yy_opm_port_ipv6);
+                       return;
+               }
+
+               yy_opm_port_ipv6 = port;
+       }
+}
+
+static void
+conf_set_opm_listen_port_ipv4(void *data)
+{
+       conf_set_opm_listen_port_both(data, false);
+}
+
+static void
+conf_set_opm_listen_port_ipv6(void *data)
+{
+       conf_set_opm_listen_port_both(data, true);
+}
+
+static void
+conf_set_opm_listen_port(void *data)
+{
+       conf_set_opm_listen_port_both(data, true);
+       conf_set_opm_listen_port_both(data, false);
+}
+
+static void
+conf_set_opm_scan_ports_all(void *data, const char *node, const char *type)
+{
+       conf_parm_t *args = data;
+       for (; args; args = args->next)
+       {
+               rb_dlink_node *ptr;
+               bool dup = false;
+
+               if(CF_TYPE(args->type) != CF_INT)
+               {
+                       conf_report_error("%s argument is not an integer -- ignoring.", node);
+                       continue;
+               }
+               
+               if(args->v.number > 65535 || args->v.number <= 0)
+               {
+                       conf_report_error("%s argument is not an integer between 1 and 65535 -- ignoring.", node);
+                       continue;
+               }
+
+               /* Check for duplicates */
+               RB_DLINK_FOREACH(ptr, yy_opm_scanner_list.head)
+               {
+                       struct opm_scanner *scanner = ptr->data;
+
+                       if(scanner->port == args->v.number && strcmp(type, scanner->type) == 0)
+                       {
+                               conf_report_error("%s argument is duplicate", node);
+                               dup = true;
+                               break;
+                       }
+               }
+
+               if(!dup)
+               {
+                       struct opm_scanner *scanner = rb_malloc(sizeof(struct opm_scanner));
+                       scanner->port = args->v.number;
+                       scanner->type = type;
+                       rb_dlinkAdd(scanner, &scanner->node, &yy_opm_scanner_list);
+               }
+       }
+}
+
+static void
+conf_set_opm_scan_ports_socks4(void *data)
+{
+       conf_set_opm_scan_ports_all(data, "opm::socks4_ports", "socks4");
+}
+
+static void
+conf_set_opm_scan_ports_socks5(void *data)
+{
+       conf_set_opm_scan_ports_all(data, "opm::socks5_ports", "socks5");
+}
+
 /* public functions */
 
 
@@ -2542,4 +2809,13 @@ newconf_init()
        add_conf_item("blacklist", "type", CF_STRING | CF_FLIST, conf_set_blacklist_type);
        add_conf_item("blacklist", "matches", CF_QSTRING | CF_FLIST, conf_set_blacklist_matches);
        add_conf_item("blacklist", "reject_reason", CF_QSTRING, conf_set_blacklist_reason);
+
+       add_top_conf("opm", conf_begin_opm, conf_end_opm, NULL);
+       add_conf_item("opm", "listen_ipv4", CF_QSTRING, conf_set_opm_listen_address_ipv4);
+       add_conf_item("opm", "listen_ipv6", CF_QSTRING, conf_set_opm_listen_address_ipv6);
+       add_conf_item("opm", "port_v4", CF_INT, conf_set_opm_listen_port_ipv4);
+       add_conf_item("opm", "port_v6", CF_INT, conf_set_opm_listen_port_ipv6);
+       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);
 }