User Tools

Site Tools


infoblox:api

This is an old revision of the document!


BloxOne API

(NIOS further down the page)

REMEMBER, in Linux you can pipe output into “jq” which will format the output as a response to JSON query.

Swagger

Quick CURL

curl -X GET -H "Authorization: Token token=<API_KEY>" "https://csp.infoblox.com/tide/api/data/threats?type=host&class=bot"

Simple CURL

Quick Sample

PORTAL="csp.eu.infoblox.com"
BASE_URL="https://$PORTAL"
API_TOKEN="INSERT_API_KEY_HERE"
curl -s -X GET \
-H "Content-Type: application/json" \
-H "Authorization: Token token=$API_TOKEN" \
"$BASE_URL/api/atcfw/v1/network_lists" | jq
CONTENT_TYPE="Content-Type: application/json"
AUTHORIZATION="Authorization: Token token=$API_TOKEN"

Then you can just run

curl -s -X GET -H "$CONTENT_TYPE" -H "$AUTHORIZATION" \
"$BASE_URL/api/atcfw/v1/network_lists" | jq

What you can do is insert the following lines into .bashrc to have them auto populate when you log in. Be careful about this as it exposes your API key. Nice in a lab but risky in production.

PORTAL="csp.eu.infoblox.com"
BASE_URL="https://$PORTAL"
API_TOKEN="INSERT_API_KEY_HERE"

or even

API="/api/atcfw/v1/network_lists"
curl -s -X GET -H "$CONTENT_TYPE" -H "$AUTHORIZATION" "$BASE_URL$API" | jq

External Networks

API documentation here. Look for 'network_lists'.

Get list of all External Networks including the ID number

curl -s -X GET "https://csp.infoblox.com/api/atcfw/v1/network_lists" -H "Authorization: Token token=ADD_API_KEY" -H "Content-Type: application/json"

Create External Network

curl -s -X POST "https://csp.infoblox.com/api/atcfw/v1/network_lists" -H "Authorization: Token token=ADD_API_KEY" -H "Content-Type: application/json" -d '{"description": "Description of External Network","items": ["1.1.1.0/24","1.1.2.0/24"],"name": "NameOfExternalNetworks"}'

Update Existing External Network - Note the ID number in the URL. Note we completely replace the list with the new list (we are not appending, we are replacing)

curl -s -X PUT "https://csp.infoblox.com/api/atcfw/v1/network_lists/451333" -H "Authorization: Token token=ADD_API_KEY" -H "Content-Type: application/json" -d '{"items": [""1.1.1.0/24","1.1.2.0/24","1.1.3.0/24","1.1.4.0/24"],"name": "NameOfExternalNetworks"}'

Get Support WAPI Versions

curl -k1 -u admin:infoblox -X GET 'https://192.168.1.2/wapi/v2.11/?_schema'

Slightly fancier version

curl -k1 -u admin:infoblox -X GET 'https://192.168.1.2/wapi/v2.11/?_schema&_schema_version=2&_get_doc=1'

Setup

Documentation here.

You will need to install Python3 and

pip3 install bloxone

You will probably want to isntall requests as well

python -m pip install requests

You will also need to have a data file with the API key in.

[BloxOne]
url = 'https://csp.infoblox.com'
api_version = 'v1'
api_key = '1234567890987654321234567890988765434567654345676545665456765456'

Also may need the following for some data transformation scripts

pip install openpyxl

Example

Python Examples.

Set Tag Value in Universal DDI

It takes a CLI argument to set the value of the “Department” tag used to filter which subnets are shown.

# Import the needed Python libraries
import bloxone
import logging
 
# This import is needed if we want to do the JSON iterations
import json
 
# This import is needed to read CLI arguments
import sys
 
 
# Configure Logging
log=logging.getLogger(__name__)
# logging.basicConfig(level=logging.DEBUG)
 
# Create a BloxOne DDI Object and reference the bloxone.ini file that contains the API key
b1ddi = bloxone.b1ddi('/home/bstafford/bloxone.ini')
 
# Show API Key
#print("API Key: ",b1ddi.api_key)
#print("API Version: ",b1ddi.api_version)
 
# Get a response with data.
# In this example, we query the subnets, we apply a filter to show only those subnets that have the "Department" tag set to a value of "Demo" and we only return the address field.
#response = b1ddi.get('/ipam/subnet', _tfilter="Department==Demo", _fields="address")
# In this example, we query the subnets, we apply a filter to show only those subnets that have the "Department" tag set to a value of "Demo" and we return all data as the iterator will control what is printed
# Actually, the value of tag isn't Demo now. It is whatever is passed to the script from the CLI
tag=sys.argv[1]
filter="Department==%s" % (tag)
response = b1ddi.get('/ipam/subnet', _tfilter=filter)
# Response object handling
#print(response.status_code)
#print(response.text)
#print(response.json())
 
# Convert the text results into JSON object
data = json.loads(response.text)
print("All subnets tagged as",tag)
# Iterate over the JSON objects and print the value of each "address" field
for _results in data["results"]:
    print("\tSubnet: ",_results["address"])
 
 
