Add http/block outbound & Improve route

This commit is contained in:
世界
2022-07-03 23:23:18 +08:00
parent 18e3f43df3
commit 4fc4eb09b0
25 changed files with 408 additions and 201 deletions

View File

@@ -1,31 +0,0 @@
package option
import (
"net/netip"
"github.com/goccy/go-json"
)
type ListenAddress netip.Addr
func (a ListenAddress) MarshalJSON() ([]byte, error) {
addr := netip.Addr(a)
if !addr.IsValid() {
return json.Marshal("")
}
return json.Marshal(addr.String())
}
func (a *ListenAddress) UnmarshalJSON(bytes []byte) error {
var value string
err := json.Unmarshal(bytes, &value)
if err != nil {
return err
}
addr, err := netip.ParseAddr(value)
if err != nil {
return err
}
*a = ListenAddress(addr)
return nil
}

View File

@@ -2,14 +2,15 @@ package option
import (
"github.com/goccy/go-json"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
E "github.com/sagernet/sing/common/exceptions"
)
type _Inbound struct {
Tag string `json:"tag,omitempty"`
Type string `json:"type"`
Tag string `json:"tag,omitempty"`
DirectOptions DirectInboundOptions `json:"-"`
SocksOptions SimpleInboundOptions `json:"-"`
HTTPOptions SimpleInboundOptions `json:"-"`
@@ -22,25 +23,25 @@ type Inbound _Inbound
func (h Inbound) Equals(other Inbound) bool {
return h.Type == other.Type &&
h.Tag == other.Tag &&
common.Equals(h.DirectOptions, other.DirectOptions) &&
common.Equals(h.SocksOptions, other.SocksOptions) &&
common.Equals(h.HTTPOptions, other.HTTPOptions) &&
common.Equals(h.MixedOptions, other.MixedOptions) &&
common.Equals(h.ShadowsocksOptions, other.ShadowsocksOptions)
h.DirectOptions == other.DirectOptions &&
h.SocksOptions.Equals(other.SocksOptions) &&
h.HTTPOptions.Equals(other.HTTPOptions) &&
h.MixedOptions.Equals(other.MixedOptions) &&
h.ShadowsocksOptions == other.ShadowsocksOptions
}
func (h Inbound) MarshalJSON() ([]byte, error) {
var v any
switch h.Type {
case "direct":
case C.TypeDirect:
v = h.DirectOptions
case "socks":
case C.TypeSocks:
v = h.SocksOptions
case "http":
case C.TypeHTTP:
v = h.HTTPOptions
case "mixed":
case C.TypeMixed:
v = h.MixedOptions
case "shadowsocks":
case C.TypeShadowsocks:
v = h.ShadowsocksOptions
default:
return nil, E.New("unknown inbound type: ", h.Type)
@@ -55,15 +56,15 @@ func (h *Inbound) UnmarshalJSON(bytes []byte) error {
}
var v any
switch h.Type {
case "direct":
case C.TypeDirect:
v = &h.DirectOptions
case "socks":
case C.TypeSocks:
v = &h.SocksOptions
case "http":
case C.TypeHTTP:
v = &h.HTTPOptions
case "mixed":
case C.TypeMixed:
v = &h.MixedOptions
case "shadowsocks":
case C.TypeShadowsocks:
v = &h.ShadowsocksOptions
default:
return nil
@@ -99,23 +100,9 @@ type DirectInboundOptions struct {
OverridePort uint16 `json:"override_port,omitempty"`
}
func (o DirectInboundOptions) Equals(other DirectInboundOptions) bool {
return o.ListenOptions == other.ListenOptions &&
common.ComparableSliceEquals(o.Network, other.Network) &&
o.OverrideAddress == other.OverrideAddress &&
o.OverridePort == other.OverridePort
}
type ShadowsocksInboundOptions struct {
ListenOptions
Network NetworkList `json:"network,omitempty"`
Method string `json:"method"`
Password string `json:"password"`
}
func (o ShadowsocksInboundOptions) Equals(other ShadowsocksInboundOptions) bool {
return o.ListenOptions == other.ListenOptions &&
common.ComparableSliceEquals(o.Network, other.Network) &&
o.Method == other.Method &&
o.Password == other.Password
}

View File

@@ -5,6 +5,8 @@ import (
"github.com/goccy/go-json"
"github.com/sagernet/sing-box/common/badjson"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
)
func ToMap(v any) (*badjson.JSONObject, error) {
@@ -33,6 +35,12 @@ func MergeObjects(objects ...any) (*badjson.JSONObject, error) {
}
func MarshallObjects(objects ...any) ([]byte, error) {
objects = common.Filter(objects, func(v any) bool {
return v != nil
})
if len(objects) == 1 {
return json.Marshal(objects[0])
}
content, err := MergeObjects(objects...)
if err != nil {
return nil, err
@@ -53,6 +61,12 @@ func UnmarshallExcluded(inputContent []byte, parentObject any, object any) error
for _, key := range parentContent.Keys() {
content.Remove(key)
}
if object == nil {
if content.IsEmpty() {
return nil
}
return E.New("unexpected key: ", content.Keys()[0])
}
inputContent, err = content.MarshalJSON()
if err != nil {
return err

View File

@@ -1,27 +0,0 @@
package option
import "github.com/goccy/go-json"
type Listable[T comparable] []T
func (l Listable[T]) MarshalJSON() ([]byte, error) {
arrayList := []T(l)
if len(arrayList) == 1 {
return json.Marshal(arrayList[0])
}
return json.Marshal(arrayList)
}
func (l *Listable[T]) UnmarshalJSON(bytes []byte) error {
err := json.Unmarshal(bytes, (*[]T)(l))
if err == nil {
return nil
}
var singleItem T
err = json.Unmarshal(bytes, &singleItem)
if err != nil {
return err
}
*l = []T{singleItem}
return nil
}

View File

@@ -1,39 +0,0 @@
package option
import (
"github.com/goccy/go-json"
C "github.com/sagernet/sing-box/constant"
E "github.com/sagernet/sing/common/exceptions"
)
type NetworkList []string
func (v *NetworkList) UnmarshalJSON(data []byte) error {
var networkList []string
err := json.Unmarshal(data, &networkList)
if err != nil {
var networkItem string
err = json.Unmarshal(data, &networkItem)
if err != nil {
return err
}
networkList = []string{networkItem}
}
for _, networkName := range networkList {
switch networkName {
case C.NetworkTCP, C.NetworkUDP:
break
default:
return E.New("unknown network: " + networkName)
}
}
*v = networkList
return nil
}
func (v *NetworkList) Build() []string {
if len(*v) == 0 {
return []string{C.NetworkTCP, C.NetworkUDP}
}
return *v
}

View File

@@ -2,6 +2,7 @@ package option
import (
"github.com/goccy/go-json"
C "github.com/sagernet/sing-box/constant"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
)
@@ -11,6 +12,7 @@ type _Outbound struct {
Type string `json:"type,omitempty"`
DirectOptions DirectOutboundOptions `json:"-"`
SocksOptions SocksOutboundOptions `json:"-"`
HTTPOptions HTTPOutboundOptions `json:"-"`
ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"`
}
@@ -19,12 +21,16 @@ type Outbound _Outbound
func (h Outbound) MarshalJSON() ([]byte, error) {
var v any
switch h.Type {
case "direct":
case C.TypeDirect:
v = h.DirectOptions
case "socks":
case C.TypeSocks:
v = h.SocksOptions
case "shadowsocks":
case C.TypeHTTP:
v = h.HTTPOptions
case C.TypeShadowsocks:
v = h.ShadowsocksOptions
case C.TypeBlock:
v = nil
default:
return nil, E.New("unknown outbound type: ", h.Type)
}
@@ -38,12 +44,16 @@ func (h *Outbound) UnmarshalJSON(bytes []byte) error {
}
var v any
switch h.Type {
case "direct":
case C.TypeDirect:
v = &h.DirectOptions
case "socks":
case C.TypeSocks:
v = &h.SocksOptions
case "shadowsocks":
case C.TypeHTTP:
v = &h.HTTPOptions
case C.TypeShadowsocks:
v = &h.ShadowsocksOptions
case C.TypeBlock:
v = nil
default:
return nil
}
@@ -71,10 +81,8 @@ type OverrideStreamOptions struct {
UDPOverTCP bool `json:"udp_over_tcp,omitempty"`
}
type DirectOutboundOptions struct {
DialerOptions
OverrideAddress string `json:"override_address,omitempty"`
OverridePort uint16 `json:"override_port,omitempty"`
func (o *OverrideStreamOptions) IsValid() bool {
return o != nil && (o.TLS || o.UDPOverTCP)
}
type ServerOptions struct {
@@ -86,10 +94,24 @@ func (o ServerOptions) Build() M.Socksaddr {
return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
}
type DirectOutboundOptions struct {
DialerOptions
OverrideAddress string `json:"override_address,omitempty"`
OverridePort uint16 `json:"override_port,omitempty"`
}
type SocksOutboundOptions struct {
DialerOptions
ServerOptions
Version string `json:"version,omitempty"`
Version string `json:"version,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Network NetworkList `json:"network,omitempty"`
}
type HTTPOutboundOptions struct {
DialerOptions
ServerOptions
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
}
@@ -97,6 +119,7 @@ type SocksOutboundOptions struct {
type ShadowsocksOutboundOptions struct {
DialerOptions
ServerOptions
Method string `json:"method"`
Password string `json:"password"`
Method string `json:"method"`
Password string `json:"password"`
Network NetworkList `json:"network,omitempty"`
}

View File

@@ -8,8 +8,9 @@ import (
)
type RouteOptions struct {
GeoIP *GeoIPOptions `json:"geoip,omitempty"`
Rules []Rule `json:"rules,omitempty"`
GeoIP *GeoIPOptions `json:"geoip,omitempty"`
Rules []Rule `json:"rules,omitempty"`
DefaultDetour string `json:"default_detour,omitempty"`
}
func (o RouteOptions) Equals(other RouteOptions) bool {
@@ -24,17 +25,17 @@ type GeoIPOptions struct {
}
type _Rule struct {
Type string `json:"type,omitempty"`
DefaultOptions *DefaultRule `json:"-"`
LogicalOptions *LogicalRule `json:"-"`
Type string `json:"type,omitempty"`
DefaultOptions DefaultRule `json:"-"`
LogicalOptions LogicalRule `json:"-"`
}
type Rule _Rule
func (r Rule) Equals(other Rule) bool {
return r.Type == other.Type &&
common.PtrEquals(r.DefaultOptions, other.DefaultOptions) &&
common.PtrEquals(r.LogicalOptions, other.LogicalOptions)
r.DefaultOptions.Equals(other.DefaultOptions) &&
r.LogicalOptions.Equals(other.LogicalOptions)
}
func (r Rule) MarshalJSON() ([]byte, error) {

90
option/types.go Normal file
View File

@@ -0,0 +1,90 @@
package option
import (
"net/netip"
"strings"
"github.com/goccy/go-json"
C "github.com/sagernet/sing-box/constant"
E "github.com/sagernet/sing/common/exceptions"
)
type ListenAddress netip.Addr
func (a ListenAddress) MarshalJSON() ([]byte, error) {
addr := netip.Addr(a)
if !addr.IsValid() {
return json.Marshal("")
}
return json.Marshal(addr.String())
}
func (a *ListenAddress) UnmarshalJSON(content []byte) error {
var value string
err := json.Unmarshal(content, &value)
if err != nil {
return err
}
addr, err := netip.ParseAddr(value)
if err != nil {
return err
}
*a = ListenAddress(addr)
return nil
}
type NetworkList string
func (v *NetworkList) UnmarshalJSON(content []byte) error {
var networkList []string
err := json.Unmarshal(content, &networkList)
if err != nil {
var networkItem string
err = json.Unmarshal(content, &networkItem)
if err != nil {
return err
}
networkList = []string{networkItem}
}
for _, networkName := range networkList {
switch networkName {
case C.NetworkTCP, C.NetworkUDP:
break
default:
return E.New("unknown network: " + networkName)
}
}
*v = NetworkList(strings.Join(networkList, "\n"))
return nil
}
func (v NetworkList) Build() []string {
if v == "" {
return []string{C.NetworkTCP, C.NetworkUDP}
}
return strings.Split(string(v), "\n")
}
type Listable[T comparable] []T
func (l Listable[T]) MarshalJSON() ([]byte, error) {
arrayList := []T(l)
if len(arrayList) == 1 {
return json.Marshal(arrayList[0])
}
return json.Marshal(arrayList)
}
func (l *Listable[T]) UnmarshalJSON(content []byte) error {
err := json.Unmarshal(content, (*[]T)(l))
if err == nil {
return nil
}
var singleItem T
err = json.Unmarshal(content, &singleItem)
if err != nil {
return err
}
*l = []T{singleItem}
return nil
}