Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

Commit

Permalink
Add LAN IP whitelist and blacklist to inbound
Browse files Browse the repository at this point in the history
configuration
  • Loading branch information
MerlinKodo committed Nov 14, 2023
1 parent 93dc2ba commit de5b09a
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 1 deletion.
65 changes: 65 additions & 0 deletions adapter/inbound/ipfilter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package inbound

import (
"net"
"net/netip"

C "github.com/MerlinKodo/clash-rev/constant"
)

var lanAllowedIPs []netip.Prefix
var lanDisAllowedIPs []netip.Prefix

func SetAllowedIPs(prefixes []netip.Prefix) {
lanAllowedIPs = prefixes
}

func SetDisAllowedIPs(prefixes []netip.Prefix) {
lanDisAllowedIPs = prefixes
}

func AllowedIPs() []netip.Prefix {
return lanAllowedIPs
}

func DisAllowedIPs() []netip.Prefix {
return lanDisAllowedIPs
}

func IsRemoteAddrAllowed(addr net.Addr) bool {
m := C.Metadata{}
if err := m.SetRemoteAddr(addr); err != nil {
return false
}
return isAllowed(m.AddrPort().Addr()) && !isDisAllowed(m.AddrPort().Addr())
}

func IsRemoteAddressAllowed(addr string) bool {
m := C.Metadata{}
if err := m.SetRemoteAddress(addr); err != nil {
return false
}
return isAllowed(m.AddrPort().Addr()) && !isDisAllowed(m.AddrPort().Addr())
}

func isAllowed(addr netip.Addr) bool {
if addr.IsValid() {
for _, prefix := range lanAllowedIPs {
if prefix.Contains(addr.Unmap()) {
return true
}
}
}
return false
}

