2024-10-21 15:38:34 +00:00
|
|
|
package rule
|
2022-07-02 14:55:10 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"net/netip"
|
|
|
|
"strings"
|
|
|
|
|
2022-07-08 15:03:57 +00:00
|
|
|
"github.com/sagernet/sing-box/adapter"
|
2022-07-04 07:51:41 +00:00
|
|
|
E "github.com/sagernet/sing/common/exceptions"
|
2022-08-25 14:22:20 +00:00
|
|
|
|
|
|
|
"go4.org/netipx"
|
2022-07-02 14:55:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var _ RuleItem = (*IPCIDRItem)(nil)
|
|
|
|
|
|
|
|
type IPCIDRItem struct {
|
2022-08-25 14:22:20 +00:00
|
|
|
ipSet *netipx.IPSet
|
|
|
|
isSource bool
|
|
|
|
description string
|
2022-07-02 14:55:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
|
2022-08-25 14:22:20 +00:00
|
|
|
var builder netipx.IPSetBuilder
|
2022-07-04 07:51:41 +00:00
|
|
|
for i, prefixString := range prefixStrings {
|
2022-07-02 14:55:10 +00:00
|
|
|
prefix, err := netip.ParsePrefix(prefixString)
|
2022-08-25 14:22:20 +00:00
|
|
|
if err == nil {
|
|
|
|
builder.AddPrefix(prefix)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
addr, addrErr := netip.ParseAddr(prefixString)
|
|
|
|
if addrErr == nil {
|
|
|
|
builder.Add(addr)
|
|
|
|
continue
|
2022-07-02 14:55:10 +00:00
|
|
|
}
|
2023-12-01 05:24:12 +00:00
|
|
|
return nil, E.Cause(err, "parse [", i, "]")
|
2022-08-25 14:22:20 +00:00
|
|
|
}
|
|
|
|
var description string
|
|
|
|
if isSource {
|
2024-01-14 05:01:57 +00:00
|
|
|
description = "source_ip_cidr="
|
2022-08-25 14:22:20 +00:00
|
|
|
} else {
|
2024-01-14 05:01:57 +00:00
|
|
|
description = "ip_cidr="
|
2022-08-25 14:22:20 +00:00
|
|
|
}
|
|
|
|
if dLen := len(prefixStrings); dLen == 1 {
|
|
|
|
description += prefixStrings[0]
|
|
|
|
} else if dLen > 3 {
|
|
|
|
description += "[" + strings.Join(prefixStrings[:3], " ") + "...]"
|
|
|
|
} else {
|
|
|
|
description += "[" + strings.Join(prefixStrings, " ") + "]"
|
|
|
|
}
|
|
|
|
ipSet, err := builder.IPSet()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2022-07-02 14:55:10 +00:00
|
|
|
}
|
|
|
|
return &IPCIDRItem{
|
2022-08-25 14:22:20 +00:00
|
|
|
ipSet: ipSet,
|
|
|
|
isSource: isSource,
|
|
|
|
description: description,
|
2022-07-02 14:55:10 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2023-12-01 05:24:12 +00:00
|
|
|
func NewRawIPCIDRItem(isSource bool, ipSet *netipx.IPSet) *IPCIDRItem {
|
|
|
|
var description string
|
|
|
|
if isSource {
|
2024-01-14 05:01:57 +00:00
|
|
|
description = "source_ip_cidr="
|
2023-12-01 05:24:12 +00:00
|
|
|
} else {
|
2024-01-14 05:01:57 +00:00
|
|
|
description = "ip_cidr="
|
2023-12-01 05:24:12 +00:00
|
|
|
}
|
|
|
|
description += "<binary>"
|
|
|
|
return &IPCIDRItem{
|
|
|
|
ipSet: ipSet,
|
|
|
|
isSource: isSource,
|
|
|
|
description: description,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-02 14:55:10 +00:00
|
|
|
func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
|
2024-02-10 14:35:35 +00:00
|
|
|
if r.isSource || metadata.IPCIDRMatchSource {
|
2022-09-25 14:16:24 +00:00
|
|
|
return r.ipSet.Contains(metadata.Source.Addr)
|
2024-06-24 01:41:00 +00:00
|
|
|
}
|
|
|
|
if metadata.Destination.IsIP() {
|
|
|
|
return r.ipSet.Contains(metadata.Destination.Addr)
|
|
|
|
}
|
|
|
|
if len(metadata.DestinationAddresses) > 0 {
|
|
|
|
for _, address := range metadata.DestinationAddresses {
|
|
|
|
if r.ipSet.Contains(address) {
|
|
|
|
return true
|
2022-07-02 14:55:10 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-24 01:41:00 +00:00
|
|
|
return false
|
2022-07-02 14:55:10 +00:00
|
|
|
}
|
2024-06-24 01:41:00 +00:00
|
|
|
return metadata.IPCIDRAcceptEmpty
|
2022-07-02 14:55:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *IPCIDRItem) String() string {
|
2022-08-25 14:22:20 +00:00
|
|
|
return r.description
|
2022-07-02 14:55:10 +00:00
|
|
|
}
|