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-----
|
||||||
|
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
|
||||||
|
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-----
|
||||||
|
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
|
||||||
|
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