mirror of
https://codeberg.org/1414codeforge/ubgpsuite.git
synced 2025-06-05 21:29:11 +02:00
[*] Initial commit
This commit is contained in:
214
tools/bgpgrep/bgpgrep_asmatch.c
Executable file
214
tools/bgpgrep/bgpgrep_asmatch.c
Executable file
@ -0,0 +1,214 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* \file bgpgrep_asmatch.c
|
||||
*
|
||||
* AS_PATH regular expressions compilation.
|
||||
*
|
||||
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
||||
* \author Lorenzo Cogotti
|
||||
*/
|
||||
|
||||
#include "bgpgrep_local.h"
|
||||
|
||||
#include "sys/con.h"
|
||||
#include "sys/endian.h"
|
||||
#include "lexer.h"
|
||||
#include "strlib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAXEXCERPTLEN 32
|
||||
|
||||
#define GROWSTEP 128
|
||||
|
||||
typedef struct {
|
||||
unsigned cap, len;
|
||||
Asn expr[FLEX_ARRAY];
|
||||
} Asnbuf;
|
||||
|
||||
// Return TRUE if `asn` may be followed by '+', '?' or '*' wildcards.
|
||||
static Boolean WildcardAllowed(Asn asn)
|
||||
{
|
||||
return asn != ASN_START && asn != ASN_END && asn != ASN_ALT && asn != ASN_NEWGRP;
|
||||
}
|
||||
|
||||
static void AddAsnToList(Asnbuf **pbuf, Asn asn)
|
||||
{
|
||||
Asnbuf *buf = *pbuf;
|
||||
|
||||
if (!buf || buf->len == buf->cap) {
|
||||
size_t oldcap = buf ? buf->cap : 0;
|
||||
size_t newcap = oldcap + GROWSTEP;
|
||||
|
||||
buf = (Asnbuf *) realloc(buf, offsetof(Asnbuf, expr[newcap]));
|
||||
if (!buf)
|
||||
Bgpgrep_Fatal("Memory allocation failure");
|
||||
|
||||
buf->cap = newcap;
|
||||
buf->len = oldcap;
|
||||
|
||||
*pbuf = buf;
|
||||
}
|
||||
|
||||
buf->expr[buf->len++] = asn;
|
||||
}
|
||||
|
||||
Sint32 BgpgrepC_BakeAsRegexp(void)
|
||||
{
|
||||
// Generate expression name
|
||||
char expnam[1 + 16 + MAXEXCERPTLEN + 1 + 1], *ptr = expnam;
|
||||
|
||||
const char *match = BgpgrepC_ExpectAnyToken();
|
||||
|
||||
*ptr++ = '<';
|
||||
|
||||
strcpy(ptr, "AS PATH regexp: "); ptr += 16;
|
||||
|
||||
size_t n = Df_strncpyz(ptr, match, MAXEXCERPTLEN);
|
||||
if (n > MAXEXCERPTLEN) strcpy(ptr + MAXEXCERPTLEN-3, "...");
|
||||
|
||||
ptr += n;
|
||||
|
||||
*ptr++ = '>';
|
||||
*ptr = '\0';
|
||||
|
||||
// Setup lexer
|
||||
Lex p;
|
||||
Tok tok;
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
if (!S.noColor)
|
||||
SetLexerFlags(&p, L_COLORED);
|
||||
|
||||
BeginLexerSession(&p, expnam, /*line=*/1);
|
||||
SetLexerTextn(&p, match, n);
|
||||
SetLexerErrorFunc(&p, LEX_QUIT, LEX_WARN, NULL);
|
||||
|
||||
// Compile expression
|
||||
Asnbuf *buf = NULL;
|
||||
|
||||
int notcount = 0;
|
||||
int nparens = 0;
|
||||
Boolean seenAsn = FALSE, seenBol = FALSE, seenEol = FALSE;
|
||||
Boolean wUnmatchable = TRUE;
|
||||
Asn asn;
|
||||
|
||||
while (Lex_ReadToken(&p, &tok)) {
|
||||
// Special handling for negation (don't produce any ASN)
|
||||
if (strcmp(tok.text, "!") == 0) {
|
||||
notcount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Any other case
|
||||
if (strcmp(tok.text, "(") == 0) {
|
||||
if (notcount > 0)
|
||||
LexerError(&p, "Illegal '(' after '!' ASN modifier");
|
||||
|
||||
AddAsnToList(&buf, ASN_NEWGRP);
|
||||
seenBol = seenAsn = seenEol = FALSE;
|
||||
wUnmatchable = TRUE;
|
||||
nparens++;
|
||||
} else if (strcmp(tok.text, ")") == 0) {
|
||||
if (notcount > 0)
|
||||
LexerError(&p, "Dangling '!' at end of group");
|
||||
if (nparens == 0)
|
||||
LexerError(&p, "Stray ')' in match expression");
|
||||
|
||||
AddAsnToList(&buf, ASN_ENDGRP);
|
||||
seenBol = seenAsn = seenEol = FALSE;
|
||||
wUnmatchable = TRUE;
|
||||
nparens--;
|
||||
} else if (strcmp(tok.text, "^") == 0) {
|
||||
if (notcount > 0)
|
||||
LexerError(&p, "Illegal '^' after '!' ASN modifier");
|
||||
if (seenBol)
|
||||
LexerWarning(&p, "Duplicate '^'");
|
||||
if (seenAsn && wUnmatchable) {
|
||||
LexerWarning(&p, "'^' following ASN term never matches");
|
||||
wUnmatchable = FALSE;
|
||||
}
|
||||
if (seenEol && wUnmatchable) {
|
||||
LexerWarning(&p, "'^' following '$' never matches");
|
||||
wUnmatchable = FALSE;
|
||||
}
|
||||
|
||||
AddAsnToList(&buf, ASN_START);
|
||||
seenBol = TRUE;
|
||||
} else if (strcmp(tok.text, "$") == 0) {
|
||||
if (notcount > 0)
|
||||
LexerError(&p, "Illegal '$' after '!' ASN modifier");
|
||||
if (seenEol)
|
||||
LexerWarning(&p, "Duplicate '$'");
|
||||
|
||||
AddAsnToList(&buf, ASN_END);
|
||||
seenEol = TRUE;
|
||||
} else if (strcmp(tok.text, "|") == 0) {
|
||||
if (notcount > 0)
|
||||
LexerError(&p, "Alternative not allowed after '!'");
|
||||
|
||||
AddAsnToList(&buf, ASN_ALT);
|
||||
seenBol = seenAsn = seenEol = FALSE;
|
||||
wUnmatchable = TRUE;
|
||||
} else {
|
||||
if (strcmp(tok.text, ".") == 0) {
|
||||
// Any match, make sure ! wasn't used
|
||||
if (notcount > 0)
|
||||
LexerError(&p, "Illegal use of '!' combined with '.' operator");
|
||||
|
||||
asn = ASN_ANY;
|
||||
|
||||
} else {
|
||||
// Read actual numeric ASN
|
||||
Lex_UngetToken(&p, &tok);
|
||||
|
||||
long long num = Lex_ParseInt(&p, /*optionalSign=*/FALSE);
|
||||
if (num > 0xffffffff)
|
||||
LexerError(&p, "%lld: ASN is out of range", num);
|
||||
|
||||
asn = ASN32BIT(beswap32(num));
|
||||
}
|
||||
|
||||
if (notcount & 1)
|
||||
asn = ASNNOT(asn); // negate match
|
||||
|
||||
if (seenEol && wUnmatchable) {
|
||||
LexerWarning(&p, "ASN term following '$' never matches");
|
||||
wUnmatchable = FALSE;
|
||||
}
|
||||
|
||||
AddAsnToList(&buf, asn);
|
||||
notcount = 0;
|
||||
|
||||
seenAsn = TRUE;
|
||||
}
|
||||
|
||||
// Allow *, ? and + repetition operators
|
||||
if (WildcardAllowed(buf->expr[buf->len-1])) {
|
||||
if (Lex_CheckToken(&p, "*"))
|
||||
AddAsnToList(&buf, ASN_STAR);
|
||||
else if (Lex_CheckToken(&p, "+"))
|
||||
AddAsnToList(&buf, ASN_PLUS);
|
||||
else if (Lex_CheckToken(&p, "?"))
|
||||
AddAsnToList(&buf, ASN_QUEST);
|
||||
}
|
||||
}
|
||||
if (nparens != 0)
|
||||
LexerError(&p, "Missing ')' at end of match expression");
|
||||
if (notcount != 0)
|
||||
LexerError(&p, "Dangling '!' at end of match expression");
|
||||
|
||||
void *regexp = Bgp_VmCompileAsMatch(&S.vm, buf->expr, buf->len);
|
||||
if (!regexp)
|
||||
Bgpgrep_Fatal("AS PATH Regexp compilation failed");
|
||||
|
||||
Sint32 kidx = BGP_VMSETKA(&S.vm, Bgp_VmNewk(&S.vm), regexp);
|
||||
if (kidx == -1)
|
||||
Bgpgrep_Fatal("Maximum BGP VM variables limit hit: please try to simplify the filtering expression");
|
||||
|
||||
free(buf);
|
||||
|
||||
return kidx;
|
||||
}
|
Reference in New Issue
Block a user