progress.
This commit is contained in:
parent
d5a2dbfc49
commit
e781dfa22d
@ -1,4 +1,2 @@
|
|||||||
Entropy:
|
pip uninstall pycrypto
|
||||||
|
pip install pycryptodome
|
||||||
Sequence entropy: 4.37
|
|
||||||
This is close to the theoretical maximum entropy (log2(21) ≈ 4.39), suggesting the sequence is highly random.
|
|
4
build.py
4
build.py
@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def format():
|
def format():
|
||||||
"""
|
"""
|
||||||
@ -28,7 +30,7 @@ def build():
|
|||||||
Build the program. Output is pgs.
|
Build the program. Output is pgs.
|
||||||
"""
|
"""
|
||||||
format()
|
format()
|
||||||
system("gcc pgs.c -o pgs -lpython3.12 -I/usr/include/python3.14")
|
system("PY_SSIZE_T_CLEAN=1 gcc pgs.c -o pgs -lpython3.12 -I/usr/include/python3.14")
|
||||||
|
|
||||||
@task
|
@task
|
||||||
def run():
|
def run():
|
||||||
|
13
pgs.c
13
pgs.c
@ -1,4 +1,6 @@
|
|||||||
|
#define PY_SSIZE_T_CLEAN 1
|
||||||
#include "py.h"
|
#include "py.h"
|
||||||
|
#include <Python.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -121,7 +123,7 @@ void close_connection(int epoll_fd, connection_t *conn) {
|
|||||||
|
|
||||||
int forward_data(int from_fd, int to_fd) {
|
int forward_data(int from_fd, int to_fd) {
|
||||||
static char buffer[BUFFER_SIZE];
|
static char buffer[BUFFER_SIZE];
|
||||||
// Feels great to do somehow. Better safe than sorry.
|
// Feels great to do somehow. Better safe than sorry.
|
||||||
memset(buffer, 0, BUFFER_SIZE);
|
memset(buffer, 0, BUFFER_SIZE);
|
||||||
ssize_t bytes_read = recv(from_fd, buffer, sizeof(buffer), 0);
|
ssize_t bytes_read = recv(from_fd, buffer, sizeof(buffer), 0);
|
||||||
if (bytes_read > 0) {
|
if (bytes_read > 0) {
|
||||||
@ -183,7 +185,7 @@ int main() {
|
|||||||
struct epoll_event events[MAX_EVENTS];
|
struct epoll_event events[MAX_EVENTS];
|
||||||
memset(events, 0, sizeof(events));
|
memset(events, 0, sizeof(events));
|
||||||
|
|
||||||
printf("Intercepting load balancer listening on port %d\n", LISTEN_PORT);
|
printf("Pretty Good Server listening on port %d\n", LISTEN_PORT);
|
||||||
connection_t connections[MAX_EVENTS][sizeof(connection_t)] = {0};
|
connection_t connections[MAX_EVENTS][sizeof(connection_t)] = {0};
|
||||||
while (1) {
|
while (1) {
|
||||||
int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
|
int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
|
||||||
@ -219,7 +221,6 @@ int main() {
|
|||||||
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &client_event);
|
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &client_event);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Handle data forwarding for existing connections
|
|
||||||
connection_t *conn = connections[events[i].data.fd];
|
connection_t *conn = connections[events[i].data.fd];
|
||||||
if (events[i].events & (EPOLLHUP | EPOLLERR)) {
|
if (events[i].events & (EPOLLHUP | EPOLLERR)) {
|
||||||
printf("Connection closed: client_fd=%d, upstream_fd=%d\n",
|
printf("Connection closed: client_fd=%d, upstream_fd=%d\n",
|
||||||
@ -231,7 +232,7 @@ int main() {
|
|||||||
int upstream_fd = py_route(conn->client_fd, conn->upstream_fd);
|
int upstream_fd = py_route(conn->client_fd, conn->upstream_fd);
|
||||||
|
|
||||||
if (upstream_fd == -1) {
|
if (upstream_fd == -1) {
|
||||||
close(conn->client_fd);
|
close_connection(epoll_fd, conn);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
set_nonblocking(upstream_fd);
|
set_nonblocking(upstream_fd);
|
||||||
@ -246,8 +247,8 @@ int main() {
|
|||||||
|
|
||||||
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, upstream_fd, &upstream_event);
|
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, upstream_fd, &upstream_event);
|
||||||
|
|
||||||
printf("Connected: client_fd=%d, upstream_fd=%d\n",
|
printf("Connected: client_fd=%d, upstream_fd=%d\n", conn->client_fd,
|
||||||
conn->client_fd, conn->upstream_fd);
|
conn->upstream_fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
85
pgscript.py
85
pgscript.py
@ -1,5 +1,19 @@
|
|||||||
import socket
|
import socket
|
||||||
import os
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
import pathlib
|
||||||
|
import html
|
||||||
|
server_start = datetime.now()
|
||||||
|
import pgs
|
||||||
|
print(pgs.add(1,2))
|
||||||
|
|
||||||
|
def get_server_uptime():
|
||||||
|
seconds = (datetime.now() - server_start).total_seconds()
|
||||||
|
if seconds > 60*60: # hour
|
||||||
|
return f"{int(seconds/60/60)} hours"
|
||||||
|
elif seconds > 60: # minute
|
||||||
|
return f"{int(seconds/60)} minutes"
|
||||||
|
return f"{seconds} seconds"
|
||||||
|
|
||||||
# Hostname, only resolved at startup.
|
# Hostname, only resolved at startup.
|
||||||
hostname = socket.gethostname()
|
hostname = socket.gethostname()
|
||||||
@ -69,20 +83,78 @@ def route(downstream,upstream):
|
|||||||
u = socket.fromfd(upstream, socket.AF_INET, socket.SOCK_STREAM)
|
u = socket.fromfd(upstream, socket.AF_INET, socket.SOCK_STREAM)
|
||||||
#u = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
#u = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
#print("FD:",u.fileno())
|
#print("FD:",u.fileno())
|
||||||
peek = os.read(downstream, 4096)
|
peek = pgs.read(downstream, 4096).tobytes()
|
||||||
|
|
||||||
if peek.startswith(b"SSH"):
|
|
||||||
|
if pgs.is_ssh(peek):
|
||||||
print("Forwarding to ssh molodetz")
|
print("Forwarding to ssh molodetz")
|
||||||
u.connect(("molodetz.nl", 22))
|
u.connect(("molodetz.nl", 22))
|
||||||
elif is_http(peek):
|
elif pgs.is_http(peek):
|
||||||
print("Forwarding to zhurnal")
|
|
||||||
if b'/random' in peek or b'random.' in peek:
|
if b'/random' in peek or b'random.' in peek:
|
||||||
|
|
||||||
|
print("Forwarding to 127.0.0.1:3028.")
|
||||||
peek = peek.replace(b'/random', b'/')
|
peek = peek.replace(b'/random', b'/')
|
||||||
peek = peek.replace(b'random.', b'')
|
peek = peek.replace(b'random.', b'')
|
||||||
u.connect(("127.0.0.1", 3028))
|
u.connect(("127.0.0.1", 3028))
|
||||||
elif b'molodetz.local' in peek:
|
elif b'molodetz.local' in peek:
|
||||||
|
print("Forwarding to 127.0.0.1:8082.")
|
||||||
peek = peek.replace(b'molodetz.local', b'localhost')
|
peek = peek.replace(b'molodetz.local', b'localhost')
|
||||||
u.connect(("127.0.0.1", 8082))
|
u.connect(("127.0.0.1", 8082))
|
||||||
|
elif b'bench.local' in peek:
|
||||||
|
print("Responding with bench page.")
|
||||||
|
body = f"""<html>\n<head>\n<title>Benchmark page.</title>\n</head>\n<body>\n<h1>Bench</h1>\n<p>{counter}</p>\n</body>\n</html>\n""".encode()
|
||||||
|
|
||||||
|
s = socket.fromfd(downstream, socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
s.sendall(
|
||||||
|
b'HTTP/1.1 200 Pretty Good Server.\r\n'
|
||||||
|
+ b'Content-Length: ' + str(len(body)).encode() + b'\r\n'
|
||||||
|
+ b'Content-Type: text/html\r\n\r\n'
|
||||||
|
+ body
|
||||||
|
)
|
||||||
|
u = None
|
||||||
|
s.shutdown(socket.SHUT_RDWR)
|
||||||
|
else:
|
||||||
|
# 404
|
||||||
|
if env == "prod":
|
||||||
|
pgs.write(downstream,
|
||||||
|
b'HTTP/1.1 403 Authorization Required.\r\n\r\n')
|
||||||
|
else:
|
||||||
|
pgscript_source = html.escape(pathlib.Path(__file__).read_text())
|
||||||
|
content = f"""<pre>
|
||||||
|
Server: Pretty Good Server
|
||||||
|
Environment: {env}
|
||||||
|
Total connections: {counter}
|
||||||
|
Local hostname: {hostname}
|
||||||
|
Downstream FD: {downstream}
|
||||||
|
Upstream FD: {upstream}
|
||||||
|
Current time server: {datetime.now()}
|
||||||
|
Server started on: {server_start}
|
||||||
|
Server uptime: {get_server_uptime()}
|
||||||
|
</pre>
|
||||||
|
<h3>Source code of pgscript.py</h3>
|
||||||
|
<i>Location: {pathlib.Path(__file__).resolve()}</i>
|
||||||
|
<pre style="color:blue;">
|
||||||
|
{pgscript_source}
|
||||||
|
</pre>
|
||||||
|
"""
|
||||||
|
body = f"""<html>\n<head>\n<title>Debug page.</title>\n</head>\n<body>\n<h1>Pretty Good Server</h1>\n<h3>Debugging information</h3>\n<p>{content}</p>\n</body>\n</html>\n"""
|
||||||
|
headers = ["HTTP/1.1 200 Pretty Good Server.",
|
||||||
|
"Content-Length: {len(body)}",
|
||||||
|
"Content-Type: text/html",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
headers = "\r\n".join(headers)
|
||||||
|
response = f"{headers}{body}"
|
||||||
|
|
||||||
|
pgs.write(downstream,response)
|
||||||
|
|
||||||
|
# Unset socket so the server will close it.
|
||||||
|
# Do not disconnect in python!
|
||||||
|
# Instead of a 404, we also could've displayed a custom page.
|
||||||
|
# Maybe some server statistics?
|
||||||
|
u = None
|
||||||
|
|
||||||
elif is_https(peek) and env == "prod":
|
elif is_https(peek) and env == "prod":
|
||||||
print("Forwarding to dev.to")
|
print("Forwarding to dev.to")
|
||||||
u.connect(("devrant.com", 443))
|
u.connect(("devrant.com", 443))
|
||||||
@ -91,10 +163,11 @@ def route(downstream,upstream):
|
|||||||
else:
|
else:
|
||||||
# Error.
|
# Error.
|
||||||
print("Could not find upstream for header content.")
|
print("Could not find upstream for header content.")
|
||||||
print(b"Closing connection. Your current environment: {env}")
|
print(f"Closing connection. Your current environment: {env}")
|
||||||
# Don't have to close socket, pgs will do that himself.
|
# Don't have to close socket, pgs will do that himself.
|
||||||
# Socket handling is done at one place to avoid race conditions.
|
# Socket handling is done at one place to avoid race conditions.
|
||||||
|
u = None
|
||||||
|
|
||||||
if not u:
|
if not u:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
43
py.h
43
py.h
@ -1,3 +1,5 @@
|
|||||||
|
#define PY_SSIZE_T_CLEAN 1
|
||||||
|
#include "pgs_api.h"
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
@ -5,8 +7,37 @@ PyObject *_pModule = NULL;
|
|||||||
bool python_initialized = false;
|
bool python_initialized = false;
|
||||||
|
|
||||||
PyObject *py_construct() {
|
PyObject *py_construct() {
|
||||||
|
|
||||||
|
PyStatus status;
|
||||||
|
PyConfig config;
|
||||||
if (!python_initialized) {
|
if (!python_initialized) {
|
||||||
Py_Initialize();
|
if (PyImport_AppendInittab("pgs", PyInit_mymodule) == -1) {
|
||||||
|
fprintf(stderr, "Failed to add mymodule to the interpreter's table\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyConfig_InitPythonConfig(&config);
|
||||||
|
|
||||||
|
/* optional but recommended */
|
||||||
|
status = PyConfig_SetBytesString(&config, &config.program_name, "pgs");
|
||||||
|
if (PyStatus_Exception(status)) {
|
||||||
|
goto exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = Py_InitializeFromConfig(&config);
|
||||||
|
if (PyStatus_Exception(status)) {
|
||||||
|
goto exception;
|
||||||
|
}
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
// Py_Initialize();
|
||||||
|
if (!Py_IsInitialized()) {
|
||||||
|
fprintf(stderr, "Python initialization failed!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyGILState_STATE gstate = PyGILState_Ensure();
|
||||||
|
|
||||||
|
PyRun_SimpleString("import pgs");
|
||||||
|
|
||||||
|
// Py_InitModule("pgscript", NULL);
|
||||||
python_initialized = true;
|
python_initialized = true;
|
||||||
PyObject *sysPath = PySys_GetObject("path");
|
PyObject *sysPath = PySys_GetObject("path");
|
||||||
PyList_Append(sysPath, PyUnicode_FromString("."));
|
PyList_Append(sysPath, PyUnicode_FromString("."));
|
||||||
@ -15,9 +46,14 @@ PyObject *py_construct() {
|
|||||||
_pModule = PyImport_Import(pName);
|
_pModule = PyImport_Import(pName);
|
||||||
Py_DECREF(pName);
|
Py_DECREF(pName);
|
||||||
|
|
||||||
|
PyGILState_Release(gstate);
|
||||||
python_initialized = true;
|
python_initialized = true;
|
||||||
}
|
}
|
||||||
return _pModule;
|
return _pModule;
|
||||||
|
exception:
|
||||||
|
PyConfig_Clear(&config);
|
||||||
|
Py_ExitStatusException(status);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void py_destruct() {
|
void py_destruct() {
|
||||||
@ -36,7 +72,12 @@ int py_route(int downstream, int upstream) {
|
|||||||
if (PyCallable_Check(pFunc)) {
|
if (PyCallable_Check(pFunc)) {
|
||||||
PyObject *pArgs = PyTuple_Pack(2, PyLong_FromLong(downstream),
|
PyObject *pArgs = PyTuple_Pack(2, PyLong_FromLong(downstream),
|
||||||
PyLong_FromLong(upstream));
|
PyLong_FromLong(upstream));
|
||||||
|
|
||||||
|
PyGILState_STATE gstate = PyGILState_Ensure();
|
||||||
|
|
||||||
PyObject *pValue = PyObject_CallObject(pFunc, pArgs);
|
PyObject *pValue = PyObject_CallObject(pFunc, pArgs);
|
||||||
|
PyGILState_Release(gstate);
|
||||||
|
|
||||||
Py_DECREF(pArgs);
|
Py_DECREF(pArgs);
|
||||||
if (pValue != NULL) {
|
if (pValue != NULL) {
|
||||||
upstream_fd = PyLong_AsLong(pValue);
|
upstream_fd = PyLong_AsLong(pValue);
|
||||||
|
Loading…
Reference in New Issue
Block a user