init
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Author struct {
|
||||
cstype int
|
||||
token string
|
||||
clusterHost string
|
||||
clusterPort int
|
||||
Conn *tls.Conn
|
||||
Channel MessageChannel
|
||||
}
|
||||
|
||||
func NewAuthor(token, clusterHost string, clusterPort, cstype int) (author Author, err error) {
|
||||
conn, err := TlsConnect(clusterHost, clusterPort, 5000)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
author = Author{
|
||||
cstype: cstype,
|
||||
token: token,
|
||||
Conn: &conn,
|
||||
clusterHost: clusterHost,
|
||||
clusterPort: clusterPort,
|
||||
Channel: NewMessageChannelTls(&conn),
|
||||
}
|
||||
return
|
||||
}
|
||||
func (a *Author) DoControlAuth() (err error) {
|
||||
err = a.Channel.Write(MsgLogin{
|
||||
Msg: Msg{MsgType: MSG_TYPE_LOGIN},
|
||||
Token: a.token,
|
||||
CSType: a.cstype,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var resp MsgResponse
|
||||
err = a.Channel.ReadTimeout(&resp, 30000)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !resp.IsSuccess() {
|
||||
err = fmt.Errorf(resp.Message)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a *Author) IsServer() bool {
|
||||
return a.cstype == CSTYPE_SERVER
|
||||
}
|
||||
func (a *Author) IsClient() bool {
|
||||
return a.cstype == CSTYPE_CLIENT
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package at_common
|
||||
|
||||
var (
|
||||
server_cert_bytes []byte
|
||||
server_key_bytes []byte
|
||||
client_cert_bytes []byte
|
||||
client_key_bytes []byte
|
||||
root_cert_bytes []byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
server_cert_bytes = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDOTCCAiECCQDW3K+RyvKd8DANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJD
|
||||
TjESMBAGA1UECAwJR3VhbmdEb25nMRYwFAYDVQQKDA1Mb2NhbGhvc3QgTHRkMRcw
|
||||
FQYDVQQDDA5Mb2NhbGhvc3QgUm9vdDAeFw0xNzA5MTgwNzEzMDRaFw0yNzA5MTYw
|
||||
NzEzMDRaMGsxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxEjAQBgNV
|
||||
BAcMCUd1YW5nemhvdTEZMBcGA1UECgwQTG9jYWxob3N0IFNlcnZlcjEZMBcGA1UE
|
||||
AwwQYW55dHVubmVsLXNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAMDOzjT2PlwzbPqSvS9EMsqyY1G7/l770623Qp1S9Z2/A7fpldvblMh5Jttr
|
||||
zfQCJcx2RMb7InF3yFwsbaUqxFcR3hNzzzL6ib4Zyui5eNRggVSCw9W9oq4fYguK
|
||||
K83JtUE7sJDDgYF11ASDZUXVzIMF+RWG3VS38hs0w0TeTztyufSW8CHi2F8Txtim
|
||||
cyOVG2z0/a/wWaZ49C9ptTOJ5h4RrItA9yUtt6RVGNYaAA1UwMKLMQbPsPXSaxHK
|
||||
vanBQP2VH5ol1+efvfYc5WvaOqlAoXrAp9mv0a/QX5En+MPTmMnfQZS1y+jfXUTU
|
||||
5nqgRt7YEv7Ps04LyAJWS+8S8FcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAYL1L
|
||||
ai5WRxBzt6qCIujLaJY3zfFDu7WN1V4f8q/DwsXhfj9RwmTGU0s4e0HVhqL9ClbW
|
||||
0z40idlswbVf3UfvE0PhHyAtljjWoF03Gj/gGUiIaACP/UvtAeIzS3bKdI2wTHg+
|
||||
gmvp7sNCK7GyDdVKzsOYl2GO//EdHrmBEYaV2I3SBlPa4Zd9Ucg1WRvrtZz5jXwk
|
||||
/e3t9lEY2f02Q6CmCBjSaoJmXnTByexx/A7gYNG6/zYRBN+mmSndmOU3m2vyW99k
|
||||
xz/rNufScuVPM9Wx2kTyl+do75meSOabDpvS7Et/HkII8NFtuLU4KohmV/0SN9iS
|
||||
Jc6sB8ooIsRakdxVtQ==
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
server_key_bytes = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEoQIBAAKCAQEAwM7ONPY+XDNs+pK9L0QyyrJjUbv+XvvTrbdCnVL1nb8Dt+mV
|
||||
29uUyHkm22vN9AIlzHZExvsicXfIXCxtpSrEVxHeE3PPMvqJvhnK6Ll41GCBVILD
|
||||
1b2irh9iC4orzcm1QTuwkMOBgXXUBINlRdXMgwX5FYbdVLfyGzTDRN5PO3K59Jbw
|
||||
IeLYXxPG2KZzI5UbbPT9r/BZpnj0L2m1M4nmHhGsi0D3JS23pFUY1hoADVTAwosx
|
||||
Bs+w9dJrEcq9qcFA/ZUfmiXX55+99hzla9o6qUChesCn2a/Rr9BfkSf4w9OYyd9B
|
||||
lLXL6N9dRNTmeqBG3tgS/s+zTgvIAlZL7xLwVwIDAQABAoIBACZ2myhxn0shbzIl
|
||||
p9wQDNnm8G1TxZEJR9c14fIkpJ8Nhh5gWOb9TRcZJClNvk5ZR1UcmuffHaXpMW1B
|
||||
57W1bGm6RMU4qzMOTABCgPogVfx4LBTB6XNwW03FMPgAXnC1NpWG5NhcSC+dY+hq
|
||||
lf9ygVP6ExC6UNkfwQqwYewRNVk0VreJ7CTKLwIK/oSgp43379Ifri717w/WfpNz
|
||||
hO27tlaFHGoSa37ajGDhSgO5rU1KkK96xcbV+XpsGmOAkMl1VWpz51n+LML8ghf5
|
||||
vy1a6N1KE3mLueAQbtQet1kcQ/aAV9C6VYEu2gvH3j6wwKEgat1kHzGclgxXPqBu
|
||||
Sw+vRMECgYEA+E4hFPNaLjWudgAGd/94tq/xK67+lksg8QyCK+4LQ0/sson4sO8B
|
||||
OiQioKLHmKkkLPt9P+HqntdofcnwO2/97ePqP+9Efz30oeh5GBVz3RqsBKwf8hqZ
|
||||
/aEAkV6X5IC/M55oqwtjhJlXNep70e49WkfCbubaUZUB53snmgpHa2cCgYEAxshm
|
||||
quutrSw3IhgzV8kR5v0r6neaHmmHbdBZh0nyUXY8urxXZi6JUYiLi3zBkFXl+YTN
|
||||
sTNjtqshRBwhYr0596lxgXJNBra5Oc6Dqrx0G16q12aDMYBhoL7GLp3zpXVlfixS
|
||||
Zeg0BYu5nUwIz+Z6G6qRV2GMMzg/5rjSSIKSLZECgYBaNAfQlJcuMlIui9PNxAEW
|
||||
XNRAClJyRtiwuNqRGuj8iwxxz62ImUrY1EfAE2JvEwMRVEsr6eZRze8nwzSCYyzc
|
||||
Pu/aShGYJ+m2570WArUUnZvgFqeETCWk/dg29yY23I6ZMfLUME723L3R2F0i5mlj
|
||||
Yq4/m520BW2rqhG45AMOAQJ/Jgw1moGBvKO56cy4BxV1V8EdpsM9vJR2V46JlFuT
|
||||
BgSbmyJxmB1QK0r3art2USof2qKQvFoZu90FgQPhYATYE49bKmu2UpKm4WmlyghI
|
||||
MPTtvkzgz5jDFwFs7X9OI11VD9Fr9BV935He9TyYczKqLKF5MEB7lVIu6Pp3RWm4
|
||||
kQKBgQCqu2Lj5tFb76ec97de62tV74YLc46Me5HGBD/Nbq8BmhSmmTkNOMzmm3pe
|
||||
1e/d2j3flzDBAj1jZ40GnJ2tWzbwZyQHzPiCHqvWa99Yvgn3masknDR463CJcAsW
|
||||
n667udC8bjyP6DXXjXtQaZGvUh9wzs9ErtRdE5g39JauHNGF2w==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`)
|
||||
client_cert_bytes = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDOTCCAiECCQDW3K+RyvKd8TANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJD
|
||||
TjESMBAGA1UECAwJR3VhbmdEb25nMRYwFAYDVQQKDA1Mb2NhbGhvc3QgTHRkMRcw
|
||||
FQYDVQQDDA5Mb2NhbGhvc3QgUm9vdDAeFw0xNzA5MTgwNzEzMDRaFw0yNzA5MTYw
|
||||
NzEzMDRaMGsxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxEjAQBgNV
|
||||
BAcMCUd1YW5nemhvdTEZMBcGA1UECgwQTG9jYWxob3N0IENsaWVudDEZMBcGA1UE
|
||||
AwwQYW55dHVubmVsLWNsaWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBALBoyM/0i+JxCra8hVMDNs7l8s0xAXImw3+d2UhqtRq5BC0lsyTBpfId5hrF
|
||||
fsUlZaO4ksAqzRN39XCgm4pM3DwR0M5vHqDpQ9IcVZBT+2Yq7THtrAO4a3n4PJ/0
|
||||
DfefWtmpN933rCBsFnPbId4qI6QBxYTto8Wd36LyPa1yGBL5n6sPhQp9UmiFcRYx
|
||||
SSv4tRbMilypHe/YLF2IkUhX+UGRqAZku7g2jisSd5FP1VD0U3OhockyjkKJv5/f
|
||||
TFwfXXliEb1p8uwpL5YFzTy98DDn7Cygdy7cg6zw5cd/gpRNZLNQhC28r4vE8wKg
|
||||
hwmRdy29CKgQMZGxre1cab0lA8ECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZGeU
|
||||
qWRQf66ycYvI7tT8BeKAM++ONWcEkFlflSel3EUq+r2wYzpDZo5qm2kZoE63ibNb
|
||||
Frr2SfH4+RS7RnGQwgzyqrRhFiSKEXOFWUvT7M0eY3fPBZpZjunnyVXXZvchS0Qy
|
||||
s5w391H4td96PiVrqVAFdZmYUM0juexTx+wMYVfZnViJjrPvfaoS8I3RJz1ZNuia
|
||||
nBWMq9gKmLl9KMy05A2EqNMMb8XaooVfigDA53izXDPVS5xhF/0vvGb021+YMzXS
|
||||
qjk7Yrn2JFTm58dp1YBfOAoO566rCXgBhvTxniCnub12cq0m7hjtSKkbOFCPvOvl
|
||||
pMg9UF1tz8uTos/MkQ==
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
client_key_bytes = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAsGjIz/SL4nEKtryFUwM2zuXyzTEBcibDf53ZSGq1GrkELSWz
|
||||
JMGl8h3mGsV+xSVlo7iSwCrNE3f1cKCbikzcPBHQzm8eoOlD0hxVkFP7ZirtMe2s
|
||||
A7hrefg8n/QN959a2ak33fesIGwWc9sh3iojpAHFhO2jxZ3fovI9rXIYEvmfqw+F
|
||||
Cn1SaIVxFjFJK/i1FsyKXKkd79gsXYiRSFf5QZGoBmS7uDaOKxJ3kU/VUPRTc6Gh
|
||||
yTKOQom/n99MXB9deWIRvWny7CkvlgXNPL3wMOfsLKB3LtyDrPDlx3+ClE1ks1CE
|
||||
Lbyvi8TzAqCHCZF3Lb0IqBAxkbGt7VxpvSUDwQIDAQABAoIBAC/criclzVIpo2OC
|
||||
8JVeON+XqfGcCy1icQZN2Gb6dJqEeiqZoOonFBQFoqm+za9FfzcVW9OBiVRv5oqh
|
||||
OLIkOlid6M4pfeDgiQMXputarcnBectjFZmIzrgv7prjR2rYtHh7nem+SdgeG1Vh
|
||||
reWt/y9/P4zaQOXb+JIoMS2+1+NFnYKatpGkVqaiEk6awdwkMpobksvaJbOCszQs
|
||||
QTs8TuPHCraMc+lCUUKwAVu0hTb4AFDvwPumaxbRDmHZn2XoMy/eqWrg0pYhbdtu
|
||||
3o0S8ytsCFW8LHChHkk4krQsDQlgfm+xXhPSDfxSyiGn5OanWRyKxl//QGw6qy9n
|
||||
9YtZlmUCgYEA2OOjj9PeJ0cqbxndoCzCYFZGEy2bzNfQpJC6bB3WnASdlafG/0OO
|
||||
9VGbxYsOO703Q//Id0Exl390UFR5vBdRyoSHJsW+EolwcOm/+szCRKBR1KWP1u/c
|
||||
OJlijN3Z6F6D3H6jOIA5YNec7nRhSfRnVe7ridXrepuWiDIXBaBtZFsCgYEA0Dhz
|
||||
0PwC5R2+6YAXPfQrKZHju7WRUYfc0Uk/7AQHGYpTcokhF2EdN11atMr7447pi1Bu
|
||||
AezAPKwh16mc+byF6rjR+RGyy4KVNlTmH298gkg425+XPTHkODX/IzbOWA/1KKl4
|
||||
rSyYxtgyO7+zoixa7Q5x2s8gFktAOqZdLR/EgxMCgYAt+kvhIJPWlcKMHNqbqwFl
|
||||
tMRUKnX9vb5wNHIgm060clIJuLB5ypOSs8Mm5GyXA2yk0KNpjHt71zwMD2xjEDp5
|
||||
iRCxinfZrCMW/KaC/0crjyTpxFMyyFRR90op/JnGJcskQgBN6PjA69RLxIYfTF1f
|
||||
nS93X870hekqZBv3SGQIQwKBgGR8mgglVxBThqsRkiXoDFyHd6xDN9ptAvhNrXet
|
||||
ie+dfiAsZbfuujbZ6siNnXp4oeUF79El/LBLMhnuVT+A5/AbOdpF3E+yuWf7GQPa
|
||||
ve/yAt6a6lYyGb228WaBMJv3N41kHEUW3LQ56iRDo+GEHm2BJxk+FHIt5tVnLFh2
|
||||
mFPZAoGAC6Qy4DaCDl2ghr1n3ovX1+TRwu+XVGfCFPxGMKeY8Pph6IADN/Zm08gL
|
||||
i2TAKdk+V42rpzqCs7Tp2jCUqSZdgACgckNA9EtOq5ec3JCkvF/8PKNcjmqAGipK
|
||||
5rzS1cyEfXOvuYMVp2bzTiiTI1pMALfjFqPkDCOnN57BSfTvjRo=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
`)
|
||||
root_cert_bytes = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDdzCCAl+gAwIBAgIJANzSq37zesapMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV
|
||||
BAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxFjAUBgNVBAoMDUxvY2FsaG9zdCBM
|
||||
dGQxFzAVBgNVBAMMDkxvY2FsaG9zdCBSb290MB4XDTE3MDkxODA3MTMwNFoXDTI3
|
||||
MDkxNjA3MTMwNFowUjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nRG9uZzEW
|
||||
MBQGA1UECgwNTG9jYWxob3N0IEx0ZDEXMBUGA1UEAwwOTG9jYWxob3N0IFJvb3Qw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+V42izvaDJzkkxyCKrszL
|
||||
QoK7yxTvf7xCyzh+y7wMMWam+IsVzuv7SYv5FYQ8w1lzaoygsKin2+djtlbgvmrv
|
||||
9bEb1YnuwJz39DmtR2j+w3XlZFGUg+qhp7mJEHSe0mOm5hL8vMQmW0Itcd3lR+wh
|
||||
XP9B63NSxiJHVs+6WlY9g3+889w11fUfVECVea6p5JYp4UUN1F/PosUtMURLGcER
|
||||
Q80fw7h+2GnBlIaDbtuZDPEiaGrNIfHHiVJUOaylfQDWFYDjLi2ytM7xfhggRuwt
|
||||
zyo4Xbk+SRTUlloTTRw4zdzuhFQ2qtfhh9gSvVXVpsPNKmkIl3sIkxklRt6vAaWx
|
||||
AgMBAAGjUDBOMB0GA1UdDgQWBBSM7gXj5Rdow6NUI6pE9SYj6tflZTAfBgNVHSME
|
||||
GDAWgBSM7gXj5Rdow6NUI6pE9SYj6tflZTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQB3xR5Z6ksN2nb2JNgjG7hkJjr5jdXwA7LAX8ZYkQ+bGVQMcUO8
|
||||
eYePyXPmSj03a6362Cc/QENY8g+n/i7r22e2/q6BOnsomc4JQumO25ulsMNxi+Ar
|
||||
fDwPg3ixYJFEzlNipcPrr8AOsfJGTh41qQr9cqhk2ciTEOG3Xcfkdp26u9h/D/rm
|
||||
cL4tsSWQ7b1dgoUFLfRvMMRhKUU9ounWiDt+CvMNK1FWV642jKyCE5kEsZ+QHFDW
|
||||
Cc2Xg/3AyG3/8BsKpqtsoI72u6mGsGsyNClwoQTOdMgs3Gert5Q+elp/2NddrOJD
|
||||
hSKTBrKUOEhWpAwPz2DMArggBfM4CAiQbpQ5
|
||||
-----END CERTIFICATE-----
|
||||
`)
|
||||
}
|
||||
func GetServerCert() []byte {
|
||||
return server_cert_bytes
|
||||
}
|
||||
func GetServerKey() []byte {
|
||||
return server_key_bytes
|
||||
}
|
||||
func GetClientCert() []byte {
|
||||
return client_cert_bytes
|
||||
}
|
||||
func GetClientKey() []byte {
|
||||
return client_key_bytes
|
||||
}
|
||||
func GetRootCert() []byte {
|
||||
return root_cert_bytes
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package des
|
||||
|
||||
import (
|
||||
utils "anytunnel/at-common"
|
||||
"bytes"
|
||||
"crypto/des"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
func PKCS5UnPadding(origData []byte) []byte {
|
||||
length := len(origData)
|
||||
unpadding := int(origData[length-1])
|
||||
return origData[:(length - unpadding)]
|
||||
}
|
||||
|
||||
func ZeroPadding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{0}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
func ZeroUnPadding(origData []byte) []byte {
|
||||
return bytes.TrimFunc(origData,
|
||||
func(r rune) bool {
|
||||
return r == rune(0)
|
||||
})
|
||||
}
|
||||
|
||||
func Encrypt(src []byte, key string) (string, error) {
|
||||
block, err := des.NewCipher([]byte(utils.Md5(key)[0:8]))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bs := block.BlockSize()
|
||||
src = ZeroPadding(src, bs)
|
||||
// src = PKCS5Padding(src, bs)
|
||||
if len(src)%bs != 0 {
|
||||
return "", errors.New("Need a multiple of the blocksize")
|
||||
}
|
||||
out := make([]byte, len(src))
|
||||
dst := out
|
||||
for len(src) > 0 {
|
||||
block.Encrypt(dst, src[:bs])
|
||||
src = src[bs:]
|
||||
dst = dst[bs:]
|
||||
}
|
||||
return hex.EncodeToString(out), nil
|
||||
}
|
||||
|
||||
func Decrypt(_src string, _key string) ([]byte, error) {
|
||||
key := []byte(utils.Md5(_key)[0:8])
|
||||
src, err := hex.DecodeString(_src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]byte, len(src))
|
||||
dst := out
|
||||
bs := block.BlockSize()
|
||||
if len(src)%bs != 0 {
|
||||
return nil, errors.New("crypto/cipher: input not full blocks")
|
||||
}
|
||||
for len(src) > 0 {
|
||||
block.Decrypt(dst, src[:bs])
|
||||
src = src[bs:]
|
||||
dst = dst[bs:]
|
||||
}
|
||||
out = ZeroUnPadding(out)
|
||||
// out = PKCS5UnPadding(out)
|
||||
return out, nil
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
const (
|
||||
BASE_64_TABLE = "1234567890poiuytreqwasdfghjklmnbvcxzQWERTYUIOPLKJHGFDSAZXCVBNM-_"
|
||||
)
|
||||
|
||||
type Encrypt struct{}
|
||||
|
||||
func NewEncrypt() *Encrypt {
|
||||
return &Encrypt{}
|
||||
}
|
||||
|
||||
//base64 加密
|
||||
func (encrypt *Encrypt) Base64Encode(str string) string {
|
||||
var coder = base64.NewEncoding(BASE_64_TABLE)
|
||||
var src []byte = []byte(str)
|
||||
return string([]byte(coder.EncodeToString(src)))
|
||||
}
|
||||
|
||||
//base64 加密
|
||||
func (encrypt *Encrypt) Base64EncodeBytes(bytes []byte) []byte {
|
||||
var coder = base64.NewEncoding(BASE_64_TABLE)
|
||||
return []byte(coder.EncodeToString(bytes))
|
||||
}
|
||||
|
||||
//base64 解密
|
||||
func (encrypt *Encrypt) Base64Decode(str string) (string, error) {
|
||||
var src []byte = []byte(str)
|
||||
var coder = base64.NewEncoding(BASE_64_TABLE)
|
||||
by, err := coder.DecodeString(string(src))
|
||||
return string(by), err
|
||||
}
|
||||
|
||||
//base64 解密
|
||||
func (encrypt *Encrypt) Base64DecodeBytes(str string) ([]byte, error) {
|
||||
var coder = base64.NewEncoding(BASE_64_TABLE)
|
||||
return coder.DecodeString(str)
|
||||
}
|
||||
|
||||
//md5加密
|
||||
func (encrypt *Encrypt) Md5Encode(str string) string {
|
||||
hash := md5.New()
|
||||
hash.Write([]byte(str))
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
||||
Executable
+343
@@ -0,0 +1,343 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DES_KEY_HOSTPORT = "3j49d723"
|
||||
)
|
||||
|
||||
//fileGetContents
|
||||
func FileGetContents(file string) (content string, err error) {
|
||||
defer func(err *error) {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
*err = fmt.Errorf("%s", e)
|
||||
}
|
||||
}(&err)
|
||||
bytes, err := ioutil.ReadFile(file)
|
||||
content = string(bytes)
|
||||
return
|
||||
}
|
||||
|
||||
func InArray(val interface{}, array interface{}) (exists bool, index int) {
|
||||
exists = false
|
||||
index = -1
|
||||
|
||||
switch reflect.TypeOf(array).Kind() {
|
||||
case reflect.Slice:
|
||||
s := reflect.ValueOf(array)
|
||||
|
||||
for i := 0; i < s.Len(); i++ {
|
||||
if reflect.DeepEqual(val, s.Index(i).Interface()) == true {
|
||||
index = i
|
||||
exists = true
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
func PathExists(_path string) bool {
|
||||
_, err := os.Stat(_path)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
func IoBind(dst io.ReadWriter, src io.ReadWriter, fn func(err error), cfn func(count int, isPositive bool), bytesPreSec float64) {
|
||||
go func() {
|
||||
errchn := make(chan error, 2)
|
||||
go func() {
|
||||
var err error
|
||||
if bytesPreSec > 0 {
|
||||
newreader := NewReader(src)
|
||||
newreader.SetRateLimit(bytesPreSec)
|
||||
_, err = ioCopy(dst, newreader, func(c int) {
|
||||
cfn(c, false)
|
||||
})
|
||||
|
||||
} else {
|
||||
_, err = ioCopy(dst, src, func(c int) {
|
||||
cfn(c, false)
|
||||
})
|
||||
}
|
||||
|
||||
errchn <- err
|
||||
}()
|
||||
go func() {
|
||||
var err error
|
||||
if bytesPreSec > 0 {
|
||||
newReader := NewReader(dst)
|
||||
newReader.SetRateLimit(bytesPreSec)
|
||||
_, err = ioCopy(src, newReader, func(c int) {
|
||||
cfn(c, true)
|
||||
})
|
||||
} else {
|
||||
_, err = ioCopy(src, dst, func(c int) {
|
||||
cfn(c, true)
|
||||
})
|
||||
}
|
||||
errchn <- err
|
||||
}()
|
||||
fn(<-errchn)
|
||||
}()
|
||||
}
|
||||
func ioCopy(dst io.Writer, src io.Reader, fn ...func(count int)) (written int64, err error) {
|
||||
buf := make([]byte, 32*1024)
|
||||
for {
|
||||
nr, er := src.Read(buf)
|
||||
if nr > 0 {
|
||||
nw, ew := dst.Write(buf[0:nr])
|
||||
if nw > 0 {
|
||||
written += int64(nw)
|
||||
if len(fn) == 1 {
|
||||
fn[0](nw)
|
||||
}
|
||||
}
|
||||
if ew != nil {
|
||||
err = ew
|
||||
break
|
||||
}
|
||||
if nr != nw {
|
||||
err = io.ErrShortWrite
|
||||
break
|
||||
}
|
||||
}
|
||||
if er != nil {
|
||||
err = er
|
||||
break
|
||||
}
|
||||
}
|
||||
return written, err
|
||||
}
|
||||
func TlsConnectHost(host string, timeout int) (conn tls.Conn, err error) {
|
||||
h := strings.Split(host, ":")
|
||||
port, _ := strconv.Atoi(h[1])
|
||||
return TlsConnect(h[0], port, timeout)
|
||||
}
|
||||
|
||||
func TlsConnect(host string, port, timeout int) (conn tls.Conn, err error) {
|
||||
conf, err := getRequestTlsConfig(true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), time.Duration(timeout)*time.Millisecond)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return *tls.Client(_conn, conf), err
|
||||
}
|
||||
func getRequestTlsConfig(isInternal bool) (conf *tls.Config, err error) {
|
||||
if isInternal {
|
||||
var cert tls.Certificate
|
||||
cert, err = tls.X509KeyPair(GetClientCert(), GetClientKey())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serverCertPool := x509.NewCertPool()
|
||||
ok := serverCertPool.AppendCertsFromPEM(GetRootCert())
|
||||
if !ok {
|
||||
err = errors.New("failed to parse root certificate")
|
||||
}
|
||||
conf = &tls.Config{
|
||||
RootCAs: serverCertPool,
|
||||
Certificates: []tls.Certificate{cert},
|
||||
ServerName: "anytunnel-server",
|
||||
InsecureSkipVerify: false,
|
||||
}
|
||||
} else {
|
||||
conf = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
func Connect(host string, port, timeout int) (conn net.Conn, err error) {
|
||||
conn, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), time.Duration(timeout)*time.Millisecond)
|
||||
return
|
||||
}
|
||||
func ConnectHost(hostAndPort string, timeout int) (conn net.Conn, err error) {
|
||||
conn, err = net.DialTimeout("tcp", hostAndPort, time.Duration(timeout)*time.Millisecond)
|
||||
return
|
||||
}
|
||||
func ListenTls(ip string, port int) (ln *net.Listener, err error) {
|
||||
var cert tls.Certificate
|
||||
cert, err = tls.X509KeyPair(GetServerCert(), GetServerKey())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
clientCertPool := x509.NewCertPool()
|
||||
ok := clientCertPool.AppendCertsFromPEM(GetRootCert())
|
||||
if !ok {
|
||||
err = errors.New("failed to parse root certificate")
|
||||
}
|
||||
config := &tls.Config{
|
||||
ClientCAs: clientCertPool,
|
||||
ServerName: "anytunnel-client",
|
||||
Certificates: []tls.Certificate{cert},
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
}
|
||||
_ln, err := tls.Listen("tcp", fmt.Sprintf("%s:%d", ip, port), config)
|
||||
if err == nil {
|
||||
ln = &_ln
|
||||
}
|
||||
return
|
||||
}
|
||||
func Response(channel *MessageChannel, success bool, msg string) (err error) {
|
||||
status := STATUS_FAIL
|
||||
if success {
|
||||
status = STATUS_SUCCESS
|
||||
}
|
||||
resp := MsgResponse{
|
||||
Msg: Msg{MsgType: MSG_RESPONSE},
|
||||
Status: status,
|
||||
Message: msg,
|
||||
}
|
||||
err = channel.Write(resp)
|
||||
return
|
||||
}
|
||||
func GetClusterHost(url, token, typ string) (addr string, err error) {
|
||||
if url == "" {
|
||||
err = fmt.Errorf("url is empty")
|
||||
return
|
||||
}
|
||||
if strings.Contains(url, "?") {
|
||||
url += fmt.Sprintf("&token=%s&type=%s", token, typ)
|
||||
} else {
|
||||
url += fmt.Sprintf("?token=%s&type=%s", token, typ)
|
||||
}
|
||||
d, code, err := HttpGet(url)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if code != 200 {
|
||||
err = fmt.Errorf(string(d))
|
||||
return
|
||||
}
|
||||
addr = string(d)
|
||||
return
|
||||
}
|
||||
func GetAllInterfaceAddr() ([]net.IP, error) {
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addresses := []net.IP{}
|
||||
for _, iface := range ifaces {
|
||||
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue // interface down
|
||||
}
|
||||
// if iface.Flags&net.FlagLoopback != 0 {
|
||||
// continue // loopback interface
|
||||
// }
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
// if ip == nil || ip.IsLoopback() {
|
||||
// continue
|
||||
// }
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue // not an ipv4 address
|
||||
}
|
||||
addresses = append(addresses, ip)
|
||||
}
|
||||
}
|
||||
if len(addresses) == 0 {
|
||||
return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses)
|
||||
}
|
||||
//only need first
|
||||
return addresses, nil
|
||||
}
|
||||
|
||||
var allChina = strings.Split("北京,海淀,东城,西城,宣武,丰台,朝阳,崇文,大兴,石景山,门头沟,房山,通州,顺义,怀柔,昌平,平谷,密云县,延庆县,天津,和平,河西,河北,河东,南开,红桥,北辰,津南,武清,塘沽,西青,汉沽,大港,宝坻,东丽,蓟县,静海县,宁河县,上海,黄浦,卢湾,徐汇,长宁,静安,普陀,闸北,杨浦,虹口,闵行,宝山,嘉定,浦东新,金山,松江,青浦,南汇,奉贤,崇明县,重庆,渝中,大渡口,江北,沙坪坝,九龙坡,南岸,北碚,万盛,双桥,渝北,巴南,万州,涪陵,黔江,长寿,江津,永川,南川,綦江县,潼南县,铜梁县,大足县,荣昌县,璧山县,垫江县,武隆县,丰都县,城口县,梁平县,开县,巫溪县,巫山县,奉节县,云阳县,忠县,石柱土家族,彭水苗族土家族,酉阳苗族,秀山土家族苗族,新疆维吾尔,乌鲁木齐,克拉玛依,石河子,阿拉尔,图木舒克,五家渠,哈密,吐鲁番,阿克苏,喀什,和田,伊宁,塔城,阿勒泰,奎屯,博乐,昌吉,阜康,库尔勒,阿图什,乌苏,西藏,拉萨,日喀则,宁夏回族,银川,石嘴山,吴忠,固原,中卫,青,铜峡,灵武,内蒙古,呼和浩特,包头,乌海,赤峰,通辽,鄂尔多斯,呼伦贝尔,巴彦淖尔,乌兰察布,霍林郭勒,满洲里,牙克石,扎兰屯,根河,额尔古纳,丰镇,锡林浩特,二连浩特,乌兰浩特,阿尔山,广西壮族,南宁,柳州,桂林,梧州,北海,崇左,来宾,贺州,玉林,百色,河池,钦州,防城港,贵港,岑溪,凭祥,合山,北流,宜州,东兴,桂平,黑龙江,哈尔滨,大庆,齐齐哈尔,佳木斯,鸡西,鹤岗,双鸭山,牡丹江,伊春,七台河,黑河,绥化,五常,双城,尚志,纳河,虎林,密山,铁力,同江,富锦,绥芬河,海林,宁安,穆林,北安,五大连池,肇东,海伦,安达,长春,吉林,四平,辽源,通化,白山,松原,白城,九台,榆树,德惠,舒兰,桦甸,蛟河,磐石,公主岭,双辽,梅河口,集安,临江,大安,洮南,延吉,图们,敦化,龙井,珲春,和龙,辽宁,沈阳,大连,鞍山,抚顺,本溪,丹东,锦州,营口,阜新,辽阳,盘锦,铁岭,朝阳,葫芦岛,新民,瓦房店,普兰,庄河,海城,东港,凤城,凌海,北镇,大石桥,盖州,灯塔,调兵山,开原,凌源,北票,兴城,河北,石家庄,唐山,邯郸,秦皇岛,保定,张家口,承德,廊坊,沧州,衡水,邢台,辛集,藁城,晋州,新乐,鹿泉,遵化,迁安,武安,南宫,沙河,涿州,定州,安国,高碑店,泊头,任丘,黄骅,河间,霸州,三河,冀州,深州,山东,济南,青岛,淄博,枣庄,东营,烟台,潍坊,济宁,泰安,威海,日照,莱芜,临沂,德州,聊城,菏泽,滨州,章丘,胶南,胶州,平度,莱西,即墨,滕州,龙口,莱阳,莱州,招远,蓬莱,栖霞,海阳,青州,诸城,安丘,高密,昌邑,兖州,曲阜,邹城,乳山,文登,荣成,乐陵,临清,禹城,江苏,南京,镇江,常州,无锡,苏州,徐州,连云港,淮安,盐城,扬州,泰州,南通,宿迁,江阴,宜兴,邳州,新沂,金坛,溧阳,常熟,张家港,太仓,昆山,吴江,如皋,通州,海门,启东,东台,大丰,高邮,江都,仪征,丹阳,扬中,句容,泰兴,姜堰,靖江,兴化,安徽,合肥,蚌埠,芜湖,淮南,亳州,阜阳,淮北,宿州,滁州,安庆,巢湖,马鞍山,宣城,黄山,池州,铜陵,界首,天长,明光,桐城,宁国,浙江,杭州,嘉兴,湖州,宁波,金华,温州,丽水,绍兴,衢州,舟山,台州,建德,富阳,临安,余姚,慈溪,奉化,瑞安,乐清,海宁,平湖,桐乡,诸暨,上虞,嵊州,兰溪,义乌,东阳,永康,江山,临海,温岭,龙泉,福建,福州,厦门,泉州,三明,南平,漳州,莆田,宁德,龙岩,福清,长乐,永安,石狮,晋江,南安,龙海,邵武,武夷山,建瓯,建阳,漳平,福安,福鼎,广东,广州,深圳,汕头,惠州,珠海,揭阳,佛山,河源,阳江,茂名,湛江,梅州,肇庆,韶关,潮州,东莞,中山,清远,江门,汕尾,云浮,增城,从化,乐昌,南雄,台山,开平,鹤山,恩平,廉江,雷州,吴川,高州,化州,高要,四会,兴宁,陆丰,阳春,英德,连州,普宁,罗定,海南,海口,三亚,琼海,文昌,万宁,五指山,儋州,东方,云南,昆明,曲靖,玉溪,保山,昭通,丽江,普洱,临沧,安宁,宣威,个旧,开远,景洪,楚雄,大理,潞西,瑞丽,贵州,贵阳,六盘水,遵义,安顺,清镇,赤水,仁怀,铜仁,毕节,兴义,凯里,都匀,福泉,四川,成都,绵阳,德阳,广元,自贡,攀枝花,乐山,南充,内江,遂宁,广安,泸州,达州,眉山,宜宾,雅安,资阳,都江堰,彭州,邛崃,崇州,广汉,什邡,绵竹,江油,峨眉山,阆中,华蓥,万源,简阳,西昌,湖南,长沙,株洲,湘潭,衡阳,岳阳,郴州,永州,邵阳,怀化,常德,益阳,张家界,娄底,浏阳,醴陵,湘乡,韶山,耒阳,常宁,武冈,临湘,汨罗津,沅江,资兴,洪江,冷水江,涟源,吉首,湖北,武汉,襄樊,宜昌,黄石,鄂州,随州,荆州,荆门,十堰,孝感,黄冈,咸宁,大冶,丹江口,洪湖,石首,松滋,宜都,当阳,枝江,老河口,枣阳,宜城,钟祥,应城,安陆,汉川,麻城,武穴,赤壁,广水,仙桃,天门,潜江,恩施,利川,河南,郑州,洛阳,开封,漯河,安阳,新乡,周口,三门峡,焦作,平顶山,信阳,南阳,鹤壁,濮阳,许昌,商丘,驻马店,巩义,新郑,新密,登封,荥阳,偃师,汝州,舞钢,林州,卫辉,辉县,沁阳,孟州,禹州,长葛,义马,灵宝,邓州,永城,项城,济源,山西,太原,大同,忻州,阳泉,长治,晋城,朔州,晋中,运城,临汾,吕梁,古交,潞城,高平,介休,永济,河津,原平,侯马,霍州,孝义,汾阳,陕西,西安,咸阳,铜川,延安,宝鸡,渭南,汉中,安康,商洛,榆林,兴平,韩城,华阴,甘肃,兰州,天水,平凉,酒泉,嘉峪关,金昌,白银,武威,张掖,庆阳,定西,陇南,玉门,敦煌,临夏,合作,青海,西宁,格尔木,德令哈,江西,南昌,九江,赣州,吉安,鹰潭,上饶,萍乡,景德镇,新余,宜春,抚州,乐平,瑞昌,贵溪,瑞金,南康,井冈山,丰城,樟树,高安,德兴", ",")
|
||||
|
||||
func IsChina(country string) bool {
|
||||
for _, v := range allChina {
|
||||
if strings.HasPrefix(country, v) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//md5加密
|
||||
func Md5(str string) string {
|
||||
hash := md5.New()
|
||||
hash.Write([]byte(str))
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
||||
func UDPPacket(srcAddr string, packet []byte) []byte {
|
||||
addrBytes := []byte(srcAddr)
|
||||
addrLength := uint16(len(addrBytes))
|
||||
bodyLength := uint16(len(packet))
|
||||
pkg := new(bytes.Buffer)
|
||||
binary.Write(pkg, binary.LittleEndian, addrLength)
|
||||
binary.Write(pkg, binary.LittleEndian, addrBytes)
|
||||
binary.Write(pkg, binary.LittleEndian, bodyLength)
|
||||
binary.Write(pkg, binary.LittleEndian, packet)
|
||||
return pkg.Bytes()
|
||||
}
|
||||
func ReadUDPPacket(conn *tls.Conn) (srcAddr string, packet []byte, err error) {
|
||||
reader := bufio.NewReader(conn)
|
||||
var addrLength uint16
|
||||
var bodyLength uint16
|
||||
err = binary.Read(reader, binary.LittleEndian, &addrLength)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_srcAddr := make([]byte, addrLength)
|
||||
n, err := reader.Read(_srcAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != int(addrLength) {
|
||||
return
|
||||
}
|
||||
srcAddr = string(_srcAddr)
|
||||
|
||||
err = binary.Read(reader, binary.LittleEndian, &bodyLength)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
packet = make([]byte, bodyLength)
|
||||
n, err = reader.Read(packet)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n != int(bodyLength) {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func HttpGetNotInternal(URL string) (body []byte, code int, err error) {
|
||||
return _HttpGet(URL, false)
|
||||
}
|
||||
func HttpPostNotInternal(URL string, data map[string]string, header map[string]string) (body []byte, code int, err error) {
|
||||
return _HttpPost(URL, data, header, false)
|
||||
}
|
||||
func HttpPost(URL string, data map[string]string, header map[string]string) (body []byte, code int, err error) {
|
||||
return _HttpPost(URL, data, header, true)
|
||||
}
|
||||
func HttpGet(URL string) (body []byte, code int, err error) {
|
||||
return _HttpGet(URL, true)
|
||||
}
|
||||
func _HttpGet(URL string, isInternal bool) (body []byte, code int, err error) {
|
||||
client, tr, err := getRequestClient(URL, isInternal)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp, err := client.Get(URL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer tr.CloseIdleConnections()
|
||||
code = resp.StatusCode
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
return
|
||||
}
|
||||
func _HttpPost(URL string, data map[string]string, header map[string]string, isInternal bool) (body []byte, code int, err error) {
|
||||
postParamsString := ""
|
||||
if data != nil {
|
||||
postParams := []string{}
|
||||
for k, v := range data {
|
||||
postParams = append(postParams, url.QueryEscape(k)+"="+url.QueryEscape(v))
|
||||
}
|
||||
postParamsString = strings.Join(postParams, "&")
|
||||
}
|
||||
return HttpPostRaw(URL, postParamsString, header, isInternal)
|
||||
}
|
||||
|
||||
func HttpPostRaw(URL, postParamsString string, header map[string]string, isInternal bool) (body []byte, code int, err error) {
|
||||
var resp *http.Response
|
||||
var client *http.Client
|
||||
var tr *http.Transport
|
||||
defer func() {
|
||||
if resp != nil && resp.Body != nil {
|
||||
resp.Body.Close()
|
||||
}
|
||||
if tr != nil {
|
||||
tr.CloseIdleConnections()
|
||||
}
|
||||
}()
|
||||
req, err := http.NewRequest("POST", URL, strings.NewReader(postParamsString))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
client, tr, err = getRequestClient(URL, isInternal)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if header != nil {
|
||||
for k, v := range header {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
body, err = ioutil.ReadAll(resp.Body)
|
||||
code = resp.StatusCode
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getRequestClient(url string, isInternal bool) (client *http.Client, tr *http.Transport, err error) {
|
||||
var conf *tls.Config
|
||||
conf, err = getRequestTlsConfig(isInternal)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if strings.Contains(url, "https://") {
|
||||
tr = &http.Transport{TLSClientConfig: conf}
|
||||
client = &http.Client{Timeout: time.Second * 5, Transport: tr}
|
||||
} else {
|
||||
tr = &http.Transport{}
|
||||
client = &http.Client{Timeout: time.Second * 5, Transport: tr}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func UrlArgs(url, args string) string {
|
||||
if strings.Contains(url, "?") {
|
||||
return url + "&" + args
|
||||
}
|
||||
return url + "?" + args
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNotInternal(t *testing.T) {
|
||||
for {
|
||||
fmt.Println(rand.Uint64() / 10000)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
func TestOpenPort(t *testing.T) {
|
||||
// /port/open/:TunnelID/:ServerToken/:ServerBindIP/:ServerListenPort
|
||||
// /:ClientToken/:ClientLocalHost/:ClientLocalPort/:Protocol/:BytesPerSec
|
||||
body, code, err := HttpGet("https://127.0.0.1:37080/port/open/3/guest/0.0.0.0/20090/guest_client/8.8.8.8/53/2/102400")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClosePort(t *testing.T) {
|
||||
// /port/close/:TunnelID
|
||||
body, code, err := HttpGet("https://127.0.0.1:37080/port/close/3")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusPort(t *testing.T) {
|
||||
// /port/close/:TunnelID
|
||||
body, code, err := HttpGet("https://127.0.0.1:37080/port/status/1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
func TestTrafficCount(t *testing.T) {
|
||||
// /traffic/count
|
||||
body, code, err := HttpGet("https://127.0.0.1:37080/traffic/count")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrafficCountTunnel(t *testing.T) {
|
||||
// /traffic/count/:TunnelID
|
||||
body, code, err := HttpGet("https://127.0.0.1:37080/traffic/count/1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
func TestServerOffline(t *testing.T) {
|
||||
// /server/offline/:ServerToken
|
||||
body, code, err := HttpGet("https://127.0.0.1:37080/server/offline/guest")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
func TestClientOffline(t *testing.T) {
|
||||
// /server/offline/:ClientToken
|
||||
body, code, err := HttpGet("https://127.0.0.1:37080/client/offline/guest_client")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsAdd(t *testing.T) {
|
||||
|
||||
values := map[string]string{
|
||||
"server_ip": "127.0.0.1",
|
||||
"server_token": "akdhkajhdkashdksdhk",
|
||||
"client_ip": "124.176.89.90",
|
||||
"client_token": "akhdkahdah",
|
||||
"cluster_ip": "34.67.78.89",
|
||||
"comment": "djadjllajd",
|
||||
}
|
||||
body, _, err := HttpPost("https://127.0.0.1:37081/cs/add", values, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsUpdate(t *testing.T) {
|
||||
|
||||
values := map[string]string{
|
||||
"cs_id": "2",
|
||||
"server_ip": "127.0.0.1",
|
||||
"server_token": "akdhkajhdkashdksdhk",
|
||||
"client_ip": "124.176.89.90",
|
||||
"client_token": "tokentoken",
|
||||
"cluster_ip": "34.67.78.89",
|
||||
"comment": "djadjllajd",
|
||||
}
|
||||
body, _, err := HttpPost("https://127.0.0.1:37081/cs/update", values, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsList(t *testing.T) {
|
||||
//body, err := HttpGet("https://127.0.0.1:37081/cs/list")
|
||||
body, _, err := HttpGet("https://127.0.0.1:37081/cs/list?keyword=tokentoken")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsDelete(t *testing.T) {
|
||||
body, _, err := HttpGet("https://127.0.0.1:37081/cs/delete?cs_id=1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCsGetCsByCsId(t *testing.T) {
|
||||
|
||||
body, _, err := HttpGet("https://127.0.0.1:37081/cs/getCsByCsId?cs_id=1")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClusterReport(t *testing.T) {
|
||||
|
||||
values := map[string]string{
|
||||
"sys_conn_number": "1312",
|
||||
"tunnel_conn_number": "3443",
|
||||
"bandwidth": "1232",
|
||||
}
|
||||
body, code, err := HttpPost("https://127.0.0.1:37081/cluster/report", values, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
func TestCSAuth(t *testing.T) {
|
||||
|
||||
body, code, err := HttpGet("https://127.0.0.1:37081/cs/auth?token=guest&type=server")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
func TestCSOnlineOffline(t *testing.T) {
|
||||
|
||||
body, code, err := HttpGet("https://127.0.0.1:37081/cs/status?token=guest_client&type=client&action=offline")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserTraffic(t *testing.T) {
|
||||
data := `{"1":{"positive":32300100,"negative":5324},"2":{"negative":3997696,"positive":0},"3":{"positive":3231,"negative":5324}}`
|
||||
body, code, err := HttpPostRaw("https://127.0.0.1:37081/user/traffic", data, nil, true)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCSCluster(t *testing.T) {
|
||||
body, code, err := HttpGet("https://127.0.0.1:29531/cluster/get?token=guest&type=server")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
b := string(body)
|
||||
fmt.Println(code)
|
||||
fmt.Println(b)
|
||||
}
|
||||
}
|
||||
|
||||
type ClusterTunnel struct {
|
||||
TunnelID uint64
|
||||
ServerToken string
|
||||
ServerBindIP string
|
||||
ServerListenPort int
|
||||
ClientToken string
|
||||
ClientLocalHost string
|
||||
ClientLocalPort int
|
||||
Protocol int
|
||||
BytesPerSec float64
|
||||
}
|
||||
|
||||
func Test(t *testing.T) {
|
||||
_, code, err := HttpGet("https://127.0.0.1:37080/port/open/2/guest/0.0.0.0/20080/guest_client/127.0.0.1/80/1/102400")
|
||||
fmt.Println(code, err)
|
||||
}
|
||||
func getMyInterfaceAddr() ([]net.IP, error) {
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addresses := []net.IP{}
|
||||
for _, iface := range ifaces {
|
||||
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue // interface down
|
||||
}
|
||||
if iface.Flags&net.FlagLoopback != 0 {
|
||||
continue // loopback interface
|
||||
}
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
if ip == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue // not an ipv4 address
|
||||
}
|
||||
addresses = append(addresses, ip)
|
||||
}
|
||||
}
|
||||
if len(addresses) == 0 {
|
||||
return nil, fmt.Errorf("no address Found, net.InterfaceAddrs: %v", addresses)
|
||||
}
|
||||
//only need first
|
||||
return addresses, nil
|
||||
}
|
||||
func TestReadTimeout(t *testing.T) {
|
||||
conn, err := TlsConnect("127.0.0.1", 29531, 3000)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
byt := make([]byte, 1)
|
||||
_, err := conn.Read(byt)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
const burstLimit = 1000 * 1000 * 1000
|
||||
|
||||
type Reader struct {
|
||||
r io.Reader
|
||||
limiter *rate.Limiter
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
type Writer struct {
|
||||
w io.Writer
|
||||
limiter *rate.Limiter
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// NewReader returns a reader that implements io.Reader with rate limiting.
|
||||
func NewReader(r io.Reader) *Reader {
|
||||
return &Reader{
|
||||
r: r,
|
||||
ctx: context.Background(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewReaderWithContext returns a reader that implements io.Reader with rate limiting.
|
||||
func NewReaderWithContext(r io.Reader, ctx context.Context) *Reader {
|
||||
return &Reader{
|
||||
r: r,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// NewWriter returns a writer that implements io.Writer with rate limiting.
|
||||
func NewWriter(w io.Writer) *Writer {
|
||||
return &Writer{
|
||||
w: w,
|
||||
ctx: context.Background(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewWriterWithContext returns a writer that implements io.Writer with rate limiting.
|
||||
func NewWriterWithContext(w io.Writer, ctx context.Context) *Writer {
|
||||
return &Writer{
|
||||
w: w,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
// SetRateLimit sets rate limit (bytes/sec) to the reader.
|
||||
func (s *Reader) SetRateLimit(bytesPerSec float64) {
|
||||
s.limiter = rate.NewLimiter(rate.Limit(bytesPerSec), burstLimit)
|
||||
s.limiter.AllowN(time.Now(), burstLimit) // spend initial burst
|
||||
}
|
||||
|
||||
// Read reads bytes into p.
|
||||
func (s *Reader) Read(p []byte) (int, error) {
|
||||
if s.limiter == nil {
|
||||
return s.r.Read(p)
|
||||
}
|
||||
n, err := s.r.Read(p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if err := s.limiter.WaitN(s.ctx, n); err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// SetRateLimit sets rate limit (bytes/sec) to the writer.
|
||||
func (s *Writer) SetRateLimit(bytesPerSec float64) {
|
||||
s.limiter = rate.NewLimiter(rate.Limit(bytesPerSec), burstLimit)
|
||||
s.limiter.AllowN(time.Now(), burstLimit) // spend initial burst
|
||||
}
|
||||
|
||||
// Write writes bytes from p.
|
||||
func (s *Writer) Write(p []byte) (int, error) {
|
||||
if s.limiter == nil {
|
||||
return s.w.Write(p)
|
||||
}
|
||||
n, err := s.w.Write(p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if err := s.limiter.WaitN(s.ctx, n); err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var SHARD_COUNT = 32
|
||||
|
||||
// A "thread" safe map of type string:Anything.
|
||||
// To avoid lock bottlenecks this map is dived to several (SHARD_COUNT) map shards.
|
||||
type ConcurrentMap []*ConcurrentMapShared
|
||||
|
||||
// A "thread" safe string to anything map.
|
||||
type ConcurrentMapShared struct {
|
||||
items map[string]interface{}
|
||||
sync.RWMutex // Read Write mutex, guards access to internal map.
|
||||
}
|
||||
|
||||
// Creates a new concurrent map.
|
||||
func NewConcurrentMap() ConcurrentMap {
|
||||
m := make(ConcurrentMap, SHARD_COUNT)
|
||||
for i := 0; i < SHARD_COUNT; i++ {
|
||||
m[i] = &ConcurrentMapShared{items: make(map[string]interface{})}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// Returns shard under given key
|
||||
func (m ConcurrentMap) GetShard(key string) *ConcurrentMapShared {
|
||||
return m[uint(fnv32(key))%uint(SHARD_COUNT)]
|
||||
}
|
||||
|
||||
func (m ConcurrentMap) MSet(data map[string]interface{}) {
|
||||
for key, value := range data {
|
||||
shard := m.GetShard(key)
|
||||
shard.Lock()
|
||||
shard.items[key] = value
|
||||
shard.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the given value under the specified key.
|
||||
func (m ConcurrentMap) Set(key string, value interface{}) {
|
||||
// Get map shard.
|
||||
shard := m.GetShard(key)
|
||||
shard.Lock()
|
||||
shard.items[key] = value
|
||||
shard.Unlock()
|
||||
}
|
||||
|
||||
// Callback to return new element to be inserted into the map
|
||||
// It is called while lock is held, therefore it MUST NOT
|
||||
// try to access other keys in same map, as it can lead to deadlock since
|
||||
// Go sync.RWLock is not reentrant
|
||||
type UpsertCb func(exist bool, valueInMap interface{}, newValue interface{}) interface{}
|
||||
|
||||
// Insert or Update - updates existing element or inserts a new one using UpsertCb
|
||||
func (m ConcurrentMap) Upsert(key string, value interface{}, cb UpsertCb) (res interface{}) {
|
||||
shard := m.GetShard(key)
|
||||
shard.Lock()
|
||||
v, ok := shard.items[key]
|
||||
res = cb(ok, v, value)
|
||||
shard.items[key] = res
|
||||
shard.Unlock()
|
||||
return res
|
||||
}
|
||||
|
||||
// Sets the given value under the specified key if no value was associated with it.
|
||||
func (m ConcurrentMap) SetIfAbsent(key string, value interface{}) bool {
|
||||
// Get map shard.
|
||||
shard := m.GetShard(key)
|
||||
shard.Lock()
|
||||
_, ok := shard.items[key]
|
||||
if !ok {
|
||||
shard.items[key] = value
|
||||
}
|
||||
shard.Unlock()
|
||||
return !ok
|
||||
}
|
||||
|
||||
// Retrieves an element from map under given key.
|
||||
func (m ConcurrentMap) Get(key string) (interface{}, bool) {
|
||||
// Get shard
|
||||
shard := m.GetShard(key)
|
||||
shard.RLock()
|
||||
// Get item from shard.
|
||||
val, ok := shard.items[key]
|
||||
shard.RUnlock()
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// Returns the number of elements within the map.
|
||||
func (m ConcurrentMap) Count() int {
|
||||
count := 0
|
||||
for i := 0; i < SHARD_COUNT; i++ {
|
||||
shard := m[i]
|
||||
shard.RLock()
|
||||
count += len(shard.items)
|
||||
shard.RUnlock()
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// Looks up an item under specified key
|
||||
func (m ConcurrentMap) Has(key string) bool {
|
||||
// Get shard
|
||||
shard := m.GetShard(key)
|
||||
shard.RLock()
|
||||
// See if element is within shard.
|
||||
_, ok := shard.items[key]
|
||||
shard.RUnlock()
|
||||
return ok
|
||||
}
|
||||
|
||||
// Removes an element from the map.
|
||||
func (m ConcurrentMap) Remove(key string) {
|
||||
// Try to get shard.
|
||||
shard := m.GetShard(key)
|
||||
shard.Lock()
|
||||
delete(shard.items, key)
|
||||
shard.Unlock()
|
||||
}
|
||||
|
||||
// Removes an element from the map and returns it
|
||||
func (m ConcurrentMap) Pop(key string) (v interface{}, exists bool) {
|
||||
// Try to get shard.
|
||||
shard := m.GetShard(key)
|
||||
shard.Lock()
|
||||
v, exists = shard.items[key]
|
||||
delete(shard.items, key)
|
||||
shard.Unlock()
|
||||
return v, exists
|
||||
}
|
||||
|
||||
// Checks if map is empty.
|
||||
func (m ConcurrentMap) IsEmpty() bool {
|
||||
return m.Count() == 0
|
||||
}
|
||||
|
||||
// Used by the Iter & IterBuffered functions to wrap two variables together over a channel,
|
||||
type Tuple struct {
|
||||
Key string
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
// Returns an iterator which could be used in a for range loop.
|
||||
//
|
||||
// Deprecated: using IterBuffered() will get a better performence
|
||||
func (m ConcurrentMap) Iter() <-chan Tuple {
|
||||
chans := snapshot(m)
|
||||
ch := make(chan Tuple)
|
||||
go fanIn(chans, ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
// Returns a buffered iterator which could be used in a for range loop.
|
||||
func (m ConcurrentMap) IterBuffered() <-chan Tuple {
|
||||
chans := snapshot(m)
|
||||
total := 0
|
||||
for _, c := range chans {
|
||||
total += cap(c)
|
||||
}
|
||||
ch := make(chan Tuple, total)
|
||||
go fanIn(chans, ch)
|
||||
return ch
|
||||
}
|
||||
|
||||
// Returns a array of channels that contains elements in each shard,
|
||||
// which likely takes a snapshot of `m`.
|
||||
// It returns once the size of each buffered channel is determined,
|
||||
// before all the channels are populated using goroutines.
|
||||
func snapshot(m ConcurrentMap) (chans []chan Tuple) {
|
||||
chans = make([]chan Tuple, SHARD_COUNT)
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(SHARD_COUNT)
|
||||
// Foreach shard.
|
||||
for index, shard := range m {
|
||||
go func(index int, shard *ConcurrentMapShared) {
|
||||
// Foreach key, value pair.
|
||||
shard.RLock()
|
||||
chans[index] = make(chan Tuple, len(shard.items))
|
||||
wg.Done()
|
||||
for key, val := range shard.items {
|
||||
chans[index] <- Tuple{key, val}
|
||||
}
|
||||
shard.RUnlock()
|
||||
close(chans[index])
|
||||
}(index, shard)
|
||||
}
|
||||
wg.Wait()
|
||||
return chans
|
||||
}
|
||||
|
||||
// fanIn reads elements from channels `chans` into channel `out`
|
||||
func fanIn(chans []chan Tuple, out chan Tuple) {
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(len(chans))
|
||||
for _, ch := range chans {
|
||||
go func(ch chan Tuple) {
|
||||
for t := range ch {
|
||||
out <- t
|
||||
}
|
||||
wg.Done()
|
||||
}(ch)
|
||||
}
|
||||
wg.Wait()
|
||||
close(out)
|
||||
}
|
||||
|
||||
// Returns all items as map[string]interface{}
|
||||
func (m ConcurrentMap) Items() map[string]interface{} {
|
||||
tmp := make(map[string]interface{})
|
||||
|
||||
// Insert items to temporary map.
|
||||
for item := range m.IterBuffered() {
|
||||
tmp[item.Key] = item.Val
|
||||
}
|
||||
|
||||
return tmp
|
||||
}
|
||||
|
||||
// Iterator callback,called for every key,value found in
|
||||
// maps. RLock is held for all calls for a given shard
|
||||
// therefore callback sess consistent view of a shard,
|
||||
// but not across the shards
|
||||
type IterCb func(key string, v interface{})
|
||||
|
||||
// Callback based iterator, cheapest way to read
|
||||
// all elements in a map.
|
||||
func (m ConcurrentMap) IterCb(fn IterCb) {
|
||||
for idx := range m {
|
||||
shard := (m)[idx]
|
||||
shard.RLock()
|
||||
for key, value := range shard.items {
|
||||
fn(key, value)
|
||||
}
|
||||
shard.RUnlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Return all keys as []string
|
||||
func (m ConcurrentMap) Keys() []string {
|
||||
count := m.Count()
|
||||
ch := make(chan string, count)
|
||||
go func() {
|
||||
// Foreach shard.
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(SHARD_COUNT)
|
||||
for _, shard := range m {
|
||||
go func(shard *ConcurrentMapShared) {
|
||||
// Foreach key, value pair.
|
||||
shard.RLock()
|
||||
for key := range shard.items {
|
||||
ch <- key
|
||||
}
|
||||
shard.RUnlock()
|
||||
wg.Done()
|
||||
}(shard)
|
||||
}
|
||||
wg.Wait()
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
// Generate keys
|
||||
keys := make([]string, 0, count)
|
||||
for k := range ch {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
//Reviles ConcurrentMap "private" variables to json marshal.
|
||||
func (m ConcurrentMap) MarshalJSON() ([]byte, error) {
|
||||
// Create a temporary map, which will hold all item spread across shards.
|
||||
tmp := make(map[string]interface{})
|
||||
|
||||
// Insert items to temporary map.
|
||||
for item := range m.IterBuffered() {
|
||||
tmp[item.Key] = item.Val
|
||||
}
|
||||
return json.Marshal(tmp)
|
||||
}
|
||||
|
||||
func fnv32(key string) uint32 {
|
||||
hash := uint32(2166136261)
|
||||
const prime32 = uint32(16777619)
|
||||
for i := 0; i < len(key); i++ {
|
||||
hash *= prime32
|
||||
hash ^= uint32(key[i])
|
||||
}
|
||||
return hash
|
||||
}
|
||||
|
||||
// Concurrent map uses Interface{} as its value, therefor JSON Unmarshal
|
||||
// will probably won't know which to type to unmarshal into, in such case
|
||||
// we'll end up with a value of type map[string]interface{}, In most cases this isn't
|
||||
// out value type, this is why we've decided to remove this functionality.
|
||||
|
||||
// func (m *ConcurrentMap) UnmarshalJSON(b []byte) (err error) {
|
||||
// // Reverse process of Marshal.
|
||||
|
||||
// tmp := make(map[string]interface{})
|
||||
|
||||
// // Unmarshal into a single map.
|
||||
// if err := json.Unmarshal(b, &tmp); err != nil {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// // foreach key,value pair in temporary map insert into our concurrent map.
|
||||
// for key, val := range tmp {
|
||||
// m.Set(key, val)
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
@@ -0,0 +1,315 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Msg struct {
|
||||
MsgType int
|
||||
}
|
||||
type message struct {
|
||||
Type int
|
||||
Data interface{}
|
||||
}
|
||||
|
||||
type msgErrorHandler func(channel *MessageChannel, rawMsg interface{}, err error)
|
||||
type msgCallback func(channel *MessageChannel, msg interface{})
|
||||
type closeCallback func(channel *MessageChannel, isPeerClose bool)
|
||||
|
||||
type MessageChannel struct {
|
||||
reader *bufio.Reader
|
||||
writer *bufio.Writer
|
||||
msgHandler map[int][]msgCallback
|
||||
msgErrorHandler msgErrorHandler
|
||||
msgTypeMap map[int]interface{}
|
||||
readlock *sync.Mutex
|
||||
writelock *sync.Mutex
|
||||
readHandler func(msg message)
|
||||
serveStared bool
|
||||
ConnectionID uint64
|
||||
Conn *net.Conn
|
||||
remoteAddr net.Addr
|
||||
localAddr net.Addr
|
||||
}
|
||||
|
||||
func NewMessageChannel(conn *net.Conn) MessageChannel {
|
||||
ch := MessageChannel{
|
||||
Conn: conn,
|
||||
remoteAddr: (*conn).RemoteAddr(),
|
||||
localAddr: (*conn).LocalAddr(),
|
||||
reader: bufio.NewReader(*conn),
|
||||
writer: bufio.NewWriter(*conn),
|
||||
msgTypeMap: map[int]interface{}{},
|
||||
readlock: &sync.Mutex{},
|
||||
writelock: &sync.Mutex{},
|
||||
ConnectionID: rand.Uint64(),
|
||||
msgErrorHandler: func(channel *MessageChannel, rawMsg interface{}, err error) {},
|
||||
msgHandler: map[int][]msgCallback{},
|
||||
}
|
||||
ch.RegMsg(MSG_TYPE_PING, new(MsgPing), func(channel *MessageChannel, msg interface{}) {
|
||||
msgPing := msg.(*MsgPing)
|
||||
channel.Pong(msgPing.ID)
|
||||
return
|
||||
})
|
||||
return ch
|
||||
}
|
||||
func NewMessageChannelTls(conn *tls.Conn) MessageChannel {
|
||||
con := net.Conn(conn)
|
||||
return NewMessageChannel(&con)
|
||||
}
|
||||
|
||||
func (mc *MessageChannel) CloseConn() (err error) {
|
||||
(*mc.Conn).SetDeadline(time.Now().Add(time.Millisecond))
|
||||
return (*mc.Conn).Close()
|
||||
}
|
||||
|
||||
func (mc *MessageChannel) RegMsg(msgType int, msg interface{}, fn msgCallback, fns ...msgCallback) {
|
||||
mc.msgTypeMap[msgType] = msg
|
||||
mc.msgHandler[msgType] = append(fns, fn)
|
||||
}
|
||||
func (mc *MessageChannel) SetMsgErrorHandler(fn func(channel *MessageChannel, rawMsg interface{}, err error)) {
|
||||
mc.msgErrorHandler = fn
|
||||
}
|
||||
func (mc *MessageChannel) encode(data interface{}) (msg []byte, err error) {
|
||||
var message []byte
|
||||
message, err = json.Marshal(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 读取消息的长度
|
||||
var length int32 = int32(len(message))
|
||||
var pkg *bytes.Buffer = new(bytes.Buffer)
|
||||
// 写入消息头
|
||||
err = binary.Write(pkg, binary.LittleEndian, length)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 写入消息实体
|
||||
err = binary.Write(pkg, binary.LittleEndian, message)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return pkg.Bytes(), nil
|
||||
}
|
||||
func (mc *MessageChannel) Write(msg interface{}) (err error) {
|
||||
defer mc.writelock.Unlock()
|
||||
mc.writelock.Lock()
|
||||
if reflect.TypeOf(msg).Kind().String() != "struct" {
|
||||
err = fmt.Errorf("error : message must be a struct , send to %s", mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
if _, ok := reflect.TypeOf(msg).FieldByName("MsgType"); !ok {
|
||||
err = fmt.Errorf("error : message must be has MsgType field , send to %s", mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
if reflect.ValueOf(msg).FieldByName("MsgType").Int() <= 0 {
|
||||
err = fmt.Errorf("error : message's MsgType field must be great than 0, send to %s", mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
v := reflect.ValueOf(msg).FieldByName("MsgType").Int()
|
||||
pack := message{
|
||||
Type: int(v),
|
||||
Data: msg,
|
||||
}
|
||||
var msgData []byte
|
||||
msgData, err = mc.encode(pack)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("encode message error : %s , to : %s", err, mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
_, err = mc.writer.Write(msgData)
|
||||
|
||||
if err != nil {
|
||||
err = fmt.Errorf("write messasge fail to %s , ERR : %s", mc.remoteAddr, err)
|
||||
return
|
||||
}
|
||||
err = mc.writer.Flush()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("flush messasge fail %s , ERR : %s", mc.remoteAddr, err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
func (mc *MessageChannel) ReadTimeout(msg interface{}, timeout int) (err error) {
|
||||
if !mc.serveStared {
|
||||
err = fmt.Errorf("DoServe() must be called before call Read(),From : %s", mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
type M struct {
|
||||
Err error
|
||||
Msg interface{}
|
||||
}
|
||||
msgChn := make(chan M, 1)
|
||||
mc.readHandler = func(rawMsg message) {
|
||||
_, err = mc.toStruct(rawMsg.Data, &msg)
|
||||
msgChn <- M{
|
||||
Msg: msg,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
m := M{}
|
||||
if timeout > 0 {
|
||||
select {
|
||||
case m = <-msgChn:
|
||||
msg = m.Msg
|
||||
err = m.Err
|
||||
case <-time.After(time.Duration(timeout) * time.Millisecond):
|
||||
err = fmt.Errorf("read channel message timeout from %s", mc.remoteAddr)
|
||||
}
|
||||
} else {
|
||||
m = <-msgChn
|
||||
msg = m.Msg
|
||||
err = m.Err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (mc *MessageChannel) Read(msg interface{}) (err error) {
|
||||
return mc.ReadTimeout(msg, 0)
|
||||
}
|
||||
|
||||
func (mc *MessageChannel) read() (msg message, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
(*mc.Conn).Close()
|
||||
}
|
||||
mc.readlock.Unlock()
|
||||
}()
|
||||
mc.readlock.Lock()
|
||||
// 读取消息的长度
|
||||
lengthByte, err := mc.reader.Peek(4)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read message length error : %s , from %s", err, mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
lengthBuff := bytes.NewBuffer(lengthByte)
|
||||
var length int32
|
||||
err = binary.Read(lengthBuff, binary.LittleEndian, &length)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read message error : %s , from %s", err, mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
if int32(mc.reader.Buffered()) < length+4 {
|
||||
err = fmt.Errorf("message data length error from %s", mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
// 读取消息真正的内容
|
||||
pack := make([]byte, int(4+length))
|
||||
_, err = mc.reader.Read(pack)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("read message error : %s , from %s", err, mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(pack[4:], &msg)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unmarshal message error : %s , from %s", err, mc.remoteAddr)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
func (mc *MessageChannel) DoServe(errfn func(err error)) {
|
||||
mc.serveStared = true
|
||||
go func() {
|
||||
var err error
|
||||
var msg message
|
||||
for {
|
||||
msg, err = mc.read()
|
||||
if err != nil {
|
||||
go errfn(err)
|
||||
mc.serveStared = false
|
||||
return
|
||||
}
|
||||
if mc.readHandler != nil {
|
||||
go mc.readHandler(msg)
|
||||
mc.readHandler = nil
|
||||
continue
|
||||
}
|
||||
|
||||
h, ok := mc.msgHandler[msg.Type]
|
||||
var data interface{}
|
||||
|
||||
if ok {
|
||||
data, err = mc.parse(msg)
|
||||
} else {
|
||||
err = fmt.Errorf("msg handler not found , msgType:%d", msg.Type)
|
||||
}
|
||||
if err != nil {
|
||||
go mc.msgErrorHandler(mc, msg.Data, err)
|
||||
} else {
|
||||
for i := len(h) - 1; i >= 0; i-- {
|
||||
go h[i](mc, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
func (mc *MessageChannel) Ping() (id string, err error) {
|
||||
id = randStr(32)
|
||||
ping := MsgPing{
|
||||
Msg: Msg{MsgType: MSG_TYPE_PING},
|
||||
ID: id,
|
||||
}
|
||||
err = mc.Write(ping)
|
||||
return
|
||||
}
|
||||
func (mc *MessageChannel) Pong(id string) (err error) {
|
||||
pong := MsgPong{
|
||||
Msg: Msg{MsgType: MSG_TYPE_PONG},
|
||||
ID: id,
|
||||
}
|
||||
err = mc.Write(pong)
|
||||
return
|
||||
}
|
||||
|
||||
func (mc *MessageChannel) RemoteAddr() net.Addr {
|
||||
return mc.remoteAddr
|
||||
}
|
||||
func (mc *MessageChannel) LocalAddr() net.Addr {
|
||||
return mc.localAddr
|
||||
}
|
||||
|
||||
func (mc *MessageChannel) parse(msg message) (data interface{}, err error) {
|
||||
data, ok := mc.msgTypeMap[msg.Type]
|
||||
if !ok {
|
||||
err = fmt.Errorf("message type not registed")
|
||||
return
|
||||
}
|
||||
mbytes, err := json.Marshal(msg.Data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(mbytes, data)
|
||||
return
|
||||
}
|
||||
func (mc *MessageChannel) toStruct(msg, struc interface{}) (data interface{}, err error) {
|
||||
mbytes, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(mbytes, &struc)
|
||||
data = struc
|
||||
return
|
||||
}
|
||||
|
||||
func randStr(strlen int) string {
|
||||
codes := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
codeLen := len(codes)
|
||||
data := make([]byte, strlen)
|
||||
rand.Seed(time.Now().UnixNano() + rand.Int63() + rand.Int63() + rand.Int63() + rand.Int63())
|
||||
for i := 0; i < strlen; i++ {
|
||||
idx := rand.Intn(codeLen)
|
||||
data[i] = byte(codes[idx])
|
||||
}
|
||||
return string(data)
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
nONE = iota
|
||||
TUNNEL_PROTOCOL_TCP
|
||||
TUNNEL_PROTOCOL_UDP
|
||||
CSTYPE_SERVER
|
||||
CSTYPE_CLIENT
|
||||
MSG_CLIENT_OPEN_CONNECTION
|
||||
MSG_SERVER_OPEN_PORT
|
||||
MSG_SERVER_CLOSE_PORT
|
||||
MSG_SERVER_STATUS_PORT
|
||||
MSG_RESPONSE
|
||||
STATUS_SUCCESS
|
||||
STATUS_FAIL
|
||||
MSG_TYPE_LOGIN
|
||||
MSG_TYPE_PING
|
||||
MSG_TYPE_PONG
|
||||
CS_CLIENT uint8 = 1
|
||||
CS_SERVER uint8 = 2
|
||||
)
|
||||
|
||||
type MsgPing struct {
|
||||
Msg
|
||||
ID string
|
||||
}
|
||||
type MsgPong struct {
|
||||
Msg
|
||||
ID string
|
||||
}
|
||||
|
||||
type MsgClientOpenConnection struct {
|
||||
Msg
|
||||
TunnelID uint64
|
||||
ConnectinID uint64
|
||||
LocalHost string
|
||||
LocalPort int
|
||||
Protocol int
|
||||
}
|
||||
|
||||
type MsgServerOpenPort struct {
|
||||
Msg
|
||||
TunnelID uint64
|
||||
BindPort int
|
||||
BindIP string
|
||||
Protocol int
|
||||
}
|
||||
|
||||
func (m *MsgServerOpenPort) ProtocolString() string {
|
||||
return GetProtocolString(m.Protocol)
|
||||
}
|
||||
|
||||
type MsgServerClosePort struct {
|
||||
Msg
|
||||
TunnelID uint64
|
||||
Protocol int
|
||||
}
|
||||
type MsgServerStatusPort struct {
|
||||
Msg
|
||||
TunnelID uint64
|
||||
Protocol int
|
||||
}
|
||||
type MsgLogin struct {
|
||||
Msg
|
||||
Token string
|
||||
CSType int
|
||||
}
|
||||
|
||||
func (m *MsgLogin) IsServer() bool {
|
||||
return m.CSType == CSTYPE_SERVER
|
||||
}
|
||||
func (m *MsgLogin) IsClient() bool {
|
||||
return m.CSType == CSTYPE_CLIENT
|
||||
}
|
||||
func (m *MsgLogin) CSTypeString() string {
|
||||
return GetCSTypeString(m.CSType)
|
||||
}
|
||||
|
||||
type MsgResponse struct {
|
||||
Msg
|
||||
Status int
|
||||
Message string
|
||||
}
|
||||
|
||||
func (m *MsgResponse) IsSuccess() bool {
|
||||
return m.Status == STATUS_SUCCESS
|
||||
}
|
||||
|
||||
func Encode(data interface{}) (msg []byte, err error) {
|
||||
var message []byte
|
||||
message, err = json.Marshal(data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 读取消息的长度
|
||||
var length int32 = int32(len(message))
|
||||
var pkg *bytes.Buffer = new(bytes.Buffer)
|
||||
// 写入消息头
|
||||
err = binary.Write(pkg, binary.LittleEndian, length)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// 写入消息实体
|
||||
err = binary.Write(pkg, binary.LittleEndian, message)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return pkg.Bytes(), nil
|
||||
}
|
||||
|
||||
func Decode(reader *bufio.Reader) (msg message, err error) {
|
||||
// 读取消息的长度
|
||||
lengthByte, _ := reader.Peek(4)
|
||||
lengthBuff := bytes.NewBuffer(lengthByte)
|
||||
var length int32
|
||||
err = binary.Read(lengthBuff, binary.LittleEndian, &length)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if int32(reader.Buffered()) < length+4 {
|
||||
err = errors.New("data length error")
|
||||
return
|
||||
}
|
||||
// 读取消息真正的内容
|
||||
pack := make([]byte, int(4+length))
|
||||
_, err = reader.Read(pack)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var _msg message
|
||||
err = json.Unmarshal(pack[4:], &_msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return _msg, nil
|
||||
}
|
||||
func GetCSTypeString(cstype int) string {
|
||||
switch cstype {
|
||||
case CSTYPE_CLIENT:
|
||||
return "CLIENT"
|
||||
case CSTYPE_SERVER:
|
||||
return "SERVER"
|
||||
}
|
||||
return "UNKONWN_CSTYPE"
|
||||
}
|
||||
func GetProtocolString(protocol int) string {
|
||||
switch protocol {
|
||||
case TUNNEL_PROTOCOL_UDP:
|
||||
return "udp"
|
||||
case TUNNEL_PROTOCOL_TCP:
|
||||
return "tcp"
|
||||
}
|
||||
return "UNKONWN_PROTOCOL"
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package qqwry
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
)
|
||||
|
||||
// qqwry.LoadData("data/qqwry.dat")
|
||||
// rs := qqwry.Find("32.30.50.128")
|
||||
// log.Println(rs)
|
||||
|
||||
const (
|
||||
// IndexLen 索引长度
|
||||
IndexLen = 7
|
||||
// RedirectMode1 国家的类型, 指向另一个指向
|
||||
RedirectMode1 = 0x01
|
||||
// RedirectMode2 国家的类型, 指向一个指向
|
||||
RedirectMode2 = 0x02
|
||||
)
|
||||
|
||||
// ResultQQwry 归属地信息
|
||||
type ResultQQwry struct {
|
||||
IP string `json:"ip"`
|
||||
Country string `json:"country"`
|
||||
Area string `json:"area"`
|
||||
}
|
||||
|
||||
type fileData struct {
|
||||
Data []byte
|
||||
FilePath string
|
||||
Path *os.File
|
||||
IPNum int64
|
||||
}
|
||||
|
||||
// QQwry 纯真ip库
|
||||
type QQwry struct {
|
||||
Data *fileData
|
||||
Offset int64
|
||||
}
|
||||
|
||||
func LoadData(datFile string) {
|
||||
IPData.FilePath = datFile
|
||||
startTime := time.Now().UnixNano()
|
||||
res := IPData.InitIPData()
|
||||
if v, ok := res.(error); ok {
|
||||
log.Panic(v)
|
||||
}
|
||||
endTime := time.Now().UnixNano()
|
||||
log.Printf("IP 库加载完成 共加载:%d 条 IP 记录, 所花时间:%.1f ms\n", IPData.IPNum, float64(endTime-startTime)/1000000)
|
||||
}
|
||||
|
||||
// IPData IP库的数据
|
||||
var IPData fileData
|
||||
var q = NewQQwry()
|
||||
|
||||
func Find(ip string) (res ResultQQwry) {
|
||||
return q.Find(ip)
|
||||
}
|
||||
func FindIPs(ips []string) (rs map[string]ResultQQwry) {
|
||||
return q.FindIPs(ips)
|
||||
}
|
||||
|
||||
// InitIPData 初始化ip库数据到内存中
|
||||
func (f *fileData) InitIPData() (rs interface{}) {
|
||||
|
||||
// 判断文件是否存在
|
||||
_, err := os.Stat(f.FilePath)
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
rs = errors.New("文件不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 打开文件句柄
|
||||
f.Path, err = os.OpenFile(f.FilePath, os.O_RDONLY, 0400)
|
||||
if err != nil {
|
||||
rs = err
|
||||
return
|
||||
}
|
||||
defer f.Path.Close()
|
||||
|
||||
tmpData, err := ioutil.ReadAll(f.Path)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
rs = err
|
||||
return
|
||||
}
|
||||
|
||||
f.Data = tmpData
|
||||
|
||||
buf := f.Data[0:8]
|
||||
start := binary.LittleEndian.Uint32(buf[:4])
|
||||
end := binary.LittleEndian.Uint32(buf[4:])
|
||||
|
||||
f.IPNum = int64((end-start)/IndexLen + 1)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// NewQQwry 新建 qqwry 类型
|
||||
func NewQQwry() QQwry {
|
||||
return QQwry{
|
||||
Data: &IPData,
|
||||
}
|
||||
}
|
||||
|
||||
// ReadData 从文件中读取数据
|
||||
func (q *QQwry) ReadData(num int, offset ...int64) (rs []byte) {
|
||||
if len(offset) > 0 {
|
||||
q.SetOffset(offset[0])
|
||||
}
|
||||
nums := int64(num)
|
||||
end := q.Offset + nums
|
||||
dataNum := int64(len(q.Data.Data))
|
||||
if q.Offset > dataNum {
|
||||
return nil
|
||||
}
|
||||
|
||||
if end > dataNum {
|
||||
end = dataNum
|
||||
}
|
||||
rs = q.Data.Data[q.Offset:end]
|
||||
q.Offset = end
|
||||
return
|
||||
}
|
||||
|
||||
// SetOffset 设置偏移量
|
||||
func (q *QQwry) SetOffset(offset int64) {
|
||||
q.Offset = offset
|
||||
}
|
||||
func (q *QQwry) FindIPs(ips []string) (rs map[string]ResultQQwry) {
|
||||
rs = map[string]ResultQQwry{}
|
||||
if len(ips) > 0 {
|
||||
for _, v := range ips {
|
||||
rs[v] = q.Find(v)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Find ip地址查询对应归属地信息
|
||||
func (q *QQwry) Find(ip string) (res ResultQQwry) {
|
||||
|
||||
res = ResultQQwry{}
|
||||
|
||||
res.IP = ip
|
||||
if strings.Count(ip, ".") != 3 {
|
||||
return res
|
||||
}
|
||||
offset := q.searchIndex(binary.BigEndian.Uint32(net.ParseIP(ip).To4()))
|
||||
if offset <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var country []byte
|
||||
var area []byte
|
||||
|
||||
mode := q.readMode(offset + 4)
|
||||
if mode == RedirectMode1 {
|
||||
countryOffset := q.readUInt24()
|
||||
mode = q.readMode(countryOffset)
|
||||
if mode == RedirectMode2 {
|
||||
c := q.readUInt24()
|
||||
country = q.readString(c)
|
||||
countryOffset += 4
|
||||
} else {
|
||||
country = q.readString(countryOffset)
|
||||
countryOffset += uint32(len(country) + 1)
|
||||
}
|
||||
area = q.readArea(countryOffset)
|
||||
} else if mode == RedirectMode2 {
|
||||
countryOffset := q.readUInt24()
|
||||
country = q.readString(countryOffset)
|
||||
area = q.readArea(offset + 8)
|
||||
} else {
|
||||
country = q.readString(offset + 4)
|
||||
area = q.readArea(offset + uint32(5+len(country)))
|
||||
}
|
||||
|
||||
enc := simplifiedchinese.GBK.NewDecoder()
|
||||
res.Country, _ = enc.String(string(country))
|
||||
res.Area, _ = enc.String(string(area))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// readMode 获取偏移值类型
|
||||
func (q *QQwry) readMode(offset uint32) byte {
|
||||
mode := q.ReadData(1, int64(offset))
|
||||
return mode[0]
|
||||
}
|
||||
|
||||
// readArea 读取区域
|
||||
func (q *QQwry) readArea(offset uint32) []byte {
|
||||
mode := q.readMode(offset)
|
||||
if mode == RedirectMode1 || mode == RedirectMode2 {
|
||||
areaOffset := q.readUInt24()
|
||||
if areaOffset == 0 {
|
||||
return []byte("")
|
||||
}
|
||||
return q.readString(areaOffset)
|
||||
}
|
||||
return q.readString(offset)
|
||||
}
|
||||
|
||||
// readString 获取字符串
|
||||
func (q *QQwry) readString(offset uint32) []byte {
|
||||
q.SetOffset(int64(offset))
|
||||
data := make([]byte, 0, 30)
|
||||
buf := make([]byte, 1)
|
||||
for {
|
||||
buf = q.ReadData(1)
|
||||
if buf[0] == 0 {
|
||||
break
|
||||
}
|
||||
data = append(data, buf[0])
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// searchIndex 查找索引位置
|
||||
func (q *QQwry) searchIndex(ip uint32) uint32 {
|
||||
header := q.ReadData(8, 0)
|
||||
|
||||
start := binary.LittleEndian.Uint32(header[:4])
|
||||
end := binary.LittleEndian.Uint32(header[4:])
|
||||
|
||||
buf := make([]byte, IndexLen)
|
||||
mid := uint32(0)
|
||||
_ip := uint32(0)
|
||||
|
||||
for {
|
||||
mid = q.getMiddleOffset(start, end)
|
||||
buf = q.ReadData(IndexLen, int64(mid))
|
||||
_ip = binary.LittleEndian.Uint32(buf[:4])
|
||||
|
||||
if end-start == IndexLen {
|
||||
offset := byteToUInt32(buf[4:])
|
||||
buf = q.ReadData(IndexLen)
|
||||
if ip < binary.LittleEndian.Uint32(buf[:4]) {
|
||||
return offset
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// 找到的比较大,向前移
|
||||
if _ip > ip {
|
||||
end = mid
|
||||
} else if _ip < ip { // 找到的比较小,向后移
|
||||
start = mid
|
||||
} else if _ip == ip {
|
||||
return byteToUInt32(buf[4:])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// readUInt24
|
||||
func (q *QQwry) readUInt24() uint32 {
|
||||
buf := q.ReadData(3)
|
||||
return byteToUInt32(buf)
|
||||
}
|
||||
|
||||
// getMiddleOffset
|
||||
func (q *QQwry) getMiddleOffset(start uint32, end uint32) uint32 {
|
||||
records := ((end - start) / IndexLen) >> 1
|
||||
return start + records*IndexLen
|
||||
}
|
||||
|
||||
// byteToUInt32 将 byte 转换为uint32
|
||||
func byteToUInt32(data []byte) uint32 {
|
||||
i := uint32(data[0]) & 0xff
|
||||
i |= (uint32(data[1]) << 8) & 0xff00
|
||||
i |= (uint32(data[2]) << 16) & 0xff0000
|
||||
return i
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package qqwry
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/yinheli/mahonia"
|
||||
// "encoding/hex"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
// q := qqwry.NewQQwry("data/qqwry.dat")
|
||||
// q.Find("103.30.50.128")
|
||||
// log.Println(q.Country, q.City, q.Ip)
|
||||
const (
|
||||
INDEX_LEN = 7
|
||||
REDIRECT_MODE_1 = 0x01
|
||||
REDIRECT_MODE_2 = 0x02
|
||||
)
|
||||
|
||||
// @author yinheli
|
||||
type QQwry struct {
|
||||
Ip string
|
||||
Country string
|
||||
City string
|
||||
filepath string
|
||||
file *os.File
|
||||
}
|
||||
|
||||
func NewQQwry(file string) (qqwry *QQwry) {
|
||||
qqwry = &QQwry{filepath: file}
|
||||
return
|
||||
}
|
||||
|
||||
func (this *QQwry) Find(ip string) {
|
||||
if this.filepath == "" {
|
||||
return
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(this.filepath, os.O_RDONLY, 0400)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
this.file = file
|
||||
|
||||
this.Ip = ip
|
||||
offset := this.searchIndex(binary.BigEndian.Uint32(net.ParseIP(ip).To4()))
|
||||
// log.Println("loc offset:", offset)
|
||||
if offset <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var country []byte
|
||||
var area []byte
|
||||
|
||||
mode := this.readMode(offset + 4)
|
||||
// log.Println("mode", mode)
|
||||
if mode == REDIRECT_MODE_1 {
|
||||
countryOffset := this.readUInt24()
|
||||
mode = this.readMode(countryOffset)
|
||||
// log.Println("1 - mode", mode)
|
||||
if mode == REDIRECT_MODE_2 {
|
||||
c := this.readUInt24()
|
||||
country = this.readString(c)
|
||||
countryOffset += 4
|
||||
} else {
|
||||
country = this.readString(countryOffset)
|
||||
countryOffset += uint32(len(country) + 1)
|
||||
}
|
||||
area = this.readArea(countryOffset)
|
||||
} else if mode == REDIRECT_MODE_2 {
|
||||
countryOffset := this.readUInt24()
|
||||
country = this.readString(countryOffset)
|
||||
area = this.readArea(offset + 8)
|
||||
} else {
|
||||
country = this.readString(offset + 4)
|
||||
area = this.readArea(offset + uint32(5+len(country)))
|
||||
}
|
||||
|
||||
enc := mahonia.NewDecoder("gbk")
|
||||
this.Country = enc.ConvertString(string(country))
|
||||
this.City = enc.ConvertString(string(area))
|
||||
|
||||
}
|
||||
|
||||
func (this *QQwry) readMode(offset uint32) byte {
|
||||
this.file.Seek(int64(offset), 0)
|
||||
mode := make([]byte, 1)
|
||||
this.file.Read(mode)
|
||||
return mode[0]
|
||||
}
|
||||
|
||||
func (this *QQwry) readArea(offset uint32) []byte {
|
||||
mode := this.readMode(offset)
|
||||
if mode == REDIRECT_MODE_1 || mode == REDIRECT_MODE_2 {
|
||||
areaOffset := this.readUInt24()
|
||||
if areaOffset == 0 {
|
||||
return []byte("")
|
||||
} else {
|
||||
return this.readString(areaOffset)
|
||||
}
|
||||
} else {
|
||||
return this.readString(offset)
|
||||
}
|
||||
return []byte("")
|
||||
}
|
||||
|
||||
func (this *QQwry) readString(offset uint32) []byte {
|
||||
this.file.Seek(int64(offset), 0)
|
||||
data := make([]byte, 0, 30)
|
||||
buf := make([]byte, 1)
|
||||
for {
|
||||
this.file.Read(buf)
|
||||
if buf[0] == 0 {
|
||||
break
|
||||
}
|
||||
data = append(data, buf[0])
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (this *QQwry) searchIndex(ip uint32) uint32 {
|
||||
header := make([]byte, 8)
|
||||
this.file.Seek(0, 0)
|
||||
this.file.Read(header)
|
||||
|
||||
start := binary.LittleEndian.Uint32(header[:4])
|
||||
end := binary.LittleEndian.Uint32(header[4:])
|
||||
|
||||
// log.Printf("len info %v, %v ---- %v, %v", start, end, hex.EncodeToString(header[:4]), hex.EncodeToString(header[4:]))
|
||||
|
||||
for {
|
||||
mid := this.getMiddleOffset(start, end)
|
||||
this.file.Seek(int64(mid), 0)
|
||||
buf := make([]byte, INDEX_LEN)
|
||||
this.file.Read(buf)
|
||||
_ip := binary.LittleEndian.Uint32(buf[:4])
|
||||
|
||||
// log.Printf(">> %v, %v, %v -- %v", start, mid, end, hex.EncodeToString(buf[:4]))
|
||||
|
||||
if end-start == INDEX_LEN {
|
||||
offset := byte3ToUInt32(buf[4:])
|
||||
this.file.Read(buf)
|
||||
if ip < binary.LittleEndian.Uint32(buf[:4]) {
|
||||
return offset
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// 找到的比较大,向前移
|
||||
if _ip > ip {
|
||||
end = mid
|
||||
} else if _ip < ip { // 找到的比较小,向后移
|
||||
start = mid
|
||||
} else if _ip == ip {
|
||||
return byte3ToUInt32(buf[4:])
|
||||
}
|
||||
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (this *QQwry) readUInt24() uint32 {
|
||||
buf := make([]byte, 3)
|
||||
this.file.Read(buf)
|
||||
return byte3ToUInt32(buf)
|
||||
}
|
||||
|
||||
func (this *QQwry) getMiddleOffset(start uint32, end uint32) uint32 {
|
||||
records := ((end - start) / INDEX_LEN) >> 1
|
||||
return start + records*INDEX_LEN
|
||||
}
|
||||
|
||||
func byte3ToUInt32(data []byte) uint32 {
|
||||
i := uint32(data[0]) & 0xff
|
||||
i |= (uint32(data[1]) << 8) & 0xff00
|
||||
i |= (uint32(data[2]) << 16) & 0xff0000
|
||||
return i
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package at_common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
type ServerChannel struct {
|
||||
ip string
|
||||
port int
|
||||
Listener *net.Listener
|
||||
UDPListener *net.UDPConn
|
||||
errAcceptHandler func(err error)
|
||||
}
|
||||
|
||||
func NewServerChannel(ip string, port int) ServerChannel {
|
||||
return ServerChannel{
|
||||
ip: ip,
|
||||
port: port,
|
||||
errAcceptHandler: func(err error) {
|
||||
fmt.Printf("accept error , ERR:%s", err)
|
||||
},
|
||||
}
|
||||
}
|
||||
func (sc *ServerChannel) SetErrAcceptHandler(fn func(err error)) {
|
||||
sc.errAcceptHandler = fn
|
||||
}
|
||||
func (sc *ServerChannel) ListenTls(fn func(channel MessageChannel, conn net.Conn)) (err error) {
|
||||
sc.Listener, err = ListenTls(sc.ip, sc.port)
|
||||
if err == nil {
|
||||
go func() {
|
||||
for {
|
||||
var conn net.Conn
|
||||
conn, err = (*sc.Listener).Accept()
|
||||
if err == nil {
|
||||
go func() {
|
||||
fn(NewMessageChannel(&conn), conn)
|
||||
}()
|
||||
} else {
|
||||
sc.errAcceptHandler(err)
|
||||
(*sc.Listener).Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (sc *ServerChannel) ListenTCP(fn func(channel MessageChannel, conn net.Conn)) (err error) {
|
||||
l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", sc.ip, sc.port))
|
||||
if err == nil {
|
||||
sc.Listener = &l
|
||||
go func() {
|
||||
for {
|
||||
var conn net.Conn
|
||||
conn, err = (*sc.Listener).Accept()
|
||||
if err == nil {
|
||||
go func() {
|
||||
fn(NewMessageChannel(&conn), conn)
|
||||
}()
|
||||
} else {
|
||||
sc.errAcceptHandler(err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
return
|
||||
}
|
||||
func (sc *ServerChannel) ListenUDP(fn func(packet []byte, localAddr, srcAddr *net.UDPAddr)) (err error) {
|
||||
addr := &net.UDPAddr{IP: net.ParseIP(sc.ip), Port: sc.port}
|
||||
l, err := net.ListenUDP("udp", addr)
|
||||
if err == nil {
|
||||
sc.UDPListener = l
|
||||
go func() {
|
||||
for {
|
||||
var buf = make([]byte, 2048)
|
||||
n, srcAddr, err := (*sc.UDPListener).ReadFromUDP(buf)
|
||||
if err == nil {
|
||||
packet := buf[0:n]
|
||||
go func() {
|
||||
fn(packet, addr, srcAddr)
|
||||
}()
|
||||
} else {
|
||||
sc.errAcceptHandler(err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package at_common
|
||||
|
||||
type TrafficTotal struct {
|
||||
Tunnels int `json="tunnels"`
|
||||
Servers int `json="servers"`
|
||||
Clients int `json="clinets"`
|
||||
UploadBytes uint64 `json="uploadBytes"`
|
||||
DownloadBytes uint64 `json="downloadBytes"`
|
||||
TotalBytes uint64 `json="totalBytes"`
|
||||
Connections int `json="connections"`
|
||||
}
|
||||
type TrafficStatistics struct {
|
||||
Total TrafficTotal `json="total"`
|
||||
Traffic map[string]map[string]uint64 `json="traffic"`
|
||||
}
|
||||
Reference in New Issue
Block a user