This is an old revision of the document!
Table of Contents
BloxOne API
REMEMBER, in Linux you can pipe output into “jq” which will format the output as a response to JSON query.
Swagger
- Official Doc Page linking to both of the links above.
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.
