blob: eaad0d4f74ca1c87141a733c457448c5c3c2aa85 [file] [log] [blame]
ChetanGaonker42d75812016-06-06 16:32:52 -07001#
Chetan Gaonkercfcce782016-05-10 10:10:42 -07002# Copyright 2016-present Ciena Corporation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
ChetanGaonker42d75812016-06-06 16:32:52 -07007#
Chetan Gaonkercfcce782016-05-10 10:10:42 -07008# http://www.apache.org/licenses/LICENSE-2.0
ChetanGaonker42d75812016-06-06 16:32:52 -07009#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070010# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080016from scapy.all import *
A R Karthick76a497a2017-04-12 10:59:39 -070017from CordTestUtils import log_test
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080018
19conf.verb = 0 # Disable Scapy verbosity
20conf.checkIPaddr = 0 # Don't check response packets for matching destination IPs
21
22class DHCPTest:
23
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +000024 def __init__(self, seed_ip = '192.168.1.1', iface = 'veth0',lease_time=600):
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080025 self.seed_ip = seed_ip
26 self.seed_mac = self.ipToMac(self.seed_ip)
27 self.iface = iface
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +000028 self.lease_time = lease_time
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080029 self.mac_map = {}
30 self.mac_inverse_map = {}
Chetan Gaonkerf72ca402016-05-02 16:29:32 -070031 self.bootpmac = None
32 self.dhcpresp = None
Chetan Gaonkerc11d3222016-05-11 17:39:36 -070033 self.servermac = None
Chetan Gaonker1dabecc2016-05-16 14:56:01 -070034 self.return_option = None
Chetan Gaonkerc11d3222016-05-11 17:39:36 -070035 self.after_T2 = False
Chetan Gaonker1dabecc2016-05-16 14:56:01 -070036 self.send_different_option = None
ChetanGaonker5b984cb2016-07-12 15:50:49 -070037 self.specific_lease = None
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080038
39 def is_mcast(self, ip):
40 mcast_octet = (atol(ip) >> 24) & 0xff
41 return True if mcast_octet >= 224 and mcast_octet <= 239 else False
42
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -080043 def discover(self, mac = None, update_seed = False):
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080044 '''Send a DHCP discover/offer'''
45
46 if mac is None:
47 mac = self.seed_mac
48 if update_seed:
49 self.seed_ip = self.incIP(self.seed_ip)
50 self.seed_mac = self.ipToMac(self.seed_ip)
51 mac = self.seed_mac
Chetan Gaonkerf1483862016-05-06 14:14:31 -070052
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080053 chmac = self.macToChaddr(mac)
A R Karthick76a497a2017-04-12 10:59:39 -070054 #log_test.info('mac and chmac are %s %s'%(mac, chmac))
Chetan Gaonkerf72ca402016-05-02 16:29:32 -070055 self.bootpmac = chmac
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080056 L2 = Ether(dst="ff:ff:ff:ff:ff:ff", src=mac)
57 L3 = IP(src="0.0.0.0", dst="255.255.255.255")
58 L4 = UDP(sport=68, dport=67)
59 L5 = BOOTP(chaddr=chmac)
60 L6 = DHCP(options=[("message-type","discover"),"end"])
Chetan Gaonker49ef0852016-03-23 15:06:18 -070061 resp = srp1(L2/L3/L4/L5/L6, filter="udp and port 68", timeout=10, iface=self.iface)
A R Karthick76a497a2017-04-12 10:59:39 -070062 #log_test.info('dhcp discover packet is %s'%(L2/L3/L4/L5/L6).show())
ChetanGaonker42d75812016-06-06 16:32:52 -070063 self.dhcpresp = resp
A R Karthick76a497a2017-04-12 10:59:39 -070064 #log_test.info('discover response is %s'%resp.show())
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080065 try:
66 srcIP = resp.yiaddr
67 serverIP = resp.siaddr
68 except AttributeError:
A R Karthick76a497a2017-04-12 10:59:39 -070069 log_test.info("Failed to acquire IP via DHCP for %s on interface %s" %(mac, self.iface))
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080070 return (None, None)
71
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -070072 subnet_mask = "0.0.0.0"
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080073 for x in resp.lastlayer().options:
74 if(x == 'end'):
75 break
76 op,val = x
77 if(op == "subnet_mask"):
78 subnet_mask = val
79 elif(op == 'server_id'):
80 server_id = val
Chetan Gaonkerf1483862016-05-06 14:14:31 -070081
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080082 L5 = BOOTP(chaddr=chmac, yiaddr=srcIP)
Chetan Gaonkerf1483862016-05-06 14:14:31 -070083 L6 = DHCP(options=[("message-type","request"), ("server_id",server_id),
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080084 ("subnet_mask",subnet_mask), ("requested_addr",srcIP), "end"])
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +000085 resp2 = srp1(L2/L3/L4/L5/L6, filter="udp and port 68", timeout=10, iface=self.iface)
A R Karthick76a497a2017-04-12 10:59:39 -070086 #log_test.info('request response is %s'%resp2.show())
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080087 self.mac_map[mac] = (srcIP, serverIP)
88 self.mac_inverse_map[srcIP] = (mac, serverIP)
89 return (srcIP, serverIP)
90
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +000091 def only_discover(self, mac = None, desired = False, lease_time = False, lease_value=600, multiple = False):
Chetan Gaonkerf72ca402016-05-02 16:29:32 -070092 '''Send a DHCP discover'''
93
94 if mac is None:
ChetanGaonker42d75812016-06-06 16:32:52 -070095 if multiple:
96 mac = RandMAC()._fix()
97 else:
98 mac = self.seed_mac
99
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700100
101 chmac = self.macToChaddr(mac)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700102 self.bootpmac = chmac
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700103 L2 = Ether(dst="ff:ff:ff:ff:ff:ff", src=mac)
104 L3 = IP(src="0.0.0.0", dst="255.255.255.255")
105 L4 = UDP(sport=68, dport=67)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700106 L5 = BOOTP(chaddr=chmac)
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700107 if desired:
108 L6 = DHCP(options=[("message-type","discover"),("requested_addr",self.seed_ip),"end"])
ChetanGaonker42d75812016-06-06 16:32:52 -0700109
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700110 elif lease_time:
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000111 L6 = DHCP(options=[("message-type","discover"),("lease_time",lease_value),"end"])
ChetanGaonker42d75812016-06-06 16:32:52 -0700112
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700113 else:
114 L6 = DHCP(options=[("message-type","discover"),"end"])
A R Karthick76a497a2017-04-12 10:59:39 -0700115 #log_test.info('only discover packet is %s'%(L2/L3/L4/L5/L6).show())
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700116
117 resp = srp1(L2/L3/L4/L5/L6, filter="udp and port 68", timeout=10, iface=self.iface)
A R Karthick76a497a2017-04-12 10:59:39 -0700118 #log_test.info('discovery packet is %s'%(L2/L3/L4/L5/L6).show())
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700119 if resp == None:
ChetanGaonker42d75812016-06-06 16:32:52 -0700120 return (None, None, mac, None)
A R Karthick76a497a2017-04-12 10:59:39 -0700121 #log_test.info('only discover response is %s'%resp.show())
ChetanGaonker42d75812016-06-06 16:32:52 -0700122
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700123 self.dhcpresp = resp
124 for x in resp.lastlayer().options:
125 if(x == 'end'):
126 break
127 op,val = x
128 if(op == "message-type"):
ChetanGaonker42d75812016-06-06 16:32:52 -0700129
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700130 if(val == 2):
ChetanGaonker42d75812016-06-06 16:32:52 -0700131
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700132 try:
133 srcIP = resp.yiaddr
134 serverIP = resp.siaddr
135 except AttributeError:
A R Karthick76a497a2017-04-12 10:59:39 -0700136 log_test.info("In Attribute error.")
137 log_test.info("Failed to acquire IP via DHCP for %s on interface %s" %(mac, self.iface))
ChetanGaonker42d75812016-06-06 16:32:52 -0700138 return (None, None, None, None)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700139
140 if self.return_option:
Chetan Gaonker717b2942016-05-13 17:42:59 -0700141 for x in resp.lastlayer().options:
142 if(x == 'end'):
143 break
144 op,val = x
ChetanGaonker42d75812016-06-06 16:32:52 -0700145
Chetan Gaonker717b2942016-05-13 17:42:59 -0700146 if op == "lease_time":
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700147 if self.return_option == 'lease':
Chetan Gaonker717b2942016-05-13 17:42:59 -0700148 return (srcIP, serverIP, mac, val)
149
150 elif op == "subnet_mask":
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700151 if self.return_option == 'subnet':
ChetanGaonker42d75812016-06-06 16:32:52 -0700152 return (srcIP, serverIP, mac, val)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700153 elif op == "router":
154 if self.return_option == 'router':
ChetanGaonker42d75812016-06-06 16:32:52 -0700155 return (srcIP, serverIP, mac, val)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700156 elif op == "broadcast_address":
157 if self.return_option == 'broadcast_address':
ChetanGaonker42d75812016-06-06 16:32:52 -0700158 return (srcIP, serverIP, mac, val)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700159 elif op == "name_server":
160 if self.return_option == 'dns':
ChetanGaonker42d75812016-06-06 16:32:52 -0700161 return (srcIP, serverIP, mac, val)
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700162
ChetanGaonker42d75812016-06-06 16:32:52 -0700163
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700164 else:
ChetanGaonker42d75812016-06-06 16:32:52 -0700165 return (srcIP, serverIP, mac, None)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700166 elif(val == 6):
ChetanGaonker42d75812016-06-06 16:32:52 -0700167 return (None, None, mac, None)
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700168
ChetanGaonker42d75812016-06-06 16:32:52 -0700169
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000170 def only_request(self, cip, mac, cl_reboot = False, lease_time = False, lease_value=600, renew_time = False, rebind_time = False, unicast = False):
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700171 '''Send a DHCP offer'''
ChetanGaonker42d75812016-06-06 16:32:52 -0700172
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700173 subnet_mask = "0.0.0.0"
174 for x in self.dhcpresp.lastlayer().options:
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700175 if(x == 'end'):
176 break
177 op,val = x
178 if(op == "subnet_mask"):
179 subnet_mask = val
180 elif(op == 'server_id'):
181 server_id = val
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700182
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700183 if unicast and self.servermac:
184 L2 = Ether(dst=self.servermac, src=mac)
185 L3 = IP(src=cip, dst=server_id)
ChetanGaonker42d75812016-06-06 16:32:52 -0700186 else:
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700187 L2 = Ether(dst="ff:ff:ff:ff:ff:ff", src=mac)
188 if self.after_T2:
189 L3 = IP(src=cip, dst="255.255.255.255")
190 else:
191 L3 = IP(src="0.0.0.0", dst="255.255.255.255")
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700192 L4 = UDP(sport=68, dport=67)
ChetanGaonker42d75812016-06-06 16:32:52 -0700193
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700194 if self.after_T2 == True:
195 L5 = BOOTP(chaddr=self.bootpmac, ciaddr = cip)
196 else:
197
198 L5 = BOOTP(chaddr=self.bootpmac, yiaddr=cip)
ChetanGaonker42d75812016-06-06 16:32:52 -0700199
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700200 if cl_reboot or self.after_T2:
ChetanGaonker42d75812016-06-06 16:32:52 -0700201 L6 = DHCP(options=[("message-type","request"),("subnet_mask",subnet_mask), ("requested_addr",cip), "end"])
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700202 elif self.send_different_option:
203 if self.send_different_option == 'subnet':
204 L6 = DHCP(options=[("message-type","request"),("server_id",server_id),
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000205 ("subnet_mask",'255.255.252.252'), ("requested_addr",cip), "end"])
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700206 elif self.send_different_option == 'router':
207 L6 = DHCP(options=[("message-type","request"),("server_id",server_id),
208 ("subnet_mask",subnet_mask), ("router",'1.1.1.1'), ("requested_addr",cip), "end"])
209 elif self.send_different_option == 'broadcast_address':
210 L6 = DHCP(options=[("message-type","request"),("server_id",server_id),
211 ("subnet_mask",subnet_mask), ("broadcast_address",'1.1.1.1'), ("requested_addr",cip), "end"])
212
213 elif self.send_different_option == 'dns':
214 L6 = DHCP(options=[("message-type","request"),("server_id",server_id),
215 ("subnet_mask",subnet_mask), ("name_server",'1.1.1.1'), ("requested_addr",cip), "end"])
ChetanGaonker42d75812016-06-06 16:32:52 -0700216
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000217 elif lease_time:
ChetanGaonker5860c182016-07-05 16:33:06 -0700218 L6 = DHCP(options=[("message-type","request"), ("server_id",server_id),
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000219 ("subnet_mask",subnet_mask), ("requested_addr",cip),("lease_time",lease_value), "end"])
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700220 else:
ChetanGaonker5860c182016-07-05 16:33:06 -0700221 L6 = DHCP(options=[("message-type","request"), ("server_id",server_id),
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700222 ("subnet_mask",subnet_mask), ("requested_addr",cip), "end"])
223
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700224 resp=srp1(L2/L3/L4/L5/L6, filter="udp and port 68", timeout=10, iface=self.iface)
A R Karthick76a497a2017-04-12 10:59:39 -0700225 #log_test.info('request packet is %s'%(L2/L3/L4/L5/L6).show())
226 #log_test.info('response packet is %s'%resp.show())
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700227 if resp == None:
228 return (None, None)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700229
230
231 self.servermac = resp.getlayer(Ether).src
232
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700233 for x in resp.lastlayer().options:
234 if(x == 'end'):
235 break
236 op,val = x
237 if(op == "message-type"):
ChetanGaonker42d75812016-06-06 16:32:52 -0700238
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700239 if(val == 5):
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700240 try:
241 srcIP = resp.yiaddr
242 serverIP = resp.siaddr
ChetanGaonker5860c182016-07-05 16:33:06 -0700243 self.mac_map[mac] = (srcIP, serverIP)
244 self.mac_inverse_map[srcIP] = (mac, serverIP)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700245 except AttributeError:
A R Karthick76a497a2017-04-12 10:59:39 -0700246 log_test.info("In Attribute error.")
247 log_test.info("Failed to acquire IP via DHCP for %s on interface %s" %(mac, self.iface))
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700248 return (None, None)
ChetanGaonker42d75812016-06-06 16:32:52 -0700249
ChetanGaonker5860c182016-07-05 16:33:06 -0700250 if lease_time or renew_time or rebind_time or self.specific_lease:
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700251 for x in resp.lastlayer().options:
252 if(x == 'end'):
253 break
254 op,val = x
ChetanGaonker42d75812016-06-06 16:32:52 -0700255
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700256 if op == "lease_time":
ChetanGaonker5860c182016-07-05 16:33:06 -0700257
258 if self.specific_lease:
259 return (srcIP, serverIP, val)
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700260 if lease_time == True:
261 self.mac_map[mac] = (srcIP, serverIP)
262 self.mac_inverse_map[srcIP] = (mac, serverIP)
263 return (srcIP, serverIP, val)
264 elif op == "renewal_time":
265 if renew_time == True:
266 self.mac_map[mac] = (srcIP, serverIP)
267 self.mac_inverse_map[srcIP] = (mac, serverIP)
268 return (srcIP, serverIP, val)
269 elif op == "rebinding_time":
270 if rebind_time == True:
271 self.mac_map[mac] = (srcIP, serverIP)
272 self.mac_inverse_map[srcIP] = (mac, serverIP)
273 return (srcIP, serverIP, val)
274 else:
275 self.mac_map[mac] = (srcIP, serverIP)
276 self.mac_inverse_map[srcIP] = (mac, serverIP)
277 return (srcIP, serverIP)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700278 elif(val == 6):
ChetanGaonker42d75812016-06-06 16:32:52 -0700279
A R Karthick76a497a2017-04-12 10:59:39 -0700280 log_test.info("Got DHCP NAK.")
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700281 return (None, None)
ChetanGaonker42d75812016-06-06 16:32:52 -0700282
283
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700284
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -0800285 def discover_next(self):
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800286 '''Send next dhcp discover/request with updated mac'''
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -0800287 return self.discover(update_seed = True)
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800288
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -0800289 def release(self, ip):
290 '''Send a DHCP discover/offer'''
291 if ip is None:
292 return False
293 if not self.mac_inverse_map.has_key(ip):
294 return False
295 mac, server_ip = self.mac_inverse_map[ip]
296 chmac = self.macToChaddr(mac)
297 L2 = Ether(dst="ff:ff:ff:ff:ff:ff", src=mac)
298 L3 = IP(src="0.0.0.0", dst="255.255.255.255")
299 L4 = UDP(sport=68, dport=67)
300 L5 = BOOTP(chaddr=chmac, ciaddr = ip)
301 L6 = DHCP(options=[("message-type","release"), ("server_id", server_ip), "end"])
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000302 sendp(L2/L3/L4/L5/L6, iface = self.iface, count=2)
A R Karthick76a497a2017-04-12 10:59:39 -0700303 #log_test.info('release response is %s'%resp)
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -0800304 del self.mac_map[mac]
305 del self.mac_inverse_map[ip]
306 return True
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800307
308 def macToChaddr(self, mac):
309 rv = []
310 mac = mac.split(":")
311 for x in mac:
312 rv.append(chr(int(x, 16)))
313 return reduce(lambda x,y: x + y, rv)
314
315 def get_ip(self, mac):
316 if self.mac_map.has_key(mac):
317 return self.mac_map[mac]
318 return (None, None)
319
320 def get_mac(self, ip):
321 if self.mac_inverse_map.has_key(ip):
322 return self.mac_inverse_map[ip]
323 return (None, None)
324
325 def ipToMac(self, ip):
326 '''Generate a mac from a ip'''
327
328 mcast = self.is_mcast(ip)
329 mac = "01:00:5e" if mcast == True else "00:00:00"
330 octets = ip.split(".")
331 for x in range(1,4):
332 num = str(hex(int(octets[x])))
333 num = num.split("x")[1]
334 if len(num) < 2:
335 num = "0" + str(num)
336 mac += ":" + num
337 return mac
338
339 def incIP(self, ip, n=1):
340 '''Increment an IP'''
341
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700342 if n < 1:
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800343 return ip
344 o = ip.split(".")
345 for ii in range(3,-1,-1):
346 if int(o[ii]) < 255:
347 o[ii] = str(int(o[ii]) + 1)
348 break
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700349 else:
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800350 o[ii] = str(0)
351
352 n -= 1
353 return self.incIP(".".join(o), n)