int parse_ip(uint32_t *addr, const char *saddr) { if (parse_vars(&saddr, saddr)) { return -1; } char *ip_parts[5]; char saddr_cpy[MAX_STR_LEN_PROC]; if (strlen(saddr) > MAX_STR_LEN_PROC) { set_errf("String too long (max supported: %d)", MAX_STR_LEN_PROC); return -2; } strncpy(saddr_cpy, saddr, MAX_STR_LEN_PROC); if (4 != rte_strsplit(saddr_cpy, strlen(saddr_cpy), ip_parts, 5, '.')) { set_errf("Expecting 4 octets in ip."); return -1; } uint32_t val; for (uint8_t i = 0; i < 4; ++i) { val = atoi(ip_parts[i]); if (val > 255) { set_errf("Maximum value for octet is 255 but octet %u is %u", i, val); return -1; } *addr = *addr << 8 | val; } return 0; }
int parse_int_mask(uint32_t *val, uint32_t *mask, const char *str) { char str_cpy[MAX_STR_LEN_PROC]; char *mask_str; if (parse_vars(&str, str)) { return -1; } if (strlen(str) > MAX_STR_LEN_PROC) { set_errf("String too long (max supported: %d)", MAX_STR_LEN_PROC); return -2; } strncpy(str_cpy, str, MAX_STR_LEN_PROC); mask_str = strchr(str_cpy, '&'); if (mask_str == NULL) { set_errf("Missing '&' when parsing mask"); return -2; } *mask_str = 0; if (parse_int(val, str)) return -1; if (parse_int(mask, mask_str + 1)) return -1; return 0; }
int parse_ip4_cidr(struct ip4_subnet *val, const char *str2) { char str[MAX_STR_LEN_PROC]; char *slash; int prefix; if (parse_vars(str, sizeof(str), str2)) return -1; slash = strstr(str, "/"); if (slash == NULL) { set_errf("Missing '/' when parsing CIDR notation"); return -2; } *slash = 0; prefix = atoi(slash + 1); val->prefix = prefix; if (prefix > 32) { set_errf("Prefix %d is too big", prefix); return -2; } if (prefix < 1) { set_errf("Prefix %d is too small", prefix); } if (parse_ip(&val->ip, str)) return -2; /* Apply mask making all bits outside the prefix zero */ val->ip &= ((int)(1 << 31)) >> (prefix - 1); return 0; }
int parse_ip6_cidr(struct ip6_subnet *val, const char *saddr) { char saddr_cpy[MAX_STR_LEN_PROC]; char *slash; int prefix; if (parse_vars(&saddr, saddr)) { return -1; } if (strlen(saddr) > MAX_STR_LEN_PROC) { set_errf("String too long (max supported: %d)", MAX_STR_LEN_PROC); return -2; } strncpy(saddr_cpy, saddr, MAX_STR_LEN_PROC); slash = strstr(saddr_cpy, "/"); if (slash == NULL) { set_errf("Missing '/' when parsing CIDR notation"); return -2; } *slash = 0; prefix = atoi(slash + 1); val->prefix = prefix; parse_ip6((struct ipv6_addr *)&val->ip, saddr_cpy); /* Apply mask making all bits outside the prefix zero */ int p = 120; int cnt = 0; while (p >= prefix) { val->ip[15-cnt] = 0; p -= 8; cnt++; } if (prefix % 8 != 0) { val->ip[15-cnt] &= ((int8_t)(1 << 7)) >> ((prefix %8) - 1); }
int parse_ip4_cidr(struct ip4_subnet *val, const char *saddr) { char saddr_cpy[MAX_STR_LEN_PROC]; char *slash; int prefix; if (parse_vars(&saddr, saddr)) { return -1; } if (strlen(saddr) > MAX_STR_LEN_PROC) { set_errf("String too long (max supported: %d)", MAX_STR_LEN_PROC); return -2; } strncpy(saddr_cpy, saddr, MAX_STR_LEN_PROC); slash = strstr(saddr_cpy, "/"); if (slash == NULL) { set_errf("Missing '/' when parsing CIDR notation"); return -2; } *slash = 0; prefix = atoi(slash + 1); val->prefix = prefix; if (prefix > 32) { set_errf("Prefix %d is too big", prefix); return -2; } if (prefix < 1) { set_errf("Prefix %d is too small", prefix); } if (parse_ip(&val->ip, saddr_cpy)) return -2; /* Apply mask making all bits outside the prefix zero */ val->ip &= ((int)(1 << 31)) >> (prefix - 1); return 0; }
static int parse_single_var(const char **val, const char *name) { for (uint8_t i = 0; i < nb_vars; ++i) { if (!strcmp(name, vars[i].name)) { *val = vars[i].val; return 0; } } set_errf("Variable '%s' not defined!", name); return 1; }
static int parse_single_var(char *val, size_t len, const char *name) { struct var *match; match = var_lookup(name); if (match) { if (strlen(match->val) + 1 > len) { set_errf("Variables '%s' with value '%s' is too long\n", match->name, match->val); return -1; } strncpy(val, match->val, len); return 0; } else { /* name + 1 to skip leading '$' */ if (lua_to_string(prox_lua(), GLOBAL, name + 1, val, len) >= 0) return 0; } set_errf("Variable '%s' not defined!", name); return 1; }
int parse_range(uint32_t* lo, uint32_t* hi, const char *str2) { char str[MAX_STR_LEN_PROC]; char *dash; if (parse_vars(str, sizeof(str), str2)) return -1; dash = strstr(str, "-"); if (dash == NULL) { set_errf("Missing '-' when parsing mask"); return -2; } *dash = 0; if (parse_int(lo, str)) return -1; if (parse_int(hi, dash + 1)) return -1; int64_t tmp = strtol(str, 0, 0); if (tmp > UINT32_MAX) { set_errf("Integer is bigger than %u", UINT32_MAX); return -1; } if (tmp < 0) { set_errf("Integer is negative"); return -2; } *lo = tmp; tmp = strtol(dash + 1, 0, 0); if (tmp > UINT32_MAX) { set_errf("Integer is bigger than %u", UINT32_MAX); return -1; } if (tmp < 0) { set_errf("Integer is negative"); return -2; } *hi = tmp; if (*lo > *hi) { set_errf("Low boundary is above high boundary in range"); return -2; } return 0; }
int parse_ip6_cidr(struct ip6_subnet *val, const char *str2) { char str[MAX_STR_LEN_PROC]; char *slash; int prefix; if (parse_vars(str, sizeof(str), str2)) return -1; slash = strstr(str, "/"); if (slash == NULL) { set_errf("Missing '/' when parsing CIDR notation"); return -2; } *slash = 0; prefix = atoi(slash + 1); val->prefix = prefix; parse_ip6((struct ipv6_addr *)&val->ip, str); /* Apply mask making all bits outside the prefix zero */ int p = 120; int cnt = 0; while (p >= prefix) { val->ip[15-cnt] = 0; p -= 8; cnt++; } if (prefix % 8 != 0) { val->ip[15-cnt] &= ((int8_t)(1 << 7)) >> ((prefix %8) - 1); }
int parse_int_mask(uint32_t *val, uint32_t *mask, const char *str2) { char str[MAX_STR_LEN_PROC]; char *mask_str; if (parse_vars(str, sizeof(str), str2)) return -1; mask_str = strchr(str, '&'); if (mask_str == NULL) { set_errf("Missing '&' when parsing mask"); return -2; } *mask_str = 0; if (parse_int(val, str)) return -1; if (parse_int(mask, mask_str + 1)) return -1; return 0; }
int parse_range(uint32_t* lo, uint32_t* hi, const char *str) { char str_cpy[MAX_STR_LEN_PROC]; char *dash; if (parse_vars(&str, str)) { return -1; } if (strlen(str) > MAX_STR_LEN_PROC) { set_errf("String too long (max supported: %d)", MAX_STR_LEN_PROC); return -2; } strncpy(str_cpy, str, MAX_STR_LEN_PROC); dash = strstr(str_cpy, "-"); if (dash == NULL) { set_errf("Missing '-' when parsing mask"); return -2; } *dash = 0; if (parse_int(lo, str_cpy)) return -1; if (parse_int(hi, dash + 1)) return -1; int64_t tmp = strtol(str_cpy, 0, 0); if (tmp > UINT32_MAX) { set_errf("Integer is bigger than %u", UINT32_MAX); return -1; } if (tmp < 0) { set_errf("Integer is negative"); return -2; } *lo = tmp; tmp = strtol(dash + 1, 0, 0); if (tmp > UINT32_MAX) { set_errf("Integer is bigger than %u", UINT32_MAX); return -1; } if (tmp < 0) { set_errf("Integer is negative"); return -2; } *hi = tmp; if (*lo > *hi) { set_errf("Low boundary is above high boundary in range"); return -2; } return 0; }
/* Replace $... and each occurrence of ${...} with what has been added through add_var */ static int parse_vars(const char **val, const char *name) { static char result[2048]; static char cur_var[2048]; size_t name_len = strlen(name); enum parse_vars_state {NO_VAR, WHOLE_VAR, INLINE_VAR} state = NO_VAR; size_t result_len = 0; size_t start_var = 0; if (name == result) { *val = name; return 0; } memset(result, 0, sizeof(result)); PROX_PANIC(name_len > sizeof(result), "\tUnable to parse var %s: too long\n", name); for (size_t i = 0; i < name_len; ++i) { switch (state) { case NO_VAR: if (name[i] == '$') { if (i != name_len - 1 && name[i + 1] == '{') { start_var = i + 2; state = INLINE_VAR; i = i + 1; } else if (i == 0 && i != name_len - 1) { state = WHOLE_VAR; } else { set_errf("Invalid variable syntax"); return -1; } } else { result[result_len++] = name[i]; } break; case INLINE_VAR: if (name[i] == '}') { const char *parsed; cur_var[0] = '$'; size_t var_len = i - start_var; if (var_len == 0) { set_errf("Empty variable are not allowed"); return -1; } strncpy(&cur_var[1], &name[start_var], var_len); cur_var[1 + var_len] = 0; if (parse_single_var(&parsed, cur_var)) { return -1; } strcpy(&result[result_len], parsed); result_len += strlen(parsed); state = NO_VAR; } else if (i == name_len - 1) { set_errf("Invalid variable syntax, expected '}'."); return -1; } break; case WHOLE_VAR: if (i == name_len - 1) { return parse_single_var(val, name); } break; } } *val = result; return 0; }