Contents

MS-DHCP ⤐ To Infoblox migration strategy and implementation


Scenario: This is one of the way to migrate MS-DHCP subnets to Infoblox (one subnet at a time) approach. This will provide overview of the workflow I used during the project.


Overview 💡

If you ask me, how it started ~K2 ? Well, I got pulled into SD-ACCESS Project where I needed to migrate all scopes from existing MS DHCP server to new Infoblox server. Later on, I felt the requirement to automate the process as the data was just too much to deal with manually. I started thinking an easy way to move all the scopes with just one click sorta zero touch provisioning.

Being a UNIX background guy, I was surprised with the way powershell was evolving. Also it made much sense to use powershell the data I need to work was scattered around MS products. My end goal was to move DNS/DHCP and IPAM completely over to Infoblox and it exactly fit in with my requirement. I know that I can use the same code (with minor changes) to migrate DDI from Vital QIP to Infoblox which was my next project.

Background

We will now explore required powershell module to access DHCP server. The main idea is to store the information and utilize it over infoblox API that we will discuss in details.

MS DHCP Server PowerShell Module

As I mentioned, powershell is one of the easy way to access the DHCP servers and we can access it just by using powershell DHCP Server Module called DHCPServer. It can be installed with Add-WindowsFeature -Name DHCP -IncludeManagementTools in a powershell. Here are some useful commands.

Examples:

PS C:\Users\703430520> Get-Command -Module DHCPServer

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           Reconcile-DhcpServerv4IPRecord                     2.0.0.0    DhcpServer
Function        Add-DhcpServerInDC                                 2.0.0.0    DhcpServer
Function        Add-DhcpServerSecurityGroup                        2.0.0.0    DhcpServer
Function        Backup-DhcpServer                                  2.0.0.0    DhcpServer
Function        Export-DhcpServer                                  2.0.0.0    DhcpServer
Function        Get-DhcpServerAuditLog                             2.0.0.0    DhcpServer
Function        Get-DhcpServerDatabase                             2.0.0.0    DhcpServer
Function        Import-DhcpServer                                  2.0.0.0    DhcpServer
Function        Invoke-DhcpServerv4FailoverReplication             2.0.0.0    DhcpServer
Function        Remove-DhcpServerDnsCredential                     2.0.0.0    DhcpServer
Function        Remove-DhcpServerInDC                              2.0.0.0    DhcpServer
Function        Rename-DhcpServerv4Superscope                      2.0.0.0    DhcpServer
Function        Repair-DhcpServerv4IPRecord                        2.0.0.0    DhcpServer
Function        Restore-DhcpServer                                 2.0.0.0    DhcpServer
Function        Set-DhcpServerAuditLog                             2.0.0.0    DhcpServer
Function        Set-DhcpServerDatabase                             2.0.0.0    DhcpServer
...             ...                                                ...        ...

We can get all the info of particular scope from DHCP server and its reserved IPs by using following command.

PS C:\> Get-DhcpServerv4Scope -ComputerName $myserver -scopeid 172.19.132.0 | format-list

ScopeId          : 172.19.132.0
Name             : TEST SUBNET
Description      : TEST SUBNET
SuperscopeName   : 
SubnetMask       : 255.255.252.0
StartRange       : 172.19.132.201
EndRange         : 172.19.135.254
LeaseDuration    : 1.00:00:00
NapProfile       : 
NapEnable        : False
Delay(ms)        : 0
State            : Active
Type             : Dhcp
MaxBootpClients  : 4294967295
ActivatePolicies : True

PS C:\>
PS C:\>
PS C:\> Get-DhcpServerv4Reservation -ComputerName $myserver -scopeid 172.19.132.0

IPAddress        ScopeId        ClientId             Name        Type   Description
---------        -------        --------             ----        ----   -----------
172.19.133.210   172.19.132.0   00-e0-4b-2d-86-36    DevA        Both   Device-A
172.19.132.211   172.19.132.0   28-29-86-24-d3-2a    apc24D32A   Dhcp   UPS 
172.19.132.212   172.19.132.0   b8-a4-4f-09-bd-9e    axis-cam    Dhcp   CAMERA

So, here’s a game plan, store all the information into variables and then apply it to REST API for Infoblox.

Steps at Infoblox using REST API:

  • We will create scopes
  • fix the options or any extensible attributes
  • create DHCP range and assign it to grid
  • move all reserved and static entries to Infoblox.

Storing info in variables:

# User Input Required Parameters:
write-Host "Provide these two parameters:" -ForegroundColor White -BackgroundColor Blue
"----------------------------"
$dhcpserver=$(write-Host  -NoNewline '1. DHCP SERVER: '; read-host)
$scopeid=$(write-Host  -NoNewline '2. SCOPE-ID: '; read-host)