b1p = bloxone.b1platform('/home/username/bloxone.ini')
# Query the list of OPH. Filter by OPH with the tag "Department" set to a value of "Support". Only print the value of "display_name" field.
response = b1p.on_prem_hosts(_tfilter="Department=Support", _fields="display_name")
#print(response.text)

Show Lookalike Domains

# Import the needed Python libraries
import bloxone
import logging
 
# This import is needed if we want to do the JSON iterations
import json
 
# This import is needed to read CLI arguments
import sys
 
 
# Configure Logging
log=logging.getLogger(__name__)
# logging.basicConfig(level=logging.DEBUG)
LAD = Look Alike Domain
# Create a BloxOne TD LAD Object and reference the bloxone.ini file that contains the API key
lad = bloxone.b1tdlad('/home/userbane/bloxone.ini')
data = lad.get('/lookalike_domains').json()
 
# Convert the text results into JSON object
# Iterate over the JSON objects and print the value of each "address" field
for _results in data["results"]:
    if _results["target_domain"] == 'paloaltonetworks.com':
      #print(_results["lookalike_domain"]," is like ",_results["target_domain"])
      print(_results["lookalike_domain"])

List Threat Feed Size

This simple python script will pull down the sizes of the Threat Feeds from Infoblox

#!/usr/bin/env python3
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
 
APIKEY = "ADD_API_KEY_HERE"
 
import requests
import json
 
# Needed to read CLI parameters
import sys
 
# Needed to parse arguments
import argparse
 
# Needed to deal with date / time
from datetime import datetime
 
# Needed to print as a table
# May need to run 'pip install prettytable'
from prettytable import PrettyTable
 
 
# List of names to match
names_to_match_main = [
    "infoblox-base.rpz.infoblox.local",
    "infoblox-base-ip.rpz.infoblox.local",
    "infoblox-high-risk.rpz.infoblox.local",
    "infoblox-med-risk.rpz.infoblox.local",
    "infoblox-low-risk.rpz.infoblox.local",
    "infoblox-informational.rpz.infoblox.local",
    "farsightnod.rpz.infoblox.local"
]
 
names_to_match_policy = [
    "public-doh.rpz.infoblox.local",
    "public-doh-ip.rpz.infoblox.local",
    "bogon.rpz.infoblox.local",
    "cryptocurrency.rpz.infoblox.local",
    "dhs-ais-domain.rpz.infoblox.local",
    "dhs-ais-ip.rpz.infoblox.local",
    "eecn-ip.rpz.infoblox.local",
    "tor-exit-node-ip.rpz.infoblox.local",
    "sanctions-ip.rpz.infoblox.local",
    "sanctions-high.rpz.infoblox.local",
    "sanctions-med.rpz.infoblox.local"
]
 
 
 
 
# Make the cURL request
url = "https://csp.infoblox.com/api/v1/atconfig/dns_firewall/2347/zones"
headers = {
    "Content-Type": "application/json",
    "Authorization": "Token " + APIKEY
}
response = requests.get(url, headers=headers)
 
 
# Create the parser
parser = argparse.ArgumentParser(description="Detect if -s parameter is given")
 
# Add the -s parameter
parser.add_argument('-s', action='store_true', help="Include this flag to print simple CSV")
parser.add_argument('-w', action='store_true', help="Include this flag to print simple HTML")
# Parse the arguments
args = parser.parse_args()
 
 
# Check if the request was successful (status code 200)
if response.status_code == 200:
    data = response.json()
    results = data["results"]
 
    if args.s:
      for result in data["results"]:
        if result["name"] in names_to_match_main:
          print(datetime.today().strftime('%Y-%m-%d'),",",result['name'],",",result['count'], sep="")
      for result in data["results"]:
        if result["name"] in names_to_match_policy:
          print(datetime.today().strftime('%Y-%m-%d'),",",result['name'],",",result['count'], sep="")
    else:
      # Create a PrettyTable object
      table = PrettyTable()
 
      # Define the column names
      table.field_names = ["Threat Feed Name", "Count"]
 
 
      total_count=0
      grand_total=0
      for result in data["results"]:
        if result["name"] in names_to_match_main:
 
          countnumber = result['count']
          formatted_number = "{:,}".format(countnumber)
          table.add_row([result['name'],formatted_number])
          total_count += result['count']
      grand_total=grand_total+total_count
      total_count=0
      for result in data["results"]:
        if result["name"] in names_to_match_policy:
          countnumber = result['count']
          formatted_number = "{:,}".format(countnumber)
          table.add_row([result['name'],formatted_number])
 
          total_count += result['count']
      grand_total=grand_total+total_count
 
 
      # Align columns to left and right
      table.align["Threat Feed Name"] = "l"
      table.align["Count"] = "r"
 
      # Format Count column as integer with commas
      table.float_format["Count"] = ",.0f"
 
      # Print the table
      if args.w:
          print(table.get_html_string())
      else:
          print(table)
 
 
      print("Grand Total: ","{:,}".format(grand_total),"on",datetime.today().strftime('%Y-%m-%d'))
else:
    print("Error:", response.status_code)
 
