shithub: riscv

Download patch

ref: 9ea93a5fd347a04ed409c46410cd5ead033c0695
parent: 407cf4ac6e59556b65d29b3c0de6ada6fdcc3cc7
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Jul 17 12:53:20 EDT 2020

libndb: order subnets by prefix length for ndbipinfo() lookups

to reproduce:

ipnet=foo0 ip=192.168.0.0 ipmask=/16
ipnet=foo1 ip=192.168.0.0 ipmask=/24
ip=192.168.0.1 sys=foo2

% ndb/ipquery sys foo2 ipnet ipmask
ipnet=foo0 ipmask=/16

we would expect to get ipnet=foo1 here as it is more
specific subnet.

the solution is to order the subnets by prefix length
in subnet() before calling filter(), so that we process
the longest prefixes first.

--- a/sys/src/libndb/ndbipinfo.c
+++ b/sys/src/libndb/ndbipinfo.c
@@ -114,17 +114,18 @@
 }
 
 /*
- *  look through a containing subset
+ *  look through containing subsets
  */
 static Ndbtuple*
 subnet(Ndb *db, uchar *net, Ndbtuple *f, int prefix)
 {
 	Ndbs s;
+	int nprefix;
 	char netstr[64];
 	uchar mask[IPaddrlen];
-	Ndbtuple *t, *nt, *xt;
+	Ndbtuple *at[128+1], *nt, *xt, *t;
 
-	t = nil;
+	memset(at, 0, sizeof(at));
 	snprint(netstr, sizeof(netstr), "%I", net);
 	nt = ndbsearch(db, &s, "ip", netstr);
 	while(nt != nil){
@@ -133,13 +134,20 @@
 			xt = ndbfindattr(nt, nt, "ipmask");
 			if(xt == nil || parseipmask(mask, xt->val, isv4(net)) == -1)
 				ipmove(mask, defmask(net));
-			if(prefixlen(mask) <= prefix){
-				t = ndbconcatenate(t, filter(db, nt, f));
+			nprefix = prefixlen(mask);
+			if(nprefix <= prefix && at[nprefix] == nil){
+				/* remember containing subnet, order by prefix length */
+				at[nprefix] = nt;
 				nt = nil;
 			}
 		}
 		ndbfree(nt);
 		nt = ndbsnext(&s, "ip", netstr);
+	}
+	/* filter subnets, longest prefix first */
+	for(t = nil; prefix >= 0; prefix--){
+		if(at[prefix] != nil)
+			t = ndbconcatenate(t, filter(db, at[prefix], f));
 	}
 	ndbsetmalloctag(t, getcallerpc(&db));
 	return t;