1module Test_dhcpd = 2 3let lns = Dhcpd.lns 4 5let conf = "# 6# Sample configuration file for ISC dhcpd for Debian 7# 8# Attention: If /etc/ltsp/dhcpd.conf exists, that will be used as 9# configuration file instead of this file. 10# 11# $Id: dhcpd.conf,v 1.1.1.1 2002/05/21 00:07:44 peloy Exp $ 12# 13 14# The ddns-updates-style parameter controls whether or not the server will 15# attempt to do a DNS update when a lease is confirmed. We default to the 16# behavior of the version 2 packages ('none', since DHCP v2 didn't 17# have support for DDNS.) 18ddns-update-style none; 19 20# option definitions common to all supported networks... 21option domain-name \"example.org\"; 22option domain-name-servers ns1.example.org, ns2.example.org; 23 24default-lease-time 600; 25max-lease-time 7200; 26 27# If this DHCP server is the official DHCP server for the local 28# network, the authoritative directive should be uncommented. 29authoritative; 30 31allow booting; 32allow bootp; 33 34# Use this to send dhcp log messages to a different log file (you also 35# have to hack syslog.conf to complete the redirection). 36log-facility local7; 37 38# No service will be given on this subnet, but declaring it helps the 39# DHCP server to understand the network topology. 40 41subnet 10.152.187.0 netmask 255.255.255.0 { 42} 43 44# This is a very basic subnet declaration. 45 46subnet 10.254.239.0 netmask 255.255.255.224 { 47 range 10.254.239.10 10.254.239.20; 48 option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; 49} 50 51# This declaration allows BOOTP clients to get dynamic addresses, 52# which we don't really recommend. 53 54subnet 10.254.239.32 netmask 255.255.255.224 { 55 range dynamic-bootp 10.254.239.40 10.254.239.60; 56 option broadcast-address 10.254.239.31; 57 option routers rtr-239-32-1.example.org; 58} 59 60# A slightly different configuration for an internal subnet. 61subnet 10.5.5.0 netmask 255.255.255.224 { 62 range 10.5.5.26 10.5.5.30; 63 option domain-name-servers ns1.internal.example.org; 64 option domain-name \"internal.example.org\"; 65 option routers 10.5.5.1; 66 option broadcast-address 10.5.5.31; 67 default-lease-time 600; 68 max-lease-time 7200; 69} 70 71# Hosts which require special configuration options can be listed in 72# host statements. If no address is specified, the address will be 73# allocated dynamically (if possible), but the host-specific information 74# will still come from the host declaration. 75 76host passacaglia { 77 hardware ethernet 0:0:c0:5d:bd:95; 78 filename \"vmunix.passacaglia\"; 79 server-name \"toccata.fugue.com\"; 80} 81 82# Fixed IP addresses can also be specified for hosts. These addresses 83# should not also be listed as being available for dynamic assignment. 84# Hosts for which fixed IP addresses have been specified can boot using 85# BOOTP or DHCP. Hosts for which no fixed address is specified can only 86# be booted with DHCP, unless there is an address range on the subnet 87# to which a BOOTP client is connected which has the dynamic-bootp flag 88# set. 89host fantasia { 90 hardware ethernet 08:00:07:26:c0:a5; 91 fixed-address fantasia.fugue.com; 92} 93 94# You can declare a class of clients and then do address allocation 95# based on that. The example below shows a case where all clients 96# in a certain class get addresses on the 10.17.224/24 subnet, and all 97# other clients get addresses on the 10.0.29/24 subnet. 98 99#class \"foo\" { 100# match if substring (option vendor-class-identifier, 0, 4) = \"SUNW\"; 101#} 102 103shared-network 224-29 { 104 subnet 10.17.224.0 netmask 255.255.255.0 { 105 option routers rtr-224.example.org; 106 } 107 subnet 10.0.29.0 netmask 255.255.255.0 { 108 option routers rtr-29.example.org; 109 } 110 pool { 111 allow members of \"foo\"; 112 range 10.17.224.10 10.17.224.250; 113 } 114 pool { 115 deny members of \"foo\"; 116 range 10.0.29.10 10.0.29.230; 117 } 118} 119" 120 121test lns get "authoritative;" = { "authoritative" } 122test lns get "ddns-update-style none;" = { "ddns-update-style" = "none" } 123test lns get "option domain-name \"example.org\";" = 124 { "option" 125 { "domain-name" 126 { "arg" = "example.org" } 127 } 128 } 129 130test lns get "option domain-name-servers ns1.example.org, ns2.example.org;" = 131 { "option" 132 { "domain-name-servers" 133 { "arg" = "ns1.example.org" } 134 { "arg" = "ns2.example.org" } 135 } 136 } 137 138test lns get "default-lease-time 600;" = { "default-lease-time" = "600" } 139test lns get "range 10.254.239.60;" = 140{ "range" 141 { "to" = "10.254.239.60" } 142 } 143 144test lns get "range dynamic-bootp 10.254.239.60;" = 145 { "range" 146 { "flag" = "dynamic-bootp" } 147 { "to" = "10.254.239.60" } 148 } 149 150test lns get "range dynamic-bootp 10.254.239.40 10.254.239.60;" = 151 { "range" 152 { "flag" = "dynamic-bootp" } 153 { "from" = "10.254.239.40" } 154 { "to" = "10.254.239.60" } 155 } 156 157test lns get "subnet 10.152.187.0 netmask 255.255.255.0 {}\n" = 158 { "subnet" 159 { "network" = "10.152.187.0" } 160 { "netmask" = "255.255.255.0" } 161 } 162 163test lns get " pool { 164 pool { 165 166 } 167} 168" = 169 { "pool" 170 { "pool" } 171 } 172 173test lns get "group { host some-host {hardware ethernet 00:00:aa:bb:cc:dd; 174fixed-address 10.1.1.1;}}" = 175 { "group" 176 { "host" = "some-host" 177 { "hardware" 178 { "type" = "ethernet" } 179 { "address" = "00:00:aa:bb:cc:dd" } 180 } 181 { "fixed-address" = "10.1.1.1" } 182 } 183 } 184 185test lns get "group fan-tas_tic { }" = 186 { "group" = "fan-tas_tic" } 187 188test Dhcpd.stmt_secu get "allow members of \"foo\";" = { "allow-members-of" = "foo" } 189test Dhcpd.stmt_secu get "allow booting;" = { "allow" = "booting" } 190test Dhcpd.stmt_secu get "allow bootp;" = { "allow" = "bootp" } 191test Dhcpd.stmt_option get "option voip-boot-server code 66 = string;" = 192 { "rfc-code" 193 { "label" = "voip-boot-server" } 194 { "code" = "66" } 195 { "type" = "string" } 196 } 197 198test Dhcpd.stmt_option get "option special-option code 25 = array of string;" = 199 { "rfc-code" 200 { "label" = "special-option" } 201 { "code" = "25" } 202 { "type" = "array of string" } 203 } 204 205test Dhcpd.stmt_option get "option special-option code 25 = integer 32;" = 206 { "rfc-code" 207 { "label" = "special-option" } 208 { "code" = "25" } 209 { "type" = "integer 32" } 210 } 211 212 213test Dhcpd.stmt_option get "option special-option code 25 = array of integer 32;" = 214 { "rfc-code" 215 { "label" = "special-option" } 216 { "code" = "25" } 217 { "type" = "array of integer 32" } 218 } 219 220 221 222test Dhcpd.lns get "authoritative; 223log-facility local7; 224ddns-update-style none; 225default-lease-time 21600; 226max-lease-time 43200; 227 228# Additional options for VOIP 229option voip-boot-server code 66 = string; 230option voip-vlan-id code 128 = string; 231" = 232 { "authoritative" } 233 { "log-facility" = "local7" } 234 { "ddns-update-style" = "none" } 235 { "default-lease-time" = "21600" } 236 { "max-lease-time" = "43200" 237 { "#comment" = "Additional options for VOIP" } 238 } 239 { "rfc-code" 240 { "label" = "voip-boot-server" } 241 { "code" = "66" } 242 { "type" = "string" } 243 } 244 { "rfc-code" 245 { "label" = "voip-vlan-id" } 246 { "code" = "128" } 247 { "type" = "string" } 248 } 249 250 251test Dhcpd.lns get " 252option domain-name-servers 10.1.1.1, 10.11.2.1, 10.1.3.1; 253next-server 10.1.1.1; 254 255failover peer \"redondance01\" { 256 primary; 257 address 10.1.1.1; 258 port 647; 259 peer address 10.1.1.1; 260 peer port 647; 261 max-response-delay 20; 262 max-unacked-updates 10; 263 mclt 3600; #comment. 264 split 128; #comment. 265 load balance max seconds 3; 266 } 267" = 268 { } 269 { "option" 270 { "domain-name-servers" 271 { "arg" = "10.1.1.1" } 272 { "arg" = "10.11.2.1" } 273 { "arg" = "10.1.3.1" } 274 } 275 } 276 { "next-server" = "10.1.1.1" } 277 { "failover peer" = "redondance01" 278 { "primary" } 279 { "address" = "10.1.1.1" } 280 { "port" = "647" } 281 { "peer address" = "10.1.1.1" } 282 { "peer port" = "647" } 283 { "max-response-delay" = "20" } 284 { "max-unacked-updates" = "10" } 285 { "mclt" = "3600" 286 { "#comment" = "comment." } 287 } 288 { "split" = "128" 289 { "#comment" = "comment." } 290 } 291 { "load balance max seconds" = "3" } 292 } 293 294 295(* test get and put for record types *) 296let record_test = "option test_records code 123 = { string, ip-address, integer 32, ip6-address, domain-list };" 297 298test Dhcpd.lns get record_test = 299 { "rfc-code" 300 { "label" = "test_records" } 301 { "code" = "123" } 302 { "record" 303 { "1" = "string" } 304 { "2" = "ip-address" } 305 { "3" = "integer 32" } 306 { "4" = "ip6-address" } 307 { "5" = "domain-list" } 308 } 309 } 310 311test Dhcpd.lns put record_test after set "/rfc-code[1]/code" "124" = 312 "option test_records code 124 = { string, ip-address, integer 32, ip6-address, domain-list };" 313 314test Dhcpd.lns get " 315option CallManager code 150 = ip-address; 316option slp-directory-agent true 10.1.1.1, 10.2.2.2; 317option slp-service-scope true \"SLP-GLOBAL\"; 318option nds-context \"EXAMPLE\"; 319option nds-tree-name \"EXAMPLE\"; 320" = 321 { } 322 { "rfc-code" 323 { "label" = "CallManager" } 324 { "code" = "150" } 325 { "type" = "ip-address" } 326 } 327 { "option" 328 { "slp-directory-agent" = "true" 329 { "arg" = "10.1.1.1" } 330 { "arg" = "10.2.2.2" } 331 } 332 } 333 { "option" 334 { "slp-service-scope" = "true" 335 { "arg" = "SLP-GLOBAL" } 336 } 337 } 338 { "option" 339 { "nds-context" 340 { "arg" = "EXAMPLE" } 341 } 342 } 343 { "option" 344 { "nds-tree-name" 345 { "arg" = "EXAMPLE" } 346 } 347 } 348 349 350test Dhcpd.lns get "option voip-vlan-id \"VLAN=1234;\";" = 351 { "option" 352 { "voip-vlan-id" 353 { "arg" = "VLAN=1234;" } 354 } 355 } 356 357test Dhcpd.lns get "option domain-name \"x.example.com y.example.com z.example.com\";" = 358 { "option" 359 { "domain-name" 360 { "arg" = "x.example.com y.example.com z.example.com" } 361 } 362 } 363 364test Dhcpd.lns get "include \"/etc/dhcpd.master\";" = 365 { "include" = "/etc/dhcpd.master" } 366 367test Dhcpd.lns put "\n" after set "/include" "/etc/dhcpd.master" = 368 "\ninclude \"/etc/dhcpd.master\";\n" 369 370test Dhcpd.fct_args get "(option dhcp-client-identifier, 1, 3)" = 371 { "args" 372 { "arg" = "option dhcp-client-identifier" } 373 { "arg" = "1" } 374 { "arg" = "3" } 375 } 376 377test Dhcpd.stmt_match get "match if substring (option dhcp-client-identifier, 1, 3) = \"RAS\";" = 378 { "match" 379 { "function" = "substring" 380 { "args" 381 { "arg" = "option dhcp-client-identifier" } 382 { "arg" = "1" } 383 { "arg" = "3" } 384 } 385 } 386 { "value" = "RAS" } 387 } 388 389test Dhcpd.stmt_match get "match if suffix (option dhcp-client-identifier, 4) = \"RAS\";" = 390 { "match" 391 { "function" = "suffix" 392 { "args" 393 { "arg" = "option dhcp-client-identifier" } 394 { "arg" = "4" } 395 } 396 } 397 { "value" = "RAS" } 398 } 399 400test Dhcpd.stmt_match get "match if option vendor-class-identifier=\"RAS\";" = 401 { "match" 402 { "option" = "vendor-class-identifier" 403 { "value" = "RAS" } 404 } 405 } 406 407 408test Dhcpd.lns get "match pick-first-value (option dhcp-client-identifier, hardware);" = 409 { "match" 410 { "function" = "pick-first-value" 411 { "args" 412 { "arg" = "option dhcp-client-identifier" } 413 { "arg" = "hardware" } 414 } 415 } 416 } 417 418test Dhcpd.fct_args get "(16, 32, \"\", substring(hardware, 0, 4))" = 419 { "args" 420 { "arg" = "16" } 421 { "arg" = "32" } 422 { "arg" = "\"\"" } 423 { "arg" = "substring(hardware, 0, 4)" } 424 } 425 426test Dhcpd.stmt_match get "match if binary-to-ascii(16, 32, \"\", substring(hardware, 0, 4)) = \"1525400\";" = 427 { "match" 428 { "function" = "binary-to-ascii" 429 { "args" 430 { "arg" = "16" } 431 { "arg" = "32" } 432 { "arg" = "\"\"" } 433 { "arg" = "substring(hardware, 0, 4)" } 434 } 435 } 436 { "value" = "1525400" } 437 } 438 439test Dhcpd.lns get "subclass allocation-class-1 1:8:0:2b:4c:39:ad;" = 440 { "subclass" 441 { "name" = "allocation-class-1" } 442 { "value" = "1:8:0:2b:4c:39:ad" } 443 } 444 445 446test Dhcpd.lns get "subclass \"allocation-class-1\" 1:8:0:2b:4c:39:ad;" = 447 { "subclass" 448 { "name" = "allocation-class-1" } 449 { "value" = "1:8:0:2b:4c:39:ad" } 450 } 451 452test Dhcpd.lns get "subclass \"quoted class\" \"quoted value\";" = 453 { "subclass" 454 { "name" = "quoted class" } 455 { "value" = "quoted value" } 456 } 457 458 459(* overall test *) 460test Dhcpd.lns put conf after rm "/x" = conf 461 462(* bug #293: primary should support argument *) 463let input293 = "zone EXAMPLE.ORG. { 464 primary 127.0.0.1; 465}" 466 467test Dhcpd.lns get input293 = 468 { "zone" = "EXAMPLE.ORG." 469 { "primary" = "127.0.0.1" } 470 } 471 472(* bug #311: filename should be quoted *) 473let input311 = "subnet 172.16.0.0 netmask 255.255.255.0 { 474filename \"pxelinux.0\"; 475}" 476 477test Dhcpd.lns put "subnet 172.16.0.0 netmask 255.255.255.0 { 478}" after 479 set "subnet/filename" "pxelinux.0" = input311 480 481(* GH issue #34: support conditional structures *) 482let gh34_empty = "if exists dhcp-parameter-request-list { 483}\n" 484 485test Dhcpd.lns get gh34_empty = 486 { "@if" = "exists dhcp-parameter-request-list" } 487 488let gh34_empty_multi = "subnet 192.168.100.0 netmask 255.255.255.0 { 489 if true { 490 } elsif false { 491 } else { 492 } 493}\n" 494 495test Dhcpd.lns get gh34_empty_multi = 496 { "subnet" 497 { "network" = "192.168.100.0" } 498 { "netmask" = "255.255.255.0" } 499 { "@if" = "true" 500 { "@elsif" = "false" } 501 { "@else" } } 502 } 503 504let gh34_simple = "if exists dhcp-parameter-request-list { 505 default-lease-time 600; 506 } else { 507default-lease-time 200; 508}\n" 509 510test Dhcpd.lns get gh34_simple = 511 { "@if" = "exists dhcp-parameter-request-list" 512 { "default-lease-time" = "600" } 513 { "@else" 514 { "default-lease-time" = "200" } } } 515 516test Dhcpd.lns get "omapi-key fookey;" = 517 { "omapi-key" = "fookey" } 518 519(* almost all DHCP groups should support braces starting on the next line *) 520test Dhcpd.lns get "class introduction 521{ 522}" = 523 { "class" = "introduction" } 524 525(* equals should work the same *) 526test Dhcpd.lns get "option test_records code 123 = 527 string;" = 528 { "rfc-code" 529 { "label" = "test_records" } 530 { "code" = "123" } 531 { "type" = "string" } 532 } 533 534test Dhcpd.lns get "deny members of \"Are things like () allowed?\";" = 535 { "deny-members-of" = "Are things like () allowed?" } 536 537test Dhcpd.lns get "deny unknown clients;" = 538 { "deny" = "unknown clients" } 539test Dhcpd.lns get "deny known-clients;" = 540 { "deny" = "known-clients" } 541 542test Dhcpd.lns get "set ClientMac = binary-to-ascii(16, 8, \":\" , substring(hardware, 1, 6));" = 543 { "set" = "ClientMac" 544 { "value" = "binary-to-ascii(16, 8, \":\" , substring(hardware, 1, 6))" } 545 } 546 547test Dhcpd.lns get "set myvariable = foo;" = 548 { "set" = "myvariable" 549 { "value" = "foo" } 550 } 551 552test Dhcpd.stmt_hardware get "hardware fddi 00:01:02:03:04:05;" = 553 { "hardware" 554 { "type" = "fddi" } 555 { "address" = "00:01:02:03:04:05" } 556 } 557 558test Dhcpd.lns get "on commit 559{ 560 set test = thing; 561}" = 562 { "on" = "commit" 563 { "set" = "test" 564 { "value" = "thing" } 565 } 566 } 567 568(* key block get/put/set test *) 569let key_tests = "key sample { 570 algorithm hmac-md5; 571 secret \"secret==\"; 572} 573 574key \"interesting\" { }; 575 576key \"third key\" { 577 secret \"two==\"; 578}" 579 580test Dhcpd.lns get key_tests = 581 { "key_block" = "sample" 582 { "algorithm" = "hmac-md5" } 583 { "secret" = "secret==" } 584 } 585 { "key_block" = "interesting" } 586 { "key_block" = "third key" 587 { "secret" = "two==" } 588 } 589 590test Dhcpd.lns put key_tests after set "/key_block[1]" "sample2" = 591 "key sample2 { 592 algorithm hmac-md5; 593 secret \"secret==\"; 594} 595 596key \"interesting\" { }; 597 598key \"third key\" { 599 secret \"two==\"; 600}" 601 602test Dhcpd.lns get "group \"hello\" { }" = 603 { "group" = "hello" } 604 605test Dhcpd.lns get "class \"testing class with spaces and quotes and ()\" {}" = 606 { "class" = "testing class with spaces and quotes and ()" } 607