| [189] | 1 | #!/usr/bin/python | 
|---|
| [191] | 2 | import sys | 
|---|
| [190] | 3 | sys.path.append('pydhcplib/') | 
|---|
| [189] | 4 | import pydhcplib | 
|---|
| [190] | 5 | import pydhcplib.dhcp_network | 
|---|
| [189] | 6 | from pydhcplib.dhcp_packet import * | 
|---|
 | 7 | from pydhcplib.type_hw_addr import hwmac | 
|---|
 | 8 | from pydhcplib.type_ipv4 import ipv4 | 
|---|
| [191] | 9 | from pydhcplib.type_strlist import strlist | 
|---|
| [189] | 10 |  | 
|---|
| [190] | 11 | import event_logger | 
|---|
 | 12 | if '__main__' == __name__: | 
|---|
| [191] | 13 |     event_logger.init("stdout", 'DEBUG', {}) | 
|---|
| [189] | 14 | from event_logger import Log | 
|---|
 | 15 |  | 
|---|
 | 16 | import sipb_xen_database | 
|---|
 | 17 |  | 
|---|
| [191] | 18 | dhcp_options = {'subnet_mask': '255.255.0.0', | 
|---|
 | 19 |                 'router': '18.181.0.1', | 
|---|
 | 20 |                 'domain_name_server': '18.70.0.160,18.71.0.151,18.72.0.3', | 
|---|
 | 21 |                 'domain_name': 'mit.edu'} | 
|---|
 | 22 |      | 
|---|
 | 23 |  | 
|---|
| [189] | 24 | class DhcpBackend: | 
|---|
 | 25 |     def __init__(self, database=None): | 
|---|
 | 26 |         if database is not None: | 
|---|
 | 27 |             sipb_xen_database.connect(database) | 
|---|
 | 28 |     def findIP(self, mac): | 
|---|
 | 29 |         value = sipb_xen_database.NIC.get_by(mac_addr=mac) | 
|---|
 | 30 |         if value is None: | 
|---|
 | 31 |             return None | 
|---|
 | 32 |         ip = value.ip | 
|---|
 | 33 |         if ip is None:  #Deactivated? | 
|---|
 | 34 |             return None | 
|---|
 | 35 |         return ip | 
|---|
| [191] | 36 |     def getParameters(self): | 
|---|
 | 37 |         options = {} | 
|---|
 | 38 |         for parameter, value in dhcp_options.iteritems(): | 
|---|
 | 39 |             option_type = DhcpOptionsTypes[DhcpOptions[parameter]] | 
|---|
| [189] | 40 |  | 
|---|
| [191] | 41 |             if option_type == "ipv4" : | 
|---|
 | 42 |                 # this is a single ip address | 
|---|
 | 43 |                 options[parameter] = map(int,value.split(".")) | 
|---|
 | 44 |             elif option_type == "ipv4+" : | 
|---|
 | 45 |                 # this is multiple ip address | 
|---|
 | 46 |                 iplist = value.split(",") | 
|---|
 | 47 |                 opt = [] | 
|---|
 | 48 |                 for single in iplist : | 
|---|
 | 49 |                     opt.append(ipv4(single).list()) | 
|---|
 | 50 |                 options[parameter] = opt | 
|---|
 | 51 |             elif option_type == "32-bits" : | 
|---|
 | 52 |                 # This is probably a number... | 
|---|
 | 53 |                 digit = int(value) | 
|---|
 | 54 |                 options[parameter] = [digit>>24&0xFF,(digit>>16)&0xFF,(digit>>8)&0xFF,digit&0xFF] | 
|---|
 | 55 |             elif option_type == "16-bits" : | 
|---|
 | 56 |                 digit = int(value) | 
|---|
 | 57 |                 options[parameter] = [(digit>>8)&0xFF,digit&0xFF] | 
|---|
 | 58 |  | 
|---|
 | 59 |             elif option_type == "char" : | 
|---|
 | 60 |                 digit = int(value) | 
|---|
 | 61 |                 options[parameter] = [digit&0xFF] | 
|---|
 | 62 |  | 
|---|
 | 63 |             elif option_type == "bool" : | 
|---|
 | 64 |                 if value=="False" or value=="false" or value==0 : | 
|---|
 | 65 |                     options[parameter] = [0] | 
|---|
 | 66 |                 else : options[parameter] = [1] | 
|---|
 | 67 |                      | 
|---|
 | 68 |             elif option_type == "string" : | 
|---|
 | 69 |                 options[parameter] = strlist(value).list() | 
|---|
 | 70 |                  | 
|---|
 | 71 |             else : | 
|---|
 | 72 |                 options[parameter] = strlist(value).list() | 
|---|
 | 73 |         return options | 
|---|
 | 74 |  | 
