]> jfr.im git - irc/charybdis-ircd/charybdis.git/commitdiff
Add error handling to parse_netmask()
authorEd Kellett <redacted>
Sun, 5 Jul 2020 23:45:49 +0000 (00:45 +0100)
committerEd Kellett <redacted>
Sun, 26 Jul 2020 21:03:06 +0000 (22:03 +0100)
include/hostmask.h
ircd/hostmask.c
ircd/newconf.c
modules/m_dline.c
modules/m_kline.c

index 28b47d66e2b358b4c1e73e05441ce54578749455..7b2ce4354685bdc670750a39298132e9bb69b944 100644 (file)
 #define INCLUDE_hostmask_h 1
 enum
 {
+       HM_ERROR,
        HM_HOST,
        HM_IPV4,
        HM_IPV6,
 };
 
 int parse_netmask(const char *, struct rb_sockaddr_storage *, int *);
+int parse_netmask_strict(const char *, struct rb_sockaddr_storage *, int *);
 struct ConfItem *find_conf_by_address(const char *host, const char *sockhost,
                                      const char *orighost, struct sockaddr *,
                                      int, int, const char *, const char *);
index 942140411614b4f93e55ddc6736dcaa239ab217e..751adceef759b64befadfddd29c3cff0d0db4577 100644 (file)
@@ -35,18 +35,12 @@ static unsigned long hash_ipv6(struct sockaddr *, int);
 static unsigned long hash_ipv4(struct sockaddr *, int);
 
 
-/* int parse_netmask(const char *, struct rb_sockaddr_storage *, int *);
- * Input: A hostmask, or an IPV4/6 address.
- * Output: An integer describing whether it is an IPV4, IPV6 address or a
- *         hostmask, an address(if it is an IP mask),
- *         a bitlength(if it is IP mask).
- * Side effects: None
- */
-int
-parse_netmask(const char *text, struct rb_sockaddr_storage *naddr, int *nb)
+static int
+_parse_netmask(const char *text, struct rb_sockaddr_storage *naddr, int *nb, bool strict)
 {
        char *ip = LOCAL_COPY(text);
        char *ptr;
+       char *endp;
        struct rb_sockaddr_storage *addr, xaddr;
        int *b, xb;
        if(nb == NULL)
@@ -69,11 +63,15 @@ parse_netmask(const char *text, struct rb_sockaddr_storage *naddr, int *nb)
                {
                        *ptr = '\0';
                        ptr++;
-                       *b = atoi(ptr);
-                       if(*b > 128)
-                               *b = 128;
-                       else if(*b < 0)
+                       long n = strtol(ptr, &endp, 10);
+                       if (endp == ptr || n < 0)
                                return HM_HOST;
+                       if (n > 128 || *endp != '\0')
+                               if (strict)
+                                       return HM_ERROR;
+                               else
+                                       n = 128;
+                       *b = n;
                } else
                        *b = 128;
                if(rb_inet_pton_sock(ip, addr) > 0)
@@ -87,11 +85,15 @@ parse_netmask(const char *text, struct rb_sockaddr_storage *naddr, int *nb)
                {
                        *ptr = '\0';
                        ptr++;
-                       *b = atoi(ptr);
-                       if(*b > 32)
-                               *b = 32;
-                       else if(*b < 0)
+                       long n = strtol(ptr, &endp, 10);
+                       if (endp == ptr || n < 0)
                                return HM_HOST;
+                       if (n > 32 || *endp != '\0')
+                               if (strict)
+                                       return HM_ERROR;
+                               else
+                                       n = 32;
+                       *b = n;
                } else
                        *b = 32;
                if(rb_inet_pton_sock(ip, addr) > 0)
@@ -102,6 +104,23 @@ parse_netmask(const char *text, struct rb_sockaddr_storage *naddr, int *nb)
        return HM_HOST;
 }
 
+/* int parse_netmask(const char *, struct rb_sockaddr_storage *, int *);
+ * Input: A hostmask, or an IPV4/6 address.
+ * Output: An integer describing whether it is an IPV4, IPV6 address or a
+ *         hostmask, an address(if it is an IP mask),
+ *         a bitlength(if it is IP mask).
+ * Side effects: None
+ */
+int parse_netmask(const char *mask, struct rb_sockaddr_storage *addr, int *blen)
+{
+       return _parse_netmask(mask, addr, blen, false);
+}
+
+int parse_netmask_strict(const char *mask, struct rb_sockaddr_storage *addr, int *blen)
+{
+       return _parse_netmask(mask, addr, blen, true);
+}
+
 /* Hashtable stuff...now external as its used in m_stats.c */
 struct AddressRec *atable[ATABLE_SIZE];
 
