├── README.md ├── build_bind ├── build_bind.conf.sample ├── build_bind.inc.php ├── install.php ├── install.sql └── plugin_info.php /README.md: -------------------------------------------------------------------------------- 1 | build_bind 2 | ============== 3 | 4 | This is the module that will enable the ability to extract and build BIND DNS server configurations from the database. It will output the configuration text that would normally be located in something like /etc/bind/named.conf or similar. 5 | 6 | Install 7 | ------- 8 | 9 | 10 | * If you have not already, run the following command `echo '/opt/ona' > /etc/onabase`. This assumes you installed ONA into /opt/ona 11 | * Ensure you have the following prerequisites installed: 12 | * A BIND DNS server. It is not required to be on the same host as the ONA system. 13 | * `sendEmail` for notification messages. [Download here](http://caspian.dotconf.net/menu/Software/SendEmail/) or use the package from your distribution. 14 | * A functioning dcm.pl install on your DHCP server. 15 | * Download the archive and place it in your $ONABASE/www/local/plugins directory, the directory must be named `build_bind` 16 | * Make the plugin directory owned by your webserver user I.E.: `chown -R www-data /opt/ona/www/local/plugins/build_bind` 17 | * From within the GUI, click _Plugins->Manage Plugins_ while logged in as an admin user 18 | * Click the install icon for the plugin which should be listed by the plugin name 19 | * Follow any instructions it prompts you with. 20 | * Install the $ONABASE/www/local/plugins/build_bind/build_bind script on your DNS server. It is suggested to place it in /opt/ona/bin 21 | * Modify the variables at the top of the build_bind script to suit your environment. 22 | 23 | Usage 24 | ----- 25 | At least one host within ONA should be defined as a DNS server for whatever domains you expect it to be responsible for. The install process above should have also created a system configuration variable called "build_dns_type" with a value of "bind". 26 | 27 | You should now see the configuration being built real time in the web interface each time you select the server host and view its DNS server display page. 28 | 29 | This now also exposes the dcm.pl module called `build_bind_conf` and `build_bind_domain`. These will be used by the build_bind script to extract the configuration. It is also used by the web interface to generate configuration data. 30 | 31 | There are a few configuration options in the build script that should be examined. Edit the file `/opt/ona/bin/build_bind` and adjust the following options as needed: 32 | 33 | 34 | # this will default to placing data files in /opt/ona/etc/bind, you can update the following for your system as needed 35 | # for things like chroot jails etc 36 | ONA_PATH="${ONABASE}/etc/bind" 37 | 38 | # Get the local hosts FQDN. It will be an assumption!! that it is the same as the hostname in ONA 39 | # Also, the use of hostname -f can vary from system type to system type. be aware! 40 | SRV_FQDN="$(hostname -f)" 41 | 42 | # Path to the dcm.pl command. Also include any options that might be needed 43 | DCM_PATH="${ONABASE}/bin/dcm.pl" 44 | 45 | # Define path for curl binary requires if pulling templates from remote web server 46 | CURL_PATH="/usr/bin/curl" 47 | 48 | # Specify a URL to a directory located on a web server containing domain based 49 | # footers with additional DNS records to be appended to respective DNS zones. 50 | # Using this method footer files don't have to be manually synced between 51 | # name servers. The remote path can be located on the web server that also 52 | # provided for the OpenNetAdmin instance. 53 | # 54 | # It is highly recommended to use HTTPS (SSL/TLS) for transport security but 55 | # at least ip address based access control e.g. using a htaccess file. 56 | # When using http basic authentication you can embed the user credentials 57 | # within the URI like this: 58 | # 59 | # # e.g. FOOTER_URL="https://USERNAME:PASSWORD@ipam.mydomain.tld/zone_footers" 60 | FOOTER_URL="https://USER:PASSWORD@ona.domain.tld/zone_footers" # no trailing slash 61 | 62 | # The command used to check the configuration syntax prior to restarting the daemon 63 | CHECKCOMMAND="named-checkconf -z" 64 | 65 | # The command used to restart bind 66 | # two options would be standard init.d or something like RNDC if it is configured 67 | # in your environment 68 | SYSTEMINIT="/etc/init.d/named reload" 69 | 70 | # Email settings for config_archive to send status information to (diffs etc) 71 | MAIL_SERVER=mail.example.com # name or IP of the mail server to use 72 | MAIL_FROM=ona-build_dhcpd@${SRV_FQDN} # email address to use in the from field 73 | MAIL_TO=hostmaster@example.com # email address(es) to send our notifications to 74 | 75 | Most BIND servers default to using `/etc/bind/named.conf` or similar as their config. You should make this a symbolic link to `/opt/ona/etc/bind/named.conf.ona` or do an `include` of this config file in your main named.conf. 76 | 77 | On some systems you may need to add the ONA related files to your apparmor or similar security tool. 78 | 79 | Now that it is installed you should be able to execute `/opt/ona/bin/build_bind` as root. This will build a configuration file from the data in ONA, test its syntax, and place it into the file `/opt/ona/etc/bind/named.conf.ona`. When the test is ran it will process configurations built from the database that are stored in /opt/ona/etc/bind. If it is successful it will restart the BIND server using the init program defined in the `SYSTEMINIT` config variable. Also set the value of `CHECKCOMMAND` to somethine like `named-config -z` to test the configuration before restarting. 80 | 81 | Once you have a successful rebuild of your configuration, you can then put the `/opt/ona/bin/build_bind` build script into a cron that runs at whatever interval you see as appropriate for your environment. I would suggest at least 2 times a day all the way down to once every 15 minutes. Remember, you can always run it on demand if needed. You will need to run it as root since it needs to restart the daemon. 82 | 83 | Many modern linux systems use the /etc/cron.d method. You can put ONA related cron jobs into this directory. As an example you can create a file called /etc/cron.d/ona with the following content: 84 | 85 | # Please store only OpenNetAdmin related cron entries here. 86 | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin/:/opt/ona/bin 87 | 88 | # Rebuild BIND configuration file and restart daemon every hour 89 | 0 * * * * root /opt/ona/bin/build_bind > /dev/null 2>&1 90 | 91 | Configuration (version 1.6+) 92 | ----- 93 | 94 | Since version 1.6 the configuration is no longer embedded within the `build_bind` script itself. Instead it uses a separate config file expected at `${ONABASE}/etc/build_bind.conf`. 95 | 96 | Simply copy the sample config `build_bind.conf.sample` to etc/ within your base folder and adjust its parameters to fit your needs. However, it is also possible to provide a custom config using the `-c /CONFIG` option. 97 | 98 | 99 | Fetching Zone Footers from Remote Web Server 100 | ----- 101 | 102 | ONA does not yet support DNS records to be placed within DNS zones as long as those aren't handled through ONA itself. For instance, as of the moment it *is not possible* to add records for mail servers (MX) or canonical names (CNAMES) that are pointing to external servers. Creating local zone records for such email servers is one way to work around this limitation. However, it's fairly inconvenient especially when facing the fact that addresses for MX servers of large providers like Google are operated using volatile ip pools. 103 | 104 | The reason why this wasn't fixed within ONA yet? It is related to the current database design. Matt explains it in the following threads: 105 | 106 | Non ONA managed CNAMES (external DNS references) 107 | https://github.com/opennetadmin/ona/issues/70 108 | 109 | Adding remote host or CNAME - DNS import 110 | http://opennetadmin.com/forum_archive/4/t-65.html 111 | 112 | To overcome this limitation for the moment, one can use zone footers in order to add necessary DNS records per zone e.g. using a script that's executed right after zones were generated by the build_bind script. 113 | 114 | At the moment `build_dns` tries to implement this using so called 'remote footers'. By simply specifying the `-t` option `build_dns` can look for domain specific footers within a directory on a remote web server. Once a match was found the content of the footer file will be automatically appended to the local zone of the respective domain. 115 | 116 | This approach allows for footers to be kept centrally without the need to manually synchronize them across servers. E.g. in order to add the global mail exchange servers of Google to the zone file of `example.com` do the following: 117 | 118 | [root@ona ~]# cd /var/www/html/ona/ 119 | [root@ona ona]# mkdir zone_footers 120 | [root@ona ona]# cat <<'HERE' > zone_footers/example.com.footer 121 | ; MX Records 122 | @ 1800 IN MX 10 aspmx.l.google.com 123 | @ 1800 IN MX 20 alt1.aspmx.l.google.com 124 | @ 1800 IN MX 30 alt2.aspmx.l.google.com 125 | @ 1800 IN MX 40 aspmx2.googlemail.com 126 | @ 1800 IN MX 50 aspmx3.googlemail.com 127 | HERE 128 | 129 | In this example we're deploying the footers on the web server that is also hosting our ONA instance. This way one can re-use the .htpasswd file that's used to protect access to the dcm.php script. You do restrict access to your dcm.php script, don't you? 130 | 131 | A bit out of scope but here's a snippet for a httpd virtual host containing the directives required to secure your installation including the footers folder: 132 | 133 | 134 | 135 | Order deny,allow 136 | # name server ip address 137 | allow from 10.238.13.8 138 | allow from localhost 139 | 140 | AuthUserFile /opt/ona/www/.htpasswd 141 | AuthName "dcm access" 142 | AuthType basic 143 | Require valid-user 144 | 145 | 146 | 147 | Order deny,allow 148 | # name server ip address 149 | allow from 10.238.13.8 150 | allow from localhost 151 | 152 | Options Indexes MultiViews FollowSymLinks 153 | AllowOverride All 154 | 155 | AuthUserFile /opt/ona/www/.htpasswd 156 | AuthName "footer access" 157 | AuthType basic 158 | Require valid-user 159 | 160 | 161 | 162 | Create a separate account for authenticating access to the footers directory (the username reflects within the web server log file). 163 | 164 | 165 | [root@ona ona]# htpasswd /opt/ona/www/.htpasswd footers 166 | New password: ******* 167 | Re-type new password: ******* 168 | Adding password for user footers 169 | 170 | 171 | On the name server you should now be able to fetch the footer for zone example.com we've created earlier: 172 | 173 | 174 | [root@ns01 ~]# curl -s --output example.com.footer https://footers:MYPASSWORD@ona.domain.tld/zone_footers/example.com.footer 175 | [root@ns01 ~]# cat example.com.footer 176 | 177 | 178 | 179 | Lets run `build_bind` with the `-t` option and see what happens: 180 | 181 | 182 | [root@ns01 ~]# /opt/ona/bin/build_bind -t 183 | Sep 30 22:51:17 [ONA:build_bind]: INFO => Building BIND DNS config for ns01.example.com... 184 | Sep 30 22:51:23 [ONA:build_bind]: INFO => Scanning for footers on remote server ... 185 | Sep 30 22:51:23 [ONA:build_bind]: INFO => Found a match for zone example.com.. appending. 186 | Sep 30 22:51:26 [ONA:build_bind]: INFO => Testing new config files for SYNTAX only... 187 | [...] 188 | Sep 30 23:01:37 [ONA:build_bind]: INFO => Completed BIND configuration 189 | extraction and daemon reload. 190 | 191 | [root@ns01 ~]# tail -6 /var/named/zone_data/named-example.com 192 | ; MX Records 193 | @ 1800 IN MX 10 aspmx.l.google.com 194 | @ 1800 IN MX 20 alt1.aspmx.l.google.com 195 | @ 1800 IN MX 30 alt2.aspmx.l.google.com 196 | @ 1800 IN MX 40 aspmx2.googlemail.com 197 | @ 1800 IN MX 50 aspmx3.googlemail.com 198 | 199 | 200 | Hint: It is highly recommended to implement transport security by using TLS. In a medium scale deployment w/o a proper way of distributing security certificates it almost always makes sense to use certs issued by a public CA. It is furthermore recommended to use a platform that delivers support for Perfect Forward Secrecy such as Apache 2.4 as part of CentOS 7. 201 | 202 | -------------------------------------------------------------------------------- /build_bind: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # build_bind.sh -- v1.6 4 | # 5 | # Written by: Matt Pascoe 6 | # Edited by: Jan Dennis Bungart 7 | # 8 | # License: 9 | # build_bind.sh (hereafter referred to as "program") is free software; 10 | # you can redistribute it and/or modify it under the terms of the GNU General 11 | # Public License as published by the Free Software Foundation; either version 12 | # 2 of the License, or (at your option) any later version. 13 | # Note that when redistributing modified versions of this source code, you 14 | # must ensure that this disclaimer and the above coder's names are included 15 | # VERBATIM in the modified code. 16 | # 17 | # Disclaimer: 18 | # This program is provided with no warranty of any kind, either expressed or 19 | # implied. It is the responsibility of the user (you) to fully research and 20 | # comprehend the usage of this program. As with any tool, it can be misused, 21 | # either intentionally (you're a vandal) or unintentionally (you're a moron). 22 | # THE AUTHOR(S) IS(ARE) NOT RESPONSIBLE FOR ANYTHING YOU DO WITH THIS PROGRAM 23 | # or anything that happens because of your use (or misuse) of this program, 24 | # including but not limited to anything you, your lawyers, or anyone else 25 | # can dream up. And now, a relevant quote directly from the GPL: 26 | # 27 | # NO WARRANTY 28 | # 29 | # 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 30 | # FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 31 | # OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 32 | # PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 33 | # OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 34 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 35 | # TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 36 | # PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 37 | # REPAIR OR CORRECTION. 38 | # 39 | # The GNU GPL can be found at http://www.fsf.org/copyleft/gpl.html 40 | # 41 | # ----------------------------------------------------------------------- 42 | # Description 43 | # Subversion info: $Id: build_bind 95 2012-01-15 03:56:43Z matt $ 44 | # 45 | # 46 | # THIS IS A REFERENCE DESIGN BUILD SCRIPT, IT WORKS FOR ME BUT MAY NOT FOR YOU 47 | # IT IS INTENDED TO GIVE AN EXAMPLE OF HOW A SCRIPT LIKE THIS COULD BE BUILT. IF IT WORKS 48 | # FOR YOU, GREAT! IF NOT THEN MAKE WHATEVER ADJUSTMENTS TO IT YOU NEED TO GET IT WORKING! 49 | # ASK FOR HELP IN THE FORUMS IF NEEDED. 50 | # 51 | # 52 | # REQUIRES: dcm.pl, build_bind_server_domain_list module, build_bind_domain module and 53 | # build_bind_conf module, working rndc for the local server. 54 | # 55 | # Since this script must restart the named daemon, it should be ran as the bind user or as root. 56 | # 57 | # dcm.pl should be working on your system and either in your path or you will need 58 | # to put the full path to it in the DCM_PATH variable below. 59 | # 60 | # The tools rndc and named-checkconf must be in your path as well. 61 | # 62 | # Remember that the checks done by named-checkconf are only syntax checks. They will not 63 | # ensure that the content of your files is correct. If you have missing records or 64 | # incorrect data it could impact your environment or the functionality of other domain servers. 65 | # It is recomended that you run a BIND server under ONA control as a hidden master, then 66 | # slave other dns servers off of it that would service your end users. This helps protect 67 | # against failures during build time causing outages for end users. 68 | # 69 | # By default the local host name is determined using "hostname -f" but can also 70 | # be specified with the -s option. The server name must match the FQDN of the server 71 | # in ONA. It must be the PRIMARY name, not an CNAME or alternate A record. 72 | # 73 | # For ease of use, it is recommended to add /opt/ona/bin to your $PATH environment variable 74 | # 75 | # Add the following line to your system named.conf file. Probably in /etc/bind/named.conf 76 | # or named.conf.local depending on your system. The placement of this line could vary 77 | # depending on how your distro organizes named. named.conf.local should be used for 78 | # ubuntu/debian based systems. 79 | # 80 | # include "/opt/ona/etc/bind/named.conf.ona"; 81 | # 82 | # You will need to execute the following dcm commands to automatically create the appropriate module entries: 83 | # 84 | # NOTE: this script was developed and tested on an ubuntu box. Your mileage may vary on other distros. 85 | # NOTE: On my ubuntu box I had to modify the apparmor configuration in 86 | # /etc/apparmor.d/usr.sbin.named to include "/opt/ona/etc/bind/** r," 87 | # NOTE: to view example configs in the GUI you need to set build_dns_type to "bind" in the sys_config table 88 | # 89 | # ----------------------------------------------------------------------- 90 | 91 | [ ! -r /etc/onabase ] && echo "[$0] ERROR: Unable to read /etc/onabase." && exit 1 92 | ONABASE=$(cat /etc/onabase) 93 | 94 | # define path to local configuration file and inform if it's not present 95 | LOCALCONF="${ONABASE}/etc/build_bind.conf" 96 | [ ! -r ${LOCALCONF} ] && echo "[$0] NOTICE: Local config file ${LOCALCONF} absent, exiting." && exit 1 97 | 98 | #### Process the commandline options 99 | USAGE=" 100 | Usage: $(basename $0) [-c] [-s ] [-b] [-t] [-d] 101 | 102 | -c Specify the absolute path to a custom config file 103 | -s FQDN of the server you wish to build BIND configs for 104 | -b Enable batch mode (less verbose logging for scripted runs) 105 | -t Enable download of domain specific footers from a web server 106 | -d Enable debug output 107 | " 108 | 109 | while getopts "c:sbtd" options; do 110 | case $options in 111 | c ) LOCALCONF=$OPTARG;; 112 | s ) SRV_FQDN=$OPTARG;; 113 | b ) BATCHMODE=1;; 114 | t ) FOOTERS=1;; 115 | d ) DEBUGON=1;; 116 | \? ) echo "$USAGE" 117 | exit 1;; 118 | * ) echo "$USAGE" 119 | exit 1;; 120 | esac 121 | done 122 | 123 | # include a local configuration file if present to prevent settings from being 124 | # overwritten whenever the build_bind script is being updated 125 | [ ! -r "${LOCALCONF}" ] || source "${LOCALCONF}" 126 | 127 | # This will log a message in a standardized way 128 | # Its job is simple.. take the message that was passed in and log it via some mechanism. 129 | # Currently, it echos to stdout and logs in syslog 130 | function ONA_LOG { 131 | # Log it to the screen 132 | [ $BATCHMODE ] || echo $(date +'%h %d %H:%M:%S') [ONA:$(basename $0)]: "$1" 133 | 134 | # log it to syslog 135 | logger -t [ONA:$(basename $0)] "$1" 136 | } 137 | 138 | # This function will exit with a status of 1 and if in batch mode, will print a success/fail message 139 | function MAIL_ALERT { 140 | [ $BATCHMODE ] && echo FAILURE 141 | # send an email notification 142 | sendEmail -s $MAIL_SERVER -f $MAIL_FROM -t $MAIL_TO \ 143 | -u "[ONA:$(basename $0)] $SRV_FQDN: Failure during BIND rebuild." \ 144 | -m "The BIND server '${SRV_FQDN}' has encountered an error during its last rebuild, please check the status of the server. To investigate further you can execute the following command on the server: ${CHECKCOMMAND}" 145 | if [ $? -ne 0 ] 146 | then 147 | ONA_LOG "ERROR => There was an issue sending the notification email." 148 | fi 149 | exit 1 150 | } 151 | 152 | # Check if the $ONA_PATH directory exists 153 | if ! test -d $ONA_PATH/zone_data 154 | then 155 | ONA_LOG "ERROR => Unable to find directory '${ONA_PATH}/zone_data', please create it." 156 | MAIL_ALERT 157 | fi 158 | 159 | # Check if $FOOTER_PATH directory exists 160 | if ! test -d $FOOTER_PATH 161 | then 162 | ONA_LOG "ERROR => Unable to find directory '${FOOTER_PATH}', please create it." 163 | MAIL_ALERT 164 | fi 165 | 166 | [ $BATCHMODE ] || ONA_LOG "INFO => Building BIND DNS config for ${SRV_FQDN}..." 167 | 168 | # Lets get a list of domains for this server from the database 169 | #DOMAIN_LIST=$($DCM_PATH -r build_bind_server_domain_list server=$SRV_FQDN) || abend "Unable to determine domain list for server named $SRV_FQDN." 170 | if ! DOMAIN_LIST=$($DCM_PATH -r build_bind_server_domain_list server=$SRV_FQDN) 171 | then 172 | ONA_LOG "ERROR => Unable to determine domain list for server named ${SRV_FQDN}." 173 | MAIL_ALERT 174 | fi 175 | 176 | # build the named.conf.ona file 177 | # Note, I cut the first / off due to the DCM issue with paths 178 | if ! $DCM_PATH -r build_bind_conf path=$(echo $ONA_PATH|cut -c2-60)/zone_data server=$SRV_FQDN > $ONA_PATH/named.conf.ona 179 | then 180 | ONA_LOG "ERROR => Unable to build bind config file." 181 | MAIL_ALERT 182 | fi 183 | 184 | # loop through list of domains and build the zone file 185 | for DOMAIN in $(echo $DOMAIN_LIST) 186 | do 187 | if ! $DCM_PATH -r build_bind_domain domain=$DOMAIN > $ONA_PATH/zone_data/named-$DOMAIN 188 | then 189 | ONA_LOG "ERROR => Unable to build zonefile: named-${DOMAIN}." 190 | MAIL_ALERT 191 | fi 192 | done 193 | 194 | # check if fetching remote footers was requested 195 | if [ -n "${FOOTERS}" ] 196 | then 197 | 198 | [ $BATCHMODE ] || ONA_LOG "INFO => Scanning for footers on remote server ..." 199 | 200 | # create a folder used to temporarily store the footers 201 | FOOTER_TMPDIR="$(mktemp -d)" 202 | 203 | # loop through list of domains and attach remote footers to local zone files 204 | for DOMAIN in $(echo $DOMAIN_LIST) 205 | do 206 | $CURL_PATH -s --fail --output "${FOOTER_TMPDIR}/${DOMAIN}.footer" "${FOOTER_URL}/${DOMAIN}.footer" 207 | if [ $? == 0 ] 208 | then 209 | ONA_LOG "INFO => Found a match for zone ${DOMAIN}.. appending." 210 | # attach footer to local zone file 211 | cat $FOOTER_TMPDIR/$DOMAIN.footer >> $ONA_PATH/zone_data/named-$DOMAIN 212 | fi 213 | done 214 | 215 | # safely remove footers and temp folder 216 | rm -rf ${FOOTER_TMPDIR}/*footer 217 | rmdir ${FOOTER_TMPDIR} 218 | 219 | fi 220 | 221 | [ $BATCHMODE ] || ONA_LOG "INFO => Testing new config files for SYNTAX only..." 222 | 223 | # Test that our new config is syntacticaly correct 224 | # this assumes named-checkconf is in your path and that you are using the standard named.conf file path of /etc/bind/named.conf 225 | if ! $CHECKCOMMAND 226 | then 227 | ONA_LOG "ERROR => The resulting config files contain one or more syntax errors." 228 | MAIL_ALERT 229 | fi 230 | 231 | # refresh the bind nameserver 232 | # there are a few ways to do this.. RNDC is probably "best" but not everyone has that configured so a SIGHUP should do the trick as well 233 | # also RNDC could use a reconfig or a reload. for now I'm going for a full reload.. if it is a HUGE server, reconfig might be better. 234 | # though for now I'm rebuilding all the zones anyway. 235 | # 236 | # Or a simple /etc/init.d/bind9 reload would work 237 | if ! $SYSTEMINIT 238 | then 239 | ONA_LOG "ERROR => Unable to reload the named daemon using the command ${SYSTEMINIT}." 240 | MAIL_ALERT 241 | fi 242 | 243 | [ $BATCHMODE ] || ONA_LOG "INFO => Completed BIND configuration extraction and daemon reload." 244 | -------------------------------------------------------------------------------- /build_bind.conf.sample: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # this will default to placing data files in /opt/ona/etc/bind, you can update the following for your system as needed 3 | # for things like chroot jails etc 4 | ONA_PATH="${ONABASE}/etc/bind" 5 | 6 | # Define the FQDN of the local server. That it is the same as the hostname in ONA 7 | # It is recommended to hard code the host name rather than using "$(hostname -f)" 8 | # since it relies on a system with a proper hostname and domain configuration 9 | SRV_FQDN="ns01.example.com" 10 | 11 | # Path to the dcm.pl command. Also include any options that might be needed 12 | DCM_PATH="${ONABASE}/bin/dcm.pl" 13 | 14 | # Define path for curl binary requires if pulling templates from remote web server 15 | CURL_PATH="/usr/bin/curl" 16 | 17 | # Specify a URL to a directory located on a web server used to store domain based 18 | # footers. Each file contains additional DNS records to be appended to respective 19 | # local DNS zones generated from ONA. 20 | # 21 | # Using this method footers don't have to be manually synced between 22 | # name servers. The remote path can be located on the web server that also 23 | # provided for the OpenNetAdmin instance (preferred way). 24 | # 25 | # It is highly recommended to use HTTPS (SSL/TLS) for transport security but 26 | # at least ip address based access control on the target server 27 | # e.g. using a htaccess file. When using http basic authentication 28 | # you can embed the user credentials within the URI in the following way: 29 | # 30 | # e.g. FOOTER_URL="https://USERNAME:PASSWORD@ipam.mydomain.tld/zone_footers" 31 | # 32 | FOOTER_URL="https://USER:PASSWORD@ona.domain.tld/zone_footers" # no trailing slash 33 | 34 | # The command used to check the configuration syntax prior to restarting the daemon 35 | CHECKCOMMAND="named-checkconf -z" 36 | 37 | # The command used to restart bind 38 | # two options would be standard init.d or something like RNDC if it is configured 39 | # in your environment 40 | SYSTEMINIT="/etc/init.d/named reload" 41 | 42 | # Email settings for config_archive to send status information to (diffs etc) 43 | MAIL_SERVER=mail.example.com # name or IP of the mail server to use 44 | MAIL_FROM=ona-build_dhcpd@${SRV_FQDN} # email address to use in the from field 45 | MAIL_TO=hostmaster@example.com # email address(es) to send our notifications to 46 | -------------------------------------------------------------------------------- /build_bind.inc.php: -------------------------------------------------------------------------------- 1 | Found install file for ".basename(dirname(__FILE__))." plugin.", 1); 6 | include(dirname(__FILE__)."/install.php"); 7 | } else { 8 | 9 | // Place initial popupwindow content here if this plugin uses one. 10 | 11 | 12 | } 13 | 14 | 15 | // Make sure we have necessary functions & DB connectivity 16 | require_once($conf['inc_functions_db']); 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | /////////////////////////////////////////////////////////////////////// 25 | // Function: build_bind_server_domain_list (string $options='') 26 | // 27 | // Input Options: 28 | // $options = key=value pairs of options for this function. 29 | // multiple sets of key=value pairs should be separated 30 | // by an "&" symbol. 31 | // 32 | // Output: 33 | // Returns a two part list: 34 | // 1. The exit status of the function (0 on success, non-zero on error) 35 | // 2. A textual message for display on the console or web interface. 36 | // 37 | // Example: list($status, $result) = build_bind_server_domain_list('server=test'); 38 | // 39 | // Exit codes: 40 | // 0 :: No error 41 | // 1 :: Help text printed - Insufficient or invalid input received 42 | // 43 | // 44 | // 45 | /////////////////////////////////////////////////////////////////////// 46 | function build_bind_server_domain_list($options="") { 47 | 48 | // The important globals 49 | global $conf, $self, $onadb; 50 | 51 | // Version - UPDATE on every edit! 52 | $version = '1.50'; 53 | 54 | printmsg("DEBUG => build_bind_server_domain_list({$options}) called", 3); 55 | 56 | // Parse incoming options string to an array 57 | $options = parse_options($options); 58 | 59 | // Return the usage summary if we need to 60 | if ($options['help'] or !$options['server']) { 61 | // NOTE: Help message lines should not exceed 80 characters for proper display on a console 62 | $self['error'] = 'ERROR => Insufficient parameters'; 63 | return(array(1, 64 | << build_bind_server_domain_list() server record: {$domain['server']}", 3); 88 | if (!$shost['id']) { 89 | printmsg("DEBUG => Unknown server record: {$options['server']}",3); 90 | $self['error'] = "ERROR => Unknown server record: {$options['server']}"; 91 | return(array(3, $self['error'] . "\n")); 92 | } 93 | 94 | // For the given server id. find all domains for that server 95 | list($status, $rows, $records) = db_get_records($onadb, 'dns_server_domains', array('host_id' => $shost['id']), ''); 96 | 97 | //MP: TODO - for now this just returns a list of all the domains. In the future this could/should just return 98 | // a list of domains that need refreshed. This would imply a version to do ALL and one for just UPDATED domains. 99 | foreach ($records as $sdomain) { 100 | list($status, $rows, $domain) = ona_get_domain_record(array('id' => $sdomain['domain_id'])); 101 | $text .= $domain['fqdn'] . "\n"; 102 | } 103 | 104 | // Return the list 105 | return(array(0, $text)); 106 | } 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | /////////////////////////////////////////////////////////////////////// 117 | // Function: build_bind_conf (string $options='') 118 | // 119 | // Input Options: 120 | // $options = key=value pairs of options for this function. 121 | // multiple sets of key=value pairs should be separated 122 | // by an "&" symbol. 123 | // 124 | // Output: 125 | // Returns a two part list: 126 | // 1. The exit status of the function (0 on success, non-zero on error) 127 | // 2. A textual message for display on the console or web interface. 128 | // 129 | // Example: list($status, $result) = build_bind_conf('server=test'); 130 | // 131 | // Exit codes: 132 | // 0 :: No error 133 | // 1 :: Help text printed - Insufficient or invalid input received 134 | // 2 :: No such host 135 | // 3 :: Host is not a DNS server 136 | // 4 :: SQL Query failed 137 | // 138 | // 139 | // History: 140 | // 141 | // x/x/06 - Matt Pascoe: 142 | // 143 | // 2/27/06 - Matt Pascoe: adjusted header section to pull headers 144 | // from the template database and insert them. The format 145 | // is to look for templates named "named_header_" 146 | // 147 | /////////////////////////////////////////////////////////////////////// 148 | function build_bind_conf($options="") { 149 | 150 | // The important globals 151 | global $conf, $self, $onadb; 152 | 153 | // Version - UPDATE on every edit! 154 | $version = '1.51'; 155 | 156 | printmsg("DEBUG => build_bind_conf({$options}) called", 3); 157 | 158 | // Parse incoming options string to an array 159 | $options = parse_options($options); 160 | 161 | // Return the usage summary if we need to 162 | if ($options['help'] or !($options['server'] and $options['path'])) { 163 | // NOTE: Help message lines should not exceed 80 characters for proper display on a console 164 | $self['error'] = 'ERROR => Insufficient parameters'; 165 | return(array(1, 166 | << build_bind_conf() server record: {$domain['server']}", 3); 201 | if (!$shost['id']) { 202 | printmsg("DEBUG => Unknown server record: {$options['server']}",3); 203 | $self['error'] = "ERROR => Unknown server record: {$options['server']}"; 204 | return(array(3, $self['error'] . "\n")); 205 | } 206 | 207 | // For the given server id. find all domains for that server 208 | list($status, $rows, $records) = db_get_records($onadb, 'dns_server_domains', array('host_id' => $shost['id']), ''); 209 | 210 | 211 | // Start building the named.conf - save it in $text 212 | $text = "# Named.conf file for {$shost['fqdn']} built on " . date($conf['date_format']) . "\n"; 213 | $text .= "# TOTAL DOMAINS (count={$rows})\n\n"; 214 | 215 | ////////////// Header stuff ////////////////// 216 | 217 | // Allow for a local header include.. I expect this to rarely be used 218 | // MP: it is probably best to let the user set up all their own stuff and just include the resulting config 219 | // file in whatever their own config is. SOOO no need for this 220 | // $text .= "; Allow for a local header include.. I expect this to rarely be used.\n"; 221 | // $text .= "include \"/etc/named.conf-header\";\n\n"; 222 | 223 | 224 | ////////////// End Header stuff ////////////////// 225 | 226 | foreach ($records as $sdomain) { 227 | list($status, $rows, $domain) = ona_get_domain_record(array('id' => $sdomain['domain_id'])); 228 | // what is the role for this server. 229 | switch (strtolower($sdomain['role'])) { 230 | case "forward": 231 | //TODO: fixme.. this needs IPs like slaves do.. no file 232 | $text .= "zone \"{$domain['fqdn']}\" in {\n type forward;\n file \"/{$options['path']}/named-{$domain['fqdn']}\";}\n"; 233 | break; 234 | case "master": 235 | $text .= "zone \"{$domain['fqdn']}\" in {\n type master;\n file \"/{$options['path']}/named-{$domain['fqdn']}\";\n};\n\n"; 236 | break; 237 | 238 | case "slave": 239 | 240 | // get the IP addresses for the master domain servers for this domain 241 | list($status, $rows, $records) = db_get_records($onadb, 'dns_server_domains', array('domain_id' => $domain['id'], 'role' => 'master'), ''); 242 | 243 | // TODO: if there are no rows then bail 244 | // TODO: look for static master list stored in DB and append it to the list. 245 | 246 | $text .= "zone \"{$domain['fqdn']}\" in {\n type slave;\n file \"/{$options['path']}/named-{$domain['fqdn']}\";\n masterfile-format text;\n"; 247 | // Print the master statement 248 | $text .= " masters { "; 249 | foreach ($records as $master ) { 250 | // Lookup a bunch of crap.. this should be done better. 251 | list($status, $rows, $rec) = ona_get_host_record(array('id' => $master['host_id'])); 252 | list($status, $rows, $rec) = ona_get_dns_record(array('id' => $rec['primary_dns_id'])); 253 | list($status, $rows, $rec) = ona_get_interface_record(array('id' => $rec['interface_id'])); 254 | $text .= $rec['ip_addr_text']."; "; 255 | } 256 | $text .= "};\n"; 257 | $text .= "};\n\n"; 258 | break; 259 | 260 | default: 261 | $text .= "# {$domain['name']} has an invalid value for the column ROLE.\n"; 262 | break; 263 | 264 | } 265 | } 266 | 267 | 268 | // Return the config file 269 | return(array(0, $text)); 270 | 271 | } 272 | 273 | 274 | 275 | 276 | /////////////////////////////////////////////////////////////////////// 277 | // Function: build_bind_domain (string $options='') 278 | // 279 | // Input Options: 280 | // $options = key=value pairs of options for this function. 281 | // multiple sets of key=value pairs should be separated 282 | // by an "&" symbol. 283 | // 284 | // Output: 285 | // Returns a two part list: 286 | // 1. The exit status of the function (0 on success, non-zero on error) 287 | // 2. A textual message for display on the console or web interface. 288 | // 289 | // Example: list($status, $result) = build_zone('zone=test'); 290 | // 291 | // Exit codes: 292 | // 0 :: No error 293 | // 1 :: Help text printed - Insufficient or invalid input received 294 | // 2 :: No such host 295 | // 296 | // 297 | // 298 | /////////////////////////////////////////////////////////////////////// 299 | function build_bind_domain($options="") { 300 | 301 | // The important globals 302 | global $conf, $self, $onadb; 303 | 304 | // Version - UPDATE on every edit! 305 | $version = '1.51'; 306 | 307 | printmsg("DEBUG => build_bind_domain({$options}) called", 3); 308 | 309 | // Parse incoming options string to an array 310 | $options = parse_options($options); 311 | 312 | // Return the usage summary if we need to 313 | if ($options['help'] or !$options['domain']) { 314 | // NOTE: Help message lines should not exceed 80 characters for proper display on a console 315 | $self['error'] = 'ERROR => Insufficient parameters'; 316 | return(array(1, 317 | << build_bind_domain() Domain record: {$domain['domain']}", 3); 336 | if (!$domain['id']) { 337 | printmsg("DEBUG => Unknown domain record: {$options['domain']}",3); 338 | $self['error'] = "ERROR => Unknown domain record: {$options['domain']}"; 339 | return(array(2, $self['error'] . "\n")); 340 | } 341 | 342 | // if for some reason the domains default_ttl is not set, use the one from the $conf['dns']['default_ttl'] 343 | if ($domain['default_ttl'] == 0) $domain['default_ttl'] = $conf['dns']['default_ttl']; 344 | 345 | if ($domain['primary_master'] == '') $domain['primary_master'] = 'localhost'; 346 | 347 | 348 | // loop through records and display them 349 | $q=" 350 | SELECT * 351 | FROM dns 352 | WHERE domain_id = {$domain['id']} 353 | ORDER BY type"; 354 | 355 | 356 | // exectue the query 357 | $rs = $onadb->Execute($q); 358 | if ($rs === false or (!$rs->RecordCount())) { 359 | $self['error'] = 'ERROR => build_zone(): SQL query failed: ' . $onadb->ErrorMsg(); 360 | printmsg($self['error'], 0); 361 | $exit += 1; 362 | } 363 | $rows = $rs->RecordCount(); 364 | 365 | // check if this is a ptr domain that has delegation 366 | $ptrdelegation=false; 367 | if (strpos(preg_replace("/[ip6nadr-]+.arpa/", '', $domain['fqdn']),'-') !== FALSE) { 368 | $ptrdelegation=true; 369 | } 370 | 371 | // Start building the named.conf - save it in $text 372 | $text = "; DNS zone file for {$domain['fqdn']} built on " . date($conf['date_format']) . "\n"; 373 | 374 | // print the opening host comment with row count 375 | $text .= "; TOTAL RECORDS (count={$rows})\n\n"; 376 | // FIXME: MP do more to ensure that dots are at the end as appropriate 377 | $text .= "\$ORIGIN {$domain['fqdn']}.\n"; 378 | $text .= "\$TTL {$domain['default_ttl']}\n"; 379 | $text .= ";Serial number is current unix timestamp (seconds since UTC)\n\n"; 380 | 381 | // NOTE: There are various ways that one could generate the serial. The bind book suggests YYYYMMDDXX where XX is 1/100th of the day or some counter in the day. 382 | // I feel this is too limiting. I prefer the Unix timestamp (seconds since UTC) method. TinyDNS uses this method as well and it allows for much more granularity. 383 | // Referr to the following for some discussion on the topic: http://www.lifewithdjbdns.com/#Migration 384 | // NOTE: for now I am generating the serial each time the zone is built. I'm ignoring, and may remove, the one stored in the database. 385 | $serial_number = time(); 386 | 387 | // Build the SOA record 388 | // FIXME: MP do a bit more to ensure that dots are where they should be 389 | $text .= "@ IN SOA {$domain['primary_master']}. {$domain['admin_email']} ({$serial_number} {$domain['refresh']} {$domain['retry']} {$domain['expiry']} {$domain['minimum']})\n\n"; 390 | 391 | 392 | // Loop through the record set 393 | while ($dnsrecord = $rs->FetchRow()) { 394 | // Dont build records that begin in the future 395 | if (strtotime($dnsrecord['ebegin']) > time()) continue; 396 | if (strtotime($dnsrecord['ebegin']) < 0) continue; 397 | 398 | // If there are notes, put the comment character in front of it 399 | if ($dnsrecord['notes']) $dnsrecord['notes'] = '; '.str_replace("\n", "; ", $dnsrecord['notes']); 400 | 401 | // If the ttl is empty then make it truely empty 402 | if ($dnsrecord['ttl'] == 0) $dnsrecord['ttl'] = ''; 403 | 404 | // Also, if the records ttl is the same as the domains ttl then dont display it, just to keep it "cleaner" 405 | if (!strcmp($dnsrecord['ttl'],$domain['default_ttl'])) $dnsrecord['ttl'] = ''; 406 | 407 | // Dont print a dot unless hostname has a value 408 | if ($dnsrecord['name']) $dnsrecord['name'] = $dnsrecord['name'].'.'; 409 | 410 | if ($dnsrecord['type'] == 'A') { 411 | // Find the interface record 412 | list($status, $rows, $interface) = ona_get_interface_record(array('id' => $dnsrecord['interface_id'])); 413 | if ($status or !$rows) { 414 | printmsg("ERROR => Unable to find interface record!",3); 415 | $self['error'] = "ERROR => Unable to find interface record!"; 416 | return(array(5, $self['error'] . "\n")); 417 | } 418 | 419 | // Determine A record type if it is IPv6 420 | $dnsrecord['type'] = (strpos($interface['ip_addr_text'],':') ? 'AAAA' : 'A'); 421 | 422 | $fqdn = $dnsrecord['name'].$domain['fqdn']; 423 | $text .= sprintf("%-50s %-8s IN %-8s %-30s %s\n" ,$fqdn.'.',$dnsrecord['ttl'],$dnsrecord['type'],$interface['ip_addr_text'],$dnsrecord['notes']); 424 | } 425 | 426 | if ($dnsrecord['type'] == 'PTR') { 427 | // Find the interface record 428 | list($status, $rows, $interface) = ona_get_interface_record(array('id' => $dnsrecord['interface_id'])); 429 | if ($status or !$rows) { 430 | printmsg("ERROR => Unable to find interface record!",3); 431 | $self['error'] = "ERROR => Unable to find interface record!"; 432 | return(array(5, $self['error'] . "\n")); 433 | } 434 | 435 | // Get the name info that the cname points to 436 | list($status, $rows, $ptr) = ona_get_dns_record(array('id' => $dnsrecord['dns_id']), ''); 437 | 438 | // set the ptr zone type for IPv6 records 439 | $arpatype = (strpos($interface['ip_addr_text'],':') ? 'ip6' : 'in-addr'); 440 | 441 | // If this is a delegation domain, find the subnet cidr 442 | if ($ptrdelegation) { 443 | list($status, $rows, $subnet) = ona_get_subnet_record(array('id' => $interface['subnet_id'])); 444 | 445 | $ip_last = ip_mangle($interface['ip_addr'],'flip'); 446 | $ip_last_digit = substr($ip_last, 0, strpos($ip_last,'.')); 447 | $ip_remainder = substr($ip_last, strpos($ip_last,'.')).".${arpatype}.arpa."; 448 | $text .= sprintf("%-50s %-8s IN %-8s %s.%-30s %s\n" ,$ip_last_digit.'-'.ip_mangle($subnet['ip_mask'],'cidr').$ip_remainder,$dnsrecord['ttl'],$dnsrecord['type'],$ptr['name'],$ptr['domain_fqdn'].'.',$dnsrecord['notes']); 449 | } else { 450 | $text .= sprintf("%-50s %-8s IN %-8s %s.%-30s %s\n" ,ip_mangle($interface['ip_addr'],'flip').".${arpatype}.arpa.",$dnsrecord['ttl'],$dnsrecord['type'],$ptr['name'],$ptr['domain_fqdn'].'.',$dnsrecord['notes']); 451 | } 452 | } 453 | 454 | if ($dnsrecord['type'] == 'CNAME') { 455 | // Find the interface record 456 | list($status, $rows, $interface) = ona_get_interface_record(array('id' => $dnsrecord['interface_id'])); 457 | if ($status or !$rows) { 458 | printmsg("ERROR => Unable to find interface record!",3); 459 | $self['error'] = "ERROR => Unable to find interface record!"; 460 | return(array(5, $self['error'] . "\n")); 461 | } 462 | 463 | // Get the name info that the cname points to 464 | list($status, $rows, $cname) = ona_get_dns_record(array('id' => $dnsrecord['dns_id']), ''); 465 | 466 | $fqdn = $dnsrecord['name'].$domain['fqdn']; 467 | $text .= sprintf("%-50s %-8s IN %-8s %s.%-30s %s\n" ,$fqdn.'.',$dnsrecord['ttl'],$dnsrecord['type'],$cname['name'],$cname['domain_fqdn'].'.',$dnsrecord['notes']); 468 | } 469 | 470 | if ($dnsrecord['type'] == 'NS') { 471 | // Find the interface record 472 | list($status, $rows, $interface) = ona_get_interface_record(array('id' => $dnsrecord['interface_id'])); 473 | if ($status or !$rows) { 474 | printmsg("ERROR => Unable to find interface record!",3); 475 | $self['error'] = "ERROR => Unable to find interface record!"; 476 | return(array(5, $self['error'] . "\n")); 477 | } 478 | 479 | // Get the name info that the cname points to 480 | list($status, $rows, $ns) = ona_get_dns_record(array('id' => $dnsrecord['dns_id']), ''); 481 | 482 | $text .= sprintf("%-50s %-8s IN %-8s %s.%-30s %s\n" ,$domain['fqdn'].'.',$dnsrecord['ttl'],$dnsrecord['type'],$ns['name'],$ns['domain_fqdn'].'.',$dnsrecord['notes']); 483 | } 484 | 485 | if ($dnsrecord['type'] == 'MX') { 486 | // Find the interface record 487 | list($status, $rows, $interface) = ona_get_interface_record(array('id' => $dnsrecord['interface_id'])); 488 | if ($status or !$rows) { 489 | printmsg("ERROR => Unable to find interface record!",3); 490 | $self['error'] = "ERROR => Unable to find interface record!"; 491 | return(array(5, $self['error'] . "\n")); 492 | } 493 | 494 | // Get the name info that the cname points to 495 | list($status, $rows, $mx) = ona_get_dns_record(array('id' => $dnsrecord['dns_id']), ''); 496 | 497 | if ($dnsrecord['name']) { 498 | $name = $dnsrecord['name'].$domain['fqdn']; 499 | } 500 | else { 501 | $name = $domain['name']; 502 | } 503 | $text .= sprintf("%-50s %-8s IN %s %-5s %s.%-30s %s\n" ,$name.'.',$dnsrecord['ttl'],$dnsrecord['type'],$dnsrecord['mx_preference'],$mx['name'],$mx['domain_fqdn'].'.',$dnsrecord['notes']); 504 | } 505 | 506 | if ($dnsrecord['type'] == 'SRV') { 507 | // Find the interface record 508 | list($status, $rows, $interface) = ona_get_interface_record(array('id' => $dnsrecord['interface_id'])); 509 | if ($status or !$rows) { 510 | printmsg("ERROR => Unable to find interface record!",3); 511 | $self['error'] = "ERROR => Unable to find interface record!"; 512 | return(array(5, $self['error'] . "\n")); 513 | } 514 | 515 | // Get the name info that the cname points to 516 | list($status, $rows, $srv) = ona_get_dns_record(array('id' => $dnsrecord['dns_id']), ''); 517 | 518 | if ($dnsrecord['name']) { 519 | $name = $dnsrecord['name'].$domain['fqdn']; 520 | } 521 | else { 522 | $name = $domain['name']; 523 | } 524 | $text .= sprintf("%-50s %-8s IN %s %s %s %-8s %-30s %s\n" ,$name.'.',$dnsrecord['ttl'],$dnsrecord['type'],$dnsrecord['srv_pri'],$dnsrecord['srv_weight'],$dnsrecord['srv_port'],$srv['fqdn'].'.',$dnsrecord['notes']); 525 | } 526 | 527 | if ($dnsrecord['type'] == 'TXT') { 528 | $fqdn = $dnsrecord['name'].$domain['fqdn']; 529 | $text .= sprintf("%-50s %-8s IN %-8s %-30s %s\n" ,$fqdn.'.',$dnsrecord['ttl'],$dnsrecord['type'],'"'.$dnsrecord['txt'].'"',$dnsrecord['notes']); 530 | } 531 | } 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | ////////////// Footer stuff ////////////////// 540 | 541 | // MP: FIXME: For now I"m not using this.. bind errors out if the file doesnt exist. need a deterministic way to do this. 542 | // Allow for a local footer include.. I expect this to rarely be used 543 | // $text .= "\n; Allow for a local footer include.. I expect this to rarely be used.\n"; 544 | // $text .= "\$INCLUDE named-{$domain['fqdn']}-footer\n"; 545 | 546 | 547 | 548 | 549 | // Return the zone file 550 | return(array(0, $text)); 551 | 552 | 553 | } 554 | 555 | 556 | 557 | 558 | ?> 559 | -------------------------------------------------------------------------------- /install.php: -------------------------------------------------------------------------------- 1 | ' + 56 | el('{$window_name}_title_r').innerHTML; 57 | 58 | /* Put a help icon in the title bar */ 59 | el('{$window_name}_title_r').innerHTML = 60 | ' ' + 61 | el('{$window_name}_title_r').innerHTML; 62 | 63 | EOL; 64 | 65 | $window['html'] .= "
"; 66 | 67 | 68 | if (!is_writable($conf['plugin_dir'])) { 69 | $window['html'] .= "
ERROR=> The plugin directory '{$conf['plugin_dir']}' is not writable by the web server!
      You might execute the command: chown -R {$_ENV['APACHE_RUN_USER']} {$conf['plugin_dir']}
"; 70 | $stat++; 71 | } 72 | 73 | // If we have defined modules, process them 74 | if (count($pmodules) > 0 ) { 75 | $window['html'] .= <<Installing new DCM modules:
77 | EOL; 78 | 79 | 80 | 81 | // Get list of existing DCM modules to see if they are already installed, Use cache if possible 82 | if (!is_array($self['cache']['modules']) or !array_key_exists('get_module_list', $self['cache']['modules'])) { 83 | require_once($conf['dcm_module_dir'] . '/get_module_list.inc.php'); 84 | list($status, $self['cache']['modules']) = get_module_list('type=array'); 85 | } 86 | 87 | // If the new module does not already exist, add it 88 | foreach ($pmodules as $modname => $attributes) { 89 | if (!array_key_exists($modname,$self['cache']['modules'])) { 90 | // default the file location if it is not set to use the main lugin file 91 | if (!$attributes['file']) $attributes['file'] = "..{$plugindir}/{$plugin_name}.inc.php"; 92 | list($status, $output) = run_module('add_module', array('name' => $modname, 'desc' => $attributes['desc'], 'file' => $attributes['file'])); 93 | if ($status) { 94 | $stat++; 95 | $window['html'] .= "     {$modname} failed to install.
"; 96 | } else { 97 | printmsg("DEBUG => Plugin install for {$plugin_name} created new DCM module {$modname}.",2); 98 | $window['html'] .= "     {$modname}
"; 99 | } 100 | } else { 101 | $window['html'] .= "     {$modname}, already installed.
"; 102 | } 103 | } 104 | } 105 | 106 | // If there is a SQL file to process. lets do that 107 | $sqlfile = dirname(__FILE__)."/install.sql"; 108 | if (file_exists($sqlfile)) { 109 | 110 | $sqlcontent = file_get_contents($sqlfile); 111 | $statements = preg_split("/;/", $sqlcontent); 112 | 113 | $has_trans = $onadb->BeginTrans(); 114 | if (!$has_trans) printmsg("WARNING => Transactions support not available on this database, this can cause problems!", 1); 115 | 116 | // If begintrans worked and we support transactions, do the smarter "starttrans" function 117 | if ($has_trans) { 118 | printmsg("DEBUG => Starting transaction", 2); 119 | $onadb->StartTrans(); 120 | } 121 | 122 | 123 | // Run the SQL 124 | printmsg("DEBUG => Installing {$modname} plugin SQL statements.", 4); 125 | $i = 0; 126 | while ($i < count($statements)-1) { 127 | 128 | // The SQL statements are split above based on a ; character. 129 | // This may not always work but should cover most things, just be aware. 130 | //$window['html'] .= $statements[$i].'---

'; 131 | $ok = $onadb->Execute($statements[$i].';'); 132 | $error = $onadb->ErrorMsg(); 133 | 134 | if ($ok === false or $error) { 135 | if ($has_trans) { 136 | printmsg("INFO => There was a module error, marking transaction for a Rollback!", 1); 137 | $onadb->FailTrans(); 138 | } 139 | break; 140 | } 141 | $i++; 142 | } 143 | 144 | // Report any errors 145 | if ($ok === false or $error) { 146 | $window['html'] .= <<Installing database updates:
148 | ERROR => SQL statements failed:
{$error}
149 |
Unable to automatically process SQL statements
150 |       Please try again, or add the following SQL statements manually: 151 |
152 |         {$sqlcontent}
153 |         
154 |
155 | Possibly use the following command:
156 | mysql -u {$self['db_login']} -p{$self['db_passwd']} {$self['db_database']} < {$sqlfile}


157 | EOL; 158 | $stat++; 159 | } else { 160 | $window['html'] .= <<Installing database updates:
162 |      All SQL updates were successful.
163 | EOL; 164 | if ($has_trans) { $onadb->CompleteTrans(); } 165 | } 166 | 167 | } 168 | 169 | // Lets check for files that should be installed. 170 | $window['html'] .= "
Checking required files:
"; 171 | 172 | $reqfile = $onainstalldir.'/bin/build_bind'; 173 | if (file_exists($reqfile)) { 174 | $window['html'] .= "     {$reqfile}
"; 175 | } else { 176 | $window['html'] .= "     INFO=> Install build script:
"; 177 | // Provide some information to the user on how to fix the problem manually 178 | $window['html'] .= "You will want to install the build_bind script on your BIND DNS server.
Download or copy '{$installdir}/build_bind' to /opt/ona/bin/ on your BIND server.


