Skip to content

Commit d0f7f1e

Browse files
committed
[plugin_core] add map_cidr action
Change-Id: I24092d6f2b1c76e2b2399c8f6bcc5ac6365ac0c2
1 parent 11df378 commit d0f7f1e

File tree

2 files changed

+161
-0
lines changed

2 files changed

+161
-0
lines changed

doc/plugin_core.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,32 @@
679679
</example>
680680
</action>
681681

682+
<action name="map_cidr">
683+
<short>maps the client IP to a user defined action</short>
684+
<parameter name="mapping">
685+
<short>maps CIDRs or lists of CIDRs to actions</short>
686+
</parameter>
687+
<description><markdown>
688+
The most specific CIDR (longest prefix length) takes precedence; if one CIDR is used more than once the last entry wins.
689+
`default` or `"all"` matches every client address (even those not associated with an IP).
690+
</markdown></description>
691+
<example>
692+
<config>
693+
map_cidr [
694+
"192.168.0.0/16" => {
695+
respond 200 => "root";
696+
},
697+
["10.0.0.0/8", "172.12.0.0/16"] => {
698+
respond 200 => "news";
699+
},
700+
default => {
701+
respond 404;
702+
},
703+
];
704+
</config>
705+
</example>
706+
</action>
707+
682708
<setup name="listen">
683709
<short>listen to a socket address, see above for accepted formats (default TCP port is 80)</short>
684710
<parameter name="socket-address">

src/main/plugin_core.c

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,140 @@ static liAction* core_map(liServer *srv, liWorker *wrk, liPlugin* p, liValue *va
18961896
return li_action_new_function(core_handle_map, NULL, core_map_free, md);
18971897
}
18981898

