chore: add IN-USER and IN-NAME rules

This commit is contained in:
wwqgtxx 2023-05-28 17:19:57 +08:00
parent 7aae781569
commit 9c2972afb0
9 changed files with 142 additions and 18 deletions

View file

@ -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 { func WithSpecialRules(specialRules string) Addition {
return func(metadata *C.Metadata) { return func(metadata *C.Metadata) {
metadata.SpecialRules = specialRules metadata.SpecialRules = specialRules

View file

@ -133,6 +133,7 @@ type Metadata struct {
InIP netip.Addr `json:"inboundIP"` InIP netip.Addr `json:"inboundIP"`
InPort string `json:"inboundPort"` InPort string `json:"inboundPort"`
InName string `json:"inboundName"` InName string `json:"inboundName"`
InUser string `json:"inboundUser"`
Host string `json:"host"` Host string `json:"host"`
DNSMode DNSMode `json:"dnsMode"` DNSMode DNSMode `json:"dnsMode"`
Uid uint32 `json:"uid"` Uid uint32 `json:"uid"`

View file

@ -14,12 +14,14 @@ const (
SrcPort SrcPort
DstPort DstPort
InPort InPort
InUser
InName
InType
Process Process
ProcessPath ProcessPath
RuleSet RuleSet
Network Network
Uid Uid
INTYPE
SubRules SubRules
MATCH MATCH
AND AND
@ -55,6 +57,12 @@ func (rt RuleType) String() string {
return "DstPort" return "DstPort"
case InPort: case InPort:
return "InPort" return "InPort"
case InUser:
return "InUser"
case InName:
return "InName"
case InType:
return "InType"
case Process: case Process:
return "Process" return "Process"
case ProcessPath: case ProcessPath:
@ -67,8 +75,6 @@ func (rt RuleType) String() string {
return "Network" return "Network"
case Uid: case Uid:
return "Uid" return "Uid"
case INTYPE:
return "InType"
case SubRules: case SubRules:
return "SubRules" return "SubRules"
case AND: case AND:

View file

@ -2,8 +2,11 @@ package sing
import ( import (
"context" "context"
"golang.org/x/exp/slices"
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
"github.com/sagernet/sing/common/auth"
) )
type contextKey string type contextKey string
@ -22,3 +25,20 @@ func getAdditions(ctx context.Context) []inbound.Addition {
} }
return nil 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
}

View file

@ -3,7 +3,6 @@ package sing
import ( import (
"context" "context"
"errors" "errors"
"golang.org/x/exp/slices"
"net" "net"
"net/netip" "net/netip"
"sync" "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 { 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 { switch metadata.Destination.Fqdn {
case mux.Destination.Fqdn: case mux.Destination.Fqdn:
return mux.HandleConnection(ctx, h, log.SingLogger, conn, UpstreamMetadata(metadata)) 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) { if deadline.NeedAdditionalReadDeadline(conn) {
conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline 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 return nil
} }
func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error { 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) { if deadline.NeedAdditionalReadDeadline(conn) {
conn = deadline.NewFallbackPacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline 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, buff: buff,
} }
select { 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: default:
} }
} }

49
rules/common/in_name.go Normal file
View 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
}

View file

@ -23,7 +23,7 @@ func (u *InType) Match(metadata *C.Metadata) (bool, string) {
} }
func (u *InType) RuleType() C.RuleType { func (u *InType) RuleType() C.RuleType {
return C.INTYPE return C.InType
} }
func (u *InType) Adapter() string { func (u *InType) Adapter() string {
@ -37,7 +37,7 @@ func (u *InType) Payload() string {
func NewInType(iTypes, adapter string) (*InType, error) { func NewInType(iTypes, adapter string) (*InType, error) {
types := strings.Split(iTypes, "/") types := strings.Split(iTypes, "/")
if len(types) == 0 { 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) tps, err := parseInTypes(types)

49
rules/common/in_user.go Normal file
View 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
}

View file

@ -47,6 +47,10 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string]
parsed, parseErr = RC.NewUid(payload, target) parsed, parseErr = RC.NewUid(payload, target)
case "IN-TYPE": case "IN-TYPE":
parsed, parseErr = RC.NewInType(payload, target) 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": case "SUB-RULE":
parsed, parseErr = logic.NewSubRule(payload, target, subRules, ParseRule) parsed, parseErr = logic.NewSubRule(payload, target, subRules, ParseRule)
case "AND": case "AND":