}
/* Helper to check if every octet do not exceed UINT_MAX */
-static bool lcommunity_list_valid(const char *community)
+bool lcommunity_list_valid(const char *community, int style)
{
int octets;
char **splits, **communities;
+ char *endptr;
int num, num_communities;
+ regex_t *regres;
+ int invalid = 0;
frrstr_split(community, " ", &communities, &num_communities);
frrstr_split(communities[j], ":", &splits, &num);
for (int i = 0; i < num; i++) {
- if (strtoul(splits[i], NULL, 10) > UINT_MAX)
- return false;
-
if (strlen(splits[i]) == 0)
- return false;
+ /* There is no digit to check */
+ invalid++;
+
+ if (style == LARGE_COMMUNITY_LIST_STANDARD) {
+ if (*splits[i] == '-')
+ /* Must not be negative */
+ invalid++;
+ else if (strtoul(splits[i], &endptr, 10)
+ > UINT_MAX)
+ /* Larger than 4 octets */
+ invalid++;
+ else if (*endptr)
+ /* Not all characters were digits */
+ invalid++;
+ } else {
+ regres = bgp_regcomp(communities[j]);
+ if (!regres)
+ /* malformed regex */
+ invalid++;
+ else
+ bgp_regex_free(regres);
+ }
octets++;
XFREE(MTYPE_TMP, splits[i]);
}
XFREE(MTYPE_TMP, splits);
- if (octets < 3)
- return false;
+ if (octets != 3)
+ invalid++;
XFREE(MTYPE_TMP, communities[j]);
}
XFREE(MTYPE_TMP, communities);
- return true;
+ return (invalid > 0) ? false : true;
}
/* Set lcommunity-list. */
}
if (str) {
- if (!lcommunity_list_valid(str))
+ if (!lcommunity_list_valid(str, style))
return COMMUNITY_LIST_ERR_MALFORMED_VAL;
if (style == LARGE_COMMUNITY_LIST_STANDARD)
lcomhash = NULL;
}
-/* Large Communities token enum. */
-enum lcommunity_token {
- lcommunity_token_unknown = 0,
- lcommunity_token_val,
-};
-
-/* Get next Large Communities token from the string. */
+/* Get next Large Communities token from the string.
+ * Assumes str is space-delimeted and describes 0 or more
+ * valid large communities
+ */
static const char *lcommunity_gettoken(const char *str,
- struct lcommunity_val *lval,
- enum lcommunity_token *token)
+ struct lcommunity_val *lval)
{
const char *p = str;
return NULL;
/* Community value. */
- if (isdigit((unsigned char)*p)) {
- int separator = 0;
- int digit = 0;
- uint32_t globaladmin = 0;
- uint32_t localdata1 = 0;
- uint32_t localdata2 = 0;
-
- while (isdigit((unsigned char)*p) || *p == ':') {
- if (*p == ':') {
- if (separator == 2) {
- *token = lcommunity_token_unknown;
- return NULL;
- } else {
- separator++;
- digit = 0;
- if (separator == 1) {
- globaladmin = localdata2;
- } else {
- localdata1 = localdata2;
- }
- localdata2 = 0;
- }
+ int separator = 0;
+ int digit = 0;
+ uint32_t globaladmin = 0;
+ uint32_t localdata1 = 0;
+ uint32_t localdata2 = 0;
+
+ while (*p && *p != ' ') {
+ /* large community valid chars */
+ assert(isdigit((unsigned char)*p) || *p == ':');
+
+ if (*p == ':') {
+ separator++;
+ digit = 0;
+ if (separator == 1) {
+ globaladmin = localdata2;
} else {
- digit = 1;
- localdata2 *= 10;
- localdata2 += (*p - '0');
+ localdata1 = localdata2;
}
- p++;
+ localdata2 = 0;
+ } else {
+ digit = 1;
+ /* left shift the accumulated value and add current
+ * digit
+ */
+ localdata2 *= 10;
+ localdata2 += (*p - '0');
}
- if (!digit) {
- *token = lcommunity_token_unknown;
- return NULL;
- }
-
- /*
- * Copy the large comm.
- */
- lval->val[0] = (globaladmin >> 24) & 0xff;
- lval->val[1] = (globaladmin >> 16) & 0xff;
- lval->val[2] = (globaladmin >> 8) & 0xff;
- lval->val[3] = globaladmin & 0xff;
- lval->val[4] = (localdata1 >> 24) & 0xff;
- lval->val[5] = (localdata1 >> 16) & 0xff;
- lval->val[6] = (localdata1 >> 8) & 0xff;
- lval->val[7] = localdata1 & 0xff;
- lval->val[8] = (localdata2 >> 24) & 0xff;
- lval->val[9] = (localdata2 >> 16) & 0xff;
- lval->val[10] = (localdata2 >> 8) & 0xff;
- lval->val[11] = localdata2 & 0xff;
-
- *token = lcommunity_token_val;
- return p;
+ p++;
}
- *token = lcommunity_token_unknown;
+
+ /* Assert str was a valid large community */
+ assert(separator == 2 && digit == 1);
+
+ /*
+ * Copy the large comm.
+ */
+ lval->val[0] = (globaladmin >> 24) & 0xff;
+ lval->val[1] = (globaladmin >> 16) & 0xff;
+ lval->val[2] = (globaladmin >> 8) & 0xff;
+ lval->val[3] = globaladmin & 0xff;
+ lval->val[4] = (localdata1 >> 24) & 0xff;
+ lval->val[5] = (localdata1 >> 16) & 0xff;
+ lval->val[6] = (localdata1 >> 8) & 0xff;
+ lval->val[7] = localdata1 & 0xff;
+ lval->val[8] = (localdata2 >> 24) & 0xff;
+ lval->val[9] = (localdata2 >> 16) & 0xff;
+ lval->val[10] = (localdata2 >> 8) & 0xff;
+ lval->val[11] = localdata2 & 0xff;
+
return p;
}
struct lcommunity *lcommunity_str2com(const char *str)
{
struct lcommunity *lcom = NULL;
- enum lcommunity_token token = lcommunity_token_unknown;
struct lcommunity_val lval;
+ if (!lcommunity_list_valid(str, LARGE_COMMUNITY_LIST_STANDARD))
+ return NULL;
+
do {
- str = lcommunity_gettoken(str, &lval, &token);
- switch (token) {
- case lcommunity_token_val:
- if (lcom == NULL)
- lcom = lcommunity_new();
- lcommunity_add_val(lcom, &lval);
- break;
- case lcommunity_token_unknown:
- default:
- if (lcom)
- lcommunity_free(&lcom);
- return NULL;
- }
+ str = lcommunity_gettoken(str, &lval);
+ if (lcom == NULL)
+ lcom = lcommunity_new();
+ lcommunity_add_val(lcom, &lval);
} while (str);
return lcom;