progress.
This commit is contained in:
parent
d5a2dbfc49
commit
e781dfa22d
@ -1,4 +1,2 @@
|
||||
Entropy:
|
||||
|
||||
Sequence entropy: 4.37
|
||||
This is close to the theoretical maximum entropy (log2(21) ≈ 4.39), suggesting the sequence is highly random.
|
||||
pip uninstall pycrypto
|
||||
pip install pycryptodome
|
4
build.py
4
build.py
@ -1,4 +1,6 @@
|
||||
|
||||
|
||||
|
||||
@task
|
||||
def format():
|
||||
"""
|
||||
@ -28,7 +30,7 @@ def build():
|
||||
Build the program. Output is pgs.
|
||||
"""
|
||||
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
|
||||
def run():
|
||||
|
13
pgs.c
13
pgs.c
@ -1,4 +1,6 @@
|
||||
#define PY_SSIZE_T_CLEAN 1
|
||||
#include "py.h"
|
||||
#include <Python.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.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) {
|
||||
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);
|
||||
ssize_t bytes_read = recv(from_fd, buffer, sizeof(buffer), 0);
|
||||
if (bytes_read > 0) {
|
||||
@ -183,7 +185,7 @@ int main() {
|
||||
struct epoll_event events[MAX_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};
|
||||
while (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);
|
||||
|
||||
} else {
|
||||
// Handle data forwarding for existing connections
|
||||
connection_t *conn = connections[events[i].data.fd];
|
||||
if (events[i].events & (EPOLLHUP | EPOLLERR)) {
|
||||
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);
|
||||
|
||||
if (upstream_fd == -1) {
|
||||
close(conn->client_fd);
|
||||
close_connection(epoll_fd, conn);
|
||||
continue;
|
||||
}
|
||||
set_nonblocking(upstream_fd);
|
||||
@ -246,8 +247,8 @@ int main() {
|
||||
|
||||
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, upstream_fd, &upstream_event);
|
||||
|
||||
printf("Connected: client_fd=%d, upstream_fd=%d\n",
|
||||
conn->client_fd, conn->upstream_fd);
|
||||
printf("Connected: client_fd=%d, upstream_fd=%d\n", conn->client_fd,
|
||||
conn->upstream_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
85
pgscript.py
85
pgscript.py
@ -1,5 +1,19 @@
|
||||
import socket
|
||||
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 = socket.gethostname()
|
||||
@ -69,20 +83,78 @@ def route(downstream,upstream):
|
||||
u = socket.fromfd(upstream, socket.AF_INET, socket.SOCK_STREAM)
|
||||
#u = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
#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")
|
||||
u.connect(("molodetz.nl", 22))
|
||||
elif is_http(peek):
|
||||
print("Forwarding to zhurnal")
|
||||
elif pgs.is_http(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'')
|
||||
u.connect(("127.0.0.1", 3028))
|
||||
elif b'molodetz.local' in peek:
|
||||
print("Forwarding to 127.0.0.1:8082.")
|
||||
peek = peek.replace(b'molodetz.local', b'localhost')
|
||||
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":
|
||||
print("Forwarding to dev.to")
|
||||
u.connect(("devrant.com", 443))
|
||||
@ -91,10 +163,11 @@ def route(downstream,upstream):
|
||||
else:
|
||||
# Error.
|
||||
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.
|
||||
# Socket handling is done at one place to avoid race conditions.
|
||||
|
||||
u = None
|
||||
|
||||
if not u:
|
||||
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 <stdbool.h>
|
||||
|
||||
@ -5,8 +7,37 @@ PyObject *_pModule = NULL;
|
||||
bool python_initialized = false;
|
||||
|
||||
PyObject *py_construct() {
|
||||
|
||||
PyStatus status;
|
||||
PyConfig config;
|
||||
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;
|
||||
PyObject *sysPath = PySys_GetObject("path");
|
||||
PyList_Append(sysPath, PyUnicode_FromString("."));
|
||||
@ -15,9 +46,14 @@ PyObject *py_construct() {
|
||||
_pModule = PyImport_Import(pName);
|
||||
Py_DECREF(pName);
|
||||
|
||||
PyGILState_Release(gstate);
|
||||
python_initialized = true;
|
||||
}
|
||||
return _pModule;
|
||||
exception:
|
||||
PyConfig_Clear(&config);
|
||||
Py_ExitStatusException(status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void py_destruct() {
|
||||
@ -36,7 +72,12 @@ int py_route(int downstream, int upstream) {
|
||||
if (PyCallable_Check(pFunc)) {
|
||||
PyObject *pArgs = PyTuple_Pack(2, PyLong_FromLong(downstream),
|
||||
PyLong_FromLong(upstream));
|
||||
|
||||
PyGILState_STATE gstate = PyGILState_Ensure();
|
||||
|
||||
PyObject *pValue = PyObject_CallObject(pFunc, pArgs);
|
||||
PyGILState_Release(gstate);
|
||||
|
||||
Py_DECREF(pArgs);
|
||||
if (pValue != NULL) {
|
||||
upstream_fd = PyLong_AsLong(pValue);
|
||||
|
Loading…
Reference in New Issue
Block a user