sys.exit(1)

Reference

API Docs here.

AWS IPAM

To get the Infoblox ID needed by AWS IPAM for management:

curl -s -H "Authorization: Token <YOUR_API_KEY>" https://csp.infoblox.com/v2/current_user | jq '.result.account_infoblox_id'

Get Internal Domain List

The following gets the full list of Internal Domain lists (Security) as well as their contents. You can use this to get the ID of each list.

curl -X GET -H "Authorization: Token token=<APIKEY>" "https://csp.eu.infoblox.com/api/atcfw/v1/internal_domain_lists"

The code below is for when you want to filter the query to show just the contents of a specific list (in this case, the ID is 1234)

curl -X GET -H "Authorization: Token token=<APIKEY>" "https://csp.eu.infoblox.com/api/atcfw/v1/internal_domain_lists/1234"

Get Data of Threat Feed

curl -s -X GET "https://csp.infoblox.com/api/atcfw/v1/threat_feeds?_filter=((name=='AntiMalware')or(name=='FarSightNOD'))" -H "Authorization: Token token=ADD_API_KEY" -H "Content-Type: application/json"

Get Data on Each Threat Feed

Including Threat count data

curl -s -X GET "https://csp.infoblox.com/api/v1/atconfig/dns_firewall/2347/zones" -H "Authorization: Token token=ADD_API_KEY" -H "Content-Type: application/json"

Get Tenant Firewall Data

Get DNS servers, Key data, and client IP to notifiy data.

curl -s -X GET "https://csp.infoblox.com/api/v1/atconfig/dns_firewall" -H "Authorization: Token token=ADD_API_KEY" -H "Content-Type: application/json"

Endpoint

Get full list of endpoint groups

{{base_url}}/api/atcep/v1/roaming_device_groups

Get specific endpoint group

{{base_url}}/api/atcep/v1/roaming_device_groups/225072

To change setting, in Postman goe to Body>raw and set format to TXT

Text: {"name": "name-of-group-test", "tamper_protection_enabled": true, "basic_protection_enabled": true}

Threat Feeds

tdc = bloxone.b1tdc('/home/username/bloxone.ini')
threatfeeds = tdc.get('/threat_feeds').json()
 
for _results in threatfeeds["results"]:
    if _results["threat_level"] == 'HIGH':
      print(_results["key"]," has threat level ",_results["threat_level"])

Feed values in “results”

  • key : 'antimalware-ip'
  • name : 'AntiMalware_IP'
  • description : Some Text
  • source : 'Infoblox/Custom/?'
  • threat_level : HIGH/MEDIUM/LOW
  • confidence_level : HIGH/MEDIUM/LOW

URL Filters

Threat Feeds

tdc = bloxone.b1tdc('/home/username/bloxone.ini')
categories = tdc.get('/content_categories').json()
 
for _results in categories ["results"]:
    if _results["functional_group"] == 'Drugs':
      print(_results["category_name"]," is a gategory in group ",_results["functional_group"])

Feed values in “results”

  • category_code : three digit number
  • category_name : String
  • functional_group : String

Lookalikes

{{base_url}}/api/atclad/v1/lookalikes?_order_by=detected_at desc&_filter=target_domain=="example.lan"

The following will get lookalikes for infoblox.com but only those found after 2025-01-01T17:52:22Z and only those that are detected as suspicious, phishing or malware.

{{base_url}}/api/atclad/v1/lookalikes?limit=101&_offset=0&_filter=detected_at>="2025-01-01T17:52:22Z" and (suspicious=="true" or phishing=="true" or malware=="true") and target_domain:="infoblox.com"&_order_by=registration_date desc

CURL version

curl -X GET -H "Authorization: Token token=MYTOKEN" "https://csp.infoblox.com/api/atclad/v1/lookalikes?_limit=101&_offset=0&_filter=detected_at%3E=%222025-01-1T17:52:22Z%22%20and%20%28suspicious==%22true%22%20or%20phishing==%22true%22%20or%20malware==%22true%22%29%20and%20target_domain:=%22infoblox.com%22&_order_by=registration_date%20desc"

NIOS-X Host Monitoring

This is JSON to use in Postman Test to filter results of monitoring NIOS-X service Documentation Page for Metrics

curl -k "https://<Server IP address>/api/hostmonitoring/v1/metrics" --header 'Accept: application/json' | jq

Documentation Page for Statuses

curl -k "https://<Server IP address>/api/hostmonitoring/v1/statuses" --header 'Accept: application/json' | jq
// ALT+CTLR+C to view Postman Console for this output
let jsonData = pm.response.json();

let jsonObject = jsonData.find(item => item.name === "onprem_host_cpu_percentage_combined");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("Host CPU:", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_host_memory_usage_total");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    let gb = objValue / (1024 ** 3);
    console.log("Host Memory Total:", gb.toFixed(1));
}
jsonObject = jsonData.find(item => item.name === "onprem_host_memory_usage_used");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    let gb = objValue / (1024 ** 3);
    console.log("Host Memory Used:", gb.toFixed(1));
}
jsonObject = jsonData.find(item => item.name === "onprem_host_last_disconnected_timestamp");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("Host Disconnected Time Stamp:", objValue);
}