|---|
| [189] | 75 |     def Discover(self, packet): | 
|---|
 | 76 |         Log.Output(Log.debug,"dhcp_backend : Discover ") | 
|---|
 | 77 |         chaddr = hwmac(packet.GetHardwareAddress()) | 
|---|
 | 78 |         ip = self.findIP(str(chaddr)) | 
|---|
 | 79 |         if ip is not None: | 
|---|
 | 80 |             ip = ipv4(ip) | 
|---|
 | 81 |             Log.Output(Log.debug,"dhcp_backend : Discover result = "+str(ip)) | 
|---|
| [191] | 82 |             packet_parameters = self.getParameters() | 
|---|
| [189] | 83 |  | 
|---|
 | 84 |             # FIXME: Other offer parameters go here | 
|---|
 | 85 |             packet_parameters["yiaddr"] = ip.list() | 
|---|
 | 86 |              | 
|---|
 | 87 |             packet.SetMultipleOptions(packet_parameters) | 
|---|
 | 88 |             return True | 
|---|
 | 89 |         return False | 
|---|
 | 90 |          | 
|---|
 | 91 |     def Request(self, packet): | 
|---|
 | 92 |         Log.Output(Log.debug, "dhcp_backend : Request") | 
|---|
 | 93 |          | 
|---|
 | 94 |         discover = self.Discover(packet) | 
|---|
 | 95 |          | 
|---|
 | 96 |         chaddr = hwmac(packet.GetHardwareAddress()) | 
|---|
 | 97 |         request = packet.GetOption("request_ip_address") | 
|---|
 | 98 |         yiaddr = packet.GetOption("yiaddr") | 
|---|
 | 99 |  | 
|---|
 | 100 |         if not discover: | 
|---|
 | 101 |             Log.Output(Log.info,"Unknown MAC address: "+str(chaddr)) | 
|---|
 | 102 |             return False | 
|---|
 | 103 |          | 
|---|
 | 104 |         if yiaddr!="0.0.0.0" and yiaddr == request : | 
|---|
 | 105 |             Log.Output(Log.info,"Ack ip "+str(yiaddr)+" for "+str(chaddr)) | 
|---|
 | 106 |             return True | 
|---|
 | 107 |         else: | 
|---|
 | 108 |             Log.Output(Log.info,"Requested ip "+str(request)+" not available for "+str(chaddr)) | 
|---|
 | 109 |         return False | 
|---|
 | 110 |  | 
|---|
 | 111 |     def Decline(self, packet): | 
|---|
 | 112 |         pass | 
|---|
 | 113 |     def Release(self, packet): | 
|---|
 | 114 |         pass | 
|---|
 | 115 |      | 
|---|
 | 116 |  | 
|---|
 | 117 | class DhcpServer(pydhcplib.dhcp_network.DhcpServer): | 
|---|
 | 118 |     def __init__(self, backend, options = {'client_listenport':68,'server_listenport':67}): | 
|---|
 | 119 |         pydhcplib.dhcp_network.DhcpServer.__init__(self,"0.0.0.0",options["client_listen_port"],options["server_listen_port"],) | 
|---|
 | 120 |         self.backend = backend | 
|---|
 | 121 |         Log.Output(Log.debug, "__init__ DhcpServer") | 
|---|
 | 122 |  | 
|---|
 | 123 |     def SendPacket(self, packet): | 
|---|
| [190] | 124 |         """Encode and send the packet.""" | 
|---|
| [189] | 125 |          | 
|---|
 | 126 |         giaddr = packet.GetOption('giaddr') | 
|---|
 | 127 |  | 
|---|
 | 128 |         # in all case, if giaddr is set, send packet to relay_agent | 
|---|
 | 129 |         # network address defines by giaddr | 
|---|
 | 130 |         if giaddr!=[0,0,0,0] : | 
|---|
 | 131 |             agent_ip = ".".join(map(str,giaddr)) | 
|---|
 | 132 |             self.SendDhcpPacketTo(agent_ip,packet) | 
|---|
 | 133 |             Log.Output(Log.debug, "SendPacket to agent : "+agent_ip) | 
|---|
 | 134 |  | 
|---|
 | 135 |         # FIXME: This shouldn't broadcast if it has an IP address to send | 
|---|
 | 136 |         # it to instead. See RFC2131 part 4.1 for full details | 
|---|
 | 137 |         else : | 
|---|
 | 138 |             Log.Output(Log.debug, "No agent, broadcast packet.") | 
|---|
 | 139 |             self.SendDhcpPacketTo("255.255.255.255",packet) | 
|---|
 | 140 |              | 
|---|
 | 141 |  | 
|---|
 | 142 |     def HandleDhcpDiscover(self, packet): | 
