Reset a project

This commit is contained in:
9seconds
2021-03-04 10:15:34 +03:00
parent 7718f62477
commit baee322cd7
95 changed files with 2 additions and 6505 deletions
-312
View File
@@ -1,312 +0,0 @@
package config
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"math"
"net"
"github.com/alecthomas/units"
statsd "github.com/smira/go-statsd"
"go.uber.org/zap"
)
type SecretMode uint8
func (s SecretMode) String() string {
switch s {
case SecretModeSimple:
return "simple"
case SecretModeSecured:
return "secured"
case SecretModeTLS:
return "tls"
}
return "tls"
}
const (
SecretModeSimple SecretMode = iota
SecretModeSecured
SecretModeTLS
)
type PreferIP uint8
const (
PreferIPv4 PreferIP = iota
PreferIPv6
)
const SimpleSecretLength = 16
type OptionType uint8
const (
OptionTypeDebug OptionType = iota
OptionTypeVerbose
OptionTypePreferIP
OptionTypeBind
OptionTypePublicIPv4
OptionTypePublicIPv6
OptionTypeStatsBind
OptionTypeStatsNamespace
OptionTypeStatsdAddress
OptionTypeStatsdTagsFormat
OptionTypeStatsdTags
OptionTypeWriteBufferSize
OptionTypeReadBufferSize
OptionTypeCloakPort
OptionTypeAntiReplayMaxSize
OptionTypeMultiplexPerConnection
OptionTypeNTPServers
OptionTypeSecret
OptionTypeAdtag
)
type Config struct {
Bind *net.TCPAddr `json:"bind"`
PublicIPv4 *net.TCPAddr `json:"public_ipv4"`
PublicIPv6 *net.TCPAddr `json:"public_ipv6"`
StatsBind *net.TCPAddr `json:"stats_bind"`
StatsdAddr *net.TCPAddr `json:"stats_addr"`
StatsdTagsFormat *statsd.TagFormat `json:"statsd_tags_format"`
StatsNamespace string `json:"stats_namespace"`
CloakHost string `json:"cloak_host"`
StatsdTags map[string]string `json:"statsd_tags"`
WriteBuffer int `json:"write_buffer"`
ReadBuffer int `json:"read_buffer"`
CloakPort int `json:"cloak_port"`
AntiReplayMaxSize int `json:"anti_replay_max_size"`
MultiplexPerConnection int `json:"multiplex_per_connection"`
Debug bool `json:"debug"`
Verbose bool `json:"verbose"`
SecretMode SecretMode `json:"secret_mode"`
PreferIP PreferIP `json:"prefer_ip"`
NTPServers []string `json:"ntp_servers"`
Secret []byte `json:"secret"`
AdTag []byte `json:"adtag"`
}
func (c *Config) ClientReadBuffer() int {
return c.ReadBuffer
}
func (c *Config) ClientWriteBuffer() int {
return c.WriteBuffer
}
func (c *Config) MiddleProxyMode() bool {
return len(c.AdTag) > 0
}
func (c *Config) ProxyReadBuffer() int {
value := c.ReadBuffer
if c.MiddleProxyMode() {
value = c.adjustProxyValue(value)
}
return value
}
func (c *Config) ProxyWriteBuffer() int {
value := c.WriteBuffer
if c.MiddleProxyMode() {
value = c.adjustProxyValue(value)
}
return value
}
func (c *Config) adjustProxyValue(value int) int {
if c.MultiplexPerConnection == 0 {
return value
}
fvalue := float64(value)
newValue := fvalue * 2 * math.Log(float64(c.MultiplexPerConnection))
newValue = math.Ceil(newValue)
newValue = math.Max(fvalue, newValue)
return int(newValue)
}
type Opt struct {
Option OptionType
Value interface{}
}
var C = Config{}
func Init(options ...Opt) error { // nolint: gocyclo, funlen, cyclop
for _, opt := range options {
switch opt.Option {
case OptionTypeDebug:
C.Debug = opt.Value.(bool)
case OptionTypeVerbose:
C.Verbose = opt.Value.(bool)
case OptionTypePreferIP:
value := opt.Value.(string)
switch value {
case "ipv4":
C.PreferIP = PreferIPv4
case "ipv6":
C.PreferIP = PreferIPv6
default:
return fmt.Errorf("incorrect direct IP mode %s", value)
}
case OptionTypeBind:
C.Bind = opt.Value.(*net.TCPAddr)
case OptionTypePublicIPv4:
C.PublicIPv4 = opt.Value.(*net.TCPAddr)
if C.PublicIPv4 == nil {
C.PublicIPv4 = &net.TCPAddr{}
}
case OptionTypePublicIPv6:
C.PublicIPv6 = opt.Value.(*net.TCPAddr)
if C.PublicIPv6 == nil {
C.PublicIPv6 = &net.TCPAddr{}
}
case OptionTypeStatsBind:
C.StatsBind = opt.Value.(*net.TCPAddr)
case OptionTypeStatsNamespace:
C.StatsNamespace = opt.Value.(string)
case OptionTypeStatsdAddress:
C.StatsdAddr = opt.Value.(*net.TCPAddr)
case OptionTypeStatsdTagsFormat:
value := opt.Value.(string)
switch value {
case "datadog":
C.StatsdTagsFormat = statsd.TagFormatDatadog
case "influxdb":
C.StatsdTagsFormat = statsd.TagFormatInfluxDB
default:
return fmt.Errorf("incorrect statsd tag %s", value)
}
case OptionTypeStatsdTags:
C.StatsdTags = opt.Value.(map[string]string)
case OptionTypeWriteBufferSize:
C.WriteBuffer = int(opt.Value.(units.Base2Bytes))
case OptionTypeReadBufferSize:
C.ReadBuffer = int(opt.Value.(units.Base2Bytes))
case OptionTypeCloakPort:
C.CloakPort = int(opt.Value.(uint16))
case OptionTypeAntiReplayMaxSize:
C.AntiReplayMaxSize = int(opt.Value.(units.Base2Bytes))
case OptionTypeMultiplexPerConnection:
C.MultiplexPerConnection = int(opt.Value.(uint))
case OptionTypeNTPServers:
C.NTPServers = opt.Value.([]string)
if len(C.NTPServers) == 0 {
return errors.New("ntp server list is empty")
}
case OptionTypeSecret:
C.Secret = opt.Value.([]byte)
case OptionTypeAdtag:
C.AdTag = opt.Value.([]byte)
default:
return fmt.Errorf("unknown tag %v", opt.Option)
}
}
switch {
case len(C.Secret) == 1+SimpleSecretLength && bytes.HasPrefix(C.Secret, []byte{0xdd}):
C.SecretMode = SecretModeSecured
C.Secret = bytes.TrimPrefix(C.Secret, []byte{0xdd})
case len(C.Secret) > SimpleSecretLength && bytes.HasPrefix(C.Secret, []byte{0xee}):
C.SecretMode = SecretModeTLS
secret := bytes.TrimPrefix(C.Secret, []byte{0xee})
C.Secret = secret[:SimpleSecretLength]
C.CloakHost = string(secret[SimpleSecretLength:])
case len(C.Secret) == SimpleSecretLength:
C.SecretMode = SecretModeSimple
default:
return errors.New("incorrect secret")
}
if C.MultiplexPerConnection == 0 {
return errors.New("cannot use 0 clients per connection for multiplexing")
}
if C.CloakHost != "" {
if _, err := net.LookupHost(C.CloakHost); err != nil {
zap.S().Warnw("Cannot resolve address of host", "hostname", C.CloakHost, "error", err)
}
}
return nil
}
func InitPublicAddress(ctx context.Context) error {
if C.PublicIPv4.Port == 0 {
C.PublicIPv4.Port = C.Bind.Port
}
if C.PublicIPv6.Port == 0 {
C.PublicIPv6.Port = C.Bind.Port
}
foundAddress := C.PublicIPv4.IP != nil || C.PublicIPv6.IP != nil
if C.PublicIPv4.IP == nil {
ip, err := getGlobalIPv4(ctx)
if err != nil {
zap.S().Warnw("Cannot resolve public address", "error", err)
} else {
C.PublicIPv4.IP = ip
foundAddress = true
}
}
if C.PublicIPv6.IP == nil {
ip, err := getGlobalIPv6(ctx)
if err != nil {
zap.S().Warnw("Cannot resolve public address", "error", err)
} else {
C.PublicIPv6.IP = ip
foundAddress = true
}
}
if !foundAddress {
return errors.New("cannot resolve any public address")
}
return nil
}
func Printable() interface{} {
data, err := json.Marshal(C)
if err != nil {
panic(err)
}
rv := map[string]interface{}{}
if err := json.Unmarshal(data, &rv); err != nil {
panic(err)
}
return rv
}
-78
View File
@@ -1,78 +0,0 @@
package config
import (
"context"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"strings"
"time"
)
const (
ifconfigAddress = "https://ifconfig.co/ip"
ifconfigTimeout = 10 * time.Second
)
func getGlobalIPv4(ctx context.Context) (net.IP, error) {
ip, err := fetchIP(ctx, "tcp4")
if err != nil || ip.To4() == nil {
return nil, fmt.Errorf("cannot find public ipv4 address: %w", err)
}
return ip, nil
}
func getGlobalIPv6(ctx context.Context) (net.IP, error) {
ip, err := fetchIP(ctx, "tcp6")
if err != nil || ip.To4() != nil {
return nil, fmt.Errorf("cannot find public ipv6 address: %w", err)
}
return ip, nil
}
func fetchIP(ctx context.Context, network string) (net.IP, error) {
dialer := &net.Dialer{FallbackDelay: -1}
client := &http.Client{
Jar: nil,
Timeout: ifconfigTimeout,
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, addr string) (net.Conn, error) {
return dialer.DialContext(ctx, network, addr)
},
},
}
req, err := http.NewRequest("GET", ifconfigAddress, nil)
if err != nil {
return nil, fmt.Errorf("cannot create a request: %w", err)
}
resp, err := client.Do(req.WithContext(ctx))
if err != nil {
if resp != nil {
io.Copy(ioutil.Discard, resp.Body) // nolint: errcheck
}
return nil, fmt.Errorf("cannot perform a request: %w", err)
}
defer resp.Body.Close()
respDataBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("cannot read response body: %w", err)
}
respData := strings.TrimSpace(string(respDataBytes))
ip := net.ParseIP(respData)
if ip == nil {
return nil, fmt.Errorf("ifconfig.co returns incorrect IP %s", respData)
}
return ip, nil
}
-99
View File
@@ -1,99 +0,0 @@
package config
import (
"encoding/hex"
"net"
"net/url"
"strconv"
)
type URLs struct {
TG string `json:"tg_url"`
TMe string `json:"tme_url"`
TGQRCode string `json:"tg_qrcode"`
TMeQRCode string `json:"tme_qrcode"`
}
type IPURLs struct {
IPv4 *URLs `json:"ipv4,omitempty"`
IPv6 *URLs `json:"ipv6,omitempty"`
BotSecret string `json:"secret_for_mtproxybot"`
}
func GetURLs() (urls IPURLs) {
secret := ""
switch C.SecretMode {
case SecretModeSimple:
secret = hex.EncodeToString(C.Secret)
case SecretModeSecured:
secret = "dd" + hex.EncodeToString(C.Secret)
case SecretModeTLS:
secret = "ee" + hex.EncodeToString(C.Secret) + hex.EncodeToString([]byte(C.CloakHost))
}
if C.PublicIPv4.IP != nil {
urls.IPv4 = makeURLs(C.PublicIPv4, secret)
}
if C.PublicIPv6.IP != nil {
urls.IPv6 = makeURLs(C.PublicIPv6, secret)
}
urls.BotSecret = hex.EncodeToString(C.Secret)
return urls
}
func makeURLs(addr *net.TCPAddr, secret string) *URLs {
urls := &URLs{}
values := url.Values{}
values.Set("server", addr.IP.String())
values.Set("port", strconv.Itoa(addr.Port))
values.Set("secret", secret)
return &URLs{
TG: makeTGURL(values),
TMe: makeTMeURL(values),
TGQRCode: makeQRCodeURL(urls.TG),
TMeQRCode: makeQRCodeURL(urls.TMe),
}
}
func makeTGURL(values url.Values) string {
tgURL := url.URL{
Scheme: "tg",
Host: "proxy",
RawQuery: values.Encode(),
}
return tgURL.String()
}
func makeTMeURL(values url.Values) string {
tMeURL := url.URL{
Scheme: "https",
Host: "t.me",
Path: "proxy",
RawQuery: values.Encode(),
}
return tMeURL.String()
}
func makeQRCodeURL(data string) string {
qr := url.URL{
Scheme: "https",
Host: "api.qrserver.com",
Path: "v1/create-qr-code",
}
values := url.Values{}
values.Set("qzone", "4")
values.Set("format", "svg")
values.Set("data", data)
qr.RawQuery = values.Encode()
return qr.String()
}