jsonObject = jsonData.find(item => item.name === "onprem_named_qps");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    let answer = objValue * 1;
    console.log("BIND QPS:", answer.toFixed(2));
}
jsonObject = jsonData.find(item => item.name === "onprem_named_recursion_queries_total");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("Recursive Queries Total:", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_named_success_queries_total");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("Success Queries Total:", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_named_failure_queries_total");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("Failure Queries Total:", objValue);
}


jsonObject = jsonData.find(item => item.name === "onprem_coreDNS_qps");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    let answer = objValue * 1;	
    console.log("DFP QPS:", answer.toFixed(2));
}
jsonObject = jsonData.find(item => item.name === "onprem_coredns_health");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("DFP Health:", objValue);
}


jsonObject = jsonData.find(item => item.name === "onprem_kea_pkt4_request_received");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("DHCP REQUEST Received:", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_kea_pkt4_sent");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("DHCP Sent Total:", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_kea_pkt4_discover_received");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("DHCP DISCOVER Received:", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_kea_pkt4_offer_sent");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("DHCP OFFER Sent:", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_kea_pkt4_received");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("DHCP Recieved Total:", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_kea_pkt4_ack_sent");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("DHCP ACK Sent:", objValue);
}


jsonObject = jsonData.find(item => item.name === "onprem_ntp_stratum");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("NTP Stratum:", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_ntp_offset_milliseconds");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("NTP Offset (ms):", objValue);
}
jsonObject = jsonData.find(item => item.name === "onprem_ntp_reach_octal");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    console.log("NTP Reach Octal:", objValue);
}


jsonObject = jsonData.find(item => item.name === "onprem_cdc_volume_used_MB");
if (jsonObject && jsonObject.metrics.length > 0) {
    let objValue = jsonObject.metrics[0].value;
    let answer = objValue * 1;
    console.log("Total CDC Volume in MB:", answer.toFixed(1));
}

Printing state is much easier

// ALT+CTLR+C to view Postman Console for this output
let jsonData = pm.response.json();

jsonData.forEach(item => {
    console.log("Object: " + item.object + ", State: " + item.state);
});

NIOS

Calls to create network objects are blocking, within a network space. Essentially single threaded. If there are enough calls queued up, waiting for service, those calls will hit a timeout within the product.

Note: Sending calls to the GMC works for most objects except the discovery objects. Those you have to send to the GM.

Version

When starting to use NIOS WAPI for the first time, pick the WAPI version that was introduced in that version of NIOS.

e.g. 2.13.1 was the version introduced with NIOS 9.0.3.

As of May 2025, if you use Terraform, the Infoblox provider currently supports v2.12.3 to ensure compatibility across versions.

Cloud Platform Appliance

curl -k1 -u api:infoblox -H "Content-Type: application/json" -X POST https://192.168.99.1/wapi/v2.8/record:host -d '{"name":"machine1.acme.com","ipv4addrs":[{"ipv4addr":"func:nextavailableip:172.16.0.0/24,default"}],"extattrs":{"Tenant ID":{"value":"Engineering"},"CMP Type":{"value":"Vmware"},"VM ID":{"value":"VM-ID-01"},"VM Name":{"value":"machine-1"},"Cloud API Owned":{"value":"True"}}}'

NIOS API Performance

Anecdotally, 100-125 read/second and 25-30 write/second operations depending on model of GM.

Move read API calls to GMC as there is no way to dynamically tell if GM is overloaded.

More specific searches are always going to be better than broad searches. Similarly, search keys that reduce the result set faster coming first will always be better.

GetGridData

How to download a Grid backup via API

  • BACKUP
  • BACKUP_DTC
  • NTP_KEY_FILE
  • SNMP_MIBS_FILE
  • HF_MANIFEST_FILE

Get download URL and token

curl -k1 -u apiuser:apiuser -X POST 'https://192.168.11.11/wapi/v2.13.7/fileop?_function=getgriddata'  -H "Content-Type: application/json"  -d '{"type": "BACKUP"}'
curl -k1 -u apiuser:apiuser -H "Content-type:application/force-download" -O "https://192.168.11.11/http_direct_file_io/req_id-DOWNLOAD-1103213338881444/database.bak"
curl -k1 -u apiuser:apiuser -X POST 'https://192.168.11.11/wapi/v2.13.7/fileop?_function=downloadcomplete' -H "Content-Type: application/json" -d '{ "token": "eJytjk0LwiAYx79KeG7ao8tst8UKgiiIoKO4tCVtuZxBEX335qGuXTr+357n90RWo2yAvLlGq5Niofe6+vNnmRAIwYBTYBwQVMaYqGA2TurfUPGWxj+glMOKWjacoE5oKlHNK+cvN1vHYKoe0yQvolBi4w\nAIYxI9GW2npzCPJoayOtI78eE62CKlVncKnOkSJq2TgdGVCR73K5nS++gbkcnLaXKoaz5frjR0m6\n4LyqDAlN+weU1xs5+lzD\n" }'

GetMemberData