# Saving all the info:
$output=Get-DhcpServerv4Scope -ComputerName $dhcpserver -ScopeId $scopeid 
$subnetmask=$output.SubnetMask.IPAddressToString
$startrange=$output.StartRange.IPAddressToString
$endrange=$output.EndRange.IPAddressToString
$subnet_name=$output.Name

Python for static ARP Entries (Optional)

quote text=“Again, this step is completely optional, I was thinking about to log into SVI (i.e. device) and get the info of the static arps. The reason of this step to get a complete info of the static devices and reserve it so that even if we want to expand the scope, we can do it without an issue. Example: say 192.168.0.0/24 scope has its DHCP services configured between 192.168.0.100 to 192.168.0.200. Even if some devices being leased out static IPs outside the range, the script will get the info of that device and assign it into the infoblox. Thus, even if we want to expand the scope to 192.168.0.0 to 192.168.0.200, it will still reserve the statically typed IP spaces.”

For logging into device, we are using a popular python module called netmiko that that can log into network devices and run any kind of commands. The code can be self explanatory with the comments. In future I will definetely write a blog post about myy best python modules.

import netmiko
import sys
import re
import ipaddress
from getpass import getpass
from netaddr import IPAddress 

# Username and password save
username='user'
password=getpass()

# Arguments saved in a variables
scope_id=sys.argv[1]
end_range=sys.argv[2]
subnet_mask=sys.argv[3]

# Calculating network mask, broadcast IP and gateway IP
subnet_maskbits = IPAddress(subnet_mask).netmask_bits()
mynetwork=ipaddress.ip_network(scope_id+'/'+str(subnet_maskbits))
my_broadcast = mynetwork.broadcast_address

# Depends on what kind of gateway you on scope (In this example, gateway is .254 for /24 scope)
gateway_ip = my_broadcast - 1
start_range=scope_id[0]+"."+scope_id[1]+"."+scope_id[2]+".1"

# Function to login the device using Netmiko module
def ssh_config(ip,command):
    connect=netmiko.ConnectHandler(ip=ip, device_type='cisco_ios', username=username, password=password)
    switch=connect.find_prompt()
    output=connect.send_command(command)
    return(output)

output=ssh_config(str(gateway_ip),"show ip arp")

# Finding the IP in an arp is challenging. So the logic is to 
# check the index and find it out if it throws error or not.
# len((output.splitlines()[3]).split())

index=0

while index < len((output.splitlines()[20]).split()):
    try:
        ipaddress.ip_address(output.splitlines()[20].split()[index])
        break
    except:
        index+=1
        pass

static_ips_macs=""  #Initializing empty variables

for line in output.splitlines()[1:]:
    try:
        if int(ipaddress.ip_address(line.split()[index])) > int(ipaddress.ip_address(end_range)) and int(ipaddress.ip_address(line.split()[index])) < int(ipaddress.ip_address(str(my_broadcast))):
            if "INCOMPLETE" in line:
                continue
            else:  
                static_ips_macs+=line.split()[index]+"   -------->   "+line.split()[index+2]+"\n"
    except:
        continue

print(static_ips_macs)
# This value can be returned or printed on powershell side for further data processing.

     

Infoblox ⤐ DNS, DHCP, IPAM (DDI)

As a recap, we saved information from MS DHCP to variables and also saved static arp entries. Now the remaining task is to send all the info to infoblox and start creating the scopes, comment with useful description and all the thing that mentioned earlier.

I will tell you that Infoblox did not paid me to write about them but if you want to know why Infoblox ? The idea is to use same platform for entire DNS, DHCP and IPAM as they tie up together. With the growing need of cloud, network function virtualization, software defined solution, and internet of things, modern DDI would need a better functionality with API designs, scalable, agile, secure and enterprise grade alternatives. Infoblox is one of the modern DDI platform with most of the features that supports security, reliability, efficiency and DDI management/provisioning. Find more info about mylink link=“https://www.infoblox.com/" text=“Infoblox here.”

Infoblox ⤐ WAPI

Infoblox WAPI is an REST API interface that uses HTTP methods for operation and suports input and output data in JSON and XML format. Many resources for Infoblox WAPI can be found. Few of them that I followed are 🔗infoblox-deployment-infoblox-rest-api, 🔗WAPI documentation and ofcourse 🔗Infoblox Community.

Powershell Snippets for Infoblox

Here are some powershell codes that will create network, with DHCP options and scopes.

