Browse Source

luci-lib-ip: support specifying source address in route()

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Jo-Philipp Wich 4 years ago
parent
commit
d73553e530
2 changed files with 42 additions and 18 deletions
  1. 40 18
      libs/luci-lib-ip/src/ip.c
  2. 2 0
      libs/luci-lib-ip/src/ip.luadoc

+ 40 - 18
libs/luci-lib-ip/src/ip.c

@@ -1075,22 +1075,24 @@ static int cb_dump_route(struct nl_msg *msg, void *arg)
 
 	bitlen = AF_BITS(rt->rtm_family);
 
-	if ((f->type   && rt->rtm_type     != f->type)   ||
-	    (f->family && rt->rtm_family   != f->family) ||
-	    (f->proto  && rt->rtm_protocol != f->proto)  ||
-	    (f->scope  && rt->rtm_scope    != f->scope)  ||
-		(f->iif    && iif              != f->iif)    ||
-		(f->oif    && oif              != f->oif)    ||
-		(f->table  && table            != f->table)  ||
-	    diff_prefix(rt->rtm_family, from, rt->rtm_src_len,
-	                f->from_exact, &f->from)         ||
-	    diff_prefix(rt->rtm_family, dst,  rt->rtm_dst_len,
-	                f->dst_exact, &f->dst)           ||
-	    diff_prefix(rt->rtm_family, gw,   bitlen,
-	                false, &f->gw)                   ||
-	    diff_prefix(rt->rtm_family, src,  bitlen,
-	                false, &f->src))
-		goto out;
+	if (!f->get) {
+		if ((f->type   && rt->rtm_type     != f->type)   ||
+		    (f->family && rt->rtm_family   != f->family) ||
+		    (f->proto  && rt->rtm_protocol != f->proto)  ||
+		    (f->scope  && rt->rtm_scope    != f->scope)  ||
+		    (f->iif    && iif              != f->iif)    ||
+		    (f->oif    && oif              != f->oif)    ||
+		    (f->table  && table            != f->table)  ||
+		    diff_prefix(rt->rtm_family, from, rt->rtm_src_len,
+		                f->from_exact, &f->from)         ||
+		    diff_prefix(rt->rtm_family, dst,  rt->rtm_dst_len,
+		                f->dst_exact, &f->dst)           ||
+		    diff_prefix(rt->rtm_family, gw,   bitlen,
+		                false, &f->gw)                   ||
+		    diff_prefix(rt->rtm_family, src,  bitlen,
+		                false, &f->src))
+			goto out;
+	}
 
 	if (s->callback)
 		lua_pushvalue(s->L, 2);
@@ -1216,10 +1218,15 @@ static int _route_dump(lua_State *L, struct dump_filter *filter)
 
 	nlmsg_append(msg, &rtm, sizeof(rtm), 0);
 
-	if (filter->get)
+	if (filter->get) {
 		nla_put(msg, RTA_DST, AF_BYTES(filter->dst.family),
 		        &filter->dst.addr.v6);
 
+		if (filter->src.family)
+			nla_put(msg, RTA_SRC, AF_BYTES(filter->src.family),
+			        &filter->src.addr.v6);
+	}
+
 	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_dump_route, &s);
 	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &s);
 	nl_cb_err(cb, NL_CB_CUSTOM, cb_error, &s);
@@ -1236,17 +1243,32 @@ static int _route_dump(lua_State *L, struct dump_filter *filter)
 
 out:
 	nl_cb_put(cb);
-	return (s.callback == 0);
+
+	if (s.callback)
+		return 0;
+
+	if (!filter->get)
+		return 1;
+
+	return (s.index > 0);
 }
 
 static int route_get(lua_State *L)
 {
 	struct dump_filter filter = { .get = true };
 	const char *dest = luaL_checkstring(L, 1);
+	const char *from = luaL_optstring(L, 2, NULL);
 
 	if (!parse_cidr(dest, &filter.dst))
 		return _error(L, -1, "Invalid destination");
 
+	if (from && !parse_cidr(from, &filter.src))
+		return _error(L, -1, "Invalid source");
+
+	if (filter.src.family != 0 &&
+	    filter.src.family != filter.dst.family)
+		return _error(L, -1, "Different source/destination family");
+
 	filter.family = filter.dst.family;
 
 	return _route_dump(L, &filter);

+ 2 - 0
libs/luci-lib-ip/src/ip.luadoc

@@ -178,6 +178,8 @@ Determine the route leading to the given destination.
 @name route
 @param address	A `luci.ip.cidr` instance or a string containing
 a valid IPv4 or IPv6 range as specified by `luci.ip.new()`.
+@param source   A `luci.ip.cidr` instance or a string containing
+the preferred source address for route selection (optional).
 @return <p>Table containing the fields described below.</p>
 <table id="routetable">
 <tr><th>Field</th><th>Description</th></tr>