To download the BIND config file from a member: (works on Linux curl but not Windows 11 curl)

Download logs

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X POST "https://192.168.1.53/wapi/v2.13.1/fileop?_function=get_log_files" -d '{"include_rotated":false,"log_type":"PTOPLOG","node_type":"ACTIVE"}'

Get DNS BIND config file (named.conf)

curl -k -u apiuser:apiuser -H 'Content-Type: application/json' -X POST https://192.168.1.53/wapi/v2.13.6/fileop?_function=getmemberdata -d '{"member":"ns1.member.local","type":"DNS_CFG"}'

Example output (URL for the download. Token for the “disable download” after actually downloading the file)

{
    "token": "eJytjrsKwjAUhl8FMtskp+nFdKtWQRAFERxDadIaaJuaRvCC764ZdHVx/C/n/N8DaYmyCbLqLLQM\nit1xu9nlRUBnwAFYEvGUAQ0jNJ0gdR20vQmnO/U+gTSOE5pSynHKEsbh3bjY1j87OTeMGSHAQwzJ\nDANgiBnxtpDaqsqJWrdKaEN+7RLZjwvT19iVFjd3jyFLV4rOSA+BivyQi/1y9Q1UXxmp+8aH8/X2\n43tJRmds2SjiuuEvMM8XgLpeEA==\n",
    "url": "https://192.168.1.53/http_direct_file_io/req_id-DOWNLOAD-0819113649731024/dnsConf.tar.gz"
}

Type Options:

  • NTP_KEY_FILE
  • DNS_CFG
  • DHCP_CFG
  • DHCPV6_CFG
  • RADIUS_CFG
  • DNS_CACHE
  • DNS_ACCEL_CACHE
  • DHCP_EXPERT_MODE_CFG
  • TRAFFIC_CAPTURE_FILE
  • DNS_STATS
  • DNS_RECURSING_CACHE
  • FP_CPU_USAGE

Use the following to download

curl -k1 -u apiuser:apiuser -H "Content-type: application/force-download" -O https://192.168.1.53/http_direct_file_io/req_id-DOWNLOAD-0819113649731024/dnsConf.tar.gz

For the DNS_CFG specifically, if you want the list of zones on that member, run

tar -xf dnsConf.tar.gz
cat named.conf | grep zone | grep "in {" | awk -F " " '{print $2}' | sed s/\"//g

Finally, close off the download link using the token

curl -k1 -u apiuser:apiuser -H 'Content-Type: application/json' -X POST https://192.168.1.53/wapi/v2.13.6/fileop?_function=downloadcomplete -d '{"token": "eJytjs0KwjAQhF8FctakadMm7a1SBUGsiOAxlCbWgG1quoI/+O42B7168TgzuzPfExmFsgly+iKN\nmhXlYbMu82IWiEDQOIqZ4CGjLEDTCdK33ri7BNPq8YXymCU8SJnAPOSMR9F4cnVn33YC6IeMEJqG\nmCYCU4rHMuJtqYzTNcijOWtpLPk1TLZg+7VtMFQONw/PoSqoZGuVp0BFvs/lbrH8BrqrrTJd48P5\navPxvSQDWFc1mkDb/wXm9QbOnl5G\n"}'

List DNS Data

The following gets a full list of zones in a specific view.

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X GET "https://192.168.11.11/wapi/v2.0/zone_auth?view=external"

The following, given the zone and view, will return JSON with name, zone, type, and view

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X GET "https://192.168.11.11/wapi/v2.13.5/allrecords?_return_fields=name,zone,type,view&zone=external.corp&view=external"

Script to pull the number of zones and records in a given DNS view.

import requests
import urllib3
import argparse

# Suppress SSL warnings for HTTPS
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def main():
    # Set up command-line argument parser
    parser = argparse.ArgumentParser(description="Pull DNS zones and record counts from Infoblox NIOS")
    parser.add_argument("-gm", "--grid_manager", required=True, help="Grid Manager hostname (e.g., nios.staffordnet.uk)")
    parser.add_argument("-u", "--username", required=True, help="Username")
    parser.add_argument("-p", "--password", required=True, help="Password")
    parser.add_argument("-wv", "--wapi_version", required=True, help="WAPI Version (e.g., v2.13.5)")
    parser.add_argument("-view", "--dns_view", required=True, help="DNS View (e.g., internal or external)")

    args = parser.parse_args()

    grid_manager = args.grid_manager
    username = args.username
    password = args.password
    wapi_version = args.wapi_version
    dns_view = args.dns_view

    base_url = f"https://{grid_manager}/wapi/{wapi_version}"

    # Step 1: Get list of DNS zones (zone_auth objects)
    zones_url = f"{base_url}/zone_auth?view={dns_view}"

    try:
        response = requests.get(zones_url, auth=(username, password), verify=False)
        response.raise_for_status()
        zones = response.json()
    except requests.exceptions.RequestException as e:
        print(f"Error fetching DNS zones: {e}")
        return

    zone_names = [zone['fqdn'] for zone in zones]
    print(f"\nNumber of DNS Zones found: {len(zone_names)}\n")

    total_records = 0

    # Step 2: For each zone, get all records and count them
    for zone in zone_names:
        records_url = f"{base_url}/allrecords"
        params = {
            "_return_fields": "name,zone,type,view",
            "zone": zone,
            "view": dns_view
        }

        try:
            rec_response = requests.get(records_url, params=params, auth=(username, password), headers={
                "Content-Type": "application/json"
            }, verify=False)
            rec_response.raise_for_status()
            records = rec_response.json()
            record_count = len(records)
            total_records += record_count
            print(f"{zone}: {record_count} records")
        except requests.exceptions.RequestException as e:
            print(f"Error fetching records for zone {zone}: {e}")

    print(f"\nTotal DNS records across all zones: {total_records}")