"; 179 | } 180 | 181 | $reqfile = $onainstalldir.'/bin/dcm.pl'; 182 | if (file_exists($reqfile)) { 183 | $window['html'] .= "     {$reqfile}
"; 184 | } else { 185 | $window['html'] .= "     INFO=> Unable to find dcm.pl, try the following:
"; 186 | // Provide some information to the user on how to fix the problem manually 187 | $window['html'] .= "Please install dcm.pl:
Make a symlink or install into {$onainstalldir}/bin


"; 188 | } 189 | 190 | $window['html'] .= "
Disabling install script:
"; 191 | // If there were no errors, move this install file out of the way. 192 | if (!$stat) { 193 | $window['html'] .= "    Moved install files.

Install complete. Not disabling install script, this way you can always find where the build script is located.
Even though this install may look like it failed.. everything is OK to proceed.

You should read the documentation located HERE for further install instructions.


CLOSE WINDOW
"; 194 | } else { 195 | $window['html'] .= "     Not disabling install script due to previous errors.

Fix the errors and then click to TRY AGAIN
"; 196 | 197 | } 198 | 199 | $window['html'] .= "

END OF INSTALL
"; 200 | 201 | ?> 202 | -------------------------------------------------------------------------------- /install.sql: -------------------------------------------------------------------------------- 1 | insert into sys_config (name, value, description, field_validation_rule, failed_rule_text, editable, deleteable) values ('build_dns_type', 'bind', 'DNS build type', '', '', 1, 1) on duplicate key update value='bind'; -------------------------------------------------------------------------------- /plugin_info.php: -------------------------------------------------------------------------------- 1 | 13 | --------------------------------------------------------------------------------