luci-lib-ip: support specifying source address in route()
authorJo-Philipp Wich <jo@mein.io>
Tue, 6 Aug 2019 11:37:51 +0000 (13:37 +0200)
committerJo-Philipp Wich <jo@mein.io>
Tue, 6 Aug 2019 13:19:50 +0000 (15:19 +0200)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
libs/luci-lib-ip/src/ip.c
libs/luci-lib-ip/src/ip.luadoc

index 854a0c09c2e646323ae77456191adad7e7324d23..188a70f144847be4cfa348d78d5373dc959401e2 100644 (file)
@@ -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);
index a2df96cdb5c6c1fbbe161b40bcd683c4d7594cae..afd171bebf6d00179733054bce9a86b3e0cd6515 100644 (file)
@@ -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>