blob: 1d4150cba3a7acea53d0f7d3ffcc3c8be68fa2fd [file] [log] [blame]
Vince Lehmanb8b18062015-07-14 13:07:22 -05001# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2#
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -05003# Copyright (C) 2015-2017, The University of Memphis,
Vince Lehman5d5a5662015-12-02 12:33:12 -06004# Arizona Board of Regents,
5# Regents of the University of California.
Vince Lehmanb8b18062015-07-14 13:07:22 -05006#
7# This file is part of Mini-NDN.
8# See AUTHORS.md for a complete list of Mini-NDN authors and contributors.
9#
10# Mini-NDN is free software: you can redistribute it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation, either version 3 of the License, or
13# (at your option) any later version.
14#
15# Mini-NDN is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with Mini-NDN, e.g., in COPYING.md file.
22# If not, see <http://www.gnu.org/licenses/>.
23
Vince Lehman5d5a5662015-12-02 12:33:12 -060024from mininet.clean import sh
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -050025from mininet.examples.cluster import RemoteMixin
Vince Lehman5d5a5662015-12-02 12:33:12 -060026
Ashlesh Gawande792c6aa2015-07-10 12:18:36 -050027from ndn.ndn_application import NdnApplication
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -050028from ndn.util import ssh, scp
ashuef3490b2015-02-17 11:01:04 -060029
Vince Lehman5d5a5662015-12-02 12:33:12 -060030import shutil
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -050031import os
Vince Lehman5d5a5662015-12-02 12:33:12 -060032import textwrap
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -050033from subprocess import call
Ashlesh Gawande59f86242017-05-05 09:45:18 -050034import time
Vince Lehman5d5a5662015-12-02 12:33:12 -060035
Ashlesh Gawandef6a610b2017-02-21 14:48:08 -060036NETWORK="/ndn/"
37
Ashlesh Gawande792c6aa2015-07-10 12:18:36 -050038class Nlsr(NdnApplication):
Ashlesh Gawande708fcca2017-06-23 14:04:12 -050039 def __init__(self, node, neighbors, faceType):
Ashlesh Gawande792c6aa2015-07-10 12:18:36 -050040 NdnApplication.__init__(self, node)
Ashlesh Gawande708fcca2017-06-23 14:04:12 -050041 self.node = node
42 self.neighbors = neighbors
43 self.faceType = faceType
ashuef3490b2015-02-17 11:01:04 -060044 self.routerName = "/%sC1.Router/cs/%s" % ('%', node.name)
Ashlesh Gawande1b663692015-10-14 16:38:10 -050045 self.confFile = "%s/nlsr.conf" % node.homeFolder
ashuef3490b2015-02-17 11:01:04 -060046
47 # Make directory for log file
Ashlesh Gawande1b663692015-10-14 16:38:10 -050048 self.logDir = "%s/log" % node.homeFolder
Ashlesh Gawande708fcca2017-06-23 14:04:12 -050049 self.node.cmd("mkdir %s" % self.logDir)
50
51 # Create faces in NFD
52 self.createFaces()
ashuef3490b2015-02-17 11:01:04 -060053
ashuef3490b2015-02-17 11:01:04 -060054 def start(self):
Ashlesh Gawande59f86242017-05-05 09:45:18 -050055 NdnApplication.start(self, "nlsr -f {} > /dev/null 2>&1 &".format(self.confFile))
56 time.sleep(1)
ashuef3490b2015-02-17 11:01:04 -060057
Ashlesh Gawande708fcca2017-06-23 14:04:12 -050058 def createFaces(self):
59 for ip in self.neighbors:
60 self.node.cmd("nfdc face create {}://{} permanent".format(self.faceType, ip))
61
Vince Lehman5d5a5662015-12-02 12:33:12 -060062 @staticmethod
63 def createKey(host, name, outputFile):
64 host.cmd("ndnsec-keygen {} > {}".format(name, outputFile))
65
66 @staticmethod
67 def createCertificate(host, name, prefix, keyFile, outputFile, signer=None):
68 if signer is None:
69 host.cmd("ndnsec-certgen -N {} -p {} {} > {}".format(name, prefix, keyFile, outputFile))
70 else:
71 host.cmd("ndnsec-certgen -N {} -p {} -s {} {} > {}".format(name, prefix, signer, keyFile, outputFile))
72
73 @staticmethod
74 def createKeysAndCertificates(net, workDir):
75 securityDir = "{}/security".format(workDir)
76
77 if not os.path.exists(securityDir):
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -050078 os.mkdir(securityDir)
Vince Lehman5d5a5662015-12-02 12:33:12 -060079
80 # Create root certificate
Ashlesh Gawandef6a610b2017-02-21 14:48:08 -060081 rootName = NETWORK
Vince Lehman5d5a5662015-12-02 12:33:12 -060082 sh("ndnsec-keygen {} > {}/root.keys".format(rootName, securityDir))
83 sh("ndnsec-certgen -N {} -p {} {}/root.keys > {}/root.cert".format(rootName, rootName, securityDir, securityDir))
84
85 # Create necessary certificates for each site
86 for host in net.hosts:
87 nodeSecurityFolder = "{}/security".format(host.homeFolder)
88
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -050089 host.cmd("mkdir -p %s" % nodeSecurityFolder)
90
91 # Create temp folders for remote nodes on this machine (localhost) to store site.key file
92 # from RemoteNodes
93 if not os.path.exists(nodeSecurityFolder) and isinstance(host, RemoteMixin) and host.isRemote:
94 os.makedirs(nodeSecurityFolder)
Vince Lehman5d5a5662015-12-02 12:33:12 -060095
96 shutil.copyfile("{}/root.cert".format(securityDir), "{}/root.cert".format(nodeSecurityFolder))
97
98 # Create site certificate
Ashlesh Gawandef6a610b2017-02-21 14:48:08 -060099 siteName = "{}{}-site".format(NETWORK, host.name)
Vince Lehman5d5a5662015-12-02 12:33:12 -0600100 siteKeyFile = "{}/site.keys".format(nodeSecurityFolder)
101 siteCertFile = "{}/site.cert".format(nodeSecurityFolder)
102 Nlsr.createKey(host, siteName, siteKeyFile)
103
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -0500104 # Copy siteKeyFile from remote for ndnsec-certgen
105 if isinstance(host, RemoteMixin) and host.isRemote:
106 login = "mininet@{}".format(host.server)
107 src = "{}:{}".format(login, siteKeyFile)
108 dst = siteKeyFile
109 scp(src, dst)
110
Vince Lehman5d5a5662015-12-02 12:33:12 -0600111 # Root key is in root namespace, must sign site key and then install on host
112 sh("ndnsec-certgen -N {} -s {} -p {} {} > {}".format(siteName, rootName, siteName, siteKeyFile, siteCertFile))
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -0500113
114 # Copy root.cert and site.cert from localhost to remote host
115 if isinstance(host, RemoteMixin) and host.isRemote:
116 login = "mininet@{}".format(host.server)
117 src = "{}/site.cert".format(nodeSecurityFolder)
118 src2 = "{}/root.cert".format(nodeSecurityFolder)
119 dst = "{}:/tmp/".format(login)
120 scp(src, src2, dst)
121 host.cmd("mv /tmp/*.cert {}".format(nodeSecurityFolder))
122
Vince Lehman5d5a5662015-12-02 12:33:12 -0600123 host.cmd("ndnsec-cert-install -f {}".format(siteCertFile))
124
Ashlesh Gawande3bed4832017-02-08 18:17:31 -0600125 # Create and install operator certificate
Vince Lehman5d5a5662015-12-02 12:33:12 -0600126 opName = "{}/%C1.Operator/op".format(siteName)
127 opKeyFile = "{}/op.keys".format(nodeSecurityFolder)
128 opCertFile = "{}/op.cert".format(nodeSecurityFolder)
129 Nlsr.createKey(host, opName, opKeyFile)
130 Nlsr.createCertificate(host, opName, opName, opKeyFile, opCertFile, signer=siteName)
Ashlesh Gawande3bed4832017-02-08 18:17:31 -0600131 host.cmd("ndnsec-cert-install -f {}".format(opCertFile))
Vince Lehman5d5a5662015-12-02 12:33:12 -0600132
Ashlesh Gawande3bed4832017-02-08 18:17:31 -0600133 # Create and install router certificate
Vince Lehman5d5a5662015-12-02 12:33:12 -0600134 routerName = "{}/%C1.Router/cs/{}".format(siteName, host.name)
135 routerKeyFile = "{}/router.keys".format(nodeSecurityFolder)
136 routerCertFile = "{}/router.cert".format(nodeSecurityFolder)
137 Nlsr.createKey(host, routerName, routerKeyFile)
138 Nlsr.createCertificate(host, routerName, routerName, routerKeyFile, routerCertFile, signer=opName)
Ashlesh Gawande3bed4832017-02-08 18:17:31 -0600139 host.cmd("ndnsec-cert-install -f {}".format(routerCertFile))
Vince Lehman5d5a5662015-12-02 12:33:12 -0600140
ashuef3490b2015-02-17 11:01:04 -0600141class NlsrConfigGenerator:
142
143 ROUTING_LINK_STATE = "ls"
144 ROUTING_HYPERBOLIC = "hr"
145
Ashlesh Gawande708fcca2017-06-23 14:04:12 -0500146 def __init__(self, node, isSecurityEnabled, faceType):
ashuef3490b2015-02-17 11:01:04 -0600147 self.node = node
Vince Lehman5d5a5662015-12-02 12:33:12 -0600148 self.isSecurityEnabled = isSecurityEnabled
Ashlesh Gawande708fcca2017-06-23 14:04:12 -0500149 self.faceType = faceType
ashuef3490b2015-02-17 11:01:04 -0600150
151 parameters = node.nlsrParameters
152
153 self.nFaces = parameters.get("max-faces-per-prefix", 3)
154 self.hyperbolicState = parameters.get("hyperbolic-state", "off")
155 self.hyperRadius = parameters.get("radius", 0.0)
156 self.hyperAngle = parameters.get("angle", 0.0)
Ashlesh Gawandec3ed2b92015-07-01 12:58:08 -0500157 self.logLevel = parameters.get("nlsr-log-level", "DEBUG")
Ashlesh Gawande708fcca2017-06-23 14:04:12 -0500158 self.neighborIPs = []
ashuef3490b2015-02-17 11:01:04 -0600159
160 def createConfigFile(self):
161
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -0500162 tmp_conf = "/tmp/nlsr.conf"
ashuef3490b2015-02-17 11:01:04 -0600163
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -0500164 configFile = open(tmp_conf, 'w')
165 configFile.write(self.__getConfig())
ashuef3490b2015-02-17 11:01:04 -0600166 configFile.close()
167
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -0500168 # If this node is a remote node scp the nlsr.conf file to its /tmp/nlsr.conf
169 if isinstance(self.node, RemoteMixin) and self.node.isRemote:
170 login = "mininet@%s" % self.node.server
171 src = tmp_conf
172 dst = "%s:%s" % (login, tmp_conf)
173 scp(src, dst)
ashuef3490b2015-02-17 11:01:04 -0600174
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -0500175 # Copy nlsr.conf to home folder
176 self.node.cmd("mv %s nlsr.conf" % tmp_conf)
ashuef3490b2015-02-17 11:01:04 -0600177
178 def __getConfig(self):
179
Ashlesh Gawandef5f304b2016-06-16 16:42:41 -0500180 config = self.__getGeneralSection() + "\n"
181 config += self.__getNeighborsSection() + "\n"
182 config += self.__getHyperbolicSection() + "\n"
183 config += self.__getFibSection() + "\n"
184 config += self.__getAdvertisingSection() + "\n"
ashuef3490b2015-02-17 11:01:04 -0600185 config += self.__getSecuritySection()
186
187 return config
188
189 def __getGeneralSection(self):
190
191 general = "general\n"
192 general += "{\n"
Ashlesh Gawandef6a610b2017-02-21 14:48:08 -0600193 general += " network {}\n".format(NETWORK)
Ashlesh Gawandee144ceb2016-11-14 13:56:24 -0600194 general += " site /{}-site\n".format(self.node.name)
ashuef3490b2015-02-17 11:01:04 -0600195 general += " router /%C1.Router/cs/" + self.node.name + "\n"
Ashlesh Gawandec3ed2b92015-07-01 12:58:08 -0500196 general += " log-level " + self.logLevel + "\n"
Ashlesh Gawande1b663692015-10-14 16:38:10 -0500197 general += " log-dir " + self.node.homeFolder + "/log\n"
198 general += " seq-dir " + self.node.homeFolder + "/log\n"
ashuef3490b2015-02-17 11:01:04 -0600199 general += "}\n"
200
201 return general
202
203 def __getNeighborsSection(self):
204
205 neighbors = "neighbors\n"
206 neighbors += "{\n"
207
208 for intf in self.node.intfList():
209 link = intf.link
210 if link:
211 node1, node2 = link.intf1.node, link.intf2.node
212
213 if node1 == self.node:
214 other = node2
215 ip = other.IP(str(link.intf2))
216 else:
217 other = node1
218 ip = other.IP(str(link.intf1))
219
ashu7b6ba182015-04-17 15:02:37 -0500220 linkCost = intf.params.get("delay", "10ms").replace("ms", "")
ashuef3490b2015-02-17 11:01:04 -0600221
Ashlesh Gawande708fcca2017-06-23 14:04:12 -0500222 # To be used later to create faces
223 self.neighborIPs.append(ip)
224
ashuef3490b2015-02-17 11:01:04 -0600225 neighbors += "neighbor\n"
226 neighbors += "{\n"
Ashlesh Gawandef6a610b2017-02-21 14:48:08 -0600227 neighbors += " name " + NETWORK + other.name + "-site/%C1.Router/cs/" + other.name + "\n"
Ashlesh Gawande708fcca2017-06-23 14:04:12 -0500228 neighbors += " face-uri {}://{}\n".format(self.faceType, ip)
ashuef3490b2015-02-17 11:01:04 -0600229 neighbors += " link-cost " + linkCost + "\n"
230 neighbors += "}\n"
231
232 neighbors += "}\n"
233
234 return neighbors
235
236 def __getHyperbolicSection(self):
237
238 hyper = "hyperbolic\n"
239 hyper += "{\n"
240 hyper += "state %s\n" % self.hyperbolicState
241 hyper += "radius " + str(self.hyperRadius) + "\n"
242 hyper += "angle " + str(self.hyperAngle) + "\n"
243 hyper += "}\n"
244
245 return hyper
246
247 def __getFibSection(self):
248
249 fib = "fib\n"
250 fib += "{\n"
251 fib += " max-faces-per-prefix " + str(self.nFaces) + "\n"
252 fib += "}\n"
253
254 return fib
255
256 def __getAdvertisingSection(self):
257
258 advertising = "advertising\n"
259 advertising += "{\n"
Ashlesh Gawandef6a610b2017-02-21 14:48:08 -0600260 advertising += " prefix "+ NETWORK + self.node.name + "-site/" + self.node.name + "\n"
ashuef3490b2015-02-17 11:01:04 -0600261 advertising += "}\n"
262
263 return advertising
264
265 def __getSecuritySection(self):
Vince Lehman5d5a5662015-12-02 12:33:12 -0600266 if self.isSecurityEnabled is False:
267 security = textwrap.dedent("""\
268 security
269 {
270 validator
271 {
272 trust-anchor
273 {
274 type any
275 }
276 }
277 prefix-update-validator
278 {
279 trust-anchor
280 {
281 type any
282 }
283 }
284 }""")
285 else:
286 security = textwrap.dedent("""\
287 security
288 {
289 validator
290 {
291 rule
292 {
293 id "NSLR Hello Rule"
294 for data
295 filter
296 {
297 type name
298 regex ^[^<NLSR><INFO>]*<NLSR><INFO><><>$
299 }
300 checker
301 {
302 type customized
303 sig-type rsa-sha256
304 key-locator
305 {
306 type name
307 hyper-relation
308 {
309 k-regex ^([^<KEY><NLSR>]*)<NLSR><KEY><ksk-.*><ID-CERT>$
310 k-expand \\\\1
311 h-relation equal
312 p-regex ^([^<NLSR><INFO>]*)<NLSR><INFO><><>$
313 p-expand \\\\1
314 }
315 }
316 }
317 }
ashuef3490b2015-02-17 11:01:04 -0600318
Vince Lehman5d5a5662015-12-02 12:33:12 -0600319 rule
320 {
321 id "NSLR LSA Rule"
322 for data
323 filter
324 {
325 type name
326 regex ^[^<NLSR><LSA>]*<NLSR><LSA>
327 }
328 checker
329 {
330 type customized
331 sig-type rsa-sha256
332 key-locator
333 {
334 type name
335 hyper-relation
336 {
337 k-regex ^([^<KEY><NLSR>]*)<NLSR><KEY><ksk-.*><ID-CERT>$
338 k-expand \\\\1
339 h-relation equal
Ashlesh Gawande3bed4832017-02-08 18:17:31 -0600340 p-regex ^<localhop>([^<NLSR><LSA>]*)<NLSR><LSA>(<>*)<><><><>$
Vince Lehman5d5a5662015-12-02 12:33:12 -0600341 p-expand \\\\1\\\\2
342 }
343 }
344 }
345 }
346
347 rule
348 {
349 id "NSLR Hierarchy Exception Rule"
350 for data
351 filter
352 {
353 type name
354 regex ^[^<KEY><%C1.Router>]*<%C1.Router>[^<KEY><NLSR>]*<KEY><ksk-.*><ID-CERT><>$
355 }
356 checker
357 {
358 type customized
359 sig-type rsa-sha256
360 key-locator
361 {
362 type name
363 hyper-relation
364 {
365 k-regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><ksk-.*><ID-CERT>$
366 k-expand \\\\1
367 h-relation equal
368 p-regex ^([^<KEY><%C1.Router>]*)<%C1.Router>[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
369 p-expand \\\\1
370 }
371 }
372 }
373 }
374
375 rule
376 {
377 id "NSLR Hierarchical Rule"
378 for data
379 filter
380 {
381 type name
382 regex ^[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
383 }
384 checker
385 {
386 type hierarchical
387 sig-type rsa-sha256
388 }
389 }
390
391 trust-anchor
392 {
393 type file
394 file-name "security/root.cert"
395 }
396 }
397
398 prefix-update-validator
399 {
400 rule
401 {
402 id "NLSR ControlCommand Rule"
403 for interest
404 filter
405 {
406 type name
407 regex ^<localhost><nlsr><prefix-update>[<advertise><withdraw>]<>$
408 }
409 checker
410 {
411 type customized
412 sig-type rsa-sha256
413 key-locator
414 {
415 type name
416 regex ^([^<KEY><%C1.Operator>]*)<%C1.Operator>[^<KEY>]*<KEY><ksk-.*><ID-CERT>$
417 }
418 }
419 }
420
421 rule
422 {
423 id "NLSR Hierarchy Rule"
424 for data
425 filter
426 {
427 type name
428 regex ^[^<KEY>]*<KEY><ksk-.*><ID-CERT><>$
429 }
430 checker
431 {
432 type hierarchical
433 sig-type rsa-sha256
434 }
435 }
436
437 trust-anchor
438 {
439 type file
440 file-name "security/site.cert"
441 }
442 }
443 ; cert-to-publish "security/root.cert" ; optional, a file containing the root certificate
444 ; Only the router that is designated to publish the root cert
445 ; needs to specify this
446
447 cert-to-publish "security/site.cert" ; optional, a file containing the site certificate
448 ; Only the router that is designated to publish the site cert
449 ; needs to specify this
450
451 cert-to-publish "security/op.cert" ; optional, a file containing the operator certificate
452 ; Only the router that is designated to publish the operator
453 ; cert needs to specify this
454
455 cert-to-publish "security/router.cert" ; required, a file containing the router certificate.
456 }""")
ashuef3490b2015-02-17 11:01:04 -0600457
458 return security