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.2 on Sierra is similar to the DHCP service that was included in Server 10.2 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 OS X, 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">
<string>192.168.210 Wi-Fi</string>

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 = "2016-10-04 04:24:17 +0000"
dhcp:numDHCPActiveClients = 0
dhcp:timeOfSnapShot = "2016-10-04 04:24:19 +0000"
dhcp:dhcpLeasesArray = _empty_array
dhcp:logPaths:systemLog = "/var/log/system.log"
dhcp:numConfiguredStaticMaps = 1
dhcp:timeServiceStarted = "2016-10-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

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.

October 13th, 2016

Posted In: Mac OS X Server, Network Infrastructure

Tags: , , , ,

Leave a Comment

Dropping network connections can be incredibly frustrating. And finding the source can be a challenge. Over the years, I’ve found a number of troubleshooting methods, but the intermittent drop can be the worse to troubleshoot around. When this happens, I’ve occasionally resorted to scripting around failures, and dumping information into a log file to find the issue. For example, you may find that when a network connection fails, you have a very strong signal somewhere, or that you have a very weak signal on all networks.

I’ve found there are three pretty simple commands to test joining/unjoining, and using networks (beyond the standard pings or port scans on hosts). The first is the airport command, along with –disassociate. This just unjoins all networks:

sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport --disassociate

The second is a quick scan. Here, I’ve grep’d out the network I’m after (aka SSIDofNetwork – a very likely wireless network name), but when looking for environmental issues, you might choose to parse this into a csv and output all networks:

sudo /System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -s | grep SSIDofNetwork

Finally, you can join a network. You might have to escape out special characters in a password and it’s never wise to put a password into a script, etc. But, quick and dirty, this will join that SSIDofNetwork network:

sudo networksetup -setairportnetwork en0 "SSIDofNetwork" mysecretpassword

Anyway, loop it, invoke it however you invoke it, etc. Hope this helps someone, and if you have other tricks you’ve found helpful, feel free to throw them in the ‘ole comments!

How Users Feel About Intermittent Networking Issues

August 26th, 2016

Posted In: Mac OS X, Mac OS X Server, Mac Security, Network Infrastructure, Programming

Tags: , , , , , , ,

When I was speaking at MacADUK, I asked Tom Bridge about starting a podcast. He’s got a great voice, and I thought he’d be a great co-host. Before we were able to get to that when we got home, Adam Codega, independently of the conversation I’d had with Tom, dropped a note on Twitter to see who else might be interested in doing a Podcast. A few people responded that they’d be interested in also jumping in on a new Podcast. Over the next few weeks, decisions were made that the podcast would be hosted as a part of, the format, the hosting location, and lots of other really cool stuff. And some of us got together and recorded the first episode. And then, last night, we recorded the second episode just in time to get that into editorial before Episode 1 is released.

And soooooo, episode 1 is out! It includes Tom Bridge, Emil Kausalik, Adam Codega, and myself. We also have an interview with some of the organizers from the Penn State Mac Admins conference, which I wasn’t able to sit in on, but find just fantastic. And Tom did some of the editing. Aaron Lippincott (@dials-Mavis) did a lot of work on the mastering and deserves lots of credit there (he made everyone sound way betterer). And John Kitzmiller did a lot of work on the domain and website and DNS type of stuff, as well as helping with hosting of the podcast assets as well. And Adam’s done a lot of work on the back end linking things together, so a great team effort.

The next episode also features Pepijn Bruienne and Marcus Ransom (who I lovingly decided we should call the He-Man of the Mac Universe) and covers the latest iOS 9.3 release, as well as some information about the Classroom app. So stay tuned for that, but click below to give the episode a listen, or find on iTunes once it appears (and I’ll post a link to that once we can).

Overall, I’m really stoked to get this thing going, and that the group has built a great system for future episodes, that should be sustainable for many, many episodes. I’m also really stoked to be able to get to work with this specific group – I’m a big fan of everyone, and I look forward to many episodes to come! So follow on Twitter at @MacAdmPodcast and feel free to let us know if you’ve done something awesome and we should mention it or interview you!

Episode 1: It Begins

Screen Shot 2016-03-28 at 10.39.29 AM

March 28th, 2016

Posted In: iPhone, Mac OS X, Mac OS X Server, Mac Security, Mass Deployment, Network Infrastructure, personal

Tags: , , , , , ,

