Skip to content

Commit 356d7b2

Browse files
committed
Working on converting PyTCP to library
1 parent 83e14aa commit 356d7b2

File tree

234 files changed

+1047
-911
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

234 files changed

+1047
-911
lines changed

.vscode/settings.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"python.analysis.extraPaths": [
3+
"./pytcp"
4+
],
5+
"python.formatting.provider": "black"
6+
}

Makefile

+9-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,15 @@ lint: venv
3030
@echo '<<< MYPY'
3131
@./$(VENV)/bin/mypy -p pytcp
3232

33-
test: venv
34-
@echo '<<< TESTSLIDE'
35-
@./$(VENV)/bin/testslide tests/*.py
33+
test_unit: venv
34+
@echo '<<< TESTSLIDE UNIT'
35+
@./$(VENV)/bin/testslide tests/unit/*.py
36+
37+
test_integration: venv
38+
@echo '<<< TESTSLIDE INTEGRATION'
39+
@./$(VENV)/bin/testslide tests/integration/*.py
40+
41+
test: test_unit test_integration
3642

3743
bridge:
3844
@brctl addbr br0

examples/main.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import sys
5+
import time
6+
7+
current = os.path.dirname(os.path.realpath(__file__))
8+
parent = os.path.dirname(current)
9+
sys.path.append(parent)
10+
11+
from pytcp import TcpIpStack
12+
13+
def main():
14+
stack = TcpIpStack("tap7")
15+
stack.start()
16+
time.sleep(60)
17+
stack.stop()
18+
19+
20+
21+
if __name__ == "__main__":
22+
main()

pytcp/__init__.py

+68
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,71 @@
2929
#
3030
# ver 2.7
3131
#
32+
33+
34+
import fcntl
35+
import os
36+
import struct
37+
import sys
38+
import time
39+
40+
import pytcp.misc.stack as stack
41+
from pytcp.lib.logger import log
42+
from pytcp.subsystems.packet_handler import PacketHandler
43+
from pytcp.subsystems.rx_ring import RxRing
44+
from pytcp.subsystems.stack_cli_server import StackCliServer
45+
from pytcp.subsystems.timer import Timer
46+
from pytcp.subsystems.tx_ring import TxRing
47+
48+
TUNSETIFF = 0x400454CA
49+
IFF_TAP = 0x0002
50+
IFF_NO_PI = 0x1000
51+
52+
53+
class TcpIpStack:
54+
"""
55+
Main PyTCP library class.
56+
"""
57+
58+
def __init__(self, interface: str):
59+
"""
60+
Initialize stack on given interface.
61+
"""
62+
63+
try:
64+
self.tap = os.open("/dev/net/tun", os.O_RDWR)
65+
66+
except FileNotFoundError:
67+
log("stack", "<CRIT>Unable to access '/dev/net/tun' device</>")
68+
sys.exit(-1)
69+
70+
fcntl.ioctl(
71+
self.tap,
72+
TUNSETIFF,
73+
struct.pack("16sH", interface.encode(), IFF_TAP | IFF_NO_PI),
74+
)
75+
76+
def start(self):
77+
"""
78+
Start stack components.
79+
"""
80+
stack.timer.start()
81+
stack.arp_cache.start()
82+
stack.nd_cache.start()
83+
stack.rx_ring.start(self.tap)
84+
stack.tx_ring.start(self.tap)
85+
stack.packet_handler.start()
86+
stack.packet_handler.assign_ip6_addresses()
87+
stack.packet_handler.assign_ip4_addresses()
88+
stack.packet_handler.log_stack_address_info()
89+
90+
def stop(self):
91+
"""
92+
Stop stack components.
93+
"""
94+
stack.packet_handler.stop()
95+
stack.tx_ring.stop()
96+
stack.rx_ring.stop()
97+
stack.arp_cache.stop()
98+
stack.nd_cache.stop()
99+
stack.timer.stop()

pytcp/clients/icmp_echo.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@
3838
import time
3939
from datetime import datetime
4040

41-
import misc.stack as stack
42-
from lib.ip4_address import Ip4Address
43-
from lib.ip6_address import Ip6Address
44-
from lib.logger import log
45-
from misc.ip_helper import str_to_ip
41+
import pytcp.misc.stack as stack
42+
from pytcp.lib.ip4_address import Ip4Address
43+
from pytcp.lib.ip6_address import Ip6Address
44+
from pytcp.lib.logger import log
45+
from pytcp.misc.ip_helper import str_to_ip
4646

4747

4848
class ClientIcmpEcho:

pytcp/clients/tcp_echo.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@
3838
import time
3939

4040
import lib.socket as socket
41-
from lib.logger import log
42-
from misc.ip_helper import ip_version
41+
42+
from pytcp.lib.logger import log
43+
from pytcp.misc.ip_helper import ip_version
4344

4445

4546
class ClientTcpEcho:

pytcp/clients/udp_echo.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@
3737
import time
3838

3939
import lib.socket as socket
40-
from lib.logger import log
41-
from misc.ip_helper import ip_version
40+
41+
from pytcp.lib.logger import log
42+
from pytcp.misc.ip_helper import ip_version
4243

4344

4445
class ClientUdpEcho:

pytcp/dhcp4/client.py

+28-19
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,22 @@
3636
import random
3737
from typing import TYPE_CHECKING
3838

39-
import dhcp4.ps
40-
import lib.socket as socket
41-
from lib.ip4_address import Ip4Address
42-
from lib.logger import log
39+
import pytcp.lib.socket as socket
40+
from pytcp.dhcp4.ps import (
41+
DHCP4_MSG_DISCOVER,
42+
DHCP4_MSG_REQUEST,
43+
DHCP4_MSG_OFFER,
44+
DHCP4_MSG_ACK,
45+
DHCP4_OP_REQUEST,
46+
DHCP4_OPT_ROUTER,
47+
DHCP4_OPT_SUBNET_MASK,
48+
Dhcp4Packet,
49+
)
50+
from pytcp.lib.ip4_address import Ip4Address
51+
from pytcp.lib.logger import log
4352

4453
if TYPE_CHECKING:
45-
from lib.mac_address import MacAddress
54+
from pytcp.lib.mac_address import MacAddress
4655

4756

4857
class Dhcp4Client:
@@ -69,18 +78,18 @@ def fetch(self) -> tuple[str, str | None] | tuple[None, None]:
6978

7079
# Send DHCP Discover
7180
s.send(
72-
dhcp4.ps.Dhcp4Packet(
73-
dhcp_op=dhcp4.ps.DHCP4_OP_REQUEST,
81+
Dhcp4Packet(
82+
dhcp_op=DHCP4_OP_REQUEST,
7483
dhcp_xid=dhcp_xid,
7584
dhcp_ciaddr=Ip4Address("0.0.0.0"),
7685
dhcp_yiaddr=Ip4Address("0.0.0.0"),
7786
dhcp_siaddr=Ip4Address("0.0.0.0"),
7887
dhcp_giaddr=Ip4Address("0.0.0.0"),
7988
dhcp_chaddr=bytes(self._mac_address),
80-
dhcp_msg_type=dhcp4.ps.DHCP4_MSG_DISCOVER,
89+
dhcp_msg_type=DHCP4_MSG_DISCOVER,
8190
dhcp_param_req_list=[
82-
dhcp4.ps.DHCP4_OPT_SUBNET_MASK,
83-
dhcp4.ps.DHCP4_OPT_ROUTER,
91+
DHCP4_OPT_SUBNET_MASK,
92+
DHCP4_OPT_ROUTER,
8493
],
8594
dhcp_host_name="PyTCP",
8695
).raw_packet
@@ -90,14 +99,14 @@ def fetch(self) -> tuple[str, str | None] | tuple[None, None]:
9099

91100
# Wait for DHCP Offer
92101
try:
93-
dhcp_packet_rx = dhcp4.ps.Dhcp4Packet(s.recv(timeout=5))
102+
dhcp_packet_rx = Dhcp4Packet(s.recv(timeout=5))
94103
except socket.ReceiveTimeout:
95104
if __debug__:
96105
log("dhcp4", "Didn't receive DHCP Offer message - timeout")
97106
s.close()
98107
return None, None
99108

100-
if dhcp_packet_rx.dhcp_msg_type != dhcp4.ps.DHCP4_MSG_OFFER:
109+
if dhcp_packet_rx.dhcp_msg_type != DHCP4_MSG_OFFER:
101110
if __debug__:
102111
log(
103112
"dhcp4",
@@ -122,20 +131,20 @@ def fetch(self) -> tuple[str, str | None] | tuple[None, None]:
122131

123132
# Send DHCP Request
124133
s.send(
125-
dhcp4.ps.Dhcp4Packet(
126-
dhcp_op=dhcp4.ps.DHCP4_OP_REQUEST,
134+
Dhcp4Packet(
135+
dhcp_op=DHCP4_OP_REQUEST,
127136
dhcp_xid=dhcp_xid,
128137
dhcp_ciaddr=Ip4Address("0.0.0.0"),
129138
dhcp_yiaddr=Ip4Address("0.0.0.0"),
130139
dhcp_siaddr=Ip4Address("0.0.0.0"),
131140
dhcp_giaddr=Ip4Address("0.0.0.0"),
132141
dhcp_chaddr=bytes(self._mac_address),
133-
dhcp_msg_type=dhcp4.ps.DHCP4_MSG_REQUEST,
142+
dhcp_msg_type=DHCP4_MSG_REQUEST,
134143
dhcp_srv_id=dhcp_srv_id,
135144
dhcp_req_ip_addr=dhcp_yiaddr,
136145
dhcp_param_req_list=[
137-
dhcp4.ps.DHCP4_OPT_SUBNET_MASK,
138-
dhcp4.ps.DHCP4_OPT_ROUTER,
146+
DHCP4_OPT_SUBNET_MASK,
147+
DHCP4_OPT_ROUTER,
139148
],
140149
dhcp_host_name="PyTCP",
141150
).raw_packet
@@ -150,14 +159,14 @@ def fetch(self) -> tuple[str, str | None] | tuple[None, None]:
150159

151160
# Wait for DHCP Ack
152161
try:
153-
dhcp_packet_rx = dhcp4.ps.Dhcp4Packet(s.recv(timeout=5))
162+
dhcp_packet_rx = Dhcp4Packet(s.recv(timeout=5))
154163
except socket.ReceiveTimeout:
155164
if __debug__:
156165
log("dhcp4", "Didn't receive DHCP ACK message - timeout")
157166
s.close()
158167
return None, None
159168

160-
if dhcp_packet_rx.dhcp_msg_type != dhcp4.ps.DHCP4_MSG_ACK:
169+
if dhcp_packet_rx.dhcp_msg_type != DHCP4_MSG_ACK:
161170
if __debug__:
162171
log(
163172
"dhcp4",

pytcp/dhcp4/ps.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
import struct
3737

38-
from lib.ip4_address import Ip4Address, Ip4Mask
38+
from pytcp.lib.ip4_address import Ip4Address, Ip4Mask
3939

4040
# DHCP packet header (RFC 2131)
4141

pytcp/lib/ip4_address.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
import socket
3838
import struct
3939

40-
from lib.ip_address import (
40+
from pytcp.lib.ip_address import (
4141
IpAddress,
4242
IpAddressFormatError,
4343
IpHost,
@@ -47,7 +47,7 @@
4747
IpNetwork,
4848
IpNetworkFormatError,
4949
)
50-
from lib.mac_address import MacAddress
50+
from pytcp.lib.mac_address import MacAddress
5151

5252
IP4_REGEX = (
5353
r"((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}"

pytcp/lib/ip6_address.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
import socket
3838
import struct
3939

40-
from lib.ip_address import (
40+
from pytcp.lib.ip_address import (
4141
IpAddress,
4242
IpAddressFormatError,
4343
IpHost,
@@ -47,7 +47,7 @@
4747
IpNetwork,
4848
IpNetworkFormatError,
4949
)
50-
from lib.mac_address import MacAddress
50+
from pytcp.lib.mac_address import MacAddress
5151

5252
IP6_REGEX = (
5353
r"(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|"

pytcp/lib/ip_address.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@
3838
from typing import TYPE_CHECKING
3939

4040
if TYPE_CHECKING:
41-
from lib.ip4_address import Ip4Address
42-
from lib.ip6_address import Ip6Address, Ip6Host
43-
from lib.mac_address import MacAddress
41+
from pytcp.lib.ip4_address import Ip4Address
42+
from pytcp.lib.ip6_address import Ip6Address, Ip6Host
43+
from pytcp.lib.mac_address import MacAddress
4444

4545

4646
class IpAddressFormatError(Exception):

pytcp/lib/logger.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@
3434
from __future__ import annotations
3535

3636
import inspect
37+
import os
38+
import sys
3739
import time
3840

39-
import config
41+
import pytcp.config as config
4042

4143
STYLES = {
4244
"</>": "\33[0m",

pytcp/lib/socket.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,19 @@
3737
from enum import IntEnum
3838
from typing import TYPE_CHECKING
3939

40-
import config
41-
import misc.stack as stack
42-
from lib.ip4_address import Ip4Address, Ip4AddressFormatError
43-
from lib.ip6_address import Ip6Address, Ip6AddressFormatError
44-
from misc.ip_helper import pick_local_ip_address
45-
from protocols.tcp.metadata import TcpMetadata
46-
from protocols.tcp.session import FsmState, TcpSession
47-
from protocols.udp.metadata import UdpMetadata
40+
import pytcp.config as config
41+
import pytcp.misc.stack as stack
42+
from pytcp.lib.ip4_address import Ip4Address, Ip4AddressFormatError
43+
from pytcp.lib.ip6_address import Ip6Address, Ip6AddressFormatError
44+
from pytcp.misc.ip_helper import pick_local_ip_address
45+
from pytcp.protocols.tcp.metadata import TcpMetadata
46+
from pytcp.protocols.tcp.session import FsmState, TcpSession
47+
from pytcp.protocols.udp.metadata import UdpMetadata
4848

4949
if TYPE_CHECKING:
5050
from threading import Semaphore
5151

52-
from lib.ip_address import IpAddress
52+
from pytcp.lib.ip_address import IpAddress
5353

5454

5555
class gaierror(OSError):
@@ -108,8 +108,8 @@ def socket(
108108

109109
assert type is SOCK_STREAM or type is SOCK_DGRAM
110110

111-
from protocols.tcp.socket import TcpSocket
112-
from protocols.udp.socket import UdpSocket
111+
from pytcp.protocols.tcp.socket import TcpSocket
112+
from pytcp.protocols.udp.socket import UdpSocket
113113

114114
if type is SOCK_DGRAM:
115115
return UdpSocket(family)

0 commit comments

Comments
 (0)