socks5interceptor.mm

来自「lumaqq」· MM 代码 · 共 302 行

MM
302
字号
/* * LumaQQ - Cross platform QQ client, special edition for Mac * * Copyright (C) 2007 luma <stubma@163.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#import <arpa/inet.h>#import <netdb.h>#import "ByteTool.h"#import "Socks5Interceptor.h"#import "ByteBuffer.h"#import "Connection.h"#import "NetworkLayer.h"#import "NSMutableData-CustomAppending.h"#import "NSString-Validate.h"#define _kStatusInit 0#define _kStatusAuthenticating 1#define _kStatusConnect 2#define _kStatusAssociate 3#define _kStatusReady 4static const char _kVersion5 = 5;static const char _kNoAuth = 0;static const char _kBasicAuth = 2;static const char _kReqConnect = 1;static const char _kReqAssociate = 3;static const char _kAddrTypeIpv4 = 1;static const char _kAddrTypeDomainName = 3;static const char _kAddrTypeIpv6 = 4;static const char _kReplyOK = 0;static const char _kReplyBasicAuth = 2;@implementation Socks5Interceptor- (id)initWithConnection:(Connection*)conn {	self = [super init];	if(self) {		m_status = _kStatusInit;		m_connection = [conn retain];	}	return self;}- (void) dealloc {	[m_connection release];	[super dealloc];}#pragma mark -#pragma mark Interceptor protocol- (void)kickoff {	[self initialize];	m_status = _kStatusInit;}- (void)initialize {	/*	* init request	* +----+----------+----------+	* |VER | NMETHODS | METHODS  |	* +----+----------+----------+	* | 1  |    1     | 1 to 255 |	* +----+----------+----------+	*/		// check user name	BOOL bAuth = NO;	if(![[m_connection proxyUsername] isEmpty] && ![[m_connection proxyPassword] isEmpty])		bAuth = YES;		// send	NSMutableData* data = [NSMutableData data];	[data appendByte:_kVersion5];	[data appendByte:1];	[data appendByte:(bAuth ? _kBasicAuth : _kNoAuth)];	[m_connection write:data];}- (void)associate {	/*	 * establish udp connection     * +----+-----+-------+------+----------+----------+     * |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |     * +----+-----+-------+------+----------+----------+     * | 1  |  1  | X'00' |  1   | Variable |    2     |     * +----+-----+-------+------+----------+----------+     */		// check server address format	NSData* ip = [ByteTool string2IpData:[m_connection server]];	BOOL isIp = ip != nil;		// get port	uint16_t port = htons([[m_connection proxyPort] unsignedShortValue]);		NSMutableData* data = [NSMutableData data];	[data appendByte:_kVersion5];	[data appendByte:_kReqAssociate];	[data appendByte:0];	[data appendByte:(isIp ? _kAddrTypeIpv4 : _kAddrTypeDomainName)];	if(isIp)		[data appendData:ip];	else {		[data appendByte:[[m_connection server] cStringLength]];		[data appendBytes:[[m_connection server] cString] length:[[m_connection server] cStringLength]];	}	[data appendBytes:(const void*)&port length:2];	[m_connection write:data];}- (void)connect {	/*	 * establish tcp connection     * +----+-----+-------+------+----------+----------+     * |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |     * +----+-----+-------+------+----------+----------+     * | 1  |  1  | X'00' |  1   | Variable |    2     |     * +----+-----+-------+------+----------+----------+     */		// check server address format	NSData* ip = [ByteTool string2IpData:[m_connection server]];	BOOL isIp = ip != nil;		// get port	uint16_t port = htons([[m_connection proxyPort] unsignedShortValue]);		NSMutableData* data = [NSMutableData data];	[data appendByte:_kVersion5];	[data appendByte:_kReqConnect];	[data appendByte:0];	[data appendByte:(isIp ? _kAddrTypeIpv4 : _kAddrTypeDomainName)];	if(isIp)		[data appendData:ip];	else {		[data appendByte:[[m_connection server] cStringLength]];		[data appendBytes:[[m_connection server] cString] length:[[m_connection server] cStringLength]];	}	[data appendBytes:(const void*)&port length:2];	[m_connection write:data];}- (void)auth {	/*	 * auth request     * +----+------+----------+------+----------+     * |VER | ULEN |  UNAME   | PLEN |  PASSWD  |     * +----+------+----------+------+----------+     * | 1  |  1   | 1 to 255 |  1   | 1 to 255 |     * +----+------+----------+------+----------+     */		NSMutableData* data = [NSMutableData data];	[data appendByte:_kVersion5];	[data appendByte:[[m_connection proxyUsername] cStringLength]];	[data appendBytes:[[m_connection proxyUsername] cString] length:[[m_connection proxyUsername] cStringLength]];	[data appendByte:[[m_connection proxyPassword] cStringLength]];	[data appendBytes:[[m_connection proxyPassword] cString] length:[[m_connection proxyPassword] cStringLength]];	[m_connection write:data];}- (void)flush {	if(m_status == _kStatusReady)		[m_connection flush];}- (void)put:(NSData*)data {	if(m_status == _kStatusReady)		[m_connection put:data];	else {		const char* bytes = (const char*)[data bytes];		if(bytes[0] != _kVersion5) {			[[m_connection network] sendConnectionBrokenMessage:[m_connection connectionId]];		} else {			switch(m_status) {				case _kStatusInit:					if(bytes[1] == _kNoAuth) {						if([m_connection isUdp]) {							m_status = _kStatusAssociate;							[self associate];						} else {							m_status = _kStatusConnect;							[self connect];						}					} else if(bytes[1] == _kBasicAuth) {						NSLog(@"Socks5 proxy need auth");						[self auth];						m_status = _kStatusAuthenticating;					} else						[[m_connection network] sendConnectionBrokenMessage:[m_connection connectionId]];					break;				case _kStatusAuthenticating:					if(bytes[1] == _kReplyOK) {						NSLog(@"Socks5 proxy auth ok");						if([m_connection isUdp]) {							m_status = _kStatusAssociate;							[self associate];						} else {							m_status = _kStatusConnect;							[self connect];						}										} else						[[m_connection network] sendConnectionBrokenMessage:[m_connection connectionId]];					break;				case _kStatusConnect:					if(bytes[1] == _kReplyOK) {						NSLog(@"Socks proxy: TCP connection established");						m_status = _kStatusReady;						[[m_connection network] sendConnectionEstablishMessage:[m_connection connectionId]];					} else						[[m_connection network] sendConnectionBrokenMessage:[m_connection connectionId]];					break;				case _kStatusAssociate:					if(bytes[1] == _kReplyOK) {						// get buffer						ByteBuffer* buf = [ByteBuffer bufferWithBytes:(char*)bytes length:[data length]];												// get address type						[buf skip:3];						char addrType = [buf getByte];												// get address data						char* addrBytes = (char*)malloc([data length] - 6);						[buf getBytes:addrBytes length:([data length] - 6)];												// check address type						NSString* proxy = nil;						if(addrType == _kAddrTypeIpv4) {							proxy = [ByteTool ip2String:addrBytes];						} else if(addrType == _kAddrTypeDomainName) {							proxy = [NSString stringWithCString:addrBytes length:([data length] - 6)];						} else {							NSLog(@"Unsupport address type");							[[m_connection network] sendConnectionBrokenMessage:[m_connection connectionId]];							break;						}												// log						NSLog(@"bind address: %@", proxy);												// get port						UInt16 port = [buf getUInt16];												// create socket address						struct sockaddr_in addr;						struct hostent* hostAddr;						if ((hostAddr = gethostbyname([proxy cString])) == NULL)							addr.sin_addr.s_addr = inet_addr((const char*)[proxy cString]);						else {							bzero(&addr, sizeof(addr));							bcopy(hostAddr->h_addr, (char *)&addr.sin_addr, hostAddr->h_length);						}						addr.sin_len = sizeof(addr);						addr.sin_family = AF_INET;						addr.sin_port = htons(port);												// reassociate						if(connect([m_connection socket], (const sockaddr*)&addr, sizeof(addr)) < 0) {							NSLog(@"Failed to connect to %@", proxy);							[[m_connection network] sendConnectionBrokenMessage:[m_connection connectionId]];							return;						}												// change status						NSLog(@"Socks5 proxy: UDP connection established");						m_status = _kStatusReady;												// release						free(addrBytes);												// notify						[[m_connection network] sendConnectionEstablishMessage:[m_connection connectionId]];					} else						[[m_connection network] sendConnectionBrokenMessage:[m_connection connectionId]];					break;			}		}	}}@end

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?