-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathremote_access.go
166 lines (133 loc) · 4.33 KB
/
remote_access.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright 2023 qbee.io
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
package client
import (
"fmt"
"strconv"
"strings"
)
// Network protocols supported by the remote access.
const (
TCP = "tcp"
UDP = "udp"
)
// RemoteAccessConnection defines a remote access connection.
type RemoteAccessConnection struct {
// DeviceID is the device ID of the device to which the remote access connection belongs.
DeviceID string `json:"device_id"`
// Targets is a list of remote access targets.
Targets []string `json:"targets"`
}
// RemoteAccessTarget defines
type RemoteAccessTarget struct {
// Protocol is the protocol used for the remote access.
// Can be either "tcp" or "udp".
Protocol string
// LocalHost is the address on which the local port is bound.
// Set to "localhost" to bind to the loopback interface.
LocalHost string
// LocalPort is the port on the local machine to which the remote port is forwarded.
LocalPort string
// RemoteHost is the host of the remote machine to which the local port is forwarded.
RemoteHost string
// RemotePort is the port on the remote machine to which the local port is forwarded.
RemotePort string
}
// IsValidDeviceID checks if the provided device ID is valid.
func IsValidDeviceID(deviceID string) bool {
// make sure length is correct before we check the content
if len(deviceID) != 64 {
return false
}
// iterate over every character and make sure it is a valid hex character
for _, c := range deviceID {
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) {
return false
}
}
return true
}
// ParseRemoteAccessTarget parses a remote access target string.
// The target string has the following format:
// [<local_host>:]<local_port>:<remote_host>:<remote_port>[/udp]
func ParseRemoteAccessTarget(targetString string) (RemoteAccessTarget, error) {
target := RemoteAccessTarget{}
// Split the target string into its parts.
parts := strings.Split(targetString, ":")
if len(parts) != 3 && len(parts) != 4 {
return target, fmt.Errorf("invalid format")
}
var err error
var localHost string
var localPort string
var remoteHost string
var remotePort string
if len(parts) == 3 {
localHost = "localhost"
localPort = parts[0]
remoteHost = parts[1]
remotePort = parts[2]
} else {
localHost = parts[0]
localPort = parts[1]
remoteHost = parts[2]
remotePort = parts[3]
}
target.LocalHost = localHost
target.RemoteHost = remoteHost
if target.LocalPort, err = parseLocalNetworkPort(localPort); err != nil {
return target, fmt.Errorf("invalid local port: %w", err)
}
if strings.HasSuffix(remotePort, "/udp") {
target.Protocol = UDP
remotePort = strings.TrimSuffix(remotePort, "/udp")
} else {
target.Protocol = TCP
}
if target.RemotePort, err = parseNetworkPort(remotePort); err != nil {
return target, fmt.Errorf("invalid remote port: %w", err)
}
return target, nil
}
// String returns the string representation of a remote access target.
func (target RemoteAccessTarget) String() string {
base := fmt.Sprintf("%s:%s:%s:%s", target.LocalHost, target.LocalPort, target.RemoteHost, target.RemotePort)
if target.Protocol == UDP {
return base + "/udp"
}
return base
}
// parseLocalNetworkPort parses a network port string and accepts either a port number or "stdio".
func parseLocalNetworkPort(portString string) (string, error) {
if portString == "stdio" {
return portString, nil
}
if _, err := parseNetworkPort(portString); err != nil {
return "", err
}
return portString, nil
}
// parseNetworkPort parses a network port string and accepts a port number.
func parseNetworkPort(portString string) (string, error) {
if portString == "" {
return "", fmt.Errorf("empty port")
}
_, err := strconv.ParseUint(portString, 10, 16)
if err != nil {
return "", fmt.Errorf("invalid port number")
}
return portString, nil
}