View Your Old Settings
The first step to moving services from macOS Server for pretty much all services is to check out the old settings. The second step is to probably ask if where you’re going to put the service is a good idea. For example, these days I prefer to run DHCP services on a network appliance. But it can absolutely be run on a Mac. And so let’s look at how to do that. Here, we’ll use the serveradmin command to view the settings of the DHCP service:
/Applications/Server.app/Contents/ServerRoot/usr/sbin/serveradmin settings dhcp
The output is an array of subnets with different settings per subnet.
dhcp:static_maps = _empty_array
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:WINS_primary_server = ""
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:dhcp_router = "10.15.40.1"
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:WINS_secondary_server = ""
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:net_range_start = "10.15.40.2"
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:net_range_end = "10.15.43.253"
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:dhcp_domain_name = "clients.msp.jamfsw.corp"
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:dhcp_domain_name_server:_array_index:0 = "8.8.8.8"
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:dhcp_domain_name_server:_array_index:1 = "4.4.4.4"
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:lease_max = 36000
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:net_mask = "255.255.252.0"
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:dhcp_ldap_url = _empty_array
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:WINS_node_type = "NOT_SET"
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:dhcp_enabled = yes
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:WINS_NBDD_server = ""
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:net_address = "10.15.40.0"
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:WINS_scope_id = ""
dhcp:subnets:_array_id:22217FF5-4DDB-4841-A731-EF5DA080E672:selected_port_name = "en1"
dhcp:subnet_defaults:logVerbosity = "MEDIUM"
dhcp:subnet_defaults:routers:en0 = "10.15.40.1"
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:WINS_node_type = "NOT_SET"
dhcp:subnet_defaults:dhcp_domain_name = "https://krypted.com/"
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 = "8.8.8.8"
dhcp:subnet_defaults:dhcp_domain_name_server:_array_index:1 = "4.4.4.4"
dhcp:subnet_defaults:selected_port_key = "en0"
dhcp:subnet_defaults:selected_port_key_list:_array_index:0 = "en0"
dhcp:subnet_defaults:selected_port_key_list:_array_index:1 = "bridge0"
dhcp:logging_level = "MEDIUM"
Configure DHCP Settings
The easy thing is to configure a DHCP server is using Internet Sharing from the Sharing System Preference pane. To do so, simply open System Preferences, click on Sharing and then Internet Sharing. But wait, where do you configure a scope, or the DNS Server or… The answer is “the command line” but don’t be put off by that. In this case I prefer it.
Now, let’s go hacking around in your bootp.plist. This file is stored at /private/etc/bootpd.plist and you’ll need to sudo in order to edit the file. First, back it up. Next, let’s cat the file and cover a few basic examples of migrating the settings:
<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>
<plist version=”1.0″>
<dict>
<key>NetBoot</key>
<dict/>
<key>Subnets</key>
<array>
<dict>
<key>allocate</key>
<true/>
<key>dhcp_domain_name</key>
<string>krypted.com</string>
<key>dhcp_domain_name_server</key>
<array>
<string>8.8.8.8</string>
<string>4.4.4.4</string>
</array>
<key>dhcp_router</key>
<string>10.15.40.1</string>
<key>lease_max</key>
<integer>36000</integer>
<key>name</key>
<string>10.15.42/22 Wi-Fi</string>
<key>net_address</key>
<string>10.15.40.0</string>
<key>net_mask</key>
<string>255.255.252.0</string>
<key>net_range</key>
<array>
<string>10.15.40.2</string>
<string>10.15.43.253</string>
</array>
<key>selected_port_name</key>
<string>en1</string>
<key>uuid</key>
<string>22217FF5-4DDB-4841-A731-EF5DA080E672</string>
</dict>
</array>
<key>netboot_disabled</key>
<array>
<string>en8</string>
</array>
</dict>
</plist>
Let’s start with a simple example of copying the range from one of these to another. First, locate the net_range_start
and the net_range_end
keys in your serveradmin output. Then find the net_range array in your bootp.plist. They’re the same in my two examples because the macOS Server app was just hacking the bootp.plist (OK it was doing more but that was the main thing it was doing). On a fresh new server you might have a very different plist, so you can borrow the above if ya’ need to. Replace the two values in the two strings with those in your server if needed.
Next, find the dhcp_router
setting for that subnet and match it to the same in the bootp.plist. Then, the net_mask. These are all that are required for DHCP to work (technically, the router isn’t required, but it’s super-weird on Apple stuff when there’s not a router, so it’s best to have one when possible. If you need WINS, domain names, DNS Servers, etc, simply repeat the process. You can also copy and paste the code block between the <dict> sections if you need multiple subnets. Or you could move the service to a network appliance more capable, if needed.
The settings for bootp include the following, many of which can be seen in the above output:
- 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 172.16.25.0.
- 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 172.16.25.2 to 172.16.25.253.
- 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.
Configure DHCP Reservations
To configure reservations, use 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.pretendco.com 1 00:00:00:aa:bb:cc 172.16.25.25
b.pretendco.com 1 00:00:00:aa:bb:cc 172.16.25.29
Starting and Stopping the Service
Once everything is configured, fire it up using the following command:
sudo /bin/launchctl load -w /System/Library/LaunchDaemons/bootps.plist
And terminate using the following command:
sudo /bin/launchctl unload -w /System/Library/LaunchDaemons/bootps.plist
Once configured, configure the service to start automatically. To do so, open /System/Library/LaunchDaemons/bootps.plist. Here, just change the Disabled key to False, by changing the word True in line 6 to False.
Troubleshooting: Inspect Leases on Clients
I did an article some time ago about how DHCP leases work. Once you have clients using the DHCP server, you can also renew and view their leases from the command line, which does not usually show you a new lease in the GUI immediately. To reset the DHCP lease from the command line, use ipconfig:
ipconfig set en0 BOOTP
ipconfig set en0 DHCP
If the information is displayed on the screen, then it has to be stored somewhere, right? When your system sends an acceptance for a lease, the leases are then stored in /var/db/dhcpclient/leases. These are stored in standard property list form using the interface, followed by the MAC address of the interface followed by .plist. For example, if your MAC address is en0-1,10:9a:cc:ab:5d:ac then the lease would cat as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IPAddress</key>
<string>192.168.210.94</string>
<key>LeaseLength</key>
<integer>86400</integer>
<key>LeaseStartDate</key>
<date>2018-02-31T15:36:59Z</date>
<key>PacketData</key>
<data>
AgEGAMHrfCMAAAAAAAAAAMCo0l4AAAAAAAAAABCa3atdrAAAAAAAAAAAAAD/AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABjglNjNQEFNgTAqNIBAQT///8A
MwQAAVGANAEDAwTAqNIBBghEV02CRFdIgv8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
</data>
<key>RouterHardwareAddress</key>
<data>
AAaxLwVA
</data>
<key>RouterIPAddress</key>
<string>192.168.210.1</string>
</dict>
</plist>
The keys in this file make it easier to script figuring out a few things about your active leases, such as when they’re going to expire, when the lease was accepted or even whether or not the system has a lease (especially when it shouldn’t have a lease). But they can cause misreporting. If the information seems “stuck” in the System Preferences pane you can then rm the dhcp lease file.
Note: If the RouterIPAddress cannot be reached, the lease will be delayed in processing, causing the lease to appear to take a long time to be obtained even though it’s looping to hopefully find a more appropriate lease with a RouterIPAddress that can be reached.
For anyone who uses a shell script to reset their IP address, I recommend using the following as the full script, rather than the two lines most commonly used (where $leasefile is the name of your lease file):
ipconfig set en0 BOOTP
ipconfig set en0 DHCP
rm /var/db/dhcpclient/leases/$leasefile
Being the nerd I am, I called mine ipcfg.exe and end with an echo of the IP:
ipconfig getifaddr en0
Finally, a very effective way I’ve seen people reset leases that are seriously stuck is to swap locations and then swap back. Let’s say your users generally use the “Automatic” location and you have one called “TEMP”. You can use the scselect command to see locations and switch between them. So to switch to TEMP, we would simply:
scselect TEMP
And then to select Automatic again:
scselect Automatic
Now be careful with this last little tidbit. As if you have TEMP and don’t have any interfaces active and are running remotely then you might have some walking (or driving) around to do…
Configure DHCP Options
The DHCP Service also has a number of DHCP options available; most notably the options available in the GUI. But what about options that aren’t available in the GUI, such as NTP. Well, using /etc/bootpd.plist, the same file we used to define servers allowed to relay, you can also define other options. These begin with the following keys that can be added into your property list:
- dhcp_time_offset (option 2)
- dhcp_router (option 3)
- dhcp_domain_name_server (option 6)
- dhcp_domain_name (option 15)
- dhcp_network_time_protocol_servers (option 42)
- dhcp_nb_over_tcpip_name_server (option 44)
- dhcp_nb__over_tcpip_dgram_dist_server (option 45)
- dhcp_nb_over_tcpip_node_type (option 46)
- dhcp_nb_over_tcpip_scope (option 47)
- dhcp_smtp_server (option 69)
- dhcp_pop3_server (option 70)
- dhcp_nntp_server (option 71)
- dhcp_ldap_url (option 95)
- dhcp_netinfo_server_address (option 112)
- dhcp_netinfo_server_tag (option 113)
- dhcp_url (option 114)
- dhcp_domain_search (option 119)
- dhcp_proxy_auto_discovery_url (option 252)
But you can also add options by their numerical identifier. To add them, add the following into your /etc/bootpd.plist file and then restart the DHCP service:
<string>dhcp_option_120</string>
<data>
192.168.210.7
</data>
0 – Pad1 – Subnet Mask3 – Router4 – Time Server5 – Name Server6 – Domain Name Server7 – Log Server8 Quote Server9 – LPR Server10 – Impress Server11 – Resource Location Server12 – Host Name13 – Boot File Size14 – Merit Dump File15 – Domain Name16 – Swap Server17 – Root Path18 – Extensions Path19 – IP Forwarding20 – WAN Source Routing21 – Policy Filter22 – Maximum Datagram Reassembly Size23 – Default IP Time-to-live24 – Path MTU Aging Timeout25 – Path MTU Plateau Table26 – Interface MTU27 – All Subnets are Local28 – Broadcast Address29 – Perform Mask Discovery30 – Mask supplier31 – Perform router discovery32 – Router solicitation address33 – Static routing table34 – Trailer encapsulation.35 – ARP cache timeout36 – Ethernet encapsulation37 – Default TCP TTL38 – TCP keep alive interval39 – TCP keep alive garbage40 – Network Information Service Domain41 – Network Information Servers42 – NTP servers43 – Vendor specific information44 – NetBIOS over TCP/IP name server45 – NetBIOS over TCP/IP Datagram Distribution Server46 – NetBIOS over TCP/IP Node Type47 – NetBIOS over TCP/IP Scope48 – X Window System Font Server49 – X Window System Display Manager50 – Requested IP Address51 – IP address lease time52 – Option overload53 – DHCP message type54 – Server identifier55 – Parameter request list56 – Message57 – Maximum DHCP message size58 – Renew time value59 – Rebinding time value60 – Class-identifier61 – Client-identifier62 – NetWare over IP Domain Name63 – NetWare over IP information64 – Network Information Service Domain65 – Network Information Service Servers66 – TFTP server name67 – Bootfile name68 – Mobile IP Home Agent69 – Simple Mail Transport Protocol Server70 – Post Office Protocol Server71 – Network News Transport Protocol Server72 – Default World Wide Web Server73 – Default Finger Server74 – Default Internet Relay Chat Server77 – User Class Information78 – SLP Directory Agent79 – SLP Service Scope80 – Rapid Commit81 – Fully Qualified Domain Name82 – Relay Agent Information83 – Internet Storage Name Service85 – NDS servers86 – NDS tree name87 – NDS context88 – BCMCS Controller Domain Name list89 – BCMCS Controller IPv4 address list90 – Authentication91 – Client Last Transaction Time92 – Associated IP93 – Client System Architecture Type94 – Client Network Interface Identifier95 – LDAP, Lightweight Directory Access Protocol97 – Client Machine Identifier98 – Open Group User Authentication100 – IEEE 1003.1 TZ String101 – Reference to the TZ Database112 – NetInfo Parent Server Address113 – NetInfo Parent Server Tag114- URL116 – Auto-Configure117 – Name Service Search118 – Subnet Selection119 – DNS domain search list120 – SIP Servers DHCP Option121 – Classless Static Route Option123 – GeoConfiguration124 – Vendor-Identifying Vendor Class125 – Vendor-Identifying Vendor Specific128 – TFPT Server IP address129 – Call Server IP address130 – Discrimination string131 – Remote statistics server IP address132 – 802.1P VLAN ID133 – 802.1Q L2 Priority134 – Diffserv Code Point135 – HTTP Proxy for phone-specific applications136 – PANA Authentication Agent139 – IPv4 MoS140 – IPv4 Fully Qualified Domain Name MoS150 – TFTP server address176 – IP Telephone220 – Subnet Allocation221 – Virtual Subnet Selection252 – Proxy auto-discovery254 – Private use255 – End
And that’s it. This whole thing can take 5-10 minutes. In fact, if you were using macOS Server then just backup your bootp.plist and copy it to another machine, assuming the network interface (en0, en1, etc) hasn’t changed. Or change it if it has. But, for all the other weird stuff that was in the UI (or even the stuff that was never in the UI), here’s a pretty lengthy explanation of how to manage all of it from the command line. Building a GUI to configure these wouldn’t be that hard either, assuming you have bootp built into the Mac for awhile (and I think you need it for Internet sharing). Oh, that reminds me, Internet sharing is likely to overwrite any custom settings, so once you hack the plist, don’t go back to System Preferences-based management.