Skip to content
This repository was archived by the owner on Jun 14, 2018. It is now read-only.

Commit cb01757

Browse files
committed
test code
1 parent f37a75d commit cb01757

File tree

9 files changed

+312
-0
lines changed

9 files changed

+312
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,9 @@ ENV/
9999

100100
# mypy
101101
.mypy_cache/
102+
103+
# macOS auto-generated file
104+
.DS_Store
105+
106+
# VS Code files
107+
.vscode/

client.json.example

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"in": {
3+
"type": "plain",
4+
"addr": "127.0.0.1",
5+
"port": 8388
6+
},
7+
"out": [
8+
{
9+
"type": "tls",
10+
"addr": "example.com",
11+
"port": 443,
12+
"outpass": "password",
13+
"ca": "ca.crt"
14+
}
15+
]
16+
}

config.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'''
2+
FBoT, Foo or Bar over TLS.
3+
Copyright (C) 2017 yvbbrjdr
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
'''
18+
19+
import json
20+
from hashlib import sha256
21+
22+
config = {}
23+
24+
def load(fp):
25+
global config
26+
config = json.load(fp)
27+
for out in config['out']:
28+
if out.get('inpass'):
29+
out['inpass'] = sha256(out['inpass'].encode()).digest()
30+
else:
31+
out['inpass'] = b''
32+
if out.get('outpass'):
33+
out['outpass'] = sha256(out['outpass'].encode()).digest()
34+
else:
35+
out['outpass'] = b''

fbot.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python3
2+
3+
'''
4+
FBoT, Foo or Bar over TLS.
5+
Copyright (C) 2017 yvbbrjdr
6+
7+
This program is free software: you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation, either version 3 of the License, or
10+
(at your option) any later version.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License
18+
along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
'''
20+
21+
import argparse
22+
import version
23+
import config
24+
import tcpserver
25+
26+
def main():
27+
parser = argparse.ArgumentParser(prog = 'FBoT', description = 'Foo or Bar over TLS.')
28+
parser.add_argument('-v', '--version', action = 'version', version='%(prog)s ' + version.version)
29+
parser.add_argument('config', help = 'the JSON config file to load', type = argparse.FileType('r'))
30+
with parser.parse_args().config as fp:
31+
config.load(fp)
32+
tcpserver.TCPServer().listen()
33+
34+
if __name__ == '__main__':
35+
main()

log.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'''
2+
FBoT, Foo or Bar over TLS.
3+
Copyright (C) 2017 yvbbrjdr
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
'''
18+
19+
import datetime
20+
import socket
21+
22+
def log(text, sock = None):
23+
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
24+
if sock:
25+
addr, port = sock.getpeername()
26+
print('[%s] %s:%d %s' % (now, addr, port, text))
27+
else:
28+
print('[%s] %s' % (now, text))

server.json.example

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"in": {
3+
"type": "tls",
4+
"addr": "0.0.0.0",
5+
"port": 443,
6+
"cert": "cert.pem",
7+
"key": "key.pem"
8+
},
9+
"out": [
10+
{
11+
"type": "plain",
12+
"addr": "127.0.0.1",
13+
"port": 80
14+
},
15+
{
16+
"type": "plain",
17+
"addr": "127.0.0.1",
18+
"port": 8388,
19+
"inpass": "password"
20+
}
21+
]
22+
}

tcpserver.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'''
2+
FBoT, Foo or Bar over TLS.
3+
Copyright (C) 2017 yvbbrjdr
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
'''
18+
19+
import socket
20+
import ssl
21+
import tunnel
22+
import config
23+
import log
24+
25+
class TCPServer(object):
26+
def __init__(self):
27+
self.config = config.config['in']
28+
self.isTLS = self.config['type'] == 'tls'
29+
if self.isTLS:
30+
self.context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
31+
self.context.load_cert_chain(certfile = self.config['cert'], keyfile = self.config['key'])
32+
self.socket = socket.socket()
33+
self.socket.bind((self.config['addr'], self.config['port']))
34+
35+
def listen(self):
36+
self.socket.listen()
37+
log.log('Server is listening at %s:%d' % (self.config['addr'], self.config['port']))
38+
while True:
39+
clientSocket, _ = self.socket.accept()
40+
if self.isTLS:
41+
clientSocket = self.context.wrap_socket(clientSocket, server_side = True)
42+
tunnel.Tunnel(clientSocket).start()
43+
44+
def __del__(self):
45+
self.socket.close()