|---|
 | 143 |         """Build and send DHCPOFFER packet in response to DHCPDISCOVER | 
|---|
 | 144 |         packet.""" | 
|---|
 | 145 |  | 
|---|
 | 146 |         logmsg = "Get DHCPDISCOVER packet from " + hwmac(packet.GetHardwareAddress()).str() | 
|---|
 | 147 |  | 
|---|
 | 148 |         Log.Output(Log.info, logmsg) | 
|---|
 | 149 |         offer = DhcpPacket() | 
|---|
 | 150 |         offer.CreateDhcpOfferPacketFrom(packet) | 
|---|
 | 151 |          | 
|---|
| [191] | 152 |         if self.backend.Discover(offer): | 
|---|
| [189] | 153 |             self.SendPacket(offer) | 
|---|
 | 154 |         # FIXME : what if false ? | 
|---|
 | 155 |  | 
|---|
 | 156 |  | 
|---|
 | 157 |     def HandleDhcpRequest(self, packet): | 
|---|
 | 158 |         """Build and send DHCPACK or DHCPNACK packet in response to | 
|---|
 | 159 |         DHCPREQUEST packet. 4 types of DHCPREQUEST exists.""" | 
|---|
 | 160 |  | 
|---|
 | 161 |         ip = packet.GetOption("request_ip_address") | 
|---|
 | 162 |         sid = packet.GetOption("server_identifier") | 
|---|
 | 163 |         ciaddr = packet.GetOption("ciaddr") | 
|---|
 | 164 |  | 
|---|
 | 165 |         if sid != [0,0,0,0] and ciaddr == [0,0,0,0] : | 
|---|
 | 166 |             Log.Output(Log.info, "Get DHCPREQUEST_SELECTING_STATE packet") | 
|---|
 | 167 |  | 
|---|
 | 168 |         elif sid == [0,0,0,0] and ciaddr == [0,0,0,0] and ip : | 
|---|
 | 169 |             Log.Output(Log.info, "Get DHCPREQUEST_INITREBOOT_STATE packet") | 
|---|
 | 170 |  | 
|---|
 | 171 |         elif sid == [0,0,0,0] and ciaddr != [0,0,0,0] and not ip : | 
|---|
 | 172 |             Log.Output(Log.info,"Get DHCPREQUEST_INITREBOOT_STATE packet") | 
|---|
 | 173 |  | 
|---|
 | 174 |         else : Log.Output(Log.info,"Get DHCPREQUEST_UNKNOWN_STATE packet : not implemented") | 
|---|
 | 175 |  | 
|---|
 | 176 |         if self.backend.Request(packet) : packet.TransformToDhcpAckPacket() | 
|---|
 | 177 |         else : packet.TransformToDhcpNackPacket() | 
|---|
 | 178 |  | 
|---|
 | 179 |         self.SendPacket(packet) | 
|---|
 | 180 |  | 
|---|
 | 181 |  | 
|---|
 | 182 |  | 
|---|
 | 183 |     # FIXME: These are not yet implemented. | 
|---|
 | 184 |     def HandleDhcpDecline(self, packet): | 
|---|
 | 185 |         Log.Output(Log.info, "Get DHCPDECLINE packet") | 
|---|
 | 186 |         self.backend.Decline(packet) | 
|---|
 | 187 |          | 
|---|
 | 188 |     def HandleDhcpRelease(self, packet): | 
|---|
 | 189 |         Log.Output(Log.info,"Get DHCPRELEASE packet") | 
|---|
 | 190 |         self.backend.Release(packet) | 
|---|
 | 191 |          | 
|---|
 | 192 |     def HandleDhcpInform(self, packet): | 
|---|
 | 193 |         Log.Output(Log.info, "Get DHCPINFORM packet") | 
|---|
 | 194 |  | 
|---|
 | 195 |         if self.backend.Request(packet) : | 
|---|
 | 196 |             packet.TransformToDhcpAckPacket() | 
|---|
 | 197 |             # FIXME : Remove lease_time from options | 
|---|
 | 198 |             self.SendPacket(packet) | 
|---|
 | 199 |  | 
|---|
 | 200 |         # FIXME : what if false ? | 
|---|
 | 201 |  | 
|---|
 | 202 | if '__main__' == __name__: | 
|---|
 | 203 |     options = { "server_listen_port":67, | 
|---|
 | 204 |                 "client_listen_port":68, | 
|---|
 | 205 |                 "listen_address":"0.0.0.0"} | 
|---|
 | 206 |     backend = DhcpBackend('postgres://sipb-xen@sipb-xen-dev/sipb_xen') | 
|---|
 | 207 |     server = DhcpServer(backend, options) | 
|---|
 | 208 |  | 
|---|
 | 209 |     while True : server.GetNextDhcpPacket() | 
|---|