diff --git a/constant/rule.go b/constant/rule.go index c04379f6..6550f5c4 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -9,8 +9,9 @@ const ( GEOSITE GEOIP SrcGEOIP - IPASN SrcMAC + DstMAC + IPASN SrcIPASN IPCIDR SrcIPCIDR @@ -55,10 +56,12 @@ func (rt RuleType) String() string { return "GeoIP" case SrcGEOIP: return "SrcGeoIP" - case IPASN: - return "IPASN" case SrcMAC: return "SrcMAC" + case DstMAC: + return "DstMAC" + case IPASN: + return "IPASN" case SrcIPASN: return "SrcIPASN" case IPCIDR: diff --git a/rules/common/mac.go b/rules/common/mac.go index 008c975b..902a018c 100644 --- a/rules/common/mac.go +++ b/rules/common/mac.go @@ -19,21 +19,27 @@ var arpTable = make(map[string]string) const reloadInterval = 5 * time.Minute var startOnce sync.Once + func init() { } -type SrcMAC struct { +type MacAddr struct { *Base - mac string - adapter string + mac string + adapter string + isSourceIP bool } -func (d *SrcMAC) RuleType() C.RuleType { - return C.SrcMAC +func (d *MacAddr) RuleType() C.RuleType { + if d.isSourceIP { + return C.SrcMAC + } else { + return C.DstMAC + } } func getLoadArpTableFunc() func() (string, error) { - const ipv6Error = "can't load ipv6 arp table, SRC-MAC rule can't match src ipv6 address" + const ipv6Error = "can't load ipv6 arp table, SRC-MAC/DST-MAC rule can't match src ipv6 address" getIpv4Only := func() (string, error) { return cmd.ExecCmd("arp -a") @@ -95,39 +101,45 @@ func getLoadArpTableFunc() func() (string, error) { } } -func (d *SrcMAC) Match(metadata *C.Metadata) (bool, string) { +func (d *MacAddr) Match(metadata *C.Metadata) (bool, string) { table := getArpTable() - srcIP := metadata.SrcIP.String() - mac, exists := table[srcIP] + var ip string + if d.isSourceIP { + ip = metadata.SrcIP.String() + } else { + ip = metadata.DstIP.String() + } + mac, exists := table[ip] if exists { if mac == d.mac { return true, d.adapter } } else { - log.Warnln("can't find the IP address in arp table: %s", srcIP) + log.Infoln("can't find the IP address in arp table: %s", ip) } return false, d.adapter } -func (d *SrcMAC) Adapter() string { +func (d *MacAddr) Adapter() string { return d.adapter } -func (d *SrcMAC) Payload() string { +func (d *MacAddr) Payload() string { return d.mac } var macRegex = regexp.MustCompile(`^([0-9a-f]{2}:){5}[0-9a-f]{2}$`) -func NewMAC(mac string, adapter string) (*SrcMAC, error) { +func NewMAC(mac string, adapter string, isSrc bool) (*MacAddr, error) { macAddr := strings.ReplaceAll(strings.ToLower(mac), "-", ":") if !macRegex.MatchString(macAddr) { return nil, errors.New("mac address format error: " + mac) } - return &SrcMAC{ - Base: &Base{}, - mac: macAddr, - adapter: adapter, + return &MacAddr{ + Base: &Base{}, + mac: macAddr, + adapter: adapter, + isSourceIP: isSrc, }, nil } diff --git a/rules/parser.go b/rules/parser.go index 12bc2710..77a99ba5 100644 --- a/rules/parser.go +++ b/rules/parser.go @@ -26,11 +26,13 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string] parsed, parseErr = RC.NewGEOIP(payload, target, false, noResolve) case "SRC-GEOIP": parsed, parseErr = RC.NewGEOIP(payload, target, true, true) + case "SRC-MAC": + parsed, parseErr = RC.NewMAC(payload, target, true) + case "DST-MAC": + parsed, parseErr = RC.NewMAC(payload, target, false) case "IP-ASN": noResolve := RC.HasNoResolve(params) parsed, parseErr = RC.NewIPASN(payload, target, false, noResolve) - case "SRC-MAC": - parsed, parseErr = RC.NewMAC(payload, target) case "SRC-IP-ASN": parsed, parseErr = RC.NewIPASN(payload, target, true, true) case "IP-CIDR", "IP-CIDR6":