Compare commits
9 Commits
Author | SHA1 | Date |
---|---|---|
|
b8c03bbe02 | 1 year ago |
|
975940006d | 1 year ago |
|
c1f872e565 | 1 year ago |
|
90fe430f35 | 1 year ago |
|
ea5f30b301 | 1 year ago |
|
d23f829fb2 | 1 year ago |
|
30aeca973e | 1 year ago |
|
ed63f45b54 | 1 year ago |
|
07b868be13 | 1 year ago |
15 changed files with 479 additions and 0 deletions
@ -0,0 +1,4 @@
@@ -0,0 +1,4 @@
|
||||
colorama==0.4.4 |
||||
commonmark==0.9.1 |
||||
Pygments==2.9.0 |
||||
rich==10.4.0 |
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
import socket |
||||
from typing import Protocol |
||||
from rich.console import Console |
||||
from .ethernet import EthernetFrame, EthernetProtoType |
||||
from .ip import Ipv4Packet |
||||
from .arp import ArpPacket |
||||
|
||||
console = Console() |
||||
|
||||
|
||||
class Printable(Protocol): |
||||
def print(self, console: Console): |
||||
pass |
||||
|
||||
|
||||
def print_packet(frame: EthernetFrame) -> None: |
||||
if frame.frame_type == EthernetProtoType.IPV4: |
||||
Ipv4Packet.decode(frame.data).print(console) |
||||
elif frame.frame_type == EthernetProtoType.ARP: |
||||
ArpPacket.decode(frame.data).print(console) |
||||
else: |
||||
frame.print(console) |
||||
|
||||
|
||||
def main(): |
||||
conn = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.ntohs(3)) |
||||
while True: |
||||
raw_data, _ = conn.recvfrom(65536) |
||||
ethernet_frame = EthernetFrame.decode(raw_data) |
||||
print_packet(ethernet_frame) |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
main() |
||||
|
@ -0,0 +1,27 @@
@@ -0,0 +1,27 @@
|
||||
import struct |
||||
from dataclasses import dataclass |
||||
from rich.console import Console |
||||
|
||||
|
||||
|
||||
@dataclass() |
||||
class ArpPacket: |
||||
operation: int |
||||
|
||||
@classmethod |
||||
def decode(cls, data: bytes) -> "ArpPacket": |
||||
operation = struct.unpack("!H", data[6:8])[0] |
||||
return cls(operation=operation) |
||||
|
||||
def _describe_operaion(self) -> str: |
||||
if self.operation == 1: |
||||
return "request" |
||||
elif self.operation == 2: |
||||
return "response" |
||||
else: |
||||
return "unknown" |
||||
|
||||
def print(self, console: Console): |
||||
console.print("[ARP]", style="bold blue", end=" ") |
||||
console.print("operation", self._describe_operaion()) |
||||
|
@ -0,0 +1,39 @@
@@ -0,0 +1,39 @@
|
||||
import struct |
||||
import binascii |
||||
from dataclasses import dataclass |
||||
from enum import Enum |
||||
from rich.console import Console |
||||
|
||||
|
||||
def format_mac(mac_addr: str) -> str: |
||||
return ":".join(mac_addr[i:i+2] for i in range(0, len(mac_addr), 2)) |
||||
|
||||
|
||||
class EthernetProtoType(int, Enum): |
||||
IPV4 = 0x0800 |
||||
ARP = 0x0806 |
||||
|
||||
|
||||
@dataclass() |
||||
class EthernetFrame: |
||||
src: str |
||||
dst: str |
||||
frame_type: int |
||||
data: bytes |
||||
|
||||
@classmethod |
||||
def decode(cls, data: bytes) -> "EthernetFrame": |
||||
eth_header = struct.unpack("!6s6sH", data[0:14]) |
||||
dst_mac = binascii.hexlify(eth_header[0]).decode("ascii") |
||||
src_mac = binascii.hexlify(eth_header[1]).decode("ascii") |
||||
proto = eth_header[2] |
||||
return cls(src=src_mac, dst=dst_mac, frame_type=proto, data=data[14:]) |
||||
|
||||
def print(self, console: Console): |
||||
console.print("[Ethernet]", style="bold blue", end=" ") |
||||
console.print(f"from {self.src} to {self.dst} transfered {len(self.data)} bytes") |
||||
console.print( |
||||
" " + binascii.hexlify(self.data).decode('ascii'), |
||||
style="bright_black", crop=True, no_wrap=True, overflow="ellipsis", |
||||
) |
||||
|
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
from .ip import Ipv4Packet, IpProto |
||||
|
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
import struct |
||||
import binascii |
||||
from dataclasses import dataclass |
||||
from enum import Enum |
||||
from rich.console import Console |
||||
|
||||
|
||||
class IpProto(str, Enum): |
||||
IPV4 = "ipv4" |
||||
IPV6 = "ipv6" |
||||
UNKNOWN = "unknown" |
||||
|
||||
|
||||
|
||||
@dataclass() |
||||
class Ipv4Packet: |
||||
ttl: int |
||||
proto: int |
||||
src: str |
||||
dst: str |
||||
data: bytes |
||||
|
||||
@classmethod |
||||
def decode(cls, data: bytes) -> "Ipv4Packet": |
||||
ttl, proto, src, dst = struct.unpack("!8xBB2x4s4s", data[:20]) |
||||
fmt_ip = lambda addr: ".".join(map(str, addr)) |
||||
return cls(ttl=ttl, proto=proto, src=fmt_ip(src), dst=fmt_ip(dst), data=data[20:]) |
||||
|
||||
def print(self, console: Console): |
||||
console.print("[IPV4]", style="bold blue", end=" ") |
||||
console.print(f"from {self.src} to {self.dst} transfered {len(self.data)} bytes") |
||||
console.print( |
||||
" " + binascii.hexlify(self.data).decode('ascii'), |
||||
style="bright_black", crop=True, no_wrap=True, overflow="ellipsis", |
||||
) |
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
import requests |
||||
from http.server import BaseHTTPRequestHandler, HTTPServer |
||||
|
||||
REMOTE_URL = "https://0x73.ru" |
||||
|
||||
|
||||
class ProxyHandler(BaseHTTPRequestHandler): |
||||
def proxy_request(self) -> None: |
||||
resp = requests.request( |
||||
method=self.command, |
||||
url=REMOTE_URL + self.path, |
||||
headers=self.headers, |
||||
) |
||||
self.send_response(resp.status_code) |
||||
for k, v in resp.headers.items(): |
||||
self.send_header(k, v) |
||||
self.end_headers() |
||||
self.wfile.write(resp.raw.read(-1)) |
||||
|
||||
def do_GET(self): |
||||
self.proxy_request() |
||||
|
||||
def do_POST(self): |
||||
self.proxy_request() |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
HTTPServer(("", 8080), ProxyHandler).serve_forever() |
||||
|
@ -0,0 +1,121 @@
@@ -0,0 +1,121 @@
|
||||
import socket |
||||
import struct |
||||
|
||||
|
||||
class SocksServer: |
||||
def __init__(self): |
||||
self._ports_pool = list(range(30000, 31000)) |
||||
|
||||
def is_supported_version(self, version: int) -> bool: |
||||
return version == 5 |
||||
|
||||
def choose_auth_method(self) -> int: |
||||
return 0x02 |
||||
|
||||
def auth_client(self, *_) -> bool: |
||||
return True |
||||
|
||||
def pop_port(self) -> int: |
||||
return self._ports_pool.pop() |
||||
|
||||
def serve_conn(self, remote_ip: str, remote_port: int, local_port: int): |
||||
try: |
||||
self._serve_remote_conn(remote_ip, remote_port, local_port) |
||||
finally: |
||||
self._ports_pool.append(local_port) |
||||
|
||||
@staticmethod |
||||
def _serve_remote_conn(remote_ip: str, remote_port: int, local_port: int): |
||||
local_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||
local_sock.bind(("", local_port)) |
||||
local_sock.listen(1) |
||||
client_conn, _ = local_sock.accept() |
||||
remote_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||
remote_sock.connect((remote_ip, remote_port)) |
||||
while True: |
||||
data = client_conn.recv(1) |
||||
remote_sock.send(data) |
||||
|
||||
|
||||
class SocksHandler: |
||||
def __init__(self, host: str, port: int, server: SocksServer) -> None: |
||||
self.host = host |
||||
self.port = port |
||||
self._srv = server |
||||
|
||||
def _handle_greeting(self, conn: socket.socket): |
||||
version, auth_methods_count = struct.unpack("BB", conn.recv(2)) |
||||
conn.recv(auth_methods_count) |
||||
if not self._srv.is_supported_version(version): |
||||
conn.send(bytes([0xFF])) |
||||
raise ConnectionAbortedError() |
||||
auth_method = self._srv.choose_auth_method() |
||||
conn.send(bytes([0x05, auth_method])) |
||||
|
||||
def _handle_creds_auth(self, conn: socket.socket): |
||||
_, username_len = struct.unpack("BB", conn.recv(2)) |
||||
username = conn.recv(username_len).decode("ascii") |
||||
password_len = struct.unpack("B", conn.recv(1))[-1] |
||||
password = conn.recv(password_len).decode("ascii") |
||||
if not self._srv.auth_client(username, password): |
||||
conn.send(bytes([0x01, 0xff])) |
||||
raise ConnectionAbortedError() |
||||
conn.send(bytes([0x01, 0x00])) |
||||
|
||||
def _handle_conn_request(self, conn: socket.socket): |
||||
_, cmd = struct.unpack("BBx", conn.recv(3)) |
||||
if cmd != 0x01: |
||||
conn.send(bytes([0x05, 0x07, 0x00])) |
||||
raise ConnectionAbortedError() |
||||
remote_host = self._recv_host(conn) |
||||
remote_port = struct.unpack(">H", conn.recv(2))[-1] |
||||
local_port = self._srv.pop_port() |
||||
resp = bytes([ |
||||
0x05, 0x00, 0x00, 0x01, |
||||
0x01, 127, 0, 0, 1, |
||||
local_port >> 8 & 0xff, local_port & 0xff, |
||||
]) |
||||
conn.send(resp) |
||||
self._srv.serve_conn(remote_host, remote_port, local_port) |
||||
|
||||
@staticmethod |
||||
def _recv_host(conn: socket.socket) -> str: |
||||
address_type = struct.unpack("B", conn.recv(1))[-1] |
||||
if address_type == 0x01: |
||||
addr = conn.recv(4) |
||||
return ".".join(str(i) for i in addr) |
||||
elif address_type == 0x03: |
||||
raise Exception("что ты такое?") |
||||
elif address_type == 0x04: |
||||
name_len = struct.unpack("B", conn.recv(1))[-1] |
||||
return conn.recv(name_len).decode("ascii") |
||||
else: |
||||
raise ValueError("unknown address family") |
||||
|
||||
def _handle(self, conn: socket.socket): |
||||
try: |
||||
self._handle_greeting(conn) |
||||
print("Greeting passed") |
||||
self._handle_creds_auth(conn) |
||||
print("Client authenticated") |
||||
self._handle_conn_request(conn) |
||||
except ConnectionAbortedError: |
||||
pass |
||||
|
||||
def serve(self): |
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
||||
try: |
||||
s.bind((self.host, self.port)) |
||||
s.listen(1) |
||||
while True: |
||||
conn, _ = s.accept() |
||||
self._handle(conn) |
||||
finally: |
||||
s.close() |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
server = SocksServer() |
||||
handler = SocksHandler("", 1080, server) |
||||
handler.serve() |
||||
|
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
# Lab9 |
||||
|
||||
Start server: `python3 -m lab9 server` |
||||
|
||||
Start client: `python3 -m lab9 client` |
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
import sys |
||||
from . import client, server |
||||
|
||||
|
||||
def main(): |
||||
if len(sys.argv) < 2: |
||||
print("...") |
||||
print(sys.argv) |
||||
|
||||
if sys.argv[1] == "client": |
||||
client.main() |
||||
elif sys.argv[1] == "server": |
||||
server.main() |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
main() |
||||
|
@ -0,0 +1,30 @@
@@ -0,0 +1,30 @@
|
||||
import socket |
||||
import time |
||||
from .proto import ClientRegisterEvent, NewTaskEvent, SolveResultEvent |
||||
|
||||
SERVER_ADDR = ("127.0.0.1", 30030) |
||||
|
||||
|
||||
def main(): |
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
||||
sock.bind(("0.0.0.0", 30031)) |
||||
hello_packet = ClientRegisterEvent("127.0.0.1", 30031) |
||||
sock.sendto(hello_packet.to_bytes(), SERVER_ADDR) |
||||
while True: |
||||
data = sock.recv(1024) |
||||
message_type = data[0] |
||||
if message_type == 1: |
||||
event = NewTaskEvent.from_bytes(data) |
||||
print("New task recieved:", event.expression) |
||||
time.sleep(0.5) |
||||
result = eval(event.expression) |
||||
print(f"Task {event.identifier} solved. Result: {result}") |
||||
solve_event = SolveResultEvent( |
||||
identifier=event.identifier, result=str(result).encode("utf-8"), |
||||
) |
||||
sock.sendto(solve_event.to_bytes(), SERVER_ADDR) |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
main() |
||||
|
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
import struct |
||||
from dataclasses import dataclass |
||||
|
||||
|
||||
@dataclass() |
||||
class ClientRegisterEvent: |
||||
remote_addr: str |
||||
remote_port: int |
||||
|
||||
@classmethod |
||||
def from_bytes(cls, data: bytes) -> "ClientRegisterEvent": |
||||
addr_len, data = data[1], data[2:] |
||||
addr = data[:addr_len].decode("utf-8") |
||||
port = struct.unpack("H", data[-2:]) |
||||
return cls(remote_addr=addr, remote_port=port[0]) |
||||
|
||||
def to_bytes(self) -> bytes: |
||||
addr = self.remote_addr.encode("utf-8") |
||||
return bytes([0]) + struct.pack(f"B{len(addr)}sH", len(addr), addr, self.remote_port) |
||||
|
||||
|
||||
@dataclass() |
||||
class NewTaskEvent: |
||||
identifier: int |
||||
expression: str |
||||
|
||||
@classmethod |
||||
def from_bytes(cls, data: bytes) -> "NewTaskEvent": |
||||
identifier = struct.unpack("I", data[1:5]) |
||||
expression = data[5:] |
||||
return cls(identifier=identifier[-1], expression=expression.decode("utf-8")) |
||||
|
||||
def to_bytes(self) -> bytes: |
||||
return bytes([1]) + struct.pack("I", self.identifier) + self.expression.encode("utf-8") |
||||
|
||||
|
||||
@dataclass() |
||||
class SolveResultEvent: |
||||
identifier: int |
||||
result: bytes |
||||
|
||||
@classmethod |
||||
def from_bytes(cls, data: bytes) -> "SolveResultEvent": |
||||
data = data[1:] |
||||
struct_fmt = "I" |
||||
header_len = struct.calcsize(struct_fmt) |
||||
identifier, data = struct.unpack("I", data[:header_len]), data[header_len:] |
||||
return cls(identifier=identifier[0], result=data) |
||||
|
||||
def to_bytes(self) -> bytes: |
||||
return bytes([2]) + struct.pack("I", self.identifier) + self.result |
||||
|
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
import socket |
||||
from pprint import pprint |
||||
from typing import List, Tuple |
||||
from .proto import ClientRegisterEvent, NewTaskEvent, SolveResultEvent |
||||
|
||||
Matrix = List[List[int]] |
||||
|
||||
|
||||
def make_tasks(matrix_1: Matrix, matrix_2: Matrix) -> List[NewTaskEvent]: |
||||
result: List[NewTaskEvent] = [] |
||||
for i in range(0, len(matrix_1)): |
||||
row_1, row_2 = matrix_1[i], matrix_2[i] |
||||
eval_str = ", ".join(f"{a} + {b}" for a, b in zip(row_1, row_2)) |
||||
eval_str = f"[{eval_str}]" |
||||
result.append(NewTaskEvent(identifier=len(result), expression=eval_str)) |
||||
return result |
||||
|
||||
|
||||
def build_result(solves: List[SolveResultEvent]) -> Matrix: |
||||
solves = sorted(solves, key=lambda x: x.identifier) |
||||
result: Matrix = [] |
||||
for solve in solves: |
||||
solve_text = solve.result.decode("utf-8") |
||||
s = eval(solve_text) |
||||
result.append(s) |
||||
return result |
||||
|
||||
|
||||
def sum_matrix(sock: socket.socket, matrix_1: Matrix, matrix_2: Matrix) -> Matrix: |
||||
tasks = make_tasks(matrix_1, matrix_2) |
||||
pending_tasks_count = len(tasks) |
||||
results: List[SolveResultEvent] = [] |
||||
clients: List[Tuple[str, int]] = [] |
||||
|
||||
def send_task(remote_addr: str, remote_port: int): |
||||
if len(tasks) == 0: |
||||
return |
||||
task = tasks.pop() |
||||
sock.sendto(task.to_bytes(), (remote_addr, remote_port)) |
||||
print(f"Task #{task.identifier} sent") |
||||
|
||||
while True: |
||||
message, client = sock.recvfrom(1024) |
||||
message_type = message[0] |
||||
|
||||
if message_type == 0: |
||||
event = ClientRegisterEvent.from_bytes(message) |
||||
print(f"New client {event.remote_addr}:{event.remote_port}") |
||||
clients.append((event.remote_addr, event.remote_port)) |
||||
send_task(event.remote_addr, event.remote_port) |
||||
elif message_type == 2: |
||||
event = SolveResultEvent.from_bytes(message) |
||||
results.append(event) |
||||
pending_tasks_count += -1 |
||||
print(f"Solve for task #{event.identifier} received. Result: {event.result.decode('utf-8')}") |
||||
send_task(*client) |
||||
if pending_tasks_count == 0: |
||||
return build_result(results) |
||||
|
||||
|
||||
def main(): |
||||
input_matrix_1 = [ |
||||
[0, 2, 0], |
||||
[1, 0, 1], |
||||
[0, 1, 0], |
||||
] |
||||
input_matrix_2 = [ |
||||
[1, 0, 1], |
||||
[0, 1, 0], |
||||
[1, 0, 1], |
||||
] |
||||
|
||||
udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
||||
udp.bind(("0.0.0.0", 30030)) |
||||
print("Handle 0.0.0.0:30030") |
||||
result = sum_matrix(udp, input_matrix_1, input_matrix_2) |
||||
pprint(result) |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
main() |
||||
|
Reference in new issue