func isDisAllowed(addr netip.Addr) bool {
if addr.IsValid() {
for _, prefix := range lanDisAllowedIPs {
if prefix.Contains(addr.Unmap()) {
return true
}
}
}
return false
}
8 changes: 7 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ type Inbound struct {
VmessConfig string `json:"vmess-config"`
Authentication []string `json:"authentication"`
SkipAuthPrefixes []netip.Prefix `json:"skip-auth-prefixes"`
LanAllowedIPs []netip.Prefix `json:"lan-allowed-ips"`
LanDisAllowedIPs []netip.Prefix `json:"lan-disallowed-ips"`
AllowLan bool `json:"allow-lan"`
BindAddress string `json:"bind-address"`
InboundTfo bool `json:"inbound-tfo"`
Expand Down Expand Up @@ -275,6 +277,8 @@ type RawConfig struct {
Authentication []string `yaml:"authentication"`
SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"`
AllowLan bool `yaml:"allow-lan"`
LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips"`
LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips"`
BindAddress string `yaml:"bind-address"`
Mode T.TunnelMode `yaml:"mode"`
UnifiedDelay bool `yaml:"unified-delay"`
Expand Down Expand Up @@ -368,6 +372,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
rawCfg := &RawConfig{
AllowLan: false,
BindAddress: "*",
LanAllowedIPs: []netip.Prefix{netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("::/0")},
IPv6: true,
Mode: T.Rule,
GeodataMode: C.GeodataMode,
Expand Down Expand Up @@ -473,7 +478,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
if err := yaml.Unmarshal(buf, rawCfg); err != nil {
return nil, err
}

return rawCfg, nil
}

Expand Down Expand Up @@ -623,6 +627,8 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
ShadowSocksConfig: cfg.ShadowSocksConfig,
VmessConfig: cfg.VmessConfig,
AllowLan: cfg.AllowLan,
LanAllowedIPs: cfg.LanAllowedIPs,
LanDisAllowedIPs: cfg.LanDisAllowedIPs,
SkipAuthPrefixes: cfg.SkipAuthPrefixes,
BindAddress: cfg.BindAddress,
InboundTfo: cfg.InboundTfo,
Expand Down
5 changes: 5 additions & 0 deletions docs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口

allow-lan: true # 允许局域网连接
bind-address: "*" # 绑定 IP 地址,仅作用于 allow-lan 为 true,'*'表示所有地址
lan-allowed-ips: # 允许连接的 IP 地址段,仅作用于 allow-lan 为 true, 默认值为0.0.0.0/0和::/0
- 0.0.0.0/0
- ::/0
lan-disallowed-ips: # 禁止连接的 IP 地址段, 黑名单优先级高于白名单
- 10.65.10.0/24

# find-process-mode has 3 values:always, strict, off
# - always, 开启,强制匹配所有进程
Expand Down
4 changes: 4 additions & 0 deletions hub/executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ func GetGeneral() *config.General {
VmessConfig: ports.VmessConfig,
Authentication: authenticator,
SkipAuthPrefixes: inbound.SkipAuthPrefixes(),
LanAllowedIPs: inbound.AllowedIPs(),
LanDisAllowedIPs: inbound.DisAllowedIPs(),
AllowLan: listener.AllowLan(),
BindAddress: listener.BindAddress(),
},
Expand All @@ -166,6 +168,8 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList
allowLan := general.AllowLan
listener.SetAllowLan(allowLan)
inbound.SetSkipAuthPrefixes(general.SkipAuthPrefixes)
inbound.SetAllowedIPs(general.LanAllowedIPs)
inbound.SetDisAllowedIPs(general.LanDisAllowedIPs)

bindAddress := general.BindAddress
listener.SetBindAddress(bindAddress)
Expand Down
10 changes: 10 additions & 0 deletions hub/route/configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ type configSchema struct {
UdptunConfig *string `json:"udptun-config"`
AllowLan *bool `json:"allow-lan"`
SkipAuthPrefixes *[]netip.Prefix `json:"skip-auth-prefixes"`
LanAllowedIPs *[]netip.Prefix `json:"lan-allowed-ips"`
LanDisAllowedIPs *[]netip.Prefix `json:"lan-disallowed-ips"`
BindAddress *string `json:"bind-address"`
Mode *tunnel.TunnelMode `json:"mode"`
LogLevel *log.LogLevel `json:"log-level"`
Expand Down Expand Up @@ -252,6 +254,14 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
inbound.SetSkipAuthPrefixes(*general.SkipAuthPrefixes)
}

if general.LanAllowedIPs != nil {
inbound.SetAllowedIPs(*general.LanAllowedIPs)
}

if general.LanDisAllowedIPs != nil {
inbound.SetDisAllowedIPs(*general.LanDisAllowedIPs)
}

if general.BindAddress != nil {
P.SetBindAddress(*general.BindAddress)
}
Expand Down
4 changes: 4 additions & 0 deletions listener/http/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool]

func authenticate(request *http.Request, cache *cache.LruCache[string, bool]) *http.Response {
authenticator := authStore.Authenticator()
if !inbound.IsRemoteAddressAllowed(request.RemoteAddr) {
log.Infoln("Remote address %s is not allowed", request.RemoteAddr)
return responseWith(request, http.StatusForbidden)
}
if inbound.SkipAuthRemoteAddress(request.RemoteAddr) {
authenticator = nil
}
Expand Down
8 changes: 8 additions & 0 deletions listener/socks/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func handleSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition)

func HandleSocks4(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
authenticator := authStore.Authenticator()
if inbound.IsRemoteAddrAllowed(conn.RemoteAddr()) {
conn.Close()
return
}
if inbound.SkipAuthRemoteAddr(conn.RemoteAddr()) {
authenticator = nil
}
Expand All @@ -100,6 +104,10 @@ func HandleSocks4(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition)

func HandleSocks5(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) {
authenticator := authStore.Authenticator()
if !inbound.IsRemoteAddrAllowed(conn.RemoteAddr()) {
conn.Close()
return
}
if inbound.SkipAuthRemoteAddr(conn.RemoteAddr()) {
authenticator = nil
}
Expand Down

0 comments on commit de5b09a

Please sign in to comment.