if __name__ == "__main__":
    main()

Zone ID

Get the ID of an Auth Zone (need when creating LBDN via API)

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X GET 'https://192.168.1.53/wapi/v2.13.6/zone_auth?fqdn=zone.corp'

DTC

You can use the API to enable/disable DTC LBDN, Pool and Server objects without restarting DNS.

When managing workloads programmatically, the recommended best practice based on DTC's functional constraints is to group servers intended for simultaneous availability into a single dedicated pool. Additionally, servers requiring more granular operational control (such as the frequent addition or removal of individual workloads) should be placed in separate dedicated pools. This approach ensures precise control of workload availability during routine operational activities without disrupting overall service continuity.

Disabling a pool in the GUI effectively takes the pool out of service without requiring a DNS service restart (BIND/named). Nesting a target server within a pool allows you to programmatically manage server availability without frequent restarts. Pools thus support horizontal scalability, but adding or removing individual pool members normally triggers DNS record changes necessitating restarts. Disabling the entire pool is equivalent to a failed health check and circumvents restarts.

It is important to note that, based on the default behaviour of the product, removing a member from a pool by design will trigger a DNS service restart as it is considered a more permanent change, typically requiring a scheduled maintenance window. Conversely, temporarily disabling an entire pool is viewed as a maintenance or administrative action within routine business operations (BAU) that should not disrupt normal service availability.

Get Server REFID

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X GET \
'https://192.168.1.53/wapi/v2.13.6/dtc:server?name=web1-server-object'

Disable Server

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X POST 'https://192.168.1.53/wapi/v2.13.6/dtc?_function=dtc_object_disable' \
-d '{"dtc_object": "dtc:server/ZG5zLmlkbnNfc2VydmVyJHdlYjEtc2VydmVy:web1-server-object","disable_on": ["gridmanager.example.corp"],"disable_timeframe": "UNTIL_MANUAL_ENABLING","disable_health_monitoring":true,"specific_time_disable":1,"delayed_disable":false,"delayed_disable_time":1}'

Enable Server

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X POST 'https://192.168.1.53/wapi/v2.13.6/dtc?_function=dtc_object_enable' \
-d '{"dtc_object": "dtc:server/ZG5zLmlkbnNfc2VydmVyJHdlYjEtc2VydmVy:web1-server-object","enable_on": ["gridmanager.example.corp"]}'

Get Pool REFID

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X GET \
'https://192.168.1.53/wapi/v2.13.6/dtc:pool?name=webtest-pool-object1'

Disable Pool

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X POST 'https://192.168.1.53/wapi/v2.13.6/dtc?_function=dtc_object_disable' \
-d '{"dtc_object": "dtc:pool/ZG5zLmlkbnNfcG9vbCRib29rLXRlc3QucG9vbDE:webtest-pool-object1","disable_on": ["gridmanager.example.corp"],"disable_timeframe": "UNTIL_MANUAL_ENABLING","disable_health_monitoring":true,"specific_time_disable":1,"delayed_disable":false,"delayed_disable_time":1}'

Enable Pool

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X POST 'https://192.168.1.53/wapi/v2.13.6/dtc?_function=dtc_object_enable' \
-d '{"dtc_object": "dtc:pool/ZG5zLmlkbnNfcG9vbCRib29rLXRlc3QucG9vbDE:webtest-pool-object1","enable_on": ["gridmanager.example.corp"]}'

Create LBDN

curl -k -u apiuser:apiuser -H "Content-Type: application/json" -X POST \
"https://192.168.1.53/wapi/v2.13.6/dtc:lbdn" \
-d '{
  "name": "web.internal.bank",
  "pattern": "web.internal.bank",
  "dns_view": "internal",
  "zone": "internal.bank",
  "network_view": "Zulu",
  "lb_method": "ROUND_ROBIN",
  "persistence": 0,
  "priority": 1,
  "pools": [
    {
      "name": "web.internal.bank-pool-1"
    }
  ],
  "record_types": ["A", "CNAME", "AAAA"],
  "ttl": 5,
  "override_ttl": true
}'

Network

Create network 10.32.10.0/24 (output will provide REFID)

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X POST 'https://192.168.1.53/wapi/v2.12/network' \
-d '{"network": "10.32.10.0/24", "network_view": "default", "comment": "Created via API"}'

Alt version - Create network 10.32.10.0/24 (output will provide REFID)

