diff --git a/src/ip-util.c b/src/ip-util.c index f7c38a5c..41d2d95a 100644 --- a/src/ip-util.c +++ b/src/ip-util.c @@ -121,3 +121,74 @@ int ip_route_sanity_check(void *pool, char **_route) talloc_free(route); return 0; } + +static +int bit_count(uint32_t i) +{ + int c = 0; + unsigned int seen_one = 0; + + while (i > 0) { + if (i & 1) { + seen_one = 1; + c++; + } else { + if (seen_one) { + return -1; + } + } + i >>= 1; + } + + return c; +} + +static int mask2prefix(struct in_addr mask) +{ + return bit_count(ntohl(mask.s_addr)); +} + +static +int ipv4_mask_to_int(const char *prefix) +{ + int ret; + struct in_addr in; + + ret = inet_pton(AF_INET, prefix, &in); + if (ret == 0) + return -1; + + return mask2prefix(in); +} + +/* Converts a route from xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx format, to + * xxx.xxx.xxx.xxx/prefix format. + */ +char *ipv4_route_to_cidr(void *pool, const char *route) +{ + int prefix; + int len; + const char *p; + + /* this check is valid for IPv4 only */ + p = strchr(route, '.'); + if (p == NULL) + return talloc_strdup(pool, route); + + p = strchr(p, '/'); + if (p == NULL) { + return NULL; + } + len = (ptrdiff_t)(p-route); + p++; + + /* if we are in CIDR format exit */ + if (strchr(p, '.') == 0) + return talloc_strdup(pool, route); + + prefix = ipv4_mask_to_int(p); + if (prefix <= 0 || prefix > 32) + return NULL; + + return talloc_asprintf(pool, "%.*s/%d", len, route, prefix); +} diff --git a/src/ip-util.h b/src/ip-util.h index 8f073a36..2f6f5a41 100644 --- a/src/ip-util.h +++ b/src/ip-util.h @@ -40,6 +40,8 @@ inline static int valid_ipv6_prefix(unsigned prefix) return 0; } +char *ipv4_route_to_cidr(void *pool, const char *route); + /* Helper casts */ #define SA_IN_P(p) (&((struct sockaddr_in *)(p))->sin_addr) #define SA_IN_U8_P(p) ((uint8_t*)(&((struct sockaddr_in *)(p))->sin_addr)) diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 005d7b5c..01a591fa 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -585,10 +585,10 @@ no-route = 192.168.5.0/255.255.255.0 #default-group-config = /etc/ocserv/defaults/group.conf # The system command to use to setup a route. %{R} will be replaced with the -# route/mask and %{D} with the (tun) device. +# route/mask, %{RI} with the route in CIDR format, and %{D} with the (tun) device. # -# The following example is from linux systems. %R should be something -# like 192.168.2.0/24 (the argument of iroute). +# The following example is from linux systems. %{R} should be something +# like 192.168.2.0/255.255.255.0 and %{RI} 192.168.2.0/24 (the argument of iroute). #route-add-cmd = "ip route add %{R} dev %{D}" #route-del-cmd = "ip route delete %{R} dev %{D}" diff --git a/src/route-add.c b/src/route-add.c index f6754b3a..e6fc47d7 100644 --- a/src/route-add.c +++ b/src/route-add.c @@ -31,7 +31,6 @@ #include #include - static int replace_cmd(struct main_server_st* s, proc_st *proc, char **cmd, const char* pattern, @@ -39,13 +38,14 @@ int replace_cmd(struct main_server_st* s, proc_st *proc, { str_st str; int ret; - str_rep_tab tab[5]; + str_rep_tab tab[6]; STR_TAB_SET(0, "%{R}", route); STR_TAB_SET(1, "%R", route); STR_TAB_SET(2, "%{D}", dev); STR_TAB_SET(3, "%D", dev); - STR_TAB_TERM(4); + STR_TAB_SET_FUNC(4, "%{RC}", ipv4_route_to_cidr, route); + STR_TAB_TERM(5); str_init(&str, proc); diff --git a/src/str.c b/src/str.c index 7d86b115..c1d7ca91 100644 --- a/src/str.c +++ b/src/str.c @@ -180,7 +180,10 @@ int str_replace_str(str_st *str, const str_rep_tab *tab) return -1; str->length -= final_len + ptab->pattern_length; - ret = str_append_str(str, ptab->rep_val); + if (ptab->rep_val) + ret = str_append_str(str, ptab->rep_val); + else + ret = str_append_str(str, ptab->rep_func(str->pool, ptab->rep_func_input)); if (ret < 0) { talloc_free(final); return ret; diff --git a/src/str.h b/src/str.h index 940340aa..7513e20f 100644 --- a/src/str.h +++ b/src/str.h @@ -31,12 +31,23 @@ tab[i].pattern_length = sizeof(pat)-1; \ tab[i].rep_val = val; \ } +#define STR_TAB_SET_FUNC(i,pat,func,funcinput) { \ + tab[i].pattern = pat; \ + tab[i].pattern_length = sizeof(pat)-1; \ + tab[i].rep_val = NULL; \ + tab[i].rep_func = func; \ + tab[i].rep_func_input = funcinput; \ + } #define STR_TAB_TERM(i) tab[i].pattern = NULL +typedef char *(*str_get_func)(void *pool, const char *input); + typedef struct { const char *pattern; unsigned pattern_length; const char *rep_val; + str_get_func rep_func; + const void *rep_func_input; } str_rep_tab; typedef struct {