Who still says “like a boss?” I guess I did. Get over it. But don’t get over spam. Especially annoying are the ones we know we accidentally signed up for. Because it’s our own darn fault. But luckily, there’s a lot more tools for dealing with bulk mail (solicited or unsolicited) these days. Most modern email clients have the ability to deal with spam. Exchange/Office 365 has clutter and junk. You can build rules on sites. You can use spam assassin on your servers. But, there’s also a nice little app called Once you sign up you’ll have 3 ways of dealing with each message: request removal from a list, mark as rolled up into a single daily digest, or mark as good email.

Download it here. The app works a lot like something like Tinder. You swipe right to like something, left to not like something. Facebook should implement this into your timeline!

Screen Shot 2015-12-01 at 2.34.08 PM

If you decide to mark emails as digests, you’ll get an email once a day that looks like this:

Screen Shot 2015-12-01 at 2.20.58 PM

This works great for organizations that actually properly remove you from lists (which is surprisingly most). Using this swiping type of workflow, you can knock through 100 or more emails in 10-15 minutes. For organizations that don’t respect unfollow or stop sending me your crap emails, there’s also always just marking them as spam. The only problem with this is that you likely have a phone, a computer, a home computer, and maybe a tablet. No one wants to mark the same email as spam four times and then potentially have emails disappearing and not being able to figure out which computer they were marked as junk on.

There are lots and lots of options for this type of thing. But given the ease of use an quick evisceration I can do on my mailbox, I rather like Give it a shot. You might hate it. I don’t.

December 3rd, 2015

Posted In: Apps, cloud, Network Infrastructure

Tags: , , , , ,

There’s a quick and easy IT Business Edge slideshow at that I helped with about 5 Mobile Apps You Really Need for SMB Success.

Screen Shot 2015-08-10 at 2.55.35 PM

Hope you enjoy!

August 10th, 2015

Posted In: Bushel, iPhone, Mac OS X, Mac OS X Server, Mac Security, Mass Deployment, Network Infrastructure

Tags: , , , ,

Mac admins spend a lot of time building images. In System Image Utility this can mean baking an image that just looks for a path of a NetRestore source and restores an operating system. Constantly making these is a pretty duplicative task. The goal of this article is to take a generic NetRestore NetBoot image and augment it in such a way that you don’t need to create new NetBoot images unless there’s a new build train. Instead, all you need to do is edit a file that changes the path (uri) of your image so that it can be restored. Using this, you can just stop the NetInstall service in OS X Server, edit a file, start the service back up and boot clients into the NetBoot environment.

Screen Shot 2015-07-09 at 5.21.31 PM

When you make a NetBoot Set, you’ll select a source. This can be a local volume or a network volume. Once your NetBoot nbi is created, you’ll see a NetInstall.dmg. If you open that dmg, you’ll see a directory called Packages. If you open that, you’ll see an InstallPreferences.plist.

Let’s cat that real quick:

cat /Volumes/NetInstall/Packages/InstallPreferences.plist

The output would be as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">
<string>Unicast Image</string>

Here, let’s look at a few specific keys that we can edit:

  • descriptionKey: A simple, human readable description of the image that will be installed
  • sourceKey: The URI to the image that asr will connect to in order to install the image
    sourcePath: This is the path to the dmg file within the nbi. This is usually best left untouched unless you’ve switched something around within the nbi (which I’ve only seen done a couple of times).
  • restoreSourcesBrowseMulticast: Set to true to allow for multicast imaging. Obviously, DeployStudio or asr would be used to make this work and you’d need to provide a multicast address.
  • installRecoveryPartition: Set this to false if you don’t want to install a recovery partition. You probably should be creating one.
  • restoreSourcesAllowManual: Allows for manual entry of an image source.
  • restoreSourcesBrowseOthers: Allows for browsing over Bonjour for an image source.
  • restoreSourcesArray: Not present if you chose a local path.

You can also edit the NBImageInfo.plist file to set some of the other items you might otherwise edit in System Image Utility. Here, you’ll need to covert the plist to xml to edit it:

plutil -convert xml1 /Volumes/NetBootSP/NetInstall\ OS\ X\ Yosemite.nbi/NBImageInfo.plist

In here, you’ll see a plist similar to the following:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">

The important keys to look at here are:

  • SupportsDiskless: Switch this on and off if you want NetBoot to run for diskless systems (e.g. if you’re a 3 letter government agency).
  • Index: Typically use unique index IDs.
  • IsDefault: Makes that image the default image.
  • RootPath: The path to that NetInstall.dmg file from earlier.
  • ImageType: netrestore versus netinstall.
  • DisabledSystemIdentifiers: Disables certain models of Macs, which you’d edit by adding and removing items from that array.

