Allow Client and Operator blocks to be CIDR-based.
authorMichael Poole <mdpoole@troilus.org>
Mon, 18 Oct 2004 03:15:00 +0000 (03:15 +0000)
committerMichael Poole <mdpoole@troilus.org>
Mon, 18 Oct 2004 03:15:00 +0000 (03:15 +0000)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@1250 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
include/s_conf.h
ircd/ircd_lexer.l
ircd/ircd_parser.y
ircd/m_oper.c
ircd/s_bsd.c
ircd/s_conf.c

index e93870bbb059a9c3be53042ad2ae5b47b24972a4..43db773e3a76b5af8755432073f19addb56099bb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2004-10-17  Michael Poole <mdpoole@troilus.org>
+
+       * 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 <mdpoole@troilus.org>
 
        * ircd/crule.c (crule_via): Simplify the lookup for the directly
index 066e9dacf3202e70f25a37cbdf4315ac6e905351..e58d9faf188b0f7143375b2d3c2324c678adcb2d 100644 (file)
@@ -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);
 
index 2dd3e769c1bb570484941afbab5a2eee4db84a12..6207e3c83c25ffa2531cb013afd1b67121620801 100644 (file)
@@ -86,7 +86,6 @@ static struct lexer_token {
   TOKEN(REASON),
   TOKEN(RULE),
   TOKEN(ALL),
-  TOKEN(IP),
   TOKEN(CRULE),
   TOKEN(KILL),
   TOKEN(QUARANTINE),
index 6b6469dd2401cb5c1a5a07bf59d18e4c0cea144f..3b4d5375c95d3bb2a7938fb63963b5eb3b270bb4 100644 (file)
@@ -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);
index 60e9997e66fcecea9151e53d45d9ab1b8d7cb235..47ee82570354aa19ed89399028fe3a8a6c082d63 100644 (file)
@@ -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);
index 28e078a1ad45a4d7a79ada7e5cc1186e51632593..8628cbccd084f2d4249ba9e9731bafc1f3cd534a 100644 (file)
@@ -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
index 11a8c77cd4da01b44154bc36cf23f939d6a0e69b..c4516b3c9e13e561222e65e2e901121a1840efd2 100644 (file)
@@ -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;
 }