feat: Add LAN allowed and disallowed IP configurations
This commit is contained in:
parent
aef87b29ba
commit
507c02d4e6
7 changed files with 105 additions and 3 deletions
65
adapter/inbound/ipfilter.go
Normal file
65
adapter/inbound/ipfilter.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
package inbound
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
C "github.com/metacubex/mihomo/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
|
||||
}
|
|
@ -80,6 +80,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"`
|
||||
|
@ -285,6 +287,8 @@ type RawConfig struct {
|
|||
InboundMPTCP bool `yaml:"inbound-mptcp"`
|
||||
Authentication []string `yaml:"authentication" json:"authentication"`
|
||||
SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"`
|
||||
LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips"`
|
||||
LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips"`
|
||||
AllowLan bool `yaml:"allow-lan" json:"allow-lan"`
|
||||
BindAddress string `yaml:"bind-address" json:"bind-address"`
|
||||
Mode T.TunnelMode `yaml:"mode" json:"mode"`
|
||||
|
@ -383,6 +387,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,
|
||||
GeoAutoUpdate: false,
|
||||
|
@ -643,6 +648,8 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
|
|||
VmessConfig: cfg.VmessConfig,
|
||||
AllowLan: cfg.AllowLan,
|
||||
SkipAuthPrefixes: cfg.SkipAuthPrefixes,
|
||||
LanAllowedIPs: cfg.LanAllowedIPs,
|
||||
LanDisAllowedIPs: cfg.LanDisAllowedIPs,
|
||||
BindAddress: cfg.BindAddress,
|
||||
InboundTfo: cfg.InboundTfo,
|
||||
InboundMPTCP: cfg.InboundMPTCP,
|
||||
|
|
|
@ -13,6 +13,11 @@ authentication: # http,socks入口的验证用户名,密码
|
|||
skip-auth-prefixes: # 设置跳过验证的IP段
|
||||
- 127.0.0.1/8
|
||||
- ::1/128
|
||||
lan-allowed-ips: # 允许连接的 IP 地址段,仅作用于 allow-lan 为 true, 默认值为0.0.0.0/0和::/0
|
||||
- 0.0.0.0/0
|
||||
- ::/0
|
||||
lan-disallowed-ips: # 禁止连接的 IP 地址段, 黑名单优先级高于白名单, 默认值为空
|
||||
- 192.168.0.3/32
|
||||
|
||||
# find-process-mode has 3 values:always, strict, off
|
||||
# - always, 开启,强制匹配所有进程
|
||||
|
|
|
@ -140,6 +140,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(),
|
||||
},
|
||||
|
@ -165,6 +167,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)
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"github.com/metacubex/mihomo/component/dialer"
|
||||
"github.com/metacubex/mihomo/component/resolver"
|
||||
"github.com/metacubex/mihomo/config"
|
||||
"github.com/metacubex/mihomo/constant"
|
||||
C "github.com/metacubex/mihomo/constant"
|
||||
"github.com/metacubex/mihomo/hub/executor"
|
||||
P "github.com/metacubex/mihomo/listener"
|
||||
|
@ -50,6 +49,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"`
|
||||
|
@ -252,6 +253,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)
|
||||
}
|
||||
|
@ -319,7 +328,7 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
} else {
|
||||
if req.Path == "" {
|
||||
req.Path = constant.Path.Config()
|
||||
req.Path = C.Path.Config()
|
||||
}
|
||||
if !filepath.IsAbs(req.Path) {
|
||||
render.Status(r, http.StatusBadRequest)
|
||||
|
@ -364,7 +373,7 @@ func updateGeoDatabases(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
cfg, err := executor.ParseWithPath(constant.Path.Config())
|
||||
cfg, err := executor.ParseWithPath(C.Path.Config())
|
||||
if err != nil {
|
||||
log.Errorln("[REST-API] update GEO databases failed: %v", err)
|
||||
return
|
||||
|
|
|
@ -100,6 +100,10 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool],
|
|||
|
||||
func authenticate(request *http.Request, cache *lru.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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue