*** db.c.orig	Mon Nov 11 12:44:28 1996
--- db.c	Mon Feb 17 07:42:48 1997
***************
*** 1,6 ****
--- 1,8 ----
  /*
   *	Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
   *	This will be free software, but only when it is finished.
+  *
+  *	'longestmatch' driver kissg@sztaki.hu 970209
   */
  
  /*
***************
*** 138,143 ****
--- 140,146 ----
  /* drivers */
  static struct conscell	*find_domain __((struct conscell *(*lookupfn)(), struct search_info *sip));
  static struct conscell	*find_nodot_domain __((struct conscell *(*lookupfn)(), struct search_info *sip));
+ static struct conscell	*find_longest_match __((struct conscell *(*lookupfn)(), struct search_info *sip));
  /* others.. */
  static void cacheflush __((struct db_info *dbip));
  extern struct conscell	*readchunk __((char *file, long offset));
***************
*** 179,184 ****
--- 182,189 ----
  				proto_config.driver = find_nodot_domain;
  			else if (strcmp(optarg, "pathalias") == 0)
  				proto_config.driver = find_domain;
+ 			else if (strcmp(optarg, "longestmatch") == 0)
+ 				proto_config.driver = find_longest_match;
  			else
  				++errflg;
  			break;
***************
*** 940,945 ****
--- 945,1029 ----
  }
  
  /*
+  * Searching the longest match.
+  *
+  * The lookup sequence for foo.bar.edu is:
+  *
+  *	foo.bar.edu
+  *	.bar.edu
+  *	.edu
+  *	.
+  *
+  * The lookup sequence for 1.2.3.13 is:
+  *
+  *	1.2.3.13/32
+  *	1.2.3.12/31
+  *	1.2.3.12/30
+  *	1.2.3.8/29
+  *	1.2.3.0/28
+  *      ...
+  *	1.0.0.0/8
+  *	...
+  *	0.0.0.0/1
+  *	0.0.0.0/0
+  */
+ 
+ static struct conscell *
+ find_longest_match(lookupfn, sip)
+ 	struct conscell *(*lookupfn)();
+ 	struct search_info *sip;
+ {
+ 	register u_char *cp;
+ 	struct conscell *l;
+ 	u_char buf[BUFSIZ], *realkey;
+ 	unsigned int oct1,oct2,oct3,oct4;
+ 
+ 	if (sscanf((char*)(sip->key[0]=='[' ? sip->key+1 : sip->key),
+ 	    "%3u.%3u.%3u.%3u",
+ 	    &oct1,&oct2,&oct3,&oct4) == 4) { /* IP address with optional [] */
+ 		unsigned int h_addr,h_mask;
+ 		int prefix;
+ 		h_addr=(((oct1&255)<<8|oct2&255)<<8|oct3&255)<<8|oct4&255;
+ 		sip->key=buf;
+ 		for (prefix=32, h_mask=0xffffffffL;
+ 		    prefix>=0;  --prefix, h_mask<<=1) {
+ 			sprintf((char*)buf,"%u.%u.%u.%u/%d",
+ 			    (h_addr&h_mask) >> 24 & 255,
+ 			    (h_addr&h_mask) >> 16 & 255,
+ 			    (h_addr&h_mask) >>  8 & 255,
+ 			    (h_addr&h_mask)       & 255,
+ 			    prefix);
+ 			if ((l = (*lookupfn)(sip)) != NULL)
+ 				return l;
+ 		}
+ 	}
+ 	else {	/* domain name */
+ 		/* check the key as given */
+ 		if ((l = (*lookupfn)(sip)) != NULL)
+ 			return l;
+ 		realkey = sip->key;
+ 		/* iterate over the superdomains of the key */
+ 		for (cp = realkey; *cp;) {
+ 			while (*cp && *cp != '.')
+ 				++cp;
+ 			while (*cp == '.')
+ 				++cp;
+ 			if (*(cp-1) == '.') {
+ 				sip->key = cp-1;
+ 				if ((l = (*lookupfn)(sip)) != NULL)
+ 					return l;
+ 			}
+ 		}
+ 		/* Still failed ?  Try to look for "." */
+ 		sip->key = ".";
+ 		if ((l = (*lookupfn)(sip)) != NULL)
+ 			return l;
+ 	}
+ 	
+ 	return NULL;
+ }
+ 
+ /*
   * This routine is good for looking up foo.bar.edu in e.g. a gateway list.
   * It is typically used for pathalias database lookup.
   *
***************
*** 949,954 ****
--- 1033,1039 ----
   *	.bar.edu
   *	.edu
   *	.foo.bar.edu
+  *	.
   */
  
  static struct conscell *