So you can edit these files, and once you do so, you won’t need to be baking NetBoot sets all the time. Just when there’s a new build train of OS X and you can’t boot those new machines to NetBoot.


July 9th, 2015

Posted In: Mac OS X, Mac OS X Server, Mass Deployment, Network Infrastructure

Tags: , , , , , , , ,

sFlow is an industry standard that allows network equipment with the appropriate agents to send data to sFlow collectors, which then analyze network traffic. You can install sFlow on routers, switches, and even put agents on servers to monitor traffic. Brocade (along with most other switch manufacturers) supports sFlow.

Before you do anything log into the switch and check the current flow configuration:

show sFlow

To configure, log into the switch and use the the int command to access an interface. From within the interface, use the following command:

sflow forwarding

Then exit the interface using the very difficult to remember exit command:


Repeat the enablement of forwarding for any other necessary interfaces. Next, we’ll configure a few globals that would be true across all interfaces. The first is the destination address, done using the destination verb followed by the IP and then the port (I’m using the default 6343 port for sFlow):

sflow destination 6343

Set the sample rate:

sflow sample 512

Set the polling interval:

sflow polling-interval 30

Finally, enable sFlow:

sflow enable

January 2nd, 2015

Posted In: Mac OS X, Mac OS X Server, Mac Security, Network Infrastructure, Xsan

Tags: , , , , , , , , ,

I was recently building some preflight scripts and was looking to record some information about a machine live, before proceeding with a script. I found the cheapest way to determine information about architectures and chipsets when scripting preflight scripts for OS X to be the arch and machine commands respectively. For example, to verify the architecture is i386, use the arch command with no options:


Which simply outputs “i386”:


To check the machine type, simply use the machine command:


Which outputs as follows:


December 14th, 2014

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

Tags: , , , , , , ,

The other day, my daughter said “it’s opposite day” when it was time to do a little homework, trying to get out of it! Which reminded me of a funny little command line tool called rev. Rev reads a file and reverses all the lines. So let’s touch a file called rev ~/Desktop/revtest and then populate it with the following lines:


Now run rev followed by the file name:

rev ~/Desktop/revtest

Now cat it:

cat !$

Now rev it again:

rev !$

You go go forward and back at will for fun, much more fun than homework… Enjoy!

December 12th, 2014

Posted In: Mac OS X, Mac OS X Server, Mac Security, Mass Deployment, Network Infrastructure, Programming, Ubuntu, Unix

Tags: , , , , , , ,

OS X has a command called rvictl, which can be used to proxy network communications from iOS devices through a computer over what’s known as a Remote Virtual Interface, or RVI. To setup an rvi, you’ll need the udid of a device and the device will need to be plugged into a Mac and have the device paired to the Mac. This may seem like a lot but if you’ve followed along with a couple of the other articles I’ve done recently this should be pretty simple. First we’ll pair:

idevicepair pair

Then tap Trust on the device itself. Then we’ll grab that udid with idevice_id:

idevice_id -l

Next, we’ll setup a rvi with rvictl and the -s option (here I’m just going to grab the udid since I only have one device plugged into my computer):

rvictl -s `idevice_id -l`

Then we can list the connections using rvictl with the -l option:

rvictl -l

Next, we’ll run a tcpdump using this newly constructed rvi0:

tcpdump -n -i rvi0

Next, we’ll get a lot of logs. Let’s fire up the Nike FuelBand app and refresh our status. Watching the resultant traffic, we’ll see a line like this:

22:42:29.485691 IP > Flags [S], seq 3936380112, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 706439445 ecr 0,sackOK,eol], length 0

There’s an IP in there, We can look this up and see that the servers are sitting on Amazon Web Services and verify it’s Nike. Watching the traffic with tcpdump we can then obtain GET, POST and other information sent and received. Using wireshark we could get even more detailed data.

Overall though, this article is meant to focus on the iOS side of this and not on debugging and refining the approach to using tcpdump/wireshark. rvictl is a great tool in the iOS development cycle and for security researchers that are looking into how many of the apps on iOS devices exchange data. Enjoy.

November 19th, 2014

Posted In: iPhone, Mac Security, Network Infrastructure

Tags: , , , , , , , , ,

Next Page »