From 7d9e8e9d774c9e3cd5c45c273609996a9810af4c Mon Sep 17 00:00:00 2001 From: Ed Kellett Date: Mon, 6 Jul 2020 00:45:49 +0100 Subject: [PATCH] Add error handling to parse_netmask() --- include/hostmask.h | 2 ++ ircd/hostmask.c | 53 +++++++++++++++++++++++++++++++--------------- ircd/newconf.c | 3 ++- modules/m_dline.c | 13 +++++++----- modules/m_kline.c | 23 ++++++++++++-------- 5 files changed, 62 insertions(+), 32 deletions(-) diff --git a/include/hostmask.h b/include/hostmask.h index 28b47d66..7b2ce435 100644 --- a/include/hostmask.h +++ b/include/hostmask.h @@ -27,12 +27,14 @@ #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 *); diff --git a/ircd/hostmask.c b/ircd/hostmask.c index 94214041..751adcee 100644 --- a/ircd/hostmask.c +++ b/ircd/hostmask.c @@ -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]; diff --git a/ircd/newconf.c b/ircd/newconf.c index 9e200fd7..cff557fc 100644 --- a/ircd/newconf.c +++ b/ircd/newconf.c @@ -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; diff --git a/modules/m_dline.c b/modules/m_dline.c index cc62d572..e0766ac3 100644 --- a/modules/m_dline.c +++ b/modules/m_dline.c @@ -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 : ""; 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; diff --git a/modules/m_kline.c b/modules/m_kline.c index 14f6bbb5..0b1d0bf3 100644 --- a/modules/m_kline.c +++ b/modules/m_kline.c @@ -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;