chore: add IN-USER
and IN-NAME
rules
This commit is contained in:
parent
7aae781569
commit
9c2972afb0
9 changed files with 142 additions and 18 deletions
|
@ -16,6 +16,12 @@ func WithInName(name string) Addition {
|
|||
}
|
||||
}
|
||||
|
||||
func WithInUser(user string) Addition {
|
||||
return func(metadata *C.Metadata) {
|
||||
metadata.InUser = user
|
||||
}
|
||||
}
|
||||
|
||||
func WithSpecialRules(specialRules string) Addition {
|
||||
return func(metadata *C.Metadata) {
|
||||
metadata.SpecialRules = specialRules
|
||||
|
|
|
@ -133,6 +133,7 @@ type Metadata struct {
|
|||
InIP netip.Addr `json:"inboundIP"`
|
||||
InPort string `json:"inboundPort"`
|
||||
InName string `json:"inboundName"`
|
||||
InUser string `json:"inboundUser"`
|
||||
Host string `json:"host"`
|
||||
DNSMode DNSMode `json:"dnsMode"`
|
||||
Uid uint32 `json:"uid"`
|
||||
|
|
|
@ -14,12 +14,14 @@ const (
|
|||
SrcPort
|
||||
DstPort
|
||||
InPort
|
||||
InUser
|
||||
InName
|
||||
InType
|
||||
Process
|
||||
ProcessPath
|
||||
RuleSet
|
||||
Network
|
||||
Uid
|
||||
INTYPE
|
||||
SubRules
|
||||
MATCH
|
||||
AND
|
||||
|
@ -55,6 +57,12 @@ func (rt RuleType) String() string {
|
|||
return "DstPort"
|
||||
case InPort:
|
||||
return "InPort"
|
||||
case InUser:
|
||||
return "InUser"
|
||||
case InName:
|
||||
return "InName"
|
||||
case InType:
|
||||
return "InType"
|
||||
case Process:
|
||||
return "Process"
|
||||
case ProcessPath:
|
||||
|
@ -67,8 +75,6 @@ func (rt RuleType) String() string {
|
|||
return "Network"
|
||||
case Uid:
|
||||
return "Uid"
|
||||
case INTYPE:
|
||||
return "InType"
|
||||
case SubRules:
|
||||
return "SubRules"
|
||||
case AND:
|
||||
|
|
|
@ -2,8 +2,11 @@ package sing
|
|||
|
||||
import (
|
||||
"context"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
@ -22,3 +25,20 @@ func getAdditions(ctx context.Context) []inbound.Addition {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func combineAdditions(ctx context.Context, additions []inbound.Addition) []inbound.Addition {
|
||||
additionsCloned := false
|
||||
if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 {
|
||||
additions = slices.Clone(additions)
|
||||
additionsCloned = true
|
||||
additions = append(additions, ctxAdditions...)
|
||||
}
|
||||
if user, ok := auth.UserFromContext[string](ctx); ok {
|
||||
if !additionsCloned {
|
||||
additions = slices.Clone(additions)
|
||||
additionsCloned = true
|
||||
}
|
||||
additions = append(additions, inbound.WithInUser(user))
|
||||
}
|
||||
return additions
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package sing
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"golang.org/x/exp/slices"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
@ -74,11 +73,6 @@ func UpstreamMetadata(metadata M.Metadata) M.Metadata {
|
|||
}
|
||||
|
||||
func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
|
||||
additions := h.Additions
|
||||
if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 {
|
||||
additions = slices.Clone(additions)
|
||||
additions = append(additions, ctxAdditions...)
|
||||
}
|
||||
switch metadata.Destination.Fqdn {
|
||||
case mux.Destination.Fqdn:
|
||||
return mux.HandleConnection(ctx, h, log.SingLogger, conn, UpstreamMetadata(metadata))
|
||||
|
@ -103,16 +97,11 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta
|
|||
if deadline.NeedAdditionalReadDeadline(conn) {
|
||||
conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline
|
||||
}
|
||||
h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, additions...)
|
||||
h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, combineAdditions(ctx, h.Additions)...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error {
|
||||
additions := h.Additions
|
||||
if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 {
|
||||
additions = slices.Clone(additions)
|
||||
additions = append(additions, ctxAdditions...)
|
||||
}
|
||||
if deadline.NeedAdditionalReadDeadline(conn) {
|
||||
conn = deadline.NewFallbackPacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline
|
||||
}
|
||||
|
@ -162,7 +151,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.
|
|||
buff: buff,
|
||||
}
|
||||
select {
|
||||
case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, additions...):
|
||||
case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...):
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
|
49
rules/common/in_name.go
Normal file
49
rules/common/in_name.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type InName struct {
|
||||
*Base
|
||||
names []string
|
||||
adapter string
|
||||
payload string
|
||||
}
|
||||
|
||||
func (u *InName) Match(metadata *C.Metadata) (bool, string) {
|
||||
for _, name := range u.names {
|
||||
if metadata.InName == name {
|
||||
return true, u.adapter
|
||||
}
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (u *InName) RuleType() C.RuleType {
|
||||
return C.InName
|
||||
}
|
||||
|
||||
func (u *InName) Adapter() string {
|
||||
return u.adapter
|
||||
}
|
||||
|
||||
func (u *InName) Payload() string {
|
||||
return u.payload
|
||||
}
|
||||
|
||||
func NewInName(iNames, adapter string) (*InName, error) {
|
||||
names := strings.Split(iNames, "/")
|
||||
if len(names) == 0 {
|
||||
return nil, fmt.Errorf("in name couldn't be empty")
|
||||
}
|
||||
|
||||
return &InName{
|
||||
Base: &Base{},
|
||||
names: names,
|
||||
adapter: adapter,
|
||||
payload: iNames,
|
||||
}, nil
|
||||
}
|
|
@ -23,7 +23,7 @@ func (u *InType) Match(metadata *C.Metadata) (bool, string) {
|
|||
}
|
||||
|
||||
func (u *InType) RuleType() C.RuleType {
|
||||
return C.INTYPE
|
||||
return C.InType
|
||||
}
|
||||
|
||||
func (u *InType) Adapter() string {
|
||||
|
@ -37,7 +37,7 @@ func (u *InType) Payload() string {
|
|||
func NewInType(iTypes, adapter string) (*InType, error) {
|
||||
types := strings.Split(iTypes, "/")
|
||||
if len(types) == 0 {
|
||||
return nil, fmt.Errorf("in type could be empty")
|
||||
return nil, fmt.Errorf("in type couldn't be empty")
|
||||
}
|
||||
|
||||
tps, err := parseInTypes(types)
|
||||
|
|
49
rules/common/in_user.go
Normal file
49
rules/common/in_user.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type InUser struct {
|
||||
*Base
|
||||
users []string
|
||||
adapter string
|
||||
payload string
|
||||
}
|
||||
|
||||
func (u *InUser) Match(metadata *C.Metadata) (bool, string) {
|
||||
for _, user := range u.users {
|
||||
if metadata.InUser == user {
|
||||
return true, u.adapter
|
||||
}
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (u *InUser) RuleType() C.RuleType {
|
||||
return C.InUser
|
||||
}
|
||||
|
||||
func (u *InUser) Adapter() string {
|
||||
return u.adapter
|
||||
}
|
||||
|
||||
func (u *InUser) Payload() string {
|
||||
return u.payload
|
||||
}
|
||||
|
||||
func NewInUser(iUsers, adapter string) (*InUser, error) {
|
||||
users := strings.Split(iUsers, "/")
|
||||
if len(users) == 0 {
|
||||
return nil, fmt.Errorf("in user couldn't be empty")
|
||||
}
|
||||
|
||||
return &InUser{
|
||||
Base: &Base{},
|
||||
users: users,
|
||||
adapter: adapter,
|
||||
payload: iUsers,
|
||||
}, nil
|
||||
}
|
|
@ -47,6 +47,10 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string]
|
|||
parsed, parseErr = RC.NewUid(payload, target)
|
||||
case "IN-TYPE":
|
||||
parsed, parseErr = RC.NewInType(payload, target)
|
||||
case "IN-USER":
|
||||
parsed, parseErr = RC.NewInUser(payload, target)
|
||||
case "IN-NAME":
|
||||
parsed, parseErr = RC.NewInName(payload, target)
|
||||
case "SUB-RULE":
|
||||
parsed, parseErr = logic.NewSubRule(payload, target, subRules, ParseRule)
|
||||
case "AND":
|
||||
|
|
Loading…
Reference in a new issue