def start(self, transactionType: TransactionType) -> DhcpPacket:
        """Begin a DHCP transaction of given type.

        Returns the DHCP packet to send to the server.
        """

        if transactionType == TransactionType.DISCOVER:
            self.transactionType = transactionType
            return DhcpPacket.fromArgs(
                OpCode.REQUEST,  #OpCode
                self.transactionId,
                0,  #secondsElapsed
                self.clientIp,  #clientIp
                IPv4Address('0.0.0.0'),  #yourIp
                IPv4Address('255.255.255.255'),  #serverIp
                self.clientHardwareAddr,
                MessageType.DISCOVER,
                int(DEFAULT_LEASE_TIME))

        elif transactionType == TransactionType.RENEW:
            return DhcpPacket.fromArgs(
                OpCode.REQUEST,  #OpCode
                self.transactionId,
                0,  #secondsElapsed
                self.clientIp,  #clientIp
                self.yourIp,  #yourIp
                IPv4Address('255.255.255.255'),  #serverIp
                self.clientHardwareAddr,
                MessageType.REQUEST,
                int(DEFAULT_LEASE_TIME))
    def recv(self, packet: DhcpPacket) -> Tuple[bool, Optional[DhcpPacket]]:
        """Recieve a reply from the server and returns the response packet.

        The response packet may be None to indicate conclusion of the session.
        """
        self._phase += 1

        if self._phase == 1:
            if packet.clientHardwareAddr == self.clientHardwareAddr:
                if packet.messageType == MessageType.OFFER:
                    print("Client: Received offer message")
                    print("Client: Sending request message")
                    return False, DhcpPacket.fromArgs(
                        OpCode.REQUEST,  #opCode
                        packet.transactionId,
                        int(time.time() - self.transactionStartTime),
                        packet.clientIp,  #clientIP
                        packet.yourIp,
                        packet.serverIp,
                        packet.clientHardwareAddr,
                        MessageType.REQUEST,
                        int(DEFAULT_LEASE_TIME))
                if packet.messageType == MessageType.ACK:
                    print("Client: Received ACK message")
                    print("Client: IP has already been issued to client: " +
                          str(packet.yourIp))
                    return True, None
                else:
                    print("Client: Error: Phase-MessageType mismatch.")
                    return False, None
        elif packet.messageType == MessageType.DECLINE:
            print("Client: REQUEST DECLINED")
            return False, None

        elif packet.messageType == MessageType.ACK:
            if packet.clientHardwareAddr == self.clientHardwareAddr:
                if self._phase == 3:
                    if packet.messageType == MessageType.ACK:
                        self.clientIp = packet.yourIp
                        print("Client: Received ACK message")
                        print(f"Client: Renewed IP {self.clientIp}")
                        return True, DhcpPacket.fromArgs(
                            OpCode.REQUEST,  #opCode
                            packet.transactionId,
                            int(time.time() - self.transactionStartTime),
                            packet.clientIp,  #clientIP
                            packet.yourIp,
                            packet.serverIp,
                            packet.clientHardwareAddr,
                            MessageType.ACK,
                            int(DEFAULT_LEASE_TIME))
                    else:
                        print("Client: Error: Phase-MessageType mismatch")
            else:
                print("Client: MAC address does not match, could not ACK.")
            return True, None
        return True, None