USERNAME=apiuser
PASSWORD=apiuser
NIOSGM=192.168.1.53
WAPI=2.12
BASE_URL="https://$NIOSGM/wapi/v$WAPI"
curl -k1 -u $USERNAME:$USERNAME-H "Content-Type: application/json" -X POST "$BASE_URL/network" \
-d '{"network": "10.32.10.0/24", "network_view": "default", "comment": "Created via API"}'

Get the REFID of network 10.32.10.0/24 (which we use to delete them) (REF ID is also provided when the networks are created)

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X GET \
'https://192.168.1.53/wapi/v2.12/network?network=10.32.10.0/24'

Delete the network 10.32.10.0/24 using REFID

curl -k1 -u apiuser:apiuser -H "Content-Type: application/json" -X DELETE \
'https://192.168.11.53/wapi/v2.12/network/ZG5zLm5ldHdvcmskMTAuMzIuMTAuMC8yNC8w:10.32.10.0/24/default'

Get all IP data out of network 10.9.16.0/24.

curl -k1 -u admin:infoblox -X POST 'https://192.168.1.2/wapi/v2.12/request' -H "Content-Type: application/json" -d '[{
"method":"GET",
"object":"ipv4address",
"data": {"network": "10.9.16.0/24"},
  "args": {
    "_return_fields+":"discovered_data,extattrs"
  }
}]'

Get Zone data (name,type,disable,zone)

https://192.168.1.1/wapi/v2.11/allrecords?
_paging=1&
_max_results=1000&
_return_as_object=1&
_return_fields=name%2Ctype%2Cdisable%2Czone&
zone=company.com&
view=EXTERNAL_VIEW

Get ALL Network Data

  • /wapi/v2.13/network
  • /wapi/v2.13/networkcontainer
  • /wapi/v2.13/ipv6network
  • /wapi/v2.13/ipv6networkcontainer

Should you require IPs, you'd need to add ipv4address and ipv6address and when fetching those you have to pass view and network.

NIOS Add Record

# Create a record

curl -k -u apiuser:apiuser -X POST https://FQDN/wapi/v2.8/record:a -d ipv4addr=192.168.15.20 -d view=my-dns-view -d name=itworks.staffordhome.uk -d comment=This-is-a-Comment

# Search a record. You get JSON back including “_ref” that will look something like record:a/ZG5zLmrfbmRfYSQuX2RlZmF1FgQudWsec3RhZmZvcmRob21lLGl0d29ya3MsMTkyLjE2OC4xNS4yMA:itworks.staffordhome.uk/default

curl -k -u apiuser:apiuser -X GET https://FQDN/wapi/v2.8/record:a -d name=*.staffordhome.uk

# Get a list of ALL A records. You will get a “_ref” for each result in JSON

curl -k -u apiuser:apiuser -X GET https://nios.staffordnet.uk/wapi/v2.13/record

# Search more generally but with a filter for all DNS records with “staffordhome.uk” in them. You will get a “_ref” for each result in JSON

curl -k -u apiuser:apiuser -X GET https://nios.staffordnet.uk/wapi/v2.8/record:a -d view=my-dns-view -d name~:=staffordhome.uk

Find A record that has IP 1.2.3.4

curl -k -u apiuser:apiuser -X GET https://FQDN/wapi/v2.8/record:a -d view=my-dns-view -d ipv4addr=1.2.3.4

Find PTR record for has IP 1.2.3.4

curl -k -u apiuser:apiuser -X GET https://FQDN/wapi/v2.8/record:ptr -d view=my-dns-view -d ipv4addr=1.2.3.43

Find Host that has IP 1.2.3.4

curl -k -u apiuser:apiuser -X GET  https://FQDN/wapi/v2.8/record:host_ipv4addr -d view=my-dns-view -d ipv4addr=1.2.3.4

# Update DNS record with a comment

curl -k -u apiuser:apiuser -X PUT https://nios.staffordnet.uk/wapi/v2.8/record:a/ZG5zLmJpbmRfYSQuX2RlZmF1bHQudWsuc3RhZmZvcmRob21lLGl0d29ya3MsMTkyLjE2OC4xNS4yMA:itworks.staffordhome.uk/default -d comment=Sample-comment

# Delete record using reference from the search above

curl -k -u apiuser:apiuser -X DELETE https://nios.staffordnet.uk/wapi/v2.8/record:a/ZG5zLmJpbmRfYSQuX2RlZmF1bHQudWsuc3RhZmZvcmRob21lLGl0d29ya3MsMTkyLjE2OC4xNS4yMA:itworks.staffordhome.uk/default

API success

"record:txt/ZG5zLmJpbmRfdHh0JC5fZGVmYXVsdC51ay5zdGFmZm9yZGhvbWUudGVzdDIuImhlbGxvLXdvcmxkIg:test1.acme.com/default"

API Failure

{ "Error": "AdmConDataError: None (IBDataConflictError: IB.Data.Conflict:Cannot add records to a zone that is not authoritative)",
  "code": "Client.Ibap.Data.Conflict",
  "text": "Cannot add records to a zone that is not authoritative"
}

Create a Network