if (!$subnet) 
{ 
    
    Write-Host "SCOPE: $scopeid has not been created at InfoBlox." -ForegroundColor White -BackgroundColor RED
    "`n"
    $type_yes=$(write-Host  -NoNewline 'Type "yes" to Create Infoblox Scope: '; read-host)
    if ($type_yes -like "yes" ) {
   
   # CREATING A NETWORK

    $new_Net = @{network=$ip_calculation.Network; comment="SD BISMARCK $subnet_name"; options=@(); members=@()}
    $new_Net.members += @{'_struct'='dhcpmember'; ipv4addr=$DHCP_SERVER}
    $new_Net.options += @{name='routers'; value=$ip_calculation.HostMax}
    $new_Net.options += @{name='domain-name-servers'; value=$DNS_SERVER1, $DNS_SERVER2}
    # assuming DHCP Options 242; $variables are used for values
    $new_Net.options += @{num=242; value='MCIPADD=$MCIPADD,MCPORT=$PORT,HTTPSRVR=$IP_ADDRESS,TLSSRVR=$TLSSRVR'}
    
    # Adding the network
    write-Host "Creating Network ..." -ForegroundColor Black -BackgroundColor Green
    "`n"
    $new_Net | New-IBObject -type network
    "`n"
    # Add a DHCP range

    # build the range variable
    $newRange = @{ start_addr=$startrange; end_addr=$endrange; name="SD BISMARCK $subnet_name"; comment="SD BISMARCK $subnet_name" }
    $newRange.server_association_type = 'MEMBER'
    $newRange.member = @{ '_struct'='dhcpmember'; ipv4addr=$dhcpmember}
    
    # create the range
    write-Host "Creating DHCP Range within the Scope: "$ip_calculation.Network -ForegroundColor Black -BackgroundColor Green
    "`n"
    $newRange | New-IBObject -type range
    }
    else { 
    "`n"
    Break Script;
    }
}

Migrate Static and Dynamic Reservation

Here are some powershell codes that will migrate reserved and static arp’ed IP addresses from MS-DHCP to infoblox.

write-Host "InfoBlox Reservation Output for DHCP Reserved IPs:" -ForegroundColor White -BackgroundColor Blue
for($i=0; $i -le $total_count.count-1; $i++)
        {
         try {
                New-IBObject -type fixedaddress -IBObject @{ipv4addr=$alldata.IPAddress.IPAddressToString[$i];mac=$alldata.ClientId[$i];name=$alldata.Name[$i];comment='~Reserved by K2'} | Out-Null ;
                Write-Host  -NoNewline "SUCCESS --> IP:" $alldata.IPAddress.IPAddressToString[$i] "& MAC: "$alldata.ClientID[$i] -ForegroundColor Black -BackgroundColor Green "`n"
            }
        catch{
                Write-Host  -NoNewline "ERROR ON --> IP:" $alldata.IPAddress.IPAddressToString[$i] "& MAC: "$alldata.ClientID[$i]" --> (DUPLICATE)" -ForegroundColor Black -BackgroundColor Red "`n"
            }
        }


# Infoblox Host Reservation for Static IPs
write-Host "InfoBlox Reservation Output for Static IPs:" -ForegroundColor White -BackgroundColor Blue
for($i=1; $i -le $static_ips_macs.Count-1; $i++)
    {
     try {
                New-IBObject -type fixedaddress -IBObject @{ipv4addr=$($static_ips_macs[$i]|awk '{print $1}');mac=$($static_ips_macs[$i]|awk '{print $3}');name='~Reserved by K2';comment='~Reserved by K2'} | Out-Null ;
                Write-Host  -NoNewline "SUCCESS --> IP:"$($static_ips_macs[$i]|awk '{print $1}') "  MAC:"$($static_ips_macs[$i]|awk '{print $3}') -ForegroundColor Black -BackgroundColor Green "`n"
            }
        catch{
                Write-Host  -NoNewline "ERROR ON --> IP:" $($static_ips_macs[$i]|awk '{print $1}') "  MAC:"$($static_ips_macs[$i]|awk '{print $3}')" --> (DUPLICATE)" -ForegroundColor Black -BackgroundColor Red "`n"
            }
    }
    

# InfoBlox Grid Status:
$grid_stats=Get-IBObject -type grid | Invoke-IBFunction -name requestrestartservicestatus -args @{service_option='ALL'} | Out-String
Write-Host  -ForegroundColor Green -Object $grid_stats

# Restarting Grid If Necessary!
write-Host "InfoBlox grids will be restarted if necessary !" -ForegroundColor White -BackgroundColor Blue
write-Host "Thanks !!!" -ForegroundColor White -BackgroundColor Blue
$restartArgs = @{restart_option="RESTART_IF_NEEDED"}
Get-IBObject -type grid | Invoke-IBFunction -name restartservices -args $restartArgs

     

Summary

I hope this blog post help you to understand the procedure of the migration of the data from one platform to another. Entire code can be made modular and flexible once we know the scope of the migration.