Exemplo n.º 3
0
    def __gen(
        self, packet: DhcpPacket
    ) -> Generator[DhcpPacket, DhcpPacket, Optional[DhcpPacket]]:
        """Implements self.recv as a coroutine using a python generator."""

        self.transactionId = packet.transactionId
        self.clientHardwareAddr = packet.clientHardwareAddr

        if packet.messageType is MessageType.DISCOVER:
            self.transactionType = TransactionType.DISCOVER
            log.info('Start DISCOVER transaction')
            log.info('DISCOVER transaction: Reply with OFFER of '
                     f'{self.yourIp} for {self.leaseTime} seconds')
            packet = yield DhcpPacket.fromArgs(
                OpCode.REPLY, self.transactionId, packet.secondsElapsed,
                packet.clientIp, self.yourIp, self.serverIp,
                packet.clientHardwareAddr, MessageType.OFFER, self.leaseTime)

            if packet.messageType is MessageType.REQUEST:
                log.info('DISCOVER transaction: Recieved REQUEST of '
                         f'{packet.yourIp} for {packet.leaseTime} seconds')
                self.requestIp = packet.yourIp
                return DhcpPacket.fromArgs(OpCode.REPLY, self.transactionId,
                                           packet.secondsElapsed,
                                           packet.clientIp, self.yourIp,
                                           self.serverIp,
                                           packet.clientHardwareAddr,
                                           MessageType.ACK, self.leaseTime)
            else:
                raise ValueError(
                    f'Expected DHCP REQUEST. Got {packet.messageType.name}.')

        elif packet.messageType is MessageType.REQUEST:
            self.transactionType = TransactionType.RENEW
            log.info('Start RENEW transaction')
            log.info('RENEW transaction: Recieved REQUEST of '
                     f'{packet.yourIp} for {packet.leaseTime} seconds')
            packet = yield DhcpPacket.fromArgs(
                OpCode.REPLY, self.transactionId, packet.secondsElapsed,
                packet.clientIp, self.yourIp, self.serverIp,
                packet.clientHardwareAddr, MessageType.ACK, self.leaseTime)

            if packet.messageType is MessageType.ACK:
                self.requestIp = packet.yourIp
                return None
            else:
                raise ValueError(
                    f'Expected DHCP ACK. Got {packet.messageType.name}.')

        else:
            raise ValueError('Unsupported transaction.')
Exemplo n.º 4
0
def parsePacket(packet: bytes) -> DhcpPacket:
    partialPacket = DhcpPacket.fromPacket(
        packet[:DhcpPacket.initialPacketSize])
    offset: int = DhcpPacket.initialPacketSize
    while partialPacket.bytesNeeded > 0:
        nextOffset = offset + partialPacket.bytesNeeded
        partialPacket.parseMore(packet[offset:offset +
                                       partialPacket.bytesNeeded])
        offset = nextOffset

    return partialPacket.packet
 def release(self) -> DhcpPacket:
     return DhcpPacket.fromArgs(
         OpCode.REQUEST,  #opCode
         0,  #ID
         0,  #elapsed time
         IPv4Address('0.0.0.0'),  #clientIP
         IPv4Address('0.0.0.0'),  #yourIP
         IPv4Address('255.255.255.255'),  #serverIP
         self.clientHardwareAddr,
         MessageType.RELEASE,
         int(DEFAULT_LEASE_TIME))
Exemplo n.º 6
0
import logging
from typing import cast
from ipaddress import IPv4Address, IPv4Interface

logging.basicConfig(
    level=logging.DEBUG,
    format='%(levelname)s: %(name)s - %(message)s')

