blob: b3ae0eadca84bfd8509a5110ed34a6c8fd0aefac (
plain)
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
|
//
// Socks5UsernamePasswordCommand.swift
// MullvadREST
//
// Created by Marco Nikic on 2023-12-13.
// Copyright © 2025 Mullvad VPN AB. All rights reserved.
//
import Foundation
/**
The payload sent to the server is the following diagram
+----+------+----------+------+----------+
|VER | ULEN | UNAME | PLEN | PASSWD |
+----+------+----------+------+----------+
| 1 | 1 | 1 to 255 | 1 | 1 to 255 |
+----+------+----------+------+----------+
VER: The current version of this method, always 1
ULEN: The length of `username`
UNAME: The username
PLEN: The length of `password`
PASSWD: The password
**/
struct Socks5UsernamePasswordCommand {
let username: String
let password: String
var rawData: Data {
var data = Data()
guard username.count < UInt8.max,
password.count < UInt8.max,
let usernameData = username.data(using: .utf8),
let passwordData = password.data(using: .utf8)
else { return data }
// Protocol version
data.append(Socks5Constants.usernamePasswordAuthenticationProtocol)
// Username length
data.append(UInt8(username.count))
// Username
data.append(usernameData)
// Password length
data.append(UInt8(password.count))
// Password
data.append(passwordData)
return data
}
}
/**
The expected answer payload looks like this
+-----+--------+
| VER | STATUS |
+-----+--------+
| 1 | 1 |
+-----+--------+
*/
struct Socks5UsernamePasswordReply {
let version: UInt8
let status: Socks5StatusCode
/// - Parameter data: The bytes read from the network connection sent by a socks5 server as a reply to a `Socks5UsernamePasswordCommand`.
init?(from data: Data) {
let expectedSize = MemoryLayout<Self>.size
guard data.count == expectedSize else { return nil }
var iterator = data.makeIterator()
guard let readVersion = iterator.next(),
readVersion == Socks5Constants.usernamePasswordAuthenticationProtocol
else { return nil }
self.version = readVersion
guard let readStatus = iterator.next(),
let statusCode = Socks5StatusCode(rawValue: readStatus)
else { return nil }
self.status = statusCode
}
}
|