-
Notifications
You must be signed in to change notification settings - Fork 3
/
local.py
104 lines (87 loc) · 3.51 KB
/
local.py
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
#! /usr/bin/env python
# -*- coding: utf8 -*-
import socket
import SocketServer
import struct
import logbook
import icmp
REMOTE_ADDR = ("bandwagon.chashuibiao.org", 1)
class Socks5Server(SocketServer.StreamRequestHandler):
'''
Socks5 locate server
'''
def handle(self):
# 1. Authorization
self.request.recv(262)
self.request.send(b"\x05\x00")
# 2. Request
data = self.request.recv(4)
mode = ord(data[1])
if mode != 1: # if not a TCP/IP stream connection
reply = b"\x05\x07\x00\x01" # Command not supported
self.request.send(reply)
return
addrtype = ord(data[3])
if addrtype == 1: # IPv4
# 4 bytes for IPv4 address
addr = socket.inet_ntoa(self.request.recv(4))
logbook.info("ipv4 address: {}".format(addr))
elif addrtype == 3: # Domain name
# 1 byte of name length followed by the name for Domain name
addr = self.request.recv(ord(self.request.recv(1)))
logbook.info("domain name is {}".format(addr))
# port number in a network byte order, 2 bytes
port = struct.unpack('>H', self.request.recv(2))[0]
logbook.info("request port is {}".format(port))
# 3. Response
reply_prefix = b"\x05\x00\x00\x01"
reply_suffix = b"{}{}".format(
socket.inet_aton("0.0.0.0"), struct.pack(">H", 65535))
reply = b"{}{}".format(reply_prefix, reply_suffix)
self.request.send(reply)
# 4. Connect
remote = socket.socket(
socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
identifier = self.client_address[1]
goal_addr = (addr, port)
init_packet = icmp.pack(identifier, 6666, repr(goal_addr))
remote.sendto(init_packet, REMOTE_ADDR)
_ = icmp.unpack(remote.recvfrom(4096)[0])
logbook.info("first handshake reply: {}".format(_))
# 5. Communicate
local = self.request
while True:
local_data = local.recv(4096)
if len(local_data) == 0:
break
logbook.info("local data:\n{}".format(local_data))
identifier = self.client_address[1]
packet = icmp.pack(identifier, 8888, local_data)
remote.sendto(packet, REMOTE_ADDR)
recv = icmp.unpack(remote.recvfrom(8192)[0])
logbook.info("once recv:\n{}".format(recv))
if not recv:
logbook.info("remote breaking down")
break
elif recv == "shards":
while True:
packet = icmp.pack(identifier, 9999, local_data)
remote.sendto(packet, REMOTE_ADDR)
content = icmp.unpack(remote.recvfrom(8192)[0])
if content == "over":
break
else:
local.send(content)
else:
logbook.info("once return:\n{}".format(repr(recv)))
local.send(recv)
if __name__ == '__main__':
local_log = logbook.StderrHandler()
local_log.format_string = (u'[{record.time:%H:%M:%S}] '
u'lineno:{record.lineno} '
u'{record.level_name}:{record.message}')
local_log.push_application()
logbook.info("start connecting...")
server = SocketServer.ThreadingTCPServer(('', 666), Socks5Server)
logbook.info("start server at localhost in 666")
server.serve_forever()