Initial commit
This commit is contained in:
commit
b8f8e5607c
22
admin.log
Normal file
22
admin.log
Normal file
@ -0,0 +1,22 @@
|
||||
2025/12/22 13:39:35 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:39:36 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:41:40 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:41:40 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:41:48 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:41:48 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:42:36 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:42:36 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:43:14 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:43:14 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:43:38 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:43:38 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:45:28 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:45:28 ADMIN AUTH_MISSING ip=192.168.31.108:63121
|
||||
2025/12/22 13:50:59 ADMIN ADD domain=api.phone.local ip=192.168.31.108:63731
|
||||
2025/12/22 20:26:42 ADMIN ADD domain=photo.phone.local ip=192.168.31.108:57258
|
||||
2025/12/22 20:34:20 ADMIN ADD domain=api.phone.key ip=192.168.31.108:57431
|
||||
2025/12/22 20:34:36 ADMIN DELETE domain=api.phone.key ip=192.168.31.108:57431
|
||||
2025/12/22 20:34:42 ADMIN ADD domain=api.phone.local ip=192.168.31.108:57431
|
||||
2025/12/22 20:35:10 ADMIN ADD domain=photo.phone.local ip=192.168.31.108:57431
|
||||
2025/12/23 13:11:21 ADMIN ADD domain=api.phone.local ip=192.168.31.108:51617
|
||||
2025/12/23 13:16:27 ADMIN ADD domain=api.phone.key ip=192.168.31.108:51942
|
||||
127
admin/admin.html
Normal file
127
admin/admin.html
Normal file
@ -0,0 +1,127 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Relay Admin Panel</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
max-width: 600px;
|
||||
margin: 40px auto;
|
||||
}
|
||||
h1 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
input, button {
|
||||
padding: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
li {
|
||||
margin: 6px 0;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Relay Admin Panel</h1>
|
||||
|
||||
<label>
|
||||
API Key:
|
||||
<input id="apiKey" type="password" style="width: 100%" />
|
||||
</label>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>Registered domains</h3>
|
||||
<button onclick="loadDomains()">Refresh</button>
|
||||
<ul id="domains"></ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>Add domain</h3>
|
||||
<input id="newDomain" placeholder="example.phone.local" />
|
||||
<button onclick="addDomain()">Add</button>
|
||||
|
||||
<p id="status" class="error"></p>
|
||||
|
||||
<script>
|
||||
const apiBase = "/domains";
|
||||
|
||||
function headers() {
|
||||
return {
|
||||
"apikey": document.getElementById("apiKey").value
|
||||
};
|
||||
}
|
||||
|
||||
async function loadDomains() {
|
||||
const res = await fetch(apiBase, { headers: headers() });
|
||||
if (!res.ok) {
|
||||
showError(res);
|
||||
return;
|
||||
}
|
||||
|
||||
const text = await res.text();
|
||||
const list = document.getElementById("domains");
|
||||
list.innerHTML = "";
|
||||
|
||||
text.trim().split("\n").forEach(domain => {
|
||||
if (!domain) return;
|
||||
|
||||
const li = document.createElement("li");
|
||||
li.textContent = domain + " ";
|
||||
|
||||
const btn = document.createElement("button");
|
||||
btn.textContent = "Delete";
|
||||
btn.onclick = () => deleteDomain(domain);
|
||||
|
||||
li.appendChild(btn);
|
||||
list.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
async function addDomain() {
|
||||
const domain = document.getElementById("newDomain").value;
|
||||
if (!domain) return;
|
||||
|
||||
const res = await fetch(`${apiBase}?domain=${encodeURIComponent(domain)}`, {
|
||||
method: "POST",
|
||||
headers: headers()
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
showError(res);
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById("newDomain").value = "";
|
||||
loadDomains();
|
||||
}
|
||||
|
||||
async function deleteDomain(domain) {
|
||||
const res = await fetch(`${apiBase}?domain=${encodeURIComponent(domain)}`, {
|
||||
method: "DELETE",
|
||||
headers: headers()
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
showError(res);
|
||||
return;
|
||||
}
|
||||
|
||||
loadDomains();
|
||||
}
|
||||
|
||||
function showError(res) {
|
||||
document.getElementById("status").textContent =
|
||||
`Error: ${res.status} ${res.statusText}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
21
admin/admin_log.go
Normal file
21
admin/admin_log.go
Normal file
@ -0,0 +1,21 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
var adminLogger *log.Logger
|
||||
|
||||
func InitLogger() {
|
||||
f, err := os.OpenFile(
|
||||
"admin.log",
|
||||
os.O_CREATE|os.O_APPEND|os.O_WRONLY,
|
||||
0600,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal("cannot open admin.log:", err)
|
||||
}
|
||||
|
||||
adminLogger = log.New(f, "", log.LstdFlags|log.LUTC)
|
||||
}
|
||||
3
admin/config.go
Normal file
3
admin/config.go
Normal file
@ -0,0 +1,3 @@
|
||||
package admin
|
||||
|
||||
var ApiKey string
|
||||
58
admin/handlers.go
Normal file
58
admin/handlers.go
Normal file
@ -0,0 +1,58 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"relay/registry"
|
||||
)
|
||||
|
||||
func domainsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method {
|
||||
|
||||
case "GET":
|
||||
registry.Global.Mu.Lock()
|
||||
defer registry.Global.Mu.Unlock()
|
||||
for d := range registry.Global.Domains {
|
||||
w.Write([]byte(d + "\n"))
|
||||
}
|
||||
|
||||
case "POST":
|
||||
domain := strings.ToLower(r.URL.Query().Get("domain"))
|
||||
if domain == "" {
|
||||
http.Error(w, "domain required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
registry.Global.Mu.Lock()
|
||||
if _, exists := registry.Global.Domains[domain]; exists {
|
||||
w.Write([]byte("already registered\n"))
|
||||
} else {
|
||||
registry.Global.Domains[domain] = nil
|
||||
adminLogger.Printf(
|
||||
"ADMIN ADD domain=%s ip=%s",
|
||||
domain, r.RemoteAddr,
|
||||
)
|
||||
w.Write([]byte("registered\n"))
|
||||
}
|
||||
registry.Global.Mu.Unlock()
|
||||
|
||||
case "DELETE":
|
||||
domain := strings.ToLower(r.URL.Query().Get("domain"))
|
||||
|
||||
registry.Global.Mu.Lock()
|
||||
if _, exists := registry.Global.Domains[domain]; exists {
|
||||
delete(registry.Global.Domains, domain)
|
||||
adminLogger.Printf(
|
||||
"ADMIN DELETE domain=%s ip=%s",
|
||||
domain, r.RemoteAddr,
|
||||
)
|
||||
}
|
||||
registry.Global.Mu.Unlock()
|
||||
|
||||
w.Write([]byte("deleted\n"))
|
||||
|
||||
default:
|
||||
http.Error(w, "method not allowed", 405)
|
||||
}
|
||||
}
|
||||
26
admin/middleware.go
Normal file
26
admin/middleware.go
Normal file
@ -0,0 +1,26 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func requireAPIKey(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
key := r.Header.Get("apikey")
|
||||
ip := r.RemoteAddr
|
||||
|
||||
if key == "" {
|
||||
adminLogger.Printf("ADMIN AUTH_MISSING ip=%s", ip)
|
||||
http.Error(w, "missing api key", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if key != ApiKey {
|
||||
adminLogger.Printf("ADMIN AUTH_FAIL ip=%s", ip)
|
||||
http.Error(w, "invalid api key", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
24
admin/server.go
Normal file
24
admin/server.go
Normal file
@ -0,0 +1,24 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func Serve(addr string) {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/domains", requireAPIKey(http.HandlerFunc(domainsHandler)))
|
||||
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "admin.html")
|
||||
})
|
||||
|
||||
log.Println("Admin API listening on", addr)
|
||||
log.Fatal(http.ListenAndServeTLS(
|
||||
addr,
|
||||
"certs/admin.crt",
|
||||
"certs/admin.key",
|
||||
mux,
|
||||
))
|
||||
}
|
||||
19
certs/admin.crt
Normal file
19
certs/admin.crt
Normal file
@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDCTCCAfGgAwIBAgIUe6pJSs6b4SAGPq+6Y2cHcD8RPSIwDQYJKoZIhvcNAQEL
|
||||
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MTIyMjEzMzgzMloXDTI2MTIy
|
||||
MjEzMzgzMlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAuMh21DmeKPkG3W/yYCQTi2CCd01JpqOhDl5dXTFU9pBE
|
||||
5FMyx9bNKcazJhMALCrqXJU/8YKTvigbQYDYQWLsuURDhItrdaPUtDKQ2h9kaJEq
|
||||
/hYUzu/nUopkdb2FyKlvsJo5newM7GZLadHIERng+QXXjJhlDsYcZVWMSLRTZuoV
|
||||
awZSxKA3N9SiXyiFuXZ3yXSq6KTwWrVvMx+QO4zXg8RXdKXG8aWHY0aT2i2fe53D
|
||||
/4YHsZHMg2ilBnh18GTIOnArCwqXE8cuVHtmgKNQyXmmW48tj+3UnYRtdc1HtMGj
|
||||
Ecm11nnbjKt0lIwdx1DWDDclU4j6Vbpp+J6VpKaKUQIDAQABo1MwUTAdBgNVHQ4E
|
||||
FgQUS5pECl+57NwHASDX2zoHe5TXQTswHwYDVR0jBBgwFoAUS5pECl+57NwHASDX
|
||||
2zoHe5TXQTswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAdiOu
|
||||
MabNSO2Ymtead5ZTNR5tNVRCd+xUIod7BmKA9Qo1/W8PlKVyYCly5e9NgtEqBaBA
|
||||
f1NURkl70a6lDcSQRyeAPEvpkqYsANedkq74RGJ6TFbj1kBbXSySXgrzF9f/q6x6
|
||||
oZ/Age7aItfly/lHFIRZocrmi5xZxCjl39n4qonniAsT4zw1vC8jFqYsk0eVvtSe
|
||||
H1O9K091L7sMxt4wijh6YtFZWSbezZs2OudUrc5kB2DeU9IUuIP83uh585ThTBMn
|
||||
SDKlxw1Jtz7SMuP4rs7fCzIslcSNq7q+KCvtcaLOvhlQRmXQ45fd+ESASXY5BcF+
|
||||
0neKGaxItwVUvBu4DQ==
|
||||
-----END CERTIFICATE-----
|
||||
28
certs/admin.key
Normal file
28
certs/admin.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC4yHbUOZ4o+Qbd
|
||||
b/JgJBOLYIJ3TUmmo6EOXl1dMVT2kETkUzLH1s0pxrMmEwAsKupclT/xgpO+KBtB
|
||||
gNhBYuy5REOEi2t1o9S0MpDaH2RokSr+FhTO7+dSimR1vYXIqW+wmjmd7AzsZktp
|
||||
0cgRGeD5BdeMmGUOxhxlVYxItFNm6hVrBlLEoDc31KJfKIW5dnfJdKropPBatW8z
|
||||
H5A7jNeDxFd0pcbxpYdjRpPaLZ97ncP/hgexkcyDaKUGeHXwZMg6cCsLCpcTxy5U
|
||||
e2aAo1DJeaZbjy2P7dSdhG11zUe0waMRybXWeduMq3SUjB3HUNYMNyVTiPpVumn4
|
||||
npWkpopRAgMBAAECggEADG+MqbyP85og12XEO3//YxBVb3HU4gFd99wrbzfAS/tf
|
||||
xjhVhk6jOOtzB+ixngdXBZs+IK2PmQr/cewvLFAGoPL3vUjvFuLLUEOdQoS9f+5n
|
||||
JORNCwk+ZEHFQDRHTOl0R2p1tAuxv0t6H07GPA+7DN9TB0FZVGzKS+/oNJtoMoMz
|
||||
BREkBzhA+BZirITicHqv6Egcobh+2Cdd6Nh6Mhdj8280RG8SmrJZvSBdMvmR4Xqm
|
||||
c+J4gh6wNCGOewKQM6JBAIVS5bd6c5flaKvgY3jTRXzX/Gmsv4422rgUaMlwcOgO
|
||||
ZjkqRDDVcfc3VNMelVVxKuBTLWYURMhTcRIm0vBhbQKBgQD9zr4mNLcvlWZVloSz
|
||||
2basjZuHo/Ywb1t5z+U11coaQIWBYmOPw/dB3CpfTp46iUHBZQE4/bG+RVt/MGKF
|
||||
Q6ST9h2oMEz9pH5zeSYcMi3MUdttb6hgJDd/Amf6Gk71JKvCqLb0Vu8NoaOtrCsm
|
||||
zoF3RdsoIWpgSoDBlZQIb3ca7QKBgQC6YRWFmiciOh95HnimBDsmW2XaA6TOYe3W
|
||||
NOSEFlC1Rc9FsCq8OX14tTRIlre3xSXHTUEpHhJFu0bef5/cPf/JTuQpxFkvrXm6
|
||||
IdVCmvcy2fbB8br2JyvhQ6BBzA5F94p/3/bS2f2GzchBuQEyEj7dSJZPBbZHzlpR
|
||||
UyCdHaCsdQKBgHxIrNxQnBN0+TOYDUt0pPtCLJLzOy7kmMrBfuAp3FmWlsmQwGg5
|
||||
8e4SPb2F5f2MEOL+7uZVdKBTnkZeDyBqy0CZGFSvskPSNQmenYbZG4wd2XFxZ+YM
|
||||
VhCfwQK7t0ZburALpetoVo86Q8hbspXCMauSTYsNMeYNFZe2A1NOIejRAoGAPIPP
|
||||
OBzwPeW/WFUzeTwAdJjSfjIWrcgQMC/mTpjsRZ9QCGGFzq2f9rRnMHZ3WlzRwl9s
|
||||
G8yexDNldFLd9eXPim5qGMGe76MU1gGsO78TKlipDRnOyaO4VKDfhN2beM5CEvkG
|
||||
LDoJXl6seeJ25+oSrUinPSsunyv6GVOzUDBRfg0CgYAk6qV1fb/9sZY+twfdlkEg
|
||||
0h9e2b2xFInxLZKem9Ogd85fHjdjGmykIBpW2crG3DAX1vVDm8Lp2Z/IvwquO5/N
|
||||
NfY+tMhS3UgFECu7lDcwJBxe7DuYN6TWz+RB8rVnEGhuAlfyPwf5nggRt8Y+rLcz
|
||||
KpAh+zwvI7U80qQ2oiK8eA==
|
||||
-----END PRIVATE KEY-----
|
||||
BIN
certs/ca.bks
Normal file
BIN
certs/ca.bks
Normal file
Binary file not shown.
30
certs/ca.crt
Normal file
30
certs/ca.crt
Normal file
@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFDTCCAvWgAwIBAgIUcGCTDSHXhNdepDL+88XFkMrKiKIwDQYJKoZIhvcNAQEL
|
||||
BQAwFjEUMBIGA1UEAwwLUGhvbmVSb290Q0EwHhcNMjUxMTE3MjIwMzMwWhcNMzUx
|
||||
MTE1MjIwMzMwWjAWMRQwEgYDVQQDDAtQaG9uZVJvb3RDQTCCAiIwDQYJKoZIhvcN
|
||||
AQEBBQADggIPADCCAgoCggIBAOEqJqNS07VhtV8B17cm/wBo9XeDcdRTWiUJV5aw
|
||||
dmlyBjPP/eU3pngUHi5ZBy8OwSswkjGhOVXJ1pwjoi2mQ1SFTSs+Z7MMtpvGsZm/
|
||||
0WEiF15NAEgEygD0bFRIzth7QqC/qLNHSJIhhpTNQ+cxWs2ndNjaSVuf4WRDLE30
|
||||
J49MiaGeaZVnSdGAcH6lmK7Y42jZwxY1a9viTGaPz2aI4zU2bKXG+fOEmi3nWNlR
|
||||
01s/MpK2WEkEqFBDwjurzivbeHkoJ0M2TxD/x48V4YXfN/j/ykxonmKF9kXikRqW
|
||||
pJISBdlBf9i7l/vz9ApnHkKA8ZabfKm5XZHD04aJ8N6oO5KlsPjRA9Xuym/UhIUg
|
||||
dkxuu3zOpsGEe3PNMAptdLbC4oN0wfJKpghIO9MxUChD3DVNBpt/XDlwI3vWEMLy
|
||||
xnvxrJJnNy6I2jPcQ78Nv8bW767YHwEZ1NpEDbpyKrWo2cBZjRMpOnWBG2zJhcqY
|
||||
4y38CwdRnk1+AYPLY72gmsDvFN0U6aMM9OpQv64DuqOjS6ZG3vXQq3kwwdWwQa9X
|
||||
reCaVpIimzPAIKclEDIVXbd+ORM/NBqXI6O49fPgSS3hA8IdA8fuahjVnBGRXdO2
|
||||
H0+YvU9+/b8UnAE76Kv6HTVa+oOcJhFhU9QKPI0GHd+DCbCjTuxLyT6SPylKP9HQ
|
||||
c+fjAgMBAAGjUzBRMB0GA1UdDgQWBBTlFiHfyw33ardXiUf2D3YfyDmEHzAfBgNV
|
||||
HSMEGDAWgBTlFiHfyw33ardXiUf2D3YfyDmEHzAPBgNVHRMBAf8EBTADAQH/MA0G
|
||||
CSqGSIb3DQEBCwUAA4ICAQBIT2KcTDnlsFrs7T8oBp6UXz7WNxQsbd5QINGJbNcD
|
||||
bekXOFyh9nH8VZTAm4cRhIf9DAf9V3eifWk2ZAOiAU0+Tx+Fstj2qsD/QtYEWqoC
|
||||
vlvMEKaqKmdvQsIBqs0tqZW1fpBoCJFNZuROZs8OsQU7kfdPrO7p2wKXkphDXqC3
|
||||
izXb4dyunJOJoAk9wVF3sKbnO4tzy1Vr6sBy5jTsTqK9BYCQX+0zkV1tRc9M9R4k
|
||||
V9hgsdidzFDnXWdG6KG2ZU7I7Q4YursOT5yXZJSrCce1gcADQfEiedvcSkzmaBUm
|
||||
C1kJUWymV1x08MbsxzbO2tR7tsMi/URjzi/OgjFQdblM+Z1Lfd76CsMliV3l3mhT
|
||||
XKU8fTYvyAhJYKDKI7r5bzP5gobHkSf/fvr1YkHNzMd270ympn8fLJtunAfrxz2Z
|
||||
N44pL/J44OEpu1DT+LhqnnHq4KnjFEd3DKryUGs2/C8i5GN41DF0krwEMQQLFYvL
|
||||
PmW+QhNVxHpmsclTjbXsp9is/2iSoNrIRbEGSKWo8sOyX+eZGUwdEXmEdqZRh3Sy
|
||||
QMcbvC7KkU5dkwwOoJqz+XFjpden4RllldwM1vchP8qRJ6gCu5aLH55fNPc4TReb
|
||||
wxvUtntYebOC8p/VUUvWZiy481ql3khsv2Akwj/wecmKDatFVVRG5BVjiPJkLZ1O
|
||||
Nw==
|
||||
-----END CERTIFICATE-----
|
||||
BIN
certs/ca.der
Normal file
BIN
certs/ca.der
Normal file
Binary file not shown.
52
certs/ca.key
Normal file
52
certs/ca.key
Normal file
@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDhKiajUtO1YbVf
|
||||
Ade3Jv8AaPV3g3HUU1olCVeWsHZpcgYzz/3lN6Z4FB4uWQcvDsErMJIxoTlVydac
|
||||
I6ItpkNUhU0rPmezDLabxrGZv9FhIhdeTQBIBMoA9GxUSM7Ye0Kgv6izR0iSIYaU
|
||||
zUPnMVrNp3TY2klbn+FkQyxN9CePTImhnmmVZ0nRgHB+pZiu2ONo2cMWNWvb4kxm
|
||||
j89miOM1NmylxvnzhJot51jZUdNbPzKStlhJBKhQQ8I7q84r23h5KCdDNk8Q/8eP
|
||||
FeGF3zf4/8pMaJ5ihfZF4pEalqSSEgXZQX/Yu5f78/QKZx5CgPGWm3ypuV2Rw9OG
|
||||
ifDeqDuSpbD40QPV7spv1ISFIHZMbrt8zqbBhHtzzTAKbXS2wuKDdMHySqYISDvT
|
||||
MVAoQ9w1TQabf1w5cCN71hDC8sZ78aySZzcuiNoz3EO/Db/G1u+u2B8BGdTaRA26
|
||||
ciq1qNnAWY0TKTp1gRtsyYXKmOMt/AsHUZ5NfgGDy2O9oJrA7xTdFOmjDPTqUL+u
|
||||
A7qjo0umRt710Kt5MMHVsEGvV63gmlaSIpszwCCnJRAyFV23fjkTPzQalyOjuPXz
|
||||
4Ekt4QPCHQPH7moY1ZwRkV3Tth9PmL1Pfv2/FJwBO+ir+h01WvqDnCYRYVPUCjyN
|
||||
Bh3fgwmwo07sS8k+kj8pSj/R0HPn4wIDAQABAoICAAcQxAqe+D66VK8pByRbqGfS
|
||||
Y1V/PeysOulrnCCB5A1WAyTQE4cEUoh1FSdeKtAKtfwNd6DwDrUG8uGOarHlBDrc
|
||||
Pfor6KQhM3+64erRrpfOMo6GewpHgDE8ekPAzyDS6VnS+c+6XmgbfjYgJM/V6CQI
|
||||
6608WE30O+XiB7tgfHdOLwlvx59lENduoNkQiDSAYM5y+uCxB3Psa3pSa+8rP3n1
|
||||
fb5L+p7uG8px9oNHQosb9hHNgAK2jzOJlMg7kWol5mdi36yHwT5m0FPIm32Qbhi1
|
||||
qhrws3ui+YHi5KvBa2OcBiv1lrXt2QyScKd86eGrWylfMq++vdVroDEaFgFepRPb
|
||||
YE3wwXldwag6hDckhYO14BRZ75TKI/+bis5G5SFZZgi6q4dsqc0OE2zp7fHbdXK0
|
||||
UvYB1uYFUxXo59JgqpPL5oN5pAA8qjTX77CgCegVNvUQChPIEuS0eloGQ4kEb8fw
|
||||
VIaDvhL2LD8wfOwRYTQaWKm5tB0zbJBo2CX4UL1kUM+7Gva9JjQY9RUkcdAbqyvt
|
||||
HT8cA1MCHBVcs24lDXiq2k7mEaCthCwMjDrRw5dd1ReXGIUIIFL9V/Pj79pxABvV
|
||||
3V7zFK3aDAmt9UbRUBDZml0NaOTRw20mu1q/8GO+IiptENjwJN+ntv7vlUDtHYTO
|
||||
GTvT9cd7pWiXXleHPGENAoIBAQD+diSnX/xsVWXBozFWX74/nT4/GzJy7fOlF4Ky
|
||||
QJl9CHbfwJeROwPf/zHkAAkGmUaLdxei2+hAryJv3g9boSfTLROHIcMIuylpT+Wg
|
||||
QrgLJixm5c2ljgTXWAaItK36C1JffIWIOlsS8bBDpNljiR6FolaW+u7GG7X4raZP
|
||||
34TIsBOF/T3tKsvtIHhdf0sRMAAhhG3Th5wpFwKtQio+H2XQNA9TPSTTI3Q4uMlf
|
||||
FTLOLq4I22RmPbexhO7s8tXlgas3whwRwien8GIH9vyCGhn3zMX0+GlfulKdVmmY
|
||||
GFCSddeLZNOStmTMQW2a3amaWObyA0xoQigEYTqWR+seHgGHAoIBAQDihql1Fmvf
|
||||
kVx1ygdznWd7w4exWcy48mz7Kwnahc6odQPXwirWJUeE3tVKt2hSsmMdONVcS423
|
||||
/92p803jlY4RozzhROzxSJ4BmzWkMeq+NqWb908x97CX9e+WXGnnWM7vfO9wgMsq
|
||||
evqcZXKiLb8aMihfyQnA87RgrWZ9xKt+UN08rYzh7bCzBRY2wzaG3qPujzjY7Hc1
|
||||
9rNLmQbwJsH0JqZdhixpDi7Js0tVsgBvANHc5D3cFKarxEUCzhyfQn+2vH9Ni+En
|
||||
ddGFbHhl4/PBhxSdglmLxX9Lyge29i6ZWbfM4Jxabucbyp4iF+B3qqLG43DvNz03
|
||||
LYKOAl7gKC3FAoIBAGRpMFuPx+bj5+x6PizMSSGHJhn23Hh3p049McivLyIkpevz
|
||||
bpvTgtrwM7q5vNYKw8ii7QPJ7SMhOOCV6s+Ij1OIlQ0c6H5YhKXW7lDIIyHbJWhR
|
||||
RE4Q9Z4YUTO+wGxL7WxakcLI7ElUb+6xbUsWv6GSBsM7L9+i7bK8q0UXealLudiE
|
||||
rtwYqDHhPz39zhxxKYwQWto+yAN63gaKdmrfLujysh1xokdi1SjQ2j2X+t1blDdQ
|
||||
g5TIw+TcBQAhbwBKo8qz4SmsyMM/Wx+zeb7JF/gtqOva3pH0z0bg43guGBVDRRPv
|
||||
bIGXUb08EEktMREEBdX4MT1u5aWczGai6IeQ5Z8CggEAXZAbXAZHxg7nLqukikdg
|
||||
X8kyObmKinVvOArdxglwgznZvXswcETzlljnpjW8/DM8Juy7i6SVQ4OGTdT1veOe
|
||||
y4At/CmY6EwDH0y5Sjln6OrvWk06w7u3j/x/2g4PnAOdbWOgDkrUH5at/n0UbRIS
|
||||
FcLT1ERYJ/9A6JGWfKoH32ONDavtPcAMNNUMCNB2rBw3f6heZZK95mcgRUBOklCf
|
||||
2bVBD+4EV9wIzTymCB4+eZrQE7meJ1HMSbQGgRMa1VkFITgYKLJ26/KI+OAFlqgh
|
||||
nTSq+ifFzqpjWq12pEZoluRsu02mpt+Zy2vUBubvyt2K4DU/Bz88pJbCjt9Byrot
|
||||
tQKCAQEAw69rwrsZhvqBOi3enAHlvMKSoS435tUtiRPnlAGyWwo7Mag2Irb+8327
|
||||
blPJrbEIZ+nJ48JWg3P6X8Uq1hGrT2mO4DX84Sy14rVAESTI6iNqYWG0chJopBRV
|
||||
FEbhkxix2e7N1OZigHUDm3EFOpupUHJMDuWmBiW+CBM4LW1aT6Bn4wXbDJtN4P9F
|
||||
tX3yFowD9u24N+gRzTpabfkMKgiiRsj1uHVwXhw39WVPI3Ch6kwKIVe+HN74fhHo
|
||||
gMqEUX7ouVbokXC4e18j7wOAAOWPWjEjQUjcHKXLuUtbRoKxgF7RN1CVnugLomU8
|
||||
2XZAcee+tCeqgwJwg3YFbc03POFXAw==
|
||||
-----END PRIVATE KEY-----
|
||||
1
certs/ca.srl
Normal file
1
certs/ca.srl
Normal file
@ -0,0 +1 @@
|
||||
5166E809D8A7B37861DD999BE40296DD06CD077E
|
||||
9
certs/extfile.cnf
Normal file
9
certs/extfile.cnf
Normal file
@ -0,0 +1,9 @@
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = serverAuth
|
||||
subjectAltName=@alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1=api.phone.local
|
||||
DNS.2=photo.phone.local
|
||||
58
certs/g.bat
Normal file
58
certs/g.bat
Normal file
@ -0,0 +1,58 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set OPENSSL="C:\Program Files (x86)\OpenSSL-Win32\bin\openssl.exe"
|
||||
|
||||
%OPENSSL% x509 -in ca.crt -out ca.der -outform DER
|
||||
|
||||
|
||||
if not exist ca.crt (
|
||||
echo [ERROR] File ca.crt not found in this folder.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [OK] Found ca.crt
|
||||
|
||||
set BC_FILE=bcprov-jdk15on-1.70.jar
|
||||
|
||||
if not exist %BC_FILE% (
|
||||
echo [INFO] Downloading %BC_FILE% ...
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.70/bcprov-jdk15on-1.70.jar', '%BC_FILE%')"
|
||||
if not exist %BC_FILE% (
|
||||
echo [ERROR] Failed to download %BC_FILE%
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo [OK] BouncyCastle is ready: %BC_FILE%
|
||||
|
||||
echo [INFO] Converting ca.crt to ca.der ...
|
||||
%OPENSSL% x509 -in ca.crt -out ca.der -outform DER
|
||||
|
||||
if not exist ca.der (
|
||||
echo [ERROR] Failed to create ca.der
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [OK] ca.der created
|
||||
|
||||
echo [INFO] Creating BKS TrustStore ca.bks ...
|
||||
|
||||
keytool -importcert -alias relayCA -file ca.der -keystore ca.bks -storetype BKS -storepass password -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath %BC_FILE% -noprompt
|
||||
|
||||
if not exist ca.bks (
|
||||
echo [ERROR] Failed to create ca.bks
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [OK] ca.bks successfully created
|
||||
|
||||
echo [INFO] Verifying ca.bks ...
|
||||
keytool -list -v -keystore ca.bks -storepass password -storetype BKS
|
||||
|
||||
echo ca.bks is ready for Android.
|
||||
pause
|
||||
30
certs/generate_admin_cert.bat
Normal file
30
certs/generate_admin_cert.bat
Normal file
@ -0,0 +1,30 @@
|
||||
@echo off
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
set OPENSSL="C:\Program Files (x86)\OpenSSL-Win32\bin\openssl.exe"
|
||||
|
||||
if not exist %OPENSSL% (
|
||||
echo [ERROR] OpenSSL not found at:
|
||||
echo %OPENSSL%
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM генерация сертификата
|
||||
%OPENSSL% req -x509 -newkey rsa:2048 ^
|
||||
-keyout admin.key ^
|
||||
-out admin.crt ^
|
||||
-days 365 ^
|
||||
-nodes ^
|
||||
-subj "/CN=localhost"
|
||||
|
||||
if errorlevel 1 (
|
||||
echo [ERROR] OpenSSL failed
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [SUCCESS] admin.crt and admin.key generated in certs\
|
||||
pause
|
||||
26
certs/phone.crt
Normal file
26
certs/phone.crt
Normal file
@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEaDCCAlCgAwIBAgIUUWboCdins3hh3Zmb5AKW3QbNB34wDQYJKoZIhvcNAQEL
|
||||
BQAwFjEUMBIGA1UEAwwLUGhvbmVSb290Q0EwHhcNMjUxMTE3MjIwMzMyWhcNMjYx
|
||||
MTE3MjIwMzMyWjAXMRUwEwYDVQQDDAxwaG9uZS5kZXZpY2UwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQC5mV3ppEknCziHHpO9WzDqYA5O3WyNsVFec0fi
|
||||
zGNMzIZWjt9eKBzPUJH3L51oC+NtN1Qe/Qbq+/z/SzKtPz58o981bIoGNTZN0oh/
|
||||
28/IwZwimjyw8K2HB0vtTV16AIvtE72C4jOAuazsnjk8PUuJ9t7hH1afyiqSWdMa
|
||||
K5FG7oWJGMXQQQXxmgsCQADP96H+810TT02em7AWZMyD9H7sIeRJ5CNuXuUDNJZZ
|
||||
3XJgGStqfOFrk3S9dZxUsfI5jYl5MwDvt5HmR1nhwepxoT9IPPWEdm5oPPMhYymu
|
||||
f581jZAmY98v+VHY76+J6bpLDjNUSDRntDqu9LFt1aRqMe8xAgMBAAGjgawwgakw
|
||||
HwYDVR0jBBgwFoAU5RYh38sN92q3V4lH9g92H8g5hB8wCQYDVR0TBAIwADALBgNV
|
||||
HQ8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwOgYDVR0RBDMwMYILcGhvbmUu
|
||||
bG9jYWyCD2FwaS5waG9uZS5sb2NhbIIRcGhvdG8ucGhvbmUubG9jYWwwHQYDVR0O
|
||||
BBYEFBFz4PmZFnooU2PAygJXD3LOK1mzMA0GCSqGSIb3DQEBCwUAA4ICAQC+jYsM
|
||||
xjEfEbP1fgNR2zjBnfNLz+1GkXfMpuLbo+rcy6pcsqUPiK7EMoMjF12vY2zYvyD+
|
||||
8w6Pf3QCWQ/RKpN6yXHsp6ePUk/STAArZN4E3jI2+Pzp9a6PDehQDJXkjqpRBp0O
|
||||
NROjcD0PrTzDB/eHD5SrGexLpVLhxoabUdKiEh+JylBhVUki4H8iFVvQvakZkb5o
|
||||
x3F3G3nl+vmcTvbWe5dpVgY7rqjlsbg5OSQcte6B1mDvVwt7meM5ymjDFmxQdOfX
|
||||
CoKQ8woPm9TmUiJf/Ljh+/RK8VIdkuynXvjkHvX/jAXWWQD6mRJq+HvaGNOFDGox
|
||||
Oodi56Rq9H7LzY1pb7nHhzunxncR/443JjnrzAPyReuYBo2ON3RyF5g5JXgfmJNK
|
||||
0u9pb9rEYY5W6jC6Hu6Ttby/BV+NO3xDofXHRo1ujK+WHVd490+U2vo1gfiwLc5P
|
||||
wbHmmvNxXsF2xI+rrylho6OgXCF/lVcfMOl0klq0TzTwFL90+qLTz0b5AYN2VqnW
|
||||
IIDCEwtbS4imX/OXLP6wPDiHxsy0PHKJfk1nr5cWu/IFG1myfz3EYZn4W8t3VSQS
|
||||
e1h1lErCx5kMKBmTdyOukeEEu0+wCrjs/PpU8pQcFKlLWU4KR6/r7ZX/go0t6eCD
|
||||
U5EVKKdr60PwkCfzb+ld0k7A+E61czW2XgNVQg==
|
||||
-----END CERTIFICATE-----
|
||||
15
certs/phone.csr
Normal file
15
certs/phone.csr
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICXDCCAUQCAQAwFzEVMBMGA1UEAwwMcGhvbmUuZGV2aWNlMIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuZld6aRJJws4hx6TvVsw6mAOTt1sjbFRXnNH
|
||||
4sxjTMyGVo7fXigcz1CR9y+daAvjbTdUHv0G6vv8/0syrT8+fKPfNWyKBjU2TdKI
|
||||
f9vPyMGcIpo8sPCthwdL7U1degCL7RO9guIzgLms7J45PD1Lifbe4R9Wn8oqklnT
|
||||
GiuRRu6FiRjF0EEF8ZoLAkAAz/eh/vNdE09NnpuwFmTMg/R+7CHkSeQjbl7lAzSW
|
||||
Wd1yYBkranzha5N0vXWcVLHyOY2JeTMA77eR5kdZ4cHqcaE/SDz1hHZuaDzzIWMp
|
||||
rn+fNY2QJmPfL/lR2O+viem6Sw4zVEg0Z7Q6rvSxbdWkajHvMQIDAQABoAAwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAHfVrvpmjQtuuDoi05i6yMSW4TnVuKPbOWTuJrKq5HPR
|
||||
ob5KMf/hZMYpMdKN3OUjJ+Ze5BfI6X1MWUPX8Nx5kDVdSa1b0gEjMzgOlKbM0w+7
|
||||
Dv0jJsKWjmNGwD4IslSmzIrdZrD8kOZZmifBsc66unjgnhi+K8/EEgMz7AQCfS3m
|
||||
UjwAclRvqI/abvgnOcDQ+dtLF+yjEhbJltP4kQKraIkR2bxGcP53W8n+xeeyEqlK
|
||||
3NdUk9iwhAO7ovXSW7Zt7ohx3ASQTaUWCS9vYGihY9RhdRcyk1Q47vAbwOe0kmMC
|
||||
OJcA9qOZcx1FOPKkYJ4LRyj/uDj4G8zoz75BpHKzYW4=
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
28
certs/phone.key
Normal file
28
certs/phone.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC5mV3ppEknCziH
|
||||
HpO9WzDqYA5O3WyNsVFec0fizGNMzIZWjt9eKBzPUJH3L51oC+NtN1Qe/Qbq+/z/
|
||||
SzKtPz58o981bIoGNTZN0oh/28/IwZwimjyw8K2HB0vtTV16AIvtE72C4jOAuazs
|
||||
njk8PUuJ9t7hH1afyiqSWdMaK5FG7oWJGMXQQQXxmgsCQADP96H+810TT02em7AW
|
||||
ZMyD9H7sIeRJ5CNuXuUDNJZZ3XJgGStqfOFrk3S9dZxUsfI5jYl5MwDvt5HmR1nh
|
||||
wepxoT9IPPWEdm5oPPMhYymuf581jZAmY98v+VHY76+J6bpLDjNUSDRntDqu9LFt
|
||||
1aRqMe8xAgMBAAECggEAEFR7ssNKaNdWZzq1m6tERjyJL1kEV5uhG3ly+w2qGqEP
|
||||
z6bgS8vYuRVcOnUKJi3Bmj1ZHYuvltZXTNKxFOHXKo1NzHwON6/P5UOfnSxaGTTC
|
||||
LmzTgTgAwW9onh3SZzOMHDuotYIXyP0AesAMxicyGDBl+aw4HKgWwp8i18JUlODg
|
||||
sP4BsjMRMVvL3n45PsORENrxORx7n73243k3yhR4GgNiH9f6HkDUi75uHFOguzjH
|
||||
kkhy7eKMwLdNOsyTQgWXDRkf9p1q43Ij2pA0k+E0o+8C0oteG4IVNPTir9Df0FsR
|
||||
weV6NuvHQcM437iqeBK3SS6IVRq+ONaRn3xkWYJklwKBgQDoY3k3hNDRVZ2tVjpD
|
||||
HVAxHMhYIKm5J4lP6MZfIxFrfla+RPPNqbtaJetDI+FOQ9I1ww7kB+USKb13cqIM
|
||||
PzYD8KNLNmiZGXNafZGN1KlcrGyVepdSZBDhvOCr0fsuPwrvE07wEP619K9UVIMP
|
||||
TYD1wWRv8bOlGe6/IWdGf+VxFwKBgQDMdOD+8u/N1zAt2ocGSkY9QSg5LV50x1cO
|
||||
BZ0KEKFF682VjKgvPXJfwLEtjB2c7DtB02FzrSBRCai0oejqjiR9X76ustvN6lGs
|
||||
a3QyZdRQduswEh7nbjHDZWuRcJ6LcrwyXteAxCd2jYeGlNm2H4mViRPRA7Oj/5Cc
|
||||
IM6bT2v+9wKBgQDTqL5gJdU3xN4fYXkhZdKDWO7U7bMIVA1Jvf7n6f3UxTZmiFDy
|
||||
0hQ1cHIOLeDpMvaERwwJ/3LRjzjlUYBs3SnqfsOMHps4Tqj1E4d+AeLb6KPhpc2r
|
||||
mj6SDEEp3dAEeCESTajJGQGVYq5Khcr1Jic+Lw22tBNmXe9JIDh7SsQEswKBgQDK
|
||||
yM3z8C4qgdj2Ub0EXxylWn+zni0GNERC0wx71Bywxf0E7BpPqGlNUUgp/cPNRXxM
|
||||
gIQygC8CUUszxTbHlS3Z7+GnUhyyckqJcZYw+lCHcjs4VXCzZ9cRjwEOop2Nf8Hr
|
||||
T6f8vhDKA/u8XtxER6llWC0AbOR6r1rVj7B72F0r5wKBgQCe/tdr/Oe17NXCkrRP
|
||||
1iwKHqtueiwWdgKmGWiTYgZssbZDtjb+yuCt0sKFZ3fPgJWG0rdyQIilNUXeM2Yq
|
||||
TVWWNBbsncOOb2hRJ1E0CY5DlsRVRixK5hezfRnM+4Ewecr3Q9LJywJRh7RH6uXr
|
||||
plqC/CygDzL1lLEMkHRu1TRRTQ==
|
||||
-----END PRIVATE KEY-----
|
||||
BIN
certs/phone.p12
Normal file
BIN
certs/phone.p12
Normal file
Binary file not shown.
9
certs/phone_ext.cnf
Normal file
9
certs/phone_ext.cnf
Normal file
@ -0,0 +1,9 @@
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage=digitalSignature,keyEncipherment
|
||||
extendedKeyUsage=clientAuth
|
||||
subjectAltName=@alt_names
|
||||
[alt_names]
|
||||
DNS.1=phone.local
|
||||
DNS.2=api.phone.local
|
||||
DNS.3=photo.phone.local
|
||||
26
certs/relay.crt
Normal file
26
certs/relay.crt
Normal file
@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEdjCCAl6gAwIBAgIUUWboCdins3hh3Zmb5AKW3QbNB3kwDQYJKoZIhvcNAQEL
|
||||
BQAwGDEWMBQGA1UEAwwNUGhvbmUgUm9vdCBDQTAeFw0yNTExMTcyMDE3MjlaFw0y
|
||||
NjExMTcyMDE3MjlaMBAxDjAMBgNVBAMMBXJlbGF5MIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAnqXbO1kzgmhp+kqvoq2lXAbTPN3yJLr+e5bKNoP5mhYh
|
||||
CGLQ4boeS3a/1LPjLLJq9vE+eXywgG/Lk+KvHysQg7imOKtEVQmkT1cXpkBSMKYZ
|
||||
TlMLttVhlj3IhrEk0N3b5k2QcnhV+CZxIFiZrrbFC5ZDlr1QgsW0bqF6r1VyGIxx
|
||||
Aivtx5EOUNLf32hyH0wnf74Abi4/CBvo5YDEM+0F5XMV7SkZTTfNyspBPweDT9hy
|
||||
evkJysMBqMRBelxenRFoHH5iHWds9lH0CejVTsVXT817Z6+mUsk3qiV4tpCTanz9
|
||||
IgaZ/37J1VtWvMZOdlUJXa1YoEJoOYSS5Mz+vQeUVQIDAQABo4G/MIG8MB8GA1Ud
|
||||
IwQYMBaAFHxW0HxPLVn3/hGAqanNf1E/5+eXMAkGA1UdEwQCMAAwCwYDVR0PBAQD
|
||||
AgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBME0GA1UdEQRGMESCBXJlbGF5ggtyZWxh
|
||||
eS5sb2NhbIIPYXBpLnBob25lLmxvY2FsghFwaG90by5waG9uZS5sb2NhbIcEfwAA
|
||||
AYcEwKgfbDAdBgNVHQ4EFgQUBQUunM/zKMrW9//gKQWX1Ze9laUwDQYJKoZIhvcN
|
||||
AQELBQADggIBAFpialKbFXFeSTiwijhKogB0LQ9uqIjw4Mzv7/RNU/xH9fIK7fAv
|
||||
7a4MMlSDbEphhcv/6mf3pmjzZ6yqrvXmXN9RnmdUjnjwdhW+Q0TghCWabCtdCtCm
|
||||
MmPDQ08kZY0hIsJGuAaEuubW/dzoFfZ5heGMv2R2fSp8YO/OHI0+8M+9dgcQJiFz
|
||||
L4e7Dr1Lt5rzfEhJXtxGBA/Fk5R7dUEbVThLsoPFSuwk8DjJ4lz8iRtDNDD3TB2W
|
||||
vC+L9U7veRkaci6lzFRpAPGCEnA3RKJFfGNylBda2y0dnuHfHZtf9MAmrUFUL476
|
||||
OQ8YxD+FoCQn4qNjGzzdHT1t4WIrWoKjqI8NRxLiJjDq+6E3H/SiL25gjPxYtUIJ
|
||||
tLSrq9lnFqJ5zgAXee3K5/XHS5wToBGjnM4QMQru54COM9hHzTk3hSLZFTrFNNqN
|
||||
mwhaY+piTMYDJVcPvxzSetXug4hCEZBkZg4GqvX/6N4ic+YXwu1kaLvPrqpo1BEC
|
||||
SCjbJVXCorDrbNqmXFq74GHvi+W6l5RX7GIy+oiSxAQCcLMJ1IY8iA1B+PsjvpBq
|
||||
1ni9rWY0U6i67LT0Y8UutNLSCfuHQI0KIJ3Xqt7ZbRkE/VwjcoMA++lh+ML12MM+
|
||||
WgPItN/3E0oZhAOF0MaYNijGRnkAs16/o7CiiQ6Bf0bHQdmKrNhdB0aD
|
||||
-----END CERTIFICATE-----
|
||||
15
certs/relay.csr
Normal file
15
certs/relay.csr
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICVTCCAT0CAQAwEDEOMAwGA1UEAwwFcmVsYXkwggEiMA0GCSqGSIb3DQEBAQUA
|
||||
A4IBDwAwggEKAoIBAQCepds7WTOCaGn6Sq+iraVcBtM83fIkuv57lso2g/maFiEI
|
||||
YtDhuh5Ldr/Us+Mssmr28T55fLCAb8uT4q8fKxCDuKY4q0RVCaRPVxemQFIwphlO
|
||||
Uwu21WGWPciGsSTQ3dvmTZByeFX4JnEgWJmutsULlkOWvVCCxbRuoXqvVXIYjHEC
|
||||
K+3HkQ5Q0t/faHIfTCd/vgBuLj8IG+jlgMQz7QXlcxXtKRlNN83KykE/B4NP2HJ6
|
||||
+QnKwwGoxEF6XF6dEWgcfmIdZ2z2UfQJ6NVOxVdPzXtnr6ZSyTeqJXi2kJNqfP0i
|
||||
Bpn/fsnVW1a8xk52VQldrVigQmg5hJLkzP69B5RVAgMBAAGgADANBgkqhkiG9w0B
|
||||
AQsFAAOCAQEALWFuDYi3xyis834DJ+B9+snhFq9cdOZmeoR3yDoJT03NN7yf/sy/
|
||||
4pCoD+y5xfPFsi5JP/ev+ki1ZPCEpW+C8ptNtYurWo3QN3B/RmY3xsbE9C1XcTwm
|
||||
comDNUUEfOaHi64bWIJ+ee4mLzD0IdDYWTVoNzuGkDxWfPlcibvV1jrDRb1zFWEU
|
||||
UTrXXsa0LktGpGUX7QW+NIUGWuvBi7zZt/iyV2Hq9zRBbjacuo+2niyM+Igyygb9
|
||||
WB0JdxH/iChvPd498hyHQnt1zq/UEgT+pX5qQ5blTzoKDr5y+WVYPw81ump8W81v
|
||||
hqq2sDyyv0hIoKyEnZlNc6JlQA/d1DfliA==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
28
certs/relay.key
Normal file
28
certs/relay.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCepds7WTOCaGn6
|
||||
Sq+iraVcBtM83fIkuv57lso2g/maFiEIYtDhuh5Ldr/Us+Mssmr28T55fLCAb8uT
|
||||
4q8fKxCDuKY4q0RVCaRPVxemQFIwphlOUwu21WGWPciGsSTQ3dvmTZByeFX4JnEg
|
||||
WJmutsULlkOWvVCCxbRuoXqvVXIYjHECK+3HkQ5Q0t/faHIfTCd/vgBuLj8IG+jl
|
||||
gMQz7QXlcxXtKRlNN83KykE/B4NP2HJ6+QnKwwGoxEF6XF6dEWgcfmIdZ2z2UfQJ
|
||||
6NVOxVdPzXtnr6ZSyTeqJXi2kJNqfP0iBpn/fsnVW1a8xk52VQldrVigQmg5hJLk
|
||||
zP69B5RVAgMBAAECggEADOrEJtjkcMG/nzllg4FP7WZA3LvVc1gmUDm+zSGBuSIE
|
||||
HoKtLzPQM6S/ibn7zS/ZtbF+vLWCSXLQyIG0cH05IwBtyD9pmOLoFe2pZ0flaUCc
|
||||
3tu0IHbPM0Rkh1L1BGyL8vxtvmQ9266Fl3SfTrJi6MabSjKv03X1cuyC6LO0Tns/
|
||||
6QXA+BeTzUeOGQPNYQNhEfmAX9prFwVka0/ZrNK8O/uCIWo+S8sDvk+XuV001F/G
|
||||
hRw9V21gyu8o2vE7u923hNlzN3oD+cwxeW7vdTf/V+Kvb/0WkhQfMcbiLkhUvJp8
|
||||
Ln3+vDFpT9YwvsLOrPgBfkpC9egSmW6iNDjRmUQQIQKBgQDbTMFM2J+V/NAvBtMo
|
||||
tRvb4oL+g07vE6Bc2iIT1v6UxWFIkEb33Y3AbFPgeSXyqghx8A57BUkNMHAKDcwT
|
||||
UDivnWL7yOpWIjkqT0Rx9r64xQJhdwkptYZGkor0ViO3Ib3bPeHo5hmkHPeXWBDG
|
||||
RQ/Llx08LS8ePTW0JbBZFnJMtwKBgQC5MqZoO627pTd+ijH1ITqO6FVgpzAnlgrt
|
||||
HTQ7E8vZMuNzswfB9lFqL9yQs/1JLv6wF6Q0BEpaKgjO7WxHmewh662gn9kJmJk0
|
||||
7Oa+fapJV6ZJyaspXjAS99b4CfKqJwJC2g9U4Voi+UbvIcGNk5ausmy9pA6otseY
|
||||
X2YPGRHzUwKBgFnh2rRRcQ87gGRV6sQbfuCftUr1rKuGosqLyT3Sd6OoRphEMiIz
|
||||
V38Pp00wumH8WNvCJV08rFVQjgtA3mzoC2PHISPLlGhbPIzf0lDXbhIzBSfHbyT+
|
||||
NpvEQlmk2JydosAyW95mOQovqTcJrE5nTfMG67+XUWGWeuVsMRxCe/R/AoGBAKAu
|
||||
9Anh3IIaBCbaBx3b8Ndck0Q3N4p119uBUATtOXsS7fLL3iDhGUg8P42VcLWVBUtw
|
||||
F2G6eEkGZHn+l5JSyxAH1jTBLauEJrfFVEtdTCWFv1nBKd9tDS3K2k/N4utTNDx4
|
||||
eZxUEm9/pt/9FXmMN1/BChb5SIibF4ZutUrHx2PrAoGAVBam777gpXuVnkjgj2hu
|
||||
VM+Q3XZzBk3OPmN6LhWW2MaXL1PM7KEWFFa3Lg9n1xOvmLncPa/7pwwNsvvwt/Er
|
||||
Dfn/TV4MDfb0DXjEu9W51f6ZHgXmlJl1XfXMTUO2tFCyKnCqU53LfDWLAXFi2HIw
|
||||
3gd80FG9XMJxd+AlvwjzhGs=
|
||||
-----END PRIVATE KEY-----
|
||||
13
certs/relay_ext.cnf
Normal file
13
certs/relay_ext.cnf
Normal file
@ -0,0 +1,13 @@
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
extendedKeyUsage = serverAuth
|
||||
subjectAltName=@alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1=relay
|
||||
DNS.2=relay.local
|
||||
DNS.3=api.phone.local
|
||||
DNS.4=photo.phone.local
|
||||
IP.1=127.0.0.1
|
||||
IP.2=192.168.31.108
|
||||
26
certs/server.crt
Normal file
26
certs/server.crt
Normal file
@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEZjCCAk6gAwIBAgIUUWboCdins3hh3Zmb5AKW3QbNB30wDQYJKoZIhvcNAQEL
|
||||
BQAwFjEUMBIGA1UEAwwLUGhvbmVSb290Q0EwHhcNMjUxMTE3MjIwMzMxWhcNMjYx
|
||||
MTE3MjIwMzMxWjAWMRQwEgYDVQQDDAtwaG9uZS5sb2NhbDCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBALeTnJjjhfrPPaGPWhlxpJwtWOXkJyVPDK7lHM/d
|
||||
cW5bQvExpMHvDVIg04d6rlnxO+ZxMAfz29KhIIsbuTI7jW55+oS0ceUIsLZ729xi
|
||||
eMZ31WfCZ/OoPgHj+BeQWEeeMQvvYfamW/lLZNUdRBQAdEEOM3v0ygqlMJdsjxOr
|
||||
e8mTIjXWobWwGUGl0mqLH8f7Co0ef5N5A6n50furIODPeKUvVVItXz6oyuMnGwKm
|
||||
iPEVa06LATbe8zQt1UdXP7OG/cPY4OCMQhwZZaYmYLkeFDqmHfj7nqQo1e2Xrdlm
|
||||
zbdcBmcNgnwvuSJ+Fq5z0rzVQjpWjJ1nS2d+IotyuKN9dKcCAwEAAaOBqzCBqDAf
|
||||
BgNVHSMEGDAWgBTlFiHfyw33ardXiUf2D3YfyDmEHzAJBgNVHRMEAjAAMAsGA1Ud
|
||||
DwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATA5BgNVHREEMjAwgg9hcGkucGhv
|
||||
bmUubG9jYWyCEXBob3RvLnBob25lLmxvY2FshwTAqB9shwR/AAABMB0GA1UdDgQW
|
||||
BBQIOZl1Y4we6IphJqvqR7kfWg8JIDANBgkqhkiG9w0BAQsFAAOCAgEA1E8ebgK8
|
||||
Q13ne2dAZsJ8071TgZPO8gZA31duAIN/PIwO3eExVzevzn2sxtnq2tPuivnkTajN
|
||||
9dMO/EBmDZghXB41ZbEr8Bi+5u61xShHq/SSrpqEVE5nlbWnsOVv4B61WM5sA/sU
|
||||
UVMf7B9YHUhXL4Gkrm6yWMlAhsIkLPwHhlESzvyMnVaM9h3B+LdqOyp1Ws6u3noH
|
||||
IGstIRGNJY77vI0L1slfCU1IGIPrzjTc6QGGNA8Jm4bvnhjei8L4SawNKBH9+Ffl
|
||||
gH6esjM9iQL3IJRw/B7BO0/GnMzGmpLWvV01y9G6Rm4NbX4i6RParbHrMptfSMh4
|
||||
wZ5T7tawm3P4BdujHtxALr0TRiXDlg/HluF8gaHLQ7J+xJKoE6eJynCDLdUIExLd
|
||||
jrk6hNknrcguASf2Iq5uJgkavUrdoyGHMqhrEBL+2Z62RHmrzP8+dTAXuy9ckgEx
|
||||
oW9tg+rAmjOtJzGjhRLS3XaTEdKBh5xynUV82l+S8j89FVTva7wpEB9FutLDziBW
|
||||
Xh5NanQ7w+373ZPcKF7D1Xyh5DmifIN0ppMCowx2EziKQdlE3KDwtuOYxU4lCYTA
|
||||
9i40J/KtU3wSxZyTSza6H866PDo8IRN6Yy/QYDePOSmH2SWx8gHkeqzatD6yE5CB
|
||||
o0Iw73cyFDBT/5OOeUqgfFR2WKEvWt+6aTI=
|
||||
-----END CERTIFICATE-----
|
||||
15
certs/server.csr
Normal file
15
certs/server.csr
Normal file
@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICWzCCAUMCAQAwFjEUMBIGA1UEAwwLcGhvbmUubG9jYWwwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQC3k5yY44X6zz2hj1oZcaScLVjl5CclTwyu5RzP
|
||||
3XFuW0LxMaTB7w1SINOHeq5Z8TvmcTAH89vSoSCLG7kyO41uefqEtHHlCLC2e9vc
|
||||
YnjGd9VnwmfzqD4B4/gXkFhHnjEL72H2plv5S2TVHUQUAHRBDjN79MoKpTCXbI8T
|
||||
q3vJkyI11qG1sBlBpdJqix/H+wqNHn+TeQOp+dH7qyDgz3ilL1VSLV8+qMrjJxsC
|
||||
pojxFWtOiwE23vM0LdVHVz+zhv3D2ODgjEIcGWWmJmC5HhQ6ph34+56kKNXtl63Z
|
||||
Zs23XAZnDYJ8L7kifhauc9K81UI6VoydZ0tnfiKLcrijfXSnAgMBAAGgADANBgkq
|
||||
hkiG9w0BAQsFAAOCAQEAaFZNpp7JKVJAhD0yjVccyE9q9qepwFO4dCAb0U+Lf930
|
||||
sIBcALa8XYMbdcKB614Tcku4k/153TYAhY91XfbRk2CY/yrxYNZfj6nWhR//DnMX
|
||||
CvWLOcziFoS2QY8PZzu/XcSVVekuE24zX5vJnLgFmCNesTfTRZGfilhCIcnT542l
|
||||
g1CuacY1HZ/HOigFWQ3eLByxOwd2Ty7z6iOUrDofTJL914dIkBvtyDIiQyGdx57P
|
||||
a40itGI8Xpt4LKpMoNC5wdr4r+91mXga27y8FHUvlcypXYqAyaatyvc1ie141R1+
|
||||
RPzljUx3ZE/FvkbcQ2VJSYgmCEDkCogJtNyZDcbFSw==
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
28
certs/server.key
Normal file
28
certs/server.key
Normal file
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3k5yY44X6zz2h
|
||||
j1oZcaScLVjl5CclTwyu5RzP3XFuW0LxMaTB7w1SINOHeq5Z8TvmcTAH89vSoSCL
|
||||
G7kyO41uefqEtHHlCLC2e9vcYnjGd9VnwmfzqD4B4/gXkFhHnjEL72H2plv5S2TV
|
||||
HUQUAHRBDjN79MoKpTCXbI8Tq3vJkyI11qG1sBlBpdJqix/H+wqNHn+TeQOp+dH7
|
||||
qyDgz3ilL1VSLV8+qMrjJxsCpojxFWtOiwE23vM0LdVHVz+zhv3D2ODgjEIcGWWm
|
||||
JmC5HhQ6ph34+56kKNXtl63ZZs23XAZnDYJ8L7kifhauc9K81UI6VoydZ0tnfiKL
|
||||
crijfXSnAgMBAAECggEAFNlD2K1GYxS0SCvyrJ8WddJEnV9K/ta6dwZ4PjdFEaZ1
|
||||
tNTRhGD031XxEBrjwD1Ac0x5iv2sAoDgJExSvRy8VEawJ/AiW0OgZiks8BuS4d9s
|
||||
MiuHCMobuLU+UNbI3+FcaqGWO5/rJCXm3rlDKQ5gJZ9KQ5Kqe4kFOr1OhopcNak5
|
||||
yAyhlm/uo/au9Y+H/ZhwDAsL0HgMRmeBTp4o4pmvtNOUXr+vPypJwGteISeHkH4K
|
||||
DZ5XlAzK2b6lttU2wazb82jlRKQs044vt3H5hZFw8ihKgfwnWvJE2CVfsT7suVPj
|
||||
IGJ+vl/NxgwWAs+g5tgLHmbVvwdE2svPafAYwwRWkQKBgQDn6DlV6XGDh0mEvvFb
|
||||
lobbHQg9XC1Z4VJQpnpnFwdYi8ivRJraZzaAZ5HpItj5035dx0rDL63QgcrNtG+k
|
||||
4qUZxvg9Qwan9qHAP6EF4Nmc/DxY/C3bKVau4FOuAKP3QIjnLMPIbgpm46xKL0Lm
|
||||
+QvCRXt5gmSpb2f2Y532o5jfqQKBgQDKpf6lSmLv+7vayJQbT4jVndz2QTS7EZz0
|
||||
uQ58VURiDPmB5JJqd0t2T8tQMULsbYCtcPMWkFhq8RJBRY2tOI+zNPI51UKwM+DZ
|
||||
qKNh8iIw4s/UhkG7Hk/fW+JtVpcWtHBkuuclpX+ImBzzBcF1HwD61WLcJb2s3rb+
|
||||
upNrC7ijzwKBgCyp7xD6yt/4GFK2q6lmDkb5CnM2440h9kaOKZjdOI73LQmEfwZ9
|
||||
RmPojpOGIJ/M+dN55I4/CozT0olXrQDmncGfLoQt+oQy3eg22P5W1dKESeMhfntt
|
||||
NMKtdbBXczzVcwiC+JoLh3lVdAM9ovb1FCywUR2P3W88g5tSiEPOMk0xAoGBAI+U
|
||||
YQH33HWwZH81EkrvZUIFIaOQu623Yv+5hlvthg/6pWW071BjyaHAE4tz+7jMNRmu
|
||||
J23bQ+oxd/+rKiCLLLWKU/1J7oAtoahV5bzl8/ezHBG2Nig/59OXpKxXZ6F8ow2b
|
||||
p15zDhNXw1skvtce6nDOc8cLLoKnIf0FcKGtolrdAoGAOy1ruHSstC3Ln+MNrnCN
|
||||
+D8WRjUN/5Chh69R4IjER2l2xGZUmjnFHk398l7TrS1YRVn0iuGb0KfBoUjC4iH3
|
||||
lTP/pdxUOhwvLR3Q7OztZrQGHZ9+FH6OE5U724i6fJ6PhHAAp1agFGlRSQ+IP2PC
|
||||
vvCI/m3H+XLbZkvtFJ97WFE=
|
||||
-----END PRIVATE KEY-----
|
||||
10
certs/server_ext.cnf
Normal file
10
certs/server_ext.cnf
Normal file
@ -0,0 +1,10 @@
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage=digitalSignature,keyEncipherment
|
||||
extendedKeyUsage=serverAuth
|
||||
subjectAltName=@alt_names
|
||||
[alt_names]
|
||||
DNS.1=api.phone.local
|
||||
DNS.2=photo.phone.local
|
||||
IP.1=192.168.31.108
|
||||
IP.2=127.0.0.1
|
||||
6
certs/win-trace.txt
Normal file
6
certs/win-trace.txt
Normal file
@ -0,0 +1,6 @@
|
||||
== Info: Added api.phone.local:4433:192.168.31.108 to DNS cache
|
||||
== Info: Hostname api.phone.local was found in DNS cache
|
||||
== Info: Trying 192.168.31.108:4433...
|
||||
== Info: schannel: disabled automatic use of client certificate
|
||||
== Info: schannel: AcquireCredentialsHandle failed: SEC_E_ALGORITHM_MISMATCH (0x80090331) - Âçàèìîäåéñòâèå êëèåíòà è ñåðâåðà íåâîçìîæíî, ò.ê. ó íèõ ðàçíûé àëãîðèòì ðàáîòû.
|
||||
== Info: closing connection #0
|
||||
65
device/device.go
Normal file
65
device/device.go
Normal file
@ -0,0 +1,65 @@
|
||||
package device
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
tunnelpb "relay/proto/tunnel"
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
stream tunnelpb.TunnelService_TunnelServer
|
||||
sendCh chan *tunnelpb.Frame
|
||||
done chan struct{}
|
||||
closeOnce sync.Once
|
||||
|
||||
streamsMu sync.Mutex
|
||||
streams map[uint32]net.Conn
|
||||
streamDone map[uint32]chan struct{}
|
||||
nextID uint32
|
||||
}
|
||||
|
||||
func NewDevice(stream tunnelpb.TunnelService_TunnelServer) *Device {
|
||||
d := &Device{
|
||||
stream: stream,
|
||||
sendCh: make(chan *tunnelpb.Frame, 128), // backpressure here
|
||||
done: make(chan struct{}),
|
||||
streams: make(map[uint32]net.Conn),
|
||||
streamDone: make(map[uint32]chan struct{}),
|
||||
nextID: 1,
|
||||
}
|
||||
|
||||
go d.writer()
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *Device) Close() {
|
||||
d.closeOnce.Do(func() {
|
||||
close(d.done)
|
||||
})
|
||||
}
|
||||
|
||||
func (d *Device) SendFrame(f *tunnelpb.Frame) {
|
||||
select {
|
||||
case d.sendCh <- f:
|
||||
case <-d.done:
|
||||
default:
|
||||
log.Println("device backpressure: drop frame")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) writer() {
|
||||
for {
|
||||
select {
|
||||
case f := <-d.sendCh:
|
||||
if err := d.stream.Send(f); err != nil {
|
||||
log.Println("device send error:", err)
|
||||
d.Close()
|
||||
return
|
||||
}
|
||||
case <-d.done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
49
device/streams.go
Normal file
49
device/streams.go
Normal file
@ -0,0 +1,49 @@
|
||||
package device
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func (d *Device) AllocateStreamID() uint32 {
|
||||
d.streamsMu.Lock()
|
||||
defer d.streamsMu.Unlock()
|
||||
|
||||
id := d.nextID
|
||||
d.nextID++
|
||||
return id
|
||||
}
|
||||
|
||||
func (d *Device) AddStream(id uint32, conn net.Conn) chan struct{} {
|
||||
d.streamsMu.Lock()
|
||||
defer d.streamsMu.Unlock()
|
||||
|
||||
ch := make(chan struct{})
|
||||
d.streams[id] = conn
|
||||
d.streamDone[id] = ch
|
||||
return ch
|
||||
}
|
||||
|
||||
func (d *Device) RemoveStream(id uint32) {
|
||||
d.streamsMu.Lock()
|
||||
defer d.streamsMu.Unlock()
|
||||
|
||||
if c, ok := d.streams[id]; ok {
|
||||
_ = c.Close()
|
||||
delete(d.streams, id)
|
||||
}
|
||||
if ch, ok := d.streamDone[id]; ok {
|
||||
close(ch)
|
||||
delete(d.streamDone, id)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Device) GetClient(id uint32) (net.Conn, bool) {
|
||||
d.streamsMu.Lock()
|
||||
defer d.streamsMu.Unlock()
|
||||
c, ok := d.streams[id]
|
||||
return c, ok
|
||||
}
|
||||
|
||||
func (d *Device) Done() <-chan struct{} {
|
||||
return d.done
|
||||
}
|
||||
15
go.mod
Normal file
15
go.mod
Normal file
@ -0,0 +1,15 @@
|
||||
module relay
|
||||
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
google.golang.org/grpc v1.77.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
)
|
||||
|
||||
require (
|
||||
golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
|
||||
)
|
||||
36
go.sum
Normal file
36
go.sum
Normal file
@ -0,0 +1,36 @@
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo=
|
||||
golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
|
||||
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
18
grpcserver/control.go
Normal file
18
grpcserver/control.go
Normal file
@ -0,0 +1,18 @@
|
||||
package grpcserver
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
controlpb "relay/proto/control"
|
||||
)
|
||||
|
||||
type ControlServiceImpl struct {
|
||||
controlpb.UnimplementedControlServiceServer
|
||||
}
|
||||
|
||||
func (s *ControlServiceImpl) RegisterDevice(
|
||||
ctx context.Context,
|
||||
req *controlpb.RegisterRequest,
|
||||
) (*controlpb.RegisterResponse, error) {
|
||||
return &controlpb.RegisterResponse{Success: true}, nil
|
||||
}
|
||||
36
grpcserver/server.go
Normal file
36
grpcserver/server.go
Normal file
@ -0,0 +1,36 @@
|
||||
package grpcserver
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
|
||||
controlpb "relay/proto/control"
|
||||
tunnelpb "relay/proto/tunnel"
|
||||
)
|
||||
|
||||
func Serve(addr string, tlsCfg *tls.Config) {
|
||||
grpcServer := grpc.NewServer(
|
||||
grpc.Creds(credentials.NewTLS(tlsCfg)),
|
||||
grpc.KeepaliveParams(keepalive.ServerParameters{
|
||||
Time: 30 * time.Second,
|
||||
Timeout: 10 * time.Second,
|
||||
}),
|
||||
)
|
||||
|
||||
tunnelpb.RegisterTunnelServiceServer(grpcServer, &TunnelServiceImpl{})
|
||||
controlpb.RegisterControlServiceServer(grpcServer, &ControlServiceImpl{})
|
||||
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Println("gRPC listening on", addr)
|
||||
log.Fatal(grpcServer.Serve(ln))
|
||||
}
|
||||
94
grpcserver/tunnel.go
Normal file
94
grpcserver/tunnel.go
Normal file
@ -0,0 +1,94 @@
|
||||
package grpcserver
|
||||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"relay/device"
|
||||
"relay/registry"
|
||||
|
||||
tunnelpb "relay/proto/tunnel"
|
||||
)
|
||||
|
||||
type TunnelServiceImpl struct {
|
||||
tunnelpb.UnimplementedTunnelServiceServer
|
||||
}
|
||||
|
||||
func (s *TunnelServiceImpl) Tunnel(stream tunnelpb.TunnelService_TunnelServer) error {
|
||||
dev := device.NewDevice(stream)
|
||||
log.Println("Device connected")
|
||||
|
||||
defer func() {
|
||||
log.Println("Device disconnected")
|
||||
dev.Close()
|
||||
registry.Global.Mu.Lock()
|
||||
for d, v := range registry.Global.Domains {
|
||||
if v == dev {
|
||||
registry.Global.Domains[d] = nil
|
||||
log.Println("Domain unbound from device:", d)
|
||||
}
|
||||
}
|
||||
registry.Global.Mu.Unlock()
|
||||
}()
|
||||
|
||||
for {
|
||||
frame, err := stream.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch frame.Type {
|
||||
|
||||
// case tunnelpb.FrameType_FRAME_OPEN:
|
||||
// domain := strings.ToLower(string(frame.Payload))
|
||||
// log.Println("BIND request from device for domain:", domain)
|
||||
// registry.Global.Mu.Lock()
|
||||
// if _, ok := registry.Global.Domains[domain]; ok {
|
||||
// registry.Global.Domains[domain] = dev
|
||||
// log.Println("Domain bound to device:", domain)
|
||||
// } else {
|
||||
// log.Println("Bind rejected, domain not registered:", domain)
|
||||
// }
|
||||
// registry.Global.Mu.Unlock()
|
||||
|
||||
case tunnelpb.FrameType_FRAME_BIND_REQUEST:
|
||||
domain := strings.ToLower(string(frame.Payload))
|
||||
log.Println("BIND request from device for domain:", domain)
|
||||
|
||||
registry.Global.Mu.Lock()
|
||||
if _, ok := registry.Global.Domains[domain]; ok {
|
||||
registry.Global.Domains[domain] = dev
|
||||
registry.Global.Mu.Unlock()
|
||||
|
||||
log.Println("Domain bound to device:", domain)
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_BIND_OK,
|
||||
Payload: []byte(domain),
|
||||
})
|
||||
} else {
|
||||
registry.Global.Mu.Unlock()
|
||||
|
||||
log.Println("Bind rejected, domain not registered:", domain)
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_BIND_REJECTED,
|
||||
Payload: []byte(domain),
|
||||
})
|
||||
}
|
||||
|
||||
case tunnelpb.FrameType_FRAME_DATA:
|
||||
if c, ok := dev.GetClient(frame.StreamId); ok {
|
||||
if _, err := c.Write(frame.Payload); err != nil {
|
||||
dev.RemoveStream(frame.StreamId)
|
||||
}
|
||||
}
|
||||
|
||||
case tunnelpb.FrameType_FRAME_CLOSE:
|
||||
dev.RemoveStream(frame.StreamId)
|
||||
|
||||
case tunnelpb.FrameType_FRAME_PING:
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_PONG,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
82
ingress/handler.go
Normal file
82
ingress/handler.go
Normal file
@ -0,0 +1,82 @@
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"relay/registry"
|
||||
"relay/util"
|
||||
|
||||
tunnelpb "relay/proto/tunnel"
|
||||
)
|
||||
|
||||
func handleClientTCP(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
|
||||
sni, hello, err := peekClientHello(conn)
|
||||
if err != nil {
|
||||
log.Println("peek failed:", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Client SNI:", sni)
|
||||
|
||||
registry.Global.Mu.Lock()
|
||||
dev := registry.Global.Domains[sni]
|
||||
log.Println("Known domains:", util.Keys(registry.Global.Domains))
|
||||
registry.Global.Mu.Unlock()
|
||||
|
||||
if dev == nil {
|
||||
log.Println("No device bound for domain:", sni)
|
||||
conn.Write([]byte("HTTP/1.1 503 No device\r\n\r\n"))
|
||||
return
|
||||
}
|
||||
|
||||
streamID := dev.AllocateStreamID()
|
||||
done := dev.AddStream(streamID, conn)
|
||||
|
||||
log.Printf("Client [%s] → device (stream %d)\n", sni, streamID)
|
||||
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_OPEN,
|
||||
StreamId: streamID,
|
||||
Payload: []byte(sni),
|
||||
})
|
||||
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_DATA,
|
||||
StreamId: streamID,
|
||||
Payload: hello,
|
||||
})
|
||||
|
||||
go func() {
|
||||
buf := util.BufPool.Get().([]byte)
|
||||
defer util.BufPool.Put(buf)
|
||||
|
||||
for {
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_CLOSE,
|
||||
StreamId: streamID,
|
||||
})
|
||||
dev.RemoveStream(streamID)
|
||||
return
|
||||
}
|
||||
|
||||
dev.SendFrame(&tunnelpb.Frame{
|
||||
Type: tunnelpb.FrameType_FRAME_DATA,
|
||||
StreamId: streamID,
|
||||
Payload: append([]byte(nil), buf[:n]...),
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-dev.Done():
|
||||
}
|
||||
|
||||
dev.RemoveStream(streamID)
|
||||
|
||||
}
|
||||
23
ingress/listener.go
Normal file
23
ingress/listener.go
Normal file
@ -0,0 +1,23 @@
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
)
|
||||
|
||||
func Listen(addr string) {
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("HTTPS passthrough listening on", addr)
|
||||
|
||||
for {
|
||||
c, err := ln.Accept()
|
||||
if err != nil {
|
||||
log.Println("accept error:", err)
|
||||
continue
|
||||
}
|
||||
go handleClientTCP(c)
|
||||
}
|
||||
}
|
||||
73
ingress/sni.go
Normal file
73
ingress/sni.go
Normal file
@ -0,0 +1,73 @@
|
||||
package ingress
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func peekClientHello(r io.Reader) (sni string, hello []byte, err error) {
|
||||
br := bufio.NewReader(r)
|
||||
|
||||
hdr, err := br.Peek(5)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if hdr[0] != 0x16 {
|
||||
return "", nil, errors.New("not TLS handshake")
|
||||
}
|
||||
|
||||
recLen := int(binary.BigEndian.Uint16(hdr[3:5]))
|
||||
total := 5 + recLen
|
||||
|
||||
hello, err = br.Peek(total)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
data := hello[5:]
|
||||
if data[0] != 0x01 {
|
||||
return "", hello, errors.New("not ClientHello")
|
||||
}
|
||||
|
||||
i := 4
|
||||
i += 2 + 32
|
||||
|
||||
sidLen := int(data[i])
|
||||
i += 1 + sidLen
|
||||
|
||||
csLen := int(binary.BigEndian.Uint16(data[i:]))
|
||||
i += 2 + csLen
|
||||
|
||||
compLen := int(data[i])
|
||||
i += 1 + compLen
|
||||
|
||||
extLen := int(binary.BigEndian.Uint16(data[i:]))
|
||||
i += 2
|
||||
end := i + extLen
|
||||
|
||||
for i+4 <= end {
|
||||
typ := binary.BigEndian.Uint16(data[i:])
|
||||
sz := int(binary.BigEndian.Uint16(data[i+2:]))
|
||||
i += 4
|
||||
|
||||
if typ == 0x00 {
|
||||
l := int(binary.BigEndian.Uint16(data[i:]))
|
||||
j := i + 2
|
||||
for j+3 < i+l {
|
||||
nameType := data[j]
|
||||
nameLen := int(binary.BigEndian.Uint16(data[j+1:]))
|
||||
if nameType == 0 {
|
||||
sni = strings.ToLower(string(data[j+3 : j+3+nameLen]))
|
||||
return sni, hello, nil
|
||||
}
|
||||
j += 3 + nameLen
|
||||
}
|
||||
}
|
||||
i += sz
|
||||
}
|
||||
|
||||
return "", hello, nil
|
||||
}
|
||||
30
main.go
Normal file
30
main.go
Normal file
@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"relay/admin"
|
||||
"relay/grpcserver"
|
||||
"relay/ingress"
|
||||
"relay/tlsutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
admin.ApiKey = os.Getenv("SECRET_API_KEY")
|
||||
if admin.ApiKey == "" {
|
||||
log.Fatal("SECRET_API_KEY is not set")
|
||||
}
|
||||
|
||||
tlsCfg, err := tlsutil.GRPCTLSConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
admin.InitLogger()
|
||||
|
||||
go admin.Serve(":8443")
|
||||
go grpcserver.Serve(":50051", tlsCfg)
|
||||
|
||||
ingress.Listen(":443")
|
||||
}
|
||||
46
proto/control.proto
Normal file
46
proto/control.proto
Normal file
@ -0,0 +1,46 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package control;
|
||||
|
||||
option go_package = "relay/proto/control;controlpb";
|
||||
option java_package = "com.projects.httpsserverapp.control.v1";
|
||||
option java_multiple_files = true;
|
||||
|
||||
service ControlService {
|
||||
|
||||
// Регистрация устройства и доменов
|
||||
rpc RegisterDevice(RegisterRequest)
|
||||
returns (RegisterResponse);
|
||||
|
||||
// Получить список доменов
|
||||
rpc ListDomains(ListDomainsRequest)
|
||||
returns (ListDomainsResponse);
|
||||
|
||||
// Отвязать домен
|
||||
rpc UnregisterDomain(UnregisterDomainRequest)
|
||||
returns (UnregisterDomainResponse);
|
||||
}
|
||||
|
||||
message RegisterRequest {
|
||||
string device_id = 1;
|
||||
repeated string domains = 2;
|
||||
}
|
||||
|
||||
message RegisterResponse {
|
||||
bool success = 1;
|
||||
string message = 2;
|
||||
}
|
||||
|
||||
message ListDomainsRequest {}
|
||||
|
||||
message ListDomainsResponse {
|
||||
repeated string domains = 1;
|
||||
}
|
||||
|
||||
message UnregisterDomainRequest {
|
||||
string domain = 1;
|
||||
}
|
||||
|
||||
message UnregisterDomainResponse {
|
||||
bool success = 1;
|
||||
}
|
||||
492
proto/control/control.pb.go
Normal file
492
proto/control/control.pb.go
Normal file
@ -0,0 +1,492 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v6.33.1
|
||||
// source: control.proto
|
||||
|
||||
package controlpb
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type RegisterRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
DeviceId string `protobuf:"bytes,1,opt,name=device_id,json=deviceId,proto3" json:"device_id,omitempty"`
|
||||
Domains []string `protobuf:"bytes,2,rep,name=domains,proto3" json:"domains,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RegisterRequest) Reset() {
|
||||
*x = RegisterRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_control_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RegisterRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RegisterRequest) ProtoMessage() {}
|
||||
|
||||
func (x *RegisterRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_control_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RegisterRequest.ProtoReflect.Descriptor instead.
|
||||
func (*RegisterRequest) Descriptor() ([]byte, []int) {
|
||||
return file_control_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *RegisterRequest) GetDeviceId() string {
|
||||
if x != nil {
|
||||
return x.DeviceId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RegisterRequest) GetDomains() []string {
|
||||
if x != nil {
|
||||
return x.Domains
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RegisterResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
Message string `protobuf:"bytes,2,opt,name=message,proto3" json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RegisterResponse) Reset() {
|
||||
*x = RegisterResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_control_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RegisterResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RegisterResponse) ProtoMessage() {}
|
||||
|
||||
func (x *RegisterResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_control_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RegisterResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RegisterResponse) Descriptor() ([]byte, []int) {
|
||||
return file_control_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *RegisterResponse) GetSuccess() bool {
|
||||
if x != nil {
|
||||
return x.Success
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *RegisterResponse) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ListDomainsRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *ListDomainsRequest) Reset() {
|
||||
*x = ListDomainsRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_control_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ListDomainsRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListDomainsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListDomainsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_control_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListDomainsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListDomainsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_control_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
type ListDomainsResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Domains []string `protobuf:"bytes,1,rep,name=domains,proto3" json:"domains,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ListDomainsResponse) Reset() {
|
||||
*x = ListDomainsResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_control_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ListDomainsResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListDomainsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListDomainsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_control_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListDomainsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListDomainsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_control_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *ListDomainsResponse) GetDomains() []string {
|
||||
if x != nil {
|
||||
return x.Domains
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UnregisterDomainRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UnregisterDomainRequest) Reset() {
|
||||
*x = UnregisterDomainRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_control_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *UnregisterDomainRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UnregisterDomainRequest) ProtoMessage() {}
|
||||
|
||||
func (x *UnregisterDomainRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_control_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UnregisterDomainRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UnregisterDomainRequest) Descriptor() ([]byte, []int) {
|
||||
return file_control_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *UnregisterDomainRequest) GetDomain() string {
|
||||
if x != nil {
|
||||
return x.Domain
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type UnregisterDomainResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UnregisterDomainResponse) Reset() {
|
||||
*x = UnregisterDomainResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_control_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *UnregisterDomainResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UnregisterDomainResponse) ProtoMessage() {}
|
||||
|
||||
func (x *UnregisterDomainResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_control_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UnregisterDomainResponse.ProtoReflect.Descriptor instead.
|
||||
func (*UnregisterDomainResponse) Descriptor() ([]byte, []int) {
|
||||
return file_control_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *UnregisterDomainResponse) GetSuccess() bool {
|
||||
if x != nil {
|
||||
return x.Success
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var File_control_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_control_proto_rawDesc = []byte{
|
||||
0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
|
||||
0x07, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x22, 0x48, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69,
|
||||
0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64,
|
||||
0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x73, 0x22, 0x46, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73,
|
||||
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x14, 0x0a, 0x12, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x22, 0x2f, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x6f, 0x6d, 0x61, 0x69,
|
||||
0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e,
|
||||
0x73, 0x22, 0x31, 0x0a, 0x17, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44,
|
||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f,
|
||||
0x6d, 0x61, 0x69, 0x6e, 0x22, 0x34, 0x0a, 0x18, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74,
|
||||
0x65, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x32, 0xfa, 0x01, 0x0a, 0x0e, 0x43,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x45, 0x0a,
|
||||
0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12,
|
||||
0x18, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
|
||||
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x4c, 0x69,
|
||||
0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x1c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44,
|
||||
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57,
|
||||
0x0a, 0x10, 0x55, 0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x6f, 0x6d, 0x61,
|
||||
0x69, 0x6e, 0x12, 0x20, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x55, 0x6e, 0x72,
|
||||
0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x55,
|
||||
0x6e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x49, 0x0a, 0x26, 0x63, 0x6f, 0x6d, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x73, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x61, 0x70, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x76,
|
||||
0x31, 0x50, 0x01, 0x5a, 0x1d, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x3b, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_control_proto_rawDescOnce sync.Once
|
||||
file_control_proto_rawDescData = file_control_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_control_proto_rawDescGZIP() []byte {
|
||||
file_control_proto_rawDescOnce.Do(func() {
|
||||
file_control_proto_rawDescData = protoimpl.X.CompressGZIP(file_control_proto_rawDescData)
|
||||
})
|
||||
return file_control_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_control_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||
var file_control_proto_goTypes = []interface{}{
|
||||
(*RegisterRequest)(nil), // 0: control.RegisterRequest
|
||||
(*RegisterResponse)(nil), // 1: control.RegisterResponse
|
||||
(*ListDomainsRequest)(nil), // 2: control.ListDomainsRequest
|
||||
(*ListDomainsResponse)(nil), // 3: control.ListDomainsResponse
|
||||
(*UnregisterDomainRequest)(nil), // 4: control.UnregisterDomainRequest
|
||||
(*UnregisterDomainResponse)(nil), // 5: control.UnregisterDomainResponse
|
||||
}
|
||||
var file_control_proto_depIdxs = []int32{
|
||||
0, // 0: control.ControlService.RegisterDevice:input_type -> control.RegisterRequest
|
||||
2, // 1: control.ControlService.ListDomains:input_type -> control.ListDomainsRequest
|
||||
4, // 2: control.ControlService.UnregisterDomain:input_type -> control.UnregisterDomainRequest
|
||||
1, // 3: control.ControlService.RegisterDevice:output_type -> control.RegisterResponse
|
||||
3, // 4: control.ControlService.ListDomains:output_type -> control.ListDomainsResponse
|
||||
5, // 5: control.ControlService.UnregisterDomain:output_type -> control.UnregisterDomainResponse
|
||||
3, // [3:6] is the sub-list for method output_type
|
||||
0, // [0:3] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_control_proto_init() }
|
||||
func file_control_proto_init() {
|
||||
if File_control_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_control_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RegisterRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_control_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RegisterResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_control_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ListDomainsRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_control_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ListDomainsResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_control_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*UnregisterDomainRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_control_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*UnregisterDomainResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_control_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 6,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_control_proto_goTypes,
|
||||
DependencyIndexes: file_control_proto_depIdxs,
|
||||
MessageInfos: file_control_proto_msgTypes,
|
||||
}.Build()
|
||||
File_control_proto = out.File
|
||||
file_control_proto_rawDesc = nil
|
||||
file_control_proto_goTypes = nil
|
||||
file_control_proto_depIdxs = nil
|
||||
}
|
||||
189
proto/control/control_grpc.pb.go
Normal file
189
proto/control/control_grpc.pb.go
Normal file
@ -0,0 +1,189 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v6.33.1
|
||||
// source: control.proto
|
||||
|
||||
package controlpb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
ControlService_RegisterDevice_FullMethodName = "/control.ControlService/RegisterDevice"
|
||||
ControlService_ListDomains_FullMethodName = "/control.ControlService/ListDomains"
|
||||
ControlService_UnregisterDomain_FullMethodName = "/control.ControlService/UnregisterDomain"
|
||||
)
|
||||
|
||||
// ControlServiceClient is the client API for ControlService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type ControlServiceClient interface {
|
||||
// Регистрация устройства и доменов
|
||||
RegisterDevice(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error)
|
||||
// Получить список доменов
|
||||
ListDomains(ctx context.Context, in *ListDomainsRequest, opts ...grpc.CallOption) (*ListDomainsResponse, error)
|
||||
// Отвязать домен
|
||||
UnregisterDomain(ctx context.Context, in *UnregisterDomainRequest, opts ...grpc.CallOption) (*UnregisterDomainResponse, error)
|
||||
}
|
||||
|
||||
type controlServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewControlServiceClient(cc grpc.ClientConnInterface) ControlServiceClient {
|
||||
return &controlServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *controlServiceClient) RegisterDevice(ctx context.Context, in *RegisterRequest, opts ...grpc.CallOption) (*RegisterResponse, error) {
|
||||
out := new(RegisterResponse)
|
||||
err := c.cc.Invoke(ctx, ControlService_RegisterDevice_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *controlServiceClient) ListDomains(ctx context.Context, in *ListDomainsRequest, opts ...grpc.CallOption) (*ListDomainsResponse, error) {
|
||||
out := new(ListDomainsResponse)
|
||||
err := c.cc.Invoke(ctx, ControlService_ListDomains_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *controlServiceClient) UnregisterDomain(ctx context.Context, in *UnregisterDomainRequest, opts ...grpc.CallOption) (*UnregisterDomainResponse, error) {
|
||||
out := new(UnregisterDomainResponse)
|
||||
err := c.cc.Invoke(ctx, ControlService_UnregisterDomain_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ControlServiceServer is the server API for ControlService service.
|
||||
// All implementations must embed UnimplementedControlServiceServer
|
||||
// for forward compatibility
|
||||
type ControlServiceServer interface {
|
||||
// Регистрация устройства и доменов
|
||||
RegisterDevice(context.Context, *RegisterRequest) (*RegisterResponse, error)
|
||||
// Получить список доменов
|
||||
ListDomains(context.Context, *ListDomainsRequest) (*ListDomainsResponse, error)
|
||||
// Отвязать домен
|
||||
UnregisterDomain(context.Context, *UnregisterDomainRequest) (*UnregisterDomainResponse, error)
|
||||
mustEmbedUnimplementedControlServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedControlServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedControlServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedControlServiceServer) RegisterDevice(context.Context, *RegisterRequest) (*RegisterResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RegisterDevice not implemented")
|
||||
}
|
||||
func (UnimplementedControlServiceServer) ListDomains(context.Context, *ListDomainsRequest) (*ListDomainsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListDomains not implemented")
|
||||
}
|
||||
func (UnimplementedControlServiceServer) UnregisterDomain(context.Context, *UnregisterDomainRequest) (*UnregisterDomainResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UnregisterDomain not implemented")
|
||||
}
|
||||
func (UnimplementedControlServiceServer) mustEmbedUnimplementedControlServiceServer() {}
|
||||
|
||||
// UnsafeControlServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to ControlServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeControlServiceServer interface {
|
||||
mustEmbedUnimplementedControlServiceServer()
|
||||
}
|
||||
|
||||
func RegisterControlServiceServer(s grpc.ServiceRegistrar, srv ControlServiceServer) {
|
||||
s.RegisterService(&ControlService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _ControlService_RegisterDevice_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RegisterRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ControlServiceServer).RegisterDevice(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ControlService_RegisterDevice_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ControlServiceServer).RegisterDevice(ctx, req.(*RegisterRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ControlService_ListDomains_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListDomainsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ControlServiceServer).ListDomains(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ControlService_ListDomains_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ControlServiceServer).ListDomains(ctx, req.(*ListDomainsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ControlService_UnregisterDomain_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UnregisterDomainRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ControlServiceServer).UnregisterDomain(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ControlService_UnregisterDomain_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ControlServiceServer).UnregisterDomain(ctx, req.(*UnregisterDomainRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// ControlService_ServiceDesc is the grpc.ServiceDesc for ControlService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var ControlService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "control.ControlService",
|
||||
HandlerType: (*ControlServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "RegisterDevice",
|
||||
Handler: _ControlService_RegisterDevice_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListDomains",
|
||||
Handler: _ControlService_ListDomains_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UnregisterDomain",
|
||||
Handler: _ControlService_UnregisterDomain_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "control.proto",
|
||||
}
|
||||
32
proto/tunnel.proto
Normal file
32
proto/tunnel.proto
Normal file
@ -0,0 +1,32 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package tunnel;
|
||||
|
||||
option go_package = "relay/proto/tunnel;tunnelpb";
|
||||
option java_package = "com.projects.httpsserverapp.tunnel.v1";
|
||||
option java_multiple_files = true;
|
||||
|
||||
service TunnelService {
|
||||
rpc Tunnel(stream Frame) returns (stream Frame);
|
||||
}
|
||||
|
||||
enum FrameType {
|
||||
FRAME_UNSPECIFIED = 0;
|
||||
|
||||
FRAME_OPEN = 1; // открыть TCP stream
|
||||
FRAME_DATA = 2;
|
||||
FRAME_CLOSE = 3;
|
||||
|
||||
FRAME_PING = 4;
|
||||
FRAME_PONG = 5;
|
||||
|
||||
FRAME_BIND_REQUEST = 10; // device → relay
|
||||
FRAME_BIND_OK = 11; // relay → device
|
||||
FRAME_BIND_REJECTED = 12; // relay → device
|
||||
}
|
||||
|
||||
message Frame {
|
||||
FrameType type = 1;
|
||||
uint32 stream_id = 2;
|
||||
bytes payload = 3;
|
||||
}
|
||||
254
proto/tunnel/tunnel.pb.go
Normal file
254
proto/tunnel/tunnel.pb.go
Normal file
@ -0,0 +1,254 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.31.0
|
||||
// protoc v6.33.1
|
||||
// source: tunnel.proto
|
||||
|
||||
package tunnelpb
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type FrameType int32
|
||||
|
||||
const (
|
||||
FrameType_FRAME_UNSPECIFIED FrameType = 0
|
||||
FrameType_FRAME_OPEN FrameType = 1 // открыть TCP stream
|
||||
FrameType_FRAME_DATA FrameType = 2
|
||||
FrameType_FRAME_CLOSE FrameType = 3
|
||||
FrameType_FRAME_PING FrameType = 4
|
||||
FrameType_FRAME_PONG FrameType = 5
|
||||
FrameType_FRAME_BIND_REQUEST FrameType = 10 // device → relay
|
||||
FrameType_FRAME_BIND_OK FrameType = 11 // relay → device
|
||||
FrameType_FRAME_BIND_REJECTED FrameType = 12 // relay → device
|
||||
)
|
||||
|
||||
// Enum value maps for FrameType.
|
||||
var (
|
||||
FrameType_name = map[int32]string{
|
||||
0: "FRAME_UNSPECIFIED",
|
||||
1: "FRAME_OPEN",
|
||||
2: "FRAME_DATA",
|
||||
3: "FRAME_CLOSE",
|
||||
4: "FRAME_PING",
|
||||
5: "FRAME_PONG",
|
||||
10: "FRAME_BIND_REQUEST",
|
||||
11: "FRAME_BIND_OK",
|
||||
12: "FRAME_BIND_REJECTED",
|
||||
}
|
||||
FrameType_value = map[string]int32{
|
||||
"FRAME_UNSPECIFIED": 0,
|
||||
"FRAME_OPEN": 1,
|
||||
"FRAME_DATA": 2,
|
||||
"FRAME_CLOSE": 3,
|
||||
"FRAME_PING": 4,
|
||||
"FRAME_PONG": 5,
|
||||
"FRAME_BIND_REQUEST": 10,
|
||||
"FRAME_BIND_OK": 11,
|
||||
"FRAME_BIND_REJECTED": 12,
|
||||
}
|
||||
)
|
||||
|
||||
func (x FrameType) Enum() *FrameType {
|
||||
p := new(FrameType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x FrameType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (FrameType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_tunnel_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (FrameType) Type() protoreflect.EnumType {
|
||||
return &file_tunnel_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x FrameType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FrameType.Descriptor instead.
|
||||
func (FrameType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_tunnel_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type Frame struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Type FrameType `protobuf:"varint,1,opt,name=type,proto3,enum=tunnel.FrameType" json:"type,omitempty"`
|
||||
StreamId uint32 `protobuf:"varint,2,opt,name=stream_id,json=streamId,proto3" json:"stream_id,omitempty"`
|
||||
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Frame) Reset() {
|
||||
*x = Frame{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_tunnel_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Frame) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Frame) ProtoMessage() {}
|
||||
|
||||
func (x *Frame) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_tunnel_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Frame.ProtoReflect.Descriptor instead.
|
||||
func (*Frame) Descriptor() ([]byte, []int) {
|
||||
return file_tunnel_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Frame) GetType() FrameType {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return FrameType_FRAME_UNSPECIFIED
|
||||
}
|
||||
|
||||
func (x *Frame) GetStreamId() uint32 {
|
||||
if x != nil {
|
||||
return x.StreamId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Frame) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_tunnel_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_tunnel_proto_rawDesc = []byte{
|
||||
0x0a, 0x0c, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06,
|
||||
0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x22, 0x65, 0x0a, 0x05, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12,
|
||||
0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e,
|
||||
0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65,
|
||||
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x74, 0x72, 0x65, 0x61,
|
||||
0x6d, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2a, 0xb7, 0x01,
|
||||
0x0a, 0x09, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x15, 0x0a, 0x11, 0x46,
|
||||
0x52, 0x41, 0x4d, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44,
|
||||
0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x4f, 0x50, 0x45, 0x4e,
|
||||
0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x44, 0x41, 0x54, 0x41,
|
||||
0x10, 0x02, 0x12, 0x0f, 0x0a, 0x0b, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x43, 0x4c, 0x4f, 0x53,
|
||||
0x45, 0x10, 0x03, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x50, 0x49, 0x4e,
|
||||
0x47, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x50, 0x4f, 0x4e,
|
||||
0x47, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x42, 0x49, 0x4e,
|
||||
0x44, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x0a, 0x12, 0x11, 0x0a, 0x0d, 0x46,
|
||||
0x52, 0x41, 0x4d, 0x45, 0x5f, 0x42, 0x49, 0x4e, 0x44, 0x5f, 0x4f, 0x4b, 0x10, 0x0b, 0x12, 0x17,
|
||||
0x0a, 0x13, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x42, 0x49, 0x4e, 0x44, 0x5f, 0x52, 0x45, 0x4a,
|
||||
0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x0c, 0x32, 0x3b, 0x0a, 0x0d, 0x54, 0x75, 0x6e, 0x6e, 0x65,
|
||||
0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x54, 0x75, 0x6e, 0x6e,
|
||||
0x65, 0x6c, 0x12, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x46, 0x72, 0x61, 0x6d,
|
||||
0x65, 0x1a, 0x0d, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x46, 0x72, 0x61, 0x6d, 0x65,
|
||||
0x28, 0x01, 0x30, 0x01, 0x42, 0x46, 0x0a, 0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x6a,
|
||||
0x65, 0x63, 0x74, 0x73, 0x2e, 0x68, 0x74, 0x74, 0x70, 0x73, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x2e, 0x76, 0x31, 0x50, 0x01, 0x5a,
|
||||
0x1b, 0x72, 0x65, 0x6c, 0x61, 0x79, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x74, 0x75, 0x6e,
|
||||
0x6e, 0x65, 0x6c, 0x3b, 0x74, 0x75, 0x6e, 0x6e, 0x65, 0x6c, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_tunnel_proto_rawDescOnce sync.Once
|
||||
file_tunnel_proto_rawDescData = file_tunnel_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_tunnel_proto_rawDescGZIP() []byte {
|
||||
file_tunnel_proto_rawDescOnce.Do(func() {
|
||||
file_tunnel_proto_rawDescData = protoimpl.X.CompressGZIP(file_tunnel_proto_rawDescData)
|
||||
})
|
||||
return file_tunnel_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_tunnel_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_tunnel_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_tunnel_proto_goTypes = []interface{}{
|
||||
(FrameType)(0), // 0: tunnel.FrameType
|
||||
(*Frame)(nil), // 1: tunnel.Frame
|
||||
}
|
||||
var file_tunnel_proto_depIdxs = []int32{
|
||||
0, // 0: tunnel.Frame.type:type_name -> tunnel.FrameType
|
||||
1, // 1: tunnel.TunnelService.Tunnel:input_type -> tunnel.Frame
|
||||
1, // 2: tunnel.TunnelService.Tunnel:output_type -> tunnel.Frame
|
||||
2, // [2:3] is the sub-list for method output_type
|
||||
1, // [1:2] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_tunnel_proto_init() }
|
||||
func file_tunnel_proto_init() {
|
||||
if File_tunnel_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_tunnel_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Frame); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_tunnel_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_tunnel_proto_goTypes,
|
||||
DependencyIndexes: file_tunnel_proto_depIdxs,
|
||||
EnumInfos: file_tunnel_proto_enumTypes,
|
||||
MessageInfos: file_tunnel_proto_msgTypes,
|
||||
}.Build()
|
||||
File_tunnel_proto = out.File
|
||||
file_tunnel_proto_rawDesc = nil
|
||||
file_tunnel_proto_goTypes = nil
|
||||
file_tunnel_proto_depIdxs = nil
|
||||
}
|
||||
141
proto/tunnel/tunnel_grpc.pb.go
Normal file
141
proto/tunnel/tunnel_grpc.pb.go
Normal file
@ -0,0 +1,141 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v6.33.1
|
||||
// source: tunnel.proto
|
||||
|
||||
package tunnelpb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
TunnelService_Tunnel_FullMethodName = "/tunnel.TunnelService/Tunnel"
|
||||
)
|
||||
|
||||
// TunnelServiceClient is the client API for TunnelService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type TunnelServiceClient interface {
|
||||
Tunnel(ctx context.Context, opts ...grpc.CallOption) (TunnelService_TunnelClient, error)
|
||||
}
|
||||
|
||||
type tunnelServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewTunnelServiceClient(cc grpc.ClientConnInterface) TunnelServiceClient {
|
||||
return &tunnelServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *tunnelServiceClient) Tunnel(ctx context.Context, opts ...grpc.CallOption) (TunnelService_TunnelClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &TunnelService_ServiceDesc.Streams[0], TunnelService_Tunnel_FullMethodName, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &tunnelServiceTunnelClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type TunnelService_TunnelClient interface {
|
||||
Send(*Frame) error
|
||||
Recv() (*Frame, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type tunnelServiceTunnelClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *tunnelServiceTunnelClient) Send(m *Frame) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *tunnelServiceTunnelClient) Recv() (*Frame, error) {
|
||||
m := new(Frame)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// TunnelServiceServer is the server API for TunnelService service.
|
||||
// All implementations must embed UnimplementedTunnelServiceServer
|
||||
// for forward compatibility
|
||||
type TunnelServiceServer interface {
|
||||
Tunnel(TunnelService_TunnelServer) error
|
||||
mustEmbedUnimplementedTunnelServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedTunnelServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedTunnelServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedTunnelServiceServer) Tunnel(TunnelService_TunnelServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method Tunnel not implemented")
|
||||
}
|
||||
func (UnimplementedTunnelServiceServer) mustEmbedUnimplementedTunnelServiceServer() {}
|
||||
|
||||
// UnsafeTunnelServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to TunnelServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeTunnelServiceServer interface {
|
||||
mustEmbedUnimplementedTunnelServiceServer()
|
||||
}
|
||||
|
||||
func RegisterTunnelServiceServer(s grpc.ServiceRegistrar, srv TunnelServiceServer) {
|
||||
s.RegisterService(&TunnelService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _TunnelService_Tunnel_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(TunnelServiceServer).Tunnel(&tunnelServiceTunnelServer{stream})
|
||||
}
|
||||
|
||||
type TunnelService_TunnelServer interface {
|
||||
Send(*Frame) error
|
||||
Recv() (*Frame, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type tunnelServiceTunnelServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *tunnelServiceTunnelServer) Send(m *Frame) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *tunnelServiceTunnelServer) Recv() (*Frame, error) {
|
||||
m := new(Frame)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// TunnelService_ServiceDesc is the grpc.ServiceDesc for TunnelService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var TunnelService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "tunnel.TunnelService",
|
||||
HandlerType: (*TunnelServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "Tunnel",
|
||||
Handler: _TunnelService_Tunnel_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "tunnel.proto",
|
||||
}
|
||||
15
registry/registry.go
Normal file
15
registry/registry.go
Normal file
@ -0,0 +1,15 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"relay/device"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Registry struct {
|
||||
Mu sync.Mutex
|
||||
Domains map[string]*device.Device
|
||||
}
|
||||
|
||||
var Global = &Registry{
|
||||
Domains: make(map[string]*device.Device),
|
||||
}
|
||||
33
run_relay.bat
Normal file
33
run_relay.bat
Normal file
@ -0,0 +1,33 @@
|
||||
@echo off
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
|
||||
set SECRET_API_KEY=VNJ9L-BBBIM-6CJGZ-MO5AZ
|
||||
set CERT_DIR=certs
|
||||
set ADMIN_CERT=%CERT_DIR%\admin.crt
|
||||
set ADMIN_KEY=%CERT_DIR%\admin.key
|
||||
|
||||
if not exist "%ADMIN_CERT%" (
|
||||
echo [ERROR] admin.crt not found in %CERT_DIR%
|
||||
goto :error
|
||||
)
|
||||
|
||||
if not exist "%ADMIN_KEY%" (
|
||||
echo [ERROR] admin.key not found in %CERT_DIR%
|
||||
goto :error
|
||||
)
|
||||
|
||||
echo [OK] Certificates found
|
||||
echo [INFO] Starting relay server...
|
||||
echo.
|
||||
|
||||
go run .
|
||||
|
||||
goto :eof
|
||||
|
||||
:error
|
||||
echo.
|
||||
echo Fix the error and try again.
|
||||
pause
|
||||
exit /b 1
|
||||
29
tlsutil/config.go
Normal file
29
tlsutil/config.go
Normal file
@ -0,0 +1,29 @@
|
||||
package tlsutil
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func GRPCTLSConfig() (*tls.Config, error) {
|
||||
cert, err := tls.LoadX509KeyPair("certs/server.crt", "certs/server.key")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
caPEM, err := ioutil.ReadFile("certs/ca.crt")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
caPool := x509.NewCertPool()
|
||||
caPool.AppendCertsFromPEM(caPEM)
|
||||
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
ClientCAs: caPool,
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}, nil
|
||||
}
|
||||
9
util/bufpool.go
Normal file
9
util/bufpool.go
Normal file
@ -0,0 +1,9 @@
|
||||
package util
|
||||
|
||||
import "sync"
|
||||
|
||||
var BufPool = sync.Pool{
|
||||
New: func() any {
|
||||
return make([]byte, 4096)
|
||||
},
|
||||
}
|
||||
11
util/mapkeys.go
Normal file
11
util/mapkeys.go
Normal file
@ -0,0 +1,11 @@
|
||||
package util
|
||||
|
||||
import "relay/device"
|
||||
|
||||
func Keys(m map[string]*device.Device) []string {
|
||||
out := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
out = append(out, k)
|
||||
}
|
||||
return out
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user