2023-11-17 06:55:06 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								package  main  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"bytes" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"crypto/tls" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"encoding/json" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"errors" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"flag" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"io/ioutil" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"net" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"net/http" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"os" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"os/exec" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"regexp" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"sort" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"strconv" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"strings" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// the default API url 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defaultAPI  =  "https://localhost:8443" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								type  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// json definitions for the web API 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									jsonArray    [ ] * jsonCommand 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									jsonCommand  struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Method   string             ` json:"method" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ID       int                ` json:"id" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										JSONRPC  string             ` json:"jsonrpc" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Params   jsonCommandParams  ` json:"params" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										args     [ ] string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									jsonCommandParams  struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Name          string  ` json:"name" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Value         string  ` json:"value" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										TTL           int     ` json:"ttl" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ForceReverse  bool    ` json:"reverse" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Append        bool    ` json:"append" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Comment       string  ` json:"comment" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										DryRun        bool    ` json:"dry-run" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										IgnoreError   bool    ` json:"ignore-error" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Nonce         string  ` json:"nonce" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Debug         bool    ` json:"-" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									apiResponse  struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ID      int  ` json:"id" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Result  [ ] struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Changes  string  ` json:"changes" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Comment  string  ` json:"comment" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Result   string  ` json:"result" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  ` json:"result" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Error  struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Code     int     ` json:"code" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											Message  string  ` json:"message" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										}  ` json:"error" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// structure for command line options 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									command  struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										args     [ ] string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										descr    string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										options  [ ] string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										check    func ( * jsonCommand )  bool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// global vars  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								var  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									dnsAPI        string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									httpClient    http . Client 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									commands      map [ string ] command 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									generalFlags  [ ] string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Populate the generalFlags, commands and dnsAPI variables  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  init ( )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									generalFlags  =  [ ] string { "dry-run" ,  "comment" } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									commands  =  map [ string ] command { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"a" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<record>" ,  "<ipv4>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Create a A record, points to an IPv4. If the IP has no reverse, create it with the record value (won't apply for wildcard)" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "append" ,  "reverse" ,  "ttl" } ,  cmdCheckIPv4 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"aaaa" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<record>" ,  "<ipv6>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Create a AAAA record, points to an IPv6. If the IP has no reverse, create it with the record value (won't apply for wildcard)" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "append" ,  "reverse" ,  "ttl" } ,  cmdCheckIPv6 } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"cname" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<record>" ,  "<destination>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Create a CNAME record, points to another name. If that name is managed by the DNS server, it must exist" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "ttl" } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"dname" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<record>" ,  "<destination>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Create a DNAME record, points to another name. If that name is managed by the DNS server, it must exist" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "ttl" } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"caa" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<domain>" ,  "<flag>" ,  "<tag>" ,  "<value>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Create a CAA record. If value contains spaces, it must be quoted" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "append" ,  "ttl" } ,  cmdCheckCAA } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"srv" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<_service._proto.name>" ,  "<priority>" ,  "<weight>" ,  "<port>" ,  "<target>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Create a SRV record. https://en.wikipedia.org/wiki/SRV_record" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "append" ,  "ttl" } ,  cmdCheckSRV } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"txt" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<record>" ,  "<\"text\">" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Create a TXT record. No need to escape quotes, it will be done automatically on the server" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "append" ,  "ttl" } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"mx" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<record>" ,  "<priority>" ,  "<mail-server>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Create a MX record. mail-server must exist" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "append" ,  "ttl" } ,  cmdCheckMX } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"ns" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<record>" ,  "<dns-server>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Create a NS record. dns-server must exist and must be an external server" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "append" ,  "ttl" } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"ptr" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<ip | something.arpa>" ,  "<name>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Add a PTR record. If the first argument is an IP, will convert it to an .arpa name" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "append" ,  "ttl" } ,  cmdCheckPTR } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"delete" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<record>" ,  "[value]" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Remove the record. If value is not provided, remove all records of all types sharing the name. If value is specified, only remove that particuliar value. If a deleted record corresponds to a matching reverse, will remove the reverse too" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"ttl" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<record>" ,  "[value]" ,  "<ttl>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Change the TTL of a record. If value is not provided, change the TTL of all types sharing the name. If value is specified, only change that particuliar TTL" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { } ,  cmdCheckTTL } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"newzone" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<zone>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Add a new zone. The zone will be private for a private IPs reverse zone. NS and SOA options are automatically changed" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"search" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<query>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Search the pdns database" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"dump" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<zone>" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"Display the zone" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"list" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "[regexp]" } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											"List zones, filter on regexp if provided" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										"batch" :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											[ ] string { "<file>" } , 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-17 07:29:35 +01:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											"Batch mode: file is a jsonRPC 2.0 complient json file with all commands you want to execute. Example : \n      [\n       { \"jsonrpc\": \"2.0\", \"id\": 0, \"method\": \"list\" },\n       { \"jsonrpc\": \"2.0\", \"id\": 1, \"method\": \"newzone\", \"params\": {         \"name\": \"example.org\", \"ignore-error\": true } },\n       { \"jsonrpc\": \"2.0\", \"id\": 2, \"method\": \"a\", \"params\": {\n           \"comment\": \"it's the fault\", \"name\": \"toto.example.org\",\n           \"value\": \"192.0.2.1\" } }\n      ]\n      By default, an error will stop the batch. Use the boolean ignore-error to change the behaviour for a particular line. The comment and ttl switches are applied only if no explicit value is provided in a line" , 
							 
						 
					
						
							
								
									
										
										
										
											2023-11-17 06:55:06 +01:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
											[ ] string { "ttl" } ,  nil } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// we can override the default API url (for dev/debug). In this case, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// ignore the SSL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									dnsAPI  =  defaultAPI 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  os . Getenv ( "DNS_API" )  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										dnsAPI  =  os . Getenv ( "DNS_API" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// ignore security for localhost 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  strings . HasPrefix ( dnsAPI ,  "https://localhost" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										http . DefaultTransport . ( * http . Transport ) . TLSClientConfig  =  & tls . Config { InsecureSkipVerify :  true } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// set the http timeout 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									httpClient . Timeout  =  time . Duration ( 60  *  time . Second ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . Usage  =  Usage 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// cmdCheckIPv4 is the validation function for the "a" action.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Checks the 2nd argument is an IPv4 address  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  cmdCheckIPv4 ( j  * jsonCommand )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ip  :=  net . ParseIP ( j . args [ 2 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ip  !=  nil  &&  ip . To4 ( )  !=  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// cmdCheckIPv6 is the validation function for the "aaaa" action.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Checks the 2nd argument is an IPv6 address  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  cmdCheckIPv6 ( j  * jsonCommand )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ip  :=  net . ParseIP ( j . args [ 2 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ip  !=  nil  &&  ip . To4 ( )  ==  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// cmdCheckPTR is the validation function for the "reverse" action.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Checks the 1st argument is an IP or a valid .arpa name,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// converts the first argument to the valid .arpa name if necessary,  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// checks that the second argument points back to the first  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  cmdCheckPTR ( j  * jsonCommand )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  ip  net . IP 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . args [ 1 ]  =  strings . Trim ( j . args [ 1 ] ,  "." ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . args [ 2 ]  =  strings . Trim ( j . args [ 2 ] ,  "." ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  strings . HasSuffix ( j . args [ 1 ] ,  ".arpa" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ip  =  net . ParseIP ( ptrToIP ( j . args [ 1 ] ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ip  =  net . ParseIP ( j . args [ 1 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// if ip is not valid, stop here 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ip  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Fprintf ( os . Stderr ,  "Error: %s is not a valid IP or reverse\n\n" ,  j . args [ 1 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . Params . Name  =  iPtoReverse ( ip ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									strIP  :=  ip . String ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									names ,  err  :=  net . LookupHost ( j . args [ 2 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Fprintf ( os . Stderr ,  "Warning: %s must exist\n\n" ,  j . args [ 2 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									cname ,  err  :=  net . LookupCNAME ( j . args [ 2 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									cname  =  strings . Trim ( cname ,  "." ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  ==  nil  &&  cname  !=  j . args [ 2 ]  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Fprintf ( os . Stderr ,  "Error: %s cannot be a CNAME\n\n" ,  j . args [ 2 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  n  :=  range  names  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  n  ==  strIP  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									fmt . Fprintf ( os . Stderr ,  "Warning: %s must point to %s\n\n" ,  j . args [ 2 ] ,  strIP ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// cmdCheckCAA is the validation function for the "caa" action.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  cmdCheckCAA ( j  * jsonCommand )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  q  =  "\"" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  err  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  tag  int 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  tag ,  err  =  strconv . Atoi ( j . args [ 2 ] ) ;  err  !=  nil  ||  tag  <  0  ||  tag  >  255  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . args [ 4 ]  =  strings . Trim ( j . args [ 4 ] ,  q ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . args [ 4 ]  =  strings . Replace ( j . args [ 4 ] ,  q ,  "\\\"" ,  - 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . args [ 4 ]  =  q  +  j . args [ 4 ]  +  q 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . Params . Value  =  fmt . Sprintf ( "%d %s %s" ,  tag ,  j . args [ 3 ] ,  j . args [ 4 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// cmdCheckSRV is the validation function for the "srv" action.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Checks that the arguments are valid, and put them all in arg[2]  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  cmdCheckSRV ( j  * jsonCommand )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  err  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  prio ,  weight ,  port  int 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									validSRV  :=  regexp . MustCompile ( "^_[a-z0-9]+\\._(tcp|udp|tls)[^ ]+$" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! validSRV . MatchString ( j . args [ 1 ] )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  prio ,  err  =  strconv . Atoi ( j . args [ 2 ] ) ;  err  !=  nil  ||  prio  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  weight ,  err  =  strconv . Atoi ( j . args [ 3 ] ) ;  err  !=  nil  ||  weight  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  port ,  err  =  strconv . Atoi ( j . args [ 4 ] ) ;  err  !=  nil  ||  port  <  1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . Params . Value  =  fmt . Sprintf ( "%d %d %d %s" ,  prio ,  weight ,  port ,  j . args [ 5 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// cmdCheckMX is the validation function for the "mx" action.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Checks that the arguments are a weight and a mail servers  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  cmdCheckMX ( j  * jsonCommand )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  err  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  prio  int 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  prio ,  err  =  strconv . Atoi ( j . args [ 2 ] ) ;  err  !=  nil  ||  prio  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . Params . Value  =  fmt . Sprintf ( "%d %s" ,  prio ,  j . args [ 3 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// cmdCheckTTL is the validation function for the "ttl" action.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  cmdCheckTTL ( j  * jsonCommand )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  err  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// The args for this command are "<record>", "[value]", "<ttl>" (the 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// middle argument is optional). 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									n  :=  len ( j . args ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  j . Params . TTL ,  err  =  strconv . Atoi ( j . args [ n - 1 ] ) ;  err  !=  nil  ||  j . Params . TTL  <  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Default value if the optional argument is not given 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  n  <  4  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										j . Params . Value  =  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Output the usage of this specific command  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( c  * command )  Usage ( name  string )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ret  :=  fmt . Sprintf ( "   %s [options] %s %s : \n    %s\n    Options:\n" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										os . Args [ 0 ] ,  name ,  c . formatArgs ( ) ,  c . formatDescr ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									findSame  :=  map [ string ] string { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									alt  :=  map [ string ] string { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  opt  :=  range  append ( generalFlags ,  c . options ... )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fl  :=  flag . Lookup ( opt ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										findSame [ fl . Usage ]  =  opt 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . VisitAll ( func ( f  * flag . Flag )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  opt ,  ok  :=  findSame [ f . Usage ] ;  ok  &&  opt  !=  f . Name  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											alt [ opt ]  =  f . Name 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  opt  :=  range  append ( generalFlags ,  c . options ... )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										var  short ,  arg ,  defValue  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										f  :=  flag . Lookup ( opt ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  s ,  ok  :=  alt [ opt ] ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											short  =  fmt . Sprintf ( "-%s," ,  s ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  f . DefValue  !=  "false"  &&  f . DefValue  !=  "true"  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											arg  =  "<value>" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											defValue  =  fmt . Sprintf ( ", default is %s" ,  f . DefValue ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  f . DefValue  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											defValue  +=  "\"\"" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ret  +=  fmt . Sprintf ( "     %-3v --%-7v %-7v : %s%s\n" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											short ,  f . Name ,  arg ,  f . Usage ,  defValue ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ret 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// CheckArgs populate the json structure with the given arguments and check  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// they are valid  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( c  * command )  CheckArgs ( j  * jsonCommand )  bool  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									args  :=  flag . Args ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									min  :=  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  a  :=  range  c . args  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  a [ 0 ]  ==  '<'  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											min ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( args )  >  len ( c . args ) + 1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( args )  <  min  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  false 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// per construction, there is always at least 2 arguments and the commands 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// in args 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( args )  >  1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										j . Params . Name  =  args [ 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( args )  >  2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										j . Params . Value  =  args [ 2 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// use the adapted check function. It can modify the structure 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  c . check  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  c . check ( j ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// SetDryRun set the dry-run flag on every entry  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( ja  jsonArray )  SetDryRun ( )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i  :=  range  ja  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ja [ i ] . Params . DryRun  =  true 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// SetNonce gets a nonce from the API, and stores it in the structure.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// The nonce is valid for 10 min, to avoid replay attacks  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( ja  jsonArray )  SetNonce ( )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  valid  =  regexp . MustCompile ( ` ^[A-Za-z0-9+/]*$ ` ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									req ,  err  :=  http . NewRequest ( "GET" ,  fmt . Sprintf ( "%s/nonce" ,  dnsAPI ) ,  nil ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									resp ,  err  :=  httpClient . Do ( req ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  resp . Body . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									body ,  _  :=  ioutil . ReadAll ( resp . Body ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  valid . MatchString ( string ( body ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ja [ 0 ] . Params . Nonce  =  string ( body ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  errors . New ( "Cannot get Nonce : Invalid response" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// SetArgs copy the argument from the command line into the structure  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( ja  * jsonArray )  SetArgs ( j  * jsonCommand ,  args  [ ] string )  error  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  len ( args )  <  1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  errors . New ( "Not enough args" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									cmd ,  ok  :=  commands [ args [ 0 ] ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  fmt . Errorf ( "Unknown command %s" ,  args [ 0 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . Method  =  args [ 0 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . args  =  args 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . JSONRPC  =  "2.0" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									j . ID  =  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// check the arguments 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ! cmd . CheckArgs ( j )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Usage ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// evacuate the simple case first 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  args [ 0 ]  !=  "batch"  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										* ja  =  append ( * ja ,  j ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									batch ,  err  :=  ioutil . ReadFile ( args [ 1 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  json . Unmarshal ( batch ,  ja ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i  :=  range  * ja  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										( * ja ) [ i ] . JSONRPC  =  j . JSONRPC 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										( * ja ) [ i ] . ID  =  i 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( * ja ) [ i ] . Params . TTL  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											( * ja ) [ i ] . Params . TTL  =  j . Params . TTL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( * ja ) [ i ] . Params . Comment  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											( * ja ) [ i ] . Params . Comment  =  j . Params . Comment 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  ( * ja ) [ i ] . Params . DryRun  ==  false  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											( * ja ) [ i ] . Params . DryRun  =  j . Params . DryRun 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Usage print the usage for all actions, or just the one used  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  Usage ( )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									fmt . Fprintln ( flag . CommandLine . Output ( ) ,  "Usage: " ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  flag . NArg ( )  >=  1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										name  :=  flag . Arg ( 0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  cmd ,  ok  :=  commands [ name ] ;  ok  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fmt . Fprintf ( flag . CommandLine . Output ( ) ,  "%s\n\n" ,  cmd . Usage ( name ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											os . Exit ( 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									s  :=  [ ] string { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  name  :=  range  commands  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										s  =  append ( s ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sort . Strings ( s ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  name  :=  range  s  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										cmd  :=  commands [ name ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Fprintf ( flag . CommandLine . Output ( ) ,  "%s\n\n" ,  cmd . Usage ( name ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									os . Exit ( 1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// GetYubikey try to find a PGP Smartcard and return its ID  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  GetYubikey ( )  ( string ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									out ,  err  :=  exec . Command ( "gpg" ,  "--card-status" ,  "--with-colons" ) . CombinedOutput ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  "" ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  line  :=  range  strings . Split ( string ( out ) ,  "\n" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  strings . HasPrefix ( line ,  "fpr:" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  strings . Split ( line ,  ":" ) [ 1 ] ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  "" ,  errors . New ( "Yubikey issue (is it plugged in?)" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Sign runs the "gpg --clear-sign" command on the input.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// If the key ID is empty, it will return the input address  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  Sign ( payload  [ ] byte ,  gpgKey  string )  ( [ ] byte ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  gpgKey  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  payload ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									cmd  :=  exec . Command ( "gpg" ,  "--clearsign" ,  "-u" ,  gpgKey ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									stdin ,  err  :=  cmd . StdinPipe ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  payload ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									stdin . Write ( payload ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									stdin . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									out ,  err  :=  cmd . CombinedOutput ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  payload ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  out ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// sendQuery sends the payload to the API server  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  sendQuery ( payload  [ ] byte )  ( [ ] * apiResponse ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									apiRespSimple  :=  & apiResponse { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									apiRespArray  :=  [ ] * apiResponse { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									req ,  err  :=  http . NewRequest ( "POST" ,  fmt . Sprintf ( "%s/jsonrpc" ,  dnsAPI ) ,  bytes . NewBuffer ( payload ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									req . Header . Set ( "Content-Type" ,  "text/plain" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									resp ,  err  :=  httpClient . Do ( req ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									defer  resp . Body . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									s ,  _  :=  ioutil . ReadAll ( resp . Body ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  json . Unmarshal ( s ,  & apiRespArray ) ;  len ( apiRespArray )  >  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  apiRespArray ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  json . Unmarshal ( s ,  apiRespSimple ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  nil ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  append ( apiRespArray ,  apiRespSimple ) ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  main ( )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  j  jsonCommand 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  jsonStruct  jsonArray 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// parse the command line 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . BoolVar ( & j . Params . ForceReverse ,  "reverse" ,  false ,  "Force the creation of a reverse" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . BoolVar ( & j . Params . ForceReverse ,  "r" ,  false ,  "Force the creation of a reverse" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . BoolVar ( & j . Params . DryRun ,  "dry-run" ,  false ,  "Explain what the command would do, but do nothing" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . BoolVar ( & j . Params . DryRun ,  "n" ,  false ,  "Explain what the command would do, but do nothing" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . StringVar ( & j . Params . Comment ,  "comment" ,  "" ,  "Add a comment to the operation" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . StringVar ( & j . Params . Comment ,  "c" ,  "" ,  "Add a comment to the operation" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . IntVar ( & j . Params . TTL ,  "ttl" ,  172800 ,  "Specify the TTL" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . IntVar ( & j . Params . TTL ,  "t" ,  172800 ,  "Specify the TTL" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . BoolVar ( & j . Params . Append ,  "append" ,  false ,  "Append the value, don't replace the whole record" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . BoolVar ( & j . Params . Append ,  "a" ,  false ,  "Append the value, don't replace the whole record" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . BoolVar ( & j . Params . Debug ,  "debug" ,  false ,  "Add debug info" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . BoolVar ( & j . Params . Debug ,  "d" ,  false ,  "Add debug info" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									flag . Parse ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// copy and check the arguments 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  jsonStruct . SetArgs ( & j ,  flag . Args ( ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Fprintln ( os . Stderr ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										Usage ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// now we have the right number of arguments, and a valid command 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Add Nonce 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  :=  jsonStruct . SetNonce ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Fprintln ( os . Stderr ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										os . Exit ( 5 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// get the GPG Public Key from DM_GPG_KEY env var (usefull in case of several Yubikey) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  gpgEnvKey  =  os . Getenv ( "DM_GPG_KEY" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// select Key from env if define 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  gpgKey  string 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  gpgEnvKey  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										gpgKey  =  gpgEnvKey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// or the Yubikey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// get the Yubikey Public Key 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										gpgYubikey ,  err  :=  GetYubikey ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fmt . Fprintln ( os . Stderr ,  "Warning, no Yubikey; forcing dry-run mode" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											jsonStruct . SetDryRun ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										gpgKey  =  gpgYubikey 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Transform into json 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									jsonStr ,  err  :=  json . MarshalIndent ( jsonStruct ,  "  " ,  "  " ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Fprintln ( os . Stderr ,  "panic" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										os . Exit ( 6 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// debug mode 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  j . Params . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Println ( string ( jsonStr ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Sign 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									signed ,  err  :=  Sign ( jsonStr ,  gpgKey ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Fprintln ( os . Stderr ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										os . Exit ( 7 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Send to the server 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ret ,  err  :=  sendQuery ( signed ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										fmt . Fprintln ( os . Stderr ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										os . Exit ( 9 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  response  :=  range  ret  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  response . Error . Message  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											fmt . Fprintln ( os . Stderr ,  "; " + 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												strings . Replace ( response . Error . Message ,  "\n" ,  "\n; " ,  - 1 ) + "\n" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  _ ,  result  :=  range  response . Result  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  strings . Trim ( result . Comment ,  " \n" )  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												fmt . Fprintln ( os . Stderr ,  "; " + 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													strings . Replace ( result . Comment ,  "\n" ,  "\n; " ,  - 1 ) + "\n" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  result . Result  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													fmt . Fprintln ( os . Stderr ,  "; " + result . Result ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  result . Changes  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												fmt . Println ( result . Changes ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// formatDescr outputs the description while adding CR when the line is too long  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( c  * command )  formatDescr ( )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									max  :=  70 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ret  :=  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									current  :=  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  word  :=  range  strings . Split ( c . descr ,  " " )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  strings . Contains ( word ,  "\n" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											current  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ret  +=  word  +  " " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  current + len ( word )  >  max  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ret  +=  "\n      " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											current  =  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										current  +=  len ( word  +  " " ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										ret  +=  word  +  " " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ret  =  strings . Trim ( ret ,  " " ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ret 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// formatArgs concatenate the arguments for the Usage() function  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( c  * command )  formatArgs ( )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  strings . Join ( c . args ,  " " ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// iPtoReverse calculates the reverse name associated with an IPv4 or IPv6  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  iPtoReverse ( ip  net . IP )  ( arpa  string )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									const  hexDigit  =  "0123456789abcdef" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// code copied and adapted from the net library 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// ip can be 4 or 16 bytes long 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  ip . To4 ( )  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  len ( ip )  ==  16  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  uitoa ( uint ( ip [ 15 ] ) )  +  "."  +  uitoa ( uint ( ip [ 14 ] ) )  +  "."  +  uitoa ( uint ( ip [ 13 ] ) )  +  "."  +  uitoa ( uint ( ip [ 12 ] ) )  +  ".in-addr.arpa." 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  uitoa ( uint ( ip [ 3 ] ) )  +  "."  +  uitoa ( uint ( ip [ 2 ] ) )  +  "."  +  uitoa ( uint ( ip [ 1 ] ) )  +  "."  +  uitoa ( uint ( ip [ 0 ] ) )  +  ".in-addr.arpa." 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Must be IPv6 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf  :=  make ( [ ] byte ,  0 ,  len ( ip ) * 4 + len ( "ip6.arpa." ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Add it, in reverse, to the buffer 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i  :=  len ( ip )  -  1 ;  i  >=  0 ;  i --  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										v  :=  ip [ i ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										buf  =  append ( buf ,  hexDigit [ v & 0xF ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										buf  =  append ( buf ,  '.' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										buf  =  append ( buf ,  hexDigit [ v >> 4 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										buf  =  append ( buf ,  '.' ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// Append "ip6.arpa." and return (buf already has the final .) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf  =  append ( buf ,  "ip6.arpa." ... ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  string ( buf ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// Convert unsigned integer to decimal string.  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// code copied from the net library  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  uitoa ( val  uint )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  val  ==  0  {  // avoid string allocation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  "0" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  buf  [ 20 ] byte  // big enough for 64bit value base 10 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									i  :=  len ( buf )  -  1 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  val  >=  10  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										q  :=  val  /  10 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										buf [ i ]  =  byte ( '0'  +  val  -  q * 10 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										i -- 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										val  =  q 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									// val < 10 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									buf [ i ]  =  byte ( '0'  +  val ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  string ( buf [ i : ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// ptrToIP converts a .arpa name to the corresponding IP  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ptrToIP ( s  string )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									s  =  reverseParts ( s )  // reverse parts between dots (".") 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									count  :=  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									ip  :=  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									version  :=  4 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  elt  :=  range  strings . Split ( s ,  "." )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										switch  elt  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  "" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  "ip6" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											version  =  6 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  "in-addr" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										case  "arpa" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											count ++ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											ip  +=  elt 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  version  ==  4  &&  count  !=  4  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ip  +=  "." 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											if  version  ==  6  &&  count % 4  ==  0  &&  count  !=  32  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												ip  +=  ":" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  ip 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								// reverse the part order on every member of the array  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  reverseParts ( s  string )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									parts  :=  strings . Split ( s ,  "." ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  i ,  j  :=  0 ,  len ( parts ) - 1 ;  i  <  j ;  i ,  j  =  i + 1 ,  j - 1  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										parts [ i ] ,  parts [ j ]  =  parts [ j ] ,  parts [ i ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  strings . Join ( parts ,  "." ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}