Tiny Deathstars of Foulness

DHCP, or Dynamic Host Control Protocol, is the service used to hand out IP addresses and other network settings by network appliances and servers. The DHCP Server built into macOS Server 5.4 on High Sierra is similar to the DHCP service that was included in Server 10.2 and 10.2 and from the good ‘ole Panther days. It’s pretty simple to use and transparent, just as DHCP services should be.

To install the service, open the Server app and then click on the Show button beside Advanced in the server sidebar. Then click on DHCP.
At the DHCP screen, you’ll see two tabs: Settings, used for managing the service and Clients, used to see leases in use by computers that obtain IP address information from the server. You’ll also see an ON and OFF switch, but we’re going to configure our scopes, or Networks as they appear in the Server app, before we enable the service. To configure a scope, double-click on the first entry in the Networks list.
Each scope, or Network, will have the following options:
  • Name: A name for the scope, used only on the server to keep track of things.
  • Lease Duration: Select an hour, a day, a week or 30 days. This is how long a lease that is provided to a client is valid before the lease expires and the client must find a new lease, either from the server you’re configuring or a different host.
  • Network Interface: The network interface you’d like to share IPs over. Keep in mind that you can tag multiple VLANs on a NIC, assign each an interface in OS X and therefore provide different scopes for different VLANs with the same physical computer and NIC.
  • Starting IP Address: The first IP address used. For example, if you configure a scope to go from to you would have 50 useable IP addresses.
  • Ending IP Address: The last IP address used in a scope.
  • Subnet Mask: The subnet mask used for the client configuration. This setting determines the size of the network.
  • Router: The default gateway, or router for the network. Often a .1 address for the subnet used in the Starting and Ending IP address fields. Note that while in DHCP you don’t actually have to use a gateway, OS X Server does force you to do so or you cannot save changes to each scope.
  • DNS: Use the Edit button for DNS to bring up a screen that allows you to configure the DNS settings provided as part of each DHCP scope you create, taking note that by default you will be handing out a server of if you don’t configure this setting.
The DNS settings in the DHCP scope are really just the IP addresses to use for the DNS servers and the search domain. The search domain is the domain name appended to all otherwise incomplete Fully Qualified Domain Names. For example, if we use internal.krypted.lan and we have a DNS record for wiki.internal.krypted.lan then we could just type wiki into Safari to bring up the wiki server. Click the minus sign button to remove any data in these fields and then click on the plus sign to enter new values.
Click OK to save DNS settings and then OK to save each scope. Once you’ve build all required scopes, start the service. Once started, verify that a new client on the network gets an IP. Also, make sure that there are no overlapping scopes and that if you are moving a scope from one device to another (e.g. the server you’re setting up right now) that you renew all leases on client systems, most easily done using a quick reboot, or using “ipconfig /release” on a Windows computer. If you have problems with leases not renewing in macOS, check out this article I did awhile back. So far, totally easy. Each time you make a change, the change updates a few different things.

