From d2927439811aab1b91f540a1cc49fbf45893afa9 Mon Sep 17 00:00:00 2001 From: gVisor bot Date: Sat, 2 Feb 2019 21:03:13 +0800 Subject: [PATCH] Feature: SOURCE-IP-CIDR rule type (#96) --- README.md | 1 + adapters/inbound/http.go | 4 +++- adapters/inbound/https.go | 4 +++- adapters/inbound/socket.go | 1 + adapters/inbound/util.go | 7 +++++++ config/config.go | 4 +++- constant/metadata.go | 1 + constant/rule.go | 3 +++ rules/ipcidr.go | 23 ++++++++++++++--------- tunnel/tunnel.go | 6 +++--- 10 files changed, 39 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 31c2bb20..ec256ba1 100644 --- a/README.md +++ b/README.md @@ -170,6 +170,7 @@ Rule: - DOMAIN,google.com,Proxy - DOMAIN-SUFFIX,ad.com,REJECT - IP-CIDR,127.0.0.0/8,DIRECT +- SOURCE-IP-CIDR,192.168.1.201/32,DIRECT - GEOIP,CN,DIRECT # FINAL would remove after prerelease # you also can use `FINAL,Proxy` or `FINAL,,Proxy` now diff --git a/adapters/inbound/http.go b/adapters/inbound/http.go index 01aa14b8..8aa21e7c 100644 --- a/adapters/inbound/http.go +++ b/adapters/inbound/http.go @@ -32,8 +32,10 @@ func (h *HTTPAdapter) Conn() net.Conn { // NewHTTP is HTTPAdapter generator func NewHTTP(request *http.Request, conn net.Conn) *HTTPAdapter { + metadata := parseHTTPAddr(request) + metadata.SourceIP = parseSourceIP(conn) return &HTTPAdapter{ - metadata: parseHTTPAddr(request), + metadata: metadata, R: request, conn: conn, } diff --git a/adapters/inbound/https.go b/adapters/inbound/https.go index 6e36180b..e9512686 100644 --- a/adapters/inbound/https.go +++ b/adapters/inbound/https.go @@ -7,8 +7,10 @@ import ( // NewHTTPS is HTTPAdapter generator func NewHTTPS(request *http.Request, conn net.Conn) *SocketAdapter { + metadata := parseHTTPAddr(request) + metadata.SourceIP = parseSourceIP(conn) return &SocketAdapter{ - metadata: parseHTTPAddr(request), + metadata: metadata, conn: conn, } } diff --git a/adapters/inbound/socket.go b/adapters/inbound/socket.go index 8c0ef49d..66f13f65 100644 --- a/adapters/inbound/socket.go +++ b/adapters/inbound/socket.go @@ -32,6 +32,7 @@ func (s *SocketAdapter) Conn() net.Conn { func NewSocket(target socks.Addr, conn net.Conn, source C.SourceType) *SocketAdapter { metadata := parseSocksAddr(target) metadata.Source = source + metadata.SourceIP = parseSourceIP(conn) return &SocketAdapter{ conn: conn, diff --git a/adapters/inbound/util.go b/adapters/inbound/util.go index a1f5cd08..b059920a 100644 --- a/adapters/inbound/util.go +++ b/adapters/inbound/util.go @@ -61,3 +61,10 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } + +func parseSourceIP(conn net.Conn) *net.IP { + if addr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { + return &addr.IP + } + return nil +} diff --git a/config/config.go b/config/config.go index 95f27721..979da3ef 100644 --- a/config/config.go +++ b/config/config.go @@ -338,7 +338,9 @@ func parseRules(cfg *rawConfig) ([]C.Rule, error) { case "GEOIP": rules = append(rules, R.NewGEOIP(payload, target)) case "IP-CIDR", "IP-CIDR6": - rules = append(rules, R.NewIPCIDR(payload, target)) + rules = append(rules, R.NewIPCIDR(payload, target, false)) + case "SOURCE-IP-CIDR": + rules = append(rules, R.NewIPCIDR(payload, target, true)) case "MATCH": fallthrough case "FINAL": diff --git a/constant/metadata.go b/constant/metadata.go index f47a8c83..4a361dfb 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -33,6 +33,7 @@ type SourceType int type Metadata struct { NetWork NetWork Source SourceType + SourceIP *net.IP AddrType int Host string IP *net.IP diff --git a/constant/rule.go b/constant/rule.go index 1a8f5f97..ba287501 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -7,6 +7,7 @@ const ( DomainKeyword GEOIP IPCIDR + SourceIPCIDR FINAL ) @@ -24,6 +25,8 @@ func (rt RuleType) String() string { return "GEOIP" case IPCIDR: return "IPCIDR" + case SourceIPCIDR: + return "SourceIPCIDR" case FINAL: return "FINAL" default: diff --git a/rules/ipcidr.go b/rules/ipcidr.go index fe1a9d9c..597ac3e1 100644 --- a/rules/ipcidr.go +++ b/rules/ipcidr.go @@ -7,20 +7,24 @@ import ( ) type IPCIDR struct { - ipnet *net.IPNet - adapter string + ipnet *net.IPNet + adapter string + isSourceIP bool } func (i *IPCIDR) RuleType() C.RuleType { + if i.isSourceIP { + return C.SourceIPCIDR + } return C.IPCIDR } func (i *IPCIDR) IsMatch(metadata *C.Metadata) bool { - if metadata.IP == nil { - return false + ip := metadata.IP + if i.isSourceIP { + ip = metadata.SourceIP } - - return i.ipnet.Contains(*metadata.IP) + return i.ipnet.Contains(*ip) } func (i *IPCIDR) Adapter() string { @@ -31,12 +35,13 @@ func (i *IPCIDR) Payload() string { return i.ipnet.String() } -func NewIPCIDR(s string, adapter string) *IPCIDR { +func NewIPCIDR(s string, adapter string, isSourceIP bool) *IPCIDR { _, ipnet, err := net.ParseCIDR(s) if err != nil { } return &IPCIDR{ - ipnet: ipnet, - adapter: adapter, + ipnet: ipnet, + adapter: adapter, + isSourceIP: isSourceIP, } } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 30ce12ba..96920818 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -141,7 +141,7 @@ func (t *Tunnel) handleConn(localConn C.ServerAdapter) { remoConn, err := proxy.Generator(metadata) if err != nil { - log.Warnln("Proxy[%s] connect [%s] error: %s", proxy.Name(), metadata.String(), err.Error()) + log.Warnln("Proxy[%s] connect [%s --> %s] error: %s", proxy.Name(), metadata.SourceIP.String(), metadata.String(), err.Error()) return } defer remoConn.Close() @@ -174,12 +174,12 @@ func (t *Tunnel) match(metadata *C.Metadata) (C.Proxy, error) { if rule.IsMatch(metadata) { if a, ok := t.proxies[rule.Adapter()]; ok { - log.Infoln("%v match %s using %s", metadata.String(), rule.RuleType().String(), rule.Adapter()) + log.Infoln("%s --> %v match %s using %s", metadata.SourceIP.String(), metadata.String(), rule.RuleType().String(), rule.Adapter()) return a, nil } } } - log.Infoln("%v doesn't match any rule using DIRECT", metadata.String()) + log.Infoln("%s --> %v doesn't match any rule using DIRECT", metadata.SourceIP.String(), metadata.String()) return t.proxies["DIRECT"], nil }