1899+
typedef struct core_map_cidr_data core_map_cidr_data;
1900+
struct core_map_cidr_data {
1901+
GPtrArray *actions;
1902+
liRadixTree *ipv4; /* map to index in actions */
1903+
liRadixTree *ipv6; /* map to index in actions */
1904+
gint default_action;
1905+
};
1906+
static void core_map_cidr_free(liServer *srv, gpointer param) {
1907+
core_map_cidr_data *md = param;
1908+
1909+
UNUSED(srv);
1910+
1911+
for (gsize i = 0; i < md->actions->len; i++) {
1912+
li_action_release(srv, g_ptr_array_index(md->actions, i));
1913+
}
1914+
1915+
g_ptr_array_free(md->actions, TRUE);
1916+
li_radixtree_free(md->ipv4, NULL, NULL);
1917+
li_radixtree_free(md->ipv6, NULL, NULL);
1918+
1919+
g_slice_free(core_map_cidr_data, md);
1920+
}
1921+
1922+
static liHandlerResult core_handle_map_cidr(liVRequest *vr, gpointer param, gpointer *context) {
1923+
core_map_cidr_data *md = param;
1924+
gpointer action_ndx_ptr = NULL;
1925+
gint action_ndx = md->default_action;
1926+
liSockAddrPtr addr_up = vr->coninfo->remote_addr.addr_up;
1927+
UNUSED(context);
1928+
1929+
if (addr_up.plain->sa_family == AF_INET) {
1930+
action_ndx_ptr = li_radixtree_lookup(md->ipv4, &addr_up.ipv4->sin_addr.s_addr, 32);
1931+
#ifdef HAVE_IPV6
1932+
} else if (addr_up.plain->sa_family == AF_INET6) {
1933+
action_ndx_ptr = li_radixtree_lookup(md->ipv6, &addr_up.ipv6->sin6_addr.s6_addr, 128);
1934+
#endif
1935+
}
1936+
1937+
if (NULL != action_ndx_ptr) {
1938+
action_ndx = GPOINTER_TO_INT(action_ndx_ptr);
1939+
}
1940+
1941+
if (action_ndx >= 0) {
1942+
li_action_enter(vr, g_ptr_array_index(md->actions, action_ndx));
1943+
}
1944+
1945+
return LI_HANDLER_GO_ON;
1946+
}
1947+
1948+
static liAction* core_map_cidr(liServer *srv, liWorker *wrk, liPlugin* p, liValue *val, gpointer userdata) {
1949+
core_map_cidr_data *md;
1950+
liValue *cidr_list, *action;
1951+
UNUSED(wrk); UNUSED(p); UNUSED(userdata);
1952+
1953+
md = g_slice_new(core_map_cidr_data);
1954+
md->actions = g_ptr_array_new();
1955+
md->ipv4 = li_radixtree_new();
1956+
md->ipv6 = li_radixtree_new();
1957+
md->default_action = -1;
1958+
1959+
/* can't store anything at index 0 */
1960+
g_ptr_array_add(md->actions, NULL);
1961+
1962+
val = li_value_get_single_argument(val);
1963+
1964+
LI_VALUE_FOREACH(map_entry, val)
1965+
gint action_ndx;
1966+
1967+
if (!li_value_list_has_len(map_entry, 2)) {
1968+
ERROR(srv, "%s", "'map_cidr' action expects list of (key => action) pairs as parameter");
1969+
core_map_cidr_free(srv, md);
1970+
return NULL;
1971+
}
1972+
1973+
cidr_list = li_value_list_at(map_entry, 0);
1974+
action = li_value_list_at(map_entry, 1);
1975+
1976+
if (LI_VALUE_ACTION != li_value_type(action)) {
1977+
ERROR(
1978+
srv,
1979+
"'map_cidr' action expects list of (key => action) pairs as parameter, expected action, got %s",
1980+
li_value_type_string(action)
1981+
);
1982+
core_map_cidr_free(srv, md);
1983+
return NULL;
1984+
}
1985+
1986+
action_ndx = md->actions->len;
1987+
g_ptr_array_add(md->actions, li_value_extract_action(action));
1988+
1989+
if (LI_VALUE_NONE == li_value_type(cidr_list)) {
1990+
md->default_action = action_ndx;
1991+
continue;
1992+
}
1993+
1994+
if (LI_VALUE_LIST != li_value_type(cidr_list)) li_value_wrap_in_list(cidr_list);
1995+
1996+
LI_VALUE_FOREACH(cidr_entry, cidr_list)
1997+
guint32 ipv4, netmaskv4;
1998+
guint8 ipv6_addr[16];
1999+
guint ipv6_network;
2000+
2001+
if (LI_VALUE_NONE == li_value_type(cidr_entry)) {
2002+
md->default_action = action_ndx;
2003+
continue;
2004+
}
2005+
2006+
if (LI_VALUE_STRING != li_value_type(cidr_entry)) {
2007+
ERROR(srv, "%s", "map_cidr: expect strings as keys in 'map_cidr'");
2008+
core_map_cidr_free(srv, md);
2009+
return NULL;
2010+
}
2011+
2012+
if (g_str_equal(cidr_entry->data.string->str, "all")) {
2013+
md->default_action = action_ndx;
2014+
} else if (li_parse_ipv4(cidr_entry->data.string->str, &ipv4, &netmaskv4, NULL)) {
2015+
gint prefixlen;
2016+
netmaskv4 = ntohl(netmaskv4);
2017+
prefixlen = 32 - g_bit_nth_lsf(netmaskv4, -1);
2018+
if (prefixlen < 0 || prefixlen > 32) prefixlen = 0;
2019+
li_radixtree_insert(md->ipv4, &ipv4, prefixlen, GINT_TO_POINTER(action_ndx));
2020+
} else if (li_parse_ipv6(cidr_entry->data.string->str, ipv6_addr, &ipv6_network, NULL)) {
2021+
li_radixtree_insert(md->ipv6, ipv6_addr, ipv6_network, GINT_TO_POINTER(action_ndx));
2022+
} else {
2023+
ERROR(srv, "map_cidr: error parsing IP cidr: %s", cidr_entry->data.string->str);
2024+
core_map_cidr_free(srv, md);
2025+
return NULL;
2026+
}
2027+
LI_VALUE_END_FOREACH()
2028+
LI_VALUE_END_FOREACH()
2029+
2030+
return li_action_new_function(core_handle_map_cidr, NULL, core_map_cidr_free, md);
2031+
}
2032+
18992033
static void fetch_files_static_lookup(liFetchDatabase* db, gpointer data, liFetchEntry *entry) {
19002034
GHashTable *stringdb = (GHashTable*) data;
19012035
UNUSED(db);
@@ -2134,6 +2268,7 @@ static const liPluginAction actions[] = {
21342268
{ "io.buffer_in", core_buffer_in, NULL },
21352269

21362270
{ "map", core_map, NULL },
2271+
{ "map_cidr", core_map_cidr, NULL },
21372272

21382273
{ NULL, NULL, NULL }
21392274
};

0 commit comments

Comments
 (0)