ObjFW  Check-in [f8422ce7e9]

Overview
Comment:OFTCPSocket+SOCKS5.m: Use send/recv directly

This is necessary to make SOCKS5 support work with subclasses of
OFTCPSocket that override read and write, for example SSL sockets.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: f8422ce7e98e59d78797514063ef67fb6ee64c650066d08dd56953d22f34ed16
User & Date: js on 2016-03-12 11:55:00
Other Links: manifest | tags
Context
2016-03-12
13:12
OFSystemInfo: Fix a stupid typo check-in: 6baf51ebda user: js tags: trunk
11:55
OFTCPSocket+SOCKS5.m: Use send/recv directly check-in: f8422ce7e9 user: js tags: trunk
2016-03-06
17:40
OFTLSSocket: Make use of properties check-in: 143c61869a user: js tags: trunk
Changes

Modified src/OFTCPSocket+SOCKS5.m from [8b7939a5bd] to [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