First, it updates the /etc/bootpd.plist property list, which looks something like this (note the correlation between these keys and the settings in the above screen shots.:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ""> <plist version="1.0"> <dict> <key>NetBoot</key> <dict/> <key>Subnets</key> <array> <dict> <key>allocate</key> <true/> <key>dhcp_domain_name</key> <string></string> <key>dhcp_domain_name_server</key> <array> <string></string> </array> <key>dhcp_domain_search</key> <array/> <key>dhcp_router</key> <string></string> <key>lease_max</key> <integer>3600</integer> <key>name</key> <string>192.168.210 Wi-Fi</string> <key>net_address</key> <string></string> <key>net_mask</key> <string></string> <key>net_range</key> <array> <string></string> <string></string> </array> <key>selected_port_name</key> <string>en0</string> <key>uuid</key> <string>B03BAE3C-AB79-4108-9E5E-F0ABAF32179E</string> </dict> </array> <key>allow</key> <array/> <key>bootp_enabled</key> <false/> <key>deny</key> <array/> <key>detect_other_dhcp_server</key> <false/> <key>dhcp_enabled</key> <false/> <key>old_netboot_enabled</key> <false/> <key>relay_enabled</key> <false/> <key>relay_ip_list</key> <array/> </dict> </plist>

Settings from this file include:
  • dhcp_enabled – Used to enable dhcp for each network interface. Replace the <false/> immediately below with <array> <string>en0</string> </array>. For additional entries, duplice the string line and enter each from ifconfig that you’d like to use dhcp on.
  • bootp_enabled – This can be left as Disabled or set to an array of the adapters that should be enabled if you wish to use the bootp protocol in addition to dhcp. Note that the server can do both bootp and dhcp simultaneously.
  • allocate – Use the allocate key for each subnet in the Subnets array to enable each subnet once the service is enabled.
  • Subnets – Use this array to create additional scopes or subnets that you will be serving up DHCP for. To do so, copy the entry in the array and paste it immediately below the existing entry. The entry is a dictionary so copy all of the data between and including the <dict> and </dict> immediately after the <array> entry for the subnet itself.
  • lease_max and lease_min – Set these integers to the time for a client to retain its dhcp lease
  • name – If there are multiple subnet entries, this should be unique and reference a friendly name for the subnet itself.
  • net_address – The first octets of the subnet followed by a 0. For example, assuming a /24 and 172.16.25 as the first three octets the entry would be
  • net_mask – The subnet mask clients should have
  • net_range – The first entry should have the first IP in the range and the last should have the last IP in the range. For example, in the following example the addressing is to
  • dhcp_domain_name_server – There should be a string for each DNS server supplied by dhcp in this array
  • dhcp_domain_search – Each domain in the domain search field should be suppled in a string within this array, if one is needed. If not, feel free to delete the key and the array if this isn’t needed.
  • dhcp_router – This entry should contain the router or default gateway used for clients on the subnet, if there is one. If not, you can delete the key and following string entries.
If you run the serveradmin command, followed by the settings verb and then the dhcp service, you’ll see the other place that gets updated:

serveradmin settings dhcp

The output indicates that

dhcp:static_maps = _empty_array
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:WINS_secondary_server = ""
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:selected_port_name = "en0"
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:dhcp_router = ""
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:dhcp_domain_name_server:_array_index:0 = ""
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:net_mask = ""
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:WINS_NBDD_server = ""
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:net_range_start = ""
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:lease_max = 3600
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:dhcp_domain_search:_array_index:0 = "internal.krypted.lan"
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:descriptive_name = "192.168.210 Wi-Fi"
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:WINS_primary_server = ""
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:net_range_end = ""
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:dhcp_ldap_url = _empty_array
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:WINS_node_type = "NOT_SET"
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:net_address = ""
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:dhcp_enabled = yes
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:dhcp_domain_name = "internal.krypted.lan"
dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:WINS_scope_id = ""
dhcp:subnet_defaults:logVerbosity = "MEDIUM"
dhcp:subnet_defaults:WINS_node_type_list:_array_index:0 = "BROADCAST_B_NODE"
dhcp:subnet_defaults:WINS_node_type_list:_array_index:1 = "HYBRID_H_NODE"
dhcp:subnet_defaults:WINS_node_type_list:_array_index:2 = "NOT_SET"
dhcp:subnet_defaults:WINS_node_type_list:_array_index:3 = "PEER_P_NODE"
dhcp:subnet_defaults:WINS_node_type_list:_array_index:4 = "MIXED_M_NODE"
dhcp:subnet_defaults:dhcp_domain_name = ""
dhcp:subnet_defaults:WINS_node_type = "NOT_SET"
dhcp:subnet_defaults:routers = _empty_dictionary
dhcp:subnet_defaults:logVerbosityList:_array_index:0 = "LOW"
dhcp:subnet_defaults:logVerbosityList:_array_index:1 = "MEDIUM"
dhcp:subnet_defaults:logVerbosityList:_array_index:2 = "HIGH"
dhcp:subnet_defaults:dhcp_domain_name_server:_array_index:0 = ""
dhcp:subnet_defaults:selected_port_key = "en0"
dhcp:subnet_defaults:selected_port_key_list:_array_index:0 = "bridge0"
dhcp:subnet_defaults:selected_port_key_list:_array_index:1 = "en0"
dhcp:subnet_defaults:selected_port_key_list:_array_index:2 = "p2p0"
dhcp:subnet_defaults:selected_port_key_list:_array_index:3 = "en1"
dhcp:logging_level = "MEDIUM"

Notice the correlation between the uuid string in /etc/bootp.plist and the arrayid entry for each subnet/network/scope (too many terms referring to the same thing, ahhhh!). Using the serveradmin command you can configure a lot more than you can configure in the Server app gui. For example, on a dedicated DHCP server, you could increase logging level to HIGH (as root/with sudo of course):

serveradmin settings dhcp:logging_level = "MEDIUM"

You can also change settings within a scope. For example, if you realized that you were already using and 201 for statically assigned IPs elsewhere you can go ahead and ssh into the server and change the first IP in a scope to 202 using the following (assuming the uuid of the domain is the same as in the previous examples):

serveradmin settings dhcp:subnets:_array_id:B03BAE3C-AB79-4108-9E5E-F0ABAF32179E:net_range_start = ""

You can also obtain some really helpful information using the fullstatus verb with serveradmin:

serveradmin fullstatus dhcp

This output includes the number of active leases, path to log file (tailing that file is helpful when troubleshooting issues), static mappings (configured using the command line if needed), etc.

dhcp:state = "RUNNING"
dhcp:backendVersion = "10.11"
dhcp:timeOfModification = "2017-9-04 04:24:17 +0000"
dhcp:numDHCPActiveClients = 0
dhcp:timeOfSnapShot = "2017-9-04 04:24:19 +0000"
dhcp:dhcpLeasesArray = _empty_array
dhcp:logPaths:systemLog = "/var/log/system.log"
dhcp:numConfiguredStaticMaps = 1
dhcp:timeServiceStarted = "2017-9-04 04:24:17 +0000"
dhcp:setStateVersion = 1
dhcp:numDHCPLeases = 21
dhcp:readWriteSettingsVersion = 1

Once started, configure reservations using  the /etc/bootptab file. This file should have a column for the name of a computer, the hardware type (1), the hwaddr (the MAC address) and ipaddr for the desired IP address of each entry:

%% # hostname hwtype hwaddr ipaddr bootfile
a.krypted.lan 1 00:00:00:aa:bb:cc
b.krypted.lan 1 00:00:00:aa:bb:cc

You can start and stop the service either using the serveradmin command:

serveradmin stop dhcp serveradmin start dhcp

Or using the launchctl:

sudo /bin/launchctl unload -w /System/Library/LaunchDaemons/bootps.plist sudo /bin/launchctl load -w /System/Library/LaunchDaemons/bootps.plist

You can also add DHCP Reservations, or static maps. To do so, click on the clients tab and then click on the plus sign (“+”). From here, you can add a hostname and IP address to a given MAC address in order to allow that MAC address to always be assigned the IP you’d like.

Finally, you can define DHCP options in /etc/bootp.plist. This process isn’t necessarily support, there is no GUI control for options, and options are not as widely used with devices as they once were. However, it’s absolutely an option if needed.

September 26th, 2017

Posted In: Mac OS X, Mac OS X Server

Tags: , , , , , ,

You can obtain a pretty decent amount of information about leases your OS X computer gets just by looking in the Network System Preference pane, for each interface. Screen Shot 2013-10-02 at 10.16.16 PM However, you can get a little lot more information, as with most things, from the command line. First, we’re going to take a look at en0 on our host and see what the MAC address is: ifconfig en0 ether Now, we can look in the /var/db/dhcpclient/leases directory to see a list of all of the leases we have running on our system. Based on the MAC address of our computer, we should see a file there that starts with the name of our interface and finishes with our MAC address. Let’s cat this file: cat en0-1\,84\:38\:35\:63\:87\:2e The output is similar to the following (a standard plist): <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ""> <plist version="1.0"> <dict> <key>IPAddress</key> <string></string> <key>LeaseLength</key> <integer>86400</integer> <key>LeaseStartDate</key> <date>2013-10-03T02:43:36Z</date> <key>PacketData</key> <data> AgEGAPSEH9QAAAAAAAAAAMCo0pAAAAAAAAAAAIQ4NWOHLgAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABjglNjNQEFNgTAqNIBAQT///8A MwQAAVGAAwTAqNIBBggEAgICzg0cDP8= </data> <key>RouterHardwareAddress</key> <data> ABfFg9DO </data> <key>RouterIPAddress</key> <string></string> </dict> </plist> This shows us the amount of time our lease is valid for, when the lease what provided to us, what IP was provided and the IP of our router. We can then key off of that information as needed (e.g. for other scripts/tools).

October 7th, 2013

Posted In: Mac OS X, Mac Security, Mass Deployment

Tags: , , , , , , , , , ,

DeployStudio has the ability to import a csv file that is populated with the MAC address and a few specific settings. This allows you to prepopulate the database with the names that you want each machine to have. If you purchase a lot of machines from Apple then you can get a list of MAC addresses, or, you can use a bar code scanner to scan them as you’re unboxing. If you have a list of MAC addresses (en0), then you will need to format them in a very specific manner. Here, I have included a sample csv file with the data that goes into each field, which I have name DSImporter.csv. Once you paste the data that you’d like into the csv, provide the computer names (these can be pasted or compiled using formulas). Once done, save and then open Deploy Studio Admin. From here, click on Computers and then (as you would with iTunes) click on the plus sign (+) and create a new computer list (this step is optional, but I prefer to always import into computer lists, just in case something goes wrong, especially with my first import). Once you have created the computer list, you should see a screen similar to the following. Next, click on the Server menu and select Import. Now browse to your csv file and then click on the Import button. When the import is complete you will see a screen informing you as such. Click on the Done button to complete the process. You will then see your computers listed in the database and should see the names that you assigned them listed as well. You can now set a workflow item in DeployStudio for Reconfigure system with computers database content (shown below). This will set the name (and any other fields you decided to use) from the spreadsheet that you imported into the computer list. Once you have your computers in a group, you can also set a default workflow for them for their first time imaging, by clicking on the name of the group and then clicking on the Automation tab at the bottom as you can see below. Here, you will set the workflow to run and optionally set the computer to not have a default workflow moving forward or just be disabled so users can’t accidentally reimage their computers later. If you don’t have the MAC addresses for your computers ahead of time, you can use the Hostname option instead. This will enable you to enter the computer name that you would like to use moving forward into the DeployStudio Runtime at imaging and then have it stored in the DeployStudio database, where it can be used to build future workflows or even be exported and imported into the Open Directory computers. Overall, the computers and groups in DeployStudio Admin can be used to design more and more complex imaging sequences and to provide much of the scripting logic that a number of organizations need. Beyond that, JAMF, FileWave and a few other solutions offer even more logic and even more features or a little shell scripting can take you a really long way.

August 3rd, 2010

Posted In: Mac OS X, Mass Deployment

Tags: , , , , , , , , ,

DHCP provides IP addresses to clients. DHCP is critical to a number of Mac OS X Server technologies, most notably with NetBoot. In doing so, communications are comprised of 4 steps: Discovery, Offer, Acceptance, and Acknowledgment. In the Discovery step, a computer that needs an IP address sends a broadcast request to the environment. These typically remain local, although most routers will allow for configuring the gateway in such a way that UDP traffic is forwarded on to other subnets. The request also includes all of the options that the client will need, with options being anything beyond an IP address, each potential option with a numerical identifier per this list (defined in various RFPs). In the second step, any DHCP servers that received the request will issue an offer, which includes a number of DHCP options, such as a subnet mask (option 1), a gateway (option 3), DNS servers (option 6), amount of time a lease is valid for (option 51), the IP of the DHCP server making the offer (option 54). For example, WINS is two options, 44 & 46 (server and type respectively) that can be provided to clients as is LDAP (option 95). Available options are determined based on any reservations that may have been filed. For example, if an IP address has been reserved for a specific MAC address then the IP will always be the IP reserved. Because environments can have multiple DHCP servers the Transaction ID will determine which offer to accept. The servers that issued an offer will hold the IP address from the offer until they receive the response that another offer is being accepted and then move those back into their pool of available IP addresses. In step 3, Acceptance, the DHCP client will notify the server whose lease it accepts in the form of a DHCP Request, and those whose lease it will pass on. The Acceptance is actually a request for the IP address that is being held for the MAC address in question. Based on the Acceptance, the options are then applied in an acknowledgement sent back to the client from the server that it indeed has the IP address and all of the pertinent options required. All of this typically happens in under a second and therefore, you plug in your computer and it gets an IP address; unless you’re running wireshark to look at what’s happening beneath the scene you typically just assume that that’s all there is to it… The most powerful part of DHCP though is in the options, which shows that great thought was given to the protocol when it was conceived. These extensions provide for anything from NTP servers to SMTP servers provided that the client and the server support the implementation.

October 6th, 2009

Posted In: Mac OS X, Mac OS X Server, Mass Deployment, Unix, Windows XP

Tags: , , , , , , ,

Every hardware network adapter has a unique MAC address.  However, they’re not always what they seem.  According to Wikipedia:
MAC Spoofing is a hacking technique of changing an assigned Media Access Control (MAC) address of a networked device to a different one. The changing of the assigned MAC address may allow the bypassing of access control lists on servers or routers, either hiding a computer on a network or allowing it to impersonate another computer.
I was talking to someone the other day about security and the topic of spoofing MAC addresses came up.  They seemed to discount that this was usually a concern except for in super secure environments because they considered it an extremely complex process.  Here’s my answer to that:
ifconfig en0 ether 00:00:00:00:00:00 
That should take you about 5 seconds to copy to your clipboard and paste into a terminal window…  You can then replace the en0 with whichever adapter you’d like to implement the spoofed addy on, and hopefully the series of zero’s here with the actual MAC address of a target host.  The next comment was that it was really hard to figure out a MAC address and that’s what makes it hard to spoof them.  If it’s local and you can ping it then arp will cache it.  Therefore, see the IP of the host you’d like to spoof the MAC on in your arp cache with a little:
arp -a
Which gives you something like:
? ( at 0:16:cb:aa:dc:58 on en1 [ethernet]
Now, once you’ve set the MAC, you’ll need to reboot to undo it.  Or just set it back if you copied it before running the earlier command.

March 10th, 2009

Posted In: Mac OS X, Mac OS X Server, Mac Security

Tags: , , , ,

There are a number of items that get logged into Mac OS X Server with only the unique identifier of the MAC address. Sometimes it helps to find the name based on the MAC address. If you are in an environment using trusted binding you can use Open Directory to do so. To determine the name of a computer based on the MAC address from Open Directory, you can run the following from dscl:
dscl /LDAPv3/ -readall /Computers RecordName macAddress | grep -A 1 $MAC

October 9th, 2006

Posted In: Mac OS X Server, Mac Security, Mass Deployment

Tags: , ,