tunnel.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
'''
2+
FBoT, Foo or Bar over TLS.
3+
Copyright (C) 2017 yvbbrjdr
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
'''
18+
19+
import socket
20+
import threading
21+
import config
22+
import ssl
23+
from log import log
24+
25+
class Tunnel(object):
26+
27+
hashLength = 32
28+
29+
def __init__(self, clientSocket):
30+
log('connection established', clientSocket)
31+
self.config = config.config['out']
32+
self.clientSocket = clientSocket
33+
34+
def start(self):
35+
self.clientOpen = True
36+
self.serverOpen = False
37+
self.firstPacketSent = False
38+
threading.Thread(target = self.clientSocketThread).start()
39+
40+
def clientSocketThread(self):
41+
while True:
42+
data = self.clientSocket.recv(4096)
43+
if data:
44+
self.clientRecv(data)
45+
else:
46+
self.clientOpen = False
47+
self.clientSocket.close()
48+
if self.serverOpen:
49+
self.serverSocket.shutdown(socket.SHUT_RDWR)
50+
break
51+
52+
def serverSocketThread(self):
53+
while True:
54+
data = self.serverSocket.recv(4096)
55+
if data:
56+
self.clientSocket.send(data)
57+
else:
58+
self.serverOpen = False
59+
self.serverSocket.close()
60+
if self.clientOpen:
61+
self.clientSocket.shutdown(socket.SHUT_RDWR)
62+
break
63+
64+
def clientRecv(self, data):
65+
if self.firstPacketSent:
66+
self.serverSocket.send(data)
67+
else:
68+
self.firstPacketSent = True
69+
if len(data) >= Tunnel.hashLength:
70+
segment = data[:Tunnel.hashLength]
71+
bar = None
72+
for out in self.config:
73+
if out['inpass'] == segment:
74+
bar = out
75+
break
76+
if bar:
77+
self.connectToServer(bar, data[Tunnel.hashLength:])
78+
return
79+
foo = None
80+
for out in self.config:
81+
if out['inpass'] == b'':
82+
foo = out
83+
break
84+
if foo:
85+
self.connectToServer(foo, data)
86+
else:
87+
log('no out found', self.clientSocket)
88+
self.clientSocket.shutdown(socket.SHUT_RDWR)
89+
90+
def connectToServer(self, out, data):
91+
self.serverSocket = socket.socket()
92+
if out['type'] == 'tls':
93+
context = ssl.create_default_context()
94+
if out.get('ca'):
95+
context.load_verify_locations(out['ca'])
96+
self.serverSocket = context.wrap_socket(self.serverSocket, server_hostname = out['addr'])
97+
try:
98+
self.serverSocket.connect((out['addr'], out['port']))
99+
except:
100+
log('%s:%d connect failed' % (out['addr'], out['port']))
101+
self.clientSocket.shutdown(socket.SHUT_RDWR)
102+
return
103+
log('connect to %s:%d' % (out['addr'], out['port']), self.clientSocket)
104+
self.serverOpen = True
105+
self.serverSocket.send(out['outpass'] + data)
106+
threading.Thread(target = self.serverSocketThread).start()

version.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'''
2+
FBoT, Foo or Bar over TLS.
3+
Copyright (C) 2017 yvbbrjdr
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation, either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
'''
18+
19+
version = '0.0.0'

0 commit comments

Comments
 (0)