if __name__ == '__main__':
    server = DhcpServer(IPv4Interface('192.168.0.255/24'))

    packet1 = DhcpPacket.fromArgs(
        OpCode.REQUEST,
        8,
        34,
        IPv4Address(0),
        IPv4Address(0),
        IPv4Address(0),
        4,
        MessageType.DISCOVER)

    ret1 = cast(DhcpPacket, server.recv(packet1))
    leaseTime = cast(int, ret1.leaseTime)
    print()

    packet2 = DhcpPacket.fromArgs(
        OpCode.REQUEST,
        8,
        34,
        IPv4Address(0),
        ret1.yourIp,
Exemplo n.º 7
0
    def recv(self, packet: DhcpPacket) -> Optional[DhcpPacket]:
        """Recieves a DHCP packet and returns a response packet.

        The response packet may be None to indicate to not reply.
        """

        log.info(f'Recieved {packet.messageType.name} '
                 f'with MAC of {packet.clientHardwareAddr} and '
                 f'ID of {packet.transactionId}')
        log.debug(f'Recieved packet: {packet}')

        # self.__timeoutTransactions()

        transaction: Optional[ServerTransaction] = None
        returnPacket: Optional[DhcpPacket] = None

        if packet.transactionId not in self.__curTransactions:
            if packet.messageType is MessageType.DISCOVER:
                if packet.clientHardwareAddr not in self.__leasedIpsByMacs:
                    self.__timeoutIps()
                    self.__setNextIp()
                    if self.__nextIp is not None:
                        self.__markIp(self.__nextIp)
                        transaction = ServerTransaction()
                        transaction.transactionId = packet.transactionId
                        transaction.yourIp = self.__nextIp
                        transaction.serverIp = self.interface.ip
                        transaction.leaseTime = int(DEFAULT_LEASE_TIME)
                        self.__registerTransaction(transaction)

                else:
                    leaseTime = int(self.__leasedIps[self.__leasedIpsByMacs[
                        packet.clientHardwareAddr]][0] - time.time())
                    returnPacket = DhcpPacket.fromArgs(
                        OpCode.REPLY, packet.transactionId,
                        packet.secondsElapsed,
                        self.__leasedIpsByMacs[packet.clientHardwareAddr],
                        self.__leasedIpsByMacs[packet.clientHardwareAddr],
                        self.interface.ip, packet.clientHardwareAddr,
                        MessageType.ACK, leaseTime if leaseTime >= 0 else 0)

            elif packet.messageType is MessageType.REQUEST:
                if packet.yourIp not in self.__leasedIps:
                    self.__markIp(packet.yourIp)
                    transaction = ServerTransaction()
                    transaction.transactionId = packet.transactionId
                    transaction.yourIp = packet.yourIp
                    transaction.serverIp = self.interface.ip
                    transaction.leaseTime = int(DEFAULT_LEASE_TIME)
                    self.__registerTransaction(transaction)
                else:
                    returnPacket = DhcpPacket.fromArgs(
                        OpCode.REPLY,
                        packet.transactionId, packet.secondsElapsed,
                        IPv4Address(0), IPv4Address(0), self.interface.ip,
                        packet.clientHardwareAddr, MessageType.NAK)

            elif packet.messageType is MessageType.RELEASE:
                if packet.clientHardwareAddr in self.__leasedIpsByMacs:
                    self.__freeIp(
                        self.__leasedIpsByMacs[packet.clientHardwareAddr])
                else:
                    log.info(
                        f'No IP to release for {packet.clientHardwareAddr}')

        else:
            transaction = self.__curTransactions[packet.transactionId]

        if transaction is not None:
            try:
                isTransactionOver, returnPacket = transaction.recv(packet)
            except ValueError as ve:
                log.error(f'Transaction error: {ve}')
                self.__unmarkIp(transaction.yourIp)
                self.__freeTransaction(transaction.transactionId)
                returnPacket = DhcpPacket.fromArgs(
                    OpCode.REPLY,
                    transaction.transactionId, packet.secondsElapsed,
                    IPv4Address(0), IPv4Address(0), self.interface.ip,
                    transaction.clientHardwareAddr, MessageType.NAK)
            else:
                if isTransactionOver:
                    self.__unmarkIp(transaction.yourIp)
                    if transaction.transactionType is TransactionType.DISCOVER:
                        if transaction.requestIp not in self.__leasedIps:
                            self.__leaseIp(transaction.yourIp,
                                           transaction.clientHardwareAddr)
                        else:
                            returnPacket = DhcpPacket.fromArgs(
                                OpCode.REPLY, transaction.transactionId,
                                packet.secondsElapsed, packet.yourIp,
                                IPv4Address(0), self.interface.ip,
                                transaction.clientHardwareAddr,
                                MessageType.NAK)
                    elif transaction.transactionType is TransactionType.RENEW:
                        self.__leaseIp(transaction.yourIp,
                                       transaction.clientHardwareAddr)

                    self.__freeTransaction(transaction.transactionId)

        log.debug(f'Return packet: {returnPacket}')
        return returnPacket