network network_view=default -d network=10.1.10.0/24 -d comment=This-is-a-Comment

Create a DHCP Range inside an existing network

range -d start_addr=10.1.9.3 -d end_addr=10.1.9.7 -d network_view=default -d network=10.1.9.0/24 -d comment=This-is-a-Comment

Get Grid Member Status

Get list of members. This will give you “member/serial:fqdn.internal.local” which you then use on the second query.

In this case 10.1.1.1 is the Grid Manager IP

curl --insecure -k -u admin:infoblox -X GET https://10.1.1.1/wapi/v2.7.1/member

Get data on specific member

curl --insecure -k -u admin:infoblox -X GET https://10.1.1.1/wapi/v2.7.1/member/b25lLnAdcgR1QWxfbm9e3SQw:ns1.internal.local?_return_fields=node_info

or even more data

curl --insecure -k -u admin:infoblox -X GET https://10.1.1.1/wapi/v2.7.1/member/b25lLnZpcnR1YWxfbm9kZSQw:infoblox.localdomain?_return_fields=node_info,host_name,master_candidate,enable_ha,comment

Data

  • ha_status“: “NOT_CONFIGURED”,
  • hwid”: “33d1fe7450d2293dda3bf1c2312e7e9”,
  • hwmodel“: “IB-VM-820”,
  • hwplatform”: “VMWARE”,
  • hwtype“: “IB-VNIOS”,
  • lan2_physical_setting”…
  • lan_ha_port_setting“…
  • mgmt_physical_setting”…
  • service_status“

Status (FAILED, INACTIVE, OFFLINE, UNKNOWN, WARNING, WORKING)

  • NODE_STATUS
  • ENET_LAN
  • NTP_SYNC
  • OSPF
  • OSPF6
  • BGP
  • BFD
  • CORE_FILES
  • DISK_SIZE
  • VPN_CERT

Status (Percentage)

  • DB_OBJECT
  • CPU_USAGE
  • CPU_USAGE (It is listed twice)
  • MEMORY
  • SWAP_USAGE
  • DISK_USAGE
  • DISCOVERY_CAPACITY

Run DIG Command

From community page.

From documentation.

Warning: If you do go the route of WAPI, be careful using the WAPI grid?_function=query_fqdn_on_member as it has a 10s timeout that is not configurable & it's a blocking call. If you run a query and the member can't reach or communicate w/ the upstream nameserver, it will BLOCK for 10s. The GM blocks all other WAPI calls for that duration.

curl --insecure -k1 -u apiuser:apiuser -X POST 'https://fqdn.gm.appliance.local/wapi/v2.12/request' -H "Content-Type: application/json" -d \
'[
                {
                                "method":"POST",
                                "object":"grid",
                                "args":
                                {
                                                "_function":"query_fqdn_on_member"
                                },
                                "data":
                                {
                                                "name_server":"8.8.8.8",
                                                "fqdn":"infoblox.com",
                                                "record_type":"A",
                                                "member":"member1.fqdn.local"
                                }
                },
                {               "method":"POST",
                                "object":"grid",
                                "args":
                                {
                                                "_function":"query_fqdn_on_member"
                                },
                                "data":
                                {
                                                "name_server":"8.8.8.8",
                                                "fqdn":"infoblox.com",
                                                "record_type":"A",
                                                "member":" member2.fqdn.local "
                                }
                }
]'

Export DNS Zone Data

curl -k -u username:password -X GET https://ip/wapi/v2.9/allrecords?zone=zone&view=default&_return_fields=zone&_max_results=500&_return_as_object=1&_paging=1

The following call helps in pulling all record data from subzones, regardless of the DNS View:

curl -k -u username:password -X GET 'https://ip/wapi/v2.8/allrecords?zone=sub.zone&_return_as_object=1'

If you do add 'view=' after the zone argument, it will provide data from that specific DNS View, otherwise only from the default DNS View.

curl -k -u username:password -X GET 'https://ip/wapi/v2.8/allrecords?zone=sub.zone&view=default&_return_as_object=1'

This call should provide all A record details from the same zone regardless of their DNS Views

curl -k -u username:password -X GET 'https://ip/wapi/v2.8/record:a?name~=sub.zone&_return_fields=name,ipv4addr,view&_return_as_object=1'

You can specify the resource record type by defining 'record:host' or 'record:ptr' separately.

NIOS Paging

For very large results, you may need to add &_paging=1&_return_as_object=1&_max_results=1000. The return object will contain a next_page_id field, which you call in the following call with the same query but adding &_page_id={id_string_from_next_page_id}.

NIOS Perl API

The Perl API (PAPI) has been officially deprecated since NIOS version 8.4.

Starting from NIOS version 9.0.6, Perl module access is disabled by default.

All future enhancements and fixes are now provided through the RESTful API (WAPI).

To enable PAPI, the following CLI command must be executed:

set perl_mod_access

When you enable or disable the perl_mod_access, there will be no impact but the Grid interface (GUI) will be restarted. It doesn’t cause any service impact or appliance restart.

infoblox/api.1771596130.txt.gz · Last modified: by bstafford