feat(bird): Add net.match

This commit is contained in:
v-lafeychine 2024-04-01 00:06:05 +02:00
parent 8d0139925e
commit ba033f9099
Signed by: v-lafeychine
GPG key ID: F46CAAD27C7AB0D5

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import itertools
import re
from dataclasses import dataclass
from ipaddress import IPv4Address
from ipaddress import IPv4Address, IPv4Network, IPv6Network, ip_network
from typing import Any, Generic, Iterator, Literal, TypeVar
from pydantic import (
@ -89,12 +89,37 @@ class IPv4orIPv6(BaseModel):
ipv6: list[int] = Field(ge=0, min_items=2, max_items=2)
class IPFlag(str):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
pattern = r"(?P<ip>.*?)(?P<flag>[+-]|\{[0-9]+,[0-9]+\})?$"
parts = re.match(pattern, v)
return (ip_network(parts.group("ip")), parts.group("flag"))
class NetMatch(BaseModel):
matches: list[IPFlag] = Field(alias="net.match")
class NetLength(BaseModel):
length: IPv4orIPv6 = Field(alias="net.len")
Condition = (
Proto | Source | And | Or | Not | AsPathContains | AsPathLength | NetLength
Proto
| Source
| And
| Or
| Not
| AsPathContains
| AsPathLength
| NetLength
| NetMatch
)
And.update_forward_refs()
@ -210,6 +235,18 @@ def str_of_condition(condition: Condition, ctx: bool) -> str:
else:
return f"{min_v6} <= net.len && net.len <= {max_v6}"
case NetMatch(matches=matches):
if ctx.ipv4:
networks = [
m for m in matches if isinstance(m[0], IPv4Network)
]
else:
networks = [
m for m in matches if isinstance(m[0], IPv6Network)
]
return f"net ~ [ {', '.join([f'{network}{str(flag)}' for (network, flag) in networks])} ]"
def lines_of_action(action: Action, ctx: Context) -> Iterable[str]:
match action: