ObjFW  Diff

Differences From Artifact [8b7939a5bd]:

To Artifact [f0cdd75885]:


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
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#import "OFTCPSocket+SOCKS5.h"


#import "OFConnectionFailedException.h"






/* Reference for static linking */
int _OFTCPSocket_SOCKS5_reference;




























@implementation OFTCPSocket (SOCKS5)
- (void)OF_SOCKS5ConnectToHost: (OFString*)host
			  port: (uint16_t)port
{
	const char request[] = { 5, 1, 0, 3 };
	char reply[256];


	bool wasWriteBuffered;



	/* 5 1 0 -> no authentication */
	[self writeBuffer: request
		   length: 3];

	[self readIntoBuffer: reply
		 exactLength: 2];

	if (reply[0] != 5 || reply[1] != 0) {
		[self close];
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
	}

	wasWriteBuffered = [self isWriteBuffered];
	[self setWriteBuffered: true];


	/* CONNECT request */
	[self writeBuffer: request
		   length: 4];

	[self writeInt8: [host UTF8StringLength]];

	[self writeBuffer: [host UTF8String]

		   length: [host UTF8StringLength]];
	[self writeBigEndianInt16: port];




	[self flushWriteBuffer];

	[self setWriteBuffered: wasWriteBuffered];


	[self readIntoBuffer: reply
		 exactLength: 4];

	if (reply[0] != 5 || reply[1] != 0 || reply[2] != 0) {
		[self close];
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
	}

	/* Skip the rest of the reply */
	switch (reply[3]) {
	case 1: /* IPv4 */
		[self readIntoBuffer: reply
			 exactLength: 4];
		break;
	case 3: /* Domainname */
		[self readIntoBuffer: reply
			 exactLength: [self readInt8]];
		break;
	case 4: /* IPv6 */
		[self readIntoBuffer: reply
			 exactLength: 16];
		break;
	default:
		[self close];
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
	}

	[self readBigEndianInt16];
}
@end







>


>
>
>

>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|

>
>
|
>
>


|
<

<
|








|
|
>

<
|
|
>
|
>
|
>
|
|
>
>
>

|
>
|
>

<
|











<
|


|
|


<
|








|


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
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#import "OFTCPSocket+SOCKS5.h"
#import "OFDataArray.h"

#import "OFConnectionFailedException.h"
#import "OFOutOfRangeException.h"
#import "OFReadFailedException.h"
#import "OFWriteFailedException.h"

#import "socket_helpers.h"

/* Reference for static linking */
int _OFTCPSocket_SOCKS5_reference;

static void
send_or_exception(OFTCPSocket *self, int socket, char *buffer, size_t length)
{
	if (send(socket, buffer, length, 0) != length)
		@throw [OFWriteFailedException
		    exceptionWithObject: self
			requestedLength: length
				  errNo: of_socket_errno()];
}

static void
recv_exact(OFTCPSocket *self, int socket, char *buffer, size_t length)
{
	while (length > 0) {
		ssize_t ret = recv(socket, buffer, length, 0);

		if (ret < 0)
			@throw [OFReadFailedException
			    exceptionWithObject: self
				requestedLength: length
					  errNo: of_socket_errno()];

		buffer += ret;
		length -= ret;
	}
}

@implementation OFTCPSocket (SOCKS5)
- (void)OF_SOCKS5ConnectToHost: (OFString*)host
			  port: (uint16_t)port
{
	char request[] = { 5, 1, 0, 3 };
	char reply[256];
	void *pool;
	OFDataArray *connectRequest;

	if ([host UTF8StringLength] > 255)
		@throw [OFOutOfRangeException exception];

	/* 5 1 0 -> no authentication */
	send_or_exception(self, _socket, request, 3);



	recv_exact(self, _socket, reply, 2);

	if (reply[0] != 5 || reply[1] != 0) {
		[self close];
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
	}

	/* CONNECT request */
	pool = objc_autoreleasePoolPush();
	connectRequest = [OFDataArray dataArray];


	[connectRequest addItems: request
			   count: 4];

	request[0] = [host UTF8StringLength];
	[connectRequest addItem: request];
	[connectRequest addItems: [host UTF8String]
			   count: request[0]];

	request[0] = port >> 8;
	request[1] = port & 0xFF;
	[connectRequest addItems: request
			   count: 2];

	send_or_exception(self, _socket,
	    [connectRequest items], [connectRequest count]);

	objc_autoreleasePoolPop(pool);


	recv_exact(self, _socket, reply, 4);

	if (reply[0] != 5 || reply[1] != 0 || reply[2] != 0) {
		[self close];
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
	}

	/* Skip the rest of the reply */
	switch (reply[3]) {
	case 1: /* IPv4 */

		recv_exact(self, _socket, reply, 4);
		break;
	case 3: /* Domainname */
		recv_exact(self, _socket, reply, 1);
		recv_exact(self, _socket, reply, reply[0]);
		break;
	case 4: /* IPv6 */

		recv_exact(self, _socket, reply, 16);
		break;
	default:
		[self close];
		@throw [OFConnectionFailedException exceptionWithHost: host
								 port: port
							       socket: self];
	}

	recv_exact(self, _socket, reply, 2);
}
@end