blob: 35177b3b960574f07f833c5300ec21e84e4ca628 [file] [log] [blame]
Matteo Scandolo48d3d2d2017-08-08 13:05:27 -07001
2# Copyright 2017-present Open Networking Foundation
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
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# 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
16
ChetanGaonker42d75812016-06-06 16:32:52 -070017#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070018# Copyright 2016-present Ciena Corporation
19#
20# Licensed under the Apache License, Version 2.0 (the "License");
21# you may not use this file except in compliance with the License.
22# You may obtain a copy of the License at
ChetanGaonker42d75812016-06-06 16:32:52 -070023#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070024# http://www.apache.org/licenses/LICENSE-2.0
ChetanGaonker42d75812016-06-06 16:32:52 -070025#
Chetan Gaonkercfcce782016-05-10 10:10:42 -070026# Unless required by applicable law or agreed to in writing, software
27# distributed under the License is distributed on an "AS IS" BASIS,
28# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29# See the License for the specific language governing permissions and
30# limitations under the License.
31#
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080032from scapy.all import *
A R Karthick76a497a2017-04-12 10:59:39 -070033from CordTestUtils import log_test
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080034
35conf.verb = 0 # Disable Scapy verbosity
36conf.checkIPaddr = 0 # Don't check response packets for matching destination IPs
37
38class DHCPTest:
39
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +000040 def __init__(self, seed_ip = '192.168.1.1', iface = 'veth0',lease_time=600):
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080041 self.seed_ip = seed_ip
42 self.seed_mac = self.ipToMac(self.seed_ip)
43 self.iface = iface
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +000044 self.lease_time = lease_time
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080045 self.mac_map = {}
46 self.mac_inverse_map = {}
Chetan Gaonkerf72ca402016-05-02 16:29:32 -070047 self.bootpmac = None
48 self.dhcpresp = None
Chetan Gaonkerc11d3222016-05-11 17:39:36 -070049 self.servermac = None
Chetan Gaonker1dabecc2016-05-16 14:56:01 -070050 self.return_option = None
Chetan Gaonkerc11d3222016-05-11 17:39:36 -070051 self.after_T2 = False
Chetan Gaonker1dabecc2016-05-16 14:56:01 -070052 self.send_different_option = None
ChetanGaonker5b984cb2016-07-12 15:50:49 -070053 self.specific_lease = None
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080054
55 def is_mcast(self, ip):
56 mcast_octet = (atol(ip) >> 24) & 0xff
57 return True if mcast_octet >= 224 and mcast_octet <= 239 else False
58
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -080059 def discover(self, mac = None, update_seed = False):
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080060 '''Send a DHCP discover/offer'''
61
62 if mac is None:
63 mac = self.seed_mac
64 if update_seed:
65 self.seed_ip = self.incIP(self.seed_ip)
66 self.seed_mac = self.ipToMac(self.seed_ip)
67 mac = self.seed_mac
Chetan Gaonkerf1483862016-05-06 14:14:31 -070068
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080069 chmac = self.macToChaddr(mac)
A R Karthick76a497a2017-04-12 10:59:39 -070070 #log_test.info('mac and chmac are %s %s'%(mac, chmac))
Chetan Gaonkerf72ca402016-05-02 16:29:32 -070071 self.bootpmac = chmac
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080072 L2 = Ether(dst="ff:ff:ff:ff:ff:ff", src=mac)
73 L3 = IP(src="0.0.0.0", dst="255.255.255.255")
74 L4 = UDP(sport=68, dport=67)
75 L5 = BOOTP(chaddr=chmac)
76 L6 = DHCP(options=[("message-type","discover"),"end"])
Chetan Gaonker49ef0852016-03-23 15:06:18 -070077 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 -070078 #log_test.info('dhcp discover packet is %s'%(L2/L3/L4/L5/L6).show())
ChetanGaonker42d75812016-06-06 16:32:52 -070079 self.dhcpresp = resp
A R Karthick76a497a2017-04-12 10:59:39 -070080 #log_test.info('discover response is %s'%resp.show())
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080081 try:
82 srcIP = resp.yiaddr
83 serverIP = resp.siaddr
84 except AttributeError:
A R Karthick76a497a2017-04-12 10:59:39 -070085 log_test.info("Failed to acquire IP via DHCP for %s on interface %s" %(mac, self.iface))
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080086 return (None, None)
87
Chetan Gaonkercd86bdd2016-03-17 00:08:12 -070088 subnet_mask = "0.0.0.0"
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080089 for x in resp.lastlayer().options:
90 if(x == 'end'):
91 break
92 op,val = x
93 if(op == "subnet_mask"):
94 subnet_mask = val
95 elif(op == 'server_id'):
96 server_id = val
Chetan Gaonkerf1483862016-05-06 14:14:31 -070097
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -080098 L5 = BOOTP(chaddr=chmac, yiaddr=srcIP)
Chetan Gaonkerf1483862016-05-06 14:14:31 -070099 L6 = DHCP(options=[("message-type","request"), ("server_id",server_id),
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800100 ("subnet_mask",subnet_mask), ("requested_addr",srcIP), "end"])
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000101 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 -0700102 #log_test.info('request response is %s'%resp2.show())
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800103 self.mac_map[mac] = (srcIP, serverIP)
104 self.mac_inverse_map[srcIP] = (mac, serverIP)
105 return (srcIP, serverIP)
106
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000107 def only_discover(self, mac = None, desired = False, lease_time = False, lease_value=600, multiple = False):
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700108 '''Send a DHCP discover'''
109
110 if mac is None:
ChetanGaonker42d75812016-06-06 16:32:52 -0700111 if multiple:
112 mac = RandMAC()._fix()
113 else:
114 mac = self.seed_mac
115
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700116
117 chmac = self.macToChaddr(mac)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700118 self.bootpmac = chmac
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700119 L2 = Ether(dst="ff:ff:ff:ff:ff:ff", src=mac)
120 L3 = IP(src="0.0.0.0", dst="255.255.255.255")
121 L4 = UDP(sport=68, dport=67)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700122 L5 = BOOTP(chaddr=chmac)
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700123 if desired:
124 L6 = DHCP(options=[("message-type","discover"),("requested_addr",self.seed_ip),"end"])
ChetanGaonker42d75812016-06-06 16:32:52 -0700125
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700126 elif lease_time:
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000127 L6 = DHCP(options=[("message-type","discover"),("lease_time",lease_value),"end"])
ChetanGaonker42d75812016-06-06 16:32:52 -0700128
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700129 else:
130 L6 = DHCP(options=[("message-type","discover"),"end"])
A R Karthick76a497a2017-04-12 10:59:39 -0700131 #log_test.info('only discover packet is %s'%(L2/L3/L4/L5/L6).show())
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700132
133 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 -0700134 #log_test.info('discovery packet is %s'%(L2/L3/L4/L5/L6).show())
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700135 if resp == None:
ChetanGaonker42d75812016-06-06 16:32:52 -0700136 return (None, None, mac, None)
A R Karthick76a497a2017-04-12 10:59:39 -0700137 #log_test.info('only discover response is %s'%resp.show())
ChetanGaonker42d75812016-06-06 16:32:52 -0700138
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700139 self.dhcpresp = resp
140 for x in resp.lastlayer().options:
141 if(x == 'end'):
142 break
143 op,val = x
144 if(op == "message-type"):
ChetanGaonker42d75812016-06-06 16:32:52 -0700145
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700146 if(val == 2):
ChetanGaonker42d75812016-06-06 16:32:52 -0700147
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700148 try:
149 srcIP = resp.yiaddr
150 serverIP = resp.siaddr
151 except AttributeError:
A R Karthick76a497a2017-04-12 10:59:39 -0700152 log_test.info("In Attribute error.")
153 log_test.info("Failed to acquire IP via DHCP for %s on interface %s" %(mac, self.iface))
ChetanGaonker42d75812016-06-06 16:32:52 -0700154 return (None, None, None, None)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700155
156 if self.return_option:
Chetan Gaonker717b2942016-05-13 17:42:59 -0700157 for x in resp.lastlayer().options:
158 if(x == 'end'):
159 break
160 op,val = x
ChetanGaonker42d75812016-06-06 16:32:52 -0700161
Chetan Gaonker717b2942016-05-13 17:42:59 -0700162 if op == "lease_time":
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700163 if self.return_option == 'lease':
Chetan Gaonker717b2942016-05-13 17:42:59 -0700164 return (srcIP, serverIP, mac, val)
165
166 elif op == "subnet_mask":
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700167 if self.return_option == 'subnet':
ChetanGaonker42d75812016-06-06 16:32:52 -0700168 return (srcIP, serverIP, mac, val)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700169 elif op == "router":
170 if self.return_option == 'router':
ChetanGaonker42d75812016-06-06 16:32:52 -0700171 return (srcIP, serverIP, mac, val)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700172 elif op == "broadcast_address":
173 if self.return_option == 'broadcast_address':
ChetanGaonker42d75812016-06-06 16:32:52 -0700174 return (srcIP, serverIP, mac, val)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700175 elif op == "name_server":
176 if self.return_option == 'dns':
ChetanGaonker42d75812016-06-06 16:32:52 -0700177 return (srcIP, serverIP, mac, val)
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700178
ChetanGaonker42d75812016-06-06 16:32:52 -0700179
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700180 else:
ChetanGaonker42d75812016-06-06 16:32:52 -0700181 return (srcIP, serverIP, mac, None)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700182 elif(val == 6):
ChetanGaonker42d75812016-06-06 16:32:52 -0700183 return (None, None, mac, None)
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700184
ChetanGaonker42d75812016-06-06 16:32:52 -0700185
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000186 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 -0700187 '''Send a DHCP offer'''
ChetanGaonker42d75812016-06-06 16:32:52 -0700188
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700189 subnet_mask = "0.0.0.0"
190 for x in self.dhcpresp.lastlayer().options:
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700191 if(x == 'end'):
192 break
193 op,val = x
194 if(op == "subnet_mask"):
195 subnet_mask = val
196 elif(op == 'server_id'):
197 server_id = val
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700198
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700199 if unicast and self.servermac:
200 L2 = Ether(dst=self.servermac, src=mac)
201 L3 = IP(src=cip, dst=server_id)
ChetanGaonker42d75812016-06-06 16:32:52 -0700202 else:
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700203 L2 = Ether(dst="ff:ff:ff:ff:ff:ff", src=mac)
204 if self.after_T2:
205 L3 = IP(src=cip, dst="255.255.255.255")
206 else:
207 L3 = IP(src="0.0.0.0", dst="255.255.255.255")
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700208 L4 = UDP(sport=68, dport=67)
ChetanGaonker42d75812016-06-06 16:32:52 -0700209
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700210 if self.after_T2 == True:
211 L5 = BOOTP(chaddr=self.bootpmac, ciaddr = cip)
212 else:
213
214 L5 = BOOTP(chaddr=self.bootpmac, yiaddr=cip)
ChetanGaonker42d75812016-06-06 16:32:52 -0700215
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700216 if cl_reboot or self.after_T2:
ChetanGaonker42d75812016-06-06 16:32:52 -0700217 L6 = DHCP(options=[("message-type","request"),("subnet_mask",subnet_mask), ("requested_addr",cip), "end"])
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700218 elif self.send_different_option:
219 if self.send_different_option == 'subnet':
220 L6 = DHCP(options=[("message-type","request"),("server_id",server_id),
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000221 ("subnet_mask",'255.255.252.252'), ("requested_addr",cip), "end"])
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700222 elif self.send_different_option == 'router':
223 L6 = DHCP(options=[("message-type","request"),("server_id",server_id),
224 ("subnet_mask",subnet_mask), ("router",'1.1.1.1'), ("requested_addr",cip), "end"])
225 elif self.send_different_option == 'broadcast_address':
226 L6 = DHCP(options=[("message-type","request"),("server_id",server_id),
227 ("subnet_mask",subnet_mask), ("broadcast_address",'1.1.1.1'), ("requested_addr",cip), "end"])
228
229 elif self.send_different_option == 'dns':
230 L6 = DHCP(options=[("message-type","request"),("server_id",server_id),
231 ("subnet_mask",subnet_mask), ("name_server",'1.1.1.1'), ("requested_addr",cip), "end"])
ChetanGaonker42d75812016-06-06 16:32:52 -0700232
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000233 elif lease_time:
ChetanGaonker5860c182016-07-05 16:33:06 -0700234 L6 = DHCP(options=[("message-type","request"), ("server_id",server_id),
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000235 ("subnet_mask",subnet_mask), ("requested_addr",cip),("lease_time",lease_value), "end"])
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700236 else:
ChetanGaonker5860c182016-07-05 16:33:06 -0700237 L6 = DHCP(options=[("message-type","request"), ("server_id",server_id),
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700238 ("subnet_mask",subnet_mask), ("requested_addr",cip), "end"])
239
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700240 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 -0700241 #log_test.info('request packet is %s'%(L2/L3/L4/L5/L6).show())
242 #log_test.info('response packet is %s'%resp.show())
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700243 if resp == None:
244 return (None, None)
Chetan Gaonker1dabecc2016-05-16 14:56:01 -0700245
246
247 self.servermac = resp.getlayer(Ether).src
248
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700249 for x in resp.lastlayer().options:
250 if(x == 'end'):
251 break
252 op,val = x
253 if(op == "message-type"):
ChetanGaonker42d75812016-06-06 16:32:52 -0700254
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700255 if(val == 5):
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700256 try:
257 srcIP = resp.yiaddr
258 serverIP = resp.siaddr
ChetanGaonker5860c182016-07-05 16:33:06 -0700259 self.mac_map[mac] = (srcIP, serverIP)
260 self.mac_inverse_map[srcIP] = (mac, serverIP)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700261 except AttributeError:
A R Karthick76a497a2017-04-12 10:59:39 -0700262 log_test.info("In Attribute error.")
263 log_test.info("Failed to acquire IP via DHCP for %s on interface %s" %(mac, self.iface))
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700264 return (None, None)
ChetanGaonker42d75812016-06-06 16:32:52 -0700265
ChetanGaonker5860c182016-07-05 16:33:06 -0700266 if lease_time or renew_time or rebind_time or self.specific_lease:
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700267 for x in resp.lastlayer().options:
268 if(x == 'end'):
269 break
270 op,val = x
ChetanGaonker42d75812016-06-06 16:32:52 -0700271
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700272 if op == "lease_time":
ChetanGaonker5860c182016-07-05 16:33:06 -0700273
274 if self.specific_lease:
275 return (srcIP, serverIP, val)
Chetan Gaonkerc11d3222016-05-11 17:39:36 -0700276 if lease_time == True:
277 self.mac_map[mac] = (srcIP, serverIP)
278 self.mac_inverse_map[srcIP] = (mac, serverIP)
279 return (srcIP, serverIP, val)
280 elif op == "renewal_time":
281 if renew_time == True:
282 self.mac_map[mac] = (srcIP, serverIP)
283 self.mac_inverse_map[srcIP] = (mac, serverIP)
284 return (srcIP, serverIP, val)
285 elif op == "rebinding_time":
286 if rebind_time == True:
287 self.mac_map[mac] = (srcIP, serverIP)
288 self.mac_inverse_map[srcIP] = (mac, serverIP)
289 return (srcIP, serverIP, val)
290 else:
291 self.mac_map[mac] = (srcIP, serverIP)
292 self.mac_inverse_map[srcIP] = (mac, serverIP)
293 return (srcIP, serverIP)
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700294 elif(val == 6):
ChetanGaonker42d75812016-06-06 16:32:52 -0700295
A R Karthick76a497a2017-04-12 10:59:39 -0700296 log_test.info("Got DHCP NAK.")
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700297 return (None, None)
ChetanGaonker42d75812016-06-06 16:32:52 -0700298
299
Chetan Gaonkerf72ca402016-05-02 16:29:32 -0700300
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -0800301 def discover_next(self):
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800302 '''Send next dhcp discover/request with updated mac'''
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -0800303 return self.discover(update_seed = True)
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800304
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -0800305 def release(self, ip):
306 '''Send a DHCP discover/offer'''
307 if ip is None:
308 return False
309 if not self.mac_inverse_map.has_key(ip):
310 return False
311 mac, server_ip = self.mac_inverse_map[ip]
312 chmac = self.macToChaddr(mac)
313 L2 = Ether(dst="ff:ff:ff:ff:ff:ff", src=mac)
314 L3 = IP(src="0.0.0.0", dst="255.255.255.255")
315 L4 = UDP(sport=68, dport=67)
316 L5 = BOOTP(chaddr=chmac, ciaddr = ip)
317 L6 = DHCP(options=[("message-type","release"), ("server_id", server_ip), "end"])
Anil Kumar Sankacfa7c582016-12-09 23:17:22 +0000318 sendp(L2/L3/L4/L5/L6, iface = self.iface, count=2)
A R Karthick76a497a2017-04-12 10:59:39 -0700319 #log_test.info('release response is %s'%resp)
Chetan Gaonker1f7c3f82016-03-08 12:17:37 -0800320 del self.mac_map[mac]
321 del self.mac_inverse_map[ip]
322 return True
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800323
324 def macToChaddr(self, mac):
325 rv = []
326 mac = mac.split(":")
327 for x in mac:
328 rv.append(chr(int(x, 16)))
329 return reduce(lambda x,y: x + y, rv)
330
331 def get_ip(self, mac):
332 if self.mac_map.has_key(mac):
333 return self.mac_map[mac]
334 return (None, None)
335
336 def get_mac(self, ip):
337 if self.mac_inverse_map.has_key(ip):
338 return self.mac_inverse_map[ip]
339 return (None, None)
340
341 def ipToMac(self, ip):
342 '''Generate a mac from a ip'''
343
344 mcast = self.is_mcast(ip)
345 mac = "01:00:5e" if mcast == True else "00:00:00"
346 octets = ip.split(".")
347 for x in range(1,4):
348 num = str(hex(int(octets[x])))
349 num = num.split("x")[1]
350 if len(num) < 2:
351 num = "0" + str(num)
352 mac += ":" + num
353 return mac
354
355 def incIP(self, ip, n=1):
356 '''Increment an IP'''
357
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700358 if n < 1:
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800359 return ip
360 o = ip.split(".")
361 for ii in range(3,-1,-1):
362 if int(o[ii]) < 255:
363 o[ii] = str(int(o[ii]) + 1)
364 break
Chetan Gaonkerf1483862016-05-06 14:14:31 -0700365 else:
Chetan Gaonkerb2bd8242016-03-03 15:39:24 -0800366 o[ii] = str(0)
367
368 n -= 1
369 return self.incIP(".".join(o), n)