source: trunk/dhcp/dhcpserver.py @ 189

Last change on this file since 189 was 189, checked in by quentin, 17 years ago

Initial checkin of a DHCP server (untested)

File size: 5.4 KB
Line 
1#!/usr/bin/python
2import pydhcplib
3from pydhcplib.dhcp_packet import *
4from pydhcplib.type_hw_addr import hwmac
5from pydhcplib.type_ipv4 import ipv4
6
7from event_logger import Log
8
9import sipb_xen_database
10
11class DhcpBackend:
12    def __init__(self, database=None):
13        if database is not None:
14            sipb_xen_database.connect(database)
15    def findIP(self, mac):
16        value = sipb_xen_database.NIC.get_by(mac_addr=mac)
17        if value is None:
18            return None
19        ip = value.ip
20        if ip is None:  #Deactivated?
21            return None
22        return ip
23
24    def Discover(self, packet):
25        Log.Output(Log.debug,"dhcp_backend : Discover ")
26        chaddr = hwmac(packet.GetHardwareAddress())
27        ip = self.findIP(str(chaddr))
28        if ip is not None:
29            ip = ipv4(ip)
30            Log.Output(Log.debug,"dhcp_backend : Discover result = "+str(ip))
31            packet_parameters = {}
32
33            # FIXME: Other offer parameters go here
34            packet_parameters["yiaddr"] = ip.list()
35           
36            packet.SetMultipleOptions(packet_parameters)
37            return True
38        return False
39       
40    def Request(self, packet):
41        Log.Output(Log.debug, "dhcp_backend : Request")
42       
43        discover = self.Discover(packet)
44       
45        chaddr = hwmac(packet.GetHardwareAddress())
46        request = packet.GetOption("request_ip_address")
47        yiaddr = packet.GetOption("yiaddr")
48
49        if not discover:
50            Log.Output(Log.info,"Unknown MAC address: "+str(chaddr))
51            return False
52       
53        if yiaddr!="0.0.0.0" and yiaddr == request :
54            Log.Output(Log.info,"Ack ip "+str(yiaddr)+" for "+str(chaddr))
55            return True
56        else:
57            Log.Output(Log.info,"Requested ip "+str(request)+" not available for "+str(chaddr))
58        return False
59
60    def Decline(self, packet):
61        pass
62    def Release(self, packet):
63        pass
64   
65
66class DhcpServer(pydhcplib.dhcp_network.DhcpServer):
67    def __init__(self, backend, options = {'client_listenport':68,'server_listenport':67}):
68        pydhcplib.dhcp_network.DhcpServer.__init__(self,"0.0.0.0",options["client_listen_port"],options["server_listen_port"],)
69        self.backend = backend
70        Log.Output(Log.debug, "__init__ DhcpServer")
71
72    def SendPacket(self, packet):
73            """Encode and send the packet."""
74       
75        giaddr = packet.GetOption('giaddr')
76
77        # in all case, if giaddr is set, send packet to relay_agent
78        # network address defines by giaddr
79        if giaddr!=[0,0,0,0] :
80            agent_ip = ".".join(map(str,giaddr))
81            self.SendDhcpPacketTo(agent_ip,packet)
82            Log.Output(Log.debug, "SendPacket to agent : "+agent_ip)
83
84        # FIXME: This shouldn't broadcast if it has an IP address to send
85        # it to instead. See RFC2131 part 4.1 for full details
86        else :
87            Log.Output(Log.debug, "No agent, broadcast packet.")
88            self.SendDhcpPacketTo("255.255.255.255",packet)
89           
90
91    def HandleDhcpDiscover(self, packet):
92        """Build and send DHCPOFFER packet in response to DHCPDISCOVER
93        packet."""
94
95        logmsg = "Get DHCPDISCOVER packet from " + hwmac(packet.GetHardwareAddress()).str()
96
97        Log.Output(Log.info, logmsg)
98        offer = DhcpPacket()
99        offer.CreateDhcpOfferPacketFrom(packet)
100       
101        if self.backend.Discover(offer) :
102            self.SendPacket(offer)
103        # FIXME : what if false ?
104
105
106    def HandleDhcpRequest(self, packet):
107        """Build and send DHCPACK or DHCPNACK packet in response to
108        DHCPREQUEST packet. 4 types of DHCPREQUEST exists."""
109
110        ip = packet.GetOption("request_ip_address")
111        sid = packet.GetOption("server_identifier")
112        ciaddr = packet.GetOption("ciaddr")
113
114        if sid != [0,0,0,0] and ciaddr == [0,0,0,0] :
115            Log.Output(Log.info, "Get DHCPREQUEST_SELECTING_STATE packet")
116
117        elif sid == [0,0,0,0] and ciaddr == [0,0,0,0] and ip :
118            Log.Output(Log.info, "Get DHCPREQUEST_INITREBOOT_STATE packet")
119
120        elif sid == [0,0,0,0] and ciaddr != [0,0,0,0] and not ip :
121            Log.Output(Log.info,"Get DHCPREQUEST_INITREBOOT_STATE packet")
122
123        else : Log.Output(Log.info,"Get DHCPREQUEST_UNKNOWN_STATE packet : not implemented")
124
125        if self.backend.Request(packet) : packet.TransformToDhcpAckPacket()
126        else : packet.TransformToDhcpNackPacket()
127
128        self.SendPacket(packet)
129
130
131
132    # FIXME: These are not yet implemented.
133    def HandleDhcpDecline(self, packet):
134        Log.Output(Log.info, "Get DHCPDECLINE packet")
135        self.backend.Decline(packet)
136       
137    def HandleDhcpRelease(self, packet):
138        Log.Output(Log.info,"Get DHCPRELEASE packet")
139        self.backend.Release(packet)
140       
141    def HandleDhcpInform(self, packet):
142        Log.Output(Log.info, "Get DHCPINFORM packet")
143
144        if self.backend.Request(packet) :
145            packet.TransformToDhcpAckPacket()
146            # FIXME : Remove lease_time from options
147            self.SendPacket(packet)
148
149        # FIXME : what if false ?
150
151if '__main__' == __name__:
152    event_logger.init("stdout", event_logger.INFO, {})
153    options = { "server_listen_port":67,
154                "client_listen_port":68,
155                "listen_address":"0.0.0.0"}
156    backend = DhcpBackend('postgres://sipb-xen@sipb-xen-dev/sipb_xen')
157    server = DhcpServer(backend, options)
158
159    while True : server.GetNextDhcpPacket()
Note: See TracBrowser for help on using the repository browser.