From: Michael Poole Date: Mon, 18 Oct 2004 03:15:00 +0000 (+0000) Subject: Allow Client and Operator blocks to be CIDR-based. X-Git-Url: http://git.pk910.de/?a=commitdiff_plain;h=de82d3dbd2135e3772433577a16ce752a13426bd;p=ircu2.10.12-pk.git Allow Client and Operator blocks to be CIDR-based. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1250 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- diff --git a/ChangeLog b/ChangeLog index e93870b..43db773 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2004-10-17 Michael Poole + + * include/s_conf.h (ConfItem): Add new field username. Replace + unused field bits with addrbits. + (find_conf_exact): Replace user and host arguments with cptr. + (find_conf_name, read_tlines, find_restrict): Remove declaration + for undefined functions. + (conf_parse_userhost): New function. + + * ircd/m_oper.c (m_oper): Update calls to find_conf_exact(): both + resolved hostname and IP are matched in one pass now. + + * ircd/s_bsd.c (close_connection): Update call to find_conf_exact(). + + * ircd/s_conf.c (conf_parse_userhost): New function. + (check_limit_and_attach): Use correct ConfItem field to determine + maximum connections per IP. + (attach_iline): Replace user@host matching with shorter, clearer + matching against username and host/IP fields. + (find_conf_exact): Likewise. + + * ircd/ircd_parser.y: Replace assignment to aconf->host for + CONF_CLIENT and CONF_OPERATOR with calls the CIDR-aware + conf_parse_userhost(). This means CONF_CLIENT ConfItems no longer + use the name field or the IP token. Remove the latter. + + * ircd/ircd_lexer.l: Remove unused token IP. + 2004-10-17 Michael Poole * ircd/crule.c (crule_via): Simplify the lookup for the directly diff --git a/include/s_conf.h b/include/s_conf.h index 066e9da..e58d9fa 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -53,6 +53,7 @@ struct ConfItem struct ConnectionClass *conn_class; /**< Class of connection */ struct irc_sockaddr origin; /**< Local address for outbound connections */ struct irc_sockaddr address; /**< IP and port */ + char *username; /**< For CONF_CLIENT and CONF_OPERATOR, username mask. */ char *host; /**< Peer hostname */ char *origin_name; /**< Text form of origin address */ char *passwd; /**< Password field */ @@ -62,7 +63,7 @@ struct ConfItem time_t hold; /**< Earliest time to attempt an outbound connect on this ConfItem. */ int dns_pending; /**< A dns request is pending. */ - unsigned char bits; /**< Number of bits for ipkills. */ + int addrbits; /**< Number of bits valid in ConfItem::address. */ struct Privs privs; /**< Privileges for opers. */ /** Used to detect if a privilege has been set by this ConfItem. */ struct Privs privs_dirty; @@ -171,17 +172,14 @@ extern struct ConfItem* conf_find_server(const char* name); extern void det_confs_butmask(struct Client *cptr, int mask); extern enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem *aconf); -extern struct ConfItem* find_conf_exact(const char* name, const char* user, - const char* host, int statmask); +extern struct ConfItem* find_conf_exact(const char* name, struct Client *cptr, int statmask); extern enum AuthorizationCheckResult conf_check_client(struct Client *cptr); extern int conf_check_server(struct Client *cptr); -extern struct ConfItem* find_conf_name(const char* name, int statmask); extern int rehash(struct Client *cptr, int sig); -extern void read_tlines(void); extern int find_kill(struct Client *cptr); -extern int find_restrict(struct Client *cptr); extern const char *find_quarantine(const char* chname); extern void lookup_confhost(struct ConfItem *aconf); +extern void conf_parse_userhost(struct ConfItem *aconf, char *host); extern void yyerror(const char *msg); diff --git a/ircd/ircd_lexer.l b/ircd/ircd_lexer.l index 2dd3e76..6207e3c 100644 --- a/ircd/ircd_lexer.l +++ b/ircd/ircd_lexer.l @@ -86,7 +86,6 @@ static struct lexer_token { TOKEN(REASON), TOKEN(RULE), TOKEN(ALL), - TOKEN(IP), TOKEN(CRULE), TOKEN(KILL), TOKEN(QUARANTINE), diff --git a/ircd/ircd_parser.y b/ircd/ircd_parser.y index 6b6469d..3b4d537 100644 --- a/ircd/ircd_parser.y +++ b/ircd/ircd_parser.y @@ -147,7 +147,6 @@ static void parse_error(char *pattern,...) { %token TFILE %token RULE %token ALL -%token IP %token FEATURES %token QUARANTINE %token PSEUDO @@ -493,7 +492,7 @@ operblock: OPER '{' operitems '}' ';' struct ConfItem *aconf = make_conf(CONF_OPERATOR); aconf->name = name; aconf->passwd = pass; - aconf->host = host; + conf_parse_userhost(aconf, host); aconf->conn_class = c_class; memcpy(&aconf->privs, &privs, sizeof(aconf->privs)); memcpy(&aconf->privs_dirty, &privs_dirty, sizeof(aconf->privs_dirty)); @@ -643,36 +642,28 @@ clientblock: CLIENT } '{' clientitems '}' ';' { - if (host && name) + if (host) { struct ConfItem *aconf = make_conf(CONF_CLIENT); - aconf->host = host; - aconf->name = name; + conf_parse_userhost(aconf, host); aconf->conn_class = c_class ? c_class : find_class("default"); aconf->maximum = maxlinks; } else { MyFree(host); - MyFree(name); parse_error("Bad client block"); } - host = name = NULL; + host = NULL; c_class = NULL; }; clientitems: clientitem clientitems | clientitem; -clientitem: clienthost | clientclass | clientpass | clientip - | clientmaxlinks | error; -clientip: IP '=' QSTRING ';' +clientitem: clienthost | clientclass | clientpass | clientmaxlinks | error; +clienthost: HOST '=' QSTRING ';' { MyFree(host); DupString(host, $3); }; -clienthost: HOST '=' QSTRING ';' -{ - MyFree(name); - DupString(name, $3); -}; clientclass: CLASS '=' QSTRING ';' { c_class = find_class($3); diff --git a/ircd/m_oper.c b/ircd/m_oper.c index 60e9997..47ee825 100644 --- a/ircd/m_oper.c +++ b/ircd/m_oper.c @@ -142,11 +142,7 @@ int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) if (EmptyString(name) || EmptyString(password)) return need_more_params(sptr, "OPER"); - aconf = find_conf_exact(name, cli_username(sptr), cli_sockhost(sptr), CONF_OPERATOR); - if (!aconf) - aconf = find_conf_exact(name, cli_username(sptr), - ircd_ntoa(&cli_ip(cptr)), CONF_OPERATOR); - + aconf = find_conf_exact(name, sptr, CONF_OPERATOR); if (!aconf || IsIllegal(aconf)) { send_reply(sptr, ERR_NOOPERHOST); diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c index 28e078a..8628cbc 100644 --- a/ircd/s_bsd.c +++ b/ircd/s_bsd.c @@ -430,7 +430,7 @@ void close_connection(struct Client *cptr) * If the connection has been up for a long amount of time, schedule * a 'quick' reconnect, else reset the next-connect cycle. */ - if ((aconf = find_conf_exact(cli_name(cptr), 0, cli_sockhost(cptr), CONF_SERVER))) { + if ((aconf = find_conf_exact(cli_name(cptr), cptr, CONF_SERVER))) { /* * Reschedule a faster reconnect, if this was a automaticly * connected configuration entry. (Note that if we have had diff --git a/ircd/s_conf.c b/ircd/s_conf.c index 11a8c77..c4516b3 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -69,7 +69,7 @@ /** Global list of all ConfItem structures. */ struct ConfItem *GlobalConfList; -/** Count of items in #GlobalConfLis. */ +/** Count of items in #GlobalConfList. */ int GlobalConfCount; /** Global list of service mappings. */ struct s_map *GlobalServiceMapList; @@ -194,6 +194,38 @@ static void detach_conf(struct Client* cptr, struct ConfItem* aconf) } } +/** Parse a user\@host mask into username and host or IP parts. + * If \a host contains no username part, set \a aconf->username to + * NULL. If the host part of \a host looks like an IP mask, set \a + * aconf->addrbits and \a aconf->address to match. Otherwise, set + * \a aconf->host, and set \a aconf->addrbits to -1. + * @param[in,out] aconf Configuration item to set. + * @param[in] host user\@host mask to parse. + */ +void conf_parse_userhost(struct ConfItem *aconf, char *host) +{ + char *host_part; + unsigned char addrbits; + + MyFree(aconf->username); + MyFree(aconf->host); + host_part = strchr(host, '@'); + if (host_part) { + *host_part = '\0'; + DupString(aconf->username, host); + host_part++; + } else { + aconf->username = NULL; + host_part = host; + } + DupString(aconf->host, host_part); + if (ipmask_parse(aconf->host, &aconf->address.addr, &addrbits)) + aconf->addrbits = addrbits; + else + aconf->addrbits = -1; + MyFree(host); +} + /** Copies a completed DNS query into its ConfItem. * @param vptr Pointer to struct ConfItem for the block. * @param hp DNS reply, or NULL if the lookup failed. @@ -322,8 +354,9 @@ void det_confs_butmask(struct Client* cptr, int mask) } /** Check client limits and attach Client block. - * If the password field consists of one or two digits, use that - * as the per-IP connection limit; otherwise use 255. + * If there are more connections from the IP than \a aconf->maximum + * allows, return ACR_TOO_MANY_FROM_IP. Otherwise, attach \a aconf to + * \a cptr. * @param cptr Client getting \a aconf. * @param aconf Configuration item to attach. * @return Authorization check result. @@ -331,16 +364,7 @@ void det_confs_butmask(struct Client* cptr, int mask) static enum AuthorizationCheckResult check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf) { - int number = 255; - - if (aconf->passwd) { - if (IsDigit(*aconf->passwd) && !aconf->passwd[1]) - number = *aconf->passwd-'0'; - else if (IsDigit(*aconf->passwd) && IsDigit(aconf->passwd[1]) && - !aconf->passwd[2]) - number = (*aconf->passwd-'0')*10+(aconf->passwd[1]-'0'); - } - if (IPcheck_nr(cptr) > number) + if (IPcheck_nr(cptr) > aconf->maximum) return ACR_TOO_MANY_FROM_IP; return attach_conf(cptr, aconf); } @@ -349,58 +373,32 @@ check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf) * @param cptr Client for whom to check rules. * @return Authorization check result. */ -enum AuthorizationCheckResult attach_iline(struct Client* cptr) +enum AuthorizationCheckResult attach_iline(struct Client* cptr) { struct ConfItem* aconf; - static char uhost[HOSTLEN + USERLEN + 3]; - static char fullname[HOSTLEN + 1]; struct DNSReply* hp; assert(0 != cptr); hp = cli_dns_reply(cptr); for (aconf = GlobalConfList; aconf; aconf = aconf->next) { - if (aconf->status != CONF_CLIENT) + if (aconf->status != CONF_CLIENT || !aconf->host) continue; if (aconf->address.port && aconf->address.port != cli_listener(cptr)->addr.port) continue; - if (!aconf->host || !aconf->name) - continue; + if (aconf->username) { + SetFlag(cptr, FLAG_DOID); + if (match(aconf->username, cli_username(cptr))) + continue; + } if (hp) { - ircd_strncpy(fullname, hp->h_name, HOSTLEN); - fullname[HOSTLEN] = '\0'; - - Debug((DEBUG_DNS, "a_il: %s->%s", cli_sockhost(cptr), fullname)); - - if (strchr(aconf->name, '@')) { - strcpy(uhost, cli_username(cptr)); - strcat(uhost, "@"); - } - else - *uhost = '\0'; - strncat(uhost, fullname, sizeof(uhost) - 1 - strlen(uhost)); - uhost[sizeof(uhost) - 1] = 0; - if (0 == match(aconf->name, uhost)) { - if (strchr(uhost, '@')) - SetFlag(cptr, FLAG_DOID); + Debug((DEBUG_DNS, "a_il: %s->%s", cli_sockhost(cptr), hp->h_name)); + if (!match(aconf->name, hp->h_name)) return check_limit_and_attach(cptr, aconf); - } - } - if (strchr(aconf->host, '@')) { - ircd_strncpy(uhost, cli_username(cptr), sizeof(uhost) - 2); - uhost[sizeof(uhost) - 2] = 0; - strcat(uhost, "@"); } - else - *uhost = '\0'; - strncat(uhost, cli_sock_ip(cptr), sizeof(uhost) - 1 - strlen(uhost)); - uhost[sizeof(uhost) - 1] = 0; - if (match(aconf->host, uhost)) - continue; - if (strchr(uhost, '@')) - SetFlag(cptr, FLAG_DOID); - - return check_limit_and_attach(cptr, aconf); + if ((aconf->addrbits >= 0) + && ipmask_check(&cli_ip(cptr), &aconf->address.addr, aconf->addrbits)) + return check_limit_and_attach(cptr, aconf); } return ACR_NO_AUTHORIZATION; } @@ -520,41 +518,33 @@ struct ConfItem* attach_confs_byhost(struct Client* cptr, const char* host, /** Find a ConfItem that has the same name and user+host fields as * specified. Requires an exact match for \a name. * @param name Name to match - * @param user User part of match (or NULL) - * @param host Hostname part of match + * @param cptr Client to match against * @param statmask Filter for ConfItem::status * @return First found matching ConfItem. */ -struct ConfItem* find_conf_exact(const char* name, const char* user, - const char* host, int statmask) +struct ConfItem* find_conf_exact(const char* name, struct Client *cptr, int statmask) { struct ConfItem *tmp; - char userhost[USERLEN + HOSTLEN + 3]; - - if (user) - ircd_snprintf(0, userhost, sizeof(userhost), "%s@%s", user, host); - else - ircd_strncpy(userhost, host, sizeof(userhost) - 1); for (tmp = GlobalConfList; tmp; tmp = tmp->next) { if (!(tmp->status & statmask) || !tmp->name || !tmp->host || 0 != ircd_strcmp(tmp->name, name)) continue; - /* - * Accept if the *real* hostname (usually sockecthost) - * socket host) matches *either* host or name field - * of the configuration. - */ - if (match(tmp->host, userhost)) + if (tmp->username + && (EmptyString(cli_username(cptr)) + || match(tmp->username, cli_username(cptr)))) continue; - if (tmp->status & CONF_OPERATOR) { - if (tmp->clients < MaxLinks(tmp->conn_class)) - return tmp; - else + if (tmp->addrbits < 0) + { + if (match(tmp->host, cli_sockhost(cptr))) continue; } - else - return tmp; + else if (!ipmask_check(&cli_ip(cptr), &tmp->address.addr, tmp->addrbits)) + continue; + if ((tmp->status & CONF_OPERATOR) + && (tmp->clients >= MaxLinks(tmp->conn_class))) + continue; + return tmp; } return 0; }