index 9e200fd79716a40b58b1ba3bc04be3025df85262..cff557fc94be10a154eabe51be451482d7a49277 100644 (file)
@@ -1515,8 +1515,9 @@ static void
 conf_set_exempt_ip(void *data)
 {
        struct ConfItem *yy_tmp;
+       int masktype = parse_netmask_strict(data, NULL, NULL);
 
-       if(parse_netmask(data, NULL, NULL) == HM_HOST)
+       if(masktype != HM_IPV4 && masktype != HM_IPV6)
        {
                conf_report_error("Ignoring exempt -- invalid exempt::ip.");
                return;
index cc62d5725d4bfee4f1c9f0d5a7ee8d65868955ef..e0766ac3473045da5472a2437b153d028d69c7aa 100644 (file)
@@ -216,8 +216,8 @@ apply_dline(struct Client *source_p, const char *dlhost, int tdline_time, char *
        int t = AF_INET, ty, b;
        const char *creason;
 
-       ty = parse_netmask(dlhost, &daddr, &b);
-       if(ty == HM_HOST)
+       ty = parse_netmask_strict(dlhost, &daddr, &b);
+       if(ty != HM_IPV4 && ty != HM_IPV6)
        {
                sendto_one(source_p, ":%s NOTICE %s :Invalid D-Line", me.name, source_p->name);
                return;
@@ -252,8 +252,9 @@ apply_dline(struct Client *source_p, const char *dlhost, int tdline_time, char *
                if((aconf = find_dline((struct sockaddr *) &daddr, t)) != NULL)
                {
                        int bx;
-                       parse_netmask(aconf->host, NULL, &bx);
-                       if(b >= bx)
+                       int masktype = parse_netmask_strict(aconf->host, NULL, &bx);
+
+                       if (masktype != HM_ERROR && b >= bx)
                        {
                                creason = aconf->passwd ? aconf->passwd : "<No Reason>";
                                if(IsConfExemptKline(aconf))
@@ -354,7 +355,9 @@ apply_undline(struct Client *source_p, const char *cidr)
        char buf[BUFSIZE];
        struct ConfItem *aconf;
 
-       if(parse_netmask(cidr, NULL, NULL) == HM_HOST)
+       int masktype = parse_netmask_strict(cidr, NULL, NULL);
+
+       if(masktype != HM_IPV4 && masktype != HM_IPV6)
        {
                sendto_one_notice(source_p, ":Invalid D-Line");
                return;
index 14f6bbb525c48637f6c6b59eeb91fb9215c9a7f2..0b1d0bf3105bafb280dc3dd179f7f8397e76a3de 100644 (file)
@@ -153,6 +153,14 @@ mo_kline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source
 
        reason = LOCAL_COPY(parv[loc]);
 
+       if(parse_netmask_strict(host, NULL, NULL) == HM_ERROR)
+       {
+               sendto_one_notice(source_p,
+                               ":[%s@%s] looks like an ill-formed IP K-line, refusing to set it",
+                               user, host);
+               return;
+       }
+
        if(target_server != NULL)
        {
                propagate_generic(source_p, "KLINE", target_server, CAP_KLN,
@@ -700,15 +708,12 @@ already_placed_kline(struct Client *source_p, const char *luser, const char *lho
        if(aconf == NULL && ConfigFileEntry.non_redundant_klines)
        {
                bits = 0;
-               if((t = parse_netmask(lhost, &iphost, &bits)) != HM_HOST)
-               {
-                       if(t == HM_IPV6)
-                               t = AF_INET6;
-                       else
-                               t = AF_INET;
-
-                       piphost = &iphost;
-               }
+               t = parse_netmask_strict(lhost, &iphost, &bits);
+               piphost = &iphost;
+               if (t == HM_IPV4)
+                       t = AF_INET;
+               else if (t == HM_IPV6)
+                       t = AF_INET6;
                else
                        piphost = NULL;