
This patch adds IPv6 CIDR support using the new bitncmp and inet_parse_cidr functions. --- include/struct.h | 10 +++++-- src/m_rwho.c | 67 ++++++++++++++++++++++++++++++----------------------- src/m_who.c | 56 +++++++++++++++++++++++--------------------- 3 files changed, 74 insertions(+), 59 deletions(-) diff --git a/include/struct.h b/include/struct.h index 64a78e0..ee705cb 100644 --- a/include/struct.h +++ b/include/struct.h @@ -1439,8 +1439,12 @@ typedef struct SearchOptions char *ip; int class; int class_value; - unsigned int cidr4_ip; - unsigned int cidr4_mask; + int cidr_bits; + int cidr_family; + struct + { + char ip[16]; + } cidr_ip; int ts; int ts_value; aChannel *channel; @@ -1453,7 +1457,7 @@ typedef struct SearchOptions unsigned host_plus:1; unsigned gcos_plus:1; unsigned ip_plus:1; - unsigned cidr4_plus:1; + unsigned cidr_plus:1; unsigned chan_plus:1; unsigned serv_plus:1; unsigned away_plus:1; diff --git a/src/m_rwho.c b/src/m_rwho.c index 242dc04..64c79a0 100644 --- a/src/m_rwho.c +++ b/src/m_rwho.c @@ -33,7 +33,6 @@ #include "pcre.h" extern int user_modes[]; -extern unsigned int cidr_to_netmask(unsigned int); extern Link *find_channel_link(Link *, aChannel *); /* max capturing submatches to allow in all fields combined */ @@ -167,8 +166,12 @@ static struct { int (*host_func[2])(); /* host match function */ int umodes[2]; /* usermodes */ unsigned stype; /* services type */ - unsigned ip_mask[2]; /* IP netmask */ - unsigned ip_addr[2]; /* IP address */ + unsigned ip_family[2]; /* CIDR family to match */ + int ip_cidr_bits[2]; /* CIDR bits to match */ + struct + { + char ip[16]; + } ip_addr[2]; /* IP address */ char *ip_str[2]; /* IP string if CIDR is invalid */ ts_val ts[2]; /* signon timestamp */ int joined[2]; /* min/max joined chans */ @@ -439,27 +442,33 @@ static int rwho_parseopts(aClient *sptr, int parc, char *parv[]) rwho_synerr(sptr, "missing argument for match flag i"); return 0; } - if ((s = strchr(parv[arg], '/'))) - { - *s++ = 0; - i = strtol(s, &s, 10); - if (*s == 0 && 1 < i && i < 32) - rwho_opts.ip_mask[neg] = htonl(cidr_to_netmask(i)); - } - else - rwho_opts.ip_mask[neg] = ~0; - rwho_opts.ip_addr[neg] = inet_addr(parv[arg]); - if (!rwho_opts.ip_mask[neg] || - (rwho_opts.ip_mask[neg] != ~0 && - rwho_opts.ip_addr[neg] == 0xFFFFFFFF)) + if (strchr(parv[arg], '/')) { - rwho_synerr(sptr, "invalid CIDR IP for match flag i"); - return 0; + int bits; + + bits = inet_parse_cidr(AF_INET, parv[arg], + &rwho_opts.ip_addr[neg], + sizeof(struct in_addr)); + if (bits > 0) + rwho_opts.ip_family[neg] = AF_INET; + else + { + bits = inet_parse_cidr(AF_INET6, parv[arg], + &rwho_opts.ip_addr[neg], + sizeof(struct in6_addr)); + if (bits > 0) + rwho_opts.ip_family[neg] = AF_INET6; + } + if (bits > 0) + rwho_opts.ip_cidr_bits[neg] = bits; + else + { + rwho_synerr(sptr, "invalid CIDR IP for match flag i"); + return 0; + } } - if (rwho_opts.ip_addr[neg] == 0xFFFFFFFF) + else rwho_opts.ip_str[neg] = parv[arg]; - else - rwho_opts.ip_addr[neg] &= rwho_opts.ip_mask[neg]; rwho_opts.check[neg] |= RWM_IP; arg++; break; @@ -935,10 +944,10 @@ static int rwho_match(aClient *cptr, int *failcode, aClient **failclient) if (match(rwho_opts.ip_str[0], cptr->hostip)) return 0; } - else if (cptr->ip_family == AF_INET) + else if (cptr->ip_family == rwho_opts.ip_family[0]) { - if ((cptr->ip.ip4.s_addr & rwho_opts.ip_mask[0]) - != rwho_opts.ip_addr[0]) + if (bitncmp(&cptr->ip, &rwho_opts.ip_addr[0], + rwho_opts.ip_cidr_bits[0]) != 0) return 0; } else @@ -952,10 +961,10 @@ static int rwho_match(aClient *cptr, int *failcode, aClient **failclient) if (!match(rwho_opts.ip_str[1], cptr->hostip)) return 0; } - else if (cptr->ip_family == AF_INET) + else if (cptr->ip_family == rwho_opts.ip_family[1]) { - if ((cptr->ip.ip4.s_addr & rwho_opts.ip_mask[1]) - == rwho_opts.ip_addr[1]) + if (bitncmp(&cptr->ip, &rwho_opts.ip_addr[1], + rwho_opts.ip_cidr_bits[1]) == 0) return 0; } else diff --git a/src/m_who.c b/src/m_who.c index d64b7f5..703dca6 100644 --- a/src/m_who.c +++ b/src/m_who.c @@ -41,7 +41,6 @@ int chk_who(aClient *, int); extern int user_modes[]; extern Link *find_channel_link(Link *, aChannel *); -extern unsigned int cidr_to_netmask(unsigned int); int build_searchopts(aClient *sptr, int parc, char *parv[]) { @@ -317,33 +316,36 @@ int build_searchopts(aClient *sptr, int parc, char *parv[]) } else { - char *cpos; - - if((cpos = strchr(parv[args], '/'))) - { - char *err; - unsigned int maskval, ipval; - - *(cpos++) = '\0'; - - ipval = inet_addr(parv[args]); - maskval = strtol(cpos, &err, 10); - if(ipval == 0xFFFFFFFF || *err != '\0' || - maskval < 1 || maskval > 32) + if (strchr(parv[args], '/')) + { + int bits; + + bits = inet_parse_cidr(AF_INET, parv[args], + &wsopts.cidr_ip, + sizeof(wsopts.cidr_ip)); + if (bits > 0) + wsopts.cidr_family = AF_INET; + else + { + bits = inet_parse_cidr(AF_INET6, parv[args], + &wsopts.cidr_ip, + sizeof(wsopts.cidr_ip)); + if (bits > 0) + wsopts.cidr_family = AF_INET6; + } + if (bits > 0) + { + wsopts.cidr_bits = bits; + wsopts.cidr_plus = change; + } + else { sendto_one(sptr, getreply(ERR_WHOSYNTAX), me.name, sptr->name, "WHO", "who"); return 0; } - - maskval = htonl(cidr_to_netmask(maskval)); - ipval &= maskval; - - wsopts.cidr4_plus = change; - wsopts.cidr4_mask = maskval; - wsopts.cidr4_ip = ipval; - args++; - } + args++; + } else { wsopts.ip=parv[args]; @@ -470,7 +472,7 @@ int build_searchopts(aClient *sptr, int parc, char *parv[]) wsopts.serv_plus || wsopts.nick_plus || wsopts.user_plus || wsopts.ts_value || wsopts.client_type_plus || wsopts.ip_plus || - wsopts.chan_plus || wsopts.cidr4_mask)) + wsopts.chan_plus || wsopts.cidr_bits)) { if(parv[args]==NULL) { @@ -566,9 +568,9 @@ int chk_who(aClient *ac, int showall) (!wsopts.host_plus && !hchkfn(wsopts.host, ac->user->host))) return 0; - if(wsopts.cidr4_plus) - if(ac->ip_family != AF_INET || - (ac->ip.ip4.s_addr & wsopts.cidr4_mask) != wsopts.cidr4_ip) + if(wsopts.cidr_plus) + if(ac->ip_family != wsopts.cidr_family || + bitncmp(&ac->ip, &wsopts.cidr_ip, wsopts.cidr_bits) != 0) return 0; if(wsopts.ip_plus) -- 1.7.4.1